2 * vsp1_wpf.c -- R-Car VSP1 Write Pixel Formatter
4 * Copyright (C) 2013 Renesas Corporation
6 * Contact: 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.
14 #include <linux/device.h>
16 #include <media/v4l2-subdev.h>
19 #include "vsp1_rwpf.h"
20 #include "vsp1_video.h"
22 #define WPF_MAX_WIDTH 2048
23 #define WPF_MAX_HEIGHT 2048
25 /* -----------------------------------------------------------------------------
29 static inline u32
vsp1_wpf_read(struct vsp1_rwpf
*wpf
, u32 reg
)
31 return vsp1_read(wpf
->entity
.vsp1
,
32 reg
+ wpf
->entity
.index
* VI6_WPF_OFFSET
);
35 static inline void vsp1_wpf_write(struct vsp1_rwpf
*wpf
, u32 reg
, u32 data
)
37 vsp1_write(wpf
->entity
.vsp1
,
38 reg
+ wpf
->entity
.index
* VI6_WPF_OFFSET
, data
);
41 /* -----------------------------------------------------------------------------
42 * V4L2 Subdevice Core Operations
45 static int wpf_s_stream(struct v4l2_subdev
*subdev
, int enable
)
47 struct vsp1_rwpf
*wpf
= to_rwpf(subdev
);
48 struct vsp1_pipeline
*pipe
=
49 to_vsp1_pipeline(&wpf
->entity
.subdev
.entity
);
50 struct vsp1_device
*vsp1
= wpf
->entity
.vsp1
;
51 const struct v4l2_mbus_framefmt
*format
=
52 &wpf
->entity
.formats
[RWPF_PAD_SOURCE
];
58 vsp1_write(vsp1
, VI6_WPF_IRQ_ENB(wpf
->entity
.index
), 0);
63 for (i
= 0; i
< pipe
->num_inputs
; ++i
) {
64 struct vsp1_rwpf
*input
= pipe
->inputs
[i
];
66 srcrpf
|= VI6_WPF_SRCRPF_RPF_ACT_MST(input
->entity
.index
);
69 vsp1_wpf_write(wpf
, VI6_WPF_SRCRPF
, srcrpf
);
71 /* Destination stride. Cropping isn't supported yet. */
73 struct v4l2_pix_format_mplane
*format
= &wpf
->video
.format
;
75 vsp1_wpf_write(wpf
, VI6_WPF_DSTM_STRIDE_Y
,
76 format
->plane_fmt
[0].bytesperline
);
77 if (format
->num_planes
> 1)
78 vsp1_wpf_write(wpf
, VI6_WPF_DSTM_STRIDE_C
,
79 format
->plane_fmt
[1].bytesperline
);
82 vsp1_wpf_write(wpf
, VI6_WPF_HSZCLIP
,
83 format
->width
<< VI6_WPF_SZCLIP_SIZE_SHIFT
);
84 vsp1_wpf_write(wpf
, VI6_WPF_VSZCLIP
,
85 format
->height
<< VI6_WPF_SZCLIP_SIZE_SHIFT
);
89 const struct vsp1_format_info
*fmtinfo
= wpf
->video
.fmtinfo
;
91 outfmt
= fmtinfo
->hwfmt
<< VI6_WPF_OUTFMT_WRFMT_SHIFT
;
94 outfmt
|= VI6_WPF_OUTFMT_SPYCS
;
96 outfmt
|= VI6_WPF_OUTFMT_SPUVS
;
98 vsp1_wpf_write(wpf
, VI6_WPF_DSWAP
, fmtinfo
->swap
);
101 if (wpf
->entity
.formats
[RWPF_PAD_SINK
].code
!=
102 wpf
->entity
.formats
[RWPF_PAD_SOURCE
].code
)
103 outfmt
|= VI6_WPF_OUTFMT_CSC
;
105 vsp1_wpf_write(wpf
, VI6_WPF_OUTFMT
, outfmt
);
107 vsp1_write(vsp1
, VI6_DPR_WPF_FPORCH(wpf
->entity
.index
),
108 VI6_DPR_WPF_FPORCH_FP_WPFN
);
110 vsp1_write(vsp1
, VI6_WPF_WRBCK_CTRL
, 0);
112 /* Enable interrupts */
113 vsp1_write(vsp1
, VI6_WPF_IRQ_STA(wpf
->entity
.index
), 0);
114 vsp1_write(vsp1
, VI6_WPF_IRQ_ENB(wpf
->entity
.index
),
115 VI6_WFP_IRQ_ENB_FREE
);
120 /* -----------------------------------------------------------------------------
121 * V4L2 Subdevice Operations
124 static struct v4l2_subdev_video_ops wpf_video_ops
= {
125 .s_stream
= wpf_s_stream
,
128 static struct v4l2_subdev_pad_ops wpf_pad_ops
= {
129 .enum_mbus_code
= vsp1_rwpf_enum_mbus_code
,
130 .enum_frame_size
= vsp1_rwpf_enum_frame_size
,
131 .get_fmt
= vsp1_rwpf_get_format
,
132 .set_fmt
= vsp1_rwpf_set_format
,
135 static struct v4l2_subdev_ops wpf_ops
= {
136 .video
= &wpf_video_ops
,
140 /* -----------------------------------------------------------------------------
141 * Video Device Operations
144 static void wpf_vdev_queue(struct vsp1_video
*video
,
145 struct vsp1_video_buffer
*buf
)
147 struct vsp1_rwpf
*wpf
= container_of(video
, struct vsp1_rwpf
, video
);
149 vsp1_wpf_write(wpf
, VI6_WPF_DSTM_ADDR_Y
, buf
->addr
[0]);
150 if (buf
->buf
.num_planes
> 1)
151 vsp1_wpf_write(wpf
, VI6_WPF_DSTM_ADDR_C0
, buf
->addr
[1]);
152 if (buf
->buf
.num_planes
> 2)
153 vsp1_wpf_write(wpf
, VI6_WPF_DSTM_ADDR_C1
, buf
->addr
[2]);
156 static const struct vsp1_video_operations wpf_vdev_ops
= {
157 .queue
= wpf_vdev_queue
,
160 /* -----------------------------------------------------------------------------
161 * Initialization and Cleanup
164 struct vsp1_rwpf
*vsp1_wpf_create(struct vsp1_device
*vsp1
, unsigned int index
)
166 struct v4l2_subdev
*subdev
;
167 struct vsp1_video
*video
;
168 struct vsp1_rwpf
*wpf
;
172 wpf
= devm_kzalloc(vsp1
->dev
, sizeof(*wpf
), GFP_KERNEL
);
174 return ERR_PTR(-ENOMEM
);
176 wpf
->max_width
= WPF_MAX_WIDTH
;
177 wpf
->max_height
= WPF_MAX_HEIGHT
;
179 wpf
->entity
.type
= VSP1_ENTITY_WPF
;
180 wpf
->entity
.index
= index
;
181 wpf
->entity
.id
= VI6_DPR_NODE_WPF(index
);
183 ret
= vsp1_entity_init(vsp1
, &wpf
->entity
, 2);
187 /* Initialize the V4L2 subdev. */
188 subdev
= &wpf
->entity
.subdev
;
189 v4l2_subdev_init(subdev
, &wpf_ops
);
191 subdev
->entity
.ops
= &vsp1_media_ops
;
192 subdev
->internal_ops
= &vsp1_subdev_internal_ops
;
193 snprintf(subdev
->name
, sizeof(subdev
->name
), "%s wpf.%u",
194 dev_name(vsp1
->dev
), index
);
195 v4l2_set_subdevdata(subdev
, wpf
);
196 subdev
->flags
|= V4L2_SUBDEV_FL_HAS_DEVNODE
;
198 vsp1_entity_init_formats(subdev
, NULL
);
200 /* Initialize the video device. */
203 video
->type
= V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE
;
205 video
->ops
= &wpf_vdev_ops
;
207 ret
= vsp1_video_init(video
, &wpf
->entity
);
211 /* Connect the video device to the WPF. All connections are immutable
212 * except for the WPF0 source link if a LIF is present.
214 flags
= MEDIA_LNK_FL_ENABLED
;
215 if (!(vsp1
->pdata
->features
& VSP1_HAS_LIF
) || index
!= 0)
216 flags
|= MEDIA_LNK_FL_IMMUTABLE
;
218 ret
= media_entity_create_link(&wpf
->entity
.subdev
.entity
,
220 &wpf
->video
.video
.entity
, 0, flags
);
224 wpf
->entity
.sink
= &wpf
->video
.video
.entity
;
229 vsp1_video_cleanup(video
);
231 media_entity_cleanup(&wpf
->entity
.subdev
.entity
);