2 * shmob_drm_plane.c -- SH Mobile DRM Planes
4 * Copyright (C) 2012 Renesas Electronics Corporation
6 * Laurent Pinchart (laurent.pinchart@ideasonboard.com)
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
15 #include <drm/drm_crtc.h>
16 #include <drm/drm_crtc_helper.h>
17 #include <drm/drm_fb_cma_helper.h>
18 #include <drm/drm_gem_cma_helper.h>
20 #include <video/sh_mobile_meram.h>
22 #include "shmob_drm_drv.h"
23 #include "shmob_drm_kms.h"
24 #include "shmob_drm_plane.h"
25 #include "shmob_drm_regs.h"
27 struct shmob_drm_plane
{
28 struct drm_plane plane
;
32 const struct shmob_drm_format_info
*format
;
43 #define to_shmob_plane(p) container_of(p, struct shmob_drm_plane, plane)
45 static void shmob_drm_plane_compute_base(struct shmob_drm_plane
*splane
,
46 struct drm_framebuffer
*fb
,
49 struct drm_gem_cma_object
*gem
;
52 bpp
= splane
->format
->yuv
? 8 : splane
->format
->bpp
;
53 gem
= drm_fb_cma_get_gem_obj(fb
, 0);
54 splane
->dma
[0] = gem
->paddr
+ fb
->offsets
[0]
55 + y
* fb
->pitches
[0] + x
* bpp
/ 8;
57 if (splane
->format
->yuv
) {
58 bpp
= splane
->format
->bpp
- 8;
59 gem
= drm_fb_cma_get_gem_obj(fb
, 1);
60 splane
->dma
[1] = gem
->paddr
+ fb
->offsets
[1]
61 + y
/ (bpp
== 4 ? 2 : 1) * fb
->pitches
[1]
62 + x
* (bpp
== 16 ? 2 : 1);
66 static void __shmob_drm_plane_setup(struct shmob_drm_plane
*splane
,
67 struct drm_framebuffer
*fb
)
69 struct shmob_drm_device
*sdev
= splane
->plane
.dev
->dev_private
;
72 /* TODO: Support ROP3 mode */
73 format
= LDBBSIFR_EN
| (splane
->alpha
<< LDBBSIFR_LAY_SHIFT
);
75 switch (splane
->format
->fourcc
) {
76 case DRM_FORMAT_RGB565
:
80 format
|= LDBBSIFR_SWPL
| LDBBSIFR_SWPW
;
82 case DRM_FORMAT_RGB888
:
86 format
|= LDBBSIFR_SWPL
| LDBBSIFR_SWPW
| LDBBSIFR_SWPB
;
88 case DRM_FORMAT_ARGB8888
:
90 format
|= LDBBSIFR_SWPL
;
94 switch (splane
->format
->fourcc
) {
95 case DRM_FORMAT_RGB565
:
96 format
|= LDBBSIFR_AL_1
| LDBBSIFR_RY
| LDBBSIFR_RPKF_RGB16
;
98 case DRM_FORMAT_RGB888
:
99 format
|= LDBBSIFR_AL_1
| LDBBSIFR_RY
| LDBBSIFR_RPKF_RGB24
;
101 case DRM_FORMAT_ARGB8888
:
102 format
|= LDBBSIFR_AL_PK
| LDBBSIFR_RY
| LDDFR_PKF_ARGB32
;
104 case DRM_FORMAT_NV12
:
105 case DRM_FORMAT_NV21
:
106 format
|= LDBBSIFR_AL_1
| LDBBSIFR_CHRR_420
;
108 case DRM_FORMAT_NV16
:
109 case DRM_FORMAT_NV61
:
110 format
|= LDBBSIFR_AL_1
| LDBBSIFR_CHRR_422
;
112 case DRM_FORMAT_NV24
:
113 case DRM_FORMAT_NV42
:
114 format
|= LDBBSIFR_AL_1
| LDBBSIFR_CHRR_444
;
118 #define plane_reg_dump(sdev, splane, reg) \
119 dev_dbg(sdev->ddev->dev, "%s(%u): %s 0x%08x 0x%08x\n", __func__, \
120 splane->index, #reg, \
121 lcdc_read(sdev, reg(splane->index)), \
122 lcdc_read(sdev, reg(splane->index) + LCDC_SIDE_B_OFFSET))
124 plane_reg_dump(sdev
, splane
, LDBnBSIFR
);
125 plane_reg_dump(sdev
, splane
, LDBnBSSZR
);
126 plane_reg_dump(sdev
, splane
, LDBnBLOCR
);
127 plane_reg_dump(sdev
, splane
, LDBnBSMWR
);
128 plane_reg_dump(sdev
, splane
, LDBnBSAYR
);
129 plane_reg_dump(sdev
, splane
, LDBnBSACR
);
131 lcdc_write(sdev
, LDBCR
, LDBCR_UPC(splane
->index
));
132 dev_dbg(sdev
->ddev
->dev
, "%s(%u): %s 0x%08x\n", __func__
, splane
->index
,
133 "LDBCR", lcdc_read(sdev
, LDBCR
));
135 lcdc_write(sdev
, LDBnBSIFR(splane
->index
), format
);
137 lcdc_write(sdev
, LDBnBSSZR(splane
->index
),
138 (splane
->crtc_h
<< LDBBSSZR_BVSS_SHIFT
) |
139 (splane
->crtc_w
<< LDBBSSZR_BHSS_SHIFT
));
140 lcdc_write(sdev
, LDBnBLOCR(splane
->index
),
141 (splane
->crtc_y
<< LDBBLOCR_CVLC_SHIFT
) |
142 (splane
->crtc_x
<< LDBBLOCR_CHLC_SHIFT
));
143 lcdc_write(sdev
, LDBnBSMWR(splane
->index
),
144 fb
->pitches
[0] << LDBBSMWR_BSMW_SHIFT
);
146 shmob_drm_plane_compute_base(splane
, fb
, splane
->src_x
, splane
->src_y
);
148 lcdc_write(sdev
, LDBnBSAYR(splane
->index
), splane
->dma
[0]);
149 if (splane
->format
->yuv
)
150 lcdc_write(sdev
, LDBnBSACR(splane
->index
), splane
->dma
[1]);
152 lcdc_write(sdev
, LDBCR
,
153 LDBCR_UPF(splane
->index
) | LDBCR_UPD(splane
->index
));
154 dev_dbg(sdev
->ddev
->dev
, "%s(%u): %s 0x%08x\n", __func__
, splane
->index
,
155 "LDBCR", lcdc_read(sdev
, LDBCR
));
157 plane_reg_dump(sdev
, splane
, LDBnBSIFR
);
158 plane_reg_dump(sdev
, splane
, LDBnBSSZR
);
159 plane_reg_dump(sdev
, splane
, LDBnBLOCR
);
160 plane_reg_dump(sdev
, splane
, LDBnBSMWR
);
161 plane_reg_dump(sdev
, splane
, LDBnBSAYR
);
162 plane_reg_dump(sdev
, splane
, LDBnBSACR
);
165 void shmob_drm_plane_setup(struct drm_plane
*plane
)
167 struct shmob_drm_plane
*splane
= to_shmob_plane(plane
);
169 if (plane
->fb
== NULL
)
172 __shmob_drm_plane_setup(splane
, plane
->fb
);
176 shmob_drm_plane_update(struct drm_plane
*plane
, struct drm_crtc
*crtc
,
177 struct drm_framebuffer
*fb
, int crtc_x
, int crtc_y
,
178 unsigned int crtc_w
, unsigned int crtc_h
,
179 uint32_t src_x
, uint32_t src_y
,
180 uint32_t src_w
, uint32_t src_h
)
182 struct shmob_drm_plane
*splane
= to_shmob_plane(plane
);
183 struct shmob_drm_device
*sdev
= plane
->dev
->dev_private
;
184 const struct shmob_drm_format_info
*format
;
186 format
= shmob_drm_format_info(fb
->pixel_format
);
187 if (format
== NULL
) {
188 dev_dbg(sdev
->dev
, "update_plane: unsupported format %08x\n",
193 if (src_w
>> 16 != crtc_w
|| src_h
>> 16 != crtc_h
) {
194 dev_dbg(sdev
->dev
, "%s: scaling not supported\n", __func__
);
198 splane
->format
= format
;
200 splane
->src_x
= src_x
>> 16;
201 splane
->src_y
= src_y
>> 16;
202 splane
->crtc_x
= crtc_x
;
203 splane
->crtc_y
= crtc_y
;
204 splane
->crtc_w
= crtc_w
;
205 splane
->crtc_h
= crtc_h
;
207 __shmob_drm_plane_setup(splane
, fb
);
211 static int shmob_drm_plane_disable(struct drm_plane
*plane
)
213 struct shmob_drm_plane
*splane
= to_shmob_plane(plane
);
214 struct shmob_drm_device
*sdev
= plane
->dev
->dev_private
;
216 splane
->format
= NULL
;
218 lcdc_write(sdev
, LDBnBSIFR(splane
->index
), 0);
222 static void shmob_drm_plane_destroy(struct drm_plane
*plane
)
224 shmob_drm_plane_disable(plane
);
225 drm_plane_cleanup(plane
);
228 static const struct drm_plane_funcs shmob_drm_plane_funcs
= {
229 .update_plane
= shmob_drm_plane_update
,
230 .disable_plane
= shmob_drm_plane_disable
,
231 .destroy
= shmob_drm_plane_destroy
,
234 static const uint32_t formats
[] = {
246 int shmob_drm_plane_create(struct shmob_drm_device
*sdev
, unsigned int index
)
248 struct shmob_drm_plane
*splane
;
251 splane
= devm_kzalloc(sdev
->dev
, sizeof(*splane
), GFP_KERNEL
);
255 splane
->index
= index
;
258 ret
= drm_plane_init(sdev
->ddev
, &splane
->plane
, 1,
259 &shmob_drm_plane_funcs
, formats
,
260 ARRAY_SIZE(formats
), false);