Skip to content

Commit b8d181e

Browse files
pH5gregkh
authored andcommitted
staging: drm/imx: add drm plane support
This patch adds support for a drm overlay plane on DI0 using the DP. In principle, the overlay plane could also be used on DI1, but to switch the overlay plane between display interfaces, the base planes would have to be exchanged transparently while both display interfaces are inactive. Signed-off-by: Philipp Zabel <[email protected]> Signed-off-by: Greg Kroah-Hartman <[email protected]>
1 parent 6ee4d7f commit b8d181e

File tree

8 files changed

+484
-156
lines changed

8 files changed

+484
-156
lines changed

drivers/staging/imx-drm/Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,4 +8,4 @@ obj-$(CONFIG_DRM_IMX_TVE) += imx-tve.o
88
obj-$(CONFIG_DRM_IMX_LDB) += imx-ldb.o
99
obj-$(CONFIG_DRM_IMX_FB_HELPER) += imx-fbdev.o
1010
obj-$(CONFIG_DRM_IMX_IPUV3_CORE) += ipu-v3/
11-
obj-$(CONFIG_DRM_IMX_IPUV3) += ipuv3-crtc.o
11+
obj-$(CONFIG_DRM_IMX_IPUV3) += ipuv3-crtc.o ipuv3-plane.o

drivers/staging/imx-drm/TODO

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@ TODO:
99

1010
Missing features (not necessarily for moving out of staging):
1111

12-
- Add KMS plane support for CRTC driver
1312
- Add i.MX6 HDMI support
1413
- Add support for IC (Image converter)
1514
- Add support for CSI (CMOS Sensor interface)

drivers/staging/imx-drm/imx-drm-core.c

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,11 @@ struct imx_drm_connector {
6868
struct module *owner;
6969
};
7070

