1 // SPDX-License-Identifier: GPL-2.0
3 // Ingenic JZ47xx KMS driver
5 // Copyright (C) 2019, Paul Cercueil <paul@crapouillou.net>
8 #include <linux/dma-mapping.h>
9 #include <linux/module.h>
10 #include <linux/of_device.h>
11 #include <linux/platform_device.h>
12 #include <linux/regmap.h>
14 #include <drm/drm_atomic.h>
15 #include <drm/drm_atomic_helper.h>
16 #include <drm/drm_bridge.h>
17 #include <drm/drm_crtc.h>
18 #include <drm/drm_crtc_helper.h>
19 #include <drm/drm_drv.h>
20 #include <drm/drm_gem_cma_helper.h>
21 #include <drm/drm_fb_cma_helper.h>
22 #include <drm/drm_fb_helper.h>
23 #include <drm/drm_fourcc.h>
24 #include <drm/drm_gem_framebuffer_helper.h>
25 #include <drm/drm_irq.h>
26 #include <drm/drm_managed.h>
27 #include <drm/drm_of.h>
28 #include <drm/drm_panel.h>
29 #include <drm/drm_plane.h>
30 #include <drm/drm_plane_helper.h>
31 #include <drm/drm_probe_helper.h>
32 #include <drm/drm_simple_kms_helper.h>
33 #include <drm/drm_vblank.h>
35 #define JZ_REG_LCD_CFG 0x00
36 #define JZ_REG_LCD_VSYNC 0x04
37 #define JZ_REG_LCD_HSYNC 0x08
38 #define JZ_REG_LCD_VAT 0x0C
39 #define JZ_REG_LCD_DAH 0x10
40 #define JZ_REG_LCD_DAV 0x14
41 #define JZ_REG_LCD_PS 0x18
42 #define JZ_REG_LCD_CLS 0x1C
43 #define JZ_REG_LCD_SPL 0x20
44 #define JZ_REG_LCD_REV 0x24
45 #define JZ_REG_LCD_CTRL 0x30
46 #define JZ_REG_LCD_STATE 0x34
47 #define JZ_REG_LCD_IID 0x38
48 #define JZ_REG_LCD_DA0 0x40
49 #define JZ_REG_LCD_SA0 0x44
50 #define JZ_REG_LCD_FID0 0x48
51 #define JZ_REG_LCD_CMD0 0x4C
52 #define JZ_REG_LCD_DA1 0x50
53 #define JZ_REG_LCD_SA1 0x54
54 #define JZ_REG_LCD_FID1 0x58
55 #define JZ_REG_LCD_CMD1 0x5C
57 #define JZ_LCD_CFG_SLCD BIT(31)
58 #define JZ_LCD_CFG_PS_DISABLE BIT(23)
59 #define JZ_LCD_CFG_CLS_DISABLE BIT(22)
60 #define JZ_LCD_CFG_SPL_DISABLE BIT(21)
61 #define JZ_LCD_CFG_REV_DISABLE BIT(20)
62 #define JZ_LCD_CFG_HSYNCM BIT(19)
63 #define JZ_LCD_CFG_PCLKM BIT(18)
64 #define JZ_LCD_CFG_INV BIT(17)
65 #define JZ_LCD_CFG_SYNC_DIR BIT(16)
66 #define JZ_LCD_CFG_PS_POLARITY BIT(15)
67 #define JZ_LCD_CFG_CLS_POLARITY BIT(14)
68 #define JZ_LCD_CFG_SPL_POLARITY BIT(13)
69 #define JZ_LCD_CFG_REV_POLARITY BIT(12)
70 #define JZ_LCD_CFG_HSYNC_ACTIVE_LOW BIT(11)
71 #define JZ_LCD_CFG_PCLK_FALLING_EDGE BIT(10)
72 #define JZ_LCD_CFG_DE_ACTIVE_LOW BIT(9)
73 #define JZ_LCD_CFG_VSYNC_ACTIVE_LOW BIT(8)
74 #define JZ_LCD_CFG_18_BIT BIT(7)
75 #define JZ_LCD_CFG_PDW (BIT(5) | BIT(4))
77 #define JZ_LCD_CFG_MODE_GENERIC_16BIT 0
78 #define JZ_LCD_CFG_MODE_GENERIC_18BIT BIT(7)
79 #define JZ_LCD_CFG_MODE_GENERIC_24BIT BIT(6)
81 #define JZ_LCD_CFG_MODE_SPECIAL_TFT_1 1
82 #define JZ_LCD_CFG_MODE_SPECIAL_TFT_2 2
83 #define JZ_LCD_CFG_MODE_SPECIAL_TFT_3 3
85 #define JZ_LCD_CFG_MODE_TV_OUT_P 4
86 #define JZ_LCD_CFG_MODE_TV_OUT_I 6
88 #define JZ_LCD_CFG_MODE_SINGLE_COLOR_STN 8
89 #define JZ_LCD_CFG_MODE_SINGLE_MONOCHROME_STN 9
90 #define JZ_LCD_CFG_MODE_DUAL_COLOR_STN 10
91 #define JZ_LCD_CFG_MODE_DUAL_MONOCHROME_STN 11
93 #define JZ_LCD_CFG_MODE_8BIT_SERIAL 12
94 #define JZ_LCD_CFG_MODE_LCM 13
96 #define JZ_LCD_VSYNC_VPS_OFFSET 16
97 #define JZ_LCD_VSYNC_VPE_OFFSET 0
99 #define JZ_LCD_HSYNC_HPS_OFFSET 16
100 #define JZ_LCD_HSYNC_HPE_OFFSET 0
102 #define JZ_LCD_VAT_HT_OFFSET 16
103 #define JZ_LCD_VAT_VT_OFFSET 0
105 #define JZ_LCD_DAH_HDS_OFFSET 16
106 #define JZ_LCD_DAH_HDE_OFFSET 0
108 #define JZ_LCD_DAV_VDS_OFFSET 16
109 #define JZ_LCD_DAV_VDE_OFFSET 0
111 #define JZ_LCD_CTRL_BURST_4 (0x0 << 28)
112 #define JZ_LCD_CTRL_BURST_8 (0x1 << 28)
113 #define JZ_LCD_CTRL_BURST_16 (0x2 << 28)
114 #define JZ_LCD_CTRL_RGB555 BIT(27)
115 #define JZ_LCD_CTRL_OFUP BIT(26)
116 #define JZ_LCD_CTRL_FRC_GRAYSCALE_16 (0x0 << 24)
117 #define JZ_LCD_CTRL_FRC_GRAYSCALE_4 (0x1 << 24)
118 #define JZ_LCD_CTRL_FRC_GRAYSCALE_2 (0x2 << 24)
119 #define JZ_LCD_CTRL_PDD_MASK (0xff << 16)
120 #define JZ_LCD_CTRL_EOF_IRQ BIT(13)
121 #define JZ_LCD_CTRL_SOF_IRQ BIT(12)
122 #define JZ_LCD_CTRL_OFU_IRQ BIT(11)
123 #define JZ_LCD_CTRL_IFU0_IRQ BIT(10)
124 #define JZ_LCD_CTRL_IFU1_IRQ BIT(9)
125 #define JZ_LCD_CTRL_DD_IRQ BIT(8)
126 #define JZ_LCD_CTRL_QDD_IRQ BIT(7)
127 #define JZ_LCD_CTRL_REVERSE_ENDIAN BIT(6)
128 #define JZ_LCD_CTRL_LSB_FISRT BIT(5)
129 #define JZ_LCD_CTRL_DISABLE BIT(4)
130 #define JZ_LCD_CTRL_ENABLE BIT(3)
131 #define JZ_LCD_CTRL_BPP_1 0x0
132 #define JZ_LCD_CTRL_BPP_2 0x1
133 #define JZ_LCD_CTRL_BPP_4 0x2
134 #define JZ_LCD_CTRL_BPP_8 0x3
135 #define JZ_LCD_CTRL_BPP_15_16 0x4
136 #define JZ_LCD_CTRL_BPP_18_24 0x5
137 #define JZ_LCD_CTRL_BPP_MASK (JZ_LCD_CTRL_RGB555 | (0x7 << 0))
139 #define JZ_LCD_CMD_SOF_IRQ BIT(31)
140 #define JZ_LCD_CMD_EOF_IRQ BIT(30)
141 #define JZ_LCD_CMD_ENABLE_PAL BIT(28)
143 #define JZ_LCD_SYNC_MASK 0x3ff
145 #define JZ_LCD_STATE_EOF_IRQ BIT(5)
146 #define JZ_LCD_STATE_SOF_IRQ BIT(4)
147 #define JZ_LCD_STATE_DISABLED BIT(0)
149 struct ingenic_dma_hwdesc
{
158 unsigned int max_width
, max_height
;
162 struct drm_device drm
;
163 struct drm_plane primary
;
164 struct drm_crtc crtc
;
165 struct drm_encoder encoder
;
169 struct clk
*lcd_clk
, *pix_clk
;
170 const struct jz_soc_info
*soc_info
;
172 struct ingenic_dma_hwdesc
*dma_hwdesc
;
173 dma_addr_t dma_hwdesc_phys
;
178 static const u32 ingenic_drm_primary_formats
[] = {
184 static bool ingenic_drm_writeable_reg(struct device
*dev
, unsigned int reg
)
189 case JZ_REG_LCD_FID0
:
190 case JZ_REG_LCD_CMD0
:
192 case JZ_REG_LCD_FID1
:
193 case JZ_REG_LCD_CMD1
:
200 static const struct regmap_config ingenic_drm_regmap_config
= {
205 .max_register
= JZ_REG_LCD_CMD1
,
206 .writeable_reg
= ingenic_drm_writeable_reg
,
209 static inline struct ingenic_drm
*drm_device_get_priv(struct drm_device
*drm
)
211 return container_of(drm
, struct ingenic_drm
, drm
);
214 static inline struct ingenic_drm
*drm_crtc_get_priv(struct drm_crtc
*crtc
)
216 return container_of(crtc
, struct ingenic_drm
, crtc
);
219 static inline struct ingenic_drm
*
220 drm_encoder_get_priv(struct drm_encoder
*encoder
)
222 return container_of(encoder
, struct ingenic_drm
, encoder
);
225 static inline struct ingenic_drm
*drm_plane_get_priv(struct drm_plane
*plane
)
227 return container_of(plane
, struct ingenic_drm
, primary
);
230 static void ingenic_drm_crtc_atomic_enable(struct drm_crtc
*crtc
,
231 struct drm_crtc_state
*state
)
233 struct ingenic_drm
*priv
= drm_crtc_get_priv(crtc
);
235 regmap_write(priv
->map
, JZ_REG_LCD_STATE
, 0);
237 regmap_update_bits(priv
->map
, JZ_REG_LCD_CTRL
,
238 JZ_LCD_CTRL_ENABLE
| JZ_LCD_CTRL_DISABLE
,
241 drm_crtc_vblank_on(crtc
);
244 static void ingenic_drm_crtc_atomic_disable(struct drm_crtc
*crtc
,
245 struct drm_crtc_state
*state
)
247 struct ingenic_drm
*priv
= drm_crtc_get_priv(crtc
);
250 drm_crtc_vblank_off(crtc
);
252 regmap_update_bits(priv
->map
, JZ_REG_LCD_CTRL
,
253 JZ_LCD_CTRL_DISABLE
, JZ_LCD_CTRL_DISABLE
);
255 regmap_read_poll_timeout(priv
->map
, JZ_REG_LCD_STATE
, var
,
256 var
& JZ_LCD_STATE_DISABLED
,
260 static void ingenic_drm_crtc_update_timings(struct ingenic_drm
*priv
,
261 struct drm_display_mode
*mode
)
263 unsigned int vpe
, vds
, vde
, vt
, hpe
, hds
, hde
, ht
;
265 vpe
= mode
->vsync_end
- mode
->vsync_start
;
266 vds
= mode
->vtotal
- mode
->vsync_start
;
267 vde
= vds
+ mode
->vdisplay
;
268 vt
= vde
+ mode
->vsync_start
- mode
->vdisplay
;
270 hpe
= mode
->hsync_end
- mode
->hsync_start
;
271 hds
= mode
->htotal
- mode
->hsync_start
;
272 hde
= hds
+ mode
->hdisplay
;
273 ht
= hde
+ mode
->hsync_start
- mode
->hdisplay
;
275 regmap_write(priv
->map
, JZ_REG_LCD_VSYNC
,
276 0 << JZ_LCD_VSYNC_VPS_OFFSET
|
277 vpe
<< JZ_LCD_VSYNC_VPE_OFFSET
);
279 regmap_write(priv
->map
, JZ_REG_LCD_HSYNC
,
280 0 << JZ_LCD_HSYNC_HPS_OFFSET
|
281 hpe
<< JZ_LCD_HSYNC_HPE_OFFSET
);
283 regmap_write(priv
->map
, JZ_REG_LCD_VAT
,
284 ht
<< JZ_LCD_VAT_HT_OFFSET
|
285 vt
<< JZ_LCD_VAT_VT_OFFSET
);
287 regmap_write(priv
->map
, JZ_REG_LCD_DAH
,
288 hds
<< JZ_LCD_DAH_HDS_OFFSET
|
289 hde
<< JZ_LCD_DAH_HDE_OFFSET
);
290 regmap_write(priv
->map
, JZ_REG_LCD_DAV
,
291 vds
<< JZ_LCD_DAV_VDS_OFFSET
|
292 vde
<< JZ_LCD_DAV_VDE_OFFSET
);
294 if (priv
->panel_is_sharp
) {
295 regmap_write(priv
->map
, JZ_REG_LCD_PS
, hde
<< 16 | (hde
+ 1));
296 regmap_write(priv
->map
, JZ_REG_LCD_CLS
, hde
<< 16 | (hde
+ 1));
297 regmap_write(priv
->map
, JZ_REG_LCD_SPL
, hpe
<< 16 | (hpe
+ 1));
298 regmap_write(priv
->map
, JZ_REG_LCD_REV
, mode
->htotal
<< 16);
302 static void ingenic_drm_crtc_update_ctrl(struct ingenic_drm
*priv
,
303 const struct drm_format_info
*finfo
)
305 unsigned int ctrl
= JZ_LCD_CTRL_OFUP
| JZ_LCD_CTRL_BURST_16
;
307 switch (finfo
->format
) {
308 case DRM_FORMAT_XRGB1555
:
309 ctrl
|= JZ_LCD_CTRL_RGB555
;
311 case DRM_FORMAT_RGB565
:
312 ctrl
|= JZ_LCD_CTRL_BPP_15_16
;
314 case DRM_FORMAT_XRGB8888
:
315 ctrl
|= JZ_LCD_CTRL_BPP_18_24
;
319 regmap_update_bits(priv
->map
, JZ_REG_LCD_CTRL
,
320 JZ_LCD_CTRL_OFUP
| JZ_LCD_CTRL_BURST_16
|
321 JZ_LCD_CTRL_BPP_MASK
, ctrl
);
324 static int ingenic_drm_crtc_atomic_check(struct drm_crtc
*crtc
,
325 struct drm_crtc_state
*state
)
327 struct ingenic_drm
*priv
= drm_crtc_get_priv(crtc
);
330 if (!drm_atomic_crtc_needs_modeset(state
))
333 if (state
->mode
.hdisplay
> priv
->soc_info
->max_width
||
334 state
->mode
.vdisplay
> priv
->soc_info
->max_height
)
337 rate
= clk_round_rate(priv
->pix_clk
,
338 state
->adjusted_mode
.clock
* 1000);
345 static void ingenic_drm_crtc_atomic_flush(struct drm_crtc
*crtc
,
346 struct drm_crtc_state
*oldstate
)
348 struct ingenic_drm
*priv
= drm_crtc_get_priv(crtc
);
349 struct drm_crtc_state
*state
= crtc
->state
;
350 struct drm_pending_vblank_event
*event
= state
->event
;
351 struct drm_framebuffer
*drm_fb
= crtc
->primary
->state
->fb
;
352 const struct drm_format_info
*finfo
;
354 if (drm_atomic_crtc_needs_modeset(state
)) {
355 finfo
= drm_format_info(drm_fb
->format
->format
);
357 ingenic_drm_crtc_update_timings(priv
, &state
->mode
);
358 ingenic_drm_crtc_update_ctrl(priv
, finfo
);
360 clk_set_rate(priv
->pix_clk
, state
->adjusted_mode
.clock
* 1000);
362 regmap_write(priv
->map
, JZ_REG_LCD_DA0
, priv
->dma_hwdesc
->next
);
368 spin_lock_irq(&crtc
->dev
->event_lock
);
369 if (drm_crtc_vblank_get(crtc
) == 0)
370 drm_crtc_arm_vblank_event(crtc
, event
);
372 drm_crtc_send_vblank_event(crtc
, event
);
373 spin_unlock_irq(&crtc
->dev
->event_lock
);
377 static void ingenic_drm_plane_atomic_update(struct drm_plane
*plane
,
378 struct drm_plane_state
*oldstate
)
380 struct ingenic_drm
*priv
= drm_plane_get_priv(plane
);
381 struct drm_plane_state
*state
= plane
->state
;
382 unsigned int width
, height
, cpp
;
385 if (state
&& state
->fb
) {
386 addr
= drm_fb_cma_get_gem_addr(state
->fb
, state
, 0);
387 width
= state
->src_w
>> 16;
388 height
= state
->src_h
>> 16;
389 cpp
= state
->fb
->format
->cpp
[plane
->index
];
391 priv
->dma_hwdesc
->addr
= addr
;
392 priv
->dma_hwdesc
->cmd
= width
* height
* cpp
/ 4;
393 priv
->dma_hwdesc
->cmd
|= JZ_LCD_CMD_EOF_IRQ
;
397 static void ingenic_drm_encoder_atomic_mode_set(struct drm_encoder
*encoder
,
398 struct drm_crtc_state
*crtc_state
,
399 struct drm_connector_state
*conn_state
)
401 struct ingenic_drm
*priv
= drm_encoder_get_priv(encoder
);
402 struct drm_display_mode
*mode
= &crtc_state
->adjusted_mode
;
403 struct drm_connector
*conn
= conn_state
->connector
;
404 struct drm_display_info
*info
= &conn
->display_info
;
407 priv
->panel_is_sharp
= info
->bus_flags
& DRM_BUS_FLAG_SHARP_SIGNALS
;
409 if (priv
->panel_is_sharp
) {
410 cfg
= JZ_LCD_CFG_MODE_SPECIAL_TFT_1
| JZ_LCD_CFG_REV_POLARITY
;
412 cfg
= JZ_LCD_CFG_PS_DISABLE
| JZ_LCD_CFG_CLS_DISABLE
413 | JZ_LCD_CFG_SPL_DISABLE
| JZ_LCD_CFG_REV_DISABLE
;
416 if (mode
->flags
& DRM_MODE_FLAG_NHSYNC
)
417 cfg
|= JZ_LCD_CFG_HSYNC_ACTIVE_LOW
;
418 if (mode
->flags
& DRM_MODE_FLAG_NVSYNC
)
419 cfg
|= JZ_LCD_CFG_VSYNC_ACTIVE_LOW
;
420 if (info
->bus_flags
& DRM_BUS_FLAG_DE_LOW
)
421 cfg
|= JZ_LCD_CFG_DE_ACTIVE_LOW
;
422 if (info
->bus_flags
& DRM_BUS_FLAG_PIXDATA_NEGEDGE
)
423 cfg
|= JZ_LCD_CFG_PCLK_FALLING_EDGE
;
425 if (!priv
->panel_is_sharp
) {
426 if (conn
->connector_type
== DRM_MODE_CONNECTOR_TV
) {
427 if (mode
->flags
& DRM_MODE_FLAG_INTERLACE
)
428 cfg
|= JZ_LCD_CFG_MODE_TV_OUT_I
;
430 cfg
|= JZ_LCD_CFG_MODE_TV_OUT_P
;
432 switch (*info
->bus_formats
) {
433 case MEDIA_BUS_FMT_RGB565_1X16
:
434 cfg
|= JZ_LCD_CFG_MODE_GENERIC_16BIT
;
436 case MEDIA_BUS_FMT_RGB666_1X18
:
437 cfg
|= JZ_LCD_CFG_MODE_GENERIC_18BIT
;
439 case MEDIA_BUS_FMT_RGB888_1X24
:
440 cfg
|= JZ_LCD_CFG_MODE_GENERIC_24BIT
;
442 case MEDIA_BUS_FMT_RGB888_3X8
:
443 cfg
|= JZ_LCD_CFG_MODE_8BIT_SERIAL
;
451 regmap_write(priv
->map
, JZ_REG_LCD_CFG
, cfg
);
454 static int ingenic_drm_encoder_atomic_check(struct drm_encoder
*encoder
,
455 struct drm_crtc_state
*crtc_state
,
456 struct drm_connector_state
*conn_state
)
458 struct drm_display_info
*info
= &conn_state
->connector
->display_info
;
460 if (info
->num_bus_formats
!= 1)
463 if (conn_state
->connector
->connector_type
== DRM_MODE_CONNECTOR_TV
)
466 switch (*info
->bus_formats
) {
467 case MEDIA_BUS_FMT_RGB565_1X16
:
468 case MEDIA_BUS_FMT_RGB666_1X18
:
469 case MEDIA_BUS_FMT_RGB888_1X24
:
470 case MEDIA_BUS_FMT_RGB888_3X8
:
477 static irqreturn_t
ingenic_drm_irq_handler(int irq
, void *arg
)
479 struct ingenic_drm
*priv
= drm_device_get_priv(arg
);
482 regmap_read(priv
->map
, JZ_REG_LCD_STATE
, &state
);
484 regmap_update_bits(priv
->map
, JZ_REG_LCD_STATE
,
485 JZ_LCD_STATE_EOF_IRQ
, 0);
487 if (state
& JZ_LCD_STATE_EOF_IRQ
)
488 drm_crtc_handle_vblank(&priv
->crtc
);
493 static int ingenic_drm_enable_vblank(struct drm_crtc
*crtc
)
495 struct ingenic_drm
*priv
= drm_crtc_get_priv(crtc
);
497 regmap_update_bits(priv
->map
, JZ_REG_LCD_CTRL
,
498 JZ_LCD_CTRL_EOF_IRQ
, JZ_LCD_CTRL_EOF_IRQ
);
503 static void ingenic_drm_disable_vblank(struct drm_crtc
*crtc
)
505 struct ingenic_drm
*priv
= drm_crtc_get_priv(crtc
);
507 regmap_update_bits(priv
->map
, JZ_REG_LCD_CTRL
, JZ_LCD_CTRL_EOF_IRQ
, 0);
510 DEFINE_DRM_GEM_CMA_FOPS(ingenic_drm_fops
);
512 static struct drm_driver ingenic_drm_driver_data
= {
513 .driver_features
= DRIVER_MODESET
| DRIVER_GEM
| DRIVER_ATOMIC
,
514 .name
= "ingenic-drm",
515 .desc
= "DRM module for Ingenic SoCs",
521 .fops
= &ingenic_drm_fops
,
523 .dumb_create
= drm_gem_cma_dumb_create
,
524 .gem_free_object_unlocked
= drm_gem_cma_free_object
,
525 .gem_vm_ops
= &drm_gem_cma_vm_ops
,
527 .prime_handle_to_fd
= drm_gem_prime_handle_to_fd
,
528 .prime_fd_to_handle
= drm_gem_prime_fd_to_handle
,
529 .gem_prime_get_sg_table
= drm_gem_cma_prime_get_sg_table
,
530 .gem_prime_import_sg_table
= drm_gem_cma_prime_import_sg_table
,
531 .gem_prime_vmap
= drm_gem_cma_prime_vmap
,
532 .gem_prime_vunmap
= drm_gem_cma_prime_vunmap
,
533 .gem_prime_mmap
= drm_gem_cma_prime_mmap
,
535 .irq_handler
= ingenic_drm_irq_handler
,
538 static const struct drm_plane_funcs ingenic_drm_primary_plane_funcs
= {
539 .update_plane
= drm_atomic_helper_update_plane
,
540 .disable_plane
= drm_atomic_helper_disable_plane
,
541 .reset
= drm_atomic_helper_plane_reset
,
542 .destroy
= drm_plane_cleanup
,
544 .atomic_duplicate_state
= drm_atomic_helper_plane_duplicate_state
,
545 .atomic_destroy_state
= drm_atomic_helper_plane_destroy_state
,
548 static const struct drm_crtc_funcs ingenic_drm_crtc_funcs
= {
549 .set_config
= drm_atomic_helper_set_config
,
550 .page_flip
= drm_atomic_helper_page_flip
,
551 .reset
= drm_atomic_helper_crtc_reset
,
552 .destroy
= drm_crtc_cleanup
,
554 .atomic_duplicate_state
= drm_atomic_helper_crtc_duplicate_state
,
555 .atomic_destroy_state
= drm_atomic_helper_crtc_destroy_state
,
557 .enable_vblank
= ingenic_drm_enable_vblank
,
558 .disable_vblank
= ingenic_drm_disable_vblank
,
560 .gamma_set
= drm_atomic_helper_legacy_gamma_set
,
563 static const struct drm_plane_helper_funcs ingenic_drm_plane_helper_funcs
= {
564 .atomic_update
= ingenic_drm_plane_atomic_update
,
565 .prepare_fb
= drm_gem_fb_prepare_fb
,
568 static const struct drm_crtc_helper_funcs ingenic_drm_crtc_helper_funcs
= {
569 .atomic_enable
= ingenic_drm_crtc_atomic_enable
,
570 .atomic_disable
= ingenic_drm_crtc_atomic_disable
,
571 .atomic_flush
= ingenic_drm_crtc_atomic_flush
,
572 .atomic_check
= ingenic_drm_crtc_atomic_check
,
575 static const struct drm_encoder_helper_funcs ingenic_drm_encoder_helper_funcs
= {
576 .atomic_mode_set
= ingenic_drm_encoder_atomic_mode_set
,
577 .atomic_check
= ingenic_drm_encoder_atomic_check
,
580 static const struct drm_mode_config_funcs ingenic_drm_mode_config_funcs
= {
581 .fb_create
= drm_gem_fb_create
,
582 .output_poll_changed
= drm_fb_helper_output_poll_changed
,
583 .atomic_check
= drm_atomic_helper_check
,
584 .atomic_commit
= drm_atomic_helper_commit
,
587 static void ingenic_drm_free_dma_hwdesc(void *d
)
589 struct ingenic_drm
*priv
= d
;
591 dma_free_coherent(priv
->dev
, sizeof(*priv
->dma_hwdesc
),
592 priv
->dma_hwdesc
, priv
->dma_hwdesc_phys
);
595 static int ingenic_drm_probe(struct platform_device
*pdev
)
597 const struct jz_soc_info
*soc_info
;
598 struct device
*dev
= &pdev
->dev
;
599 struct ingenic_drm
*priv
;
600 struct clk
*parent_clk
;
601 struct drm_bridge
*bridge
;
602 struct drm_panel
*panel
;
603 struct drm_device
*drm
;
608 soc_info
= of_device_get_match_data(dev
);
610 dev_err(dev
, "Missing platform data\n");
614 priv
= devm_drm_dev_alloc(dev
, &ingenic_drm_driver_data
,
615 struct ingenic_drm
, drm
);
617 return PTR_ERR(priv
);
619 priv
->soc_info
= soc_info
;
623 platform_set_drvdata(pdev
, priv
);
625 ret
= drmm_mode_config_init(drm
);
629 drm
->mode_config
.min_width
= 0;
630 drm
->mode_config
.min_height
= 0;
631 drm
->mode_config
.max_width
= soc_info
->max_width
;
632 drm
->mode_config
.max_height
= 4095;
633 drm
->mode_config
.funcs
= &ingenic_drm_mode_config_funcs
;
635 base
= devm_platform_ioremap_resource(pdev
, 0);
637 dev_err(dev
, "Failed to get memory resource");
638 return PTR_ERR(base
);
641 priv
->map
= devm_regmap_init_mmio(dev
, base
,
642 &ingenic_drm_regmap_config
);
643 if (IS_ERR(priv
->map
)) {
644 dev_err(dev
, "Failed to create regmap");
645 return PTR_ERR(priv
->map
);
648 irq
= platform_get_irq(pdev
, 0);
652 if (soc_info
->needs_dev_clk
) {
653 priv
->lcd_clk
= devm_clk_get(dev
, "lcd");
654 if (IS_ERR(priv
->lcd_clk
)) {
655 dev_err(dev
, "Failed to get lcd clock");
656 return PTR_ERR(priv
->lcd_clk
);
660 priv
->pix_clk
= devm_clk_get(dev
, "lcd_pclk");
661 if (IS_ERR(priv
->pix_clk
)) {
662 dev_err(dev
, "Failed to get pixel clock");
663 return PTR_ERR(priv
->pix_clk
);
666 ret
= drm_of_find_panel_or_bridge(dev
->of_node
, 0, 0, &panel
, &bridge
);
668 if (ret
!= -EPROBE_DEFER
)
669 dev_err(dev
, "Failed to get panel handle");
674 bridge
= devm_drm_panel_bridge_add_typed(dev
, panel
,
675 DRM_MODE_CONNECTOR_DPI
);
677 priv
->dma_hwdesc
= dma_alloc_coherent(dev
, sizeof(*priv
->dma_hwdesc
),
678 &priv
->dma_hwdesc_phys
,
680 if (!priv
->dma_hwdesc
)
683 ret
= devm_add_action_or_reset(dev
, ingenic_drm_free_dma_hwdesc
, priv
);
687 priv
->dma_hwdesc
->next
= priv
->dma_hwdesc_phys
;
688 priv
->dma_hwdesc
->id
= 0xdeafbead;
690 drm_plane_helper_add(&priv
->primary
, &ingenic_drm_plane_helper_funcs
);
692 ret
= drm_universal_plane_init(drm
, &priv
->primary
,
693 0, &ingenic_drm_primary_plane_funcs
,
694 ingenic_drm_primary_formats
,
695 ARRAY_SIZE(ingenic_drm_primary_formats
),
696 NULL
, DRM_PLANE_TYPE_PRIMARY
, NULL
);
698 dev_err(dev
, "Failed to register primary plane: %i", ret
);
702 drm_crtc_helper_add(&priv
->crtc
, &ingenic_drm_crtc_helper_funcs
);
704 ret
= drm_crtc_init_with_planes(drm
, &priv
->crtc
, &priv
->primary
,
705 NULL
, &ingenic_drm_crtc_funcs
, NULL
);
707 dev_err(dev
, "Failed to init CRTC: %i", ret
);
711 priv
->encoder
.possible_crtcs
= 1;
713 drm_encoder_helper_add(&priv
->encoder
,
714 &ingenic_drm_encoder_helper_funcs
);
716 ret
= drm_simple_encoder_init(drm
, &priv
->encoder
,
717 DRM_MODE_ENCODER_DPI
);
719 dev_err(dev
, "Failed to init encoder: %i", ret
);
723 ret
= drm_bridge_attach(&priv
->encoder
, bridge
, NULL
, 0);
725 dev_err(dev
, "Unable to attach bridge");
729 ret
= drm_irq_install(drm
, irq
);
731 dev_err(dev
, "Unable to install IRQ handler");
735 ret
= drm_vblank_init(drm
, 1);
737 dev_err(dev
, "Failed calling drm_vblank_init()");
741 drm_mode_config_reset(drm
);
743 ret
= clk_prepare_enable(priv
->pix_clk
);
745 dev_err(dev
, "Unable to start pixel clock");
750 parent_clk
= clk_get_parent(priv
->lcd_clk
);
751 parent_rate
= clk_get_rate(parent_clk
);
753 /* LCD Device clock must be 3x the pixel clock for STN panels,
754 * or 1.5x the pixel clock for TFT panels. To avoid having to
755 * check for the LCD device clock everytime we do a mode change,
756 * we set the LCD device clock to the highest rate possible.
758 ret
= clk_set_rate(priv
->lcd_clk
, parent_rate
);
760 dev_err(dev
, "Unable to set LCD clock rate");
761 goto err_pixclk_disable
;
764 ret
= clk_prepare_enable(priv
->lcd_clk
);
766 dev_err(dev
, "Unable to start lcd clock");
767 goto err_pixclk_disable
;
771 ret
= drm_dev_register(drm
, 0);
773 dev_err(dev
, "Failed to register DRM driver");
774 goto err_devclk_disable
;
777 drm_fbdev_generic_setup(drm
, 32);
783 clk_disable_unprepare(priv
->lcd_clk
);
785 clk_disable_unprepare(priv
->pix_clk
);
789 static int ingenic_drm_remove(struct platform_device
*pdev
)
791 struct ingenic_drm
*priv
= platform_get_drvdata(pdev
);
794 clk_disable_unprepare(priv
->lcd_clk
);
795 clk_disable_unprepare(priv
->pix_clk
);
797 drm_dev_unregister(&priv
->drm
);
798 drm_atomic_helper_shutdown(&priv
->drm
);
803 static const struct jz_soc_info jz4740_soc_info
= {
804 .needs_dev_clk
= true,
809 static const struct jz_soc_info jz4725b_soc_info
= {
810 .needs_dev_clk
= false,
815 static const struct jz_soc_info jz4770_soc_info
= {
816 .needs_dev_clk
= false,
821 static const struct of_device_id ingenic_drm_of_match
[] = {
822 { .compatible
= "ingenic,jz4740-lcd", .data
= &jz4740_soc_info
},
823 { .compatible
= "ingenic,jz4725b-lcd", .data
= &jz4725b_soc_info
},
824 { .compatible
= "ingenic,jz4770-lcd", .data
= &jz4770_soc_info
},
827 MODULE_DEVICE_TABLE(of
, ingenic_drm_of_match
);
829 static struct platform_driver ingenic_drm_driver
= {
831 .name
= "ingenic-drm",
832 .of_match_table
= of_match_ptr(ingenic_drm_of_match
),
834 .probe
= ingenic_drm_probe
,
835 .remove
= ingenic_drm_remove
,
837 module_platform_driver(ingenic_drm_driver
);
839 MODULE_AUTHOR("Paul Cercueil <paul@crapouillou.net>");
840 MODULE_DESCRIPTION("DRM driver for the Ingenic SoCs\n");
841 MODULE_LICENSE("GPL v2");