1
2
3
4
5
6
7
8
9
10
11#include <drm/drmP.h>
12#include <drm/drm_atomic_helper.h>
13#include <drm/drm_crtc.h>
14#include <drm/drm_crtc_helper.h>
15#include <drm/drm_fourcc.h>
16#include <drm/drm_gem_cma_helper.h>
17#include <drm/drm_mipi_dsi.h>
18#include <drm/drm_panel.h>
19#include <linux/component.h>
20#include <linux/device.h>
21#include <linux/of_device.h>
22#include <linux/of_graph.h>
23#include <linux/phy/phy.h>
24#include <video/mipi_display.h>
25#include <video/videomode.h>
26
27#include "xlnx_bridge.h"
28
29
30#define XDSI_CCR 0x00
31#define XDSI_CCR_COREENB BIT(0)
32#define XDSI_CCR_CRREADY BIT(2)
33#define XDSI_PCR 0x04
34#define XDSI_PCR_VIDEOMODE(x) (((x) & 0x3) << 3)
35#define XDSI_PCR_VIDEOMODE_MASK (0x3 << 3)
36#define XDSI_PCR_VIDEOMODE_SHIFT 3
37#define XDSI_PCR_BLLPTYPE(x) ((x) << 5)
38#define XDSI_PCR_BLLPMODE(x) ((x) << 6)
39#define XDSI_PCR_EOTPENABLE(x) ((x) << 13)
40#define XDSI_GIER 0x20
41#define XDSI_ISR 0x24
42#define XDSI_IER 0x28
43#define XDSI_CMD 0x30
44#define XDSI_CMD_QUEUE_PACKET(x) ((x) & GENMASK(23, 0))
45#define XDSI_TIME1 0x50
46#define XDSI_TIME1_BLLP_BURST(x) ((x) & GENMASK(15, 0))
47#define XDSI_TIME1_HSA(x) (((x) & GENMASK(15, 0)) << 16)
48#define XDSI_TIME2 0x54
49#define XDSI_TIME2_VACT(x) ((x) & GENMASK(15, 0))
50#define XDSI_TIME2_HACT(x) (((x) & GENMASK(15, 0)) << 16)
51#define XDSI_HACT_MULTIPLIER GENMASK(1, 0)
52#define XDSI_TIME3 0x58
53#define XDSI_TIME3_HFP(x) ((x) & GENMASK(15, 0))
54#define XDSI_TIME3_HBP(x) (((x) & GENMASK(15, 0)) << 16)
55#define XDSI_TIME4 0x5c
56#define XDSI_TIME4_VFP(x) ((x) & GENMASK(7, 0))
57#define XDSI_TIME4_VBP(x) (((x) & GENMASK(7, 0)) << 8)
58#define XDSI_TIME4_VSA(x) (((x) & GENMASK(7, 0)) << 16)
59#define XDSI_LTIME 0x60
60#define XDSI_BLLP_TIME 0x64
61
62
63
64
65#define XDSI_NUM_DATA_T 4
66#define XDSI_VIDEO_MODE_SYNC_PULSE 0x0
67#define XDSI_VIDEO_MODE_SYNC_EVENT 0x1
68#define XDSI_VIDEO_MODE_BURST 0x2
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106struct xlnx_dsi {
107 struct drm_encoder encoder;
108 struct mipi_dsi_host dsi_host;
109 struct drm_connector connector;
110 struct device_node *panel_node;
111 struct drm_panel *panel;
112 struct device *dev;
113 void __iomem *iomem;
114 u32 lanes;
115 u32 mode_flags;
116 enum mipi_dsi_pixel_format format;
117 struct videomode vm;
118 u32 mul_factor;
119 struct drm_property *eotp_prop;
120 struct drm_property *bllp_mode_prop;
121 struct drm_property *bllp_type_prop;
122 struct drm_property *video_mode_prop;
123 struct drm_property *bllp_burst_time_prop;
124 struct drm_property *cmd_queue_prop;
125 bool eotp_prop_val;
126 bool bllp_mode_prop_val;
127 bool bllp_type_prop_val;
128 u32 video_mode_prop_val;
129 u32 bllp_burst_time_prop_val;
130 u32 cmd_queue_prop_val;
131 struct xlnx_bridge *bridge;
132 struct drm_property *height_out;
133 u32 height_out_prop_val;
134 struct drm_property *width_out;
135 u32 width_out_prop_val;
136 struct drm_property *in_fmt;
137 u32 in_fmt_prop_val;
138 struct drm_property *out_fmt;
139 u32 out_fmt_prop_val;
140};
141
142#define host_to_dsi(host) container_of(host, struct xlnx_dsi, dsi_host)
143#define connector_to_dsi(c) container_of(c, struct xlnx_dsi, connector)
144#define encoder_to_dsi(e) container_of(e, struct xlnx_dsi, encoder)
145
146static inline void xlnx_dsi_writel(void __iomem *base, int offset, u32 val)
147{
148 writel(val, base + offset);
149}
150
151static inline u32 xlnx_dsi_readl(void __iomem *base, int offset)
152{
153 return readl(base + offset);
154}
155
156
157
158
159
160
161
162
163
164static void xlnx_dsi_set_config_parameters(struct xlnx_dsi *dsi)
165{
166 u32 reg;
167
168 reg = XDSI_PCR_EOTPENABLE(dsi->eotp_prop_val);
169 reg |= XDSI_PCR_VIDEOMODE(dsi->video_mode_prop_val);
170 reg |= XDSI_PCR_BLLPTYPE(dsi->bllp_type_prop_val);
171 reg |= XDSI_PCR_BLLPMODE(dsi->bllp_mode_prop_val);
172
173 xlnx_dsi_writel(dsi->iomem, XDSI_PCR, reg);
174
175
176
177
178 if (dsi->video_mode_prop_val == XDSI_VIDEO_MODE_BURST) {
179 reg = XDSI_TIME1_BLLP_BURST(dsi->bllp_burst_time_prop_val);
180 xlnx_dsi_writel(dsi->iomem, XDSI_TIME1, reg);
181 }
182
183 reg = XDSI_CMD_QUEUE_PACKET(dsi->cmd_queue_prop_val);
184 xlnx_dsi_writel(dsi->iomem, XDSI_CMD, reg);
185
186 dev_dbg(dsi->dev, "PCR register value is = %x\n",
187 xlnx_dsi_readl(dsi->iomem, XDSI_PCR));
188}
189
190
191
192
193
194
195
196
197static void xlnx_dsi_set_display_mode(struct xlnx_dsi *dsi)
198{
199 struct videomode *vm = &dsi->vm;
200 u32 reg, video_mode;
201
202 reg = xlnx_dsi_readl(dsi->iomem, XDSI_PCR);
203 video_mode = (reg & XDSI_PCR_VIDEOMODE_MASK) >>
204 XDSI_PCR_VIDEOMODE_SHIFT;
205
206
207 if (!video_mode &&
208 (dsi->mode_flags & MIPI_DSI_MODE_VIDEO_SYNC_PULSE)) {
209 reg = XDSI_TIME1_HSA(vm->hsync_len);
210 xlnx_dsi_writel(dsi->iomem, XDSI_TIME1, reg);
211 }
212
213 reg = XDSI_TIME4_VFP(vm->vfront_porch) |
214 XDSI_TIME4_VBP(vm->vback_porch) |
215 XDSI_TIME4_VSA(vm->vsync_len);
216 xlnx_dsi_writel(dsi->iomem, XDSI_TIME4, reg);
217
218 reg = XDSI_TIME3_HFP(vm->hfront_porch) |
219 XDSI_TIME3_HBP(vm->hback_porch);
220 xlnx_dsi_writel(dsi->iomem, XDSI_TIME3, reg);
221
222 dev_dbg(dsi->dev, "mul factor for parsed datatype is = %d\n",
223 (dsi->mul_factor) / 100);
224
225
226
227
228
229
230
231
232
233
234
235 if ((vm->hactive & XDSI_HACT_MULTIPLIER) != 0)
236 dev_warn(dsi->dev, "Incorrect HACT will be programmed\n");
237
238 reg = XDSI_TIME2_HACT((vm->hactive) * (dsi->mul_factor) / 100) |
239 XDSI_TIME2_VACT(vm->vactive);
240 xlnx_dsi_writel(dsi->iomem, XDSI_TIME2, reg);
241
242 dev_dbg(dsi->dev, "LCD size = %dx%d\n", vm->hactive, vm->vactive);
243}
244
245
246
247
248
249
250
251
252
253static void xlnx_dsi_set_display_enable(struct xlnx_dsi *dsi)
254{
255 u32 reg;
256
257 reg = xlnx_dsi_readl(dsi->iomem, XDSI_CCR);
258 reg |= XDSI_CCR_COREENB;
259
260 xlnx_dsi_writel(dsi->iomem, XDSI_CCR, reg);
261 dev_dbg(dsi->dev, "MIPI DSI Tx controller is enabled.\n");
262}
263
264
265
266
267
268
269
270
271
272static void xlnx_dsi_set_display_disable(struct xlnx_dsi *dsi)
273{
274 u32 reg;
275
276 reg = xlnx_dsi_readl(dsi->iomem, XDSI_CCR);
277 reg &= ~XDSI_CCR_COREENB;
278
279 xlnx_dsi_writel(dsi->iomem, XDSI_CCR, reg);
280 dev_dbg(dsi->dev, "DSI Tx is disabled. reset regs to default values\n");
281}
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298static int xlnx_dsi_atomic_set_property(struct drm_connector *connector,
299 struct drm_connector_state *state,
300 struct drm_property *prop, u64 val)
301{
302 struct xlnx_dsi *dsi = connector_to_dsi(connector);
303
304 dev_dbg(dsi->dev, "property name = %s, value = %lld\n",
305 prop->name, val);
306
307 if (prop == dsi->eotp_prop)
308 dsi->eotp_prop_val = !!val;
309 else if (prop == dsi->bllp_mode_prop)
310 dsi->bllp_mode_prop_val = !!val;
311 else if (prop == dsi->bllp_type_prop)
312 dsi->bllp_type_prop_val = !!val;
313 else if (prop == dsi->video_mode_prop)
314 dsi->video_mode_prop_val = (unsigned int)val;
315 else if (prop == dsi->bllp_burst_time_prop)
316 dsi->bllp_burst_time_prop_val = (unsigned int)val;
317 else if (prop == dsi->cmd_queue_prop)
318 dsi->cmd_queue_prop_val = (unsigned int)val;
319 else if (prop == dsi->height_out)
320 dsi->height_out_prop_val = (u32)val;
321 else if (prop == dsi->width_out)
322 dsi->width_out_prop_val = (u32)val;
323 else if (prop == dsi->in_fmt)
324 dsi->in_fmt_prop_val = (u32)val;
325 else if (prop == dsi->out_fmt)
326 dsi->out_fmt_prop_val = (u32)val;
327 else
328 return -EINVAL;
329
330 xlnx_dsi_set_config_parameters(dsi);
331
332 return 0;
333}
334
335static int
336xlnx_dsi_atomic_get_property(struct drm_connector *connector,
337 const struct drm_connector_state *state,
338 struct drm_property *prop, uint64_t *val)
339{
340 struct xlnx_dsi *dsi = connector_to_dsi(connector);
341
342 if (prop == dsi->eotp_prop)
343 *val = dsi->eotp_prop_val;
344 else if (prop == dsi->bllp_mode_prop)
345 *val = dsi->bllp_mode_prop_val;
346 else if (prop == dsi->bllp_type_prop)
347 *val = dsi->bllp_type_prop_val;
348 else if (prop == dsi->video_mode_prop)
349 *val = dsi->video_mode_prop_val;
350 else if (prop == dsi->bllp_burst_time_prop)
351 *val = dsi->bllp_burst_time_prop_val;
352 else if (prop == dsi->cmd_queue_prop)
353 *val = dsi->cmd_queue_prop_val;
354 else if (prop == dsi->height_out)
355 *val = dsi->height_out_prop_val;
356 else if (prop == dsi->width_out)
357 *val = dsi->width_out_prop_val;
358 else if (prop == dsi->in_fmt)
359 *val = dsi->in_fmt_prop_val;
360 else if (prop == dsi->out_fmt)
361 *val = dsi->out_fmt_prop_val;
362 else
363 return -EINVAL;
364
365 return 0;
366}
367
368static int xlnx_dsi_host_attach(struct mipi_dsi_host *host,
369 struct mipi_dsi_device *device)
370{
371 u32 panel_lanes;
372 struct xlnx_dsi *dsi = host_to_dsi(host);
373
374 panel_lanes = device->lanes;
375 dsi->mode_flags = device->mode_flags;
376 dsi->panel_node = device->dev.of_node;
377
378 if (panel_lanes != dsi->lanes) {
379 dev_err(dsi->dev, "Mismatch of lanes. panel = %d, DSI = %d\n",
380 panel_lanes, dsi->lanes);
381 return -EINVAL;
382 }
383
384 if (dsi->lanes > 4 || dsi->lanes < 1) {
385 dev_err(dsi->dev, "%d lanes : invalid xlnx,dsi-num-lanes\n",
386 dsi->lanes);
387 return -EINVAL;
388 }
389
390 if (device->format != dsi->format) {
391 dev_err(dsi->dev, "Mismatch of format. panel = %d, DSI = %d\n",
392 device->format, dsi->format);
393 return -EINVAL;
394 }
395
396 if (dsi->connector.dev)
397 drm_helper_hpd_irq_event(dsi->connector.dev);
398
399 return 0;
400}
401
402static int xlnx_dsi_host_detach(struct mipi_dsi_host *host,
403 struct mipi_dsi_device *device)
404{
405 struct xlnx_dsi *dsi = host_to_dsi(host);
406
407 dsi->panel = NULL;
408
409 if (dsi->connector.dev)
410 drm_helper_hpd_irq_event(dsi->connector.dev);
411
412 return 0;
413}
414
415static const struct mipi_dsi_host_ops xlnx_dsi_ops = {
416 .attach = xlnx_dsi_host_attach,
417 .detach = xlnx_dsi_host_detach,
418};
419
420static int xlnx_dsi_connector_dpms(struct drm_connector *connector, int mode)
421{
422 struct xlnx_dsi *dsi = connector_to_dsi(connector);
423 int ret;
424
425 dev_dbg(dsi->dev, "connector dpms state: %d\n", mode);
426
427 switch (mode) {
428 case DRM_MODE_DPMS_ON:
429 ret = drm_panel_prepare(dsi->panel);
430 if (ret < 0) {
431 dev_err(dsi->dev, "DRM panel not found\n");
432 return ret;
433 }
434
435 ret = drm_panel_enable(dsi->panel);
436 if (ret < 0) {
437 drm_panel_unprepare(dsi->panel);
438 dev_err(dsi->dev, "DRM panel not enabled\n");
439 return ret;
440 }
441 break;
442 default:
443 drm_panel_disable(dsi->panel);
444 drm_panel_unprepare(dsi->panel);
445 break;
446 }
447
448 return drm_helper_connector_dpms(connector, mode);
449}
450
451static enum drm_connector_status
452xlnx_dsi_detect(struct drm_connector *connector, bool force)
453{
454 struct xlnx_dsi *dsi = connector_to_dsi(connector);
455
456 if (!dsi->panel) {
457 dsi->panel = of_drm_find_panel(dsi->panel_node);
458 if (dsi->panel)
459 drm_panel_attach(dsi->panel, &dsi->connector);
460 } else if (!dsi->panel_node) {
461 xlnx_dsi_connector_dpms(connector, DRM_MODE_DPMS_OFF);
462 drm_panel_detach(dsi->panel);
463 dsi->panel = NULL;
464 }
465
466 if (dsi->panel)
467 return connector_status_connected;
468
469 return connector_status_disconnected;
470}
471
472static void xlnx_dsi_connector_destroy(struct drm_connector *connector)
473{
474 drm_connector_unregister(connector);
475 drm_connector_cleanup(connector);
476 connector->dev = NULL;
477}
478
479static const struct drm_connector_funcs xlnx_dsi_connector_funcs = {
480 .dpms = xlnx_dsi_connector_dpms,
481 .detect = xlnx_dsi_detect,
482 .fill_modes = drm_helper_probe_single_connector_modes,
483 .destroy = xlnx_dsi_connector_destroy,
484 .atomic_set_property = xlnx_dsi_atomic_set_property,
485 .atomic_get_property = xlnx_dsi_atomic_get_property,
486 .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
487 .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
488 .reset = drm_atomic_helper_connector_reset,
489};
490
491static int xlnx_dsi_get_modes(struct drm_connector *connector)
492{
493 struct xlnx_dsi *dsi = connector_to_dsi(connector);
494
495 if (dsi->panel)
496 return dsi->panel->funcs->get_modes(dsi->panel);
497
498 return 0;
499}
500
501static struct drm_encoder *
502xlnx_dsi_best_encoder(struct drm_connector *connector)
503{
504 return &(connector_to_dsi(connector)->encoder);
505}
506
507static struct drm_connector_helper_funcs xlnx_dsi_connector_helper_funcs = {
508 .get_modes = xlnx_dsi_get_modes,
509 .best_encoder = xlnx_dsi_best_encoder,
510};
511
512
513
514
515
516
517
518
519
520static void xlnx_dsi_connector_create_property(struct drm_connector *connector)
521{
522 struct drm_device *dev = connector->dev;
523 struct xlnx_dsi *dsi = connector_to_dsi(connector);
524
525 dsi->eotp_prop = drm_property_create_bool(dev, 1, "eotp");
526 dsi->video_mode_prop = drm_property_create_range(dev, 0, "video_mode",
527 0, 2);
528 dsi->bllp_mode_prop = drm_property_create_bool(dev, 0, "bllp_mode");
529 dsi->bllp_type_prop = drm_property_create_bool(dev, 0, "bllp_type");
530 dsi->bllp_burst_time_prop =
531 drm_property_create_range(dev, 0, "bllp_burst_time", 0, 0xFFFF);
532 dsi->cmd_queue_prop = drm_property_create_range(dev, 0, "cmd_queue", 0,
533 0xffffff);
534 dsi->height_out = drm_property_create_range(dev, 0, "height_out",
535 2, 4096);
536 dsi->width_out = drm_property_create_range(dev, 0, "width_out",
537 2, 4096);
538 dsi->in_fmt = drm_property_create_range(dev, 0, "in_fmt", 0, 16384);
539 dsi->out_fmt = drm_property_create_range(dev, 0, "out_fmt", 0, 16384);
540}
541
542
543
544
545
546
547
548static void xlnx_dsi_connector_attach_property(struct drm_connector *connector)
549{
550 struct xlnx_dsi *dsi = connector_to_dsi(connector);
551 struct drm_mode_object *obj = &connector->base;
552
553 if (dsi->eotp_prop)
554 drm_object_attach_property(obj, dsi->eotp_prop, 1);
555
556 if (dsi->video_mode_prop)
557 drm_object_attach_property(obj, dsi->video_mode_prop, 0);
558
559 if (dsi->bllp_burst_time_prop)
560 drm_object_attach_property(&connector->base,
561 dsi->bllp_burst_time_prop, 0);
562
563 if (dsi->bllp_mode_prop)
564 drm_object_attach_property(&connector->base,
565 dsi->bllp_mode_prop, 0);
566
567 if (dsi->bllp_type_prop)
568 drm_object_attach_property(&connector->base,
569 dsi->bllp_type_prop, 0);
570
571 if (dsi->cmd_queue_prop)
572 drm_object_attach_property(&connector->base,
573 dsi->cmd_queue_prop, 0);
574
575 if (dsi->height_out)
576 drm_object_attach_property(obj, dsi->height_out, 0);
577
578 if (dsi->width_out)
579 drm_object_attach_property(obj, dsi->width_out, 0);
580
581 if (dsi->in_fmt)
582 drm_object_attach_property(obj, dsi->in_fmt, 0);
583
584 if (dsi->out_fmt)
585 drm_object_attach_property(obj, dsi->out_fmt, 0);
586}
587
588static int xlnx_dsi_create_connector(struct drm_encoder *encoder)
589{
590 struct xlnx_dsi *dsi = encoder_to_dsi(encoder);
591 struct drm_connector *connector = &dsi->connector;
592 int ret;
593
594 connector->polled = DRM_CONNECTOR_POLL_HPD;
595
596 ret = drm_connector_init(encoder->dev, connector,
597 &xlnx_dsi_connector_funcs,
598 DRM_MODE_CONNECTOR_DSI);
599 if (ret) {
600 dev_err(dsi->dev, "Failed to initialize connector with drm\n");
601 return ret;
602 }
603
604 drm_connector_helper_add(connector, &xlnx_dsi_connector_helper_funcs);
605 drm_connector_register(connector);
606 drm_mode_connector_attach_encoder(connector, encoder);
607 xlnx_dsi_connector_create_property(connector);
608 xlnx_dsi_connector_attach_property(connector);
609
610 return 0;
611}
612
613
614
615
616
617
618
619
620
621
622
623static void
624xlnx_dsi_atomic_mode_set(struct drm_encoder *encoder,
625 struct drm_crtc_state *crtc_state,
626 struct drm_connector_state *connector_state)
627{
628 struct xlnx_dsi *dsi = encoder_to_dsi(encoder);
629 struct videomode *vm = &dsi->vm;
630 struct drm_display_mode *m = &crtc_state->adjusted_mode;
631
632
633 xlnx_bridge_set_input(dsi->bridge, m->hdisplay, m->vdisplay,
634 dsi->in_fmt_prop_val);
635 xlnx_bridge_set_output(dsi->bridge, dsi->width_out_prop_val,
636 dsi->height_out_prop_val,
637 dsi->out_fmt_prop_val);
638 xlnx_bridge_enable(dsi->bridge);
639
640 vm->hactive = m->hdisplay;
641 vm->vactive = m->vdisplay;
642 vm->vfront_porch = m->vsync_start - m->vdisplay;
643 vm->vback_porch = m->vtotal - m->vsync_end;
644 vm->vsync_len = m->vsync_end - m->vsync_start;
645 vm->hfront_porch = m->hsync_start - m->hdisplay;
646 vm->hback_porch = m->htotal - m->hsync_end;
647 vm->hsync_len = m->hsync_end - m->hsync_start;
648 xlnx_dsi_set_display_mode(dsi);
649}
650
651static void xlnx_dsi_disable(struct drm_encoder *encoder)
652{
653 struct xlnx_dsi *dsi = encoder_to_dsi(encoder);
654
655 if (dsi->bridge)
656 xlnx_bridge_disable(dsi->bridge);
657
658 xlnx_dsi_set_display_disable(dsi);
659}
660
661static void xlnx_dsi_enable(struct drm_encoder *encoder)
662{
663 struct xlnx_dsi *dsi = encoder_to_dsi(encoder);
664
665 xlnx_dsi_set_display_enable(dsi);
666}
667
668static const struct drm_encoder_helper_funcs xlnx_dsi_encoder_helper_funcs = {
669 .atomic_mode_set = xlnx_dsi_atomic_mode_set,
670 .enable = xlnx_dsi_enable,
671 .disable = xlnx_dsi_disable,
672};
673
674static const struct drm_encoder_funcs xlnx_dsi_encoder_funcs = {
675 .destroy = drm_encoder_cleanup,
676};
677
678static int xlnx_dsi_parse_dt(struct xlnx_dsi *dsi)
679{
680 struct device *dev = dsi->dev;
681 struct device_node *node = dev->of_node;
682 int ret;
683 u32 datatype;
684 static const int xdsi_mul_fact[XDSI_NUM_DATA_T] = {300, 225, 225, 200};
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703 ret = of_property_read_u32(node, "xlnx,dsi-num-lanes", &dsi->lanes);
704 if (ret < 0) {
705 dev_err(dsi->dev, "missing xlnx,dsi-num-lanes property\n");
706 return ret;
707 }
708 if (dsi->lanes > 4 || dsi->lanes < 1) {
709 dev_err(dsi->dev, "%d lanes : invalid lanes\n", dsi->lanes);
710 return -EINVAL;
711 }
712 ret = of_property_read_u32(node, "xlnx,dsi-data-type", &datatype);
713 if (ret < 0) {
714 dev_err(dsi->dev, "missing xlnx,dsi-data-type property\n");
715 return ret;
716 }
717 dsi->format = datatype;
718 if (datatype > MIPI_DSI_FMT_RGB565) {
719 dev_err(dsi->dev, "Invalid xlnx,dsi-data-type string\n");
720 return -EINVAL;
721 }
722 dsi->mul_factor = xdsi_mul_fact[datatype];
723 dev_dbg(dsi->dev, "DSI controller num lanes = %d", dsi->lanes);
724 dev_dbg(dsi->dev, "DSI controller datatype = %d\n", datatype);
725
726 return 0;
727}
728
729static int xlnx_dsi_bind(struct device *dev, struct device *master,
730 void *data)
731{
732 struct xlnx_dsi *dsi = dev_get_drvdata(dev);
733 struct drm_encoder *encoder = &dsi->encoder;
734 struct drm_device *drm_dev = data;
735 int ret;
736
737
738
739
740
741
742 encoder->possible_crtcs = 1;
743 drm_encoder_init(drm_dev, encoder, &xlnx_dsi_encoder_funcs,
744 DRM_MODE_ENCODER_DSI, NULL);
745 drm_encoder_helper_add(encoder, &xlnx_dsi_encoder_helper_funcs);
746 ret = xlnx_dsi_create_connector(encoder);
747 if (ret) {
748 dev_err(dsi->dev, "fail creating connector, ret = %d\n", ret);
749 drm_encoder_cleanup(encoder);
750 return ret;
751 }
752 ret = mipi_dsi_host_register(&dsi->dsi_host);
753 if (ret) {
754 xlnx_dsi_connector_destroy(&dsi->connector);
755 drm_encoder_cleanup(encoder);
756 return ret;
757 }
758 return 0;
759}
760
761static void xlnx_dsi_unbind(struct device *dev, struct device *master,
762 void *data)
763{
764 struct xlnx_dsi *dsi = dev_get_drvdata(dev);
765
766 xlnx_dsi_disable(&dsi->encoder);
767 mipi_dsi_host_unregister(&dsi->dsi_host);
768 xlnx_bridge_disable(dsi->bridge);
769}
770
771static const struct component_ops xlnx_dsi_component_ops = {
772 .bind = xlnx_dsi_bind,
773 .unbind = xlnx_dsi_unbind,
774};
775
776static int xlnx_dsi_probe(struct platform_device *pdev)
777{
778 struct device *dev = &pdev->dev;
779 struct resource *res;
780 struct xlnx_dsi *dsi;
781 struct device_node *vpss_node;
782 int ret;
783
784 dsi = devm_kzalloc(dev, sizeof(*dsi), GFP_KERNEL);
785 if (!dsi)
786 return -ENOMEM;
787
788 dsi->dsi_host.ops = &xlnx_dsi_ops;
789 dsi->dsi_host.dev = dev;
790 dsi->dev = dev;
791
792 ret = xlnx_dsi_parse_dt(dsi);
793 if (ret)
794 return ret;
795
796 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
797 dsi->iomem = devm_ioremap_resource(dev, res);
798 if (IS_ERR(dsi->iomem))
799 return PTR_ERR(dsi->iomem);
800
801 platform_set_drvdata(pdev, dsi);
802
803
804 vpss_node = of_parse_phandle(dsi->dev->of_node, "xlnx,vpss", 0);
805 if (vpss_node) {
806 dsi->bridge = of_xlnx_bridge_get(vpss_node);
807 if (!dsi->bridge) {
808 dev_info(dsi->dev, "Didn't get bridge instance\n");
809 return -EPROBE_DEFER;
810 }
811 }
812
813 return component_add(dev, &xlnx_dsi_component_ops);
814}
815
816static int xlnx_dsi_remove(struct platform_device *pdev)
817{
818 component_del(&pdev->dev, &xlnx_dsi_component_ops);
819
820 return 0;
821}
822
823static const struct of_device_id xlnx_dsi_of_match[] = {
824 { .compatible = "xlnx,dsi"},
825 { }
826};
827MODULE_DEVICE_TABLE(of, xlnx_dsi_of_match);
828
829static struct platform_driver dsi_driver = {
830 .probe = xlnx_dsi_probe,
831 .remove = xlnx_dsi_remove,
832 .driver = {
833 .name = "xlnx-dsi",
834 .of_match_table = xlnx_dsi_of_match,
835 },
836};
837
838module_platform_driver(dsi_driver);
839
840MODULE_AUTHOR("Siva Rajesh <sivaraj@xilinx.com>");
841MODULE_DESCRIPTION("Xilinx FPGA MIPI DSI Tx Driver");
842MODULE_LICENSE("GPL v2");
843