• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * vsp1_lif.c  --  R-Car VSP1 LCD Controller Interface
3  *
4  * Copyright (C) 2013-2014 Renesas Electronics Corporation
5  *
6  * Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com)
7  *
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.
12  */
13 
14 #include <linux/device.h>
15 #include <linux/gfp.h>
16 
17 #include <media/v4l2-subdev.h>
18 
19 #include "vsp1.h"
20 #include "vsp1_dl.h"
21 #include "vsp1_lif.h"
22 
23 #define LIF_MIN_SIZE				2U
24 #define LIF_MAX_SIZE				8190U
25 
26 /* -----------------------------------------------------------------------------
27  * Device Access
28  */
29 
vsp1_lif_write(struct vsp1_lif * lif,struct vsp1_dl_list * dl,u32 reg,u32 data)30 static inline void vsp1_lif_write(struct vsp1_lif *lif, struct vsp1_dl_list *dl,
31 				  u32 reg, u32 data)
32 {
33 	vsp1_dl_list_write(dl, reg, data);
34 }
35 
36 /* -----------------------------------------------------------------------------
37  * V4L2 Subdevice Operations
38  */
39 
lif_enum_mbus_code(struct v4l2_subdev * subdev,struct v4l2_subdev_pad_config * cfg,struct v4l2_subdev_mbus_code_enum * code)40 static int lif_enum_mbus_code(struct v4l2_subdev *subdev,
41 			      struct v4l2_subdev_pad_config *cfg,
42 			      struct v4l2_subdev_mbus_code_enum *code)
43 {
44 	static const unsigned int codes[] = {
45 		MEDIA_BUS_FMT_ARGB8888_1X32,
46 		MEDIA_BUS_FMT_AYUV8_1X32,
47 	};
48 
49 	return vsp1_subdev_enum_mbus_code(subdev, cfg, code, codes,
50 					  ARRAY_SIZE(codes));
51 }
52 
lif_enum_frame_size(struct v4l2_subdev * subdev,struct v4l2_subdev_pad_config * cfg,struct v4l2_subdev_frame_size_enum * fse)53 static int lif_enum_frame_size(struct v4l2_subdev *subdev,
54 			       struct v4l2_subdev_pad_config *cfg,
55 			       struct v4l2_subdev_frame_size_enum *fse)
56 {
57 	return vsp1_subdev_enum_frame_size(subdev, cfg, fse, LIF_MIN_SIZE,
58 					   LIF_MIN_SIZE, LIF_MAX_SIZE,
59 					   LIF_MAX_SIZE);
60 }
61 
lif_set_format(struct v4l2_subdev * subdev,struct v4l2_subdev_pad_config * cfg,struct v4l2_subdev_format * fmt)62 static int lif_set_format(struct v4l2_subdev *subdev,
63 			  struct v4l2_subdev_pad_config *cfg,
64 			  struct v4l2_subdev_format *fmt)
65 {
66 	struct vsp1_lif *lif = to_lif(subdev);
67 	struct v4l2_subdev_pad_config *config;
68 	struct v4l2_mbus_framefmt *format;
69 	int ret = 0;
70 
71 	mutex_lock(&lif->entity.lock);
72 
73 	config = vsp1_entity_get_pad_config(&lif->entity, cfg, fmt->which);
74 	if (!config) {
75 		ret = -EINVAL;
76 		goto done;
77 	}
78 
79 	/* Default to YUV if the requested format is not supported. */
80 	if (fmt->format.code != MEDIA_BUS_FMT_ARGB8888_1X32 &&
81 	    fmt->format.code != MEDIA_BUS_FMT_AYUV8_1X32)
82 		fmt->format.code = MEDIA_BUS_FMT_AYUV8_1X32;
83 
84 	format = vsp1_entity_get_pad_format(&lif->entity, config, fmt->pad);
85 
86 	if (fmt->pad == LIF_PAD_SOURCE) {
87 		/* The LIF source format is always identical to its sink
88 		 * format.
89 		 */
90 		fmt->format = *format;
91 		goto done;
92 	}
93 
94 	format->code = fmt->format.code;
95 	format->width = clamp_t(unsigned int, fmt->format.width,
96 				LIF_MIN_SIZE, LIF_MAX_SIZE);
97 	format->height = clamp_t(unsigned int, fmt->format.height,
98 				 LIF_MIN_SIZE, LIF_MAX_SIZE);
99 	format->field = V4L2_FIELD_NONE;
100 	format->colorspace = V4L2_COLORSPACE_SRGB;
101 
102 	fmt->format = *format;
103 
104 	/* Propagate the format to the source pad. */
105 	format = vsp1_entity_get_pad_format(&lif->entity, config,
106 					    LIF_PAD_SOURCE);
107 	*format = fmt->format;
108 
109 done:
110 	mutex_unlock(&lif->entity.lock);
111 	return ret;
112 }
113 
114 static const struct v4l2_subdev_pad_ops lif_pad_ops = {
115 	.init_cfg = vsp1_entity_init_cfg,
116 	.enum_mbus_code = lif_enum_mbus_code,
117 	.enum_frame_size = lif_enum_frame_size,
118 	.get_fmt = vsp1_subdev_get_pad_format,
119 	.set_fmt = lif_set_format,
120 };
121 
122 static const struct v4l2_subdev_ops lif_ops = {
123 	.pad    = &lif_pad_ops,
124 };
125 
126 /* -----------------------------------------------------------------------------
127  * VSP1 Entity Operations
128  */
129 
lif_configure(struct vsp1_entity * entity,struct vsp1_pipeline * pipe,struct vsp1_dl_list * dl,enum vsp1_entity_params params)130 static void lif_configure(struct vsp1_entity *entity,
131 			  struct vsp1_pipeline *pipe,
132 			  struct vsp1_dl_list *dl,
133 			  enum vsp1_entity_params params)
134 {
135 	const struct v4l2_mbus_framefmt *format;
136 	struct vsp1_lif *lif = to_lif(&entity->subdev);
137 	unsigned int hbth = 1300;
138 	unsigned int obth = 400;
139 	unsigned int lbth = 200;
140 
141 	if (params != VSP1_ENTITY_PARAMS_INIT)
142 		return;
143 
144 	format = vsp1_entity_get_pad_format(&lif->entity, lif->entity.config,
145 					    LIF_PAD_SOURCE);
146 
147 	obth = min(obth, (format->width + 1) / 2 * format->height - 4);
148 
149 	vsp1_lif_write(lif, dl, VI6_LIF_CSBTH,
150 			(hbth << VI6_LIF_CSBTH_HBTH_SHIFT) |
151 			(lbth << VI6_LIF_CSBTH_LBTH_SHIFT));
152 
153 	vsp1_lif_write(lif, dl, VI6_LIF_CTRL,
154 			(obth << VI6_LIF_CTRL_OBTH_SHIFT) |
155 			(format->code == 0 ? VI6_LIF_CTRL_CFMT : 0) |
156 			VI6_LIF_CTRL_REQSEL | VI6_LIF_CTRL_LIF_EN);
157 }
158 
159 static const struct vsp1_entity_operations lif_entity_ops = {
160 	.configure = lif_configure,
161 };
162 
163 /* -----------------------------------------------------------------------------
164  * Initialization and Cleanup
165  */
166 
vsp1_lif_create(struct vsp1_device * vsp1)167 struct vsp1_lif *vsp1_lif_create(struct vsp1_device *vsp1)
168 {
169 	struct vsp1_lif *lif;
170 	int ret;
171 
172 	lif = devm_kzalloc(vsp1->dev, sizeof(*lif), GFP_KERNEL);
173 	if (lif == NULL)
174 		return ERR_PTR(-ENOMEM);
175 
176 	lif->entity.ops = &lif_entity_ops;
177 	lif->entity.type = VSP1_ENTITY_LIF;
178 
179 	/* The LIF is never exposed to userspace, but media entity registration
180 	 * requires a function to be set. Use PROC_VIDEO_PIXEL_FORMATTER just to
181 	 * avoid triggering a WARN_ON(), the value won't be seen anywhere.
182 	 */
183 	ret = vsp1_entity_init(vsp1, &lif->entity, "lif", 2, &lif_ops,
184 			       MEDIA_ENT_F_PROC_VIDEO_PIXEL_FORMATTER);
185 	if (ret < 0)
186 		return ERR_PTR(ret);
187 
188 	return lif;
189 }
190