1 // SPDX-License-Identifier: GPL-2.0+
3 * shmob_drm_plane.c -- SH Mobile DRM Planes
5 * Copyright (C) 2012 Renesas Electronics Corporation
7 * Laurent Pinchart (laurent.pinchart@ideasonboard.com)
10 #include <drm/drm_crtc.h>
11 #include <drm/drm_crtc_helper.h>
12 #include <drm/drm_fb_cma_helper.h>
13 #include <drm/drm_fourcc.h>
14 #include <drm/drm_gem_cma_helper.h>
16 #include "shmob_drm_drv.h"
17 #include "shmob_drm_kms.h"
18 #include "shmob_drm_plane.h"
19 #include "shmob_drm_regs.h"
21 struct shmob_drm_plane
{
22 struct drm_plane plane
;
26 const struct shmob_drm_format_info
*format
;
37 #define to_shmob_plane(p) container_of(p, struct shmob_drm_plane, plane)
39 static void shmob_drm_plane_compute_base(struct shmob_drm_plane
*splane
,
40 struct drm_framebuffer
*fb
,
43 struct drm_gem_cma_object
*gem
;
46 bpp
= splane
->format
->yuv
? 8 : splane
->format
->bpp
;
47 gem
= drm_fb_cma_get_gem_obj(fb
, 0);
48 splane
->dma
[0] = gem
->paddr
+ fb
->offsets
[0]
49 + y
* fb
->pitches
[0] + x
* bpp
/ 8;
51 if (splane
->format
->yuv
) {
52 bpp
= splane
->format
->bpp
- 8;
53 gem
= drm_fb_cma_get_gem_obj(fb
, 1);
54 splane
->dma
[1] = gem
->paddr
+ fb
->offsets
[1]
55 + y
/ (bpp
== 4 ? 2 : 1) * fb
->pitches
[1]
56 + x
* (bpp
== 16 ? 2 : 1);
60 static void __shmob_drm_plane_setup(struct shmob_drm_plane
*splane
,
61 struct drm_framebuffer
*fb
)
63 struct shmob_drm_device
*sdev
= splane
->plane
.dev
->dev_private
;
66 /* TODO: Support ROP3 mode */
67 format
= LDBBSIFR_EN
| (splane
->alpha
<< LDBBSIFR_LAY_SHIFT
);
69 switch (splane
->format
->fourcc
) {
70 case DRM_FORMAT_RGB565
:
74 format
|= LDBBSIFR_SWPL
| LDBBSIFR_SWPW
;
76 case DRM_FORMAT_RGB888
:
80 format
|= LDBBSIFR_SWPL
| LDBBSIFR_SWPW
| LDBBSIFR_SWPB
;
82 case DRM_FORMAT_ARGB8888
:
84 format
|= LDBBSIFR_SWPL
;
88 switch (splane
->format
->fourcc
) {
89 case DRM_FORMAT_RGB565
:
90 format
|= LDBBSIFR_AL_1
| LDBBSIFR_RY
| LDBBSIFR_RPKF_RGB16
;
92 case DRM_FORMAT_RGB888
:
93 format
|= LDBBSIFR_AL_1
| LDBBSIFR_RY
| LDBBSIFR_RPKF_RGB24
;
95 case DRM_FORMAT_ARGB8888
:
96 format
|= LDBBSIFR_AL_PK
| LDBBSIFR_RY
| LDDFR_PKF_ARGB32
;
100 format
|= LDBBSIFR_AL_1
| LDBBSIFR_CHRR_420
;
102 case DRM_FORMAT_NV16
:
103 case DRM_FORMAT_NV61
:
104 format
|= LDBBSIFR_AL_1
| LDBBSIFR_CHRR_422
;
106 case DRM_FORMAT_NV24
:
107 case DRM_FORMAT_NV42
:
108 format
|= LDBBSIFR_AL_1
| LDBBSIFR_CHRR_444
;
112 #define plane_reg_dump(sdev, splane, reg) \
113 dev_dbg(sdev->ddev->dev, "%s(%u): %s 0x%08x 0x%08x\n", __func__, \
114 splane->index, #reg, \
115 lcdc_read(sdev, reg(splane->index)), \
116 lcdc_read(sdev, reg(splane->index) + LCDC_SIDE_B_OFFSET))
118 plane_reg_dump(sdev
, splane
, LDBnBSIFR
);
119 plane_reg_dump(sdev
, splane
, LDBnBSSZR
);
120 plane_reg_dump(sdev
, splane
, LDBnBLOCR
);
121 plane_reg_dump(sdev
, splane
, LDBnBSMWR
);
122 plane_reg_dump(sdev
, splane
, LDBnBSAYR
);
123 plane_reg_dump(sdev
, splane
, LDBnBSACR
);
125 lcdc_write(sdev
, LDBCR
, LDBCR_UPC(splane
->index
));
126 dev_dbg(sdev
->ddev
->dev
, "%s(%u): %s 0x%08x\n", __func__
, splane
->index
,
127 "LDBCR", lcdc_read(sdev
, LDBCR
));
129 lcdc_write(sdev
, LDBnBSIFR(splane
->index
), format
);
131 lcdc_write(sdev
, LDBnBSSZR(splane
->index
),
132 (splane
->crtc_h
<< LDBBSSZR_BVSS_SHIFT
) |
133 (splane
->crtc_w
<< LDBBSSZR_BHSS_SHIFT
));
134 lcdc_write(sdev
, LDBnBLOCR(splane
->index
),
135 (splane
->crtc_y
<< LDBBLOCR_CVLC_SHIFT
) |
136 (splane
->crtc_x
<< LDBBLOCR_CHLC_SHIFT
));
137 lcdc_write(sdev
, LDBnBSMWR(splane
->index
),
138 fb
->pitches
[0] << LDBBSMWR_BSMW_SHIFT
);
140 shmob_drm_plane_compute_base(splane
, fb
, splane
->src_x
, splane
->src_y
);
142 lcdc_write(sdev
, LDBnBSAYR(splane
->index
), splane
->dma
[0]);
143 if (splane
->format
->yuv
)
144 lcdc_write(sdev
, LDBnBSACR(splane
->index
), splane
->dma
[1]);
146 lcdc_write(sdev
, LDBCR
,
147 LDBCR_UPF(splane
->index
) | LDBCR_UPD(splane
->index
));
148 dev_dbg(sdev
->ddev
->dev
, "%s(%u): %s 0x%08x\n", __func__
, splane
->index
,
149 "LDBCR", lcdc_read(sdev
, LDBCR
));
151 plane_reg_dump(sdev
, splane
, LDBnBSIFR
);
152 plane_reg_dump(sdev
, splane
, LDBnBSSZR
);
153 plane_reg_dump(sdev
, splane
, LDBnBLOCR
);
154 plane_reg_dump(sdev
, splane
, LDBnBSMWR
);
155 plane_reg_dump(sdev
, splane
, LDBnBSAYR
);
156 plane_reg_dump(sdev
, splane
, LDBnBSACR
);
159 void shmob_drm_plane_setup(struct drm_plane
*plane
)
161 struct shmob_drm_plane
*splane
= to_shmob_plane(plane
);
163 if (plane
->fb
== NULL
)
166 __shmob_drm_plane_setup(splane
, plane
->fb
);
170 shmob_drm_plane_update(struct drm_plane
*plane
, struct drm_crtc
*crtc
,
171 struct drm_framebuffer
*fb
, int crtc_x
, int crtc_y
,
172 unsigned int crtc_w
, unsigned int crtc_h
,
173 uint32_t src_x
, uint32_t src_y
,
174 uint32_t src_w
, uint32_t src_h
,
175 struct drm_modeset_acquire_ctx
*ctx
)
177 struct shmob_drm_plane
*splane
= to_shmob_plane(plane
);
178 struct shmob_drm_device
*sdev
= plane
->dev
->dev_private
;
179 const struct shmob_drm_format_info
*format
;
181 format
= shmob_drm_format_info(fb
->format
->format
);
182 if (format
== NULL
) {
183 dev_dbg(sdev
->dev
, "update_plane: unsupported format %08x\n",
188 if (src_w
>> 16 != crtc_w
|| src_h
>> 16 != crtc_h
) {
189 dev_dbg(sdev
->dev
, "%s: scaling not supported\n", __func__
);
193 splane
->format
= format
;
195 splane
->src_x
= src_x
>> 16;
196 splane
->src_y
= src_y
>> 16;
197 splane
->crtc_x
= crtc_x
;
198 splane
->crtc_y
= crtc_y
;
199 splane
->crtc_w
= crtc_w
;
200 splane
->crtc_h
= crtc_h
;
202 __shmob_drm_plane_setup(splane
, fb
);
206 static int shmob_drm_plane_disable(struct drm_plane
*plane
,
207 struct drm_modeset_acquire_ctx
*ctx
)
209 struct shmob_drm_plane
*splane
= to_shmob_plane(plane
);
210 struct shmob_drm_device
*sdev
= plane
->dev
->dev_private
;
212 splane
->format
= NULL
;
214 lcdc_write(sdev
, LDBnBSIFR(splane
->index
), 0);
218 static void shmob_drm_plane_destroy(struct drm_plane
*plane
)
220 drm_plane_force_disable(plane
);
221 drm_plane_cleanup(plane
);
224 static const struct drm_plane_funcs shmob_drm_plane_funcs
= {
225 .update_plane
= shmob_drm_plane_update
,
226 .disable_plane
= shmob_drm_plane_disable
,
227 .destroy
= shmob_drm_plane_destroy
,
230 static const uint32_t formats
[] = {
242 int shmob_drm_plane_create(struct shmob_drm_device
*sdev
, unsigned int index
)
244 struct shmob_drm_plane
*splane
;
247 splane
= devm_kzalloc(sdev
->dev
, sizeof(*splane
), GFP_KERNEL
);
251 splane
->index
= index
;
254 ret
= drm_plane_init(sdev
->ddev
, &splane
->plane
, 1,
255 &shmob_drm_plane_funcs
, formats
,
256 ARRAY_SIZE(formats
), false);