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

Commit 4dac3edf authored by Daniel Vetter's avatar Daniel Vetter
Browse files

Merge remote-tracking branch 'airlied/drm-next' into drm-intel-next



Pull in drm-next with Dave's DP MST support so that I can merge some
conflicting patches which also touch the driver load sequencing around
interrupt handling.

Conflicts:
	drivers/gpu/drm/i915/intel_display.c
	drivers/gpu/drm/i915/intel_dp.c

Signed-off-by: default avatarDaniel Vetter <daniel.vetter@ffwll.ch>
parents 48777767 e05444be
Loading
Loading
Loading
Loading
+9 −3
Original line number Diff line number Diff line
@@ -1610,7 +1610,7 @@ int max_width, max_height;</synopsis>
          The connector is then registered with a call to
          <function>drm_connector_init</function> with a pointer to the connector
          functions and a connector type, and exposed through sysfs with a call to
          <function>drm_sysfs_connector_add</function>.
          <function>drm_connector_register</function>.
        </para>
        <para>
          Supported connector types are
@@ -1768,7 +1768,7 @@ int max_width, max_height;</synopsis>
	(<function>drm_encoder_cleanup</function>) and connectors
	(<function>drm_connector_cleanup</function>). Furthermore, connectors
	that have been added to sysfs must be removed by a call to
	<function>drm_sysfs_connector_remove</function> before calling
	<function>drm_connector_unregister</function> before calling
	<function>drm_connector_cleanup</function>.
      </para>
      <para>
@@ -1813,7 +1813,7 @@ void intel_crt_init(struct drm_device *dev)
	drm_encoder_helper_add(&intel_output->enc, &intel_crt_helper_funcs);
	drm_connector_helper_add(connector, &intel_crt_connector_helper_funcs);

	drm_sysfs_connector_add(connector);
	drm_connector_register(connector);
}]]></programlisting>
      <para>
        In the example above (taken from the i915 driver), a CRTC, connector and
@@ -2336,6 +2336,12 @@ void intel_crt_init(struct drm_device *dev)
!Pdrivers/gpu/drm/drm_dp_helper.c dp helpers
!Iinclude/drm/drm_dp_helper.h
!Edrivers/gpu/drm/drm_dp_helper.c
    </sect2>
    <sect2>
      <title>Display Port MST Helper Functions Reference</title>
!Pdrivers/gpu/drm/drm_dp_mst_topology.c dp mst helper
!Iinclude/drm/drm_dp_mst_helper.h
!Edrivers/gpu/drm/drm_dp_mst_topology.c
    </sect2>
    <sect2>
      <title>EDID Helper Functions Reference</title>
+30 −0
Original line number Diff line number Diff line
Device Tree bindings for Armada DRM CRTC driver

Required properties:
 - compatible: value should be "marvell,dove-lcd".
 - reg: base address and size of the LCD controller
 - interrupts: single interrupt number for the LCD controller
 - port: video output port with endpoints, as described by graph.txt

Optional properties:

 - clocks: as described by clock-bindings.txt
 - clock-names: as described by clock-bindings.txt
	"axiclk" - axi bus clock for pixel clock
	"plldivider" - pll divider clock for pixel clock
	"ext_ref_clk0" - external clock 0 for pixel clock
	"ext_ref_clk1" - external clock 1 for pixel clock

Note: all clocks are optional but at least one must be specified.
Further clocks may be added in the future according to requirements of
different SoCs.

Example:

	lcd0: lcd-controller@820000 {
		compatible = "marvell,dove-lcd";
		reg = <0x820000 0x1000>;
		interrupts = <47>;
		clocks = <&si5351 0>;
		clock-names = "ext_ref_clk_1";
	};
+157 −35
Original line number Diff line number Diff line
@@ -18,6 +18,15 @@
#include <linux/mutex.h>
#include <linux/slab.h>

struct component_match {
	size_t alloc;
	size_t num;
	struct {
		void *data;
		int (*fn)(struct device *, void *);
	} compare[0];
};

