linux/drivers/media/platform/xilinx/xilinx-vip.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/*
   3 * Xilinx Video IP Core
   4 *
   5 * Copyright (C) 2013-2015 Ideas on Board
   6 * Copyright (C) 2013-2015 Xilinx, Inc.
   7 *
   8 * Contacts: Hyun Kwon <hyun.kwon@xilinx.com>
   9 *           Laurent Pinchart <laurent.pinchart@ideasonboard.com>
  10 */
  11
  12#include <linux/clk.h>
  13#include <linux/export.h>
  14#include <linux/kernel.h>
  15#include <linux/of.h>
  16#include <linux/platform_device.h>
  17
  18#include <dt-bindings/media/xilinx-vip.h>
  19
  20#include "xilinx-vip.h"
  21
  22/* -----------------------------------------------------------------------------
  23 * Helper functions
  24 */
  25
  26static const struct xvip_video_format xvip_video_formats[] = {
  27        { XVIP_VF_YUV_422, 8, NULL, MEDIA_BUS_FMT_UYVY8_1X16,
  28          2, V4L2_PIX_FMT_YUYV },
  29        { XVIP_VF_YUV_444, 8, NULL, MEDIA_BUS_FMT_VUY8_1X24,
  30          3, V4L2_PIX_FMT_YUV444 },
  31        { XVIP_VF_RBG, 8, NULL, MEDIA_BUS_FMT_RBG888_1X24,
  32          3, 0 },
  33        { XVIP_VF_MONO_SENSOR, 8, "mono", MEDIA_BUS_FMT_Y8_1X8,
  34          1, V4L2_PIX_FMT_GREY },
  35        { XVIP_VF_MONO_SENSOR, 8, "rggb", MEDIA_BUS_FMT_SRGGB8_1X8,
  36          1, V4L2_PIX_FMT_SRGGB8 },
  37        { XVIP_VF_MONO_SENSOR, 8, "grbg", MEDIA_BUS_FMT_SGRBG8_1X8,
  38          1, V4L2_PIX_FMT_SGRBG8 },
  39        { XVIP_VF_MONO_SENSOR, 8, "gbrg", MEDIA_BUS_FMT_SGBRG8_1X8,
  40          1, V4L2_PIX_FMT_SGBRG8 },
  41        { XVIP_VF_MONO_SENSOR, 8, "bggr", MEDIA_BUS_FMT_SBGGR8_1X8,
  42          1, V4L2_PIX_FMT_SBGGR8 },
  43};
  44
  45/**
  46 * xvip_get_format_by_code - Retrieve format information for a media bus code
  47 * @code: the format media bus code
  48 *
  49 * Return: a pointer to the format information structure corresponding to the
  50 * given V4L2 media bus format @code, or ERR_PTR if no corresponding format can
  51 * be found.
  52 */
  53const struct xvip_video_format *xvip_get_format_by_code(unsigned int code)
  54{
  55        unsigned int i;
  56
  57        for (i = 0; i < ARRAY_SIZE(xvip_video_formats); ++i) {
  58                const struct xvip_video_format *format = &xvip_video_formats[i];
  59
  60                if (format->code == code)
  61                        return format;
  62        }
  63
  64        return ERR_PTR(-EINVAL);
  65}
  66EXPORT_SYMBOL_GPL(xvip_get_format_by_code);
  67
  68/**
  69 * xvip_get_format_by_fourcc - Retrieve format information for a 4CC
  70 * @fourcc: the format 4CC
  71 *
  72 * Return: a pointer to the format information structure corresponding to the
  73 * given V4L2 format @fourcc. If not found, return a pointer to the first
  74 * available format (V4L2_PIX_FMT_YUYV).
  75 */
  76const struct xvip_video_format *xvip_get_format_by_fourcc(u32 fourcc)
  77{
  78        unsigned int i;
  79
  80        for (i = 0; i < ARRAY_SIZE(xvip_video_formats); ++i) {
  81                const struct xvip_video_format *format = &xvip_video_formats[i];
  82
  83                if (format->fourcc == fourcc)
  84                        return format;
  85        }
  86
  87        return &xvip_video_formats[0];
  88}
  89EXPORT_SYMBOL_GPL(xvip_get_format_by_fourcc);
  90
  91/**
  92 * xvip_of_get_format - Parse a device tree node and return format information
  93 * @node: the device tree node
  94 *
  95 * Read the xlnx,video-format, xlnx,video-width and xlnx,cfa-pattern properties
  96 * from the device tree @node passed as an argument and return the corresponding
  97 * format information.
  98 *
  99 * Return: a pointer to the format information structure corresponding to the
 100 * format name and width, or ERR_PTR if no corresponding format can be found.
 101 */
 102const struct xvip_video_format *xvip_of_get_format(struct device_node *node)
 103{
 104        const char *pattern = "mono";
 105        unsigned int vf_code;
 106        unsigned int i;
 107        u32 width;
 108        int ret;
 109
 110        ret = of_property_read_u32(node, "xlnx,video-format", &vf_code);
 111        if (ret < 0)
 112                return ERR_PTR(ret);
 113
 114        ret = of_property_read_u32(node, "xlnx,video-width", &width);
 115        if (ret < 0)
 116                return ERR_PTR(ret);
 117
 118        if (vf_code == XVIP_VF_MONO_SENSOR)
 119                of_property_read_string(node, "xlnx,cfa-pattern", &pattern);
 120
 121        for (i = 0; i < ARRAY_SIZE(xvip_video_formats); ++i) {
 122                const struct xvip_video_format *format = &xvip_video_formats[i];
 123
 124                if (format->vf_code != vf_code || format->width != width)
 125                        continue;
 126
 127                if (vf_code == XVIP_VF_MONO_SENSOR &&
 128                    strcmp(pattern, format->pattern))
 129                        continue;
 130
 131                return format;
 132        }
 133
 134        return ERR_PTR(-EINVAL);
 135}
 136EXPORT_SYMBOL_GPL(xvip_of_get_format);
 137
 138/**
 139 * xvip_set_format_size - Set the media bus frame format size
 140 * @format: V4L2 frame format on media bus
 141 * @fmt: media bus format
 142 *
 143 * Set the media bus frame format size. The width / height from the subdevice
 144 * format are set to the given media bus format. The new format size is stored
 145 * in @format. The width and height are clamped using default min / max values.
 146 */
 147void xvip_set_format_size(struct v4l2_mbus_framefmt *format,
 148                          const struct v4l2_subdev_format *fmt)
 149{
 150        format->width = clamp_t(unsigned int, fmt->format.width,
 151                                XVIP_MIN_WIDTH, XVIP_MAX_WIDTH);
 152        format->height = clamp_t(unsigned int, fmt->format.height,
 153                         XVIP_MIN_HEIGHT, XVIP_MAX_HEIGHT);
 154}
 155EXPORT_SYMBOL_GPL(xvip_set_format_size);
 156
 157/**
 158 * xvip_clr_or_set - Clear or set the register with a bitmask
 159 * @xvip: Xilinx Video IP device
 160 * @addr: address of register
 161 * @mask: bitmask to be set or cleared
 162 * @set: boolean flag indicating whether to set or clear
 163 *
 164 * Clear or set the register at address @addr with a bitmask @mask depending on
 165 * the boolean flag @set. When the flag @set is true, the bitmask is set in
 166 * the register, otherwise the bitmask is cleared from the register
 167 * when the flag @set is false.
 168 *
 169 * Fox example, this function can be used to set a control with a boolean value
 170 * requested by users. If the caller knows whether to set or clear in the first
 171 * place, the caller should call xvip_clr() or xvip_set() directly instead of
 172 * using this function.
 173 */
 174void xvip_clr_or_set(struct xvip_device *xvip, u32 addr, u32 mask, bool set)
 175{
 176        u32 reg;
 177
 178        reg = xvip_read(xvip, addr);
 179        reg = set ? reg | mask : reg & ~mask;
 180        xvip_write(xvip, addr, reg);
 181}
 182EXPORT_SYMBOL_GPL(xvip_clr_or_set);
 183
 184/**
 185 * xvip_clr_and_set - Clear and set the register with a bitmask
 186 * @xvip: Xilinx Video IP device
 187 * @addr: address of register
 188 * @clr: bitmask to be cleared
 189 * @set: bitmask to be set
 190 *
 191 * Clear a bit(s) of mask @clr in the register at address @addr, then set
 192 * a bit(s) of mask @set in the register after.
 193 */
 194void xvip_clr_and_set(struct xvip_device *xvip, u32 addr, u32 clr, u32 set)
 195{
 196        u32 reg;
 197
 198        reg = xvip_read(xvip, addr);
 199        reg &= ~clr;
 200        reg |= set;
 201        xvip_write(xvip, addr, reg);
 202}
 203EXPORT_SYMBOL_GPL(xvip_clr_and_set);
 204
 205int xvip_init_resources(struct xvip_device *xvip)
 206{
 207        struct platform_device *pdev = to_platform_device(xvip->dev);
 208        struct resource *res;
 209
 210        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 211        xvip->iomem = devm_ioremap_resource(xvip->dev, res);
 212        if (IS_ERR(xvip->iomem))
 213                return PTR_ERR(xvip->iomem);
 214
 215        xvip->clk = devm_clk_get(xvip->dev, NULL);
 216        if (IS_ERR(xvip->clk))
 217                return PTR_ERR(xvip->clk);
 218
 219        clk_prepare_enable(xvip->clk);
 220        return 0;
 221}
 222EXPORT_SYMBOL_GPL(xvip_init_resources);
 223
 224void xvip_cleanup_resources(struct xvip_device *xvip)
 225{
 226        clk_disable_unprepare(xvip->clk);
 227}
 228EXPORT_SYMBOL_GPL(xvip_cleanup_resources);
 229
 230/* -----------------------------------------------------------------------------
 231 * Subdev operations handlers
 232 */
 233
 234/**
 235 * xvip_enum_mbus_code - Enumerate the media format code
 236 * @subdev: V4L2 subdevice
 237 * @sd_state: V4L2 subdev state
 238 * @code: returning media bus code
 239 *
 240 * Enumerate the media bus code of the subdevice. Return the corresponding
 241 * pad format code. This function only works for subdevices with fixed format
 242 * on all pads. Subdevices with multiple format should have their own
 243 * function to enumerate mbus codes.
 244 *
 245 * Return: 0 if the media bus code is found, or -EINVAL if the format index
 246 * is not valid.
 247 */
 248int xvip_enum_mbus_code(struct v4l2_subdev *subdev,
 249                        struct v4l2_subdev_state *sd_state,
 250                        struct v4l2_subdev_mbus_code_enum *code)
 251{
 252        struct v4l2_mbus_framefmt *format;
 253
 254        /* Enumerating frame sizes based on the active configuration isn't
 255         * supported yet.
 256         */
 257        if (code->which == V4L2_SUBDEV_FORMAT_ACTIVE)
 258                return -EINVAL;
 259
 260        if (code->index)
 261                return -EINVAL;
 262
 263        format = v4l2_subdev_get_try_format(subdev, sd_state, code->pad);
 264
 265        code->code = format->code;
 266
 267        return 0;
 268}
 269EXPORT_SYMBOL_GPL(xvip_enum_mbus_code);
 270
 271/**
 272 * xvip_enum_frame_size - Enumerate the media bus frame size
 273 * @subdev: V4L2 subdevice
 274 * @sd_state: V4L2 subdev state
 275 * @fse: returning media bus frame size
 276 *
 277 * This function is a drop-in implementation of the subdev enum_frame_size pad
 278 * operation. It assumes that the subdevice has one sink pad and one source
 279 * pad, and that the format on the source pad is always identical to the
 280 * format on the sink pad. Entities with different requirements need to
 281 * implement their own enum_frame_size handlers.
 282 *
 283 * Return: 0 if the media bus frame size is found, or -EINVAL
 284 * if the index or the code is not valid.
 285 */
 286int xvip_enum_frame_size(struct v4l2_subdev *subdev,
 287                         struct v4l2_subdev_state *sd_state,
 288                         struct v4l2_subdev_frame_size_enum *fse)
 289{
 290        struct v4l2_mbus_framefmt *format;
 291
 292        /* Enumerating frame sizes based on the active configuration isn't
 293         * supported yet.
 294         */
 295        if (fse->which == V4L2_SUBDEV_FORMAT_ACTIVE)
 296                return -EINVAL;
 297
 298        format = v4l2_subdev_get_try_format(subdev, sd_state, fse->pad);
 299
 300        if (fse->index || fse->code != format->code)
 301                return -EINVAL;
 302
 303        if (fse->pad == XVIP_PAD_SINK) {
 304                fse->min_width = XVIP_MIN_WIDTH;
 305                fse->max_width = XVIP_MAX_WIDTH;
 306                fse->min_height = XVIP_MIN_HEIGHT;
 307                fse->max_height = XVIP_MAX_HEIGHT;
 308        } else {
 309                /* The size on the source pad is fixed and always identical to
 310                 * the size on the sink pad.
 311                 */
 312                fse->min_width = format->width;
 313                fse->max_width = format->width;
 314                fse->min_height = format->height;
 315                fse->max_height = format->height;
 316        }
 317
 318        return 0;
 319}
 320EXPORT_SYMBOL_GPL(xvip_enum_frame_size);
 321