1*ee4a77a3SMauro Carvalho Chehab // SPDX-License-Identifier: GPL-2.0+
2*ee4a77a3SMauro Carvalho Chehab /*
3*ee4a77a3SMauro Carvalho Chehab * vsp1_hsit.c -- R-Car VSP1 Hue Saturation value (Inverse) Transform
4*ee4a77a3SMauro Carvalho Chehab *
5*ee4a77a3SMauro Carvalho Chehab * Copyright (C) 2013 Renesas Corporation
6*ee4a77a3SMauro Carvalho Chehab *
7*ee4a77a3SMauro Carvalho Chehab * Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com)
8*ee4a77a3SMauro Carvalho Chehab */
9*ee4a77a3SMauro Carvalho Chehab
10*ee4a77a3SMauro Carvalho Chehab #include <linux/device.h>
11*ee4a77a3SMauro Carvalho Chehab #include <linux/gfp.h>
12*ee4a77a3SMauro Carvalho Chehab
13*ee4a77a3SMauro Carvalho Chehab #include <media/v4l2-subdev.h>
14*ee4a77a3SMauro Carvalho Chehab
15*ee4a77a3SMauro Carvalho Chehab #include "vsp1.h"
16*ee4a77a3SMauro Carvalho Chehab #include "vsp1_dl.h"
17*ee4a77a3SMauro Carvalho Chehab #include "vsp1_hsit.h"
18*ee4a77a3SMauro Carvalho Chehab
19*ee4a77a3SMauro Carvalho Chehab #define HSIT_MIN_SIZE 4U
20*ee4a77a3SMauro Carvalho Chehab #define HSIT_MAX_SIZE 8190U
21*ee4a77a3SMauro Carvalho Chehab
22*ee4a77a3SMauro Carvalho Chehab /* -----------------------------------------------------------------------------
23*ee4a77a3SMauro Carvalho Chehab * Device Access
24*ee4a77a3SMauro Carvalho Chehab */
25*ee4a77a3SMauro Carvalho Chehab
vsp1_hsit_write(struct vsp1_hsit * hsit,struct vsp1_dl_body * dlb,u32 reg,u32 data)26*ee4a77a3SMauro Carvalho Chehab static inline void vsp1_hsit_write(struct vsp1_hsit *hsit,
27*ee4a77a3SMauro Carvalho Chehab struct vsp1_dl_body *dlb, u32 reg, u32 data)
28*ee4a77a3SMauro Carvalho Chehab {
29*ee4a77a3SMauro Carvalho Chehab vsp1_dl_body_write(dlb, reg, data);
30*ee4a77a3SMauro Carvalho Chehab }
31*ee4a77a3SMauro Carvalho Chehab
32*ee4a77a3SMauro Carvalho Chehab /* -----------------------------------------------------------------------------
33*ee4a77a3SMauro Carvalho Chehab * V4L2 Subdevice Operations
34*ee4a77a3SMauro Carvalho Chehab */
35*ee4a77a3SMauro Carvalho Chehab
hsit_enum_mbus_code(struct v4l2_subdev * subdev,struct v4l2_subdev_state * sd_state,struct v4l2_subdev_mbus_code_enum * code)36*ee4a77a3SMauro Carvalho Chehab static int hsit_enum_mbus_code(struct v4l2_subdev *subdev,
37*ee4a77a3SMauro Carvalho Chehab struct v4l2_subdev_state *sd_state,
38*ee4a77a3SMauro Carvalho Chehab struct v4l2_subdev_mbus_code_enum *code)
39*ee4a77a3SMauro Carvalho Chehab {
40*ee4a77a3SMauro Carvalho Chehab struct vsp1_hsit *hsit = to_hsit(subdev);
41*ee4a77a3SMauro Carvalho Chehab
42*ee4a77a3SMauro Carvalho Chehab if (code->index > 0)
43*ee4a77a3SMauro Carvalho Chehab return -EINVAL;
44*ee4a77a3SMauro Carvalho Chehab
45*ee4a77a3SMauro Carvalho Chehab if ((code->pad == HSIT_PAD_SINK && !hsit->inverse) |
46*ee4a77a3SMauro Carvalho Chehab (code->pad == HSIT_PAD_SOURCE && hsit->inverse))
47*ee4a77a3SMauro Carvalho Chehab code->code = MEDIA_BUS_FMT_ARGB8888_1X32;
48*ee4a77a3SMauro Carvalho Chehab else
49*ee4a77a3SMauro Carvalho Chehab code->code = MEDIA_BUS_FMT_AHSV8888_1X32;
50*ee4a77a3SMauro Carvalho Chehab
51*ee4a77a3SMauro Carvalho Chehab return 0;
52*ee4a77a3SMauro Carvalho Chehab }
53*ee4a77a3SMauro Carvalho Chehab
hsit_enum_frame_size(struct v4l2_subdev * subdev,struct v4l2_subdev_state * sd_state,struct v4l2_subdev_frame_size_enum * fse)54*ee4a77a3SMauro Carvalho Chehab static int hsit_enum_frame_size(struct v4l2_subdev *subdev,
55*ee4a77a3SMauro Carvalho Chehab struct v4l2_subdev_state *sd_state,
56*ee4a77a3SMauro Carvalho Chehab struct v4l2_subdev_frame_size_enum *fse)
57*ee4a77a3SMauro Carvalho Chehab {
58*ee4a77a3SMauro Carvalho Chehab return vsp1_subdev_enum_frame_size(subdev, sd_state, fse,
59*ee4a77a3SMauro Carvalho Chehab HSIT_MIN_SIZE,
60*ee4a77a3SMauro Carvalho Chehab HSIT_MIN_SIZE, HSIT_MAX_SIZE,
61*ee4a77a3SMauro Carvalho Chehab HSIT_MAX_SIZE);
62*ee4a77a3SMauro Carvalho Chehab }
63*ee4a77a3SMauro Carvalho Chehab
hsit_set_format(struct v4l2_subdev * subdev,struct v4l2_subdev_state * sd_state,struct v4l2_subdev_format * fmt)64*ee4a77a3SMauro Carvalho Chehab static int hsit_set_format(struct v4l2_subdev *subdev,
65*ee4a77a3SMauro Carvalho Chehab struct v4l2_subdev_state *sd_state,
66*ee4a77a3SMauro Carvalho Chehab struct v4l2_subdev_format *fmt)
67*ee4a77a3SMauro Carvalho Chehab {
68*ee4a77a3SMauro Carvalho Chehab struct vsp1_hsit *hsit = to_hsit(subdev);
69*ee4a77a3SMauro Carvalho Chehab struct v4l2_subdev_state *config;
70*ee4a77a3SMauro Carvalho Chehab struct v4l2_mbus_framefmt *format;
71*ee4a77a3SMauro Carvalho Chehab int ret = 0;
72*ee4a77a3SMauro Carvalho Chehab
73*ee4a77a3SMauro Carvalho Chehab mutex_lock(&hsit->entity.lock);
74*ee4a77a3SMauro Carvalho Chehab
75*ee4a77a3SMauro Carvalho Chehab config = vsp1_entity_get_pad_config(&hsit->entity, sd_state,
76*ee4a77a3SMauro Carvalho Chehab fmt->which);
77*ee4a77a3SMauro Carvalho Chehab if (!config) {
78*ee4a77a3SMauro Carvalho Chehab ret = -EINVAL;
79*ee4a77a3SMauro Carvalho Chehab goto done;
80*ee4a77a3SMauro Carvalho Chehab }
81*ee4a77a3SMauro Carvalho Chehab
82*ee4a77a3SMauro Carvalho Chehab format = vsp1_entity_get_pad_format(&hsit->entity, config, fmt->pad);
83*ee4a77a3SMauro Carvalho Chehab
84*ee4a77a3SMauro Carvalho Chehab if (fmt->pad == HSIT_PAD_SOURCE) {
85*ee4a77a3SMauro Carvalho Chehab /*
86*ee4a77a3SMauro Carvalho Chehab * The HST and HSI output format code and resolution can't be
87*ee4a77a3SMauro Carvalho Chehab * modified.
88*ee4a77a3SMauro Carvalho Chehab */
89*ee4a77a3SMauro Carvalho Chehab fmt->format = *format;
90*ee4a77a3SMauro Carvalho Chehab goto done;
91*ee4a77a3SMauro Carvalho Chehab }
92*ee4a77a3SMauro Carvalho Chehab
93*ee4a77a3SMauro Carvalho Chehab format->code = hsit->inverse ? MEDIA_BUS_FMT_AHSV8888_1X32
94*ee4a77a3SMauro Carvalho Chehab : MEDIA_BUS_FMT_ARGB8888_1X32;
95*ee4a77a3SMauro Carvalho Chehab format->width = clamp_t(unsigned int, fmt->format.width,
96*ee4a77a3SMauro Carvalho Chehab HSIT_MIN_SIZE, HSIT_MAX_SIZE);
97*ee4a77a3SMauro Carvalho Chehab format->height = clamp_t(unsigned int, fmt->format.height,
98*ee4a77a3SMauro Carvalho Chehab HSIT_MIN_SIZE, HSIT_MAX_SIZE);
99*ee4a77a3SMauro Carvalho Chehab format->field = V4L2_FIELD_NONE;
100*ee4a77a3SMauro Carvalho Chehab format->colorspace = V4L2_COLORSPACE_SRGB;
101*ee4a77a3SMauro Carvalho Chehab
102*ee4a77a3SMauro Carvalho Chehab fmt->format = *format;
103*ee4a77a3SMauro Carvalho Chehab
104*ee4a77a3SMauro Carvalho Chehab /* Propagate the format to the source pad. */
105*ee4a77a3SMauro Carvalho Chehab format = vsp1_entity_get_pad_format(&hsit->entity, config,
106*ee4a77a3SMauro Carvalho Chehab HSIT_PAD_SOURCE);
107*ee4a77a3SMauro Carvalho Chehab *format = fmt->format;
108*ee4a77a3SMauro Carvalho Chehab format->code = hsit->inverse ? MEDIA_BUS_FMT_ARGB8888_1X32
109*ee4a77a3SMauro Carvalho Chehab : MEDIA_BUS_FMT_AHSV8888_1X32;
110*ee4a77a3SMauro Carvalho Chehab
111*ee4a77a3SMauro Carvalho Chehab done:
112*ee4a77a3SMauro Carvalho Chehab mutex_unlock(&hsit->entity.lock);
113*ee4a77a3SMauro Carvalho Chehab return ret;
114*ee4a77a3SMauro Carvalho Chehab }
115*ee4a77a3SMauro Carvalho Chehab
116*ee4a77a3SMauro Carvalho Chehab static const struct v4l2_subdev_pad_ops hsit_pad_ops = {
117*ee4a77a3SMauro Carvalho Chehab .init_cfg = vsp1_entity_init_cfg,
118*ee4a77a3SMauro Carvalho Chehab .enum_mbus_code = hsit_enum_mbus_code,
119*ee4a77a3SMauro Carvalho Chehab .enum_frame_size = hsit_enum_frame_size,
120*ee4a77a3SMauro Carvalho Chehab .get_fmt = vsp1_subdev_get_pad_format,
121*ee4a77a3SMauro Carvalho Chehab .set_fmt = hsit_set_format,
122*ee4a77a3SMauro Carvalho Chehab };
123*ee4a77a3SMauro Carvalho Chehab
124*ee4a77a3SMauro Carvalho Chehab static const struct v4l2_subdev_ops hsit_ops = {
125*ee4a77a3SMauro Carvalho Chehab .pad = &hsit_pad_ops,
126*ee4a77a3SMauro Carvalho Chehab };
127*ee4a77a3SMauro Carvalho Chehab
128*ee4a77a3SMauro Carvalho Chehab /* -----------------------------------------------------------------------------
129*ee4a77a3SMauro Carvalho Chehab * VSP1 Entity Operations
130*ee4a77a3SMauro Carvalho Chehab */
131*ee4a77a3SMauro Carvalho Chehab
hsit_configure_stream(struct vsp1_entity * entity,struct vsp1_pipeline * pipe,struct vsp1_dl_list * dl,struct vsp1_dl_body * dlb)132*ee4a77a3SMauro Carvalho Chehab static void hsit_configure_stream(struct vsp1_entity *entity,
133*ee4a77a3SMauro Carvalho Chehab struct vsp1_pipeline *pipe,
134*ee4a77a3SMauro Carvalho Chehab struct vsp1_dl_list *dl,
135*ee4a77a3SMauro Carvalho Chehab struct vsp1_dl_body *dlb)
136*ee4a77a3SMauro Carvalho Chehab {
137*ee4a77a3SMauro Carvalho Chehab struct vsp1_hsit *hsit = to_hsit(&entity->subdev);
138*ee4a77a3SMauro Carvalho Chehab
139*ee4a77a3SMauro Carvalho Chehab if (hsit->inverse)
140*ee4a77a3SMauro Carvalho Chehab vsp1_hsit_write(hsit, dlb, VI6_HSI_CTRL, VI6_HSI_CTRL_EN);
141*ee4a77a3SMauro Carvalho Chehab else
142*ee4a77a3SMauro Carvalho Chehab vsp1_hsit_write(hsit, dlb, VI6_HST_CTRL, VI6_HST_CTRL_EN);
143*ee4a77a3SMauro Carvalho Chehab }
144*ee4a77a3SMauro Carvalho Chehab
145*ee4a77a3SMauro Carvalho Chehab static const struct vsp1_entity_operations hsit_entity_ops = {
146*ee4a77a3SMauro Carvalho Chehab .configure_stream = hsit_configure_stream,
147*ee4a77a3SMauro Carvalho Chehab };
148*ee4a77a3SMauro Carvalho Chehab
149*ee4a77a3SMauro Carvalho Chehab /* -----------------------------------------------------------------------------
150*ee4a77a3SMauro Carvalho Chehab * Initialization and Cleanup
151*ee4a77a3SMauro Carvalho Chehab */
152*ee4a77a3SMauro Carvalho Chehab
vsp1_hsit_create(struct vsp1_device * vsp1,bool inverse)153*ee4a77a3SMauro Carvalho Chehab struct vsp1_hsit *vsp1_hsit_create(struct vsp1_device *vsp1, bool inverse)
154*ee4a77a3SMauro Carvalho Chehab {
155*ee4a77a3SMauro Carvalho Chehab struct vsp1_hsit *hsit;
156*ee4a77a3SMauro Carvalho Chehab int ret;
157*ee4a77a3SMauro Carvalho Chehab
158*ee4a77a3SMauro Carvalho Chehab hsit = devm_kzalloc(vsp1->dev, sizeof(*hsit), GFP_KERNEL);
159*ee4a77a3SMauro Carvalho Chehab if (hsit == NULL)
160*ee4a77a3SMauro Carvalho Chehab return ERR_PTR(-ENOMEM);
161*ee4a77a3SMauro Carvalho Chehab
162*ee4a77a3SMauro Carvalho Chehab hsit->inverse = inverse;
163*ee4a77a3SMauro Carvalho Chehab
164*ee4a77a3SMauro Carvalho Chehab hsit->entity.ops = &hsit_entity_ops;
165*ee4a77a3SMauro Carvalho Chehab
166*ee4a77a3SMauro Carvalho Chehab if (inverse)
167*ee4a77a3SMauro Carvalho Chehab hsit->entity.type = VSP1_ENTITY_HSI;
168*ee4a77a3SMauro Carvalho Chehab else
169*ee4a77a3SMauro Carvalho Chehab hsit->entity.type = VSP1_ENTITY_HST;
170*ee4a77a3SMauro Carvalho Chehab
171*ee4a77a3SMauro Carvalho Chehab ret = vsp1_entity_init(vsp1, &hsit->entity, inverse ? "hsi" : "hst",
172*ee4a77a3SMauro Carvalho Chehab 2, &hsit_ops,
173*ee4a77a3SMauro Carvalho Chehab MEDIA_ENT_F_PROC_VIDEO_PIXEL_ENC_CONV);
174*ee4a77a3SMauro Carvalho Chehab if (ret < 0)
175*ee4a77a3SMauro Carvalho Chehab return ERR_PTR(ret);
176*ee4a77a3SMauro Carvalho Chehab
177*ee4a77a3SMauro Carvalho Chehab return hsit;
178*ee4a77a3SMauro Carvalho Chehab }
179