71+
int imx_drm_crtc_id(struct imx_drm_crtc *crtc)
72+
{
73+
return crtc->pipe;
74+
}
75+
7176
static void imx_drm_driver_lastclose(struct drm_device *drm)
7277
{
7378
struct imx_drm_device *imxdrm = drm->dev_private;

drivers/staging/imx-drm/imx-drm.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@ struct drm_fbdev_cma;
1414
struct drm_framebuffer;
1515
struct platform_device;
1616

17+
int imx_drm_crtc_id(struct imx_drm_crtc *crtc);
18+
1719
struct imx_drm_crtc_helper_funcs {
1820
int (*enable_vblank)(struct drm_crtc *crtc);
1921
void (*disable_vblank)(struct drm_crtc *crtc);

drivers/staging/imx-drm/ipu-v3/ipu-common.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -981,7 +981,7 @@ static const struct ipu_platform_reg client_reg[] = {
981981
.dc = 5,
982982
.dp = IPU_DP_FLOW_SYNC_BG,
983983
.dma[0] = IPUV3_CHANNEL_MEM_BG_SYNC,
984-
.dma[1] = -EINVAL,
984+
.dma[1] = IPUV3_CHANNEL_MEM_FG_SYNC,
985985
},
986986
.name = "imx-ipuv3-crtc",
987987
}, {

drivers/staging/imx-drm/ipuv3-crtc.c

Lines changed: 45 additions & 153 deletions
Original file line numberDiff line numberDiff line change
@@ -25,22 +25,25 @@
2525
#include <drm/drm_crtc_helper.h>
2626
#include <linux/fb.h>
2727
#include <linux/clk.h>
28+
#include <linux/errno.h>
2829
#include <drm/drm_gem_cma_helper.h>
2930
#include <drm/drm_fb_cma_helper.h>
3031

3132
#include "ipu-v3/imx-ipu-v3.h"
3233
#include "imx-drm.h"
34+
#include "ipuv3-plane.h"
3335

3436
#define DRIVER_DESC "i.MX IPUv3 Graphics"
3537

3638
struct ipu_crtc {
3739
struct device *dev;
3840
struct drm_crtc base;
3941
struct imx_drm_crtc *imx_crtc;
40-
struct ipuv3_channel *ipu_ch;
42+
43+
/* plane[0] is the full plane, plane[1] is the partial plane */
44+
struct ipu_plane *plane[2];
45+
4146
struct ipu_dc *dc;
42-
struct ipu_dp *dp;
43-
struct dmfc_channel *dmfc;
4447
struct ipu_di *di;
4548
int enabled;
4649
struct drm_pending_vblank_event *page_flip_event;
@@ -54,35 +57,14 @@ struct ipu_crtc {
5457

5558
#define to_ipu_crtc(x) container_of(x, struct ipu_crtc, base)
5659

57-
static int calc_vref(struct drm_display_mode *mode)
58-
{
59-
unsigned long htotal, vtotal;
60-
61-
htotal = mode->htotal;
62-
vtotal = mode->vtotal;
63-
64-
if (!htotal || !vtotal)
65-
return 60;
66-
67-
return mode->clock * 1000 / vtotal / htotal;
68-
}
69-
70-
static int calc_bandwidth(struct drm_display_mode *mode, unsigned int vref)
71-
{
72-
return mode->hdisplay * mode->vdisplay * vref;
73-
}
74-
7560
static void ipu_fb_enable(struct ipu_crtc *ipu_crtc)
7661
{
7762
if (ipu_crtc->enabled)
7863
return;
7964

8065
ipu_di_enable(ipu_crtc->di);
81-
ipu_dmfc_enable_channel(ipu_crtc->dmfc);
82-
ipu_idmac_enable_channel(ipu_crtc->ipu_ch);
8366
ipu_dc_enable_channel(ipu_crtc->dc);
84-
if (ipu_crtc->dp)
85-
ipu_dp_enable_channel(ipu_crtc->dp);
67+
ipu_plane_enable(ipu_crtc->plane[0]);
8668

8769
ipu_crtc->enabled = 1;
8870
}
@@ -92,12 +74,8 @@ static void ipu_fb_disable(struct ipu_crtc *ipu_crtc)
9274
if (!ipu_crtc->enabled)
9375
return;
9476

95-
if (ipu_crtc->dp)
96-
ipu_dp_disable_channel(ipu_crtc->dp);
77+
ipu_plane_disable(ipu_crtc->plane[0]);
9778
ipu_dc_disable_channel(ipu_crtc->dc);
98-
ipu_idmac_wait_busy(ipu_crtc->ipu_ch, 50);
99-
ipu_idmac_disable_channel(ipu_crtc->ipu_ch);
100-
ipu_dmfc_disable_channel(ipu_crtc->dmfc);
10179
ipu_di_disable(ipu_crtc->di);
10280

10381
ipu_crtc->enabled = 0;
@@ -153,79 +131,22 @@ static const struct drm_crtc_funcs ipu_crtc_funcs = {
153131
.page_flip = ipu_page_flip,
154132
};
155133

156-
static int ipu_drm_set_base(struct drm_crtc *crtc, int x, int y)
157-
{
158-
struct ipu_crtc *ipu_crtc = to_ipu_crtc(crtc);
159-
struct drm_gem_cma_object *cma_obj;
160-
struct drm_framebuffer *fb = crtc->fb;
161-
unsigned long phys;
162-
163-
cma_obj = drm_fb_cma_get_gem_obj(fb, 0);
164-
if (!cma_obj) {
165-
DRM_LOG_KMS("entry is null.\n");
166-
return -EFAULT;
167-
}
168-
169-
phys = cma_obj->paddr;
170-
phys += x * (fb->bits_per_pixel >> 3);
171-
phys += y * fb->pitches[0];
172-
173-
dev_dbg(ipu_crtc->dev, "%s: phys: 0x%lx\n", __func__, phys);
174-
dev_dbg(ipu_crtc->dev, "%s: xy: %dx%d\n", __func__, x, y);
175-
176-
ipu_cpmem_set_stride(ipu_get_cpmem(ipu_crtc->ipu_ch), fb->pitches[0]);
177-
ipu_cpmem_set_buffer(ipu_get_cpmem(ipu_crtc->ipu_ch),
178-
0, phys);
179-
180-
return 0;
181-
}
182-
183134
static int ipu_crtc_mode_set(struct drm_crtc *crtc,
184135
struct drm_display_mode *orig_mode,
185136
struct drm_display_mode *mode,
186137
int x, int y,
187138
struct drm_framebuffer *old_fb)
188139
{
189140
struct ipu_crtc *ipu_crtc = to_ipu_crtc(crtc);
190-
struct drm_framebuffer *fb = ipu_crtc->base.fb;
191141
int ret;
192142
struct ipu_di_signal_cfg sig_cfg = {};
193143
u32 out_pixel_fmt;
194-
struct ipu_ch_param __iomem *cpmem = ipu_get_cpmem(ipu_crtc->ipu_ch);
195-
int bpp;
196-
u32 v4l2_fmt;
197144

198145
dev_dbg(ipu_crtc->dev, "%s: mode->hdisplay: %d\n", __func__,
199146
mode->hdisplay);
200147
dev_dbg(ipu_crtc->dev, "%s: mode->vdisplay: %d\n", __func__,
201148
mode->vdisplay);
202149

203-
ipu_ch_param_zero(cpmem);
204-
205-
switch (fb->pixel_format) {
206-
case DRM_FORMAT_XRGB8888:
207-
case DRM_FORMAT_ARGB8888:
208-
v4l2_fmt = V4L2_PIX_FMT_RGB32;
209-
bpp = 32;
210-
break;
211-
case DRM_FORMAT_RGB565:
212-
v4l2_fmt = V4L2_PIX_FMT_RGB565;
213-
bpp = 16;
214-
break;
215-
case DRM_FORMAT_RGB888:
216-
v4l2_fmt = V4L2_PIX_FMT_RGB24;
217-
bpp = 24;
218-
break;
219-
case DRM_FORMAT_BGR888:
220-
v4l2_fmt = V4L2_PIX_FMT_BGR24;
221-
bpp = 24;
222-
break;
223-
default:
224-
dev_err(ipu_crtc->dev, "unsupported pixel format 0x%08x\n",
225-
fb->pixel_format);
226-
return -EINVAL;
227-
}
228-
229150
out_pixel_fmt = ipu_crtc->interface_pix_fmt;
230151

231152
if (mode->flags & DRM_MODE_FLAG_INTERLACE)
@@ -255,18 +176,6 @@ static int ipu_crtc_mode_set(struct drm_crtc *crtc,
255176
sig_cfg.hsync_pin = ipu_crtc->di_hsync_pin;
256177
sig_cfg.vsync_pin = ipu_crtc->di_vsync_pin;
257178

258-
if (ipu_crtc->dp) {
259-
ret = ipu_dp_setup_channel(ipu_crtc->dp, IPUV3_COLORSPACE_RGB,
260-
IPUV3_COLORSPACE_RGB);
261-
if (ret) {
262-
dev_err(ipu_crtc->dev,
263-
"initializing display processor failed with %d\n",
264-
ret);
265-
return ret;
266-
}
267-
ipu_dp_set_global_alpha(ipu_crtc->dp, 1, 0, 1);
268-
}
269-
270179
ret = ipu_dc_init_sync(ipu_crtc->dc, ipu_crtc->di, sig_cfg.interlaced,
271180
out_pixel_fmt, mode->hdisplay);
272181
if (ret) {
@@ -283,30 +192,9 @@ static int ipu_crtc_mode_set(struct drm_crtc *crtc,
283192
return ret;
284193
}
285194

286-
ipu_cpmem_set_resolution(cpmem, mode->hdisplay, mode->vdisplay);
287-
ipu_cpmem_set_fmt(cpmem, v4l2_fmt);
288-
ipu_cpmem_set_high_priority(ipu_crtc->ipu_ch);
289-
290-
ret = ipu_dmfc_init_channel(ipu_crtc->dmfc, mode->hdisplay);
291-
if (ret) {
292-
dev_err(ipu_crtc->dev,
293-
"initializing dmfc channel failed with %d\n",
294-
ret);
295-
return ret;
296-
}
297-
298-
ret = ipu_dmfc_alloc_bandwidth(ipu_crtc->dmfc,
299-
calc_bandwidth(mode, calc_vref(mode)), 64);
300-
if (ret) {
301-
dev_err(ipu_crtc->dev,
302-
"allocating dmfc bandwidth failed with %d\n",
303-
ret);
304-
return ret;
305-
}
306-
307-
ipu_drm_set_base(crtc, x, y);
308-
309-
return 0;
195+
return ipu_plane_mode_set(ipu_crtc->plane[0], crtc, mode, crtc->fb,
196+
0, 0, mode->hdisplay, mode->vdisplay,
197+
x, y, mode->hdisplay, mode->vdisplay);
310198
}
311199

312200
static void ipu_crtc_handle_pageflip(struct ipu_crtc *ipu_crtc)
@@ -330,7 +218,7 @@ static irqreturn_t ipu_irq_handler(int irq, void *dev_id)
330218

331219
if (ipu_crtc->newfb) {
332220
ipu_crtc->newfb = NULL;
333-
ipu_drm_set_base(&ipu_crtc->base, 0, 0);
221+
ipu_plane_set_base(ipu_crtc->plane[0], ipu_crtc->base.fb, 0, 0);
334222
ipu_crtc_handle_pageflip(ipu_crtc);
335223
}
336224

@@ -413,12 +301,8 @@ static const struct imx_drm_crtc_helper_funcs ipu_crtc_helper_funcs = {
413301

414302
static void ipu_put_resources(struct ipu_crtc *ipu_crtc)
415303
{
416-
if (!IS_ERR_OR_NULL(ipu_crtc->ipu_ch))
417-
ipu_idmac_put(ipu_crtc->ipu_ch);
418-
if (!IS_ERR_OR_NULL(ipu_crtc->dmfc))
419-
ipu_dmfc_put(ipu_crtc->dmfc);
420-
if (!IS_ERR_OR_NULL(ipu_crtc->dp))
421-
ipu_dp_put(ipu_crtc->dp);
304+
if (!IS_ERR_OR_NULL(ipu_crtc->dc))
305+
ipu_dc_put(ipu_crtc->dc);
422306
if (!IS_ERR_OR_NULL(ipu_crtc->di))
423307
ipu_di_put(ipu_crtc->di);
424308
}
@@ -429,32 +313,12 @@ static int ipu_get_resources(struct ipu_crtc *ipu_crtc,
429313
struct ipu_soc *ipu = dev_get_drvdata(ipu_crtc->dev->parent);
430314
int ret;
431315

432-
ipu_crtc->ipu_ch = ipu_idmac_get(ipu, pdata->dma[0]);
433-
if (IS_ERR(ipu_crtc->ipu_ch)) {
434-
ret = PTR_ERR(ipu_crtc->ipu_ch);
435-
goto err_out;
436-
}
437-
438316
ipu_crtc->dc = ipu_dc_get(ipu, pdata->dc);
439317
if (IS_ERR(ipu_crtc->dc)) {
440318
ret = PTR_ERR(ipu_crtc->dc);
441319
goto err_out;
442320
}
443321

444-
ipu_crtc->dmfc = ipu_dmfc_get(ipu, pdata->dma[0]);
445-
if (IS_ERR(ipu_crtc->dmfc)) {
446-
ret = PTR_ERR(ipu_crtc->dmfc);
447-
goto err_out;
448-
}
449-
450-
if (pdata->dp >= 0) {
451-
ipu_crtc->dp = ipu_dp_get(ipu, pdata->dp);
452-
if (IS_ERR(ipu_crtc->dp)) {
453-
ret = PTR_ERR(ipu_crtc->dp);
454-
goto err_out;
455-
}
456-
}
457-
458322
ipu_crtc->di = ipu_di_get(ipu, pdata->di);
459323
if (IS_ERR(ipu_crtc->di)) {
460324
ret = PTR_ERR(ipu_crtc->di);
@@ -472,7 +336,9 @@ static int ipu_crtc_init(struct ipu_crtc *ipu_crtc,
472336
struct ipu_client_platformdata *pdata)
473337
{
474338
struct ipu_soc *ipu = dev_get_drvdata(ipu_crtc->dev->parent);
339+
int dp = -EINVAL;
475340
int ret;
341+
int id;
476342

477343
ret = ipu_get_resources(ipu_crtc, pdata);
478344
if (ret) {
@@ -490,17 +356,42 @@ static int ipu_crtc_init(struct ipu_crtc *ipu_crtc,
490356
goto err_put_resources;
491357
}
492358

493-
ipu_crtc->irq = ipu_idmac_channel_irq(ipu, ipu_crtc->ipu_ch,
494-
IPU_IRQ_EOF);
359+
if (pdata->dp >= 0)
360+
dp = IPU_DP_FLOW_SYNC_BG;
361+
id = imx_drm_crtc_id(ipu_crtc->imx_crtc);
362+
ipu_crtc->plane[0] = ipu_plane_init(ipu_crtc->base.dev, ipu,
363+
pdata->dma[0], dp, BIT(id), true);
364+
ret = ipu_plane_get_resources(ipu_crtc->plane[0]);
365+
if (ret) {
366+
dev_err(ipu_crtc->dev, "getting plane 0 resources failed with %d.\n",
367+
ret);
368+
goto err_remove_crtc;
369+
}
370+
371+
/* If this crtc is using the DP, add an overlay plane */
372+
if (pdata->dp >= 0 && pdata->dma[1] > 0) {
373+
ipu_crtc->plane[1] = ipu_plane_init(ipu_crtc->base.dev, ipu,
374+
pdata->dma[1],
375+
IPU_DP_FLOW_SYNC_FG,
376+
BIT(id), false);
377+
if (IS_ERR(ipu_crtc->plane[1]))
378+
ipu_crtc->plane[1] = NULL;
379+
}
380+
381+
ipu_crtc->irq = ipu_plane_irq(ipu_crtc->plane[0]);
495382
ret = devm_request_irq(ipu_crtc->dev, ipu_crtc->irq, ipu_irq_handler, 0,
496383
"imx_drm", ipu_crtc);
497384
if (ret < 0) {
498385
dev_err(ipu_crtc->dev, "irq request failed with %d.\n", ret);
499-
goto err_put_resources;
386+
goto err_put_plane_res;
500387
}
501388

502389
return 0;
503390

391+
err_put_plane_res:
392+
ipu_plane_put_resources(ipu_crtc->plane[0]);
393+
err_remove_crtc:
394+
imx_drm_remove_crtc(ipu_crtc->imx_crtc);
504395
err_put_resources:
505396
ipu_put_resources(ipu_crtc);
506397

@@ -539,6 +430,7 @@ static int ipu_drm_remove(struct platform_device *pdev)
539430

540431
imx_drm_remove_crtc(ipu_crtc->imx_crtc);
541432

433+
ipu_plane_put_resources(ipu_crtc->plane[0]);
542434
ipu_put_resources(ipu_crtc);
543435

544436
return 0;

0 commit comments

Comments
 (0)