summaryrefslogtreecommitdiff
path: root/drivers/gpu/drm/sun4i
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpu/drm/sun4i')
-rw-r--r--drivers/gpu/drm/sun4i/sun4i_backend.c1
-rw-r--r--drivers/gpu/drm/sun4i/sun4i_drv.c1
-rw-r--r--drivers/gpu/drm/sun4i/sun4i_frontend.c1
-rw-r--r--drivers/gpu/drm/sun4i/sun4i_hdmi_ddc_clk.c12
-rw-r--r--drivers/gpu/drm/sun4i/sun4i_tcon_dclk.c18
-rw-r--r--drivers/gpu/drm/sun4i/sun8i_csc.c113
-rw-r--r--drivers/gpu/drm/sun4i/sun8i_csc.h16
-rw-r--r--drivers/gpu/drm/sun4i/sun8i_mixer.c218
-rw-r--r--drivers/gpu/drm/sun4i/sun8i_mixer.h65
-rw-r--r--drivers/gpu/drm/sun4i/sun8i_ui_layer.c187
-rw-r--r--drivers/gpu/drm/sun4i/sun8i_ui_layer.h7
-rw-r--r--drivers/gpu/drm/sun4i/sun8i_ui_scaler.c44
-rw-r--r--drivers/gpu/drm/sun4i/sun8i_ui_scaler.h4
-rw-r--r--drivers/gpu/drm/sun4i/sun8i_vi_layer.c248
-rw-r--r--drivers/gpu/drm/sun4i/sun8i_vi_layer.h7
-rw-r--r--drivers/gpu/drm/sun4i/sun8i_vi_scaler.c51
-rw-r--r--drivers/gpu/drm/sun4i/sun8i_vi_scaler.h6
17 files changed, 500 insertions, 499 deletions
diff --git a/drivers/gpu/drm/sun4i/sun4i_backend.c b/drivers/gpu/drm/sun4i/sun4i_backend.c
index 2dded3b828df..40405a52a073 100644
--- a/drivers/gpu/drm/sun4i/sun4i_backend.c
+++ b/drivers/gpu/drm/sun4i/sun4i_backend.c
@@ -23,6 +23,7 @@
#include <drm/drm_fourcc.h>
#include <drm/drm_framebuffer.h>
#include <drm/drm_gem_dma_helper.h>
+#include <drm/drm_print.h>
#include <drm/drm_probe_helper.h>
#include "sun4i_backend.h"
diff --git a/drivers/gpu/drm/sun4i/sun4i_drv.c b/drivers/gpu/drm/sun4i/sun4i_drv.c
index c11dfb2739fa..8a409eee1dca 100644
--- a/drivers/gpu/drm/sun4i/sun4i_drv.c
+++ b/drivers/gpu/drm/sun4i/sun4i_drv.c
@@ -22,6 +22,7 @@
#include <drm/drm_gem_dma_helper.h>
#include <drm/drm_module.h>
#include <drm/drm_of.h>
+#include <drm/drm_print.h>
#include <drm/drm_probe_helper.h>
#include <drm/drm_vblank.h>
diff --git a/drivers/gpu/drm/sun4i/sun4i_frontend.c b/drivers/gpu/drm/sun4i/sun4i_frontend.c
index 5ab1604f12dd..5e9c4b97c84c 100644
--- a/drivers/gpu/drm/sun4i/sun4i_frontend.c
+++ b/drivers/gpu/drm/sun4i/sun4i_frontend.c
@@ -19,6 +19,7 @@
#include <drm/drm_framebuffer.h>
#include <drm/drm_gem_dma_helper.h>
#include <drm/drm_plane.h>
+#include <drm/drm_print.h>
#include "sun4i_drv.h"
#include "sun4i_frontend.h"
diff --git a/drivers/gpu/drm/sun4i/sun4i_hdmi_ddc_clk.c b/drivers/gpu/drm/sun4i/sun4i_hdmi_ddc_clk.c
index 12430b9d4e93..b1beadb9bb59 100644
--- a/drivers/gpu/drm/sun4i/sun4i_hdmi_ddc_clk.c
+++ b/drivers/gpu/drm/sun4i/sun4i_hdmi_ddc_clk.c
@@ -59,13 +59,15 @@ static unsigned long sun4i_ddc_calc_divider(unsigned long rate,
return best_rate;
}
-static long sun4i_ddc_round_rate(struct clk_hw *hw, unsigned long rate,
- unsigned long *prate)
+static int sun4i_ddc_determine_rate(struct clk_hw *hw,
+ struct clk_rate_request *req)
{
struct sun4i_ddc *ddc = hw_to_ddc(hw);
- return sun4i_ddc_calc_divider(rate, *prate, ddc->pre_div,
- ddc->m_offset, NULL, NULL);
+ req->rate = sun4i_ddc_calc_divider(req->rate, req->best_parent_rate,
+ ddc->pre_div, ddc->m_offset, NULL, NULL);
+
+ return 0;
}
static unsigned long sun4i_ddc_recalc_rate(struct clk_hw *hw,
@@ -101,7 +103,7 @@ static int sun4i_ddc_set_rate(struct clk_hw *hw, unsigned long rate,
static const struct clk_ops sun4i_ddc_ops = {
.recalc_rate = sun4i_ddc_recalc_rate,
- .round_rate = sun4i_ddc_round_rate,
+ .determine_rate = sun4i_ddc_determine_rate,
.set_rate = sun4i_ddc_set_rate,
};
diff --git a/drivers/gpu/drm/sun4i/sun4i_tcon_dclk.c b/drivers/gpu/drm/sun4i/sun4i_tcon_dclk.c
index 03d7de1911cd..4afb12bd5281 100644
--- a/drivers/gpu/drm/sun4i/sun4i_tcon_dclk.c
+++ b/drivers/gpu/drm/sun4i/sun4i_tcon_dclk.c
@@ -67,8 +67,8 @@ static unsigned long sun4i_dclk_recalc_rate(struct clk_hw *hw,
return parent_rate / val;
}
-static long sun4i_dclk_round_rate(struct clk_hw *hw, unsigned long rate,
- unsigned long *parent_rate)
+static int sun4i_dclk_determine_rate(struct clk_hw *hw,
+ struct clk_rate_request *req)
{
struct sun4i_dclk *dclk = hw_to_dclk(hw);
struct sun4i_tcon *tcon = dclk->tcon;
@@ -77,7 +77,7 @@ static long sun4i_dclk_round_rate(struct clk_hw *hw, unsigned long rate,
int i;
for (i = tcon->dclk_min_div; i <= tcon->dclk_max_div; i++) {
- u64 ideal = (u64)rate * i;
+ u64 ideal = (u64)req->rate * i;
unsigned long rounded;
/*
@@ -99,17 +99,19 @@ static long sun4i_dclk_round_rate(struct clk_hw *hw, unsigned long rate,
goto out;
}
- if (abs(rate - rounded / i) <
- abs(rate - best_parent / best_div)) {
+ if (abs(req->rate - rounded / i) <
+ abs(req->rate - best_parent / best_div)) {
best_parent = rounded;
best_div = i;
}
}
out:
- *parent_rate = best_parent;
+ req->best_parent_rate = best_parent;
- return best_parent / best_div;
+ req->rate = best_parent / best_div;
+
+ return 0;
}
static int sun4i_dclk_set_rate(struct clk_hw *hw, unsigned long rate,
@@ -155,7 +157,7 @@ static const struct clk_ops sun4i_dclk_ops = {
.is_enabled = sun4i_dclk_is_enabled,
.recalc_rate = sun4i_dclk_recalc_rate,
- .round_rate = sun4i_dclk_round_rate,
+ .determine_rate = sun4i_dclk_determine_rate,
.set_rate = sun4i_dclk_set_rate,
.get_phase = sun4i_dclk_get_phase,
diff --git a/drivers/gpu/drm/sun4i/sun8i_csc.c b/drivers/gpu/drm/sun4i/sun8i_csc.c
index c100d29b1a89..ce81c12f511d 100644
--- a/drivers/gpu/drm/sun4i/sun8i_csc.c
+++ b/drivers/gpu/drm/sun4i/sun8i_csc.c
@@ -3,11 +3,20 @@
* Copyright (C) Jernej Skrabec <jernej.skrabec@siol.net>
*/
+#include <drm/drm_fourcc.h>
+#include <drm/drm_framebuffer.h>
+#include <drm/drm_plane.h>
#include <drm/drm_print.h>
#include "sun8i_csc.h"
#include "sun8i_mixer.h"
+enum sun8i_csc_mode {
+ SUN8I_CSC_MODE_OFF,
+ SUN8I_CSC_MODE_YUV2RGB,
+ SUN8I_CSC_MODE_YVU2RGB,
+};
+
static const u32 ccsc_base[][2] = {
[CCSC_MIXER0_LAYOUT] = {CCSC00_OFFSET, CCSC01_OFFSET},
[CCSC_MIXER1_LAYOUT] = {CCSC10_OFFSET, CCSC11_OFFSET},
@@ -107,23 +116,28 @@ 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 drm_color_encoding encoding,
- enum drm_color_range range)
+static void sun8i_csc_setup(struct regmap *map, u32 base,
+ enum sun8i_csc_mode mode,
+ 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 (mode) {
+ case SUN8I_CSC_MODE_OFF:
+ val = 0;
+ break;
case SUN8I_CSC_MODE_YUV2RGB:
+ val = SUN8I_CSC_CTRL_EN;
base_reg = SUN8I_CSC_COEFF(base, 0);
regmap_bulk_write(map, base_reg, table, 12);
break;
case SUN8I_CSC_MODE_YVU2RGB:
+ 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 +149,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 sun8i_csc_mode mode,
- enum drm_color_encoding encoding,
- enum drm_color_range range)
+static void sun8i_de3_ccsc_setup(struct regmap *map, int layer,
+ enum sun8i_csc_mode mode,
+ 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 (mode) {
+ case SUN8I_CSC_MODE_OFF:
+ val = 0;
+ break;
case SUN8I_CSC_MODE_YUV2RGB:
+ val = mask;
addr = SUN50I_MIXER_BLEND_CSC_COEFF(DE3_BLD_BASE, layer, 0);
regmap_bulk_write(map, addr, table, 12);
break;
case SUN8I_CSC_MODE_YVU2RGB:
+ val = mask;
for (i = 0; i < 12; i++) {
if ((i & 3) == 1)
addr = SUN50I_MIXER_BLEND_CSC_COEFF(DE3_BLD_BASE,
@@ -173,67 +196,53 @@ 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 sun8i_csc_mode mode,
- enum drm_color_encoding encoding,
- enum drm_color_range range)
+static u32 sun8i_csc_get_mode(struct drm_plane_state *state)
{
- u32 base;
+ const struct drm_format_info *format;
- if (mixer->cfg->de_type == SUN8I_MIXER_DE3) {
- sun8i_de3_ccsc_set_coefficients(mixer->engine.regs, layer,
- mode, encoding, range);
- return;
- }
+ if (!state->crtc || !state->visible)
+ return SUN8I_CSC_MODE_OFF;
- base = ccsc_base[mixer->cfg->ccsc][layer];
+ format = state->fb->format;
+ if (!format->is_yuv)
+ return SUN8I_CSC_MODE_OFF;
- sun8i_csc_set_coefficients(mixer->engine.regs, base,
- mode, encoding, range);
+ switch (format->format) {
+ case DRM_FORMAT_YVU411:
+ case DRM_FORMAT_YVU420:
+ case DRM_FORMAT_YVU422:
+ case DRM_FORMAT_YVU444:
+ return SUN8I_CSC_MODE_YVU2RGB;
+ default:
+ return SUN8I_CSC_MODE_YUV2RGB;
+ }
}
-void sun8i_csc_enable_ccsc(struct sun8i_mixer *mixer, int layer, bool enable)
+void sun8i_csc_config(struct sun8i_layer *layer,
+ struct drm_plane_state *state)
{
+ u32 mode = sun8i_csc_get_mode(state);
u32 base;
- if (mixer->cfg->de_type == SUN8I_MIXER_DE3) {
- sun8i_de3_ccsc_enable(mixer->engine.regs, layer, enable);
+ if (layer->cfg->de_type == SUN8I_MIXER_DE3) {
+ sun8i_de3_ccsc_setup(layer->regs, layer->channel,
+ mode, state->color_encoding,
+ state->color_range);
return;
}
- base = ccsc_base[mixer->cfg->ccsc][layer];
+ base = ccsc_base[layer->cfg->ccsc][layer->channel];
- sun8i_csc_enable(mixer->engine.regs, base, enable);
+ sun8i_csc_setup(layer->regs, base,
+ mode, state->color_encoding,
+ state->color_range);
}
diff --git a/drivers/gpu/drm/sun4i/sun8i_csc.h b/drivers/gpu/drm/sun4i/sun8i_csc.h
index 828b86fd0cab..2a4b79599610 100644
--- a/drivers/gpu/drm/sun4i/sun8i_csc.h
+++ b/drivers/gpu/drm/sun4i/sun8i_csc.h
@@ -8,7 +8,8 @@
#include <drm/drm_color_mgmt.h>
-struct sun8i_mixer;
+struct drm_plane_state;
+struct sun8i_layer;
/* VI channel CSC units offsets */
#define CCSC00_OFFSET 0xAA050
@@ -22,16 +23,7 @@ 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,
-};
-
-void sun8i_csc_set_ccsc_coefficients(struct sun8i_mixer *mixer, int layer,
- enum sun8i_csc_mode mode,
- 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_config(struct sun8i_layer *layer,
+ struct drm_plane_state *state);
#endif
diff --git a/drivers/gpu/drm/sun4i/sun8i_mixer.c b/drivers/gpu/drm/sun4i/sun8i_mixer.c
index 31a8409b98f4..ce9c155bfad7 100644
--- a/drivers/gpu/drm/sun4i/sun8i_mixer.c
+++ b/drivers/gpu/drm/sun4i/sun8i_mixer.c
@@ -21,6 +21,7 @@
#include <drm/drm_crtc.h>
#include <drm/drm_framebuffer.h>
#include <drm/drm_gem_dma_helper.h>
+#include <drm/drm_print.h>
#include <drm/drm_probe_helper.h>
#include "sun4i_drv.h"
@@ -250,24 +251,6 @@ int sun8i_mixer_drm_format_to_hw(u32 format, u32 *hw_format)
return -EINVAL;
}
-static void sun8i_layer_enable(struct sun8i_layer *layer, bool enable)
-{
- u32 ch_base = sun8i_channel_base(layer->mixer, layer->channel);
- u32 val, reg, mask;
-
- if (layer->type == SUN8I_LAYER_TYPE_UI) {
- val = enable ? SUN8I_MIXER_CHAN_UI_LAYER_ATTR_EN : 0;
- mask = SUN8I_MIXER_CHAN_UI_LAYER_ATTR_EN;
- reg = SUN8I_MIXER_CHAN_UI_LAYER_ATTR(ch_base, layer->overlay);
- } else {
- val = enable ? SUN8I_MIXER_CHAN_VI_LAYER_ATTR_EN : 0;
- mask = SUN8I_MIXER_CHAN_VI_LAYER_ATTR_EN;
- reg = SUN8I_MIXER_CHAN_VI_LAYER_ATTR(ch_base, layer->overlay);
- }
-
- regmap_update_bits(layer->mixer->engine.regs, reg, mask, val);
-}
-
static void sun8i_mixer_commit(struct sunxi_engine *engine,
struct drm_crtc *crtc,
struct drm_atomic_state *state)
@@ -283,10 +266,10 @@ static void sun8i_mixer_commit(struct sunxi_engine *engine,
drm_for_each_plane(plane, state->dev) {
struct sun8i_layer *layer = plane_to_sun8i_layer(plane);
+ int w, h, x, y, zpos;
bool enable;
- int zpos;
- if (!(plane->possible_crtcs & drm_crtc_mask(crtc)) || layer->mixer != mixer)
+ if (!(plane->possible_crtcs & drm_crtc_mask(crtc)))
continue;
plane_state = drm_atomic_get_new_plane_state(state, plane);
@@ -295,23 +278,28 @@ static void sun8i_mixer_commit(struct sunxi_engine *engine,
enable = plane_state->crtc && plane_state->visible;
zpos = plane_state->normalized_zpos;
+ x = plane_state->dst.x1;
+ y = plane_state->dst.y1;
+ w = drm_rect_width(&plane_state->dst);
+ h = drm_rect_height(&plane_state->dst);
- DRM_DEBUG_DRIVER(" plane %d: chan=%d ovl=%d en=%d zpos=%d\n",
- plane->base.id, layer->channel, layer->overlay,
- enable, zpos);
-
- /*
- * We always update the layer enable bit, because it can clear
- * spontaneously for unknown reasons.
- */
- sun8i_layer_enable(layer, enable);
+ DRM_DEBUG_DRIVER(" plane %d: chan=%d ovl=%d en=%d zpos=%d x=%d y=%d w=%d h=%d\n",
+ plane->base.id, layer->index, layer->overlay,
+ enable, zpos, x, y, w, h);
if (!enable)
continue;
/* Route layer to pipe based on zpos */
- route |= layer->channel << SUN8I_MIXER_BLEND_ROUTE_PIPE_SHIFT(zpos);
+ route |= layer->index << SUN8I_MIXER_BLEND_ROUTE_PIPE_SHIFT(zpos);
pipe_en |= SUN8I_MIXER_BLEND_PIPE_CTL_EN(zpos);
+
+ regmap_write(bld_regs,
+ SUN8I_MIXER_BLEND_ATTR_COORD(bld_base, zpos),
+ SUN8I_MIXER_COORD(x, y));
+ regmap_write(bld_regs,
+ SUN8I_MIXER_BLEND_ATTR_INSIZE(bld_base, zpos),
+ SUN8I_MIXER_SIZE(w, h));
}
regmap_write(bld_regs, SUN8I_MIXER_BLEND_ROUTE(bld_base), route);
@@ -328,18 +316,30 @@ static struct drm_plane **sun8i_layers_init(struct drm_device *drm,
{
struct drm_plane **planes;
struct sun8i_mixer *mixer = engine_to_sun8i_mixer(engine);
+ int plane_cnt = mixer->cfg->ui_num + mixer->cfg->vi_num;
+ enum drm_plane_type type;
+ unsigned int phy_index;
int i;
- planes = devm_kcalloc(drm->dev,
- mixer->cfg->vi_num + mixer->cfg->ui_num + 1,
- sizeof(*planes), GFP_KERNEL);
+ planes = devm_kcalloc(drm->dev, plane_cnt, sizeof(*planes), GFP_KERNEL);
if (!planes)
return ERR_PTR(-ENOMEM);
for (i = 0; i < mixer->cfg->vi_num; i++) {
struct sun8i_layer *layer;
- layer = sun8i_vi_layer_init_one(drm, mixer, i);
+ if (i == 0 && !mixer->cfg->ui_num)
+ type = DRM_PLANE_TYPE_PRIMARY;
+ else
+ type = DRM_PLANE_TYPE_OVERLAY;
+
+ phy_index = i;
+ if (mixer->cfg->de_type == SUN8I_MIXER_DE33)
+ phy_index = mixer->cfg->map[i];
+
+ layer = sun8i_vi_layer_init_one(drm, type, mixer->engine.regs,
+ i, phy_index, plane_cnt,
+ &mixer->cfg->lay_cfg);
if (IS_ERR(layer)) {
dev_err(drm->dev,
"Couldn't initialize overlay plane\n");
@@ -350,16 +350,28 @@ static struct drm_plane **sun8i_layers_init(struct drm_device *drm,
}
for (i = 0; i < mixer->cfg->ui_num; i++) {
+ unsigned int index = mixer->cfg->vi_num + i;
struct sun8i_layer *layer;
- layer = sun8i_ui_layer_init_one(drm, mixer, i);
+ if (i == 0)
+ type = DRM_PLANE_TYPE_PRIMARY;
+ else
+ type = DRM_PLANE_TYPE_OVERLAY;
+
+ phy_index = index;
+ if (mixer->cfg->de_type == SUN8I_MIXER_DE33)
+ phy_index = mixer->cfg->map[index];
+
+ layer = sun8i_ui_layer_init_one(drm, type, mixer->engine.regs,
+ index, phy_index, plane_cnt,
+ &mixer->cfg->lay_cfg);
if (IS_ERR(layer)) {
dev_err(drm->dev, "Couldn't initialize %s plane\n",
i ? "overlay" : "primary");
return ERR_CAST(layer);
}
- planes[mixer->cfg->vi_num + i] = &layer->plane;
+ planes[index] = &layer->plane;
}
return planes;
@@ -692,119 +704,173 @@ static void sun8i_mixer_remove(struct platform_device *pdev)
}
static const struct sun8i_mixer_cfg sun8i_a83t_mixer0_cfg = {
- .ccsc = CCSC_MIXER0_LAYOUT,
+ .lay_cfg = {
+ .ccsc = CCSC_MIXER0_LAYOUT,
+ .de_type = SUN8I_MIXER_DE2,
+ .vi_scaler_num = 1,
+ .scaler_mask = 0xf,
+ .scanline_yuv = 2048,
+ .de2_fcc_alpha = 1,
+ },
.de_type = SUN8I_MIXER_DE2,
- .scaler_mask = 0xf,
- .scanline_yuv = 2048,
.ui_num = 3,
.vi_num = 1,
};
static const struct sun8i_mixer_cfg sun8i_a83t_mixer1_cfg = {
- .ccsc = CCSC_MIXER1_LAYOUT,
+ .lay_cfg = {
+ .ccsc = CCSC_MIXER1_LAYOUT,
+ .de_type = SUN8I_MIXER_DE2,
+ .vi_scaler_num = 1,
+ .scaler_mask = 0x3,
+ .scanline_yuv = 2048,
+ .de2_fcc_alpha = 1,
+ },
.de_type = SUN8I_MIXER_DE2,
- .scaler_mask = 0x3,
- .scanline_yuv = 2048,
.ui_num = 1,
.vi_num = 1,
};
static const struct sun8i_mixer_cfg sun8i_h3_mixer0_cfg = {
- .ccsc = CCSC_MIXER0_LAYOUT,
+ .lay_cfg = {
+ .ccsc = CCSC_MIXER0_LAYOUT,
+ .de_type = SUN8I_MIXER_DE2,
+ .vi_scaler_num = 1,
+ .scaler_mask = 0xf,
+ .scanline_yuv = 2048,
+ .de2_fcc_alpha = 1,
+ },
.de_type = SUN8I_MIXER_DE2,
.mod_rate = 432000000,
- .scaler_mask = 0xf,
- .scanline_yuv = 2048,
.ui_num = 3,
.vi_num = 1,
};
static const struct sun8i_mixer_cfg sun8i_r40_mixer0_cfg = {
- .ccsc = CCSC_MIXER0_LAYOUT,
+ .lay_cfg = {
+ .ccsc = CCSC_MIXER0_LAYOUT,
+ .de_type = SUN8I_MIXER_DE2,
+ .vi_scaler_num = 1,
+ .scaler_mask = 0xf,
+ .scanline_yuv = 2048,
+ .de2_fcc_alpha = 1,
+ },
.de_type = SUN8I_MIXER_DE2,
.mod_rate = 297000000,
- .scaler_mask = 0xf,
- .scanline_yuv = 2048,
.ui_num = 3,
.vi_num = 1,
};
static const struct sun8i_mixer_cfg sun8i_r40_mixer1_cfg = {
- .ccsc = CCSC_MIXER1_LAYOUT,
+ .lay_cfg = {
+ .ccsc = CCSC_MIXER1_LAYOUT,
+ .de_type = SUN8I_MIXER_DE2,
+ .vi_scaler_num = 1,
+ .scaler_mask = 0x3,
+ .scanline_yuv = 2048,
+ .de2_fcc_alpha = 1,
+ },
.de_type = SUN8I_MIXER_DE2,
.mod_rate = 297000000,
- .scaler_mask = 0x3,
- .scanline_yuv = 2048,
.ui_num = 1,
.vi_num = 1,
};
static const struct sun8i_mixer_cfg sun8i_v3s_mixer_cfg = {
- .de_type = SUN8I_MIXER_DE2,
- .vi_num = 2,
- .ui_num = 1,
- .scaler_mask = 0x3,
- .scanline_yuv = 2048,
- .ccsc = CCSC_MIXER0_LAYOUT,
- .mod_rate = 150000000,
+ .lay_cfg = {
+ .ccsc = CCSC_MIXER0_LAYOUT,
+ .de_type = SUN8I_MIXER_DE2,
+ .vi_scaler_num = 2,
+ .scaler_mask = 0x3,
+ .scanline_yuv = 2048,
+ },
+ .de_type = SUN8I_MIXER_DE2,
+ .mod_rate = 150000000,
+ .vi_num = 2,
+ .ui_num = 1,
};
static const struct sun8i_mixer_cfg sun20i_d1_mixer0_cfg = {
- .ccsc = CCSC_D1_MIXER0_LAYOUT,
+ .lay_cfg = {
+ .ccsc = CCSC_D1_MIXER0_LAYOUT,
+ .de_type = SUN8I_MIXER_DE2,
+ .vi_scaler_num = 1,
+ .scaler_mask = 0x3,
+ .scanline_yuv = 2048,
+ .de2_fcc_alpha = 1,
+ },
.de_type = SUN8I_MIXER_DE2,
.mod_rate = 297000000,
- .scaler_mask = 0x3,
- .scanline_yuv = 2048,
.ui_num = 1,
.vi_num = 1,
};
static const struct sun8i_mixer_cfg sun20i_d1_mixer1_cfg = {
- .ccsc = CCSC_MIXER1_LAYOUT,
+ .lay_cfg = {
+ .ccsc = CCSC_MIXER1_LAYOUT,
+ .de_type = SUN8I_MIXER_DE2,
+ .vi_scaler_num = 1,
+ .scaler_mask = 0x1,
+ .scanline_yuv = 1024,
+ .de2_fcc_alpha = 1,
+ },
.de_type = SUN8I_MIXER_DE2,
.mod_rate = 297000000,
- .scaler_mask = 0x1,
- .scanline_yuv = 1024,
.ui_num = 0,
.vi_num = 1,
};
static const struct sun8i_mixer_cfg sun50i_a64_mixer0_cfg = {
- .ccsc = CCSC_MIXER0_LAYOUT,
+ .lay_cfg = {
+ .ccsc = CCSC_MIXER0_LAYOUT,
+ .de_type = SUN8I_MIXER_DE2,
+ .vi_scaler_num = 1,
+ .scaler_mask = 0xf,
+ .scanline_yuv = 4096,
+ .de2_fcc_alpha = 1,
+ },
.de_type = SUN8I_MIXER_DE2,
.mod_rate = 297000000,
- .scaler_mask = 0xf,
- .scanline_yuv = 4096,
.ui_num = 3,
.vi_num = 1,
};
static const struct sun8i_mixer_cfg sun50i_a64_mixer1_cfg = {
- .ccsc = CCSC_MIXER1_LAYOUT,
+ .lay_cfg = {
+ .ccsc = CCSC_MIXER1_LAYOUT,
+ .de_type = SUN8I_MIXER_DE2,
+ .vi_scaler_num = 1,
+ .scaler_mask = 0x3,
+ .scanline_yuv = 2048,
+ .de2_fcc_alpha = 1,
+ },
.de_type = SUN8I_MIXER_DE2,
.mod_rate = 297000000,
- .scaler_mask = 0x3,
- .scanline_yuv = 2048,
.ui_num = 1,
.vi_num = 1,
};
static const struct sun8i_mixer_cfg sun50i_h6_mixer0_cfg = {
- .ccsc = CCSC_MIXER0_LAYOUT,
+ .lay_cfg = {
+ .de_type = SUN8I_MIXER_DE3,
+ .vi_scaler_num = 1,
+ .scaler_mask = 0xf,
+ .scanline_yuv = 4096,
+ },
.de_type = SUN8I_MIXER_DE3,
.mod_rate = 600000000,
- .scaler_mask = 0xf,
- .scanline_yuv = 4096,
.ui_num = 3,
.vi_num = 1,
};
static const struct sun8i_mixer_cfg sun50i_h616_mixer0_cfg = {
- .ccsc = CCSC_MIXER0_LAYOUT,
+ .lay_cfg = {
+ .de_type = SUN8I_MIXER_DE33,
+ .scaler_mask = 0xf,
+ .scanline_yuv = 4096,
+ },
.de_type = SUN8I_MIXER_DE33,
.mod_rate = 600000000,
- .scaler_mask = 0xf,
- .scanline_yuv = 4096,
.ui_num = 3,
.vi_num = 1,
.map = {0, 6, 7, 8},
diff --git a/drivers/gpu/drm/sun4i/sun8i_mixer.h b/drivers/gpu/drm/sun4i/sun8i_mixer.h
index a1c1cbccc654..e2f83301aae8 100644
--- a/drivers/gpu/drm/sun4i/sun8i_mixer.h
+++ b/drivers/gpu/drm/sun4i/sun8i_mixer.h
@@ -39,6 +39,9 @@
#define DE3_CH_BASE 0x1000
#define DE3_CH_SIZE 0x0800
+#define DE33_CH_BASE 0x1000
+#define DE33_CH_SIZE 0x20000
+
#define SUN8I_MIXER_BLEND_PIPE_CTL(base) ((base) + 0)
#define SUN8I_MIXER_BLEND_ATTR_FCOLOR(base, x) ((base) + 0x4 + 0x10 * (x))
#define SUN8I_MIXER_BLEND_ATTR_INSIZE(base, x) ((base) + 0x8 + 0x10 * (x))
@@ -161,29 +164,45 @@ enum sun8i_mixer_type {
};
/**
- * struct sun8i_mixer_cfg - mixer HW configuration
- * @vi_num: number of VI channels
- * @ui_num: number of UI channels
+ * struct sun8i_layer_cfg - layer configuration
+ * @vi_scaler_num: Number of VI scalers. Used on DE2 and DE3.
* @scaler_mask: bitmask which tells which channel supports scaling
* First, scaler supports for VI channels is defined and after that, scaler
* support for UI channels. For example, if mixer has 2 VI channels without
* scaler and 2 UI channels with scaler, bitmask would be 0xC.
* @ccsc: select set of CCSC base addresses from the enumeration above.
- * @mod_rate: module clock rate that needs to be set in order to have
- * a functional block.
* @de_type: sun8i_mixer_type enum representing the display engine generation.
* @scaline_yuv: size of a scanline for VI scaler for YUV formats.
- * @map: channel map for DE variants processing YUV separately (DE33)
+ * @de2_fcc_alpha: use FCC for missing DE2 VI alpha capability
+ * Most DE2 cores has FCC. If number of VI planes is one, enable this.
*/
-struct sun8i_mixer_cfg {
- int vi_num;
- int ui_num;
+struct sun8i_layer_cfg {
+ unsigned int vi_scaler_num;
int scaler_mask;
int ccsc;
- unsigned long mod_rate;
unsigned int de_type;
unsigned int scanline_yuv;
- unsigned int map[6];
+ unsigned int de2_fcc_alpha : 1;
+};
+
+/**
+ * struct sun8i_mixer_cfg - mixer HW configuration
+ * @lay_cfg: layer configuration
+ * @vi_num: number of VI channels
+ * @ui_num: number of UI channels
+ * @de_type: sun8i_mixer_type enum representing the display engine generation.
+ * @mod_rate: module clock rate that needs to be set in order to have
+ * a functional block.
+ * @map: channel map for DE variants processing YUV separately (DE33)
+ */
+
+struct sun8i_mixer_cfg {
+ struct sun8i_layer_cfg lay_cfg;
+ int vi_num;
+ int ui_num;
+ unsigned int de_type;
+ unsigned long mod_rate;
+ unsigned int map[6];
};
struct sun8i_mixer {
@@ -206,11 +225,13 @@ enum {
};
struct sun8i_layer {
- struct drm_plane plane;
- struct sun8i_mixer *mixer;
- int type;
- int channel;
- int overlay;
+ struct drm_plane plane;
+ int type;
+ int index;
+ int channel;
+ int overlay;
+ struct regmap *regs;
+ const struct sun8i_layer_cfg *cfg;
};
static inline struct sun8i_layer *
@@ -239,14 +260,14 @@ sun8i_blender_regmap(struct sun8i_mixer *mixer)
}
static inline u32
-sun8i_channel_base(struct sun8i_mixer *mixer, int channel)
+sun8i_channel_base(struct sun8i_layer *layer)
{
- 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;
+ if (layer->cfg->de_type == SUN8I_MIXER_DE33)
+ return DE33_CH_BASE + layer->channel * DE33_CH_SIZE;
+ else if (layer->cfg->de_type == SUN8I_MIXER_DE3)
+ return DE3_CH_BASE + layer->channel * DE3_CH_SIZE;
else
- return DE2_CH_BASE + channel * DE2_CH_SIZE;
+ return DE2_CH_BASE + layer->channel * DE2_CH_SIZE;
}
int sun8i_mixer_drm_format_to_hw(u32 format, u32 *hw_format);
diff --git a/drivers/gpu/drm/sun4i/sun8i_ui_layer.c b/drivers/gpu/drm/sun4i/sun8i_ui_layer.c
index f97be0040aab..f08f6da55dd0 100644
--- a/drivers/gpu/drm/sun4i/sun8i_ui_layer.c
+++ b/drivers/gpu/drm/sun4i/sun8i_ui_layer.c
@@ -18,6 +18,7 @@
#include <drm/drm_framebuffer.h>
#include <drm/drm_gem_atomic_helper.h>
#include <drm/drm_gem_dma_helper.h>
+#include <drm/drm_print.h>
#include <drm/drm_probe_helper.h>
#include "sun8i_mixer.h"
@@ -25,44 +26,49 @@
#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)
+static void sun8i_ui_layer_disable(struct sun8i_layer *layer)
{
- u32 mask, val, ch_base;
+ u32 ch_base = sun8i_channel_base(layer);
- ch_base = sun8i_channel_base(mixer, channel);
+ regmap_write(layer->regs,
+ SUN8I_MIXER_CHAN_UI_LAYER_ATTR(ch_base, layer->overlay), 0);
+}
- mask = SUN8I_MIXER_CHAN_UI_LAYER_ATTR_ALPHA_MODE_MASK |
- SUN8I_MIXER_CHAN_UI_LAYER_ATTR_ALPHA_MASK;
+static void sun8i_ui_layer_update_attributes(struct sun8i_layer *layer,
+ struct drm_plane *plane)
+{
+ struct drm_plane_state *state = plane->state;
+ const struct drm_format_info *fmt;
+ u32 val, ch_base, hw_fmt;
- val = SUN8I_MIXER_CHAN_UI_LAYER_ATTR_ALPHA(plane->state->alpha >> 8);
+ ch_base = sun8i_channel_base(layer);
+ fmt = state->fb->format;
+ sun8i_mixer_drm_format_to_hw(fmt->format, &hw_fmt);
- val |= (plane->state->alpha == DRM_BLEND_ALPHA_OPAQUE) ?
+ val = SUN8I_MIXER_CHAN_UI_LAYER_ATTR_ALPHA(state->alpha >> 8);
+ val |= (state->alpha == DRM_BLEND_ALPHA_OPAQUE) ?
SUN8I_MIXER_CHAN_UI_LAYER_ATTR_ALPHA_MODE_PIXEL :
SUN8I_MIXER_CHAN_UI_LAYER_ATTR_ALPHA_MODE_COMBINED;
+ val |= hw_fmt << SUN8I_MIXER_CHAN_UI_LAYER_ATTR_FBFMT_OFFSET;
+ val |= SUN8I_MIXER_CHAN_UI_LAYER_ATTR_EN;
- regmap_update_bits(mixer->engine.regs,
- SUN8I_MIXER_CHAN_UI_LAYER_ATTR(ch_base, overlay),
- mask, val);
+ regmap_write(layer->regs,
+ SUN8I_MIXER_CHAN_UI_LAYER_ATTR(ch_base, layer->overlay), val);
}
-static int sun8i_ui_layer_update_coord(struct sun8i_mixer *mixer, int channel,
- int overlay, struct drm_plane *plane,
- unsigned int zpos)
+static void sun8i_ui_layer_update_coord(struct sun8i_layer *layer,
+ struct drm_plane *plane)
{
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;
+ u32 ch_base;
DRM_DEBUG_DRIVER("Updating UI channel %d overlay %d\n",
- channel, overlay);
+ layer->channel, layer->overlay);
- bld_base = sun8i_blender_base(mixer);
- bld_regs = sun8i_blender_regmap(mixer);
- ch_base = sun8i_channel_base(mixer, channel);
+ ch_base = sun8i_channel_base(layer);
src_w = drm_rect_width(&state->src) >> 16;
src_h = drm_rect_height(&state->src) >> 16;
@@ -79,10 +85,10 @@ static int sun8i_ui_layer_update_coord(struct sun8i_mixer *mixer, int channel,
DRM_DEBUG_DRIVER("Layer source offset X: %d Y: %d\n",
state->src.x1 >> 16, state->src.y1 >> 16);
DRM_DEBUG_DRIVER("Layer source size W: %d H: %d\n", src_w, src_h);
- regmap_write(mixer->engine.regs,
- SUN8I_MIXER_CHAN_UI_LAYER_SIZE(ch_base, overlay),
+ regmap_write(layer->regs,
+ SUN8I_MIXER_CHAN_UI_LAYER_SIZE(ch_base, layer->overlay),
insize);
- regmap_write(mixer->engine.regs,
+ regmap_write(layer->regs,
SUN8I_MIXER_CHAN_UI_OVL_SIZE(ch_base),
insize);
@@ -94,67 +100,27 @@ 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;
- 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,
+ if (layer->cfg->de_type == SUN8I_MIXER_DE33) {
+ sun8i_vi_scaler_setup(layer, src_w, src_h, dst_w, dst_h,
+ hscale, vscale, hphase, vphase,
state->fb->format);
- sun8i_vi_scaler_enable(mixer, channel, true);
+ sun8i_vi_scaler_enable(layer, true);
} 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);
+ sun8i_ui_scaler_setup(layer, src_w, src_h, dst_w, dst_h,
+ hscale, vscale, hphase, vphase);
+ sun8i_ui_scaler_enable(layer, true);
}
} else {
DRM_DEBUG_DRIVER("HW scaling is not needed\n");
- if (mixer->cfg->de_type == SUN8I_MIXER_DE33)
- sun8i_vi_scaler_enable(mixer, channel, false);
+ if (layer->cfg->de_type == SUN8I_MIXER_DE33)
+ sun8i_vi_scaler_enable(layer, false);
else
- sun8i_ui_scaler_enable(mixer, channel, false);
+ sun8i_ui_scaler_enable(layer, false);
}
-
- /* Set base coordinates */
- 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(bld_regs,
- SUN8I_MIXER_BLEND_ATTR_COORD(bld_base, zpos),
- SUN8I_MIXER_COORD(state->dst.x1, state->dst.y1));
- regmap_write(bld_regs,
- SUN8I_MIXER_BLEND_ATTR_INSIZE(bld_base, zpos),
- outsize);
-
- return 0;
}
-static int sun8i_ui_layer_update_formats(struct sun8i_mixer *mixer, int channel,
- int overlay, struct drm_plane *plane)
-{
- struct drm_plane_state *state = plane->state;
- const struct drm_format_info *fmt;
- u32 val, ch_base, hw_fmt;
- int ret;
-
- ch_base = sun8i_channel_base(mixer, channel);
-
- fmt = state->fb->format;
- ret = sun8i_mixer_drm_format_to_hw(fmt->format, &hw_fmt);
- if (ret || fmt->is_yuv) {
- DRM_DEBUG_DRIVER("Invalid format\n");
- return -EINVAL;
- }
-
- val = hw_fmt << SUN8I_MIXER_CHAN_UI_LAYER_ATTR_FBFMT_OFFSET;
- regmap_update_bits(mixer->engine.regs,
- SUN8I_MIXER_CHAN_UI_LAYER_ATTR(ch_base, overlay),
- SUN8I_MIXER_CHAN_UI_LAYER_ATTR_FBFMT_MASK, val);
-
- return 0;
-}
-
-static int sun8i_ui_layer_update_buffer(struct sun8i_mixer *mixer, int channel,
- int overlay, struct drm_plane *plane)
+static void sun8i_ui_layer_update_buffer(struct sun8i_layer *layer,
+ struct drm_plane *plane)
{
struct drm_plane_state *state = plane->state;
struct drm_framebuffer *fb = state->fb;
@@ -163,7 +129,7 @@ static int sun8i_ui_layer_update_buffer(struct sun8i_mixer *mixer, int channel,
u32 ch_base;
int bpp;
- ch_base = sun8i_channel_base(mixer, channel);
+ ch_base = sun8i_channel_base(layer);
/* Get the physical address of the buffer in memory */
gem = drm_fb_dma_get_gem_obj(fb, 0);
@@ -180,17 +146,15 @@ static int sun8i_ui_layer_update_buffer(struct sun8i_mixer *mixer, int channel,
/* Set the line width */
DRM_DEBUG_DRIVER("Layer line width: %d bytes\n", fb->pitches[0]);
- regmap_write(mixer->engine.regs,
- SUN8I_MIXER_CHAN_UI_LAYER_PITCH(ch_base, overlay),
+ regmap_write(layer->regs,
+ SUN8I_MIXER_CHAN_UI_LAYER_PITCH(ch_base, layer->overlay),
fb->pitches[0]);
DRM_DEBUG_DRIVER("Setting buffer address to %pad\n", &dma_addr);
- regmap_write(mixer->engine.regs,
- SUN8I_MIXER_CHAN_UI_LAYER_TOP_LADDR(ch_base, overlay),
+ regmap_write(layer->regs,
+ SUN8I_MIXER_CHAN_UI_LAYER_TOP_LADDR(ch_base, layer->overlay),
lower_32_bits(dma_addr));
-
- return 0;
}
static int sun8i_ui_layer_atomic_check(struct drm_plane *plane,
@@ -201,20 +165,28 @@ static int sun8i_ui_layer_atomic_check(struct drm_plane *plane,
struct sun8i_layer *layer = plane_to_sun8i_layer(plane);
struct drm_crtc *crtc = new_plane_state->crtc;
struct drm_crtc_state *crtc_state;
- int min_scale, max_scale;
+ const struct drm_format_info *fmt;
+ int min_scale, max_scale, ret;
+ u32 hw_fmt;
if (!crtc)
return 0;
- crtc_state = drm_atomic_get_existing_crtc_state(state,
- crtc);
+ crtc_state = drm_atomic_get_new_crtc_state(state, crtc);
if (WARN_ON(!crtc_state))
return -EINVAL;
+ fmt = new_plane_state->fb->format;
+ ret = sun8i_mixer_drm_format_to_hw(fmt->format, &hw_fmt);
+ if (ret || fmt->is_yuv) {
+ DRM_DEBUG_DRIVER("Invalid plane format\n");
+ return -EINVAL;
+ }
+
min_scale = DRM_PLANE_NO_SCALING;
max_scale = DRM_PLANE_NO_SCALING;
- if (layer->mixer->cfg->scaler_mask & BIT(layer->channel)) {
+ if (layer->cfg->scaler_mask & BIT(layer->channel)) {
min_scale = SUN8I_UI_SCALER_SCALE_MIN;
max_scale = SUN8I_UI_SCALER_SCALE_MAX;
}
@@ -232,20 +204,15 @@ static void sun8i_ui_layer_atomic_update(struct drm_plane *plane,
struct drm_plane_state *new_state = drm_atomic_get_new_plane_state(state,
plane);
struct sun8i_layer *layer = plane_to_sun8i_layer(plane);
- unsigned int zpos = new_state->normalized_zpos;
- struct sun8i_mixer *mixer = layer->mixer;
- if (!new_state->crtc || !new_state->visible)
+ if (!new_state->crtc || !new_state->visible) {
+ sun8i_ui_layer_disable(layer);
return;
+ }
- sun8i_ui_layer_update_coord(mixer, layer->channel,
- layer->overlay, plane, zpos);
- sun8i_ui_layer_update_alpha(mixer, layer->channel,
- layer->overlay, plane);
- sun8i_ui_layer_update_formats(mixer, layer->channel,
- layer->overlay, plane);
- sun8i_ui_layer_update_buffer(mixer, layer->channel,
- layer->overlay, plane);
+ sun8i_ui_layer_update_attributes(layer, plane);
+ sun8i_ui_layer_update_coord(layer, plane);
+ sun8i_ui_layer_update_buffer(layer, plane);
}
static const struct drm_plane_helper_funcs sun8i_ui_layer_helper_funcs = {
@@ -291,21 +258,25 @@ static const uint64_t sun8i_layer_modifiers[] = {
};
struct sun8i_layer *sun8i_ui_layer_init_one(struct drm_device *drm,
- struct sun8i_mixer *mixer,
- int index)
+ enum drm_plane_type type,
+ struct regmap *regs,
+ int index, int phy_index,
+ int plane_cnt,
+ const struct sun8i_layer_cfg *cfg)
{
- enum drm_plane_type type = DRM_PLANE_TYPE_OVERLAY;
- int channel = mixer->cfg->vi_num + index;
struct sun8i_layer *layer;
- unsigned int plane_cnt;
int ret;
layer = devm_kzalloc(drm->dev, sizeof(*layer), GFP_KERNEL);
if (!layer)
return ERR_PTR(-ENOMEM);
- if (index == 0)
- type = DRM_PLANE_TYPE_PRIMARY;
+ layer->type = SUN8I_LAYER_TYPE_UI;
+ layer->index = index;
+ layer->channel = phy_index;
+ layer->overlay = 0;
+ layer->regs = regs;
+ layer->cfg = cfg;
/* possible crtcs are set later */
ret = drm_universal_plane_init(drm, &layer->plane, 0,
@@ -318,15 +289,13 @@ struct sun8i_layer *sun8i_ui_layer_init_one(struct drm_device *drm,
return ERR_PTR(ret);
}
- plane_cnt = mixer->cfg->ui_num + mixer->cfg->vi_num;
-
ret = drm_plane_create_alpha_property(&layer->plane);
if (ret) {
dev_err(drm->dev, "Couldn't add alpha property\n");
return ERR_PTR(ret);
}
- ret = drm_plane_create_zpos_property(&layer->plane, channel,
+ ret = drm_plane_create_zpos_property(&layer->plane, index,
0, plane_cnt - 1);
if (ret) {
dev_err(drm->dev, "Couldn't add zpos property\n");
@@ -334,10 +303,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_ui_layer.h b/drivers/gpu/drm/sun4i/sun8i_ui_layer.h
index 83892f6ff211..1581ffc6d4e5 100644
--- a/drivers/gpu/drm/sun4i/sun8i_ui_layer.h
+++ b/drivers/gpu/drm/sun4i/sun8i_ui_layer.h
@@ -50,6 +50,9 @@ struct sun8i_mixer;
struct sun8i_layer;
struct sun8i_layer *sun8i_ui_layer_init_one(struct drm_device *drm,
- struct sun8i_mixer *mixer,
- int index);
+ enum drm_plane_type type,
+ struct regmap *regs,
+ int index, int phy_index,
+ int plane_cnt,
+ const struct sun8i_layer_cfg *cfg);
#endif /* _SUN8I_UI_LAYER_H_ */
diff --git a/drivers/gpu/drm/sun4i/sun8i_ui_scaler.c b/drivers/gpu/drm/sun4i/sun8i_ui_scaler.c
index 8b7a58e27517..a178da8f532a 100644
--- a/drivers/gpu/drm/sun4i/sun8i_ui_scaler.c
+++ b/drivers/gpu/drm/sun4i/sun8i_ui_scaler.c
@@ -89,18 +89,18 @@ static const u32 lan2coefftab16[240] = {
0x0b1c1603, 0x0d1c1502, 0x0e1d1401, 0x0f1d1301,
};
-static u32 sun8i_ui_scaler_base(struct sun8i_mixer *mixer, int channel)
+static u32 sun8i_ui_scaler_base(struct sun8i_layer *layer)
{
- int vi_num = mixer->cfg->vi_num;
+ int offset = layer->cfg->vi_scaler_num;
- if (mixer->cfg->de_type == SUN8I_MIXER_DE3)
+ if (layer->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);
+ DE3_VI_SCALER_UNIT_SIZE * offset +
+ DE3_UI_SCALER_UNIT_SIZE * (layer->channel - offset);
else
return DE2_VI_SCALER_UNIT_BASE +
- DE2_VI_SCALER_UNIT_SIZE * vi_num +
- DE2_UI_SCALER_UNIT_SIZE * (channel - vi_num);
+ DE2_VI_SCALER_UNIT_SIZE * offset +
+ DE2_UI_SCALER_UNIT_SIZE * (layer->channel - offset);
}
static int sun8i_ui_scaler_coef_index(unsigned int step)
@@ -127,14 +127,11 @@ static int sun8i_ui_scaler_coef_index(unsigned int step)
}
}
-void sun8i_ui_scaler_enable(struct sun8i_mixer *mixer, int layer, bool enable)
+void sun8i_ui_scaler_enable(struct sun8i_layer *layer, bool enable)
{
u32 val, base;
- if (WARN_ON(layer < mixer->cfg->vi_num))
- return;
-
- base = sun8i_ui_scaler_base(mixer, layer);
+ base = sun8i_ui_scaler_base(layer);
if (enable)
val = SUN8I_SCALER_GSU_CTRL_EN |
@@ -142,10 +139,10 @@ void sun8i_ui_scaler_enable(struct sun8i_mixer *mixer, int layer, bool enable)
else
val = 0;
- regmap_write(mixer->engine.regs, SUN8I_SCALER_GSU_CTRL(base), val);
+ regmap_write(layer->regs, SUN8I_SCALER_GSU_CTRL(base), val);
}
-void sun8i_ui_scaler_setup(struct sun8i_mixer *mixer, int layer,
+void sun8i_ui_scaler_setup(struct sun8i_layer *layer,
u32 src_w, u32 src_h, u32 dst_w, u32 dst_h,
u32 hscale, u32 vscale, u32 hphase, u32 vphase)
{
@@ -153,10 +150,7 @@ void sun8i_ui_scaler_setup(struct sun8i_mixer *mixer, int layer,
int i, offset;
u32 base;
- if (WARN_ON(layer < mixer->cfg->vi_num))
- return;
-
- base = sun8i_ui_scaler_base(mixer, layer);
+ base = sun8i_ui_scaler_base(layer);
hphase <<= SUN8I_UI_SCALER_PHASE_FRAC - 16;
vphase <<= SUN8I_UI_SCALER_PHASE_FRAC - 16;
@@ -166,22 +160,22 @@ void sun8i_ui_scaler_setup(struct sun8i_mixer *mixer, int layer,
insize = SUN8I_UI_SCALER_SIZE(src_w, src_h);
outsize = SUN8I_UI_SCALER_SIZE(dst_w, dst_h);
- regmap_write(mixer->engine.regs,
+ regmap_write(layer->regs,
SUN8I_SCALER_GSU_OUTSIZE(base), outsize);
- regmap_write(mixer->engine.regs,
+ regmap_write(layer->regs,
SUN8I_SCALER_GSU_INSIZE(base), insize);
- regmap_write(mixer->engine.regs,
+ regmap_write(layer->regs,
SUN8I_SCALER_GSU_HSTEP(base), hscale);
- regmap_write(mixer->engine.regs,
+ regmap_write(layer->regs,
SUN8I_SCALER_GSU_VSTEP(base), vscale);
- regmap_write(mixer->engine.regs,
+ regmap_write(layer->regs,
SUN8I_SCALER_GSU_HPHASE(base), hphase);
- regmap_write(mixer->engine.regs,
+ regmap_write(layer->regs,
SUN8I_SCALER_GSU_VPHASE(base), vphase);
offset = sun8i_ui_scaler_coef_index(hscale) *
SUN8I_UI_SCALER_COEFF_COUNT;
for (i = 0; i < SUN8I_UI_SCALER_COEFF_COUNT; i++)
- regmap_write(mixer->engine.regs,
+ regmap_write(layer->regs,
SUN8I_SCALER_GSU_HCOEFF(base, i),
lan2coefftab16[offset + i]);
}
diff --git a/drivers/gpu/drm/sun4i/sun8i_ui_scaler.h b/drivers/gpu/drm/sun4i/sun8i_ui_scaler.h
index 1ef4bd6f2718..872d88a58e7e 100644
--- a/drivers/gpu/drm/sun4i/sun8i_ui_scaler.h
+++ b/drivers/gpu/drm/sun4i/sun8i_ui_scaler.h
@@ -35,8 +35,8 @@
#define SUN8I_SCALER_GSU_CTRL_EN BIT(0)
#define SUN8I_SCALER_GSU_CTRL_COEFF_RDY BIT(4)
-void sun8i_ui_scaler_enable(struct sun8i_mixer *mixer, int layer, bool enable);
-void sun8i_ui_scaler_setup(struct sun8i_mixer *mixer, int layer,
+void sun8i_ui_scaler_enable(struct sun8i_layer *layer, bool enable);
+void sun8i_ui_scaler_setup(struct sun8i_layer *layer,
u32 src_w, u32 src_h, u32 dst_w, u32 dst_h,
u32 hscale, u32 vscale, u32 hphase, u32 vphase);
diff --git a/drivers/gpu/drm/sun4i/sun8i_vi_layer.c b/drivers/gpu/drm/sun4i/sun8i_vi_layer.c
index a09ee4097537..ca3ab59e108d 100644
--- a/drivers/gpu/drm/sun4i/sun8i_vi_layer.c
+++ b/drivers/gpu/drm/sun4i/sun8i_vi_layer.c
@@ -11,64 +11,74 @@
#include <drm/drm_framebuffer.h>
#include <drm/drm_gem_atomic_helper.h>
#include <drm/drm_gem_dma_helper.h>
+#include <drm/drm_print.h>
#include <drm/drm_probe_helper.h>
+#include "sun4i_crtc.h"
#include "sun8i_csc.h"
#include "sun8i_mixer.h"
#include "sun8i_vi_layer.h"
#include "sun8i_vi_scaler.h"
-static void sun8i_vi_layer_update_alpha(struct sun8i_mixer *mixer, int channel,
- int overlay, struct drm_plane *plane)
+static void sun8i_vi_layer_disable(struct sun8i_layer *layer)
{
- u32 mask, val, ch_base;
+ u32 ch_base = sun8i_channel_base(layer);
- ch_base = sun8i_channel_base(mixer, channel);
+ regmap_write(layer->regs,
+ SUN8I_MIXER_CHAN_VI_LAYER_ATTR(ch_base, layer->overlay), 0);
+}
- 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
- (plane->state->alpha >> 8);
+static void sun8i_vi_layer_update_attributes(struct sun8i_layer *layer,
+ struct drm_plane *plane)
+{
+ struct drm_plane_state *state = plane->state;
+ const struct drm_format_info *fmt;
+ u32 val, ch_base, hw_fmt;
- val |= (plane->state->alpha == DRM_BLEND_ALPHA_OPAQUE) ?
+ ch_base = sun8i_channel_base(layer);
+ fmt = state->fb->format;
+ sun8i_mixer_drm_format_to_hw(fmt->format, &hw_fmt);
+
+ val = hw_fmt << SUN8I_MIXER_CHAN_VI_LAYER_ATTR_FBFMT_OFFSET;
+ if (!fmt->is_yuv)
+ val |= SUN8I_MIXER_CHAN_VI_LAYER_ATTR_RGB_MODE;
+ val |= SUN8I_MIXER_CHAN_VI_LAYER_ATTR_EN;
+ if (layer->cfg->de_type >= SUN8I_MIXER_DE3) {
+ val |= SUN50I_MIXER_CHAN_VI_LAYER_ATTR_ALPHA(state->alpha >> 8);
+ val |= (state->alpha == DRM_BLEND_ALPHA_OPAQUE) ?
SUN50I_MIXER_CHAN_VI_LAYER_ATTR_ALPHA_MODE_PIXEL :
SUN50I_MIXER_CHAN_VI_LAYER_ATTR_ALPHA_MODE_COMBINED;
+ }
+
+ regmap_write(layer->regs,
+ SUN8I_MIXER_CHAN_VI_LAYER_ATTR(ch_base, layer->overlay), val);
- regmap_update_bits(mixer->engine.regs,
- SUN8I_MIXER_CHAN_VI_LAYER_ATTR(ch_base,
- overlay),
- mask, val);
- } else if (mixer->cfg->vi_num == 1) {
- regmap_update_bits(mixer->engine.regs,
- SUN8I_MIXER_FCC_GLOBAL_ALPHA_REG,
- SUN8I_MIXER_FCC_GLOBAL_ALPHA_MASK,
- SUN8I_MIXER_FCC_GLOBAL_ALPHA
- (plane->state->alpha >> 8));
+ if (layer->cfg->de2_fcc_alpha) {
+ regmap_write(layer->regs,
+ SUN8I_MIXER_FCC_GLOBAL_ALPHA_REG,
+ SUN8I_MIXER_FCC_GLOBAL_ALPHA(state->alpha >> 8));
}
}
-static int sun8i_vi_layer_update_coord(struct sun8i_mixer *mixer, int channel,
- int overlay, struct drm_plane *plane,
- unsigned int zpos)
+static void sun8i_vi_layer_update_coord(struct sun8i_layer *layer,
+ struct drm_plane *plane)
{
struct drm_plane_state *state = plane->state;
+ struct sun4i_crtc *scrtc = drm_crtc_to_sun4i_crtc(state->crtc);
+ struct sun8i_mixer *mixer = engine_to_sun8i_mixer(scrtc->engine);
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;
u32 hn = 0, hm = 0;
u32 vn = 0, vm = 0;
bool subsampled;
+ u32 ch_base;
DRM_DEBUG_DRIVER("Updating VI channel %d overlay %d\n",
- channel, overlay);
+ layer->channel, layer->overlay);
- bld_base = sun8i_blender_base(mixer);
- bld_regs = sun8i_blender_regmap(mixer);
- ch_base = sun8i_channel_base(mixer, channel);
+ ch_base = sun8i_channel_base(layer);
src_w = drm_rect_width(&state->src) >> 16;
src_h = drm_rect_height(&state->src) >> 16;
@@ -105,10 +115,10 @@ static int sun8i_vi_layer_update_coord(struct sun8i_mixer *mixer, int channel,
(state->src.x1 >> 16) & ~(format->hsub - 1),
(state->src.y1 >> 16) & ~(format->vsub - 1));
DRM_DEBUG_DRIVER("Layer source size W: %d H: %d\n", src_w, src_h);
- regmap_write(mixer->engine.regs,
- SUN8I_MIXER_CHAN_VI_LAYER_SIZE(ch_base, overlay),
+ regmap_write(layer->regs,
+ SUN8I_MIXER_CHAN_VI_LAYER_SIZE(ch_base, layer->overlay),
insize);
- regmap_write(mixer->engine.regs,
+ regmap_write(layer->regs,
SUN8I_MIXER_CHAN_VI_OVL_SIZE(ch_base),
insize);
@@ -143,7 +153,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;
+ scanline = subsampled ? layer->cfg->scanline_yuv : 2048;
if (src_w > scanline) {
DRM_DEBUG_DRIVER("Using horizontal coarse scaling\n");
@@ -155,108 +165,34 @@ static int sun8i_vi_layer_update_coord(struct sun8i_mixer *mixer, int channel,
hscale = (src_w << 16) / dst_w;
vscale = (src_h << 16) / dst_h;
- 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);
+ sun8i_vi_scaler_setup(layer, src_w, src_h, dst_w, dst_h,
+ hscale, vscale, hphase, vphase, format);
+ sun8i_vi_scaler_enable(layer, true);
} else {
DRM_DEBUG_DRIVER("HW scaling is not needed\n");
- sun8i_vi_scaler_enable(mixer, channel, false);
+ sun8i_vi_scaler_enable(layer, false);
}
- regmap_write(mixer->engine.regs,
+ regmap_write(layer->regs,
SUN8I_MIXER_CHAN_VI_HDS_Y(ch_base),
SUN8I_MIXER_CHAN_VI_DS_N(hn) |
SUN8I_MIXER_CHAN_VI_DS_M(hm));
- regmap_write(mixer->engine.regs,
+ regmap_write(layer->regs,
SUN8I_MIXER_CHAN_VI_HDS_UV(ch_base),
SUN8I_MIXER_CHAN_VI_DS_N(hn) |
SUN8I_MIXER_CHAN_VI_DS_M(hm));
- regmap_write(mixer->engine.regs,
+ regmap_write(layer->regs,
SUN8I_MIXER_CHAN_VI_VDS_Y(ch_base),
SUN8I_MIXER_CHAN_VI_DS_N(vn) |
SUN8I_MIXER_CHAN_VI_DS_M(vm));
- regmap_write(mixer->engine.regs,
+ regmap_write(layer->regs,
SUN8I_MIXER_CHAN_VI_VDS_UV(ch_base),
SUN8I_MIXER_CHAN_VI_DS_N(vn) |
SUN8I_MIXER_CHAN_VI_DS_M(vm));
-
- /* Set base coordinates */
- 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(bld_regs,
- SUN8I_MIXER_BLEND_ATTR_COORD(bld_base, zpos),
- SUN8I_MIXER_COORD(state->dst.x1, state->dst.y1));
- regmap_write(bld_regs,
- SUN8I_MIXER_BLEND_ATTR_INSIZE(bld_base, zpos),
- outsize);
-
- return 0;
-}
-
-static u32 sun8i_vi_layer_get_csc_mode(const struct drm_format_info *format)
-{
- if (!format->is_yuv)
- return SUN8I_CSC_MODE_OFF;
-
- switch (format->format) {
- case DRM_FORMAT_YVU411:
- case DRM_FORMAT_YVU420:
- case DRM_FORMAT_YVU422:
- case DRM_FORMAT_YVU444:
- return SUN8I_CSC_MODE_YVU2RGB;
- default:
- return SUN8I_CSC_MODE_YUV2RGB;
- }
-}
-
-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;
- const struct drm_format_info *fmt;
- int ret;
-
- ch_base = sun8i_channel_base(mixer, channel);
-
- fmt = state->fb->format;
- ret = sun8i_mixer_drm_format_to_hw(fmt->format, &hw_fmt);
- if (ret) {
- DRM_DEBUG_DRIVER("Invalid format\n");
- return ret;
- }
-
- val = hw_fmt << SUN8I_MIXER_CHAN_VI_LAYER_ATTR_FBFMT_OFFSET;
- regmap_update_bits(mixer->engine.regs,
- 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,
- state->color_encoding,
- state->color_range);
- sun8i_csc_enable_ccsc(mixer, channel, true);
- } else {
- sun8i_csc_enable_ccsc(mixer, channel, false);
- }
-
- if (!fmt->is_yuv)
- val = SUN8I_MIXER_CHAN_VI_LAYER_ATTR_RGB_MODE;
- else
- val = 0;
-
- regmap_update_bits(mixer->engine.regs,
- SUN8I_MIXER_CHAN_VI_LAYER_ATTR(ch_base, overlay),
- SUN8I_MIXER_CHAN_VI_LAYER_ATTR_RGB_MODE, val);
-
- return 0;
}
-static int sun8i_vi_layer_update_buffer(struct sun8i_mixer *mixer, int channel,
- int overlay, struct drm_plane *plane)
+static void sun8i_vi_layer_update_buffer(struct sun8i_layer *layer,
+ struct drm_plane *plane)
{
struct drm_plane_state *state = plane->state;
struct drm_framebuffer *fb = state->fb;
@@ -267,7 +203,7 @@ static int sun8i_vi_layer_update_buffer(struct sun8i_mixer *mixer, int channel,
u32 ch_base;
int i;
- ch_base = sun8i_channel_base(mixer, channel);
+ ch_base = sun8i_channel_base(layer);
/* Adjust x and y to be dividable by subsampling factor */
src_x = (state->src.x1 >> 16) & ~(format->hsub - 1);
@@ -297,21 +233,19 @@ static int sun8i_vi_layer_update_buffer(struct sun8i_mixer *mixer, int channel,
/* Set the line width */
DRM_DEBUG_DRIVER("Layer %d. line width: %d bytes\n",
i + 1, fb->pitches[i]);
- regmap_write(mixer->engine.regs,
+ regmap_write(layer->regs,
SUN8I_MIXER_CHAN_VI_LAYER_PITCH(ch_base,
- overlay, i),
+ layer->overlay, i),
fb->pitches[i]);
DRM_DEBUG_DRIVER("Setting %d. buffer address to %pad\n",
i + 1, &dma_addr);
- regmap_write(mixer->engine.regs,
+ regmap_write(layer->regs,
SUN8I_MIXER_CHAN_VI_LAYER_TOP_LADDR(ch_base,
- overlay, i),
+ layer->overlay, i),
lower_32_bits(dma_addr));
}
-
- return 0;
}
static int sun8i_vi_layer_atomic_check(struct drm_plane *plane,
@@ -322,20 +256,28 @@ static int sun8i_vi_layer_atomic_check(struct drm_plane *plane,
struct sun8i_layer *layer = plane_to_sun8i_layer(plane);
struct drm_crtc *crtc = new_plane_state->crtc;
struct drm_crtc_state *crtc_state;
- int min_scale, max_scale;
+ const struct drm_format_info *fmt;
+ int min_scale, max_scale, ret;
+ u32 hw_fmt;
if (!crtc)
return 0;
- crtc_state = drm_atomic_get_existing_crtc_state(state,
- crtc);
+ crtc_state = drm_atomic_get_new_crtc_state(state, crtc);
if (WARN_ON(!crtc_state))
return -EINVAL;
+ fmt = new_plane_state->fb->format;
+ ret = sun8i_mixer_drm_format_to_hw(fmt->format, &hw_fmt);
+ if (ret) {
+ DRM_DEBUG_DRIVER("Invalid plane format\n");
+ return ret;
+ }
+
min_scale = DRM_PLANE_NO_SCALING;
max_scale = DRM_PLANE_NO_SCALING;
- if (layer->mixer->cfg->scaler_mask & BIT(layer->channel)) {
+ if (layer->cfg->scaler_mask & BIT(layer->channel)) {
min_scale = SUN8I_VI_SCALER_SCALE_MIN;
max_scale = SUN8I_VI_SCALER_SCALE_MAX;
}
@@ -352,20 +294,16 @@ static void sun8i_vi_layer_atomic_update(struct drm_plane *plane,
struct drm_plane_state *new_state = drm_atomic_get_new_plane_state(state,
plane);
struct sun8i_layer *layer = plane_to_sun8i_layer(plane);
- unsigned int zpos = new_state->normalized_zpos;
- struct sun8i_mixer *mixer = layer->mixer;
- if (!new_state->crtc || !new_state->visible)
+ if (!new_state->crtc || !new_state->visible) {
+ sun8i_vi_layer_disable(layer);
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);
+ sun8i_vi_layer_update_attributes(layer, plane);
+ sun8i_vi_layer_update_coord(layer, plane);
+ sun8i_csc_config(layer, new_state);
+ sun8i_vi_layer_update_buffer(layer, plane);
}
static const struct drm_plane_helper_funcs sun8i_vi_layer_helper_funcs = {
@@ -471,12 +409,14 @@ static const uint64_t sun8i_layer_modifiers[] = {
};
struct sun8i_layer *sun8i_vi_layer_init_one(struct drm_device *drm,
- struct sun8i_mixer *mixer,
- int index)
+ enum drm_plane_type type,
+ struct regmap *regs,
+ int index, int phy_index,
+ int plane_cnt,
+ const struct sun8i_layer_cfg *cfg)
{
- enum drm_plane_type type = DRM_PLANE_TYPE_OVERLAY;
u32 supported_encodings, supported_ranges;
- unsigned int plane_cnt, format_count;
+ unsigned int format_count;
struct sun8i_layer *layer;
const u32 *formats;
int ret;
@@ -485,7 +425,14 @@ struct sun8i_layer *sun8i_vi_layer_init_one(struct drm_device *drm,
if (!layer)
return ERR_PTR(-ENOMEM);
- if (mixer->cfg->de_type >= SUN8I_MIXER_DE3) {
+ layer->type = SUN8I_LAYER_TYPE_VI;
+ layer->index = index;
+ layer->channel = phy_index;
+ layer->overlay = 0;
+ layer->regs = regs;
+ layer->cfg = cfg;
+
+ if (layer->cfg->de_type >= SUN8I_MIXER_DE3) {
formats = sun8i_vi_layer_de3_formats;
format_count = ARRAY_SIZE(sun8i_vi_layer_de3_formats);
} else {
@@ -493,9 +440,6 @@ struct sun8i_layer *sun8i_vi_layer_init_one(struct drm_device *drm,
format_count = ARRAY_SIZE(sun8i_vi_layer_formats);
}
- if (!mixer->cfg->ui_num && index == 0)
- type = DRM_PLANE_TYPE_PRIMARY;
-
/* possible crtcs are set later */
ret = drm_universal_plane_init(drm, &layer->plane, 0,
&sun8i_vi_layer_funcs,
@@ -507,9 +451,7 @@ struct sun8i_layer *sun8i_vi_layer_init_one(struct drm_device *drm,
return ERR_PTR(ret);
}
- plane_cnt = mixer->cfg->ui_num + mixer->cfg->vi_num;
-
- if (mixer->cfg->vi_num == 1 || mixer->cfg->de_type >= SUN8I_MIXER_DE3) {
+ if (layer->cfg->de2_fcc_alpha || layer->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");
@@ -526,7 +468,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->de_type >= SUN8I_MIXER_DE3)
+ if (layer->cfg->de_type >= SUN8I_MIXER_DE3)
supported_encodings |= BIT(DRM_COLOR_YCBCR_BT2020);
supported_ranges = BIT(DRM_COLOR_YCBCR_LIMITED_RANGE) |
@@ -543,10 +485,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;
}
diff --git a/drivers/gpu/drm/sun4i/sun8i_vi_layer.h b/drivers/gpu/drm/sun4i/sun8i_vi_layer.h
index 655440cdc78f..29cc5573691f 100644
--- a/drivers/gpu/drm/sun4i/sun8i_vi_layer.h
+++ b/drivers/gpu/drm/sun4i/sun8i_vi_layer.h
@@ -55,6 +55,9 @@ struct sun8i_mixer;
struct sun8i_layer;
struct sun8i_layer *sun8i_vi_layer_init_one(struct drm_device *drm,
- struct sun8i_mixer *mixer,
- int index);
+ enum drm_plane_type type,
+ struct regmap *regs,
+ int index, int phy_index,
+ int plane_cnt,
+ const struct sun8i_layer_cfg *cfg);
#endif /* _SUN8I_VI_LAYER_H_ */
diff --git a/drivers/gpu/drm/sun4i/sun8i_vi_scaler.c b/drivers/gpu/drm/sun4i/sun8i_vi_scaler.c
index 82df6244af88..3dec4eeb1ba2 100644
--- a/drivers/gpu/drm/sun4i/sun8i_vi_scaler.c
+++ b/drivers/gpu/drm/sun4i/sun8i_vi_scaler.c
@@ -833,16 +833,17 @@ static const u32 bicubic4coefftab32[480] = {
0x1012110d, 0x1012110d, 0x1013110c, 0x1013110c,
};
-static u32 sun8i_vi_scaler_base(struct sun8i_mixer *mixer, int channel)
+static u32 sun8i_vi_scaler_base(struct sun8i_layer *layer)
{
- if (mixer->cfg->de_type == SUN8I_MIXER_DE33)
- return sun8i_channel_base(mixer, channel) + 0x3000;
- else if (mixer->cfg->de_type == SUN8I_MIXER_DE3)
+ if (layer->cfg->de_type == SUN8I_MIXER_DE33)
+ return DE33_VI_SCALER_UNIT_BASE +
+ DE33_CH_SIZE * layer->channel;
+ else if (layer->cfg->de_type == SUN8I_MIXER_DE3)
return DE3_VI_SCALER_UNIT_BASE +
- DE3_VI_SCALER_UNIT_SIZE * channel;
+ DE3_VI_SCALER_UNIT_SIZE * layer->channel;
else
return DE2_VI_SCALER_UNIT_BASE +
- DE2_VI_SCALER_UNIT_SIZE * channel;
+ DE2_VI_SCALER_UNIT_SIZE * layer->channel;
}
static int sun8i_vi_scaler_coef_index(unsigned int step)
@@ -909,11 +910,11 @@ static void sun8i_vi_scaler_set_coeff(struct regmap *map, u32 base,
}
}
-void sun8i_vi_scaler_enable(struct sun8i_mixer *mixer, int layer, bool enable)
+void sun8i_vi_scaler_enable(struct sun8i_layer *layer, bool enable)
{
u32 val, base;
- base = sun8i_vi_scaler_base(mixer, layer);
+ base = sun8i_vi_scaler_base(layer);
if (enable)
val = SUN8I_SCALER_VSU_CTRL_EN |
@@ -921,11 +922,11 @@ void sun8i_vi_scaler_enable(struct sun8i_mixer *mixer, int layer, bool enable)
else
val = 0;
- regmap_write(mixer->engine.regs,
+ regmap_write(layer->regs,
SUN8I_SCALER_VSU_CTRL(base), val);
}
-void sun8i_vi_scaler_setup(struct sun8i_mixer *mixer, int layer,
+void sun8i_vi_scaler_setup(struct sun8i_layer *layer,
u32 src_w, u32 src_h, u32 dst_w, u32 dst_h,
u32 hscale, u32 vscale, u32 hphase, u32 vphase,
const struct drm_format_info *format)
@@ -934,7 +935,7 @@ void sun8i_vi_scaler_setup(struct sun8i_mixer *mixer, int layer,
u32 insize, outsize;
u32 base;
- base = sun8i_vi_scaler_base(mixer, layer);
+ base = sun8i_vi_scaler_base(layer);
hphase <<= SUN8I_VI_SCALER_PHASE_FRAC - 16;
vphase <<= SUN8I_VI_SCALER_PHASE_FRAC - 16;
@@ -958,7 +959,7 @@ void sun8i_vi_scaler_setup(struct sun8i_mixer *mixer, int layer,
cvphase = vphase;
}
- if (mixer->cfg->de_type >= SUN8I_MIXER_DE3) {
+ if (layer->cfg->de_type >= SUN8I_MIXER_DE3) {
u32 val;
if (format->hsub == 1 && format->vsub == 1)
@@ -966,36 +967,36 @@ void sun8i_vi_scaler_setup(struct sun8i_mixer *mixer, int layer,
else
val = SUN50I_SCALER_VSU_SCALE_MODE_NORMAL;
- regmap_write(mixer->engine.regs,
+ regmap_write(layer->regs,
SUN50I_SCALER_VSU_SCALE_MODE(base), val);
}
- regmap_write(mixer->engine.regs,
+ regmap_write(layer->regs,
SUN8I_SCALER_VSU_OUTSIZE(base), outsize);
- regmap_write(mixer->engine.regs,
+ regmap_write(layer->regs,
SUN8I_SCALER_VSU_YINSIZE(base), insize);
- regmap_write(mixer->engine.regs,
+ regmap_write(layer->regs,
SUN8I_SCALER_VSU_YHSTEP(base), hscale);
- regmap_write(mixer->engine.regs,
+ regmap_write(layer->regs,
SUN8I_SCALER_VSU_YVSTEP(base), vscale);
- regmap_write(mixer->engine.regs,
+ regmap_write(layer->regs,
SUN8I_SCALER_VSU_YHPHASE(base), hphase);
- regmap_write(mixer->engine.regs,
+ regmap_write(layer->regs,
SUN8I_SCALER_VSU_YVPHASE(base), vphase);
- regmap_write(mixer->engine.regs,
+ regmap_write(layer->regs,
SUN8I_SCALER_VSU_CINSIZE(base),
SUN8I_VI_SCALER_SIZE(src_w / format->hsub,
src_h / format->vsub));
- regmap_write(mixer->engine.regs,
+ regmap_write(layer->regs,
SUN8I_SCALER_VSU_CHSTEP(base),
hscale / format->hsub);
- regmap_write(mixer->engine.regs,
+ regmap_write(layer->regs,
SUN8I_SCALER_VSU_CVSTEP(base),
vscale / format->vsub);
- regmap_write(mixer->engine.regs,
+ regmap_write(layer->regs,
SUN8I_SCALER_VSU_CHPHASE(base), chphase);
- regmap_write(mixer->engine.regs,
+ regmap_write(layer->regs,
SUN8I_SCALER_VSU_CVPHASE(base), cvphase);
- sun8i_vi_scaler_set_coeff(mixer->engine.regs, base,
+ sun8i_vi_scaler_set_coeff(layer->regs, base,
hscale, vscale, format);
}
diff --git a/drivers/gpu/drm/sun4i/sun8i_vi_scaler.h b/drivers/gpu/drm/sun4i/sun8i_vi_scaler.h
index 68f6593b369a..245fe2f431c3 100644
--- a/drivers/gpu/drm/sun4i/sun8i_vi_scaler.h
+++ b/drivers/gpu/drm/sun4i/sun8i_vi_scaler.h
@@ -18,6 +18,8 @@
#define DE3_VI_SCALER_UNIT_BASE 0x20000
#define DE3_VI_SCALER_UNIT_SIZE 0x08000
+#define DE33_VI_SCALER_UNIT_BASE 0x4000
+
/* this two macros assumes 16 fractional bits which is standard in DRM */
#define SUN8I_VI_SCALER_SCALE_MIN 1
#define SUN8I_VI_SCALER_SCALE_MAX ((1UL << 20) - 1)
@@ -69,8 +71,8 @@
#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_setup(struct sun8i_mixer *mixer, int layer,
+void sun8i_vi_scaler_enable(struct sun8i_layer *layer, bool enable);
+void sun8i_vi_scaler_setup(struct sun8i_layer *layer,
u32 src_w, u32 src_h, u32 dst_w, u32 dst_h,
u32 hscale, u32 vscale, u32 hphase, u32 vphase,
const struct drm_format_info *format);