struct master {
	struct list_head node;
	struct list_head components;
@@ -25,6 +34,7 @@ struct master {

	const struct component_master_ops *ops;
	struct device *dev;
	struct component_match *match;
};

struct component {
@@ -69,6 +79,11 @@ static void component_detach_master(struct master *master, struct component *c)
	c->master = NULL;
}

/*
 * Add a component to a master, finding the component via the compare
 * function and compare data.  This is safe to call for duplicate matches
 * and will not result in the same component being added multiple times.
 */
int component_master_add_child(struct master *master,
	int (*compare)(struct device *, void *), void *compare_data)
{
@@ -76,10 +91,11 @@ int component_master_add_child(struct master *master,
	int ret = -ENXIO;

	list_for_each_entry(c, &component_list, node) {
		if (c->master)
		if (c->master && c->master != master)
			continue;

		if (compare(c->dev, compare_data)) {
			if (!c->master)
				component_attach_master(master, c);
			ret = 0;
			break;
@@ -90,6 +106,34 @@ int component_master_add_child(struct master *master,
}
EXPORT_SYMBOL_GPL(component_master_add_child);

static int find_components(struct master *master)
{
	struct component_match *match = master->match;
	size_t i;
	int ret = 0;

	if (!match) {
		/*
		 * Search the list of components, looking for components that
		 * belong to this master, and attach them to the master.
		 */
		return master->ops->add_components(master->dev, master);
	}

	/*
	 * Scan the array of match functions and attach
	 * any components which are found to this master.
	 */
	for (i = 0; i < match->num; i++) {
		ret = component_master_add_child(master,
						 match->compare[i].fn,
						 match->compare[i].data);
		if (ret)
			break;
	}
	return ret;
}

/* Detach all attached components from this master */
static void master_remove_components(struct master *master)
{
@@ -113,22 +157,22 @@ static void master_remove_components(struct master *master)
static int try_to_bring_up_master(struct master *master,
	struct component *component)
{
	int ret = 0;
	int ret;

	if (master->bound)
		return 0;

	if (!master->bound) {
	/*
	 * Search the list of components, looking for components that
	 * belong to this master, and attach them to the master.
	 */
		if (master->ops->add_components(master->dev, master)) {
	if (find_components(master)) {
		/* Failed to find all components */
			master_remove_components(master);
		ret = 0;
		goto out;
	}

	if (component && component->master != master) {
			master_remove_components(master);
		ret = 0;
		goto out;
	}
@@ -143,14 +187,14 @@ static int try_to_bring_up_master(struct master *master,
	if (ret < 0) {
		devres_release_group(master->dev, NULL);
		dev_info(master->dev, "master bind failed: %d\n", ret);
			master_remove_components(master);
		goto out;
	}

	master->bound = true;
		ret = 1;
	}
	return 1;

out:
	master_remove_components(master);

	return ret;
}
@@ -180,18 +224,89 @@ static void take_down_master(struct master *master)
	master_remove_components(master);
}

int component_master_add(struct device *dev,
	const struct component_master_ops *ops)
static size_t component_match_size(size_t num)
{
	return offsetof(struct component_match, compare[num]);
}

static struct component_match *component_match_realloc(struct device *dev,
	struct component_match *match, size_t num)
{
	struct component_match *new;

	if (match && match->alloc == num)
		return match;

	new = devm_kmalloc(dev, component_match_size(num), GFP_KERNEL);
	if (!new)
		return ERR_PTR(-ENOMEM);

	if (match) {
		memcpy(new, match, component_match_size(min(match->num, num)));
		devm_kfree(dev, match);
	} else {
		new->num = 0;
	}

	new->alloc = num;

	return new;
}

/*
 * Add a component to be matched.
 *
 * The match array is first created or extended if necessary.
 */
void component_match_add(struct device *dev, struct component_match **matchptr,
	int (*compare)(struct device *, void *), void *compare_data)
{
	struct component_match *match = *matchptr;

	if (IS_ERR(match))
		return;

	if (!match || match->num == match->alloc) {
		size_t new_size = match ? match->alloc + 16 : 15;

		match = component_match_realloc(dev, match, new_size);

		*matchptr = match;

		if (IS_ERR(match))
			return;
	}

	match->compare[match->num].fn = compare;
	match->compare[match->num].data = compare_data;
	match->num++;
}
EXPORT_SYMBOL(component_match_add);

int component_master_add_with_match(struct device *dev,
	const struct component_master_ops *ops,
	struct component_match *match)
{
	struct master *master;
	int ret;

	if (ops->add_components && match)
		return -EINVAL;

	if (match) {
		/* Reallocate the match array for its true size */
		match = component_match_realloc(dev, match, match->num);
		if (IS_ERR(match))
			return PTR_ERR(match);
	}

	master = kzalloc(sizeof(*master), GFP_KERNEL);
	if (!master)
		return -ENOMEM;

	master->dev = dev;
	master->ops = ops;
	master->match = match;
	INIT_LIST_HEAD(&master->components);

	/* Add to the list of available masters. */
@@ -209,6 +324,13 @@ int component_master_add(struct device *dev,

	return ret < 0 ? ret : 0;
}
EXPORT_SYMBOL_GPL(component_master_add_with_match);

int component_master_add(struct device *dev,
	const struct component_master_ops *ops)
{
	return component_master_add_with_match(dev, ops, NULL);
}
EXPORT_SYMBOL_GPL(component_master_add);

void component_master_del(struct device *dev,
+2 −1
Original line number Diff line number Diff line
@@ -20,11 +20,12 @@ drm-$(CONFIG_COMPAT) += drm_ioc32.o
drm-$(CONFIG_DRM_GEM_CMA_HELPER) += drm_gem_cma_helper.o
drm-$(CONFIG_PCI) += ati_pcigart.o
drm-$(CONFIG_DRM_PANEL) += drm_panel.o
drm-$(CONFIG_OF) += drm_of.o

drm-usb-y   := drm_usb.o

drm_kms_helper-y := drm_crtc_helper.o drm_dp_helper.o drm_probe_helper.o \
		drm_plane_helper.o
		drm_plane_helper.o drm_dp_mst_topology.o
drm_kms_helper-$(CONFIG_DRM_LOAD_EDID_FIRMWARE) += drm_edid_load.o
drm_kms_helper-$(CONFIG_DRM_KMS_FB_HELPER) += drm_fb_helper.o
drm_kms_helper-$(CONFIG_DRM_KMS_CMA_HELPER) += drm_fb_cma_helper.o
+10 −13
Original line number Diff line number Diff line
@@ -15,20 +15,19 @@
#include "armada_drm.h"
#include "armada_hw.h"

static int armada510_init(struct armada_private *priv, struct device *dev)
static int armada510_crtc_init(struct armada_crtc *dcrtc, struct device *dev)
{
	priv->extclk[0] = devm_clk_get(dev, "ext_ref_clk_1");
	struct clk *clk;

	if (IS_ERR(priv->extclk[0]) && PTR_ERR(priv->extclk[0]) == -ENOENT)
		priv->extclk[0] = ERR_PTR(-EPROBE_DEFER);
	clk = devm_clk_get(dev, "ext_ref_clk1");
	if (IS_ERR(clk))
		return PTR_ERR(clk) == -ENOENT ? -EPROBE_DEFER : PTR_ERR(clk);

	return PTR_RET(priv->extclk[0]);
}
	dcrtc->extclk[0] = clk;

static int armada510_crtc_init(struct armada_crtc *dcrtc)
{
	/* Lower the watermark so to eliminate jitter at higher bandwidths */
	armada_updatel(0x20, (1 << 11) | 0xff, dcrtc->base + LCD_CFG_RDREG4F);

	return 0;
}

@@ -45,8 +44,7 @@ static int armada510_crtc_init(struct armada_crtc *dcrtc)
static int armada510_crtc_compute_clock(struct armada_crtc *dcrtc,
	const struct drm_display_mode *mode, uint32_t *sclk)
{
	struct armada_private *priv = dcrtc->crtc.dev->dev_private;
	struct clk *clk = priv->extclk[0];
	struct clk *clk = dcrtc->extclk[0];
	int ret;

	if (dcrtc->num == 1)
@@ -81,7 +79,6 @@ static int armada510_crtc_compute_clock(struct armada_crtc *dcrtc,
const struct armada_variant armada510_ops = {
	.has_spu_adv_reg = true,
	.spu_adv_reg = ADV_HWC32ENABLE | ADV_HWC32ARGB | ADV_HWC32BLEND,
	.init = armada510_init,
	.crtc_init = armada510_crtc_init,
	.crtc_compute_clock = armada510_crtc_compute_clock,
	.init = armada510_crtc_init,
	.compute_clock = armada510_crtc_compute_clock,
};
Loading