summaryrefslogtreecommitdiff
path: root/drivers/gpu/drm/sun4i
diff options
context:
space:
mode:
authorDave Airlie <airlied@redhat.com>2026-08-08 14:13:33 +1000
committerDave Airlie <airlied@redhat.com>2026-08-08 14:13:58 +1000
commite4d41a34eedb808d423d73cae8d8601be32f307e (patch)
treeb81478f91e13b57bce5a3580fde622a4f710d7d2 /drivers/gpu/drm/sun4i
parent7dda2a8bfde23c8f787aa34e5ce40725a6be65b9 (diff)
parentbd4f284df04d76fd65e57141cb1e6e7a49e4c3cb (diff)
Merge tag 'drm-misc-next-2026-08-06' of https://gitlab.freedesktop.org/drm/misc/kernel into drm-next
drm-misc-next for v7.3: UAPI Changes: - Remove the default udmabuf size limit of 64MB. Cross-subsystem Changes: - Add dmemcg support for eviction, and hook it up for amdgpu and xe. Core Changes: - Changes to TTM to be more aggressive when allocating below protection limit! - Improve dt binding documentation for renesas. - Add helper to convert physical address back to buddy block, add that to and improve its kunit test. Driver Changes: - Assorted small fixes to ti-sn65dsi86, panthor, imagination, omapdrm, bridge/synopsys, panel-edp, ssd130x, panel/tdo-tl070wsh30. - Add Sharp LQ120P1JX51 panel. - Add dmemcg support to nouveau. - Various updates and improvements to sun4i, among which YUV and 4k support. Signed-off-by: Dave Airlie <airlied@redhat.com> From: Maarten Lankhorst <maarten.lankhorst@linux.intel.com> Link: https://patch.msgid.link/917d462a-8976-4a15-bec4-4513ec51c5c0@linux.intel.com
Diffstat (limited to 'drivers/gpu/drm/sun4i')
-rw-r--r--drivers/gpu/drm/sun4i/sun4i_crtc.c2
-rw-r--r--drivers/gpu/drm/sun4i/sun4i_drv.c3
-rw-r--r--drivers/gpu/drm/sun4i/sun4i_framebuffer.c19
-rw-r--r--drivers/gpu/drm/sun4i/sun4i_hdmi_enc.c2
-rw-r--r--drivers/gpu/drm/sun4i/sun4i_tcon.c22
-rw-r--r--drivers/gpu/drm/sun4i/sun8i_dw_hdmi.c2
-rw-r--r--drivers/gpu/drm/sun4i/sun8i_hdmi_phy.c2
-rw-r--r--drivers/gpu/drm/sun4i/sun8i_mixer.c2
-rw-r--r--drivers/gpu/drm/sun4i/sun8i_tcon_top.c71
-rw-r--r--drivers/gpu/drm/sun4i/sun8i_tcon_top.h6
-rw-r--r--drivers/gpu/drm/sun4i/sun8i_vi_scaler.c20
-rw-r--r--drivers/gpu/drm/sun4i/sun8i_vi_scaler.h1
12 files changed, 103 insertions, 49 deletions
diff --git a/drivers/gpu/drm/sun4i/sun4i_crtc.c b/drivers/gpu/drm/sun4i/sun4i_crtc.c
index c2f7f69baf75..3fa1f4fda0f0 100644
--- a/drivers/gpu/drm/sun4i/sun4i_crtc.c
+++ b/drivers/gpu/drm/sun4i/sun4i_crtc.c
@@ -208,7 +208,7 @@ struct sun4i_crtc *sun4i_crtc_init(struct drm_device *drm,
planes = sunxi_engine_layers_init(drm, engine);
if (IS_ERR(planes)) {
dev_err(drm->dev, "Couldn't create the planes\n");
- return NULL;
+ return ERR_CAST(planes);
}
/* find primary and cursor planes for drm_crtc_init_with_planes */
diff --git a/drivers/gpu/drm/sun4i/sun4i_drv.c b/drivers/gpu/drm/sun4i/sun4i_drv.c
index 8a409eee1dca..e9baca360160 100644
--- a/drivers/gpu/drm/sun4i/sun4i_drv.c
+++ b/drivers/gpu/drm/sun4i/sun4i_drv.c
@@ -289,6 +289,8 @@ static void sun4i_drv_traverse_endpoints(struct endpoint_list *list,
kfifo_put(&list->fifo, remote);
}
+
+ of_node_put(port);
}
static int sun4i_drv_add_endpoints(struct device *dev,
@@ -394,6 +396,7 @@ static int sun4i_drv_probe(struct platform_device *pdev)
/* process this endpoint */
ret = sun4i_drv_add_endpoints(&pdev->dev, &list, &match,
endpoint);
+ of_node_put(endpoint);
/* sun4i_drv_add_endpoints can fail to allocate memory */
if (ret < 0)
diff --git a/drivers/gpu/drm/sun4i/sun4i_framebuffer.c b/drivers/gpu/drm/sun4i/sun4i_framebuffer.c
index 9c8ef927d929..fc822bc2c62b 100644
--- a/drivers/gpu/drm/sun4i/sun4i_framebuffer.c
+++ b/drivers/gpu/drm/sun4i/sun4i_framebuffer.c
@@ -14,24 +14,8 @@
#include "sun4i_drv.h"
#include "sun4i_framebuffer.h"
-static int sun4i_de_atomic_check(struct drm_device *dev,
- struct drm_atomic_commit *state)
-{
- int ret;
-
- ret = drm_atomic_helper_check_modeset(dev, state);
- if (ret)
- return ret;
-
- ret = drm_atomic_normalize_zpos(dev, state);
- if (ret)
- return ret;
-
- return drm_atomic_helper_check_planes(dev, state);
-}
-
static const struct drm_mode_config_funcs sun4i_de_mode_config_funcs = {
- .atomic_check = sun4i_de_atomic_check,
+ .atomic_check = drm_atomic_helper_check,
.atomic_commit = drm_atomic_helper_commit,
.fb_create = drm_gem_fb_create,
};
@@ -46,6 +30,7 @@ void sun4i_framebuffer_init(struct drm_device *drm)
drm->mode_config.max_width = 8192;
drm->mode_config.max_height = 8192;
+ drm->mode_config.normalize_zpos = true;
drm->mode_config.funcs = &sun4i_de_mode_config_funcs;
drm->mode_config.helper_private = &sun4i_de_mode_config_helpers;
diff --git a/drivers/gpu/drm/sun4i/sun4i_hdmi_enc.c b/drivers/gpu/drm/sun4i/sun4i_hdmi_enc.c
index e99f52ebb26f..97253d631b2b 100644
--- a/drivers/gpu/drm/sun4i/sun4i_hdmi_enc.c
+++ b/drivers/gpu/drm/sun4i/sun4i_hdmi_enc.c
@@ -160,7 +160,7 @@ static void sun4i_hdmi_enable(struct drm_encoder *encoder,
drm_atomic_helper_connector_hdmi_update_infoframes(connector, state);
- val |= SUN4I_HDMI_PKT_CTRL_TYPE(0, SUN4I_HDMI_PKT_AVI);
+ val = SUN4I_HDMI_PKT_CTRL_TYPE(0, SUN4I_HDMI_PKT_AVI);
val |= SUN4I_HDMI_PKT_CTRL_TYPE(1, SUN4I_HDMI_PKT_END);
writel(val, hdmi->base + SUN4I_HDMI_PKT_CTRL_REG(0));
diff --git a/drivers/gpu/drm/sun4i/sun4i_tcon.c b/drivers/gpu/drm/sun4i/sun4i_tcon.c
index d4c1723c5e3d..bf405a2aa324 100644
--- a/drivers/gpu/drm/sun4i/sun4i_tcon.c
+++ b/drivers/gpu/drm/sun4i/sun4i_tcon.c
@@ -717,9 +717,11 @@ void sun4i_tcon_mode_set(struct sun4i_tcon *tcon,
case DRM_MODE_ENCODER_DSI:
/* DSI is tied to special case of CPU interface */
sun4i_tcon0_mode_set_cpu(tcon, encoder, mode);
+ sun4i_tcon_set_mux(tcon, 0, encoder);
break;
case DRM_MODE_ENCODER_LVDS:
sun4i_tcon0_mode_set_lvds(tcon, encoder, mode);
+ sun4i_tcon_set_mux(tcon, 0, encoder);
break;
case DRM_MODE_ENCODER_NONE:
sun4i_tcon0_mode_set_rgb(tcon, encoder, mode);
@@ -970,6 +972,7 @@ static int sun4i_tcon_of_get_id_from_port(struct device_node *port)
continue;
ret = of_property_read_u32(remote, "reg", &reg);
+ of_node_put(remote);
if (ret)
continue;
@@ -1409,7 +1412,7 @@ static int sun8i_r40_tcon_tv_set_mux(struct sun4i_tcon *tcon,
{
struct device_node *port, *remote;
struct platform_device *pdev;
- int id, ret;
+ int id, ret = 0;
/* find TCON TOP platform device and TCON id */
@@ -1432,21 +1435,20 @@ static int sun8i_r40_tcon_tv_set_mux(struct sun4i_tcon *tcon,
if (IS_ENABLED(CONFIG_DRM_SUN8I_TCON_TOP) &&
encoder->encoder_type == DRM_MODE_ENCODER_TMDS) {
ret = sun8i_tcon_top_set_hdmi_src(&pdev->dev, id);
- if (ret) {
- put_device(&pdev->dev);
- return ret;
- }
+ if (ret)
+ goto out_put_device;
}
if (IS_ENABLED(CONFIG_DRM_SUN8I_TCON_TOP)) {
ret = sun8i_tcon_top_de_config(&pdev->dev, tcon->id, id);
- if (ret) {
- put_device(&pdev->dev);
- return ret;
- }
+ if (ret)
+ goto out_put_device;
}
- return 0;
+out_put_device:
+ put_device(&pdev->dev);
+
+ return ret;
}
static const struct sun4i_tcon_quirks sun4i_a10_quirks = {
diff --git a/drivers/gpu/drm/sun4i/sun8i_dw_hdmi.c b/drivers/gpu/drm/sun4i/sun8i_dw_hdmi.c
index 9694ad142a7d..bd3923ef5a41 100644
--- a/drivers/gpu/drm/sun4i/sun8i_dw_hdmi.c
+++ b/drivers/gpu/drm/sun4i/sun8i_dw_hdmi.c
@@ -86,6 +86,8 @@ static u32 sun8i_dw_hdmi_find_possible_crtcs(struct drm_device *drm,
of_node_put(remote_port);
}
}
+
+ of_node_put(port);
} else {
crtcs = drm_of_find_possible_crtcs(drm, node);
}
diff --git a/drivers/gpu/drm/sun4i/sun8i_hdmi_phy.c b/drivers/gpu/drm/sun4i/sun8i_hdmi_phy.c
index 4fa69c463dc4..489ea94693ff 100644
--- a/drivers/gpu/drm/sun4i/sun8i_hdmi_phy.c
+++ b/drivers/gpu/drm/sun4i/sun8i_hdmi_phy.c
@@ -91,7 +91,7 @@ static const struct dw_hdmi_mpll_config sun50i_h6_mpll_cfg[] = {
},
}, {
594000000, {
- { 0x1a40, 0x0003 },
+ { 0x1a7c, 0x0003 },
{ 0x3b4c, 0x0003 },
{ 0x5a64, 0x0003 },
},
diff --git a/drivers/gpu/drm/sun4i/sun8i_mixer.c b/drivers/gpu/drm/sun4i/sun8i_mixer.c
index 4e4226295010..b6cd7352e76c 100644
--- a/drivers/gpu/drm/sun4i/sun8i_mixer.c
+++ b/drivers/gpu/drm/sun4i/sun8i_mixer.c
@@ -785,7 +785,7 @@ static const struct sun8i_mixer_cfg sun8i_v3s_mixer_cfg = {
.de_type = SUN8I_MIXER_DE2,
.vi_scaler_num = 2,
.scaler_mask = 0x3,
- .scanline_yuv = 2048,
+ .scanline_yuv = 1024,
},
.de_type = SUN8I_MIXER_DE2,
.mod_rate = 150000000,
diff --git a/drivers/gpu/drm/sun4i/sun8i_tcon_top.c b/drivers/gpu/drm/sun4i/sun8i_tcon_top.c
index 8adda578c51b..9cbd655518b2 100644
--- a/drivers/gpu/drm/sun4i/sun8i_tcon_top.c
+++ b/drivers/gpu/drm/sun4i/sun8i_tcon_top.c
@@ -25,6 +25,49 @@ static bool sun8i_tcon_top_node_is_tcon_top(struct device_node *node)
return !!of_match_node(sun8i_tcon_top_of_table, node);
}
+static unsigned int sun8i_tcon_top_get_tcon_map(struct device_node *node)
+{
+ static const u32 out_ports[] = {
+ TCON_TOP_MIXER0_OUT_PORT,
+ TCON_TOP_MIXER1_OUT_PORT,
+ };
+ unsigned int i, map = 0;
+
+ for (i = 0; i < ARRAY_SIZE(out_ports); i++) {
+ struct device_node *port;
+
+ port = of_graph_get_port_by_id(node, out_ports[i]);
+ if (!port)
+ continue;
+
+ for_each_of_graph_port_endpoint(port, ep) {
+ struct of_endpoint endpoint;
+
+ if (of_graph_parse_endpoint(ep, &endpoint))
+ continue;
+
+ if (endpoint.id < TCON_TOP_PORT_TCON_NUM)
+ map |= BIT(endpoint.id);
+ }
+
+ of_node_put(port);
+ }
+
+ return map;
+}
+
+static unsigned int sun8i_tcon_top_park_index(struct sun8i_tcon_top *tcon_top,
+ int tcon)
+{
+ unsigned int candidates;
+
+ candidates = tcon_top->tcon_map & ~BIT(tcon);
+ if (!candidates)
+ candidates = GENMASK(TCON_TOP_PORT_TCON_NUM - 1, 0) & ~BIT(tcon);
+
+ return ffs(candidates) - 1;
+}
+
int sun8i_tcon_top_set_hdmi_src(struct device *dev, int tcon)
{
struct sun8i_tcon_top *tcon_top = dev_get_drvdata(dev);
@@ -57,6 +100,7 @@ EXPORT_SYMBOL(sun8i_tcon_top_set_hdmi_src);
int sun8i_tcon_top_de_config(struct device *dev, int mixer, int tcon)
{
struct sun8i_tcon_top *tcon_top = dev_get_drvdata(dev);
+ u32 mixer_msk, other_msk;
unsigned long flags;
u32 reg;
@@ -70,21 +114,27 @@ int sun8i_tcon_top_de_config(struct device *dev, int mixer, int tcon)
return -EINVAL;
}
- if (tcon > 3) {
- dev_err(dev, "TCON index is too high!\n");
+ if (tcon < 0 || tcon >= TCON_TOP_PORT_TCON_NUM) {
+ dev_err(dev, "TCON index is invalid!\n");
return -EINVAL;
}
+ mixer_msk = mixer ? TCON_TOP_PORT_DE1_MSK : TCON_TOP_PORT_DE0_MSK;
+ other_msk = mixer ? TCON_TOP_PORT_DE0_MSK : TCON_TOP_PORT_DE1_MSK;
+
spin_lock_irqsave(&tcon_top->reg_lock, flags);
reg = readl(tcon_top->regs + TCON_TOP_PORT_SEL_REG);
- if (mixer == 0) {
- reg &= ~TCON_TOP_PORT_DE0_MSK;
- reg |= FIELD_PREP(TCON_TOP_PORT_DE0_MSK, tcon);
- } else {
- reg &= ~TCON_TOP_PORT_DE1_MSK;
- reg |= FIELD_PREP(TCON_TOP_PORT_DE1_MSK, tcon);
+
+ reg &= ~mixer_msk;
+ reg |= field_prep(mixer_msk, tcon);
+
+ if (field_get(other_msk, reg) == tcon) {
+ reg &= ~other_msk;
+ reg |= field_prep(other_msk,
+ sun8i_tcon_top_park_index(tcon_top, tcon));
}
+
writel(reg, tcon_top->regs + TCON_TOP_PORT_SEL_REG);
spin_unlock_irqrestore(&tcon_top->reg_lock, flags);
@@ -143,6 +193,7 @@ static int sun8i_tcon_top_bind(struct device *dev, struct device *master,
return -ENOMEM;
clk_data->num = CLK_NUM;
tcon_top->clk_data = clk_data;
+ tcon_top->tcon_map = sun8i_tcon_top_get_tcon_map(dev->of_node);
spin_lock_init(&tcon_top->reg_lock);
@@ -175,10 +226,6 @@ static int sun8i_tcon_top_bind(struct device *dev, struct device *master,
goto err_assert_reset;
}
- /*
- * At least on H6, some registers have some bits set by default
- * which may cause issues. Clear them here.
- */
writel(0, regs + TCON_TOP_PORT_SEL_REG);
writel(0, regs + TCON_TOP_GATE_SRC_REG);
diff --git a/drivers/gpu/drm/sun4i/sun8i_tcon_top.h b/drivers/gpu/drm/sun4i/sun8i_tcon_top.h
index 0390584a330e..2b887470a49f 100644
--- a/drivers/gpu/drm/sun4i/sun8i_tcon_top.h
+++ b/drivers/gpu/drm/sun4i/sun8i_tcon_top.h
@@ -14,6 +14,10 @@
#define TCON_TOP_PORT_SEL_REG 0x1C
#define TCON_TOP_PORT_DE0_MSK GENMASK(1, 0)
#define TCON_TOP_PORT_DE1_MSK GENMASK(5, 4)
+#define TCON_TOP_PORT_TCON_NUM 4
+
+#define TCON_TOP_MIXER0_OUT_PORT 1
+#define TCON_TOP_MIXER1_OUT_PORT 3
#define TCON_TOP_GATE_SRC_REG 0x20
#define TCON_TOP_HDMI_SRC_MSK GENMASK(29, 28)
@@ -29,6 +33,8 @@ struct sun8i_tcon_top {
void __iomem *regs;
struct reset_control *rst;
+ unsigned int tcon_map;
+
/*
* spinlock is used to synchronize access to same
* register where multiple clock gates can be set.
diff --git a/drivers/gpu/drm/sun4i/sun8i_vi_scaler.c b/drivers/gpu/drm/sun4i/sun8i_vi_scaler.c
index 3dec4eeb1ba2..a5cc99981006 100644
--- a/drivers/gpu/drm/sun4i/sun8i_vi_scaler.c
+++ b/drivers/gpu/drm/sun4i/sun8i_vi_scaler.c
@@ -894,20 +894,26 @@ static void sun8i_vi_scaler_set_coeff(struct regmap *map, u32 base,
lan3coefftab32_left[offset + i]);
regmap_write(map, SUN8I_SCALER_VSU_YHCOEFF1(base, i),
lan3coefftab32_right[offset + i]);
+ }
+ offset = sun8i_vi_scaler_coef_index(vstep) *
+ 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]);
+
+ offset = sun8i_vi_scaler_coef_index(hstep / format->hsub) *
+ SUN8I_VI_SCALER_COEFF_COUNT;
+ for (i = 0; i < SUN8I_VI_SCALER_COEFF_COUNT; 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]);
}
-
- offset = sun8i_vi_scaler_coef_index(hstep) *
+ offset = sun8i_vi_scaler_coef_index(vstep / format->vsub) *
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]);
+ for (i = 0; i < SUN8I_VI_SCALER_COEFF_COUNT; i++)
regmap_write(map, SUN8I_SCALER_VSU_CVCOEFF(base, i),
cy[offset + i]);
- }
}
void sun8i_vi_scaler_enable(struct sun8i_layer *layer, bool enable)
@@ -969,6 +975,8 @@ void sun8i_vi_scaler_setup(struct sun8i_layer *layer,
regmap_write(layer->regs,
SUN50I_SCALER_VSU_SCALE_MODE(base), val);
+ regmap_write(layer->regs,
+ SUN50I_SCALER_VSU_GLB_ALPHA(base), 0xff);
}
regmap_write(layer->regs,
diff --git a/drivers/gpu/drm/sun4i/sun8i_vi_scaler.h b/drivers/gpu/drm/sun4i/sun8i_vi_scaler.h
index 245fe2f431c3..d89c0cbe188d 100644
--- a/drivers/gpu/drm/sun4i/sun8i_vi_scaler.h
+++ b/drivers/gpu/drm/sun4i/sun8i_vi_scaler.h
@@ -36,6 +36,7 @@
#define SUN50I_SCALER_VSU_EDSCL_CTRL(base) ((base) + 0x28)
#define SUN50I_SCALER_VSU_ANGLE_THR(base) ((base) + 0x2c)
#define SUN8I_SCALER_VSU_OUTSIZE(base) ((base) + 0x40)
+#define SUN50I_SCALER_VSU_GLB_ALPHA(base) ((base) + 0x44)
#define SUN8I_SCALER_VSU_YINSIZE(base) ((base) + 0x80)
#define SUN8I_SCALER_VSU_YHSTEP(base) ((base) + 0x88)
#define SUN8I_SCALER_VSU_YVSTEP(base) ((base) + 0x8c)