Skip to content

Commit

Permalink
Merge branch 'drm-armada-devel' of git://ftp.arm.linux.org.uk/~rmk/li…
Browse files Browse the repository at this point in the history
…nux-arm into drm-next

Merge armada changes, I've confirmed the componenet changes are same as in Greg's tree.
* 'drm-armada-devel' of git://ftp.arm.linux.org.uk/~rmk/linux-arm:
  drm/armada: register crtc with port
  drm/armada: permit CRTCs to be registered as separate devices
  dt-bindings: add Marvell Dove LCD controller documentation
  drm/armada: update Armada 510 (Dove) to use "ext_ref_clk1" as the clock
  drm/armada: convert to componentized support
  drm: add of_graph endpoint helper to find possible CRTCs
  component: fix bug with legacy API
  drm/armada: make variant a CRTC thing
  drm/armada: move variant initialisation to CRTC init
  drm/armada: use number of CRTCs registered
  drm/armada: move IRQ handling into CRTC
  component: add support for component match array
  component: ignore multiple additions of the same component
  component: fix missed cleanup in case of devres failure
  • Loading branch information
Dave Airlie committed Jul 23, 2014
2 parents 7296c84 + 9611cb9 commit 8a105aa
Show file tree
Hide file tree
Showing 12 changed files with 642 additions and 154 deletions.
30 changes: 30 additions & 0 deletions Documentation/devicetree/bindings/drm/armada/marvell,dove-lcd.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
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";
};
192 changes: 157 additions & 35 deletions drivers/base/component.c
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,23 @@
#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;
bool bound;

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

struct component {
Expand Down Expand Up @@ -69,18 +79,24 @@ 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)
{
struct component *c;
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)) {
component_attach_master(master, c);
if (!c->master)
component_attach_master(master, c);
ret = 0;
break;
}
Expand All @@ -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)
{
Expand All @@ -113,44 +157,44 @@ 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) {
/*
* 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)) {
/* Failed to find all components */
master_remove_components(master);
ret = 0;
goto out;
}
if (master->bound)
return 0;

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

if (!devres_open_group(master->dev, NULL, GFP_KERNEL)) {
ret = -ENOMEM;
goto out;
}
if (component && component->master != master) {
ret = 0;
goto out;
}

/* Found all components */
ret = master->ops->bind(master->dev);
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;
}
if (!devres_open_group(master->dev, NULL, GFP_KERNEL)) {
ret = -ENOMEM;
goto out;
}

master->bound = true;
ret = 1;
/* Found all components */
ret = master->ops->bind(master->dev);
if (ret < 0) {
devres_release_group(master->dev, NULL);
dev_info(master->dev, "master bind failed: %d\n", ret);
goto out;
}

master->bound = true;
return 1;

out:
master_remove_components(master);

return ret;
}
Expand Down Expand Up @@ -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. */
Expand All @@ -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,
Expand Down
1 change: 1 addition & 0 deletions drivers/gpu/drm/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ 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

Expand Down
23 changes: 10 additions & 13 deletions drivers/gpu/drm/armada/armada_510.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}

Expand All @@ -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)
Expand Down Expand Up @@ -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

0 comments on commit 8a105aa

Please sign in to comment.