2 * vsp1_rpf.c -- R-Car VSP1 Read 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 RPF_MAX_WIDTH 8190
23 #define RPF_MAX_HEIGHT 8190
25 /* -----------------------------------------------------------------------------
29 static inline u32
vsp1_rpf_read(struct vsp1_rwpf
*rpf
, u32 reg
)
31 return vsp1_read(rpf
->entity
.vsp1
,
32 reg
+ rpf
->entity
.index
* VI6_RPF_OFFSET
);
35 static inline void vsp1_rpf_write(struct vsp1_rwpf
*rpf
, u32 reg
, u32 data
)
37 vsp1_write(rpf
->entity
.vsp1
,
38 reg
+ rpf
->entity
.index
* VI6_RPF_OFFSET
, data
);
41 /* -----------------------------------------------------------------------------
42 * V4L2 Subdevice Core Operations
45 static int rpf_s_stream(struct v4l2_subdev
*subdev
, int enable
)
47 struct vsp1_rwpf
*rpf
= to_rwpf(subdev
);
48 const struct vsp1_format_info
*fmtinfo
= rpf
->video
.fmtinfo
;
49 const struct v4l2_pix_format_mplane
*format
= &rpf
->video
.format
;
56 /* Source size and stride. Cropping isn't supported yet. */
57 vsp1_rpf_write(rpf
, VI6_RPF_SRC_BSIZE
,
58 (format
->width
<< VI6_RPF_SRC_BSIZE_BHSIZE_SHIFT
) |
59 (format
->height
<< VI6_RPF_SRC_BSIZE_BVSIZE_SHIFT
));
60 vsp1_rpf_write(rpf
, VI6_RPF_SRC_ESIZE
,
61 (format
->width
<< VI6_RPF_SRC_ESIZE_EHSIZE_SHIFT
) |
62 (format
->height
<< VI6_RPF_SRC_ESIZE_EVSIZE_SHIFT
));
64 pstride
= format
->plane_fmt
[0].bytesperline
65 << VI6_RPF_SRCM_PSTRIDE_Y_SHIFT
;
66 if (format
->num_planes
> 1)
67 pstride
|= format
->plane_fmt
[1].bytesperline
68 << VI6_RPF_SRCM_PSTRIDE_C_SHIFT
;
70 vsp1_rpf_write(rpf
, VI6_RPF_SRCM_PSTRIDE
, pstride
);
73 infmt
= VI6_RPF_INFMT_CIPM
74 | (fmtinfo
->hwfmt
<< VI6_RPF_INFMT_RDFMT_SHIFT
);
77 infmt
|= VI6_RPF_INFMT_SPYCS
;
79 infmt
|= VI6_RPF_INFMT_SPUVS
;
81 if (rpf
->entity
.formats
[RWPF_PAD_SINK
].code
!=
82 rpf
->entity
.formats
[RWPF_PAD_SOURCE
].code
)
83 infmt
|= VI6_RPF_INFMT_CSC
;
85 vsp1_rpf_write(rpf
, VI6_RPF_INFMT
, infmt
);
86 vsp1_rpf_write(rpf
, VI6_RPF_DSWAP
, fmtinfo
->swap
);
88 /* Output location. Composing isn't supported yet. */
89 vsp1_rpf_write(rpf
, VI6_RPF_LOC
, 0);
91 /* Disable alpha, mask and color key. Set the alpha channel to a fixed
94 vsp1_rpf_write(rpf
, VI6_RPF_ALPH_SEL
, VI6_RPF_ALPH_SEL_ASEL_FIXED
);
95 vsp1_rpf_write(rpf
, VI6_RPF_VRTCOL_SET
,
96 255 << VI6_RPF_VRTCOL_SET_LAYA_SHIFT
);
97 vsp1_rpf_write(rpf
, VI6_RPF_MSK_CTRL
, 0);
98 vsp1_rpf_write(rpf
, VI6_RPF_CKEY_CTRL
, 0);
103 /* -----------------------------------------------------------------------------
104 * V4L2 Subdevice Operations
107 static struct v4l2_subdev_video_ops rpf_video_ops
= {
108 .s_stream
= rpf_s_stream
,
111 static struct v4l2_subdev_pad_ops rpf_pad_ops
= {
112 .enum_mbus_code
= vsp1_rwpf_enum_mbus_code
,
113 .enum_frame_size
= vsp1_rwpf_enum_frame_size
,
114 .get_fmt
= vsp1_rwpf_get_format
,
115 .set_fmt
= vsp1_rwpf_set_format
,
118 static struct v4l2_subdev_ops rpf_ops
= {
119 .video
= &rpf_video_ops
,
123 /* -----------------------------------------------------------------------------
124 * Video Device Operations
127 static void rpf_vdev_queue(struct vsp1_video
*video
,
128 struct vsp1_video_buffer
*buf
)
130 struct vsp1_rwpf
*rpf
= container_of(video
, struct vsp1_rwpf
, video
);
132 vsp1_rpf_write(rpf
, VI6_RPF_SRCM_ADDR_Y
, buf
->addr
[0]);
133 if (buf
->buf
.num_planes
> 1)
134 vsp1_rpf_write(rpf
, VI6_RPF_SRCM_ADDR_C0
, buf
->addr
[1]);
135 if (buf
->buf
.num_planes
> 2)
136 vsp1_rpf_write(rpf
, VI6_RPF_SRCM_ADDR_C1
, buf
->addr
[2]);
139 static const struct vsp1_video_operations rpf_vdev_ops
= {
140 .queue
= rpf_vdev_queue
,
143 /* -----------------------------------------------------------------------------
144 * Initialization and Cleanup
147 struct vsp1_rwpf
*vsp1_rpf_create(struct vsp1_device
*vsp1
, unsigned int index
)
149 struct v4l2_subdev
*subdev
;
150 struct vsp1_video
*video
;
151 struct vsp1_rwpf
*rpf
;
154 rpf
= devm_kzalloc(vsp1
->dev
, sizeof(*rpf
), GFP_KERNEL
);
156 return ERR_PTR(-ENOMEM
);
158 rpf
->max_width
= RPF_MAX_WIDTH
;
159 rpf
->max_height
= RPF_MAX_HEIGHT
;
161 rpf
->entity
.type
= VSP1_ENTITY_RPF
;
162 rpf
->entity
.index
= index
;
163 rpf
->entity
.id
= VI6_DPR_NODE_RPF(index
);
165 ret
= vsp1_entity_init(vsp1
, &rpf
->entity
, 2);
169 /* Initialize the V4L2 subdev. */
170 subdev
= &rpf
->entity
.subdev
;
171 v4l2_subdev_init(subdev
, &rpf_ops
);
173 subdev
->entity
.ops
= &vsp1_media_ops
;
174 subdev
->internal_ops
= &vsp1_subdev_internal_ops
;
175 snprintf(subdev
->name
, sizeof(subdev
->name
), "%s rpf.%u",
176 dev_name(vsp1
->dev
), index
);
177 v4l2_set_subdevdata(subdev
, rpf
);
178 subdev
->flags
|= V4L2_SUBDEV_FL_HAS_DEVNODE
;
180 vsp1_entity_init_formats(subdev
, NULL
);
182 /* Initialize the video device. */
185 video
->type
= V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE
;
187 video
->ops
= &rpf_vdev_ops
;
189 ret
= vsp1_video_init(video
, &rpf
->entity
);
193 /* Connect the video device to the RPF. */
194 ret
= media_entity_create_link(&rpf
->video
.video
.entity
, 0,
195 &rpf
->entity
.subdev
.entity
,
197 MEDIA_LNK_FL_ENABLED
|
198 MEDIA_LNK_FL_IMMUTABLE
);
205 vsp1_video_cleanup(video
);
207 media_entity_cleanup(&rpf
->entity
.subdev
.entity
);