Commit a4a7fbb4 authored by Dave Airlie's avatar Dave Airlie

Merge tag 'sunxi-drm-fixes-for-4.9' of...

Merge tag 'sunxi-drm-fixes-for-4.9' of https://git.kernel.org/pub/scm/linux/kernel/git/mripard/linux into drm-next

Allwinner sun4i DRM fixes for 4.9

A few fixes for the sun4i drm driver that range, including some fixes that
might prevent multiple planes from working depending on the sequence where
they are enabled.

* tag 'sunxi-drm-fixes-for-4.9' of https://git.kernel.org/pub/scm/linux/kernel/git/mripard/linux:
  drm/sun4i: Fix the high buffer address mask
  drm/sun4i: tv: Check mode pointer
  drm/sun4i: Fix formats usable by the primary plane
  drm/sun4i: dotclock: Round to closest clock rate
  drm/sun4i: Fix sparse warnings
  drm/sun4i: dotclock: Allow divider = 127
  drm/sun4i: dotclock: Fix clock rate read back calcation
  drm/sun4i: backend: remove redundant dev_err call in sun4i_backend_bind()
parents 378db830 f0188ef8
...@@ -83,8 +83,13 @@ void sun4i_backend_layer_enable(struct sun4i_backend *backend, ...@@ -83,8 +83,13 @@ void sun4i_backend_layer_enable(struct sun4i_backend *backend,
} }
EXPORT_SYMBOL(sun4i_backend_layer_enable); 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) { switch (format) {
case DRM_FORMAT_ARGB8888: case DRM_FORMAT_ARGB8888:
*mode = SUN4I_BACKEND_LAY_FBFMT_ARGB8888; *mode = SUN4I_BACKEND_LAY_FBFMT_ARGB8888;
...@@ -164,7 +169,7 @@ int sun4i_backend_update_layer_formats(struct sun4i_backend *backend, ...@@ -164,7 +169,7 @@ int sun4i_backend_update_layer_formats(struct sun4i_backend *backend,
DRM_DEBUG_DRIVER("Switching display backend interlaced mode %s\n", DRM_DEBUG_DRIVER("Switching display backend interlaced mode %s\n",
interlaced ? "on" : "off"); 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) { if (ret) {
DRM_DEBUG_DRIVER("Invalid format\n"); DRM_DEBUG_DRIVER("Invalid format\n");
return val; return val;
...@@ -288,10 +293,8 @@ static int sun4i_backend_bind(struct device *dev, struct device *master, ...@@ -288,10 +293,8 @@ static int sun4i_backend_bind(struct device *dev, struct device *master,
res = platform_get_resource(pdev, IORESOURCE_MEM, 0); res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
regs = devm_ioremap_resource(dev, res); regs = devm_ioremap_resource(dev, res);
if (IS_ERR(regs)) { if (IS_ERR(regs))
dev_err(dev, "Couldn't map the backend registers\n");
return PTR_ERR(regs); return PTR_ERR(regs);
}
backend->regs = devm_regmap_init_mmio(dev, regs, backend->regs = devm_regmap_init_mmio(dev, regs,
&sun4i_backend_regmap_config); &sun4i_backend_regmap_config);
......
...@@ -52,7 +52,7 @@ ...@@ -52,7 +52,7 @@
#define SUN4I_BACKEND_LAYFB_L32ADD_REG(l) (0x850 + (0x4 * (l))) #define SUN4I_BACKEND_LAYFB_L32ADD_REG(l) (0x850 + (0x4 * (l)))
#define SUN4I_BACKEND_LAYFB_H4ADD_REG 0x860 #define SUN4I_BACKEND_LAYFB_H4ADD_REG 0x860
#define SUN4I_BACKEND_LAYFB_H4ADD_MSK(l) GENMASK(3 + ((l) * 8), 0) #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_LAYFB_H4ADD(l, val) ((val) << ((l) * 8))
#define SUN4I_BACKEND_REGBUFFCTL_REG 0x870 #define SUN4I_BACKEND_REGBUFFCTL_REG 0x870
......
...@@ -62,7 +62,7 @@ static unsigned long sun4i_dclk_recalc_rate(struct clk_hw *hw, ...@@ -62,7 +62,7 @@ static unsigned long sun4i_dclk_recalc_rate(struct clk_hw *hw,
regmap_read(dclk->regmap, SUN4I_TCON0_DCLK_REG, &val); regmap_read(dclk->regmap, SUN4I_TCON0_DCLK_REG, &val);
val >>= SUN4I_TCON0_DCLK_DIV_SHIFT; val >>= SUN4I_TCON0_DCLK_DIV_SHIFT;
val &= SUN4I_TCON0_DCLK_DIV_WIDTH; val &= (1 << SUN4I_TCON0_DCLK_DIV_WIDTH) - 1;
if (!val) if (!val)
val = 1; val = 1;
...@@ -77,7 +77,7 @@ static long sun4i_dclk_round_rate(struct clk_hw *hw, unsigned long rate, ...@@ -77,7 +77,7 @@ static long sun4i_dclk_round_rate(struct clk_hw *hw, unsigned long rate,
u8 best_div = 1; u8 best_div = 1;
int i; int i;
for (i = 6; i < 127; i++) { for (i = 6; i <= 127; i++) {
unsigned long ideal = rate * i; unsigned long ideal = rate * i;
unsigned long rounded; unsigned long rounded;
...@@ -90,7 +90,8 @@ static long sun4i_dclk_round_rate(struct clk_hw *hw, unsigned long rate, ...@@ -90,7 +90,8 @@ static long sun4i_dclk_round_rate(struct clk_hw *hw, unsigned long rate,
goto out; goto out;
} }
if ((rounded < ideal) && (rounded > best_parent)) { if (abs(rate - rounded / i) <
abs(rate - best_parent / best_div)) {
best_parent = rounded; best_parent = rounded;
best_div = i; best_div = i;
} }
......
...@@ -19,7 +19,12 @@ ...@@ -19,7 +19,12 @@
#include "sun4i_drv.h" #include "sun4i_drv.h"
#include "sun4i_layer.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, static int sun4i_backend_layer_atomic_check(struct drm_plane *plane,
struct drm_plane_state *state) struct drm_plane_state *state)
...@@ -65,14 +70,35 @@ static const struct drm_plane_funcs sun4i_backend_layer_funcs = { ...@@ -65,14 +70,35 @@ static const struct drm_plane_funcs sun4i_backend_layer_funcs = {
.update_plane = drm_atomic_helper_update_plane, .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_ARGB8888,
DRM_FORMAT_RGB888,
DRM_FORMAT_XRGB8888, DRM_FORMAT_XRGB8888,
};
static const uint32_t sun4i_backend_layer_formats_overlay[] = {
DRM_FORMAT_ARGB8888,
DRM_FORMAT_RGB888, 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, 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_drv *drv = drm->dev_private;
struct sun4i_layer *layer; struct sun4i_layer *layer;
...@@ -84,10 +110,8 @@ static struct sun4i_layer *sun4i_layer_init_one(struct drm_device *drm, ...@@ -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), ret = drm_universal_plane_init(drm, &layer->plane, BIT(0),
&sun4i_backend_layer_funcs, &sun4i_backend_layer_funcs,
sun4i_backend_layer_formats, plane->formats, plane->nformats,
ARRAY_SIZE(sun4i_backend_layer_formats), plane->type, NULL);
type,
NULL);
if (ret) { if (ret) {
dev_err(drm->dev, "Couldn't initialize layer\n"); dev_err(drm->dev, "Couldn't initialize layer\n");
return ERR_PTR(ret); return ERR_PTR(ret);
...@@ -97,7 +121,7 @@ static struct sun4i_layer *sun4i_layer_init_one(struct drm_device *drm, ...@@ -97,7 +121,7 @@ static struct sun4i_layer *sun4i_layer_init_one(struct drm_device *drm,
&sun4i_backend_layer_helper_funcs); &sun4i_backend_layer_helper_funcs);
layer->drv = drv; layer->drv = drv;
if (type == DRM_PLANE_TYPE_PRIMARY) if (plane->type == DRM_PLANE_TYPE_PRIMARY)
drv->primary = &layer->plane; drv->primary = &layer->plane;
return layer; return layer;
...@@ -109,8 +133,8 @@ struct sun4i_layer **sun4i_layers_init(struct drm_device *drm) ...@@ -109,8 +133,8 @@ struct sun4i_layer **sun4i_layers_init(struct drm_device *drm)
struct sun4i_layer **layers; struct sun4i_layer **layers;
int i; int i;
layers = devm_kcalloc(drm->dev, SUN4I_NUM_LAYERS, sizeof(**layers), layers = devm_kcalloc(drm->dev, ARRAY_SIZE(sun4i_backend_planes),
GFP_KERNEL); sizeof(**layers), GFP_KERNEL);
if (!layers) if (!layers)
return ERR_PTR(-ENOMEM); return ERR_PTR(-ENOMEM);
...@@ -135,13 +159,11 @@ struct sun4i_layer **sun4i_layers_init(struct drm_device *drm) ...@@ -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 * SoCs that support it, sprites could fill the need for more
* layers. * layers.
*/ */
for (i = 0; i < SUN4I_NUM_LAYERS; i++) { for (i = 0; i < ARRAY_SIZE(sun4i_backend_planes); i++) {
enum drm_plane_type type = (i == 0) const struct sun4i_plane_desc *plane = &sun4i_backend_planes[i];
? DRM_PLANE_TYPE_PRIMARY
: DRM_PLANE_TYPE_OVERLAY;
struct sun4i_layer *layer = layers[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)) { if (IS_ERR(layer)) {
dev_err(drm->dev, "Couldn't initialize %s plane\n", dev_err(drm->dev, "Couldn't initialize %s plane\n",
i ? "overlay" : "primary"); i ? "overlay" : "primary");
...@@ -149,10 +171,10 @@ struct sun4i_layer **sun4i_layers_init(struct drm_device *drm) ...@@ -149,10 +171,10 @@ struct sun4i_layer **sun4i_layers_init(struct drm_device *drm)
}; };
DRM_DEBUG_DRIVER("Assigning %s plane to pipe %d\n", 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), regmap_update_bits(drv->backend->regs, SUN4I_BACKEND_ATTCTL_REG0(i),
SUN4I_BACKEND_ATTCTL_REG0_LAY_PIPESEL_MASK, 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; layer->id = i;
}; };
......
...@@ -161,10 +161,10 @@ struct tv_mode { ...@@ -161,10 +161,10 @@ struct tv_mode {
bool dac3_en; bool dac3_en;
bool dac_bit25_en; bool dac_bit25_en;
struct color_gains *color_gains; const struct color_gains *color_gains;
struct burst_levels *burst_levels; const struct burst_levels *burst_levels;
struct video_levels *video_levels; const struct video_levels *video_levels;
struct resync_parameters *resync_params; const struct resync_parameters *resync_params;
}; };
struct sun4i_tv { struct sun4i_tv {
...@@ -178,39 +178,39 @@ struct sun4i_tv { ...@@ -178,39 +178,39 @@ struct sun4i_tv {
struct sun4i_drv *drv; struct sun4i_drv *drv;
}; };
struct video_levels ntsc_video_levels = { static const struct video_levels ntsc_video_levels = {
.black = 282, .blank = 240, .black = 282, .blank = 240,
}; };
struct video_levels pal_video_levels = { static const struct video_levels pal_video_levels = {
.black = 252, .blank = 252, .black = 252, .blank = 252,
}; };
struct burst_levels ntsc_burst_levels = { static const struct burst_levels ntsc_burst_levels = {
.cb = 79, .cr = 0, .cb = 79, .cr = 0,
}; };
struct burst_levels pal_burst_levels = { static const struct burst_levels pal_burst_levels = {
.cb = 40, .cr = 40, .cb = 40, .cr = 40,
}; };
struct color_gains ntsc_color_gains = { static const struct color_gains ntsc_color_gains = {
.cb = 160, .cr = 160, .cb = 160, .cr = 160,
}; };
struct color_gains pal_color_gains = { static const struct color_gains pal_color_gains = {
.cb = 224, .cr = 224, .cb = 224, .cr = 224,
}; };
struct resync_parameters ntsc_resync_parameters = { static const struct resync_parameters ntsc_resync_parameters = {
.field = false, .line = 14, .pixel = 12, .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, .field = true, .line = 13, .pixel = 12,
}; };
struct tv_mode tv_modes[] = { static const struct tv_mode tv_modes[] = {
{ {
.name = "NTSC", .name = "NTSC",
.mode = SUN4I_TVE_CFG0_RES_480i, .mode = SUN4I_TVE_CFG0_RES_480i,
...@@ -289,13 +289,13 @@ drm_connector_to_sun4i_tv(struct drm_connector *connector) ...@@ -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 * So far, it doesn't seem to be preserved when the mode is passed by
* to mode_set for some reason. * 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; int i;
/* First try to identify the mode by name */ /* First try to identify the mode by name */
for (i = 0; i < ARRAY_SIZE(tv_modes); i++) { 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", DRM_DEBUG_DRIVER("Comparing mode %s vs %s",
mode->name, tv_mode->name); mode->name, tv_mode->name);
...@@ -306,7 +306,7 @@ static struct tv_mode *sun4i_tv_find_tv_by_mode(struct drm_display_mode *mode) ...@@ -306,7 +306,7 @@ static struct tv_mode *sun4i_tv_find_tv_by_mode(struct drm_display_mode *mode)
/* Then by number of lines */ /* Then by number of lines */
for (i = 0; i < ARRAY_SIZE(tv_modes); i++) { 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)", DRM_DEBUG_DRIVER("Comparing mode %s vs %s (X: %d vs %d)",
mode->name, tv_mode->name, mode->name, tv_mode->name,
...@@ -319,7 +319,7 @@ static struct tv_mode *sun4i_tv_find_tv_by_mode(struct drm_display_mode *mode) ...@@ -319,7 +319,7 @@ static struct tv_mode *sun4i_tv_find_tv_by_mode(struct drm_display_mode *mode)
return NULL; 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) struct drm_display_mode *mode)
{ {
DRM_DEBUG_DRIVER("Creating mode %s\n", mode->name); DRM_DEBUG_DRIVER("Creating mode %s\n", mode->name);
...@@ -386,7 +386,7 @@ static void sun4i_tv_mode_set(struct drm_encoder *encoder, ...@@ -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_tv *tv = drm_encoder_to_sun4i_tv(encoder);
struct sun4i_drv *drv = tv->drv; struct sun4i_drv *drv = tv->drv;
struct sun4i_tcon *tcon = drv->tcon; 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); sun4i_tcon1_mode_set(tcon, mode);
...@@ -507,8 +507,14 @@ static int sun4i_tv_comp_get_modes(struct drm_connector *connector) ...@@ -507,8 +507,14 @@ static int sun4i_tv_comp_get_modes(struct drm_connector *connector)
int i; int i;
for (i = 0; i < ARRAY_SIZE(tv_modes); 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;
struct tv_mode *tv_mode = &tv_modes[i]; 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); strcpy(mode->name, tv_mode->name);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment