11c4b5f49SLaurent Pinchart // SPDX-License-Identifier: GPL-2.0+
2989af883SLaurent Pinchart /*
3989af883SLaurent Pinchart * vsp1_lut.c -- R-Car VSP1 Look-Up Table
4989af883SLaurent Pinchart *
5989af883SLaurent Pinchart * Copyright (C) 2013 Renesas Corporation
6989af883SLaurent Pinchart *
7989af883SLaurent Pinchart * Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com)
8989af883SLaurent Pinchart */
9989af883SLaurent Pinchart
10989af883SLaurent Pinchart #include <linux/device.h>
11989af883SLaurent Pinchart #include <linux/gfp.h>
12989af883SLaurent Pinchart
13989af883SLaurent Pinchart #include <media/v4l2-subdev.h>
14989af883SLaurent Pinchart
15989af883SLaurent Pinchart #include "vsp1.h"
165e8dbbf3SLaurent Pinchart #include "vsp1_dl.h"
17989af883SLaurent Pinchart #include "vsp1_lut.h"
18989af883SLaurent Pinchart
19989af883SLaurent Pinchart #define LUT_MIN_SIZE 4U
20989af883SLaurent Pinchart #define LUT_MAX_SIZE 8190U
21989af883SLaurent Pinchart
225d7936b8SKieran Bingham #define LUT_SIZE 256
235d7936b8SKieran Bingham
24989af883SLaurent Pinchart /* -----------------------------------------------------------------------------
25989af883SLaurent Pinchart * Device Access
26989af883SLaurent Pinchart */
27989af883SLaurent Pinchart
vsp1_lut_write(struct vsp1_lut * lut,struct vsp1_dl_body * dlb,u32 reg,u32 data)2812832dd9SKieran Bingham static inline void vsp1_lut_write(struct vsp1_lut *lut,
2912832dd9SKieran Bingham struct vsp1_dl_body *dlb, u32 reg, u32 data)
30989af883SLaurent Pinchart {
3112832dd9SKieran Bingham vsp1_dl_body_write(dlb, reg, data);
32989af883SLaurent Pinchart }
33989af883SLaurent Pinchart
34989af883SLaurent Pinchart /* -----------------------------------------------------------------------------
3542e89bedSLaurent Pinchart * Controls
36989af883SLaurent Pinchart */
37989af883SLaurent Pinchart
3842e89bedSLaurent Pinchart #define V4L2_CID_VSP1_LUT_TABLE (V4L2_CID_USER_BASE | 0x1001)
3942e89bedSLaurent Pinchart
lut_set_table(struct vsp1_lut * lut,struct v4l2_ctrl * ctrl)4042e89bedSLaurent Pinchart static int lut_set_table(struct vsp1_lut *lut, struct v4l2_ctrl *ctrl)
41989af883SLaurent Pinchart {
420e6b9c56SLaurent Pinchart struct vsp1_dl_body *dlb;
430e6b9c56SLaurent Pinchart unsigned int i;
440e6b9c56SLaurent Pinchart
455d7936b8SKieran Bingham dlb = vsp1_dl_body_get(lut->pool);
460e6b9c56SLaurent Pinchart if (!dlb)
470e6b9c56SLaurent Pinchart return -ENOMEM;
480e6b9c56SLaurent Pinchart
495d7936b8SKieran Bingham for (i = 0; i < LUT_SIZE; ++i)
50764dfee1SKieran Bingham vsp1_dl_body_write(dlb, VI6_LUT_TABLE + 4 * i,
5142e89bedSLaurent Pinchart ctrl->p_new.p_u32[i]);
520e6b9c56SLaurent Pinchart
53f4e37fb7SLaurent Pinchart spin_lock_irq(&lut->lock);
540e6b9c56SLaurent Pinchart swap(lut->lut, dlb);
55f4e37fb7SLaurent Pinchart spin_unlock_irq(&lut->lock);
560e6b9c56SLaurent Pinchart
575d7936b8SKieran Bingham vsp1_dl_body_put(dlb);
580e6b9c56SLaurent Pinchart return 0;
59989af883SLaurent Pinchart }
60989af883SLaurent Pinchart
lut_s_ctrl(struct v4l2_ctrl * ctrl)6142e89bedSLaurent Pinchart static int lut_s_ctrl(struct v4l2_ctrl *ctrl)
62989af883SLaurent Pinchart {
6342e89bedSLaurent Pinchart struct vsp1_lut *lut =
6442e89bedSLaurent Pinchart container_of(ctrl->handler, struct vsp1_lut, ctrls);
65989af883SLaurent Pinchart
6642e89bedSLaurent Pinchart switch (ctrl->id) {
6742e89bedSLaurent Pinchart case V4L2_CID_VSP1_LUT_TABLE:
6842e89bedSLaurent Pinchart lut_set_table(lut, ctrl);
6942e89bedSLaurent Pinchart break;
7042e89bedSLaurent Pinchart }
71989af883SLaurent Pinchart
7242e89bedSLaurent Pinchart return 0;
73989af883SLaurent Pinchart }
7442e89bedSLaurent Pinchart
7542e89bedSLaurent Pinchart static const struct v4l2_ctrl_ops lut_ctrl_ops = {
7642e89bedSLaurent Pinchart .s_ctrl = lut_s_ctrl,
7742e89bedSLaurent Pinchart };
7842e89bedSLaurent Pinchart
7942e89bedSLaurent Pinchart static const struct v4l2_ctrl_config lut_table_control = {
8042e89bedSLaurent Pinchart .ops = &lut_ctrl_ops,
8142e89bedSLaurent Pinchart .id = V4L2_CID_VSP1_LUT_TABLE,
8242e89bedSLaurent Pinchart .name = "Look-Up Table",
8342e89bedSLaurent Pinchart .type = V4L2_CTRL_TYPE_U32,
8442e89bedSLaurent Pinchart .min = 0x00000000,
8542e89bedSLaurent Pinchart .max = 0x00ffffff,
8642e89bedSLaurent Pinchart .step = 1,
8742e89bedSLaurent Pinchart .def = 0,
885d7936b8SKieran Bingham .dims = { LUT_SIZE },
8942e89bedSLaurent Pinchart };
90989af883SLaurent Pinchart
91989af883SLaurent Pinchart /* -----------------------------------------------------------------------------
92989af883SLaurent Pinchart * V4L2 Subdevice Pad Operations
93989af883SLaurent Pinchart */
94989af883SLaurent Pinchart
95b4ccae10SLaurent Pinchart static const unsigned int lut_codes[] = {
9627ffaeb0SBoris BREZILLON MEDIA_BUS_FMT_ARGB8888_1X32,
9727ffaeb0SBoris BREZILLON MEDIA_BUS_FMT_AHSV8888_1X32,
9827ffaeb0SBoris BREZILLON MEDIA_BUS_FMT_AYUV8_1X32,
99989af883SLaurent Pinchart };
100989af883SLaurent Pinchart
lut_enum_mbus_code(struct v4l2_subdev * subdev,struct v4l2_subdev_state * sd_state,struct v4l2_subdev_mbus_code_enum * code)101b4ccae10SLaurent Pinchart static int lut_enum_mbus_code(struct v4l2_subdev *subdev,
1020d346d2aSTomi Valkeinen struct v4l2_subdev_state *sd_state,
103b4ccae10SLaurent Pinchart struct v4l2_subdev_mbus_code_enum *code)
104b4ccae10SLaurent Pinchart {
1050d346d2aSTomi Valkeinen return vsp1_subdev_enum_mbus_code(subdev, sd_state, code, lut_codes,
106b4ccae10SLaurent Pinchart ARRAY_SIZE(lut_codes));
107989af883SLaurent Pinchart }
108989af883SLaurent Pinchart
lut_enum_frame_size(struct v4l2_subdev * subdev,struct v4l2_subdev_state * sd_state,struct v4l2_subdev_frame_size_enum * fse)109989af883SLaurent Pinchart static int lut_enum_frame_size(struct v4l2_subdev *subdev,
1100d346d2aSTomi Valkeinen struct v4l2_subdev_state *sd_state,
111989af883SLaurent Pinchart struct v4l2_subdev_frame_size_enum *fse)
112989af883SLaurent Pinchart {
1130d346d2aSTomi Valkeinen return vsp1_subdev_enum_frame_size(subdev, sd_state, fse,
1140d346d2aSTomi Valkeinen LUT_MIN_SIZE,
115076e834fSLaurent Pinchart LUT_MIN_SIZE, LUT_MAX_SIZE,
116076e834fSLaurent Pinchart LUT_MAX_SIZE);
117989af883SLaurent Pinchart }
118989af883SLaurent Pinchart
lut_set_format(struct v4l2_subdev * subdev,struct v4l2_subdev_state * sd_state,struct v4l2_subdev_format * fmt)1191bd0a1bdSLaurent Pinchart static int lut_set_format(struct v4l2_subdev *subdev,
1200d346d2aSTomi Valkeinen struct v4l2_subdev_state *sd_state,
121989af883SLaurent Pinchart struct v4l2_subdev_format *fmt)
122989af883SLaurent Pinchart {
1230d346d2aSTomi Valkeinen return vsp1_subdev_set_pad_format(subdev, sd_state, fmt, lut_codes,
124b4ccae10SLaurent Pinchart ARRAY_SIZE(lut_codes),
125b4ccae10SLaurent Pinchart LUT_MIN_SIZE, LUT_MIN_SIZE,
126b4ccae10SLaurent Pinchart LUT_MAX_SIZE, LUT_MAX_SIZE);
127989af883SLaurent Pinchart }
128989af883SLaurent Pinchart
129989af883SLaurent Pinchart /* -----------------------------------------------------------------------------
130989af883SLaurent Pinchart * V4L2 Subdevice Operations
131989af883SLaurent Pinchart */
132989af883SLaurent Pinchart
133eb9163d3SLaurent Pinchart static const struct v4l2_subdev_pad_ops lut_pad_ops = {
134989af883SLaurent Pinchart .enum_mbus_code = lut_enum_mbus_code,
135989af883SLaurent Pinchart .enum_frame_size = lut_enum_frame_size,
1363f557220SLaurent Pinchart .get_fmt = vsp1_subdev_get_pad_format,
137989af883SLaurent Pinchart .set_fmt = lut_set_format,
138989af883SLaurent Pinchart };
139989af883SLaurent Pinchart
140eb9163d3SLaurent Pinchart static const struct v4l2_subdev_ops lut_ops = {
141989af883SLaurent Pinchart .pad = &lut_pad_ops,
142989af883SLaurent Pinchart };
143989af883SLaurent Pinchart
144989af883SLaurent Pinchart /* -----------------------------------------------------------------------------
1457b905f05SLaurent Pinchart * VSP1 Entity Operations
1467b905f05SLaurent Pinchart */
1477b905f05SLaurent Pinchart
lut_configure_stream(struct vsp1_entity * entity,struct v4l2_subdev_state * state,struct vsp1_pipeline * pipe,struct vsp1_dl_list * dl,struct vsp1_dl_body * dlb)14846ce3639SKieran Bingham static void lut_configure_stream(struct vsp1_entity *entity,
1494be710a3SLaurent Pinchart struct v4l2_subdev_state *state,
15083dd019dSLaurent Pinchart struct vsp1_pipeline *pipe,
151b36c6049SLaurent Pinchart struct vsp1_dl_list *dl,
15212832dd9SKieran Bingham struct vsp1_dl_body *dlb)
15346ce3639SKieran Bingham {
15446ce3639SKieran Bingham struct vsp1_lut *lut = to_lut(&entity->subdev);
15546ce3639SKieran Bingham
15612832dd9SKieran Bingham vsp1_lut_write(lut, dlb, VI6_LUT_CTRL, VI6_LUT_CTRL_EN);
15746ce3639SKieran Bingham }
15846ce3639SKieran Bingham
lut_configure_frame(struct vsp1_entity * entity,struct vsp1_pipeline * pipe,struct vsp1_dl_list * dl,struct vsp1_dl_body * dlb)15946ce3639SKieran Bingham static void lut_configure_frame(struct vsp1_entity *entity,
16046ce3639SKieran Bingham struct vsp1_pipeline *pipe,
16112832dd9SKieran Bingham struct vsp1_dl_list *dl,
16212832dd9SKieran Bingham struct vsp1_dl_body *dlb)
1637b905f05SLaurent Pinchart {
1647b905f05SLaurent Pinchart struct vsp1_lut *lut = to_lut(&entity->subdev);
16512832dd9SKieran Bingham struct vsp1_dl_body *lut_dlb;
166f4e37fb7SLaurent Pinchart unsigned long flags;
1677b905f05SLaurent Pinchart
168f4e37fb7SLaurent Pinchart spin_lock_irqsave(&lut->lock, flags);
16912832dd9SKieran Bingham lut_dlb = lut->lut;
170f4e37fb7SLaurent Pinchart lut->lut = NULL;
171f4e37fb7SLaurent Pinchart spin_unlock_irqrestore(&lut->lock, flags);
172f4e37fb7SLaurent Pinchart
17312832dd9SKieran Bingham if (lut_dlb) {
17412832dd9SKieran Bingham vsp1_dl_list_add_body(dl, lut_dlb);
1752d9445dbSKieran Bingham
1762d9445dbSKieran Bingham /* Release our local reference. */
17712832dd9SKieran Bingham vsp1_dl_body_put(lut_dlb);
1782d9445dbSKieran Bingham }
1797b905f05SLaurent Pinchart }
1807b905f05SLaurent Pinchart
lut_destroy(struct vsp1_entity * entity)1815d7936b8SKieran Bingham static void lut_destroy(struct vsp1_entity *entity)
1825d7936b8SKieran Bingham {
1835d7936b8SKieran Bingham struct vsp1_lut *lut = to_lut(&entity->subdev);
1845d7936b8SKieran Bingham
1855d7936b8SKieran Bingham vsp1_dl_body_pool_destroy(lut->pool);
1865d7936b8SKieran Bingham }
1875d7936b8SKieran Bingham
1887b905f05SLaurent Pinchart static const struct vsp1_entity_operations lut_entity_ops = {
18946ce3639SKieran Bingham .configure_stream = lut_configure_stream,
19046ce3639SKieran Bingham .configure_frame = lut_configure_frame,
1915d7936b8SKieran Bingham .destroy = lut_destroy,
1927b905f05SLaurent Pinchart };
1937b905f05SLaurent Pinchart
1947b905f05SLaurent Pinchart /* -----------------------------------------------------------------------------
195989af883SLaurent Pinchart * Initialization and Cleanup
196989af883SLaurent Pinchart */
197989af883SLaurent Pinchart
vsp1_lut_create(struct vsp1_device * vsp1)198989af883SLaurent Pinchart struct vsp1_lut *vsp1_lut_create(struct vsp1_device *vsp1)
199989af883SLaurent Pinchart {
200989af883SLaurent Pinchart struct vsp1_lut *lut;
201989af883SLaurent Pinchart int ret;
202989af883SLaurent Pinchart
203989af883SLaurent Pinchart lut = devm_kzalloc(vsp1->dev, sizeof(*lut), GFP_KERNEL);
204989af883SLaurent Pinchart if (lut == NULL)
205989af883SLaurent Pinchart return ERR_PTR(-ENOMEM);
206989af883SLaurent Pinchart
207f4e37fb7SLaurent Pinchart spin_lock_init(&lut->lock);
208f4e37fb7SLaurent Pinchart
2097b905f05SLaurent Pinchart lut->entity.ops = &lut_entity_ops;
210989af883SLaurent Pinchart lut->entity.type = VSP1_ENTITY_LUT;
211989af883SLaurent Pinchart
2126a8e07b2SLaurent Pinchart ret = vsp1_entity_init(vsp1, &lut->entity, "lut", 2, &lut_ops,
2136a8e07b2SLaurent Pinchart MEDIA_ENT_F_PROC_VIDEO_LUT);
214989af883SLaurent Pinchart if (ret < 0)
215989af883SLaurent Pinchart return ERR_PTR(ret);
216989af883SLaurent Pinchart
2175d7936b8SKieran Bingham /*
2185d7936b8SKieran Bingham * Pre-allocate a body pool, with 3 bodies allowing a userspace update
2195d7936b8SKieran Bingham * before the hardware has committed a previous set of tables, handling
2205d7936b8SKieran Bingham * both the queued and pending dl entries.
2215d7936b8SKieran Bingham */
2225d7936b8SKieran Bingham lut->pool = vsp1_dl_body_pool_create(vsp1, 3, LUT_SIZE, 0);
2235d7936b8SKieran Bingham if (!lut->pool)
2245d7936b8SKieran Bingham return ERR_PTR(-ENOMEM);
2255d7936b8SKieran Bingham
22642e89bedSLaurent Pinchart /* Initialize the control handler. */
22742e89bedSLaurent Pinchart v4l2_ctrl_handler_init(&lut->ctrls, 1);
22842e89bedSLaurent Pinchart v4l2_ctrl_new_custom(&lut->ctrls, &lut_table_control, NULL);
22942e89bedSLaurent Pinchart
23042e89bedSLaurent Pinchart lut->entity.subdev.ctrl_handler = &lut->ctrls;
23142e89bedSLaurent Pinchart
23242e89bedSLaurent Pinchart if (lut->ctrls.error) {
23342e89bedSLaurent Pinchart dev_err(vsp1->dev, "lut: failed to initialize controls\n");
23442e89bedSLaurent Pinchart ret = lut->ctrls.error;
23542e89bedSLaurent Pinchart vsp1_entity_destroy(&lut->entity);
23642e89bedSLaurent Pinchart return ERR_PTR(ret);
23742e89bedSLaurent Pinchart }
23842e89bedSLaurent Pinchart
23942e89bedSLaurent Pinchart v4l2_ctrl_handler_setup(&lut->ctrls);
24042e89bedSLaurent Pinchart
241989af883SLaurent Pinchart return lut;
242989af883SLaurent Pinchart }
243