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_rect
*crop
= &wpf
->crop
;
57 vsp1_write(vsp1
, VI6_WPF_IRQ_ENB(wpf
->entity
.index
), 0);
62 for (i
= 0; i
< pipe
->num_inputs
; ++i
) {
63 struct vsp1_rwpf
*input
= pipe
->inputs
[i
];
65 srcrpf
|= VI6_WPF_SRCRPF_RPF_ACT_MST(input
->entity
.index
);
68 vsp1_wpf_write(wpf
, VI6_WPF_SRCRPF
, srcrpf
);
70 /* Destination stride. */
72 struct v4l2_pix_format_mplane
*format
= &wpf
->video
.format
;
74 vsp1_wpf_write(wpf
, VI6_WPF_DSTM_STRIDE_Y
,
75 format
->plane_fmt
[0].bytesperline
);
76 if (format
->num_planes
> 1)
77 vsp1_wpf_write(wpf
, VI6_WPF_DSTM_STRIDE_C
,
78 format
->plane_fmt
[1].bytesperline
);
81 vsp1_wpf_write(wpf
, VI6_WPF_HSZCLIP
, VI6_WPF_SZCLIP_EN
|
82 (crop
->left
<< VI6_WPF_SZCLIP_OFST_SHIFT
) |
83 (crop
->width
<< VI6_WPF_SZCLIP_SIZE_SHIFT
));
84 vsp1_wpf_write(wpf
, VI6_WPF_VSZCLIP
, VI6_WPF_SZCLIP_EN
|
85 (crop
->top
<< VI6_WPF_SZCLIP_OFST_SHIFT
) |
86 (crop
->height
<< VI6_WPF_SZCLIP_SIZE_SHIFT
));
90 const struct vsp1_format_info
*fmtinfo
= wpf
->video
.fmtinfo
;
92 outfmt
= fmtinfo
->hwfmt
<< VI6_WPF_OUTFMT_WRFMT_SHIFT
;
95 outfmt
|= VI6_WPF_OUTFMT_SPYCS
;
97 outfmt
|= VI6_WPF_OUTFMT_SPUVS
;
99 vsp1_wpf_write(wpf
, VI6_WPF_DSWAP
, fmtinfo
->swap
);
102 if (wpf
->entity
.formats
[RWPF_PAD_SINK
].code
!=
103 wpf
->entity
.formats
[RWPF_PAD_SOURCE
].code
)
104 outfmt
|= VI6_WPF_OUTFMT_CSC
;
106 vsp1_wpf_write(wpf
, VI6_WPF_OUTFMT
, outfmt
);
108 vsp1_write(vsp1
, VI6_DPR_WPF_FPORCH(wpf
->entity
.index
),
109 VI6_DPR_WPF_FPORCH_FP_WPFN
);
111 vsp1_write(vsp1
, VI6_WPF_WRBCK_CTRL
, 0);
113 /* Enable interrupts */
114 vsp1_write(vsp1
, VI6_WPF_IRQ_STA(wpf
->entity
.index
), 0);
115 vsp1_write(vsp1
, VI6_WPF_IRQ_ENB(wpf
->entity
.index
),
116 VI6_WFP_IRQ_ENB_FREE
);
121 /* -----------------------------------------------------------------------------
122 * V4L2 Subdevice Operations
125 static struct v4l2_subdev_video_ops wpf_video_ops
= {
126 .s_stream
= wpf_s_stream
,
129 static struct v4l2_subdev_pad_ops wpf_pad_ops
= {
130 .enum_mbus_code
= vsp1_rwpf_enum_mbus_code
,
131 .enum_frame_size
= vsp1_rwpf_enum_frame_size
,
132 .get_fmt
= vsp1_rwpf_get_format
,
133 .set_fmt
= vsp1_rwpf_set_format
,
134 .get_selection
= vsp1_rwpf_get_selection
,
135 .set_selection
= vsp1_rwpf_set_selection
,
138 static struct v4l2_subdev_ops wpf_ops
= {
139 .video
= &wpf_video_ops
,
143 /* -----------------------------------------------------------------------------
144 * Video Device Operations
147 static void wpf_vdev_queue(struct vsp1_video
*video
,
148 struct vsp1_video_buffer
*buf
)
150 struct vsp1_rwpf
*wpf
= container_of(video
, struct vsp1_rwpf
, video
);
152 vsp1_wpf_write(wpf
, VI6_WPF_DSTM_ADDR_Y
, buf
->addr
[0]);
153 if (buf
->buf
.num_planes
> 1)
154 vsp1_wpf_write(wpf
, VI6_WPF_DSTM_ADDR_C0
, buf
->addr
[1]);
155 if (buf
->buf
.num_planes
> 2)
156 vsp1_wpf_write(wpf
, VI6_WPF_DSTM_ADDR_C1
, buf
->addr
[2]);
159 static const struct vsp1_video_operations wpf_vdev_ops
= {
160 .queue
= wpf_vdev_queue
,
163 /* -----------------------------------------------------------------------------
164 * Initialization and Cleanup
167 struct vsp1_rwpf
*vsp1_wpf_create(struct vsp1_device
*vsp1
, unsigned int index
)
169 struct v4l2_subdev
*subdev
;
170 struct vsp1_video
*video
;
171 struct vsp1_rwpf
*wpf
;
175 wpf
= devm_kzalloc(vsp1
->dev
, sizeof(*wpf
), GFP_KERNEL
);
177 return ERR_PTR(-ENOMEM
);
179 wpf
->max_width
= WPF_MAX_WIDTH
;
180 wpf
->max_height
= WPF_MAX_HEIGHT
;
182 wpf
->entity
.type
= VSP1_ENTITY_WPF
;
183 wpf
->entity
.index
= index
;
184 wpf
->entity
.id
= VI6_DPR_NODE_WPF(index
);
186 ret
= vsp1_entity_init(vsp1
, &wpf
->entity
, 2);
190 /* Initialize the V4L2 subdev. */
191 subdev
= &wpf
->entity
.subdev
;
192 v4l2_subdev_init(subdev
, &wpf_ops
);
194 subdev
->entity
.ops
= &vsp1_media_ops
;
195 subdev
->internal_ops
= &vsp1_subdev_internal_ops
;
196 snprintf(subdev
->name
, sizeof(subdev
->name
), "%s wpf.%u",
197 dev_name(vsp1
->dev
), index
);
198 v4l2_set_subdevdata(subdev
, wpf
);
199 subdev
->flags
|= V4L2_SUBDEV_FL_HAS_DEVNODE
;
201 vsp1_entity_init_formats(subdev
, NULL
);
203 /* Initialize the video device. */
206 video
->type
= V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE
;
208 video
->ops
= &wpf_vdev_ops
;
210 ret
= vsp1_video_init(video
, &wpf
->entity
);
214 /* Connect the video device to the WPF. All connections are immutable
215 * except for the WPF0 source link if a LIF is present.
217 flags
= MEDIA_LNK_FL_ENABLED
;
218 if (!(vsp1
->pdata
->features
& VSP1_HAS_LIF
) || index
!= 0)
219 flags
|= MEDIA_LNK_FL_IMMUTABLE
;
221 ret
= media_entity_create_link(&wpf
->entity
.subdev
.entity
,
223 &wpf
->video
.video
.entity
, 0, flags
);
227 wpf
->entity
.sink
= &wpf
->video
.video
.entity
;
232 vsp1_video_cleanup(video
);
234 media_entity_cleanup(&wpf
->entity
.subdev
.entity
);