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_of.h>
27 #include <drm/drm_panel.h>
28 #include <drm/drm_plane.h>
29 #include <drm/drm_plane_helper.h>
30 #include <drm/drm_probe_helper.h>
31 #include <drm/drm_vblank.h>
33 #define JZ_REG_LCD_CFG 0x00
34 #define JZ_REG_LCD_VSYNC 0x04
35 #define JZ_REG_LCD_HSYNC 0x08
36 #define JZ_REG_LCD_VAT 0x0C
37 #define JZ_REG_LCD_DAH 0x10
38 #define JZ_REG_LCD_DAV 0x14
39 #define JZ_REG_LCD_PS 0x18
40 #define JZ_REG_LCD_CLS 0x1C
41 #define JZ_REG_LCD_SPL 0x20
42 #define JZ_REG_LCD_REV 0x24
43 #define JZ_REG_LCD_CTRL 0x30
44 #define JZ_REG_LCD_STATE 0x34
45 #define JZ_REG_LCD_IID 0x38
46 #define JZ_REG_LCD_DA0 0x40
47 #define JZ_REG_LCD_SA0 0x44
48 #define JZ_REG_LCD_FID0 0x48
49 #define JZ_REG_LCD_CMD0 0x4C
50 #define JZ_REG_LCD_DA1 0x50
51 #define JZ_REG_LCD_SA1 0x54
52 #define JZ_REG_LCD_FID1 0x58
53 #define JZ_REG_LCD_CMD1 0x5C
55 #define JZ_LCD_CFG_SLCD BIT(31)
56 #define JZ_LCD_CFG_PS_DISABLE BIT(23)
57 #define JZ_LCD_CFG_CLS_DISABLE BIT(22)
58 #define JZ_LCD_CFG_SPL_DISABLE BIT(21)
59 #define JZ_LCD_CFG_REV_DISABLE BIT(20)
60 #define JZ_LCD_CFG_HSYNCM BIT(19)
61 #define JZ_LCD_CFG_PCLKM BIT(18)
62 #define JZ_LCD_CFG_INV BIT(17)
63 #define JZ_LCD_CFG_SYNC_DIR BIT(16)
64 #define JZ_LCD_CFG_PS_POLARITY BIT(15)
65 #define JZ_LCD_CFG_CLS_POLARITY BIT(14)
66 #define JZ_LCD_CFG_SPL_POLARITY BIT(13)
67 #define JZ_LCD_CFG_REV_POLARITY BIT(12)
68 #define JZ_LCD_CFG_HSYNC_ACTIVE_LOW BIT(11)
69 #define JZ_LCD_CFG_PCLK_FALLING_EDGE BIT(10)
70 #define JZ_LCD_CFG_DE_ACTIVE_LOW BIT(9)
71 #define JZ_LCD_CFG_VSYNC_ACTIVE_LOW BIT(8)
72 #define JZ_LCD_CFG_18_BIT BIT(7)
73 #define JZ_LCD_CFG_PDW (BIT(5) | BIT(4))
75 #define JZ_LCD_CFG_MODE_GENERIC_16BIT 0
76 #define JZ_LCD_CFG_MODE_GENERIC_18BIT BIT(7)
77 #define JZ_LCD_CFG_MODE_GENERIC_24BIT BIT(6)
79 #define JZ_LCD_CFG_MODE_SPECIAL_TFT_1 1
80 #define JZ_LCD_CFG_MODE_SPECIAL_TFT_2 2
81 #define JZ_LCD_CFG_MODE_SPECIAL_TFT_3 3
83 #define JZ_LCD_CFG_MODE_TV_OUT_P 4
84 #define JZ_LCD_CFG_MODE_TV_OUT_I 6
86 #define JZ_LCD_CFG_MODE_SINGLE_COLOR_STN 8
87 #define JZ_LCD_CFG_MODE_SINGLE_MONOCHROME_STN 9
88 #define JZ_LCD_CFG_MODE_DUAL_COLOR_STN 10
89 #define JZ_LCD_CFG_MODE_DUAL_MONOCHROME_STN 11
91 #define JZ_LCD_CFG_MODE_8BIT_SERIAL 12
92 #define JZ_LCD_CFG_MODE_LCM 13
94 #define JZ_LCD_VSYNC_VPS_OFFSET 16
95 #define JZ_LCD_VSYNC_VPE_OFFSET 0
97 #define JZ_LCD_HSYNC_HPS_OFFSET 16
98 #define JZ_LCD_HSYNC_HPE_OFFSET 0
100 #define JZ_LCD_VAT_HT_OFFSET 16
101 #define JZ_LCD_VAT_VT_OFFSET 0
103 #define JZ_LCD_DAH_HDS_OFFSET 16
104 #define JZ_LCD_DAH_HDE_OFFSET 0
106 #define JZ_LCD_DAV_VDS_OFFSET 16
107 #define JZ_LCD_DAV_VDE_OFFSET 0
109 #define JZ_LCD_CTRL_BURST_4 (0x0 << 28)
110 #define JZ_LCD_CTRL_BURST_8 (0x1 << 28)
111 #define JZ_LCD_CTRL_BURST_16 (0x2 << 28)
112 #define JZ_LCD_CTRL_RGB555 BIT(27)
113 #define JZ_LCD_CTRL_OFUP BIT(26)
114 #define JZ_LCD_CTRL_FRC_GRAYSCALE_16 (0x0 << 24)
115 #define JZ_LCD_CTRL_FRC_GRAYSCALE_4 (0x1 << 24)
116 #define JZ_LCD_CTRL_FRC_GRAYSCALE_2 (0x2 << 24)
117 #define JZ_LCD_CTRL_PDD_MASK (0xff << 16)
118 #define JZ_LCD_CTRL_EOF_IRQ BIT(13)
119 #define JZ_LCD_CTRL_SOF_IRQ BIT(12)
120 #define JZ_LCD_CTRL_OFU_IRQ BIT(11)
121 #define JZ_LCD_CTRL_IFU0_IRQ BIT(10)
122 #define JZ_LCD_CTRL_IFU1_IRQ BIT(9)
123 #define JZ_LCD_CTRL_DD_IRQ BIT(8)
124 #define JZ_LCD_CTRL_QDD_IRQ BIT(7)
125 #define JZ_LCD_CTRL_REVERSE_ENDIAN BIT(6)
126 #define JZ_LCD_CTRL_LSB_FISRT BIT(5)
127 #define JZ_LCD_CTRL_DISABLE BIT(4)
128 #define JZ_LCD_CTRL_ENABLE BIT(3)
129 #define JZ_LCD_CTRL_BPP_1 0x0
130 #define JZ_LCD_CTRL_BPP_2 0x1
131 #define JZ_LCD_CTRL_BPP_4 0x2
132 #define JZ_LCD_CTRL_BPP_8 0x3
133 #define JZ_LCD_CTRL_BPP_15_16 0x4
134 #define JZ_LCD_CTRL_BPP_18_24 0x5
135 #define JZ_LCD_CTRL_BPP_MASK (JZ_LCD_CTRL_RGB555 | (0x7 << 0))
137 #define JZ_LCD_CMD_SOF_IRQ BIT(31)
138 #define JZ_LCD_CMD_EOF_IRQ BIT(30)
139 #define JZ_LCD_CMD_ENABLE_PAL BIT(28)
141 #define JZ_LCD_SYNC_MASK 0x3ff
143 #define JZ_LCD_STATE_EOF_IRQ BIT(5)
144 #define JZ_LCD_STATE_SOF_IRQ BIT(4)
145 #define JZ_LCD_STATE_DISABLED BIT(0)
147 struct ingenic_dma_hwdesc
{
156 unsigned int max_width
, max_height
;
160 struct drm_device drm
;
161 struct drm_plane primary
;
162 struct drm_crtc crtc
;
163 struct drm_encoder encoder
;
167 struct clk
*lcd_clk
, *pix_clk
;
168 const struct jz_soc_info
*soc_info
;
170 struct ingenic_dma_hwdesc
*dma_hwdesc
;
171 dma_addr_t dma_hwdesc_phys
;
176 static const u32 ingenic_drm_primary_formats
[] = {
182 static bool ingenic_drm_writeable_reg(struct device
*dev
, unsigned int reg
)
187 case JZ_REG_LCD_FID0
:
188 case JZ_REG_LCD_CMD0
:
190 case JZ_REG_LCD_FID1
:
191 case JZ_REG_LCD_CMD1
:
198 static const struct regmap_config ingenic_drm_regmap_config
= {
203 .max_register
= JZ_REG_LCD_CMD1
,
204 .writeable_reg
= ingenic_drm_writeable_reg
,
207 static inline struct ingenic_drm
*drm_device_get_priv(struct drm_device
*drm
)
209 return container_of(drm
, struct ingenic_drm
, drm
);
212 static inline struct ingenic_drm
*drm_crtc_get_priv(struct drm_crtc
*crtc
)
214 return container_of(crtc
, struct ingenic_drm
, crtc
);
217 static inline struct ingenic_drm
*
218 drm_encoder_get_priv(struct drm_encoder
*encoder
)
220 return container_of(encoder
, struct ingenic_drm
, encoder
);
223 static inline struct ingenic_drm
*drm_plane_get_priv(struct drm_plane
*plane
)
225 return container_of(plane
, struct ingenic_drm
, primary
);
228 static void ingenic_drm_crtc_atomic_enable(struct drm_crtc
*crtc
,
229 struct drm_crtc_state
*state
)
231 struct ingenic_drm
*priv
= drm_crtc_get_priv(crtc
);
233 regmap_write(priv
->map
, JZ_REG_LCD_STATE
, 0);
235 regmap_update_bits(priv
->map
, JZ_REG_LCD_CTRL
,
236 JZ_LCD_CTRL_ENABLE
| JZ_LCD_CTRL_DISABLE
,
239 drm_crtc_vblank_on(crtc
);
242 static void ingenic_drm_crtc_atomic_disable(struct drm_crtc
*crtc
,
243 struct drm_crtc_state
*state
)
245 struct ingenic_drm
*priv
= drm_crtc_get_priv(crtc
);
248 drm_crtc_vblank_off(crtc
);
250 regmap_update_bits(priv
->map
, JZ_REG_LCD_CTRL
,
251 JZ_LCD_CTRL_DISABLE
, JZ_LCD_CTRL_DISABLE
);
253 regmap_read_poll_timeout(priv
->map
, JZ_REG_LCD_STATE
, var
,
254 var
& JZ_LCD_STATE_DISABLED
,
258 static void ingenic_drm_crtc_update_timings(struct ingenic_drm
*priv
,
259 struct drm_display_mode
*mode
)
261 unsigned int vpe
, vds
, vde
, vt
, hpe
, hds
, hde
, ht
;
263 vpe
= mode
->vsync_end
- mode
->vsync_start
;
264 vds
= mode
->vtotal
- mode
->vsync_start
;
265 vde
= vds
+ mode
->vdisplay
;
266 vt
= vde
+ mode
->vsync_start
- mode
->vdisplay
;
268 hpe
= mode
->hsync_end
- mode
->hsync_start
;
269 hds
= mode
->htotal
- mode
->hsync_start
;
270 hde
= hds
+ mode
->hdisplay
;
271 ht
= hde
+ mode
->hsync_start
- mode
->hdisplay
;
273 regmap_write(priv
->map
, JZ_REG_LCD_VSYNC
,
274 0 << JZ_LCD_VSYNC_VPS_OFFSET
|
275 vpe
<< JZ_LCD_VSYNC_VPE_OFFSET
);
277 regmap_write(priv
->map
, JZ_REG_LCD_HSYNC
,
278 0 << JZ_LCD_HSYNC_HPS_OFFSET
|
279 hpe
<< JZ_LCD_HSYNC_HPE_OFFSET
);
281 regmap_write(priv
->map
, JZ_REG_LCD_VAT
,
282 ht
<< JZ_LCD_VAT_HT_OFFSET
|
283 vt
<< JZ_LCD_VAT_VT_OFFSET
);
285 regmap_write(priv
->map
, JZ_REG_LCD_DAH
,
286 hds
<< JZ_LCD_DAH_HDS_OFFSET
|
287 hde
<< JZ_LCD_DAH_HDE_OFFSET
);
288 regmap_write(priv
->map
, JZ_REG_LCD_DAV
,
289 vds
<< JZ_LCD_DAV_VDS_OFFSET
|
290 vde
<< JZ_LCD_DAV_VDE_OFFSET
);
292 if (priv
->panel_is_sharp
) {
293 regmap_write(priv
->map
, JZ_REG_LCD_PS
, hde
<< 16 | (hde
+ 1));
294 regmap_write(priv
->map
, JZ_REG_LCD_CLS
, hde
<< 16 | (hde
+ 1));
295 regmap_write(priv
->map
, JZ_REG_LCD_SPL
, hpe
<< 16 | (hpe
+ 1));
296 regmap_write(priv
->map
, JZ_REG_LCD_REV
, mode
->htotal
<< 16);
300 static void ingenic_drm_crtc_update_ctrl(struct ingenic_drm
*priv
,
301 const struct drm_format_info
*finfo
)
303 unsigned int ctrl
= JZ_LCD_CTRL_OFUP
| JZ_LCD_CTRL_BURST_16
;
305 switch (finfo
->format
) {
306 case DRM_FORMAT_XRGB1555
:
307 ctrl
|= JZ_LCD_CTRL_RGB555
;
309 case DRM_FORMAT_RGB565
:
310 ctrl
|= JZ_LCD_CTRL_BPP_15_16
;
312 case DRM_FORMAT_XRGB8888
:
313 ctrl
|= JZ_LCD_CTRL_BPP_18_24
;
317 regmap_update_bits(priv
->map
, JZ_REG_LCD_CTRL
,
318 JZ_LCD_CTRL_OFUP
| JZ_LCD_CTRL_BURST_16
|
319 JZ_LCD_CTRL_BPP_MASK
, ctrl
);
322 static int ingenic_drm_crtc_atomic_check(struct drm_crtc
*crtc
,
323 struct drm_crtc_state
*state
)
325 struct ingenic_drm
*priv
= drm_crtc_get_priv(crtc
);
328 if (!drm_atomic_crtc_needs_modeset(state
))
331 if (state
->mode
.hdisplay
> priv
->soc_info
->max_height
||
332 state
->mode
.vdisplay
> priv
->soc_info
->max_width
)
335 rate
= clk_round_rate(priv
->pix_clk
,
336 state
->adjusted_mode
.clock
* 1000);
343 static void ingenic_drm_crtc_atomic_flush(struct drm_crtc
*crtc
,
344 struct drm_crtc_state
*oldstate
)
346 struct ingenic_drm
*priv
= drm_crtc_get_priv(crtc
);
347 struct drm_crtc_state
*state
= crtc
->state
;
348 struct drm_pending_vblank_event
*event
= state
->event
;
349 struct drm_framebuffer
*drm_fb
= crtc
->primary
->state
->fb
;
350 const struct drm_format_info
*finfo
;
352 if (drm_atomic_crtc_needs_modeset(state
)) {
353 finfo
= drm_format_info(drm_fb
->format
->format
);
355 ingenic_drm_crtc_update_timings(priv
, &state
->mode
);
356 ingenic_drm_crtc_update_ctrl(priv
, finfo
);
358 clk_set_rate(priv
->pix_clk
, state
->adjusted_mode
.clock
* 1000);
360 regmap_write(priv
->map
, JZ_REG_LCD_DA0
, priv
->dma_hwdesc
->next
);
366 spin_lock_irq(&crtc
->dev
->event_lock
);
367 if (drm_crtc_vblank_get(crtc
) == 0)
368 drm_crtc_arm_vblank_event(crtc
, event
);
370 drm_crtc_send_vblank_event(crtc
, event
);
371 spin_unlock_irq(&crtc
->dev
->event_lock
);
375 static void ingenic_drm_plane_atomic_update(struct drm_plane
*plane
,
376 struct drm_plane_state
*oldstate
)
378 struct ingenic_drm
*priv
= drm_plane_get_priv(plane
);
379 struct drm_plane_state
*state
= plane
->state
;
380 unsigned int width
, height
, cpp
;
383 if (state
&& state
->fb
) {
384 addr
= drm_fb_cma_get_gem_addr(state
->fb
, state
, 0);
385 width
= state
->src_w
>> 16;
386 height
= state
->src_h
>> 16;
387 cpp
= state
->fb
->format
->cpp
[plane
->index
];
389 priv
->dma_hwdesc
->addr
= addr
;
390 priv
->dma_hwdesc
->cmd
= width
* height
* cpp
/ 4;
391 priv
->dma_hwdesc
->cmd
|= JZ_LCD_CMD_EOF_IRQ
;
395 static void ingenic_drm_encoder_atomic_mode_set(struct drm_encoder
*encoder
,
396 struct drm_crtc_state
*crtc_state
,
397 struct drm_connector_state
*conn_state
)
399 struct ingenic_drm
*priv
= drm_encoder_get_priv(encoder
);
400 struct drm_display_mode
*mode
= &crtc_state
->adjusted_mode
;
401 struct drm_connector
*conn
= conn_state
->connector
;
402 struct drm_display_info
*info
= &conn
->display_info
;
405 priv
->panel_is_sharp
= info
->bus_flags
& DRM_BUS_FLAG_SHARP_SIGNALS
;
407 if (priv
->panel_is_sharp
) {
408 cfg
= JZ_LCD_CFG_MODE_SPECIAL_TFT_1
| JZ_LCD_CFG_REV_POLARITY
;
410 cfg
= JZ_LCD_CFG_PS_DISABLE
| JZ_LCD_CFG_CLS_DISABLE
411 | JZ_LCD_CFG_SPL_DISABLE
| JZ_LCD_CFG_REV_DISABLE
;
414 if (mode
->flags
& DRM_MODE_FLAG_NHSYNC
)
415 cfg
|= JZ_LCD_CFG_HSYNC_ACTIVE_LOW
;
416 if (mode
->flags
& DRM_MODE_FLAG_NVSYNC
)
417 cfg
|= JZ_LCD_CFG_VSYNC_ACTIVE_LOW
;
418 if (info
->bus_flags
& DRM_BUS_FLAG_DE_LOW
)
419 cfg
|= JZ_LCD_CFG_DE_ACTIVE_LOW
;
420 if (info
->bus_flags
& DRM_BUS_FLAG_PIXDATA_NEGEDGE
)
421 cfg
|= JZ_LCD_CFG_PCLK_FALLING_EDGE
;
423 if (!priv
->panel_is_sharp
) {
424 if (conn
->connector_type
== DRM_MODE_CONNECTOR_TV
) {
425 if (mode
->flags
& DRM_MODE_FLAG_INTERLACE
)
426 cfg
|= JZ_LCD_CFG_MODE_TV_OUT_I
;
428 cfg
|= JZ_LCD_CFG_MODE_TV_OUT_P
;
430 switch (*info
->bus_formats
) {
431 case MEDIA_BUS_FMT_RGB565_1X16
:
432 cfg
|= JZ_LCD_CFG_MODE_GENERIC_16BIT
;
434 case MEDIA_BUS_FMT_RGB666_1X18
:
435 cfg
|= JZ_LCD_CFG_MODE_GENERIC_18BIT
;
437 case MEDIA_BUS_FMT_RGB888_1X24
:
438 cfg
|= JZ_LCD_CFG_MODE_GENERIC_24BIT
;
440 case MEDIA_BUS_FMT_RGB888_3X8
:
441 cfg
|= JZ_LCD_CFG_MODE_8BIT_SERIAL
;
449 regmap_write(priv
->map
, JZ_REG_LCD_CFG
, cfg
);
452 static int ingenic_drm_encoder_atomic_check(struct drm_encoder
*encoder
,
453 struct drm_crtc_state
*crtc_state
,
454 struct drm_connector_state
*conn_state
)
456 struct drm_display_info
*info
= &conn_state
->connector
->display_info
;
458 if (info
->num_bus_formats
!= 1)
461 if (conn_state
->connector
->connector_type
== DRM_MODE_CONNECTOR_TV
)
464 switch (*info
->bus_formats
) {
465 case MEDIA_BUS_FMT_RGB565_1X16
:
466 case MEDIA_BUS_FMT_RGB666_1X18
:
467 case MEDIA_BUS_FMT_RGB888_1X24
:
468 case MEDIA_BUS_FMT_RGB888_3X8
:
475 static irqreturn_t
ingenic_drm_irq_handler(int irq
, void *arg
)
477 struct ingenic_drm
*priv
= arg
;
480 regmap_read(priv
->map
, JZ_REG_LCD_STATE
, &state
);
482 regmap_update_bits(priv
->map
, JZ_REG_LCD_STATE
,
483 JZ_LCD_STATE_EOF_IRQ
, 0);
485 if (state
& JZ_LCD_STATE_EOF_IRQ
)
486 drm_crtc_handle_vblank(&priv
->crtc
);
491 static void ingenic_drm_release(struct drm_device
*drm
)
493 struct ingenic_drm
*priv
= drm_device_get_priv(drm
);
495 drm_mode_config_cleanup(drm
);
500 static int ingenic_drm_enable_vblank(struct drm_crtc
*crtc
)
502 struct ingenic_drm
*priv
= drm_crtc_get_priv(crtc
);
504 regmap_update_bits(priv
->map
, JZ_REG_LCD_CTRL
,
505 JZ_LCD_CTRL_EOF_IRQ
, JZ_LCD_CTRL_EOF_IRQ
);
510 static void ingenic_drm_disable_vblank(struct drm_crtc
*crtc
)
512 struct ingenic_drm
*priv
= drm_crtc_get_priv(crtc
);
514 regmap_update_bits(priv
->map
, JZ_REG_LCD_CTRL
, JZ_LCD_CTRL_EOF_IRQ
, 0);
517 DEFINE_DRM_GEM_CMA_FOPS(ingenic_drm_fops
);
519 static struct drm_driver ingenic_drm_driver_data
= {
520 .driver_features
= DRIVER_MODESET
| DRIVER_GEM
| DRIVER_ATOMIC
,
521 .name
= "ingenic-drm",
522 .desc
= "DRM module for Ingenic SoCs",
528 .fops
= &ingenic_drm_fops
,
530 .dumb_create
= drm_gem_cma_dumb_create
,
531 .gem_free_object_unlocked
= drm_gem_cma_free_object
,
532 .gem_vm_ops
= &drm_gem_cma_vm_ops
,
534 .prime_handle_to_fd
= drm_gem_prime_handle_to_fd
,
535 .prime_fd_to_handle
= drm_gem_prime_fd_to_handle
,
536 .gem_prime_get_sg_table
= drm_gem_cma_prime_get_sg_table
,
537 .gem_prime_import_sg_table
= drm_gem_cma_prime_import_sg_table
,
538 .gem_prime_vmap
= drm_gem_cma_prime_vmap
,
539 .gem_prime_vunmap
= drm_gem_cma_prime_vunmap
,
540 .gem_prime_mmap
= drm_gem_cma_prime_mmap
,
542 .irq_handler
= ingenic_drm_irq_handler
,
543 .release
= ingenic_drm_release
,
546 static const struct drm_plane_funcs ingenic_drm_primary_plane_funcs
= {
547 .update_plane
= drm_atomic_helper_update_plane
,
548 .disable_plane
= drm_atomic_helper_disable_plane
,
549 .reset
= drm_atomic_helper_plane_reset
,
550 .destroy
= drm_plane_cleanup
,
552 .atomic_duplicate_state
= drm_atomic_helper_plane_duplicate_state
,
553 .atomic_destroy_state
= drm_atomic_helper_plane_destroy_state
,
556 static const struct drm_crtc_funcs ingenic_drm_crtc_funcs
= {
557 .set_config
= drm_atomic_helper_set_config
,
558 .page_flip
= drm_atomic_helper_page_flip
,
559 .reset
= drm_atomic_helper_crtc_reset
,
560 .destroy
= drm_crtc_cleanup
,
562 .atomic_duplicate_state
= drm_atomic_helper_crtc_duplicate_state
,
563 .atomic_destroy_state
= drm_atomic_helper_crtc_destroy_state
,
565 .enable_vblank
= ingenic_drm_enable_vblank
,
566 .disable_vblank
= ingenic_drm_disable_vblank
,
568 .gamma_set
= drm_atomic_helper_legacy_gamma_set
,
571 static const struct drm_plane_helper_funcs ingenic_drm_plane_helper_funcs
= {
572 .atomic_update
= ingenic_drm_plane_atomic_update
,
573 .prepare_fb
= drm_gem_fb_prepare_fb
,
576 static const struct drm_crtc_helper_funcs ingenic_drm_crtc_helper_funcs
= {
577 .atomic_enable
= ingenic_drm_crtc_atomic_enable
,
578 .atomic_disable
= ingenic_drm_crtc_atomic_disable
,
579 .atomic_flush
= ingenic_drm_crtc_atomic_flush
,
580 .atomic_check
= ingenic_drm_crtc_atomic_check
,
583 static const struct drm_encoder_helper_funcs ingenic_drm_encoder_helper_funcs
= {
584 .atomic_mode_set
= ingenic_drm_encoder_atomic_mode_set
,
585 .atomic_check
= ingenic_drm_encoder_atomic_check
,
588 static const struct drm_mode_config_funcs ingenic_drm_mode_config_funcs
= {
589 .fb_create
= drm_gem_fb_create
,
590 .output_poll_changed
= drm_fb_helper_output_poll_changed
,
591 .atomic_check
= drm_atomic_helper_check
,
592 .atomic_commit
= drm_atomic_helper_commit
,
595 static const struct drm_encoder_funcs ingenic_drm_encoder_funcs
= {
596 .destroy
= drm_encoder_cleanup
,
599 static void ingenic_drm_free_dma_hwdesc(void *d
)
601 struct ingenic_drm
*priv
= d
;
603 dma_free_coherent(priv
->dev
, sizeof(*priv
->dma_hwdesc
),
604 priv
->dma_hwdesc
, priv
->dma_hwdesc_phys
);
607 static int ingenic_drm_probe(struct platform_device
*pdev
)
609 const struct jz_soc_info
*soc_info
;
610 struct device
*dev
= &pdev
->dev
;
611 struct ingenic_drm
*priv
;
612 struct clk
*parent_clk
;
613 struct drm_bridge
*bridge
;
614 struct drm_panel
*panel
;
615 struct drm_device
*drm
;
620 soc_info
= of_device_get_match_data(dev
);
622 dev_err(dev
, "Missing platform data\n");
626 priv
= kzalloc(sizeof(*priv
), GFP_KERNEL
);
630 priv
->soc_info
= soc_info
;
633 drm
->dev_private
= priv
;
635 platform_set_drvdata(pdev
, priv
);
637 ret
= devm_drm_dev_init(dev
, drm
, &ingenic_drm_driver_data
);
643 drm_mode_config_init(drm
);
644 drm
->mode_config
.min_width
= 0;
645 drm
->mode_config
.min_height
= 0;
646 drm
->mode_config
.max_width
= soc_info
->max_width
;
647 drm
->mode_config
.max_height
= 4095;
648 drm
->mode_config
.funcs
= &ingenic_drm_mode_config_funcs
;
650 base
= devm_platform_ioremap_resource(pdev
, 0);
652 dev_err(dev
, "Failed to get memory resource");
653 return PTR_ERR(base
);
656 priv
->map
= devm_regmap_init_mmio(dev
, base
,
657 &ingenic_drm_regmap_config
);
658 if (IS_ERR(priv
->map
)) {
659 dev_err(dev
, "Failed to create regmap");
660 return PTR_ERR(priv
->map
);
663 irq
= platform_get_irq(pdev
, 0);
665 dev_err(dev
, "Failed to get platform irq");
669 if (soc_info
->needs_dev_clk
) {
670 priv
->lcd_clk
= devm_clk_get(dev
, "lcd");
671 if (IS_ERR(priv
->lcd_clk
)) {
672 dev_err(dev
, "Failed to get lcd clock");
673 return PTR_ERR(priv
->lcd_clk
);
677 priv
->pix_clk
= devm_clk_get(dev
, "lcd_pclk");
678 if (IS_ERR(priv
->pix_clk
)) {
679 dev_err(dev
, "Failed to get pixel clock");
680 return PTR_ERR(priv
->pix_clk
);
683 ret
= drm_of_find_panel_or_bridge(dev
->of_node
, 0, 0, &panel
, &bridge
);
685 if (ret
!= -EPROBE_DEFER
)
686 dev_err(dev
, "Failed to get panel handle");
691 bridge
= devm_drm_panel_bridge_add_typed(dev
, panel
,
692 DRM_MODE_CONNECTOR_DPI
);
694 priv
->dma_hwdesc
= dma_alloc_coherent(dev
, sizeof(*priv
->dma_hwdesc
),
695 &priv
->dma_hwdesc_phys
,
697 if (!priv
->dma_hwdesc
)
700 ret
= devm_add_action_or_reset(dev
, ingenic_drm_free_dma_hwdesc
, priv
);
704 priv
->dma_hwdesc
->next
= priv
->dma_hwdesc_phys
;
705 priv
->dma_hwdesc
->id
= 0xdeafbead;
707 drm_plane_helper_add(&priv
->primary
, &ingenic_drm_plane_helper_funcs
);
709 ret
= drm_universal_plane_init(drm
, &priv
->primary
,
710 0, &ingenic_drm_primary_plane_funcs
,
711 ingenic_drm_primary_formats
,
712 ARRAY_SIZE(ingenic_drm_primary_formats
),
713 NULL
, DRM_PLANE_TYPE_PRIMARY
, NULL
);
715 dev_err(dev
, "Failed to register primary plane: %i", ret
);
719 drm_crtc_helper_add(&priv
->crtc
, &ingenic_drm_crtc_helper_funcs
);
721 ret
= drm_crtc_init_with_planes(drm
, &priv
->crtc
, &priv
->primary
,
722 NULL
, &ingenic_drm_crtc_funcs
, NULL
);
724 dev_err(dev
, "Failed to init CRTC: %i", ret
);
728 priv
->encoder
.possible_crtcs
= 1;
730 drm_encoder_helper_add(&priv
->encoder
,
731 &ingenic_drm_encoder_helper_funcs
);
733 ret
= drm_encoder_init(drm
, &priv
->encoder
, &ingenic_drm_encoder_funcs
,
734 DRM_MODE_ENCODER_DPI
, NULL
);
736 dev_err(dev
, "Failed to init encoder: %i", ret
);
740 ret
= drm_bridge_attach(&priv
->encoder
, bridge
, NULL
, 0);
742 dev_err(dev
, "Unable to attach bridge");
746 ret
= drm_irq_install(drm
, irq
);
748 dev_err(dev
, "Unable to install IRQ handler");
752 ret
= drm_vblank_init(drm
, 1);
754 dev_err(dev
, "Failed calling drm_vblank_init()");
758 drm_mode_config_reset(drm
);
760 ret
= clk_prepare_enable(priv
->pix_clk
);
762 dev_err(dev
, "Unable to start pixel clock");
767 parent_clk
= clk_get_parent(priv
->lcd_clk
);
768 parent_rate
= clk_get_rate(parent_clk
);
770 /* LCD Device clock must be 3x the pixel clock for STN panels,
771 * or 1.5x the pixel clock for TFT panels. To avoid having to
772 * check for the LCD device clock everytime we do a mode change,
773 * we set the LCD device clock to the highest rate possible.
775 ret
= clk_set_rate(priv
->lcd_clk
, parent_rate
);
777 dev_err(dev
, "Unable to set LCD clock rate");
778 goto err_pixclk_disable
;
781 ret
= clk_prepare_enable(priv
->lcd_clk
);
783 dev_err(dev
, "Unable to start lcd clock");
784 goto err_pixclk_disable
;
788 ret
= drm_dev_register(drm
, 0);
790 dev_err(dev
, "Failed to register DRM driver");
791 goto err_devclk_disable
;
794 ret
= drm_fbdev_generic_setup(drm
, 32);
796 dev_warn(dev
, "Unable to start fbdev emulation: %i", ret
);
802 clk_disable_unprepare(priv
->lcd_clk
);
804 clk_disable_unprepare(priv
->pix_clk
);
808 static int ingenic_drm_remove(struct platform_device
*pdev
)
810 struct ingenic_drm
*priv
= platform_get_drvdata(pdev
);
813 clk_disable_unprepare(priv
->lcd_clk
);
814 clk_disable_unprepare(priv
->pix_clk
);
816 drm_dev_unregister(&priv
->drm
);
817 drm_atomic_helper_shutdown(&priv
->drm
);
822 static const struct jz_soc_info jz4740_soc_info
= {
823 .needs_dev_clk
= true,
828 static const struct jz_soc_info jz4725b_soc_info
= {
829 .needs_dev_clk
= false,
834 static const struct jz_soc_info jz4770_soc_info
= {
835 .needs_dev_clk
= false,
840 static const struct of_device_id ingenic_drm_of_match
[] = {
841 { .compatible
= "ingenic,jz4740-lcd", .data
= &jz4740_soc_info
},
842 { .compatible
= "ingenic,jz4725b-lcd", .data
= &jz4725b_soc_info
},
843 { .compatible
= "ingenic,jz4770-lcd", .data
= &jz4770_soc_info
},
846 MODULE_DEVICE_TABLE(of
, ingenic_drm_of_match
);
848 static struct platform_driver ingenic_drm_driver
= {
850 .name
= "ingenic-drm",
851 .of_match_table
= of_match_ptr(ingenic_drm_of_match
),
853 .probe
= ingenic_drm_probe
,
854 .remove
= ingenic_drm_remove
,
856 module_platform_driver(ingenic_drm_driver
);
858 MODULE_AUTHOR("Paul Cercueil <paul@crapouillou.net>");
859 MODULE_DESCRIPTION("DRM driver for the Ingenic SoCs\n");
860 MODULE_LICENSE("GPL v2");