1 // SPDX-License-Identifier: GPL-2.0+
3 * vsp1_lif.c -- R-Car VSP1 LCD Controller Interface
5 * Copyright (C) 2013-2014 Renesas Electronics Corporation
7 * Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com)
10 #include <linux/device.h>
11 #include <linux/gfp.h>
13 #include <media/v4l2-subdev.h>
19 #define LIF_MIN_SIZE 2U
20 #define LIF_MAX_SIZE 8190U
22 /* -----------------------------------------------------------------------------
26 static inline void vsp1_lif_write(struct vsp1_lif
*lif
,
27 struct vsp1_dl_body
*dlb
, u32 reg
, u32 data
)
29 vsp1_dl_body_write(dlb
, reg
+ lif
->entity
.index
* VI6_LIF_OFFSET
,
33 /* -----------------------------------------------------------------------------
34 * V4L2 Subdevice Operations
37 static const unsigned int lif_codes
[] = {
38 MEDIA_BUS_FMT_ARGB8888_1X32
,
39 MEDIA_BUS_FMT_AYUV8_1X32
,
42 static int lif_enum_mbus_code(struct v4l2_subdev
*subdev
,
43 struct v4l2_subdev_pad_config
*cfg
,
44 struct v4l2_subdev_mbus_code_enum
*code
)
46 return vsp1_subdev_enum_mbus_code(subdev
, cfg
, code
, lif_codes
,
47 ARRAY_SIZE(lif_codes
));
50 static int lif_enum_frame_size(struct v4l2_subdev
*subdev
,
51 struct v4l2_subdev_pad_config
*cfg
,
52 struct v4l2_subdev_frame_size_enum
*fse
)
54 return vsp1_subdev_enum_frame_size(subdev
, cfg
, fse
, LIF_MIN_SIZE
,
55 LIF_MIN_SIZE
, LIF_MAX_SIZE
,
59 static int lif_set_format(struct v4l2_subdev
*subdev
,
60 struct v4l2_subdev_pad_config
*cfg
,
61 struct v4l2_subdev_format
*fmt
)
63 return vsp1_subdev_set_pad_format(subdev
, cfg
, fmt
, lif_codes
,
64 ARRAY_SIZE(lif_codes
),
65 LIF_MIN_SIZE
, LIF_MIN_SIZE
,
66 LIF_MAX_SIZE
, LIF_MAX_SIZE
);
69 static const struct v4l2_subdev_pad_ops lif_pad_ops
= {
70 .init_cfg
= vsp1_entity_init_cfg
,
71 .enum_mbus_code
= lif_enum_mbus_code
,
72 .enum_frame_size
= lif_enum_frame_size
,
73 .get_fmt
= vsp1_subdev_get_pad_format
,
74 .set_fmt
= lif_set_format
,
77 static const struct v4l2_subdev_ops lif_ops
= {
81 /* -----------------------------------------------------------------------------
82 * VSP1 Entity Operations
85 static void lif_configure_stream(struct vsp1_entity
*entity
,
86 struct vsp1_pipeline
*pipe
,
87 struct vsp1_dl_list
*dl
,
88 struct vsp1_dl_body
*dlb
)
90 const struct v4l2_mbus_framefmt
*format
;
91 struct vsp1_lif
*lif
= to_lif(&entity
->subdev
);
96 format
= vsp1_entity_get_pad_format(&lif
->entity
, lif
->entity
.config
,
99 switch (entity
->vsp1
->version
& VI6_IP_VERSION_MODEL_MASK
) {
100 case VI6_IP_VERSION_MODEL_VSPD_GEN2
:
101 case VI6_IP_VERSION_MODEL_VSPD_V2H
:
103 obth
= min(128U, (format
->width
+ 1) / 2 * format
->height
- 4);
107 case VI6_IP_VERSION_MODEL_VSPDL_GEN3
:
108 case VI6_IP_VERSION_MODEL_VSPD_V3
:
114 case VI6_IP_VERSION_MODEL_VSPD_GEN3
:
122 vsp1_lif_write(lif
, dlb
, VI6_LIF_CSBTH
,
123 (hbth
<< VI6_LIF_CSBTH_HBTH_SHIFT
) |
124 (lbth
<< VI6_LIF_CSBTH_LBTH_SHIFT
));
126 vsp1_lif_write(lif
, dlb
, VI6_LIF_CTRL
,
127 (obth
<< VI6_LIF_CTRL_OBTH_SHIFT
) |
128 (format
->code
== 0 ? VI6_LIF_CTRL_CFMT
: 0) |
129 VI6_LIF_CTRL_REQSEL
| VI6_LIF_CTRL_LIF_EN
);
132 * On R-Car V3M the LIF0 buffer attribute register has to be set to a
133 * non-default value to guarantee proper operation (otherwise artifacts
134 * may appear on the output). The value required by the manual is not
135 * explained but is likely a buffer size or threshold.
137 if ((entity
->vsp1
->version
& VI6_IP_VERSION_MASK
) ==
138 (VI6_IP_VERSION_MODEL_VSPD_V3
| VI6_IP_VERSION_SOC_V3M
))
139 vsp1_lif_write(lif
, dlb
, VI6_LIF_LBA
,
141 (1536 << VI6_LIF_LBA_LBA1_SHIFT
));
144 static const struct vsp1_entity_operations lif_entity_ops
= {
145 .configure_stream
= lif_configure_stream
,
148 /* -----------------------------------------------------------------------------
149 * Initialization and Cleanup
152 struct vsp1_lif
*vsp1_lif_create(struct vsp1_device
*vsp1
, unsigned int index
)
154 struct vsp1_lif
*lif
;
157 lif
= devm_kzalloc(vsp1
->dev
, sizeof(*lif
), GFP_KERNEL
);
159 return ERR_PTR(-ENOMEM
);
161 lif
->entity
.ops
= &lif_entity_ops
;
162 lif
->entity
.type
= VSP1_ENTITY_LIF
;
163 lif
->entity
.index
= index
;
166 * The LIF is never exposed to userspace, but media entity registration
167 * requires a function to be set. Use PROC_VIDEO_PIXEL_FORMATTER just to
168 * avoid triggering a WARN_ON(), the value won't be seen anywhere.
170 ret
= vsp1_entity_init(vsp1
, &lif
->entity
, "lif", 2, &lif_ops
,
171 MEDIA_ENT_F_PROC_VIDEO_PIXEL_FORMATTER
);