Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit a4a7fbb4 authored by Dave Airlie's avatar Dave Airlie
Browse files

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
Loading
Loading
Loading
Loading
+8 −5
Original line number Diff line number Diff line
@@ -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;
@@ -288,10 +293,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);
+2 −2
Original line number Diff line number Diff line
@@ -52,7 +52,7 @@
#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_MSK(l)		GENMASK(3 + ((l) * 8), (l) * 8)
#define SUN4I_BACKEND_LAYFB_H4ADD(l, val)		((val) << ((l) * 8))

#define SUN4I_BACKEND_REGBUFFCTL_REG		0x870
+4 −3
Original line number Diff line number Diff line
@@ -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;
@@ -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;

@@ -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;
		}
+39 −17
Original line number Diff line number Diff line
@@ -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;
	};
+26 −20
Original line number Diff line number Diff line
@@ -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);

@@ -507,8 +507,14 @@ 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 tv_mode *tv_mode = &tv_modes[i];
		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);