aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Documentation/devicetree/bindings/drm/armada/marvell,dove-lcd.txt30
-rw-r--r--drivers/base/component.c192
-rw-r--r--drivers/gpu/drm/Makefile1
-rw-r--r--drivers/gpu/drm/armada/armada_510.c23
-rw-r--r--drivers/gpu/drm/armada/armada_crtc.c187
-rw-r--r--drivers/gpu/drm/armada/armada_crtc.h11
-rw-r--r--drivers/gpu/drm/armada/armada_drm.h13
-rw-r--r--drivers/gpu/drm/armada/armada_drv.c245
-rw-r--r--drivers/gpu/drm/drm_of.c67
-rw-r--r--include/drm/drm_crtc.h2
-rw-r--r--include/drm/drm_of.h18
-rw-r--r--include/linux/component.h7
12 files changed, 642 insertions, 154 deletions
diff --git a/Documentation/devicetree/bindings/drm/armada/marvell,dove-lcd.txt b/Documentation/devicetree/bindings/drm/armada/marvell,dove-lcd.txt
new file mode 100644
index 000000000000..46525ea3e646
--- /dev/null
+++ b/Documentation/devicetree/bindings/drm/armada/marvell,dove-lcd.txt
@@ -0,0 +1,30 @@
1Device Tree bindings for Armada DRM CRTC driver
2
3Required properties:
4 - compatible: value should be "marvell,dove-lcd".
5 - reg: base address and size of the LCD controller
6 - interrupts: single interrupt number for the LCD controller
7 - port: video output port with endpoints, as described by graph.txt
8
9Optional properties:
10
11 - clocks: as described by clock-bindings.txt
12 - clock-names: as described by clock-bindings.txt
13 "axiclk" - axi bus clock for pixel clock
14 "plldivider" - pll divider clock for pixel clock
15 "ext_ref_clk0" - external clock 0 for pixel clock
16 "ext_ref_clk1" - external clock 1 for pixel clock
17
18Note: all clocks are optional but at least one must be specified.
19Further clocks may be added in the future according to requirements of
20different SoCs.
21
22Example:
23
24 lcd0: lcd-controller@820000 {
25 compatible = "marvell,dove-lcd";
26 reg = <0x820000 0x1000>;
27 interrupts = <47>;
28 clocks = <&si5351 0>;
29 clock-names = "ext_ref_clk_1";
30 };
diff --git a/drivers/base/component.c b/drivers/base/component.c
index c4778995cd72..f748430bb654 100644
--- a/drivers/base/component.c
+++ b/drivers/base/component.c
@@ -18,6 +18,15 @@
18#include <linux/mutex.h> 18#include <linux/mutex.h>
19#include <linux/slab.h> 19#include <linux/slab.h>
20 20
21struct component_match {
22 size_t alloc;
23 size_t num;
24 struct {
25 void *data;
26 int (*fn)(struct device *, void *);
27 } compare[0];
28};
29
21struct master { 30struct master {
22 struct list_head node; 31 struct list_head node;
23 struct list_head components; 32 struct list_head components;
@@ -25,6 +34,7 @@ struct master {
25 34
26 const struct component_master_ops *ops; 35 const struct component_master_ops *ops;
27 struct device *dev; 36 struct device *dev;
37 struct component_match *match;
28}; 38};
29 39
30struct component { 40struct component {
@@ -69,6 +79,11 @@ static void component_detach_master(struct master *master, struct component *c)
69 c->master = NULL; 79 c->master = NULL;
70} 80}
71 81
82/*
83 * Add a component to a master, finding the component via the compare
84 * function and compare data. This is safe to call for duplicate matches
85 * and will not result in the same component being added multiple times.
86 */
72int component_master_add_child(struct master *master, 87int component_master_add_child(struct master *master,
73 int (*compare)(struct device *, void *), void *compare_data) 88 int (*compare)(struct device *, void *), void *compare_data)
74{ 89{
@@ -76,11 +91,12 @@ int component_master_add_child(struct master *master,
76 int ret = -ENXIO; 91 int ret = -ENXIO;
77 92
78 list_for_each_entry(c, &component_list, node) { 93 list_for_each_entry(c, &component_list, node) {
79 if (c->master) 94 if (c->master && c->master != master)
80 continue; 95 continue;
81 96
82 if (compare(c->dev, compare_data)) { 97 if (compare(c->dev, compare_data)) {
83 component_attach_master(master, c); 98 if (!c->master)
99 component_attach_master(master, c);
84 ret = 0; 100 ret = 0;
85 break; 101 break;
86 } 102 }
@@ -90,6 +106,34 @@ int component_master_add_child(struct master *master,
90} 106}
91EXPORT_SYMBOL_GPL(component_master_add_child); 107EXPORT_SYMBOL_GPL(component_master_add_child);
92 108
109static int find_components(struct master *master)
110{
111 struct component_match *match = master->match;
112 size_t i;
113 int ret = 0;
114
115 if (!match) {
116 /*
117 * Search the list of components, looking for components that
118 * belong to this master, and attach them to the master.
119 */
120 return master->ops->add_components(master->dev, master);
121 }
122
123 /*
124 * Scan the array of match functions and attach
125 * any components which are found to this master.
126 */
127 for (i = 0; i < match->num; i++) {
128 ret = component_master_add_child(master,
129 match->compare[i].fn,
130 match->compare[i].data);
131 if (ret)
132 break;
133 }
134 return ret;
135}
136
93/* Detach all attached components from this master */ 137/* Detach all attached components from this master */
94static void master_remove_components(struct master *master) 138static void master_remove_components(struct master *master)
95{ 139{
@@ -113,44 +157,44 @@ static void master_remove_components(struct master *master)
113static int try_to_bring_up_master(struct master *master, 157static int try_to_bring_up_master(struct master *master,
114 struct component *component) 158 struct component *component)
115{ 159{
116 int ret = 0; 160 int ret;
117 161
118 if (!master->bound) { 162 if (master->bound)
119 /* 163 return 0;
120 * Search the list of components, looking for components that
121 * belong to this master, and attach them to the master.
122 */
123 if (master->ops->add_components(master->dev, master)) {
124 /* Failed to find all components */
125 master_remove_components(master);
126 ret = 0;
127 goto out;
128 }
129 164
130 if (component && component->master != master) { 165 /*
131 master_remove_components(master); 166 * Search the list of components, looking for components that
132 ret = 0; 167 * belong to this master, and attach them to the master.
133 goto out; 168 */
134 } 169 if (find_components(master)) {
170 /* Failed to find all components */
171 ret = 0;
172 goto out;
173 }
135 174
136 if (!devres_open_group(master->dev, NULL, GFP_KERNEL)) { 175 if (component && component->master != master) {
137 ret = -ENOMEM; 176 ret = 0;
138 goto out; 177 goto out;
139 } 178 }
140 179
141 /* Found all components */ 180 if (!devres_open_group(master->dev, NULL, GFP_KERNEL)) {
142 ret = master->ops->bind(master->dev); 181 ret = -ENOMEM;
143 if (ret < 0) { 182 goto out;
144 devres_release_group(master->dev, NULL); 183 }
145 dev_info(master->dev, "master bind failed: %d\n", ret);
146 master_remove_components(master);
147 goto out;
148 }
149 184
150 master->bound = true; 185 /* Found all components */
151 ret = 1; 186 ret = master->ops->bind(master->dev);
187 if (ret < 0) {
188 devres_release_group(master->dev, NULL);
189 dev_info(master->dev, "master bind failed: %d\n", ret);
190 goto out;
152 } 191 }
192
193 master->bound = true;
194 return 1;
195
153out: 196out:
197 master_remove_components(master);
154 198
155 return ret; 199 return ret;
156} 200}
@@ -180,18 +224,89 @@ static void take_down_master(struct master *master)
180 master_remove_components(master); 224 master_remove_components(master);
181} 225}
182 226
183int component_master_add(struct device *dev, 227static size_t component_match_size(size_t num)
184 const struct component_master_ops *ops) 228{
229 return offsetof(struct component_match, compare[num]);
230}
231
232static struct component_match *component_match_realloc(struct device *dev,
233 struct component_match *match, size_t num)
234{
235 struct component_match *new;
236
237 if (match && match->alloc == num)
238 return match;
239
240 new = devm_kmalloc(dev, component_match_size(num), GFP_KERNEL);
241 if (!new)
242 return ERR_PTR(-ENOMEM);
243
244 if (match) {
245 memcpy(new, match, component_match_size(min(match->num, num)));
246 devm_kfree(dev, match);
247 } else {
248 new->num = 0;
249 }
250
251 new->alloc = num;
252
253 return new;
254}
255
256/*
257 * Add a component to be matched.
258 *
259 * The match array is first created or extended if necessary.
260 */
261void component_match_add(struct device *dev, struct component_match **matchptr,
262 int (*compare)(struct device *, void *), void *compare_data)
263{
264 struct component_match *match = *matchptr;
265
266 if (IS_ERR(match))
267 return;
268
269 if (!match || match->num == match->alloc) {
270 size_t new_size = match ? match->alloc + 16 : 15;
271
272 match = component_match_realloc(dev, match, new_size);
273
274 *matchptr = match;
275
276 if (IS_ERR(match))
277 return;
278 }
279
280 match->compare[match->num].fn = compare;
281 match->compare[match->num].data = compare_data;
282 match->num++;
283}
284EXPORT_SYMBOL(component_match_add);
285
286int component_master_add_with_match(struct device *dev,
287 const struct component_master_ops *ops,
288 struct component_match *match)
185{ 289{
186 struct master *master; 290 struct master *master;
187 int ret; 291 int ret;
188 292
293 if (ops->add_components && match)
294 return -EINVAL;
295
296 if (match) {
297 /* Reallocate the match array for its true size */
298 match = component_match_realloc(dev, match, match->num);
299 if (IS_ERR(match))
300 return PTR_ERR(match);
301 }
302
189 master = kzalloc(sizeof(*master), GFP_KERNEL); 303 master = kzalloc(sizeof(*master), GFP_KERNEL);
190 if (!master) 304 if (!master)
191 return -ENOMEM; 305 return -ENOMEM;
192 306
193 master->dev = dev; 307 master->dev = dev;
194 master->ops = ops; 308 master->ops = ops;
309 master->match = match;
195 INIT_LIST_HEAD(&master->components); 310 INIT_LIST_HEAD(&master->components);
196 311
197 /* Add to the list of available masters. */ 312 /* Add to the list of available masters. */
@@ -209,6 +324,13 @@ int component_master_add(struct device *dev,
209 324
210 return ret < 0 ? ret : 0; 325 return ret < 0 ? ret : 0;
211} 326}
327EXPORT_SYMBOL_GPL(component_master_add_with_match);
328
329int component_master_add(struct device *dev,
330 const struct component_master_ops *ops)
331{
332 return component_master_add_with_match(dev, ops, NULL);
333}
212EXPORT_SYMBOL_GPL(component_master_add); 334EXPORT_SYMBOL_GPL(component_master_add);
213 335
214void component_master_del(struct device *dev, 336void component_master_del(struct device *dev,
diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile
index af9a609861c2..61d9e9c6bc10 100644
--- a/drivers/gpu/drm/Makefile
+++ b/drivers/gpu/drm/Makefile
@@ -20,6 +20,7 @@ drm-$(CONFIG_COMPAT) += drm_ioc32.o
20drm-$(CONFIG_DRM_GEM_CMA_HELPER) += drm_gem_cma_helper.o 20drm-$(CONFIG_DRM_GEM_CMA_HELPER) += drm_gem_cma_helper.o
21drm-$(CONFIG_PCI) += ati_pcigart.o 21drm-$(CONFIG_PCI) += ati_pcigart.o
22drm-$(CONFIG_DRM_PANEL) += drm_panel.o 22drm-$(CONFIG_DRM_PANEL) += drm_panel.o
23drm-$(CONFIG_OF) += drm_of.o
23 24
24drm-usb-y := drm_usb.o 25drm-usb-y := drm_usb.o
25 26
diff --git a/drivers/gpu/drm/armada/armada_510.c b/drivers/gpu/drm/armada/armada_510.c
index 59948eff6095..ad3d2ebf95c9 100644
--- a/drivers/gpu/drm/armada/armada_510.c
+++ b/drivers/gpu/drm/armada/armada_510.c
@@ -15,20 +15,19 @@
15#include "armada_drm.h" 15#include "armada_drm.h"
16#include "armada_hw.h" 16#include "armada_hw.h"
17 17
18static int armada510_init(struct armada_private *priv, struct device *dev) 18static int armada510_crtc_init(struct armada_crtc *dcrtc, struct device *dev)
19{ 19{
20 priv->extclk[0] = devm_clk_get(dev, "ext_ref_clk_1"); 20 struct clk *clk;
21 21
22 if (IS_ERR(priv->extclk[0]) && PTR_ERR(priv->extclk[0]) == -ENOENT) 22 clk = devm_clk_get(dev, "ext_ref_clk1");
23 priv->extclk[0] = ERR_PTR(-EPROBE_DEFER); 23 if (IS_ERR(clk))
24 return PTR_ERR(clk) == -ENOENT ? -EPROBE_DEFER : PTR_ERR(clk);
24 25
25 return PTR_RET(priv->extclk[0]); 26 dcrtc->extclk[0] = clk;
26}
27 27
28static int armada510_crtc_init(struct armada_crtc *dcrtc)
29{
30 /* Lower the watermark so to eliminate jitter at higher bandwidths */ 28 /* Lower the watermark so to eliminate jitter at higher bandwidths */
31 armada_updatel(0x20, (1 << 11) | 0xff, dcrtc->base + LCD_CFG_RDREG4F); 29 armada_updatel(0x20, (1 << 11) | 0xff, dcrtc->base + LCD_CFG_RDREG4F);
30
32 return 0; 31 return 0;
33} 32}
34 33
@@ -45,8 +44,7 @@ static int armada510_crtc_init(struct armada_crtc *dcrtc)
45static int armada510_crtc_compute_clock(struct armada_crtc *dcrtc, 44static int armada510_crtc_compute_clock(struct armada_crtc *dcrtc,
46 const struct drm_display_mode *mode, uint32_t *sclk) 45 const struct drm_display_mode *mode, uint32_t *sclk)
47{ 46{
48 struct armada_private *priv = dcrtc->crtc.dev->dev_private; 47 struct clk *clk = dcrtc->extclk[0];
49 struct clk *clk = priv->extclk[0];
50 int ret; 48 int ret;
51 49
52 if (dcrtc->num == 1) 50 if (dcrtc->num == 1)
@@ -81,7 +79,6 @@ static int armada510_crtc_compute_clock(struct armada_crtc *dcrtc,
81const struct armada_variant armada510_ops = { 79const struct armada_variant armada510_ops = {
82 .has_spu_adv_reg = true, 80 .has_spu_adv_reg = true,
83 .spu_adv_reg = ADV_HWC32ENABLE | ADV_HWC32ARGB | ADV_HWC32BLEND, 81 .spu_adv_reg = ADV_HWC32ENABLE | ADV_HWC32ARGB | ADV_HWC32BLEND,
84 .init = armada510_init, 82 .init = armada510_crtc_init,
85 .crtc_init = armada510_crtc_init, 83 .compute_clock = armada510_crtc_compute_clock,
86 .crtc_compute_clock = armada510_crtc_compute_clock,
87}; 84};
diff --git a/drivers/gpu/drm/armada/armada_crtc.c b/drivers/gpu/drm/armada/armada_crtc.c
index 81c34f949dfc..3f620e21e06b 100644
--- a/drivers/gpu/drm/armada/armada_crtc.c
+++ b/drivers/gpu/drm/armada/armada_crtc.c
@@ -7,6 +7,9 @@
7 * published by the Free Software Foundation. 7 * published by the Free Software Foundation.
8 */ 8 */
9#include <linux/clk.h> 9#include <linux/clk.h>
10#include <linux/component.h>
11#include <linux/of_device.h>
12#include <linux/platform_device.h>
10#include <drm/drmP.h> 13#include <drm/drmP.h>
11#include <drm/drm_crtc_helper.h> 14#include <drm/drm_crtc_helper.h>
12#include "armada_crtc.h" 15#include "armada_crtc.h"
@@ -332,24 +335,23 @@ static void armada_drm_crtc_commit(struct drm_crtc *crtc)
332static bool armada_drm_crtc_mode_fixup(struct drm_crtc *crtc, 335static bool armada_drm_crtc_mode_fixup(struct drm_crtc *crtc,
333 const struct drm_display_mode *mode, struct drm_display_mode *adj) 336 const struct drm_display_mode *mode, struct drm_display_mode *adj)
334{ 337{
335 struct armada_private *priv = crtc->dev->dev_private;
336 struct armada_crtc *dcrtc = drm_to_armada_crtc(crtc); 338 struct armada_crtc *dcrtc = drm_to_armada_crtc(crtc);
337 int ret; 339 int ret;
338 340
339 /* We can't do interlaced modes if we don't have the SPU_ADV_REG */ 341 /* We can't do interlaced modes if we don't have the SPU_ADV_REG */
340 if (!priv->variant->has_spu_adv_reg && 342 if (!dcrtc->variant->has_spu_adv_reg &&
341 adj->flags & DRM_MODE_FLAG_INTERLACE) 343 adj->flags & DRM_MODE_FLAG_INTERLACE)
342 return false; 344 return false;
343 345
344 /* Check whether the display mode is possible */ 346 /* Check whether the display mode is possible */
345 ret = priv->variant->crtc_compute_clock(dcrtc, adj, NULL); 347 ret = dcrtc->variant->compute_clock(dcrtc, adj, NULL);
346 if (ret) 348 if (ret)
347 return false; 349 return false;
348 350
349 return true; 351 return true;
350} 352}
351 353
352void armada_drm_crtc_irq(struct armada_crtc *dcrtc, u32 stat) 354static void armada_drm_crtc_irq(struct armada_crtc *dcrtc, u32 stat)
353{ 355{
354 struct armada_vbl_event *e, *n; 356 struct armada_vbl_event *e, *n;
355 void __iomem *base = dcrtc->base; 357 void __iomem *base = dcrtc->base;
@@ -410,6 +412,27 @@ void armada_drm_crtc_irq(struct armada_crtc *dcrtc, u32 stat)
410 } 412 }
411} 413}
412 414
415static irqreturn_t armada_drm_irq(int irq, void *arg)
416{
417 struct armada_crtc *dcrtc = arg;
418 u32 v, stat = readl_relaxed(dcrtc->base + LCD_SPU_IRQ_ISR);
419
420 /*
421 * This is rediculous - rather than writing bits to clear, we
422 * have to set the actual status register value. This is racy.
423 */
424 writel_relaxed(0, dcrtc->base + LCD_SPU_IRQ_ISR);
425
426 /* Mask out those interrupts we haven't enabled */
427 v = stat & dcrtc->irq_ena;
428
429 if (v & (VSYNC_IRQ|GRA_FRAME_IRQ|DUMB_FRAMEDONE)) {
430 armada_drm_crtc_irq(dcrtc, stat);
431 return IRQ_HANDLED;
432 }
433 return IRQ_NONE;
434}
435
413/* These are locked by dev->vbl_lock */ 436/* These are locked by dev->vbl_lock */
414void armada_drm_crtc_disable_irq(struct armada_crtc *dcrtc, u32 mask) 437void armada_drm_crtc_disable_irq(struct armada_crtc *dcrtc, u32 mask)
415{ 438{
@@ -470,7 +493,6 @@ static int armada_drm_crtc_mode_set(struct drm_crtc *crtc,
470 struct drm_display_mode *mode, struct drm_display_mode *adj, 493 struct drm_display_mode *mode, struct drm_display_mode *adj,
471 int x, int y, struct drm_framebuffer *old_fb) 494 int x, int y, struct drm_framebuffer *old_fb)
472{ 495{
473 struct armada_private *priv = crtc->dev->dev_private;
474 struct armada_crtc *dcrtc = drm_to_armada_crtc(crtc); 496 struct armada_crtc *dcrtc = drm_to_armada_crtc(crtc);
475 struct armada_regs regs[17]; 497 struct armada_regs regs[17];
476 uint32_t lm, rm, tm, bm, val, sclk; 498 uint32_t lm, rm, tm, bm, val, sclk;
@@ -515,7 +537,7 @@ static int armada_drm_crtc_mode_set(struct drm_crtc *crtc,
515 } 537 }
516 538
517 /* Now compute the divider for real */ 539 /* Now compute the divider for real */
518 priv->variant->crtc_compute_clock(dcrtc, adj, &sclk); 540 dcrtc->variant->compute_clock(dcrtc, adj, &sclk);
519 541
520 /* Ensure graphic fifo is enabled */ 542 /* Ensure graphic fifo is enabled */
521 armada_reg_queue_mod(regs, i, 0, CFG_PDWN64x66, LCD_SPU_SRAM_PARA1); 543 armada_reg_queue_mod(regs, i, 0, CFG_PDWN64x66, LCD_SPU_SRAM_PARA1);
@@ -537,7 +559,7 @@ static int armada_drm_crtc_mode_set(struct drm_crtc *crtc,
537 dcrtc->v[1].spu_v_porch = tm << 16 | bm; 559 dcrtc->v[1].spu_v_porch = tm << 16 | bm;
538 val = adj->crtc_hsync_start; 560 val = adj->crtc_hsync_start;
539 dcrtc->v[1].spu_adv_reg = val << 20 | val | ADV_VSYNCOFFEN | 561 dcrtc->v[1].spu_adv_reg = val << 20 | val | ADV_VSYNCOFFEN |
540 priv->variant->spu_adv_reg; 562 dcrtc->variant->spu_adv_reg;
541 563
542 if (interlaced) { 564 if (interlaced) {
543 /* Odd interlaced frame */ 565 /* Odd interlaced frame */
@@ -546,7 +568,7 @@ static int armada_drm_crtc_mode_set(struct drm_crtc *crtc,
546 dcrtc->v[0].spu_v_porch = dcrtc->v[1].spu_v_porch + 1; 568 dcrtc->v[0].spu_v_porch = dcrtc->v[1].spu_v_porch + 1;
547 val = adj->crtc_hsync_start - adj->crtc_htotal / 2; 569 val = adj->crtc_hsync_start - adj->crtc_htotal / 2;
548 dcrtc->v[0].spu_adv_reg = val << 20 | val | ADV_VSYNCOFFEN | 570 dcrtc->v[0].spu_adv_reg = val << 20 | val | ADV_VSYNCOFFEN |
549 priv->variant->spu_adv_reg; 571 dcrtc->variant->spu_adv_reg;
550 } else { 572 } else {
551 dcrtc->v[0] = dcrtc->v[1]; 573 dcrtc->v[0] = dcrtc->v[1];
552 } 574 }
@@ -561,7 +583,7 @@ static int armada_drm_crtc_mode_set(struct drm_crtc *crtc,
561 armada_reg_queue_set(regs, i, dcrtc->v[0].spu_v_h_total, 583 armada_reg_queue_set(regs, i, dcrtc->v[0].spu_v_h_total,
562 LCD_SPUT_V_H_TOTAL); 584 LCD_SPUT_V_H_TOTAL);
563 585
564 if (priv->variant->has_spu_adv_reg) { 586 if (dcrtc->variant->has_spu_adv_reg) {
565 armada_reg_queue_mod(regs, i, dcrtc->v[0].spu_adv_reg, 587 armada_reg_queue_mod(regs, i, dcrtc->v[0].spu_adv_reg,
566 ADV_VSYNC_L_OFF | ADV_VSYNC_H_OFF | 588 ADV_VSYNC_L_OFF | ADV_VSYNC_H_OFF |
567 ADV_VSYNCOFFEN, LCD_SPU_ADV_REG); 589 ADV_VSYNCOFFEN, LCD_SPU_ADV_REG);
@@ -805,12 +827,11 @@ static int armada_drm_crtc_cursor_set(struct drm_crtc *crtc,
805{ 827{
806 struct drm_device *dev = crtc->dev; 828 struct drm_device *dev = crtc->dev;
807 struct armada_crtc *dcrtc = drm_to_armada_crtc(crtc); 829 struct armada_crtc *dcrtc = drm_to_armada_crtc(crtc);
808 struct armada_private *priv = crtc->dev->dev_private;
809 struct armada_gem_object *obj = NULL; 830 struct armada_gem_object *obj = NULL;
810 int ret; 831 int ret;
811 832
812 /* If no cursor support, replicate drm's return value */ 833 /* If no cursor support, replicate drm's return value */
813 if (!priv->variant->has_spu_adv_reg) 834 if (!dcrtc->variant->has_spu_adv_reg)
814 return -ENXIO; 835 return -ENXIO;
815 836
816 if (handle && w > 0 && h > 0) { 837 if (handle && w > 0 && h > 0) {
@@ -858,11 +879,10 @@ static int armada_drm_crtc_cursor_move(struct drm_crtc *crtc, int x, int y)
858{ 879{
859 struct drm_device *dev = crtc->dev; 880 struct drm_device *dev = crtc->dev;
860 struct armada_crtc *dcrtc = drm_to_armada_crtc(crtc); 881 struct armada_crtc *dcrtc = drm_to_armada_crtc(crtc);
861 struct armada_private *priv = crtc->dev->dev_private;
862 int ret; 882 int ret;
863 883
864 /* If no cursor support, replicate drm's return value */ 884 /* If no cursor support, replicate drm's return value */
865 if (!priv->variant->has_spu_adv_reg) 885 if (!dcrtc->variant->has_spu_adv_reg)
866 return -EFAULT; 886 return -EFAULT;
867 887
868 mutex_lock(&dev->struct_mutex); 888 mutex_lock(&dev->struct_mutex);
@@ -888,6 +908,10 @@ static void armada_drm_crtc_destroy(struct drm_crtc *crtc)
888 if (!IS_ERR(dcrtc->clk)) 908 if (!IS_ERR(dcrtc->clk))
889 clk_disable_unprepare(dcrtc->clk); 909 clk_disable_unprepare(dcrtc->clk);
890 910
911 writel_relaxed(0, dcrtc->base + LCD_SPU_IRQ_ENA);
912
913 of_node_put(dcrtc->crtc.port);
914
891 kfree(dcrtc); 915 kfree(dcrtc);
892} 916}
893 917
@@ -1027,19 +1051,20 @@ static int armada_drm_crtc_create_properties(struct drm_device *dev)
1027 return 0; 1051 return 0;
1028} 1052}
1029 1053
1030int armada_drm_crtc_create(struct drm_device *dev, unsigned num, 1054int armada_drm_crtc_create(struct drm_device *drm, struct device *dev,
1031 struct resource *res) 1055 struct resource *res, int irq, const struct armada_variant *variant,
1056 struct device_node *port)
1032{ 1057{
1033 struct armada_private *priv = dev->dev_private; 1058 struct armada_private *priv = drm->dev_private;
1034 struct armada_crtc *dcrtc; 1059 struct armada_crtc *dcrtc;
1035 void __iomem *base; 1060 void __iomem *base;
1036 int ret; 1061 int ret;
1037 1062
1038 ret = armada_drm_crtc_create_properties(dev); 1063 ret = armada_drm_crtc_create_properties(drm);
1039 if (ret) 1064 if (ret)
1040 return ret; 1065 return ret;
1041 1066
1042 base = devm_request_and_ioremap(dev->dev, res); 1067 base = devm_request_and_ioremap(dev, res);
1043 if (!base) { 1068 if (!base) {
1044 DRM_ERROR("failed to ioremap register\n"); 1069 DRM_ERROR("failed to ioremap register\n");
1045 return -ENOMEM; 1070 return -ENOMEM;
@@ -1051,8 +1076,12 @@ int armada_drm_crtc_create(struct drm_device *dev, unsigned num,
1051 return -ENOMEM; 1076 return -ENOMEM;
1052 } 1077 }
1053 1078
1079 if (dev != drm->dev)
1080 dev_set_drvdata(dev, dcrtc);
1081
1082 dcrtc->variant = variant;
1054 dcrtc->base = base; 1083 dcrtc->base = base;
1055 dcrtc->num = num; 1084 dcrtc->num = drm->mode_config.num_crtc;
1056 dcrtc->clk = ERR_PTR(-EINVAL); 1085 dcrtc->clk = ERR_PTR(-EINVAL);
1057 dcrtc->csc_yuv_mode = CSC_AUTO; 1086 dcrtc->csc_yuv_mode = CSC_AUTO;
1058 dcrtc->csc_rgb_mode = CSC_AUTO; 1087 dcrtc->csc_rgb_mode = CSC_AUTO;
@@ -1074,9 +1103,18 @@ int armada_drm_crtc_create(struct drm_device *dev, unsigned num,
1074 CFG_PDWN64x66, dcrtc->base + LCD_SPU_SRAM_PARA1); 1103 CFG_PDWN64x66, dcrtc->base + LCD_SPU_SRAM_PARA1);
1075 writel_relaxed(0x2032ff81, dcrtc->base + LCD_SPU_DMA_CTRL1); 1104 writel_relaxed(0x2032ff81, dcrtc->base + LCD_SPU_DMA_CTRL1);
1076 writel_relaxed(0x00000000, dcrtc->base + LCD_SPU_GRA_OVSA_HPXL_VLN); 1105 writel_relaxed(0x00000000, dcrtc->base + LCD_SPU_GRA_OVSA_HPXL_VLN);
1106 writel_relaxed(dcrtc->irq_ena, dcrtc->base + LCD_SPU_IRQ_ENA);
1107 writel_relaxed(0, dcrtc->base + LCD_SPU_IRQ_ISR);
1108
1109 ret = devm_request_irq(dev, irq, armada_drm_irq, 0, "armada_drm_crtc",
1110 dcrtc);
1111 if (ret < 0) {
1112 kfree(dcrtc);
1113 return ret;
1114 }
1077 1115
1078 if (priv->variant->crtc_init) { 1116 if (dcrtc->variant->init) {
1079 ret = priv->variant->crtc_init(dcrtc); 1117 ret = dcrtc->variant->init(dcrtc, dev);
1080 if (ret) { 1118 if (ret) {
1081 kfree(dcrtc); 1119 kfree(dcrtc);
1082 return ret; 1120 return ret;
@@ -1088,7 +1126,8 @@ int armada_drm_crtc_create(struct drm_device *dev, unsigned num,
1088 1126
1089 priv->dcrtc[dcrtc->num] = dcrtc; 1127 priv->dcrtc[dcrtc->num] = dcrtc;
1090 1128
1091 drm_crtc_init(dev, &dcrtc->crtc, &armada_crtc_funcs); 1129 dcrtc->crtc.port = port;
1130 drm_crtc_init(drm, &dcrtc->crtc, &armada_crtc_funcs);
1092 drm_crtc_helper_add(&dcrtc->crtc, &armada_crtc_helper_funcs); 1131 drm_crtc_helper_add(&dcrtc->crtc, &armada_crtc_helper_funcs);
1093 1132
1094 drm_object_attach_property(&dcrtc->crtc.base, priv->csc_yuv_prop, 1133 drm_object_attach_property(&dcrtc->crtc.base, priv->csc_yuv_prop,
@@ -1096,5 +1135,107 @@ int armada_drm_crtc_create(struct drm_device *dev, unsigned num,
1096 drm_object_attach_property(&dcrtc->crtc.base, priv->csc_rgb_prop, 1135 drm_object_attach_property(&dcrtc->crtc.base, priv->csc_rgb_prop,
1097 dcrtc->csc_rgb_mode); 1136 dcrtc->csc_rgb_mode);
1098 1137
1099 return armada_overlay_plane_create(dev, 1 << dcrtc->num); 1138 return armada_overlay_plane_create(drm, 1 << dcrtc->num);
1139}
1140
1141static int
1142armada_lcd_bind(struct device *dev, struct device *master, void *data)
1143{
1144 struct platform_device *pdev = to_platform_device(dev);
1145 struct drm_device *drm = data;
1146 struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
1147 int irq = platform_get_irq(pdev, 0);
1148 const struct armada_variant *variant;
1149 struct device_node *port = NULL;
1150
1151 if (irq < 0)
1152 return irq;
1153
1154 if (!dev->of_node) {
1155 const struct platform_device_id *id;
1156
1157 id = platform_get_device_id(pdev);
1158 if (!id)
1159 return -ENXIO;
1160
1161 variant = (const struct armada_variant *)id->driver_data;
1162 } else {
1163 const struct of_device_id *match;
1164 struct device_node *np, *parent = dev->of_node;
1165
1166 match = of_match_device(dev->driver->of_match_table, dev);
1167 if (!match)
1168 return -ENXIO;
1169
1170 np = of_get_child_by_name(parent, "ports");
1171 if (np)
1172 parent = np;
1173 port = of_get_child_by_name(parent, "port");
1174 of_node_put(np);
1175 if (!port) {
1176 dev_err(dev, "no port node found in %s\n",
1177 parent->full_name);
1178 return -ENXIO;
1179 }
1180
1181 variant = match->data;
1182 }
1183
1184 return armada_drm_crtc_create(drm, dev, res, irq, variant, port);
1185}
1186
1187static void
1188armada_lcd_unbind(struct device *dev, struct device *master, void *data)
1189{
1190 struct armada_crtc *dcrtc = dev_get_drvdata(dev);
1191
1192 armada_drm_crtc_destroy(&dcrtc->crtc);
1100} 1193}
1194
1195static const struct component_ops armada_lcd_ops = {
1196 .bind = armada_lcd_bind,
1197 .unbind = armada_lcd_unbind,
1198};
1199
1200static int armada_lcd_probe(struct platform_device *pdev)
1201{
1202 return component_add(&pdev->dev, &armada_lcd_ops);
1203}
1204
1205static int armada_lcd_remove(struct platform_device *pdev)
1206{
1207 component_del(&pdev->dev, &armada_lcd_ops);
1208 return 0;
1209}
1210
1211static struct of_device_id armada_lcd_of_match[] = {
1212 {
1213 .compatible = "marvell,dove-lcd",
1214 .data = &armada510_ops,
1215 },
1216 {}
1217};
1218MODULE_DEVICE_TABLE(of, armada_lcd_of_match);
1219
1220static const struct platform_device_id armada_lcd_platform_ids[] = {
1221 {
1222 .name = "armada-lcd",
1223 .driver_data = (unsigned long)&armada510_ops,
1224 }, {
1225 .name = "armada-510-lcd",
1226 .driver_data = (unsigned long)&armada510_ops,
1227 },
1228 { },
1229};
1230MODULE_DEVICE_TABLE(platform, armada_lcd_platform_ids);
1231
1232struct platform_driver armada_lcd_platform_driver = {
1233 .probe = armada_lcd_probe,
1234 .remove = armada_lcd_remove,
1235 .driver = {
1236 .name = "armada-lcd",
1237 .owner = THIS_MODULE,
1238 .of_match_table = armada_lcd_of_match,
1239 },
1240 .id_table = armada_lcd_platform_ids,
1241};
diff --git a/drivers/gpu/drm/armada/armada_crtc.h b/drivers/gpu/drm/armada/armada_crtc.h
index 9c10a07e7492..98102a5a9af5 100644
--- a/drivers/gpu/drm/armada/armada_crtc.h
+++ b/drivers/gpu/drm/armada/armada_crtc.h
@@ -32,12 +32,15 @@ struct armada_regs {
32 armada_reg_queue_mod(_r, _i, 0, 0, ~0) 32 armada_reg_queue_mod(_r, _i, 0, 0, ~0)
33 33
34struct armada_frame_work; 34struct armada_frame_work;
35struct armada_variant;
35 36
36struct armada_crtc { 37struct armada_crtc {
37 struct drm_crtc crtc; 38 struct drm_crtc crtc;
39 const struct armada_variant *variant;
38 unsigned num; 40 unsigned num;
39 void __iomem *base; 41 void __iomem *base;
40 struct clk *clk; 42 struct clk *clk;
43 struct clk *extclk[2];
41 struct { 44 struct {
42 uint32_t spu_v_h_total; 45 uint32_t spu_v_h_total;
43 uint32_t spu_v_porch; 46 uint32_t spu_v_porch;
@@ -72,12 +75,16 @@ struct armada_crtc {
72}; 75};
73#define drm_to_armada_crtc(c) container_of(c, struct armada_crtc, crtc) 76#define drm_to_armada_crtc(c) container_of(c, struct armada_crtc, crtc)
74 77
75int armada_drm_crtc_create(struct drm_device *, unsigned, struct resource *); 78struct device_node;
79int armada_drm_crtc_create(struct drm_device *, struct device *,
80 struct resource *, int, const struct armada_variant *,
81 struct device_node *);
76void armada_drm_crtc_gamma_set(struct drm_crtc *, u16, u16, u16, int); 82void armada_drm_crtc_gamma_set(struct drm_crtc *, u16, u16, u16, int);
77void armada_drm_crtc_gamma_get(struct drm_crtc *, u16 *, u16 *, u16 *, int); 83void armada_drm_crtc_gamma_get(struct drm_crtc *, u16 *, u16 *, u16 *, int);
78void armada_drm_crtc_irq(struct armada_crtc *, u32);
79void armada_drm_crtc_disable_irq(struct armada_crtc *, u32); 84void armada_drm_crtc_disable_irq(struct armada_crtc *, u32);
80void armada_drm_crtc_enable_irq(struct armada_crtc *, u32); 85void armada_drm_crtc_enable_irq(struct armada_crtc *, u32);
81void armada_drm_crtc_update_regs(struct armada_crtc *, struct armada_regs *); 86void armada_drm_crtc_update_regs(struct armada_crtc *, struct armada_regs *);
82 87
88extern struct platform_driver armada_lcd_platform_driver;
89
83#endif 90#endif
diff --git a/drivers/gpu/drm/armada/armada_drm.h b/drivers/gpu/drm/armada/armada_drm.h
index a72cae03b99b..ea63c6c7c66f 100644
--- a/drivers/gpu/drm/armada/armada_drm.h
+++ b/drivers/gpu/drm/armada/armada_drm.h
@@ -59,26 +59,23 @@ void armada_drm_vbl_event_remove_unlocked(struct armada_crtc *,
59struct armada_private; 59struct armada_private;
60 60
61struct armada_variant { 61struct armada_variant {
62 bool has_spu_adv_reg; 62 bool has_spu_adv_reg;
63 uint32_t spu_adv_reg; 63 uint32_t spu_adv_reg;
64 int (*init)(struct armada_private *, struct device *); 64 int (*init)(struct armada_crtc *, struct device *);
65 int (*crtc_init)(struct armada_crtc *); 65 int (*compute_clock)(struct armada_crtc *,
66 int (*crtc_compute_clock)(struct armada_crtc *, 66 const struct drm_display_mode *,
67 const struct drm_display_mode *, 67 uint32_t *);
68 uint32_t *);
69}; 68};
70 69
71/* Variant ops */ 70/* Variant ops */
72extern const struct armada_variant armada510_ops; 71extern const struct armada_variant armada510_ops;
73 72
74struct armada_private { 73struct armada_private {
75 const struct armada_variant *variant;
76 struct work_struct fb_unref_work; 74 struct work_struct fb_unref_work;
77 DECLARE_KFIFO(fb_unref, struct drm_framebuffer *, 8); 75 DECLARE_KFIFO(fb_unref, struct drm_framebuffer *, 8);
78 struct drm_fb_helper *fbdev; 76 struct drm_fb_helper *fbdev;
79 struct armada_crtc *dcrtc[2]; 77 struct armada_crtc *dcrtc[2];
80 struct drm_mm linear; 78 struct drm_mm linear;
81 struct clk *extclk[2];
82 struct drm_property *csc_yuv_prop; 79 struct drm_property *csc_yuv_prop;
83 struct drm_property *csc_rgb_prop; 80 struct drm_property *csc_rgb_prop;
84 struct drm_property *colorkey_prop; 81 struct drm_property *colorkey_prop;
diff --git a/drivers/gpu/drm/armada/armada_drv.c b/drivers/gpu/drm/armada/armada_drv.c
index 8ab3cd1a8cdb..e2d5792b140f 100644
--- a/drivers/gpu/drm/armada/armada_drv.c
+++ b/drivers/gpu/drm/armada/armada_drv.c
@@ -6,7 +6,9 @@
6 * published by the Free Software Foundation. 6 * published by the Free Software Foundation.
7 */ 7 */
8#include <linux/clk.h> 8#include <linux/clk.h>
9#include <linux/component.h>
9#include <linux/module.h> 10#include <linux/module.h>
11#include <linux/of_graph.h>
10#include <drm/drmP.h> 12#include <drm/drmP.h>
11#include <drm/drm_crtc_helper.h> 13#include <drm/drm_crtc_helper.h>
12#include "armada_crtc.h" 14#include "armada_crtc.h"
@@ -52,6 +54,11 @@ static const struct armada_drm_slave_config tda19988_config = {
52}; 54};
53#endif 55#endif
54 56
57static bool is_componentized(struct device *dev)
58{
59 return dev->of_node || dev->platform_data;
60}
61
55static void armada_drm_unref_work(struct work_struct *work) 62static void armada_drm_unref_work(struct work_struct *work)
56{ 63{
57 struct armada_private *priv = 64 struct armada_private *priv =
@@ -85,6 +92,7 @@ void armada_drm_queue_unref_work(struct drm_device *dev,
85static int armada_drm_load(struct drm_device *dev, unsigned long flags) 92static int armada_drm_load(struct drm_device *dev, unsigned long flags)
86{ 93{
87 const struct platform_device_id *id; 94 const struct platform_device_id *id;
95 const struct armada_variant *variant;
88 struct armada_private *priv; 96 struct armada_private *priv;
89 struct resource *res[ARRAY_SIZE(priv->dcrtc)]; 97 struct resource *res[ARRAY_SIZE(priv->dcrtc)];
90 struct resource *mem = NULL; 98 struct resource *mem = NULL;
@@ -107,7 +115,7 @@ static int armada_drm_load(struct drm_device *dev, unsigned long flags)
107 return -EINVAL; 115 return -EINVAL;
108 } 116 }
109 117
110 if (!res[0] || !mem) 118 if (!mem)
111 return -ENXIO; 119 return -ENXIO;
112 120
113 if (!devm_request_mem_region(dev->dev, mem->start, 121 if (!devm_request_mem_region(dev->dev, mem->start,
@@ -128,11 +136,7 @@ static int armada_drm_load(struct drm_device *dev, unsigned long flags)
128 if (!id) 136 if (!id)
129 return -ENXIO; 137 return -ENXIO;
130 138
131 priv->variant = (struct armada_variant *)id->driver_data; 139 variant = (const struct armada_variant *)id->driver_data;
132
133 ret = priv->variant->init(priv, dev->dev);
134 if (ret)
135 return ret;
136 140
137 INIT_WORK(&priv->fb_unref_work, armada_drm_unref_work); 141 INIT_WORK(&priv->fb_unref_work, armada_drm_unref_work);
138 INIT_KFIFO(priv->fb_unref); 142 INIT_KFIFO(priv->fb_unref);
@@ -155,40 +159,50 @@ static int armada_drm_load(struct drm_device *dev, unsigned long flags)
155 159
156 /* Create all LCD controllers */ 160 /* Create all LCD controllers */
157 for (n = 0; n < ARRAY_SIZE(priv->dcrtc); n++) { 161 for (n = 0; n < ARRAY_SIZE(priv->dcrtc); n++) {
162 int irq;
163
158 if (!res[n]) 164 if (!res[n])
159 break; 165 break;
160 166
161 ret = armada_drm_crtc_create(dev, n, res[n]); 167 irq = platform_get_irq(dev->platformdev, n);
168 if (irq < 0)
169 goto err_kms;
170
171 ret = armada_drm_crtc_create(dev, dev->dev, res[n], irq,
172 variant, NULL);
162 if (ret) 173 if (ret)
163 goto err_kms; 174 goto err_kms;
164 } 175 }
165 176
177 if (is_componentized(dev->dev)) {
178 ret = component_bind_all(dev->dev, dev);
179 if (ret)
180 goto err_kms;
181 } else {
166#ifdef CONFIG_DRM_ARMADA_TDA1998X 182#ifdef CONFIG_DRM_ARMADA_TDA1998X
167 ret = armada_drm_connector_slave_create(dev, &tda19988_config); 183 ret = armada_drm_connector_slave_create(dev, &tda19988_config);
168 if (ret) 184 if (ret)
169 goto err_kms; 185 goto err_kms;
170#endif 186#endif
187 }
171 188
172 ret = drm_vblank_init(dev, n); 189 ret = drm_vblank_init(dev, dev->mode_config.num_crtc);
173 if (ret)
174 goto err_kms;
175
176 ret = drm_irq_install(dev, platform_get_irq(dev->platformdev, 0));
177 if (ret) 190 if (ret)
178 goto err_kms; 191 goto err_comp;
179 192
180 dev->vblank_disable_allowed = 1; 193 dev->vblank_disable_allowed = 1;
181 194
182 ret = armada_fbdev_init(dev); 195 ret = armada_fbdev_init(dev);
183 if (ret) 196 if (ret)
184 goto err_irq; 197 goto err_comp;
185 198
186 drm_kms_helper_poll_init(dev); 199 drm_kms_helper_poll_init(dev);
187 200
188 return 0; 201 return 0;
189 202
190 err_irq: 203 err_comp:
191 drm_irq_uninstall(dev); 204 if (is_componentized(dev->dev))
205 component_unbind_all(dev->dev, dev);
192 err_kms: 206 err_kms:
193 drm_mode_config_cleanup(dev); 207 drm_mode_config_cleanup(dev);
194 drm_mm_takedown(&priv->linear); 208 drm_mm_takedown(&priv->linear);
@@ -203,7 +217,10 @@ static int armada_drm_unload(struct drm_device *dev)
203 217
204 drm_kms_helper_poll_fini(dev); 218 drm_kms_helper_poll_fini(dev);
205 armada_fbdev_fini(dev); 219 armada_fbdev_fini(dev);
206 drm_irq_uninstall(dev); 220
221 if (is_componentized(dev->dev))
222 component_unbind_all(dev->dev, dev);
223
207 drm_mode_config_cleanup(dev); 224 drm_mode_config_cleanup(dev);
208 drm_mm_takedown(&priv->linear); 225 drm_mm_takedown(&priv->linear);
209 flush_work(&priv->fb_unref_work); 226 flush_work(&priv->fb_unref_work);
@@ -259,52 +276,6 @@ static void armada_drm_disable_vblank(struct drm_device *dev, int crtc)
259 armada_drm_crtc_disable_irq(priv->dcrtc[crtc], VSYNC_IRQ_ENA); 276 armada_drm_crtc_disable_irq(priv->dcrtc[crtc], VSYNC_IRQ_ENA);
260} 277}
261 278
262static irqreturn_t armada_drm_irq_handler(int irq, void *arg)
263{
264 struct drm_device *dev = arg;
265 struct armada_private *priv = dev->dev_private;
266 struct armada_crtc *dcrtc = priv->dcrtc[0];
267 uint32_t v, stat = readl_relaxed(dcrtc->base + LCD_SPU_IRQ_ISR);
268 irqreturn_t handled = IRQ_NONE;
269
270 /*
271 * This is rediculous - rather than writing bits to clear, we
272 * have to set the actual status register value. This is racy.
273 */
274 writel_relaxed(0, dcrtc->base + LCD_SPU_IRQ_ISR);
275
276 /* Mask out those interrupts we haven't enabled */
277 v = stat & dcrtc->irq_ena;
278
279 if (v & (VSYNC_IRQ|GRA_FRAME_IRQ|DUMB_FRAMEDONE)) {
280 armada_drm_crtc_irq(dcrtc, stat);
281 handled = IRQ_HANDLED;
282 }
283
284 return handled;
285}
286
287static int armada_drm_irq_postinstall(struct drm_device *dev)
288{
289 struct armada_private *priv = dev->dev_private;
290 struct armada_crtc *dcrtc = priv->dcrtc[0];
291
292 spin_lock_irq(&dev->vbl_lock);
293 writel_relaxed(dcrtc->irq_ena, dcrtc->base + LCD_SPU_IRQ_ENA);
294 writel(0, dcrtc->base + LCD_SPU_IRQ_ISR);
295 spin_unlock_irq(&dev->vbl_lock);
296
297 return 0;
298}
299
300static void armada_drm_irq_uninstall(struct drm_device *dev)
301{
302 struct armada_private *priv = dev->dev_private;
303 struct armada_crtc *dcrtc = priv->dcrtc[0];
304
305 writel(0, dcrtc->base + LCD_SPU_IRQ_ENA);
306}
307
308static struct drm_ioctl_desc armada_ioctls[] = { 279static struct drm_ioctl_desc armada_ioctls[] = {
309 DRM_IOCTL_DEF_DRV(ARMADA_GEM_CREATE, armada_gem_create_ioctl, 280 DRM_IOCTL_DEF_DRV(ARMADA_GEM_CREATE, armada_gem_create_ioctl,
310 DRM_UNLOCKED), 281 DRM_UNLOCKED),
@@ -340,9 +311,6 @@ static struct drm_driver armada_drm_driver = {
340 .get_vblank_counter = drm_vblank_count, 311 .get_vblank_counter = drm_vblank_count,
341 .enable_vblank = armada_drm_enable_vblank, 312 .enable_vblank = armada_drm_enable_vblank,
342 .disable_vblank = armada_drm_disable_vblank, 313 .disable_vblank = armada_drm_disable_vblank,
343 .irq_handler = armada_drm_irq_handler,
344 .irq_postinstall = armada_drm_irq_postinstall,
345 .irq_uninstall = armada_drm_irq_uninstall,
346#ifdef CONFIG_DEBUG_FS 314#ifdef CONFIG_DEBUG_FS
347 .debugfs_init = armada_drm_debugfs_init, 315 .debugfs_init = armada_drm_debugfs_init,
348 .debugfs_cleanup = armada_drm_debugfs_cleanup, 316 .debugfs_cleanup = armada_drm_debugfs_cleanup,
@@ -362,19 +330,140 @@ static struct drm_driver armada_drm_driver = {
362 .desc = "Armada SoC DRM", 330 .desc = "Armada SoC DRM",
363 .date = "20120730", 331 .date = "20120730",
364 .driver_features = DRIVER_GEM | DRIVER_MODESET | 332 .driver_features = DRIVER_GEM | DRIVER_MODESET |
365 DRIVER_HAVE_IRQ | DRIVER_PRIME, 333 DRIVER_PRIME,
366 .ioctls = armada_ioctls, 334 .ioctls = armada_ioctls,
367 .fops = &armada_drm_fops, 335 .fops = &armada_drm_fops,
368}; 336};
369 337
338static int armada_drm_bind(struct device *dev)
339{
340 return drm_platform_init(&armada_drm_driver, to_platform_device(dev));
341}
342
343static void armada_drm_unbind(struct device *dev)
344{
345 drm_put_dev(dev_get_drvdata(dev));
346}
347
348static int compare_of(struct device *dev, void *data)
349{
350 return dev->of_node == data;
351}
352
353static int compare_dev_name(struct device *dev, void *data)
354{
355 const char *name = data;
356 return !strcmp(dev_name(dev), name);
357}
358
359static void armada_add_endpoints(struct device *dev,
360 struct component_match **match, struct device_node *port)
361{
362 struct device_node *ep, *remote;
363
364 for_each_child_of_node(port, ep) {
365 remote = of_graph_get_remote_port_parent(ep);
366 if (!remote || !of_device_is_available(remote)) {
367 of_node_put(remote);
368 continue;
369 } else if (!of_device_is_available(remote->parent)) {
370 dev_warn(dev, "parent device of %s is not available\n",
371 remote->full_name);
372 of_node_put(remote);
373 continue;
374 }
375
376 component_match_add(dev, match, compare_of, remote);
377 of_node_put(remote);
378 }
379}
380
381static int armada_drm_find_components(struct device *dev,
382 struct component_match **match)
383{
384 struct device_node *port;
385 int i;
386
387 if (dev->of_node) {
388 struct device_node *np = dev->of_node;
389
390 for (i = 0; ; i++) {
391 port = of_parse_phandle(np, "ports", i);
392 if (!port)
393 break;
394
395 component_match_add(dev, match, compare_of, port);
396 of_node_put(port);
397 }
398
399 if (i == 0) {
400 dev_err(dev, "missing 'ports' property\n");
401 return -ENODEV;
402 }
403
404 for (i = 0; ; i++) {
405 port = of_parse_phandle(np, "ports", i);
406 if (!port)
407 break;
408
409 armada_add_endpoints(dev, match, port);
410 of_node_put(port);
411 }
412 } else if (dev->platform_data) {
413 char **devices = dev->platform_data;
414 struct device *d;
415
416 for (i = 0; devices[i]; i++)
417 component_match_add(dev, match, compare_dev_name,
418 devices[i]);
419
420 if (i == 0) {
421 dev_err(dev, "missing 'ports' property\n");
422 return -ENODEV;
423 }
424
425 for (i = 0; devices[i]; i++) {
426 d = bus_find_device_by_name(&platform_bus_type, NULL,
427 devices[i]);
428 if (d && d->of_node) {
429 for_each_child_of_node(d->of_node, port)
430 armada_add_endpoints(dev, match, port);
431 }
432 put_device(d);
433 }
434 }
435
436 return 0;
437}
438
439static const struct component_master_ops armada_master_ops = {
440 .bind = armada_drm_bind,
441 .unbind = armada_drm_unbind,
442};
443
370static int armada_drm_probe(struct platform_device *pdev) 444static int armada_drm_probe(struct platform_device *pdev)
371{ 445{
372 return drm_platform_init(&armada_drm_driver, pdev); 446 if (is_componentized(&pdev->dev)) {
447 struct component_match *match = NULL;
448 int ret;
449
450 ret = armada_drm_find_components(&pdev->dev, &match);
451 if (ret < 0)
452 return ret;
453
454 return component_master_add_with_match(&pdev->dev,
455 &armada_master_ops, match);
456 } else {
457 return drm_platform_init(&armada_drm_driver, pdev);
458 }
373} 459}
374 460
375static int armada_drm_remove(struct platform_device *pdev) 461static int armada_drm_remove(struct platform_device *pdev)
376{ 462{
377 drm_put_dev(platform_get_drvdata(pdev)); 463 if (is_componentized(&pdev->dev))
464 component_master_del(&pdev->dev, &armada_master_ops);
465 else
466 drm_put_dev(platform_get_drvdata(pdev));
378 return 0; 467 return 0;
379} 468}
380 469
@@ -402,14 +491,24 @@ static struct platform_driver armada_drm_platform_driver = {
402 491
403static int __init armada_drm_init(void) 492static int __init armada_drm_init(void)
404{ 493{
494 int ret;
495
405 armada_drm_driver.num_ioctls = ARRAY_SIZE(armada_ioctls); 496 armada_drm_driver.num_ioctls = ARRAY_SIZE(armada_ioctls);
406 return platform_driver_register(&armada_drm_platform_driver); 497
498 ret = platform_driver_register(&armada_lcd_platform_driver);
499 if (ret)
500 return ret;
501 ret = platform_driver_register(&armada_drm_platform_driver);
502 if (ret)
503 platform_driver_unregister(&armada_lcd_platform_driver);
504 return ret;
407} 505}
408module_init(armada_drm_init); 506module_init(armada_drm_init);
409 507
410static void __exit armada_drm_exit(void) 508static void __exit armada_drm_exit(void)
411{ 509{
412 platform_driver_unregister(&armada_drm_platform_driver); 510 platform_driver_unregister(&armada_drm_platform_driver);
511 platform_driver_unregister(&armada_lcd_platform_driver);
413} 512}
414module_exit(armada_drm_exit); 513module_exit(armada_drm_exit);
415 514
diff --git a/drivers/gpu/drm/drm_of.c b/drivers/gpu/drm/drm_of.c
new file mode 100644
index 000000000000..16150a00c237
--- /dev/null
+++ b/drivers/gpu/drm/drm_of.c
@@ -0,0 +1,67 @@
1#include <linux/export.h>
2#include <linux/list.h>
3#include <linux/of_graph.h>
4#include <drm/drmP.h>
5#include <drm/drm_crtc.h>
6#include <drm/drm_of.h>
7
8/**
9 * drm_crtc_port_mask - find the mask of a registered CRTC by port OF node
10 * @dev: DRM device
11 * @port: port OF node
12 *
13 * Given a port OF node, return the possible mask of the corresponding
14 * CRTC within a device's list of CRTCs. Returns zero if not found.
15 */
16static uint32_t drm_crtc_port_mask(struct drm_device *dev,
17 struct device_node *port)
18{
19 unsigned int index = 0;
20 struct drm_crtc *tmp;
21
22 list_for_each_entry(tmp, &dev->mode_config.crtc_list, head) {
23 if (tmp->port == port)
24 return 1 << index;
25
26 index++;
27 }
28
29 return 0;
30}
31
32/**
33 * drm_of_find_possible_crtcs - find the possible CRTCs for an encoder port
34 * @dev: DRM device
35 * @port: encoder port to scan for endpoints
36 *
37 * Scan all endpoints attached to a port, locate their attached CRTCs,
38 * and generate the DRM mask of CRTCs which may be attached to this
39 * encoder.
40 *
41 * See Documentation/devicetree/bindings/graph.txt for the bindings.
42 */
43uint32_t drm_of_find_possible_crtcs(struct drm_device *dev,
44 struct device_node *port)
45{
46 struct device_node *remote_port, *ep = NULL;
47 uint32_t possible_crtcs = 0;
48
49 do {
50 ep = of_graph_get_next_endpoint(port, ep);
51 if (!ep)
52 break;
53
54 remote_port = of_graph_get_remote_port(ep);
55 if (!remote_port) {
56 of_node_put(ep);
57 return 0;
58 }
59
60 possible_crtcs |= drm_crtc_port_mask(dev, remote_port);
61
62 of_node_put(remote_port);
63 } while (1);
64
65 return possible_crtcs;
66}
67EXPORT_SYMBOL(drm_of_find_possible_crtcs);
diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h
index e529b68d5037..7f1bc7e4848b 100644
--- a/include/drm/drm_crtc.h
+++ b/include/drm/drm_crtc.h
@@ -41,6 +41,7 @@ struct drm_framebuffer;
41struct drm_object_properties; 41struct drm_object_properties;
42struct drm_file; 42struct drm_file;
43struct drm_clip_rect; 43struct drm_clip_rect;
44struct device_node;
44 45
45#define DRM_MODE_OBJECT_CRTC 0xcccccccc 46#define DRM_MODE_OBJECT_CRTC 0xcccccccc
46#define DRM_MODE_OBJECT_CONNECTOR 0xc0c0c0c0 47#define DRM_MODE_OBJECT_CONNECTOR 0xc0c0c0c0
@@ -314,6 +315,7 @@ struct drm_crtc_funcs {
314 */ 315 */
315struct drm_crtc { 316struct drm_crtc {
316 struct drm_device *dev; 317 struct drm_device *dev;
318 struct device_node *port;
317 struct list_head head; 319 struct list_head head;
318 320
319 /** 321 /**
diff --git a/include/drm/drm_of.h b/include/drm/drm_of.h
new file mode 100644
index 000000000000..2441f7112074
--- /dev/null
+++ b/include/drm/drm_of.h
@@ -0,0 +1,18 @@
1#ifndef __DRM_OF_H__
2#define __DRM_OF_H__
3
4struct drm_device;
5struct device_node;
6
7#ifdef CONFIG_OF
8extern uint32_t drm_of_find_possible_crtcs(struct drm_device *dev,
9 struct device_node *port);
10#else
11static inline uint32_t drm_of_find_possible_crtcs(struct drm_device *dev,
12 struct device_node *port)
13{
14 return 0;
15}
16#endif
17
18#endif /* __DRM_OF_H__ */
diff --git a/include/linux/component.h b/include/linux/component.h
index 68870182ca1e..c00dcc302611 100644
--- a/include/linux/component.h
+++ b/include/linux/component.h
@@ -29,4 +29,11 @@ void component_master_del(struct device *,
29int component_master_add_child(struct master *master, 29int component_master_add_child(struct master *master,
30 int (*compare)(struct device *, void *), void *compare_data); 30 int (*compare)(struct device *, void *), void *compare_data);
31 31
32struct component_match;
33
34int component_master_add_with_match(struct device *,
35 const struct component_master_ops *, struct component_match *);
36void component_match_add(struct device *, struct component_match **,
37 int (*compare)(struct device *, void *), void *compare_data);
38
32#endif 39#endif