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

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

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

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

Allwinner sun4i DRM driver fixes

A bunch of fixes that address:
  - Compilation errors in various corner cases
  - Move to helpers
  - Fix the pixel clock computation
  - Fix our panel probe

* tag 'sunxi-drm-fixes-for-4.7' of https://git.kernel.org/pub/scm/linux/kernel/git/mripard/linux:
  drm: sun4i: do cleanup if RGB output init fails
  drm/sun4i: Convert to connector register helpers
  drm/sun4i: remove simplefb at probe
  drm/sun4i: rgb: panel is an error pointer
  drm/sun4i: defer only if we didn't find our panel
  drm/sun4i: rgb: Validate the clock rate
  drm/sun4i: request exact rates to our parents
  drm: sun4i: fix probe error handling
  drm: sun4i: print DMA address correctly
  drm/sun4i: add COMMON_CLK dependency
parents c38e8016 13fef095
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
config DRM_SUN4I
	tristate "DRM Support for Allwinner A10 Display Engine"
	depends on DRM && ARM
	depends on DRM && ARM && COMMON_CLK
	depends on ARCH_SUNXI || COMPILE_TEST
	select DRM_GEM_CMA_HELPER
	select DRM_KMS_HELPER
+2 −2
Original line number Diff line number Diff line
@@ -190,7 +190,7 @@ int sun4i_backend_update_layer_buffer(struct sun4i_backend *backend,
	/* Get the physical address of the buffer in memory */
	gem = drm_fb_cma_get_gem_obj(fb, 0);

	DRM_DEBUG_DRIVER("Using GEM @ 0x%x\n", gem->paddr);
	DRM_DEBUG_DRIVER("Using GEM @ %pad\n", &gem->paddr);

	/* Compute the start of the displayed memory */
	bpp = drm_format_plane_cpp(fb->pixel_format, 0);
@@ -198,7 +198,7 @@ int sun4i_backend_update_layer_buffer(struct sun4i_backend *backend,
	paddr += (state->src_x >> 16) * bpp;
	paddr += (state->src_y >> 16) * fb->pitches[0];

	DRM_DEBUG_DRIVER("Setting buffer address to 0x%x\n", paddr);
	DRM_DEBUG_DRIVER("Setting buffer address to %pad\n", &paddr);

	/* Write the 32 lower bits of the address (in bits) */
	lo_paddr = paddr << 3;
+35 −4
Original line number Diff line number Diff line
@@ -72,14 +72,40 @@ static unsigned long sun4i_dclk_recalc_rate(struct clk_hw *hw,
static long sun4i_dclk_round_rate(struct clk_hw *hw, unsigned long rate,
				  unsigned long *parent_rate)
{
	return *parent_rate / DIV_ROUND_CLOSEST(*parent_rate, rate);
	unsigned long best_parent = 0;
	u8 best_div = 1;
	int i;

	for (i = 6; i < 127; i++) {
		unsigned long ideal = rate * i;
		unsigned long rounded;

		rounded = clk_hw_round_rate(clk_hw_get_parent(hw),
					    ideal);

		if (rounded == ideal) {
			best_parent = rounded;
			best_div = i;
			goto out;
		}

		if ((rounded < ideal) && (rounded > best_parent)) {
			best_parent = rounded;
			best_div = i;
		}
	}

out:
	*parent_rate = best_parent;

	return best_parent / best_div;
}

static int sun4i_dclk_set_rate(struct clk_hw *hw, unsigned long rate,
			       unsigned long parent_rate)
{
	struct sun4i_dclk *dclk = hw_to_dclk(hw);
	int div = DIV_ROUND_CLOSEST(parent_rate, rate);
	u8 div = parent_rate / rate;

	return regmap_update_bits(dclk->regmap, SUN4I_TCON0_DCLK_REG,
				  GENMASK(6, 0), div);
@@ -127,10 +153,14 @@ int sun4i_dclk_create(struct device *dev, struct sun4i_tcon *tcon)
	const char *clk_name, *parent_name;
	struct clk_init_data init;
	struct sun4i_dclk *dclk;
	int ret;

	parent_name = __clk_get_name(tcon->sclk0);
	of_property_read_string_index(dev->of_node, "clock-output-names", 0,
	ret = of_property_read_string_index(dev->of_node,
					    "clock-output-names", 0,
					    &clk_name);
	if (ret)
		return ret;

	dclk = devm_kzalloc(dev, sizeof(*dclk), GFP_KERNEL);
	if (!dclk)
@@ -140,6 +170,7 @@ int sun4i_dclk_create(struct device *dev, struct sun4i_tcon *tcon)
	init.ops = &sun4i_dclk_ops;
	init.parent_names = &parent_name;
	init.num_parents = 1;
	init.flags = CLK_SET_RATE_PARENT;

	dclk->regmap = tcon->regs;
	dclk->hw.init = &init;
+21 −29
Original line number Diff line number Diff line
@@ -24,34 +24,6 @@
#include "sun4i_layer.h"
#include "sun4i_tcon.h"

static int sun4i_drv_connector_plug_all(struct drm_device *drm)
{
	struct drm_connector *connector, *failed;
	int ret;

	mutex_lock(&drm->mode_config.mutex);
	list_for_each_entry(connector, &drm->mode_config.connector_list, head) {
		ret = drm_connector_register(connector);
		if (ret) {
			failed = connector;
			goto err;
		}
	}
	mutex_unlock(&drm->mode_config.mutex);
	return 0;

err:
	list_for_each_entry(connector, &drm->mode_config.connector_list, head) {
		if (failed == connector)
			break;

		drm_connector_unregister(connector);
	}
	mutex_unlock(&drm->mode_config.mutex);

	return ret;
}

static int sun4i_drv_enable_vblank(struct drm_device *drm, unsigned int pipe)
{
	struct sun4i_drv *drv = drm->dev_private;
@@ -125,6 +97,22 @@ static struct drm_driver sun4i_drv_driver = {
	.disable_vblank		= sun4i_drv_disable_vblank,
};

static void sun4i_remove_framebuffers(void)
{
	struct apertures_struct *ap;

	ap = alloc_apertures(1);
	if (!ap)
		return;

	/* The framebuffer can be located anywhere in RAM */
	ap->ranges[0].base = 0;
	ap->ranges[0].size = ~0;

	remove_conflicting_framebuffers(ap, "sun4i-drm-fb", false);
	kfree(ap);
}

static int sun4i_drv_bind(struct device *dev)
{
	struct drm_device *drm;
@@ -172,6 +160,9 @@ static int sun4i_drv_bind(struct device *dev)
	}
	drm->irq_enabled = true;

	/* Remove early framebuffers (ie. simplefb) */
	sun4i_remove_framebuffers();

	/* Create our framebuffer */
	drv->fbdev = sun4i_framebuffer_init(drm);
	if (IS_ERR(drv->fbdev)) {
@@ -187,7 +178,7 @@ static int sun4i_drv_bind(struct device *dev)
	if (ret)
		goto free_drm;

	ret = sun4i_drv_connector_plug_all(drm);
	ret = drm_connector_register_all(drm);
	if (ret)
		goto unregister_drm;

@@ -204,6 +195,7 @@ static void sun4i_drv_unbind(struct device *dev)
{
	struct drm_device *drm = dev_get_drvdata(dev);

	drm_connector_unregister_all(drm);
	drm_dev_unregister(drm);
	drm_kms_helper_poll_fini(drm);
	sun4i_framebuffer_free(drm);
+15 −1
Original line number Diff line number Diff line
@@ -54,8 +54,13 @@ static int sun4i_rgb_get_modes(struct drm_connector *connector)
static int sun4i_rgb_mode_valid(struct drm_connector *connector,
				struct drm_display_mode *mode)
{
	struct sun4i_rgb *rgb = drm_connector_to_sun4i_rgb(connector);
	struct sun4i_drv *drv = rgb->drv;
	struct sun4i_tcon *tcon = drv->tcon;
	u32 hsync = mode->hsync_end - mode->hsync_start;
	u32 vsync = mode->vsync_end - mode->vsync_start;
	unsigned long rate = mode->clock * 1000;
	long rounded_rate;

	DRM_DEBUG_DRIVER("Validating modes...\n");

@@ -87,6 +92,15 @@ static int sun4i_rgb_mode_valid(struct drm_connector *connector,

	DRM_DEBUG_DRIVER("Vertical parameters OK\n");

	rounded_rate = clk_round_rate(tcon->dclk, rate);
	if (rounded_rate < rate)
		return MODE_CLOCK_LOW;

	if (rounded_rate > rate)
		return MODE_CLOCK_HIGH;

	DRM_DEBUG_DRIVER("Clock rate OK\n");

	return MODE_OK;
}

@@ -203,7 +217,7 @@ int sun4i_rgb_init(struct drm_device *drm)
	int ret;

	/* If we don't have a panel, there's no point in going on */
	if (!tcon->panel)
	if (IS_ERR(tcon->panel))
		return -ENODEV;

	rgb = devm_kzalloc(drm->dev, sizeof(*rgb), GFP_KERNEL);
Loading