2 * vsp1_rpf.c -- R-Car VSP1 Read Pixel Formatter
4 * Copyright (C) 2013-2014 Renesas Electronics 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>
20 #include "vsp1_rwpf.h"
21 #include "vsp1_video.h"
23 #define RPF_MAX_WIDTH 8190
24 #define RPF_MAX_HEIGHT 8190
26 /* -----------------------------------------------------------------------------
30 static inline void vsp1_rpf_write(struct vsp1_rwpf
*rpf
,
31 struct vsp1_dl_list
*dl
, u32 reg
, u32 data
)
33 vsp1_dl_list_write(dl
, reg
+ rpf
->entity
.index
* VI6_RPF_OFFSET
, data
);
36 /* -----------------------------------------------------------------------------
37 * V4L2 Subdevice Operations
40 static struct v4l2_subdev_ops rpf_ops
= {
41 .pad
= &vsp1_rwpf_pad_ops
,
44 /* -----------------------------------------------------------------------------
45 * VSP1 Entity Operations
48 static void rpf_set_memory(struct vsp1_entity
*entity
, struct vsp1_dl_list
*dl
)
50 struct vsp1_rwpf
*rpf
= entity_to_rwpf(entity
);
52 vsp1_rpf_write(rpf
, dl
, VI6_RPF_SRCM_ADDR_Y
,
53 rpf
->mem
.addr
[0] + rpf
->offsets
[0]);
54 vsp1_rpf_write(rpf
, dl
, VI6_RPF_SRCM_ADDR_C0
,
55 rpf
->mem
.addr
[1] + rpf
->offsets
[1]);
56 vsp1_rpf_write(rpf
, dl
, VI6_RPF_SRCM_ADDR_C1
,
57 rpf
->mem
.addr
[2] + rpf
->offsets
[1]);
60 static void rpf_configure(struct vsp1_entity
*entity
,
61 struct vsp1_pipeline
*pipe
,
62 struct vsp1_dl_list
*dl
)
64 struct vsp1_rwpf
*rpf
= to_rwpf(&entity
->subdev
);
65 const struct vsp1_format_info
*fmtinfo
= rpf
->fmtinfo
;
66 const struct v4l2_pix_format_mplane
*format
= &rpf
->format
;
67 const struct v4l2_mbus_framefmt
*source_format
;
68 const struct v4l2_mbus_framefmt
*sink_format
;
69 const struct v4l2_rect
*crop
;
70 unsigned int left
= 0;
75 /* Source size, stride and crop offsets.
77 * The crop offsets correspond to the location of the crop rectangle top
78 * left corner in the plane buffer. Only two offsets are needed, as
79 * planes 2 and 3 always have identical strides.
81 crop
= vsp1_rwpf_get_crop(rpf
, rpf
->entity
.config
);
83 vsp1_rpf_write(rpf
, dl
, VI6_RPF_SRC_BSIZE
,
84 (crop
->width
<< VI6_RPF_SRC_BSIZE_BHSIZE_SHIFT
) |
85 (crop
->height
<< VI6_RPF_SRC_BSIZE_BVSIZE_SHIFT
));
86 vsp1_rpf_write(rpf
, dl
, VI6_RPF_SRC_ESIZE
,
87 (crop
->width
<< VI6_RPF_SRC_ESIZE_EHSIZE_SHIFT
) |
88 (crop
->height
<< VI6_RPF_SRC_ESIZE_EVSIZE_SHIFT
));
90 rpf
->offsets
[0] = crop
->top
* format
->plane_fmt
[0].bytesperline
91 + crop
->left
* fmtinfo
->bpp
[0] / 8;
92 pstride
= format
->plane_fmt
[0].bytesperline
93 << VI6_RPF_SRCM_PSTRIDE_Y_SHIFT
;
95 if (format
->num_planes
> 1) {
96 rpf
->offsets
[1] = crop
->top
* format
->plane_fmt
[1].bytesperline
97 + crop
->left
* fmtinfo
->bpp
[1] / 8;
98 pstride
|= format
->plane_fmt
[1].bytesperline
99 << VI6_RPF_SRCM_PSTRIDE_C_SHIFT
;
104 vsp1_rpf_write(rpf
, dl
, VI6_RPF_SRCM_PSTRIDE
, pstride
);
107 sink_format
= vsp1_entity_get_pad_format(&rpf
->entity
,
110 source_format
= vsp1_entity_get_pad_format(&rpf
->entity
,
114 infmt
= VI6_RPF_INFMT_CIPM
115 | (fmtinfo
->hwfmt
<< VI6_RPF_INFMT_RDFMT_SHIFT
);
117 if (fmtinfo
->swap_yc
)
118 infmt
|= VI6_RPF_INFMT_SPYCS
;
119 if (fmtinfo
->swap_uv
)
120 infmt
|= VI6_RPF_INFMT_SPUVS
;
122 if (sink_format
->code
!= source_format
->code
)
123 infmt
|= VI6_RPF_INFMT_CSC
;
125 vsp1_rpf_write(rpf
, dl
, VI6_RPF_INFMT
, infmt
);
126 vsp1_rpf_write(rpf
, dl
, VI6_RPF_DSWAP
, fmtinfo
->swap
);
128 /* Output location */
130 const struct v4l2_rect
*compose
;
132 compose
= vsp1_entity_get_pad_compose(pipe
->bru
,
135 left
= compose
->left
;
139 vsp1_rpf_write(rpf
, dl
, VI6_RPF_LOC
,
140 (left
<< VI6_RPF_LOC_HCOORD_SHIFT
) |
141 (top
<< VI6_RPF_LOC_VCOORD_SHIFT
));
143 /* Use the alpha channel (extended to 8 bits) when available or an
144 * alpha value set through the V4L2_CID_ALPHA_COMPONENT control
145 * otherwise. Disable color keying.
147 vsp1_rpf_write(rpf
, dl
, VI6_RPF_ALPH_SEL
, VI6_RPF_ALPH_SEL_AEXT_EXT
|
148 (fmtinfo
->alpha
? VI6_RPF_ALPH_SEL_ASEL_PACKED
149 : VI6_RPF_ALPH_SEL_ASEL_FIXED
));
151 vsp1_rpf_write(rpf
, dl
, VI6_RPF_VRTCOL_SET
,
152 rpf
->alpha
<< VI6_RPF_VRTCOL_SET_LAYA_SHIFT
);
154 vsp1_pipeline_propagate_alpha(pipe
, &rpf
->entity
, dl
, rpf
->alpha
);
156 vsp1_rpf_write(rpf
, dl
, VI6_RPF_MSK_CTRL
, 0);
157 vsp1_rpf_write(rpf
, dl
, VI6_RPF_CKEY_CTRL
, 0);
160 static const struct vsp1_entity_operations rpf_entity_ops
= {
161 .set_memory
= rpf_set_memory
,
162 .configure
= rpf_configure
,
165 /* -----------------------------------------------------------------------------
166 * Initialization and Cleanup
169 struct vsp1_rwpf
*vsp1_rpf_create(struct vsp1_device
*vsp1
, unsigned int index
)
171 struct vsp1_rwpf
*rpf
;
175 rpf
= devm_kzalloc(vsp1
->dev
, sizeof(*rpf
), GFP_KERNEL
);
177 return ERR_PTR(-ENOMEM
);
179 rpf
->max_width
= RPF_MAX_WIDTH
;
180 rpf
->max_height
= RPF_MAX_HEIGHT
;
182 rpf
->entity
.ops
= &rpf_entity_ops
;
183 rpf
->entity
.type
= VSP1_ENTITY_RPF
;
184 rpf
->entity
.index
= index
;
186 sprintf(name
, "rpf.%u", index
);
187 ret
= vsp1_entity_init(vsp1
, &rpf
->entity
, name
, 2, &rpf_ops
);
191 /* Initialize the control handler. */
192 ret
= vsp1_rwpf_init_ctrls(rpf
);
194 dev_err(vsp1
->dev
, "rpf%u: failed to initialize controls\n",
202 vsp1_entity_destroy(&rpf
->entity
);