From 9a8aa939ba33998f4c70c082dbd4d27a5ddcaaf6 Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Thu, 15 Sep 2016 03:25:58 +0000 Subject: drm/sun4i: backend: remove redundant dev_err call in sun4i_backend_bind() There is a error message within devm_ioremap_resource already, so remove the dev_err call to avoid redundant error message. Signed-off-by: Wei Yongjun Signed-off-by: Maxime Ripard --- drivers/gpu/drm/sun4i/sun4i_backend.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'drivers/gpu/drm/sun4i') diff --git a/drivers/gpu/drm/sun4i/sun4i_backend.c b/drivers/gpu/drm/sun4i/sun4i_backend.c index 91a7022..fcd4e91 100644 --- a/drivers/gpu/drm/sun4i/sun4i_backend.c +++ b/drivers/gpu/drm/sun4i/sun4i_backend.c @@ -288,10 +288,8 @@ static int sun4i_backend_bind(struct device *dev, struct device *master, res = platform_get_resource(pdev, IORESOURCE_MEM, 0); regs = devm_ioremap_resource(dev, res); - if (IS_ERR(regs)) { - dev_err(dev, "Couldn't map the backend registers\n"); + if (IS_ERR(regs)) return PTR_ERR(regs); - } backend->regs = devm_regmap_init_mmio(dev, regs, &sun4i_backend_regmap_config); -- cgit v1.1 From e996e2089f25b84149ae82b5ddf37a263a7fcc71 Mon Sep 17 00:00:00 2001 From: Chen-Yu Tsai Date: Thu, 15 Sep 2016 23:14:00 +0800 Subject: drm/sun4i: dotclock: Fix clock rate read back calcation When reading back the divider set in the register, we mask off the bits that aren't part of the divider. Unfortunately the mask used here was not converted from the field width. Fix this by converting the field width to a proper bit mask. Fixes: 9026e0d122ac ("drm: Add Allwinner A10 Display Engine support") Signed-off-by: Chen-Yu Tsai Signed-off-by: Maxime Ripard --- drivers/gpu/drm/sun4i/sun4i_dotclock.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/gpu/drm/sun4i') diff --git a/drivers/gpu/drm/sun4i/sun4i_dotclock.c b/drivers/gpu/drm/sun4i/sun4i_dotclock.c index 4332da4..1b6c225 100644 --- a/drivers/gpu/drm/sun4i/sun4i_dotclock.c +++ b/drivers/gpu/drm/sun4i/sun4i_dotclock.c @@ -62,7 +62,7 @@ static unsigned long sun4i_dclk_recalc_rate(struct clk_hw *hw, regmap_read(dclk->regmap, SUN4I_TCON0_DCLK_REG, &val); val >>= SUN4I_TCON0_DCLK_DIV_SHIFT; - val &= SUN4I_TCON0_DCLK_DIV_WIDTH; + val &= (1 << SUN4I_TCON0_DCLK_DIV_WIDTH) - 1; if (!val) val = 1; -- cgit v1.1 From 7e81bda23ac3c79b6cf747c195810900b45a77fc Mon Sep 17 00:00:00 2001 From: Chen-Yu Tsai Date: Thu, 15 Sep 2016 23:14:01 +0800 Subject: drm/sun4i: dotclock: Allow divider = 127 The dot clock divider is 7 bits wide, and the divider range is 1 ~ 127, or 6 ~ 127 if phase offsets are used. The 0 register value also represents a divider of 1 or bypass. Make the end condition of the for loop inclusive of 127 in the round_rate callback. Signed-off-by: Chen-Yu Tsai Signed-off-by: Maxime Ripard --- drivers/gpu/drm/sun4i/sun4i_dotclock.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/gpu/drm/sun4i') diff --git a/drivers/gpu/drm/sun4i/sun4i_dotclock.c b/drivers/gpu/drm/sun4i/sun4i_dotclock.c index 1b6c225..3eb9978 100644 --- a/drivers/gpu/drm/sun4i/sun4i_dotclock.c +++ b/drivers/gpu/drm/sun4i/sun4i_dotclock.c @@ -77,7 +77,7 @@ static long sun4i_dclk_round_rate(struct clk_hw *hw, unsigned long rate, u8 best_div = 1; int i; - for (i = 6; i < 127; i++) { + for (i = 6; i <= 127; i++) { unsigned long ideal = rate * i; unsigned long rounded; -- cgit v1.1 From 15ae0ea4bf4395c5ba7a3242138a528bd3dfbb14 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Mon, 19 Sep 2016 16:33:54 +0300 Subject: drm/sun4i: Fix sparse warnings MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit drm/sun4i/sun4i_tv.c:181:21: warning: symbol 'ntsc_video_levels' was not declared. Should it be static? drm/sun4i/sun4i_tv.c:185:21: warning: symbol 'pal_video_levels' was not declared. Should it be static? drm/sun4i/sun4i_tv.c:189:21: warning: symbol 'ntsc_burst_levels' was not declared. Should it be static? drm/sun4i/sun4i_tv.c:193:21: warning: symbol 'pal_burst_levels' was not declared. Should it be static? drm/sun4i/sun4i_tv.c:197:20: warning: symbol 'ntsc_color_gains' was not declared. Should it be static? drm/sun4i/sun4i_tv.c:201:20: warning: symbol 'pal_color_gains' was not declared. Should it be static? drm/sun4i/sun4i_tv.c:205:26: warning: symbol 'ntsc_resync_parameters' was not declared. Should it be static? drm/sun4i/sun4i_tv.c:209:26: warning: symbol 'pal_resync_parameters' was not declared. Should it be static? drm/sun4i/sun4i_tv.c:213:16: warning: symbol 'tv_modes' was not declared. Should it be static? Cc: Maxime Ripard Signed-off-by: Ville Syrjälä Signed-off-by: Maxime Ripard --- drivers/gpu/drm/sun4i/sun4i_tv.c | 38 +++++++++++++++++++------------------- 1 file changed, 19 insertions(+), 19 deletions(-) (limited to 'drivers/gpu/drm/sun4i') diff --git a/drivers/gpu/drm/sun4i/sun4i_tv.c b/drivers/gpu/drm/sun4i/sun4i_tv.c index b841478..3d69bd3 100644 --- a/drivers/gpu/drm/sun4i/sun4i_tv.c +++ b/drivers/gpu/drm/sun4i/sun4i_tv.c @@ -161,10 +161,10 @@ struct tv_mode { bool dac3_en; bool dac_bit25_en; - struct color_gains *color_gains; - struct burst_levels *burst_levels; - struct video_levels *video_levels; - struct resync_parameters *resync_params; + const struct color_gains *color_gains; + const struct burst_levels *burst_levels; + const struct video_levels *video_levels; + const struct resync_parameters *resync_params; }; struct sun4i_tv { @@ -178,39 +178,39 @@ struct sun4i_tv { struct sun4i_drv *drv; }; -struct video_levels ntsc_video_levels = { +static const struct video_levels ntsc_video_levels = { .black = 282, .blank = 240, }; -struct video_levels pal_video_levels = { +static const struct video_levels pal_video_levels = { .black = 252, .blank = 252, }; -struct burst_levels ntsc_burst_levels = { +static const struct burst_levels ntsc_burst_levels = { .cb = 79, .cr = 0, }; -struct burst_levels pal_burst_levels = { +static const struct burst_levels pal_burst_levels = { .cb = 40, .cr = 40, }; -struct color_gains ntsc_color_gains = { +static const struct color_gains ntsc_color_gains = { .cb = 160, .cr = 160, }; -struct color_gains pal_color_gains = { +static const struct color_gains pal_color_gains = { .cb = 224, .cr = 224, }; -struct resync_parameters ntsc_resync_parameters = { +static const struct resync_parameters ntsc_resync_parameters = { .field = false, .line = 14, .pixel = 12, }; -struct resync_parameters pal_resync_parameters = { +static const struct resync_parameters pal_resync_parameters = { .field = true, .line = 13, .pixel = 12, }; -struct tv_mode tv_modes[] = { +static const struct tv_mode tv_modes[] = { { .name = "NTSC", .mode = SUN4I_TVE_CFG0_RES_480i, @@ -289,13 +289,13 @@ drm_connector_to_sun4i_tv(struct drm_connector *connector) * So far, it doesn't seem to be preserved when the mode is passed by * to mode_set for some reason. */ -static struct tv_mode *sun4i_tv_find_tv_by_mode(struct drm_display_mode *mode) +static const struct tv_mode *sun4i_tv_find_tv_by_mode(const struct drm_display_mode *mode) { int i; /* First try to identify the mode by name */ for (i = 0; i < ARRAY_SIZE(tv_modes); i++) { - struct tv_mode *tv_mode = &tv_modes[i]; + const struct tv_mode *tv_mode = &tv_modes[i]; DRM_DEBUG_DRIVER("Comparing mode %s vs %s", mode->name, tv_mode->name); @@ -306,7 +306,7 @@ static struct tv_mode *sun4i_tv_find_tv_by_mode(struct drm_display_mode *mode) /* Then by number of lines */ for (i = 0; i < ARRAY_SIZE(tv_modes); i++) { - struct tv_mode *tv_mode = &tv_modes[i]; + const struct tv_mode *tv_mode = &tv_modes[i]; DRM_DEBUG_DRIVER("Comparing mode %s vs %s (X: %d vs %d)", mode->name, tv_mode->name, @@ -319,7 +319,7 @@ static struct tv_mode *sun4i_tv_find_tv_by_mode(struct drm_display_mode *mode) return NULL; } -static void sun4i_tv_mode_to_drm_mode(struct tv_mode *tv_mode, +static void sun4i_tv_mode_to_drm_mode(const struct tv_mode *tv_mode, struct drm_display_mode *mode) { DRM_DEBUG_DRIVER("Creating mode %s\n", mode->name); @@ -386,7 +386,7 @@ static void sun4i_tv_mode_set(struct drm_encoder *encoder, struct sun4i_tv *tv = drm_encoder_to_sun4i_tv(encoder); struct sun4i_drv *drv = tv->drv; struct sun4i_tcon *tcon = drv->tcon; - struct tv_mode *tv_mode = sun4i_tv_find_tv_by_mode(mode); + const struct tv_mode *tv_mode = sun4i_tv_find_tv_by_mode(mode); sun4i_tcon1_mode_set(tcon, mode); @@ -508,7 +508,7 @@ static int sun4i_tv_comp_get_modes(struct drm_connector *connector) for (i = 0; i < ARRAY_SIZE(tv_modes); i++) { struct drm_display_mode *mode = drm_mode_create(connector->dev); - struct tv_mode *tv_mode = &tv_modes[i]; + const struct tv_mode *tv_mode = &tv_modes[i]; strcpy(mode->name, tv_mode->name); -- cgit v1.1 From ac412c3d4ff216cb7315cd695be0956ca948aae6 Mon Sep 17 00:00:00 2001 From: Chen-Yu Tsai Date: Thu, 15 Sep 2016 23:14:02 +0800 Subject: drm/sun4i: dotclock: Round to closest clock rate With display pixel clocks we want to have the closest possible clock rate, to minimize timing and refresh rate skews. Whether the actual clock rate is higher or lower than the requested rate is less important. Also check candidates against the requested rate, rather than the ideal parent rate, the varying dividers also influence the difference between the requested rate and the rounded rate. Signed-off-by: Chen-Yu Tsai Signed-off-by: Maxime Ripard --- drivers/gpu/drm/sun4i/sun4i_dotclock.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers/gpu/drm/sun4i') diff --git a/drivers/gpu/drm/sun4i/sun4i_dotclock.c b/drivers/gpu/drm/sun4i/sun4i_dotclock.c index 3eb9978..d401156 100644 --- a/drivers/gpu/drm/sun4i/sun4i_dotclock.c +++ b/drivers/gpu/drm/sun4i/sun4i_dotclock.c @@ -90,7 +90,8 @@ static long sun4i_dclk_round_rate(struct clk_hw *hw, unsigned long rate, goto out; } - if ((rounded < ideal) && (rounded > best_parent)) { + if (abs(rate - rounded / i) < + abs(rate - best_parent / best_div)) { best_parent = rounded; best_div = i; } -- cgit v1.1 From c222f399045de480d4af0b9e4cdfff1a083e3e1d Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Mon, 19 Sep 2016 22:17:50 +0200 Subject: drm/sun4i: Fix formats usable by the primary plane Even though all our planes can support the ARGB formats, the lowest plane (ie the primary plane) cannot use the alpha component, otherwise it will just result in the transparent area being entirely black. Since some applications will still require the ARGB format, let's force the format to XRGB to drop the alpha component entirely. Signed-off-by: Maxime Ripard --- drivers/gpu/drm/sun4i/sun4i_backend.c | 9 ++++-- drivers/gpu/drm/sun4i/sun4i_layer.c | 56 ++++++++++++++++++++++++----------- 2 files changed, 46 insertions(+), 19 deletions(-) (limited to 'drivers/gpu/drm/sun4i') diff --git a/drivers/gpu/drm/sun4i/sun4i_backend.c b/drivers/gpu/drm/sun4i/sun4i_backend.c index fcd4e91..32c0584 100644 --- a/drivers/gpu/drm/sun4i/sun4i_backend.c +++ b/drivers/gpu/drm/sun4i/sun4i_backend.c @@ -83,8 +83,13 @@ void sun4i_backend_layer_enable(struct sun4i_backend *backend, } EXPORT_SYMBOL(sun4i_backend_layer_enable); -static int sun4i_backend_drm_format_to_layer(u32 format, u32 *mode) +static int sun4i_backend_drm_format_to_layer(struct drm_plane *plane, + u32 format, u32 *mode) { + if ((plane->type == DRM_PLANE_TYPE_PRIMARY) && + (format == DRM_FORMAT_ARGB8888)) + format = DRM_FORMAT_XRGB8888; + switch (format) { case DRM_FORMAT_ARGB8888: *mode = SUN4I_BACKEND_LAY_FBFMT_ARGB8888; @@ -164,7 +169,7 @@ int sun4i_backend_update_layer_formats(struct sun4i_backend *backend, DRM_DEBUG_DRIVER("Switching display backend interlaced mode %s\n", interlaced ? "on" : "off"); - ret = sun4i_backend_drm_format_to_layer(fb->pixel_format, &val); + ret = sun4i_backend_drm_format_to_layer(plane, fb->pixel_format, &val); if (ret) { DRM_DEBUG_DRIVER("Invalid format\n"); return val; diff --git a/drivers/gpu/drm/sun4i/sun4i_layer.c b/drivers/gpu/drm/sun4i/sun4i_layer.c index 068ab80..f0035bf 100644 --- a/drivers/gpu/drm/sun4i/sun4i_layer.c +++ b/drivers/gpu/drm/sun4i/sun4i_layer.c @@ -19,7 +19,12 @@ #include "sun4i_drv.h" #include "sun4i_layer.h" -#define SUN4I_NUM_LAYERS 2 +struct sun4i_plane_desc { + enum drm_plane_type type; + u8 pipe; + const uint32_t *formats; + uint32_t nformats; +}; static int sun4i_backend_layer_atomic_check(struct drm_plane *plane, struct drm_plane_state *state) @@ -65,14 +70,35 @@ static const struct drm_plane_funcs sun4i_backend_layer_funcs = { .update_plane = drm_atomic_helper_update_plane, }; -static const uint32_t sun4i_backend_layer_formats[] = { +static const uint32_t sun4i_backend_layer_formats_primary[] = { DRM_FORMAT_ARGB8888, + DRM_FORMAT_RGB888, DRM_FORMAT_XRGB8888, +}; + +static const uint32_t sun4i_backend_layer_formats_overlay[] = { + DRM_FORMAT_ARGB8888, DRM_FORMAT_RGB888, + DRM_FORMAT_XRGB8888, +}; + +static const struct sun4i_plane_desc sun4i_backend_planes[] = { + { + .type = DRM_PLANE_TYPE_PRIMARY, + .pipe = 0, + .formats = sun4i_backend_layer_formats_primary, + .nformats = ARRAY_SIZE(sun4i_backend_layer_formats_primary), + }, + { + .type = DRM_PLANE_TYPE_OVERLAY, + .pipe = 1, + .formats = sun4i_backend_layer_formats_overlay, + .nformats = ARRAY_SIZE(sun4i_backend_layer_formats_overlay), + }, }; static struct sun4i_layer *sun4i_layer_init_one(struct drm_device *drm, - enum drm_plane_type type) + const struct sun4i_plane_desc *plane) { struct sun4i_drv *drv = drm->dev_private; struct sun4i_layer *layer; @@ -84,10 +110,8 @@ static struct sun4i_layer *sun4i_layer_init_one(struct drm_device *drm, ret = drm_universal_plane_init(drm, &layer->plane, BIT(0), &sun4i_backend_layer_funcs, - sun4i_backend_layer_formats, - ARRAY_SIZE(sun4i_backend_layer_formats), - type, - NULL); + plane->formats, plane->nformats, + plane->type, NULL); if (ret) { dev_err(drm->dev, "Couldn't initialize layer\n"); return ERR_PTR(ret); @@ -97,7 +121,7 @@ static struct sun4i_layer *sun4i_layer_init_one(struct drm_device *drm, &sun4i_backend_layer_helper_funcs); layer->drv = drv; - if (type == DRM_PLANE_TYPE_PRIMARY) + if (plane->type == DRM_PLANE_TYPE_PRIMARY) drv->primary = &layer->plane; return layer; @@ -109,8 +133,8 @@ struct sun4i_layer **sun4i_layers_init(struct drm_device *drm) struct sun4i_layer **layers; int i; - layers = devm_kcalloc(drm->dev, SUN4I_NUM_LAYERS, sizeof(**layers), - GFP_KERNEL); + layers = devm_kcalloc(drm->dev, ARRAY_SIZE(sun4i_backend_planes), + sizeof(**layers), GFP_KERNEL); if (!layers) return ERR_PTR(-ENOMEM); @@ -135,13 +159,11 @@ struct sun4i_layer **sun4i_layers_init(struct drm_device *drm) * SoCs that support it, sprites could fill the need for more * layers. */ - for (i = 0; i < SUN4I_NUM_LAYERS; i++) { - enum drm_plane_type type = (i == 0) - ? DRM_PLANE_TYPE_PRIMARY - : DRM_PLANE_TYPE_OVERLAY; + for (i = 0; i < ARRAY_SIZE(sun4i_backend_planes); i++) { + const struct sun4i_plane_desc *plane = &sun4i_backend_planes[i]; struct sun4i_layer *layer = layers[i]; - layer = sun4i_layer_init_one(drm, type); + layer = sun4i_layer_init_one(drm, plane); if (IS_ERR(layer)) { dev_err(drm->dev, "Couldn't initialize %s plane\n", i ? "overlay" : "primary"); @@ -149,10 +171,10 @@ struct sun4i_layer **sun4i_layers_init(struct drm_device *drm) }; DRM_DEBUG_DRIVER("Assigning %s plane to pipe %d\n", - i ? "overlay" : "primary", i); + i ? "overlay" : "primary", plane->pipe); regmap_update_bits(drv->backend->regs, SUN4I_BACKEND_ATTCTL_REG0(i), SUN4I_BACKEND_ATTCTL_REG0_LAY_PIPESEL_MASK, - SUN4I_BACKEND_ATTCTL_REG0_LAY_PIPESEL(i)); + SUN4I_BACKEND_ATTCTL_REG0_LAY_PIPESEL(plane->pipe)); layer->id = i; }; -- cgit v1.1 From e4192089fe5320537fd88aa29721277efef64af4 Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Mon, 19 Sep 2016 22:17:51 +0200 Subject: drm/sun4i: tv: Check mode pointer The drm_mode_create call might return NULL in case of a failure, and the current code doesn't check for that. Make sure it does. Reported-by: Dan Carpenter Signed-off-by: Maxime Ripard --- drivers/gpu/drm/sun4i/sun4i_tv.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'drivers/gpu/drm/sun4i') diff --git a/drivers/gpu/drm/sun4i/sun4i_tv.c b/drivers/gpu/drm/sun4i/sun4i_tv.c index 3d69bd3..1dd3d9e 100644 --- a/drivers/gpu/drm/sun4i/sun4i_tv.c +++ b/drivers/gpu/drm/sun4i/sun4i_tv.c @@ -507,9 +507,15 @@ static int sun4i_tv_comp_get_modes(struct drm_connector *connector) int i; for (i = 0; i < ARRAY_SIZE(tv_modes); i++) { - struct drm_display_mode *mode = drm_mode_create(connector->dev); + struct drm_display_mode *mode; const struct tv_mode *tv_mode = &tv_modes[i]; + mode = drm_mode_create(connector->dev); + if (!mode) { + DRM_ERROR("Failed to create a new display mode\n"); + return 0; + } + strcpy(mode->name, tv_mode->name); sun4i_tv_mode_to_drm_mode(tv_mode, mode); -- cgit v1.1 From f0188ef8301ccbb128bbfd10751a9aeca8c9172e Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Mon, 19 Sep 2016 21:53:08 +0200 Subject: drm/sun4i: Fix the high buffer address mask The highest 3bits of the 4 layers buffers are all part of the same register. However, our mask computation was wrong, leading to all the lowest register bits being removed when we use regmap_update_bits, which will lead to the buffers being set to some random part of the RAM. Fix our mask. Signed-off-by: Maxime Ripard --- drivers/gpu/drm/sun4i/sun4i_backend.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/gpu/drm/sun4i') diff --git a/drivers/gpu/drm/sun4i/sun4i_backend.h b/drivers/gpu/drm/sun4i/sun4i_backend.h index e007186..83e63cc 100644 --- a/drivers/gpu/drm/sun4i/sun4i_backend.h +++ b/drivers/gpu/drm/sun4i/sun4i_backend.h @@ -52,8 +52,8 @@ #define SUN4I_BACKEND_LAYFB_L32ADD_REG(l) (0x850 + (0x4 * (l))) #define SUN4I_BACKEND_LAYFB_H4ADD_REG 0x860 -#define SUN4I_BACKEND_LAYFB_H4ADD_MSK(l) GENMASK(3 + ((l) * 8), 0) -#define SUN4I_BACKEND_LAYFB_H4ADD(l, val) ((val) << ((l) * 8)) +#define SUN4I_BACKEND_LAYFB_H4ADD_MSK(l) GENMASK(3 + ((l) * 8), (l) * 8) +#define SUN4I_BACKEND_LAYFB_H4ADD(l, val) ((val) << ((l) * 8)) #define SUN4I_BACKEND_REGBUFFCTL_REG 0x870 #define SUN4I_BACKEND_REGBUFFCTL_AUTOLOAD_DIS BIT(1) -- cgit v1.1