linux/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0+
   2/*
   3 * Copyright (c) 2011-2018 Magewell Electronics Co., Ltd. (Nanjing)
   4 * All rights reserved.
   5 * Author: Yong Deng <yong.deng@magewell.com>
   6 */
   7
   8#include <linux/clk.h>
   9#include <linux/delay.h>
  10#include <linux/dma-mapping.h>
  11#include <linux/err.h>
  12#include <linux/fs.h>
  13#include <linux/interrupt.h>
  14#include <linux/io.h>
  15#include <linux/ioctl.h>
  16#include <linux/module.h>
  17#include <linux/of.h>
  18#include <linux/of_device.h>
  19#include <linux/platform_device.h>
  20#include <linux/pm_runtime.h>
  21#include <linux/regmap.h>
  22#include <linux/reset.h>
  23#include <linux/sched.h>
  24#include <linux/sizes.h>
  25#include <linux/slab.h>
  26
  27#include "sun6i_csi.h"
  28#include "sun6i_csi_reg.h"
  29
  30#define MODULE_NAME     "sun6i-csi"
  31
  32struct sun6i_csi_dev {
  33        struct sun6i_csi                csi;
  34        struct device                   *dev;
  35
  36        struct regmap                   *regmap;
  37        struct clk                      *clk_mod;
  38        struct clk                      *clk_ram;
  39        struct reset_control            *rstc_bus;
  40
  41        int                             planar_offset[3];
  42};
  43
  44static inline struct sun6i_csi_dev *sun6i_csi_to_dev(struct sun6i_csi *csi)
  45{
  46        return container_of(csi, struct sun6i_csi_dev, csi);
  47}
  48
  49/* TODO add 10&12 bit YUV, RGB support */
  50bool sun6i_csi_is_format_supported(struct sun6i_csi *csi,
  51                                   u32 pixformat, u32 mbus_code)
  52{
  53        struct sun6i_csi_dev *sdev = sun6i_csi_to_dev(csi);
  54
  55        /*
  56         * Some video receivers have the ability to be compatible with
  57         * 8bit and 16bit bus width.
  58         * Identify the media bus format from device tree.
  59         */
  60        if ((sdev->csi.v4l2_ep.bus_type == V4L2_MBUS_PARALLEL
  61             || sdev->csi.v4l2_ep.bus_type == V4L2_MBUS_BT656)
  62             && sdev->csi.v4l2_ep.bus.parallel.bus_width == 16) {
  63                switch (pixformat) {
  64                case V4L2_PIX_FMT_HM12:
  65                case V4L2_PIX_FMT_NV12:
  66                case V4L2_PIX_FMT_NV21:
  67                case V4L2_PIX_FMT_NV16:
  68                case V4L2_PIX_FMT_NV61:
  69                case V4L2_PIX_FMT_YUV420:
  70                case V4L2_PIX_FMT_YVU420:
  71                case V4L2_PIX_FMT_YUV422P:
  72                        switch (mbus_code) {
  73                        case MEDIA_BUS_FMT_UYVY8_1X16:
  74                        case MEDIA_BUS_FMT_VYUY8_1X16:
  75                        case MEDIA_BUS_FMT_YUYV8_1X16:
  76                        case MEDIA_BUS_FMT_YVYU8_1X16:
  77                                return true;
  78                        default:
  79                                dev_dbg(sdev->dev, "Unsupported mbus code: 0x%x\n",
  80                                        mbus_code);
  81                                break;
  82                        }
  83                        break;
  84                default:
  85                        dev_dbg(sdev->dev, "Unsupported pixformat: 0x%x\n",
  86                                pixformat);
  87                        break;
  88                }
  89                return false;
  90        }
  91
  92        switch (pixformat) {
  93        case V4L2_PIX_FMT_SBGGR8:
  94                return (mbus_code == MEDIA_BUS_FMT_SBGGR8_1X8);
  95        case V4L2_PIX_FMT_SGBRG8:
  96                return (mbus_code == MEDIA_BUS_FMT_SGBRG8_1X8);
  97        case V4L2_PIX_FMT_SGRBG8:
  98                return (mbus_code == MEDIA_BUS_FMT_SGRBG8_1X8);
  99        case V4L2_PIX_FMT_SRGGB8:
 100                return (mbus_code == MEDIA_BUS_FMT_SRGGB8_1X8);
 101        case V4L2_PIX_FMT_SBGGR10:
 102                return (mbus_code == MEDIA_BUS_FMT_SBGGR10_1X10);
 103        case V4L2_PIX_FMT_SGBRG10:
 104                return (mbus_code == MEDIA_BUS_FMT_SGBRG10_1X10);
 105        case V4L2_PIX_FMT_SGRBG10:
 106                return (mbus_code == MEDIA_BUS_FMT_SGRBG10_1X10);
 107        case V4L2_PIX_FMT_SRGGB10:
 108                return (mbus_code == MEDIA_BUS_FMT_SRGGB10_1X10);
 109        case V4L2_PIX_FMT_SBGGR12:
 110                return (mbus_code == MEDIA_BUS_FMT_SBGGR12_1X12);
 111        case V4L2_PIX_FMT_SGBRG12:
 112                return (mbus_code == MEDIA_BUS_FMT_SGBRG12_1X12);
 113        case V4L2_PIX_FMT_SGRBG12:
 114                return (mbus_code == MEDIA_BUS_FMT_SGRBG12_1X12);
 115        case V4L2_PIX_FMT_SRGGB12:
 116                return (mbus_code == MEDIA_BUS_FMT_SRGGB12_1X12);
 117
 118        case V4L2_PIX_FMT_YUYV:
 119                return (mbus_code == MEDIA_BUS_FMT_YUYV8_2X8);
 120        case V4L2_PIX_FMT_YVYU:
 121                return (mbus_code == MEDIA_BUS_FMT_YVYU8_2X8);
 122        case V4L2_PIX_FMT_UYVY:
 123                return (mbus_code == MEDIA_BUS_FMT_UYVY8_2X8);
 124        case V4L2_PIX_FMT_VYUY:
 125                return (mbus_code == MEDIA_BUS_FMT_VYUY8_2X8);
 126
 127        case V4L2_PIX_FMT_HM12:
 128        case V4L2_PIX_FMT_NV12:
 129        case V4L2_PIX_FMT_NV21:
 130        case V4L2_PIX_FMT_NV16:
 131        case V4L2_PIX_FMT_NV61:
 132        case V4L2_PIX_FMT_YUV420:
 133        case V4L2_PIX_FMT_YVU420:
 134        case V4L2_PIX_FMT_YUV422P:
 135                switch (mbus_code) {
 136                case MEDIA_BUS_FMT_UYVY8_2X8:
 137                case MEDIA_BUS_FMT_VYUY8_2X8:
 138                case MEDIA_BUS_FMT_YUYV8_2X8:
 139                case MEDIA_BUS_FMT_YVYU8_2X8:
 140                        return true;
 141                default:
 142                        dev_dbg(sdev->dev, "Unsupported mbus code: 0x%x\n",
 143                                mbus_code);
 144                        break;
 145                }
 146                break;
 147
 148        case V4L2_PIX_FMT_RGB565:
 149                return (mbus_code == MEDIA_BUS_FMT_RGB565_2X8_LE);
 150        case V4L2_PIX_FMT_RGB565X:
 151                return (mbus_code == MEDIA_BUS_FMT_RGB565_2X8_BE);
 152
 153        case V4L2_PIX_FMT_JPEG:
 154                return (mbus_code == MEDIA_BUS_FMT_JPEG_1X8);
 155
 156        default:
 157                dev_dbg(sdev->dev, "Unsupported pixformat: 0x%x\n", pixformat);
 158                break;
 159        }
 160
 161        return false;
 162}
 163
 164int sun6i_csi_set_power(struct sun6i_csi *csi, bool enable)
 165{
 166        struct sun6i_csi_dev *sdev = sun6i_csi_to_dev(csi);
 167        struct device *dev = sdev->dev;
 168        struct regmap *regmap = sdev->regmap;
 169        int ret;
 170
 171        if (!enable) {
 172                regmap_update_bits(regmap, CSI_EN_REG, CSI_EN_CSI_EN, 0);
 173
 174                clk_disable_unprepare(sdev->clk_ram);
 175                if (of_device_is_compatible(dev->of_node,
 176                                            "allwinner,sun50i-a64-csi"))
 177                        clk_rate_exclusive_put(sdev->clk_mod);
 178                clk_disable_unprepare(sdev->clk_mod);
 179                reset_control_assert(sdev->rstc_bus);
 180                return 0;
 181        }
 182
 183        ret = clk_prepare_enable(sdev->clk_mod);
 184        if (ret) {
 185                dev_err(sdev->dev, "Enable csi clk err %d\n", ret);
 186                return ret;
 187        }
 188
 189        if (of_device_is_compatible(dev->of_node, "allwinner,sun50i-a64-csi"))
 190                clk_set_rate_exclusive(sdev->clk_mod, 300000000);
 191
 192        ret = clk_prepare_enable(sdev->clk_ram);
 193        if (ret) {
 194                dev_err(sdev->dev, "Enable clk_dram_csi clk err %d\n", ret);
 195                goto clk_mod_disable;
 196        }
 197
 198        ret = reset_control_deassert(sdev->rstc_bus);
 199        if (ret) {
 200                dev_err(sdev->dev, "reset err %d\n", ret);
 201                goto clk_ram_disable;
 202        }
 203
 204        regmap_update_bits(regmap, CSI_EN_REG, CSI_EN_CSI_EN, CSI_EN_CSI_EN);
 205
 206        return 0;
 207
 208clk_ram_disable:
 209        clk_disable_unprepare(sdev->clk_ram);
 210clk_mod_disable:
 211        if (of_device_is_compatible(dev->of_node, "allwinner,sun50i-a64-csi"))
 212                clk_rate_exclusive_put(sdev->clk_mod);
 213        clk_disable_unprepare(sdev->clk_mod);
 214        return ret;
 215}
 216
 217static enum csi_input_fmt get_csi_input_format(struct sun6i_csi_dev *sdev,
 218                                               u32 mbus_code, u32 pixformat)
 219{
 220        /* non-YUV */
 221        if ((mbus_code & 0xF000) != 0x2000)
 222                return CSI_INPUT_FORMAT_RAW;
 223
 224        switch (pixformat) {
 225        case V4L2_PIX_FMT_YUYV:
 226        case V4L2_PIX_FMT_YVYU:
 227        case V4L2_PIX_FMT_UYVY:
 228        case V4L2_PIX_FMT_VYUY:
 229                return CSI_INPUT_FORMAT_RAW;
 230        default:
 231                break;
 232        }
 233
 234        /* not support YUV420 input format yet */
 235        dev_dbg(sdev->dev, "Select YUV422 as default input format of CSI.\n");
 236        return CSI_INPUT_FORMAT_YUV422;
 237}
 238
 239static enum csi_output_fmt get_csi_output_format(struct sun6i_csi_dev *sdev,
 240                                                 u32 pixformat, u32 field)
 241{
 242        bool buf_interlaced = false;
 243
 244        if (field == V4L2_FIELD_INTERLACED
 245            || field == V4L2_FIELD_INTERLACED_TB
 246            || field == V4L2_FIELD_INTERLACED_BT)
 247                buf_interlaced = true;
 248
 249        switch (pixformat) {
 250        case V4L2_PIX_FMT_SBGGR8:
 251        case V4L2_PIX_FMT_SGBRG8:
 252        case V4L2_PIX_FMT_SGRBG8:
 253        case V4L2_PIX_FMT_SRGGB8:
 254                return buf_interlaced ? CSI_FRAME_RAW_8 : CSI_FIELD_RAW_8;
 255        case V4L2_PIX_FMT_SBGGR10:
 256        case V4L2_PIX_FMT_SGBRG10:
 257        case V4L2_PIX_FMT_SGRBG10:
 258        case V4L2_PIX_FMT_SRGGB10:
 259                return buf_interlaced ? CSI_FRAME_RAW_10 : CSI_FIELD_RAW_10;
 260        case V4L2_PIX_FMT_SBGGR12:
 261        case V4L2_PIX_FMT_SGBRG12:
 262        case V4L2_PIX_FMT_SGRBG12:
 263        case V4L2_PIX_FMT_SRGGB12:
 264                return buf_interlaced ? CSI_FRAME_RAW_12 : CSI_FIELD_RAW_12;
 265
 266        case V4L2_PIX_FMT_YUYV:
 267        case V4L2_PIX_FMT_YVYU:
 268        case V4L2_PIX_FMT_UYVY:
 269        case V4L2_PIX_FMT_VYUY:
 270                return buf_interlaced ? CSI_FRAME_RAW_8 : CSI_FIELD_RAW_8;
 271
 272        case V4L2_PIX_FMT_HM12:
 273                return buf_interlaced ? CSI_FRAME_MB_YUV420 :
 274                                        CSI_FIELD_MB_YUV420;
 275        case V4L2_PIX_FMT_NV12:
 276        case V4L2_PIX_FMT_NV21:
 277                return buf_interlaced ? CSI_FRAME_UV_CB_YUV420 :
 278                                        CSI_FIELD_UV_CB_YUV420;
 279        case V4L2_PIX_FMT_YUV420:
 280        case V4L2_PIX_FMT_YVU420:
 281                return buf_interlaced ? CSI_FRAME_PLANAR_YUV420 :
 282                                        CSI_FIELD_PLANAR_YUV420;
 283        case V4L2_PIX_FMT_NV16:
 284        case V4L2_PIX_FMT_NV61:
 285                return buf_interlaced ? CSI_FRAME_UV_CB_YUV422 :
 286                                        CSI_FIELD_UV_CB_YUV422;
 287        case V4L2_PIX_FMT_YUV422P:
 288                return buf_interlaced ? CSI_FRAME_PLANAR_YUV422 :
 289                                        CSI_FIELD_PLANAR_YUV422;
 290
 291        case V4L2_PIX_FMT_RGB565:
 292        case V4L2_PIX_FMT_RGB565X:
 293                return buf_interlaced ? CSI_FRAME_RGB565 : CSI_FIELD_RGB565;
 294
 295        case V4L2_PIX_FMT_JPEG:
 296                return buf_interlaced ? CSI_FRAME_RAW_8 : CSI_FIELD_RAW_8;
 297
 298        default:
 299                dev_warn(sdev->dev, "Unsupported pixformat: 0x%x\n", pixformat);
 300                break;
 301        }
 302
 303        return CSI_FIELD_RAW_8;
 304}
 305
 306static enum csi_input_seq get_csi_input_seq(struct sun6i_csi_dev *sdev,
 307                                            u32 mbus_code, u32 pixformat)
 308{
 309        /* Input sequence does not apply to non-YUV formats */
 310        if ((mbus_code & 0xF000) != 0x2000)
 311                return 0;
 312
 313        switch (pixformat) {
 314        case V4L2_PIX_FMT_HM12:
 315        case V4L2_PIX_FMT_NV12:
 316        case V4L2_PIX_FMT_NV16:
 317        case V4L2_PIX_FMT_YUV420:
 318        case V4L2_PIX_FMT_YUV422P:
 319                switch (mbus_code) {
 320                case MEDIA_BUS_FMT_UYVY8_2X8:
 321                case MEDIA_BUS_FMT_UYVY8_1X16:
 322                        return CSI_INPUT_SEQ_UYVY;
 323                case MEDIA_BUS_FMT_VYUY8_2X8:
 324                case MEDIA_BUS_FMT_VYUY8_1X16:
 325                        return CSI_INPUT_SEQ_VYUY;
 326                case MEDIA_BUS_FMT_YUYV8_2X8:
 327                case MEDIA_BUS_FMT_YUYV8_1X16:
 328                        return CSI_INPUT_SEQ_YUYV;
 329                case MEDIA_BUS_FMT_YVYU8_1X16:
 330                case MEDIA_BUS_FMT_YVYU8_2X8:
 331                        return CSI_INPUT_SEQ_YVYU;
 332                default:
 333                        dev_warn(sdev->dev, "Unsupported mbus code: 0x%x\n",
 334                                 mbus_code);
 335                        break;
 336                }
 337                break;
 338        case V4L2_PIX_FMT_NV21:
 339        case V4L2_PIX_FMT_NV61:
 340        case V4L2_PIX_FMT_YVU420:
 341                switch (mbus_code) {
 342                case MEDIA_BUS_FMT_UYVY8_2X8:
 343                case MEDIA_BUS_FMT_UYVY8_1X16:
 344                        return CSI_INPUT_SEQ_VYUY;
 345                case MEDIA_BUS_FMT_VYUY8_2X8:
 346                case MEDIA_BUS_FMT_VYUY8_1X16:
 347                        return CSI_INPUT_SEQ_UYVY;
 348                case MEDIA_BUS_FMT_YUYV8_2X8:
 349                case MEDIA_BUS_FMT_YUYV8_1X16:
 350                        return CSI_INPUT_SEQ_YVYU;
 351                case MEDIA_BUS_FMT_YVYU8_1X16:
 352                case MEDIA_BUS_FMT_YVYU8_2X8:
 353                        return CSI_INPUT_SEQ_YUYV;
 354                default:
 355                        dev_warn(sdev->dev, "Unsupported mbus code: 0x%x\n",
 356                                 mbus_code);
 357                        break;
 358                }
 359                break;
 360
 361        case V4L2_PIX_FMT_YUYV:
 362                return CSI_INPUT_SEQ_YUYV;
 363
 364        default:
 365                dev_warn(sdev->dev, "Unsupported pixformat: 0x%x, defaulting to YUYV\n",
 366                         pixformat);
 367                break;
 368        }
 369
 370        return CSI_INPUT_SEQ_YUYV;
 371}
 372
 373static void sun6i_csi_setup_bus(struct sun6i_csi_dev *sdev)
 374{
 375        struct v4l2_fwnode_endpoint *endpoint = &sdev->csi.v4l2_ep;
 376        struct sun6i_csi *csi = &sdev->csi;
 377        unsigned char bus_width;
 378        u32 flags;
 379        u32 cfg;
 380        bool input_interlaced = false;
 381
 382        if (csi->config.field == V4L2_FIELD_INTERLACED
 383            || csi->config.field == V4L2_FIELD_INTERLACED_TB
 384            || csi->config.field == V4L2_FIELD_INTERLACED_BT)
 385                input_interlaced = true;
 386
 387        bus_width = endpoint->bus.parallel.bus_width;
 388
 389        regmap_read(sdev->regmap, CSI_IF_CFG_REG, &cfg);
 390
 391        cfg &= ~(CSI_IF_CFG_CSI_IF_MASK | CSI_IF_CFG_MIPI_IF_MASK |
 392                 CSI_IF_CFG_IF_DATA_WIDTH_MASK |
 393                 CSI_IF_CFG_CLK_POL_MASK | CSI_IF_CFG_VREF_POL_MASK |
 394                 CSI_IF_CFG_HREF_POL_MASK | CSI_IF_CFG_FIELD_MASK |
 395                 CSI_IF_CFG_SRC_TYPE_MASK);
 396
 397        if (input_interlaced)
 398                cfg |= CSI_IF_CFG_SRC_TYPE_INTERLACED;
 399        else
 400                cfg |= CSI_IF_CFG_SRC_TYPE_PROGRESSED;
 401
 402        switch (endpoint->bus_type) {
 403        case V4L2_MBUS_PARALLEL:
 404                cfg |= CSI_IF_CFG_MIPI_IF_CSI;
 405
 406                flags = endpoint->bus.parallel.flags;
 407
 408                cfg |= (bus_width == 16) ? CSI_IF_CFG_CSI_IF_YUV422_16BIT :
 409                                           CSI_IF_CFG_CSI_IF_YUV422_INTLV;
 410
 411                if (flags & V4L2_MBUS_FIELD_EVEN_LOW)
 412                        cfg |= CSI_IF_CFG_FIELD_POSITIVE;
 413
 414                if (flags & V4L2_MBUS_VSYNC_ACTIVE_LOW)
 415                        cfg |= CSI_IF_CFG_VREF_POL_POSITIVE;
 416                if (flags & V4L2_MBUS_HSYNC_ACTIVE_LOW)
 417                        cfg |= CSI_IF_CFG_HREF_POL_POSITIVE;
 418
 419                if (flags & V4L2_MBUS_PCLK_SAMPLE_RISING)
 420                        cfg |= CSI_IF_CFG_CLK_POL_FALLING_EDGE;
 421                break;
 422        case V4L2_MBUS_BT656:
 423                cfg |= CSI_IF_CFG_MIPI_IF_CSI;
 424
 425                flags = endpoint->bus.parallel.flags;
 426
 427                cfg |= (bus_width == 16) ? CSI_IF_CFG_CSI_IF_BT1120 :
 428                                           CSI_IF_CFG_CSI_IF_BT656;
 429
 430                if (flags & V4L2_MBUS_FIELD_EVEN_LOW)
 431                        cfg |= CSI_IF_CFG_FIELD_POSITIVE;
 432
 433                if (flags & V4L2_MBUS_PCLK_SAMPLE_FALLING)
 434                        cfg |= CSI_IF_CFG_CLK_POL_FALLING_EDGE;
 435                break;
 436        default:
 437                dev_warn(sdev->dev, "Unsupported bus type: %d\n",
 438                         endpoint->bus_type);
 439                break;
 440        }
 441
 442        switch (bus_width) {
 443        case 8:
 444                cfg |= CSI_IF_CFG_IF_DATA_WIDTH_8BIT;
 445                break;
 446        case 10:
 447                cfg |= CSI_IF_CFG_IF_DATA_WIDTH_10BIT;
 448                break;
 449        case 12:
 450                cfg |= CSI_IF_CFG_IF_DATA_WIDTH_12BIT;
 451                break;
 452        case 16: /* No need to configure DATA_WIDTH for 16bit */
 453                break;
 454        default:
 455                dev_warn(sdev->dev, "Unsupported bus width: %u\n", bus_width);
 456                break;
 457        }
 458
 459        regmap_write(sdev->regmap, CSI_IF_CFG_REG, cfg);
 460}
 461
 462static void sun6i_csi_set_format(struct sun6i_csi_dev *sdev)
 463{
 464        struct sun6i_csi *csi = &sdev->csi;
 465        u32 cfg;
 466        u32 val;
 467
 468        regmap_read(sdev->regmap, CSI_CH_CFG_REG, &cfg);
 469
 470        cfg &= ~(CSI_CH_CFG_INPUT_FMT_MASK |
 471                 CSI_CH_CFG_OUTPUT_FMT_MASK | CSI_CH_CFG_VFLIP_EN |
 472                 CSI_CH_CFG_HFLIP_EN | CSI_CH_CFG_FIELD_SEL_MASK |
 473                 CSI_CH_CFG_INPUT_SEQ_MASK);
 474
 475        val = get_csi_input_format(sdev, csi->config.code,
 476                                   csi->config.pixelformat);
 477        cfg |= CSI_CH_CFG_INPUT_FMT(val);
 478
 479        val = get_csi_output_format(sdev, csi->config.pixelformat,
 480                                    csi->config.field);
 481        cfg |= CSI_CH_CFG_OUTPUT_FMT(val);
 482
 483        val = get_csi_input_seq(sdev, csi->config.code,
 484                                csi->config.pixelformat);
 485        cfg |= CSI_CH_CFG_INPUT_SEQ(val);
 486
 487        if (csi->config.field == V4L2_FIELD_TOP)
 488                cfg |= CSI_CH_CFG_FIELD_SEL_FIELD0;
 489        else if (csi->config.field == V4L2_FIELD_BOTTOM)
 490                cfg |= CSI_CH_CFG_FIELD_SEL_FIELD1;
 491        else
 492                cfg |= CSI_CH_CFG_FIELD_SEL_BOTH;
 493
 494        regmap_write(sdev->regmap, CSI_CH_CFG_REG, cfg);
 495}
 496
 497static void sun6i_csi_set_window(struct sun6i_csi_dev *sdev)
 498{
 499        struct sun6i_csi_config *config = &sdev->csi.config;
 500        u32 bytesperline_y;
 501        u32 bytesperline_c;
 502        int *planar_offset = sdev->planar_offset;
 503        u32 width = config->width;
 504        u32 height = config->height;
 505        u32 hor_len = width;
 506
 507        switch (config->pixelformat) {
 508        case V4L2_PIX_FMT_YUYV:
 509        case V4L2_PIX_FMT_YVYU:
 510        case V4L2_PIX_FMT_UYVY:
 511        case V4L2_PIX_FMT_VYUY:
 512                dev_dbg(sdev->dev,
 513                        "Horizontal length should be 2 times of width for packed YUV formats!\n");
 514                hor_len = width * 2;
 515                break;
 516        default:
 517                break;
 518        }
 519
 520        regmap_write(sdev->regmap, CSI_CH_HSIZE_REG,
 521                     CSI_CH_HSIZE_HOR_LEN(hor_len) |
 522                     CSI_CH_HSIZE_HOR_START(0));
 523        regmap_write(sdev->regmap, CSI_CH_VSIZE_REG,
 524                     CSI_CH_VSIZE_VER_LEN(height) |
 525                     CSI_CH_VSIZE_VER_START(0));
 526
 527        planar_offset[0] = 0;
 528        switch (config->pixelformat) {
 529        case V4L2_PIX_FMT_HM12:
 530        case V4L2_PIX_FMT_NV12:
 531        case V4L2_PIX_FMT_NV21:
 532        case V4L2_PIX_FMT_NV16:
 533        case V4L2_PIX_FMT_NV61:
 534                bytesperline_y = width;
 535                bytesperline_c = width;
 536                planar_offset[1] = bytesperline_y * height;
 537                planar_offset[2] = -1;
 538                break;
 539        case V4L2_PIX_FMT_YUV420:
 540        case V4L2_PIX_FMT_YVU420:
 541                bytesperline_y = width;
 542                bytesperline_c = width / 2;
 543                planar_offset[1] = bytesperline_y * height;
 544                planar_offset[2] = planar_offset[1] +
 545                                bytesperline_c * height / 2;
 546                break;
 547        case V4L2_PIX_FMT_YUV422P:
 548                bytesperline_y = width;
 549                bytesperline_c = width / 2;
 550                planar_offset[1] = bytesperline_y * height;
 551                planar_offset[2] = planar_offset[1] +
 552                                bytesperline_c * height;
 553                break;
 554        default: /* raw */
 555                dev_dbg(sdev->dev,
 556                        "Calculating pixelformat(0x%x)'s bytesperline as a packed format\n",
 557                        config->pixelformat);
 558                bytesperline_y = (sun6i_csi_get_bpp(config->pixelformat) *
 559                                  config->width) / 8;
 560                bytesperline_c = 0;
 561                planar_offset[1] = -1;
 562                planar_offset[2] = -1;
 563                break;
 564        }
 565
 566        regmap_write(sdev->regmap, CSI_CH_BUF_LEN_REG,
 567                     CSI_CH_BUF_LEN_BUF_LEN_C(bytesperline_c) |
 568                     CSI_CH_BUF_LEN_BUF_LEN_Y(bytesperline_y));
 569}
 570
 571int sun6i_csi_update_config(struct sun6i_csi *csi,
 572                            struct sun6i_csi_config *config)
 573{
 574        struct sun6i_csi_dev *sdev = sun6i_csi_to_dev(csi);
 575
 576        if (!config)
 577                return -EINVAL;
 578
 579        memcpy(&csi->config, config, sizeof(csi->config));
 580
 581        sun6i_csi_setup_bus(sdev);
 582        sun6i_csi_set_format(sdev);
 583        sun6i_csi_set_window(sdev);
 584
 585        return 0;
 586}
 587
 588void sun6i_csi_update_buf_addr(struct sun6i_csi *csi, dma_addr_t addr)
 589{
 590        struct sun6i_csi_dev *sdev = sun6i_csi_to_dev(csi);
 591
 592        regmap_write(sdev->regmap, CSI_CH_F0_BUFA_REG,
 593                     (addr + sdev->planar_offset[0]) >> 2);
 594        if (sdev->planar_offset[1] != -1)
 595                regmap_write(sdev->regmap, CSI_CH_F1_BUFA_REG,
 596                             (addr + sdev->planar_offset[1]) >> 2);
 597        if (sdev->planar_offset[2] != -1)
 598                regmap_write(sdev->regmap, CSI_CH_F2_BUFA_REG,
 599                             (addr + sdev->planar_offset[2]) >> 2);
 600}
 601
 602void sun6i_csi_set_stream(struct sun6i_csi *csi, bool enable)
 603{
 604        struct sun6i_csi_dev *sdev = sun6i_csi_to_dev(csi);
 605        struct regmap *regmap = sdev->regmap;
 606
 607        if (!enable) {
 608                regmap_update_bits(regmap, CSI_CAP_REG, CSI_CAP_CH0_VCAP_ON, 0);
 609                regmap_write(regmap, CSI_CH_INT_EN_REG, 0);
 610                return;
 611        }
 612
 613        regmap_write(regmap, CSI_CH_INT_STA_REG, 0xFF);
 614        regmap_write(regmap, CSI_CH_INT_EN_REG,
 615                     CSI_CH_INT_EN_HB_OF_INT_EN |
 616                     CSI_CH_INT_EN_FIFO2_OF_INT_EN |
 617                     CSI_CH_INT_EN_FIFO1_OF_INT_EN |
 618                     CSI_CH_INT_EN_FIFO0_OF_INT_EN |
 619                     CSI_CH_INT_EN_FD_INT_EN |
 620                     CSI_CH_INT_EN_CD_INT_EN);
 621
 622        regmap_update_bits(regmap, CSI_CAP_REG, CSI_CAP_CH0_VCAP_ON,
 623                           CSI_CAP_CH0_VCAP_ON);
 624}
 625
 626/* -----------------------------------------------------------------------------
 627 * Media Controller and V4L2
 628 */
 629static int sun6i_csi_link_entity(struct sun6i_csi *csi,
 630                                 struct media_entity *entity,
 631                                 struct fwnode_handle *fwnode)
 632{
 633        struct media_entity *sink;
 634        struct media_pad *sink_pad;
 635        int src_pad_index;
 636        int ret;
 637
 638        ret = media_entity_get_fwnode_pad(entity, fwnode, MEDIA_PAD_FL_SOURCE);
 639        if (ret < 0) {
 640                dev_err(csi->dev, "%s: no source pad in external entity %s\n",
 641                        __func__, entity->name);
 642                return -EINVAL;
 643        }
 644
 645        src_pad_index = ret;
 646
 647        sink = &csi->video.vdev.entity;
 648        sink_pad = &csi->video.pad;
 649
 650        dev_dbg(csi->dev, "creating %s:%u -> %s:%u link\n",
 651                entity->name, src_pad_index, sink->name, sink_pad->index);
 652        ret = media_create_pad_link(entity, src_pad_index, sink,
 653                                    sink_pad->index,
 654                                    MEDIA_LNK_FL_ENABLED |
 655                                    MEDIA_LNK_FL_IMMUTABLE);
 656        if (ret < 0) {
 657                dev_err(csi->dev, "failed to create %s:%u -> %s:%u link\n",
 658                        entity->name, src_pad_index,
 659                        sink->name, sink_pad->index);
 660                return ret;
 661        }
 662
 663        return 0;
 664}
 665
 666static int sun6i_subdev_notify_complete(struct v4l2_async_notifier *notifier)
 667{
 668        struct sun6i_csi *csi = container_of(notifier, struct sun6i_csi,
 669                                             notifier);
 670        struct v4l2_device *v4l2_dev = &csi->v4l2_dev;
 671        struct v4l2_subdev *sd;
 672        int ret;
 673
 674        dev_dbg(csi->dev, "notify complete, all subdevs registered\n");
 675
 676        sd = list_first_entry(&v4l2_dev->subdevs, struct v4l2_subdev, list);
 677        if (!sd)
 678                return -EINVAL;
 679
 680        ret = sun6i_csi_link_entity(csi, &sd->entity, sd->fwnode);
 681        if (ret < 0)
 682                return ret;
 683
 684        ret = v4l2_device_register_subdev_nodes(&csi->v4l2_dev);
 685        if (ret < 0)
 686                return ret;
 687
 688        return media_device_register(&csi->media_dev);
 689}
 690
 691static const struct v4l2_async_notifier_operations sun6i_csi_async_ops = {
 692        .complete = sun6i_subdev_notify_complete,
 693};
 694
 695static int sun6i_csi_fwnode_parse(struct device *dev,
 696                                  struct v4l2_fwnode_endpoint *vep,
 697                                  struct v4l2_async_subdev *asd)
 698{
 699        struct sun6i_csi *csi = dev_get_drvdata(dev);
 700
 701        if (vep->base.port || vep->base.id) {
 702                dev_warn(dev, "Only support a single port with one endpoint\n");
 703                return -ENOTCONN;
 704        }
 705
 706        switch (vep->bus_type) {
 707        case V4L2_MBUS_PARALLEL:
 708        case V4L2_MBUS_BT656:
 709                csi->v4l2_ep = *vep;
 710                return 0;
 711        default:
 712                dev_err(dev, "Unsupported media bus type\n");
 713                return -ENOTCONN;
 714        }
 715}
 716
 717static void sun6i_csi_v4l2_cleanup(struct sun6i_csi *csi)
 718{
 719        media_device_unregister(&csi->media_dev);
 720        v4l2_async_notifier_unregister(&csi->notifier);
 721        v4l2_async_notifier_cleanup(&csi->notifier);
 722        sun6i_video_cleanup(&csi->video);
 723        v4l2_device_unregister(&csi->v4l2_dev);
 724        v4l2_ctrl_handler_free(&csi->ctrl_handler);
 725        media_device_cleanup(&csi->media_dev);
 726}
 727
 728static int sun6i_csi_v4l2_init(struct sun6i_csi *csi)
 729{
 730        int ret;
 731
 732        csi->media_dev.dev = csi->dev;
 733        strscpy(csi->media_dev.model, "Allwinner Video Capture Device",
 734                sizeof(csi->media_dev.model));
 735        csi->media_dev.hw_revision = 0;
 736        snprintf(csi->media_dev.bus_info, sizeof(csi->media_dev.bus_info),
 737                 "platform:%s", dev_name(csi->dev));
 738
 739        media_device_init(&csi->media_dev);
 740        v4l2_async_notifier_init(&csi->notifier);
 741
 742        ret = v4l2_ctrl_handler_init(&csi->ctrl_handler, 0);
 743        if (ret) {
 744                dev_err(csi->dev, "V4L2 controls handler init failed (%d)\n",
 745                        ret);
 746                goto clean_media;
 747        }
 748
 749        csi->v4l2_dev.mdev = &csi->media_dev;
 750        csi->v4l2_dev.ctrl_handler = &csi->ctrl_handler;
 751        ret = v4l2_device_register(csi->dev, &csi->v4l2_dev);
 752        if (ret) {
 753                dev_err(csi->dev, "V4L2 device registration failed (%d)\n",
 754                        ret);
 755                goto free_ctrl;
 756        }
 757
 758        ret = sun6i_video_init(&csi->video, csi, "sun6i-csi");
 759        if (ret)
 760                goto unreg_v4l2;
 761
 762        ret = v4l2_async_notifier_parse_fwnode_endpoints(csi->dev,
 763                                                         &csi->notifier,
 764                                                         sizeof(struct v4l2_async_subdev),
 765                                                         sun6i_csi_fwnode_parse);
 766        if (ret)
 767                goto clean_video;
 768
 769        csi->notifier.ops = &sun6i_csi_async_ops;
 770
 771        ret = v4l2_async_notifier_register(&csi->v4l2_dev, &csi->notifier);
 772        if (ret) {
 773                dev_err(csi->dev, "notifier registration failed\n");
 774                goto clean_video;
 775        }
 776
 777        return 0;
 778
 779clean_video:
 780        sun6i_video_cleanup(&csi->video);
 781unreg_v4l2:
 782        v4l2_device_unregister(&csi->v4l2_dev);
 783free_ctrl:
 784        v4l2_ctrl_handler_free(&csi->ctrl_handler);
 785clean_media:
 786        v4l2_async_notifier_cleanup(&csi->notifier);
 787        media_device_cleanup(&csi->media_dev);
 788
 789        return ret;
 790}
 791
 792/* -----------------------------------------------------------------------------
 793 * Resources and IRQ
 794 */
 795static irqreturn_t sun6i_csi_isr(int irq, void *dev_id)
 796{
 797        struct sun6i_csi_dev *sdev = (struct sun6i_csi_dev *)dev_id;
 798        struct regmap *regmap = sdev->regmap;
 799        u32 status;
 800
 801        regmap_read(regmap, CSI_CH_INT_STA_REG, &status);
 802
 803        if (!(status & 0xFF))
 804                return IRQ_NONE;
 805
 806        if ((status & CSI_CH_INT_STA_FIFO0_OF_PD) ||
 807            (status & CSI_CH_INT_STA_FIFO1_OF_PD) ||
 808            (status & CSI_CH_INT_STA_FIFO2_OF_PD) ||
 809            (status & CSI_CH_INT_STA_HB_OF_PD)) {
 810                regmap_write(regmap, CSI_CH_INT_STA_REG, status);
 811                regmap_update_bits(regmap, CSI_EN_REG, CSI_EN_CSI_EN, 0);
 812                regmap_update_bits(regmap, CSI_EN_REG, CSI_EN_CSI_EN,
 813                                   CSI_EN_CSI_EN);
 814                return IRQ_HANDLED;
 815        }
 816
 817        if (status & CSI_CH_INT_STA_FD_PD)
 818                sun6i_video_frame_done(&sdev->csi.video);
 819
 820        regmap_write(regmap, CSI_CH_INT_STA_REG, status);
 821
 822        return IRQ_HANDLED;
 823}
 824
 825static const struct regmap_config sun6i_csi_regmap_config = {
 826        .reg_bits       = 32,
 827        .reg_stride     = 4,
 828        .val_bits       = 32,
 829        .max_register   = 0x9c,
 830};
 831
 832static int sun6i_csi_resource_request(struct sun6i_csi_dev *sdev,
 833                                      struct platform_device *pdev)
 834{
 835        struct resource *res;
 836        void __iomem *io_base;
 837        int ret;
 838        int irq;
 839
 840        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 841        io_base = devm_ioremap_resource(&pdev->dev, res);
 842        if (IS_ERR(io_base))
 843                return PTR_ERR(io_base);
 844
 845        sdev->regmap = devm_regmap_init_mmio_clk(&pdev->dev, "bus", io_base,
 846                                                 &sun6i_csi_regmap_config);
 847        if (IS_ERR(sdev->regmap)) {
 848                dev_err(&pdev->dev, "Failed to init register map\n");
 849                return PTR_ERR(sdev->regmap);
 850        }
 851
 852        sdev->clk_mod = devm_clk_get(&pdev->dev, "mod");
 853        if (IS_ERR(sdev->clk_mod)) {
 854                dev_err(&pdev->dev, "Unable to acquire csi clock\n");
 855                return PTR_ERR(sdev->clk_mod);
 856        }
 857
 858        sdev->clk_ram = devm_clk_get(&pdev->dev, "ram");
 859        if (IS_ERR(sdev->clk_ram)) {
 860                dev_err(&pdev->dev, "Unable to acquire dram-csi clock\n");
 861                return PTR_ERR(sdev->clk_ram);
 862        }
 863
 864        sdev->rstc_bus = devm_reset_control_get_shared(&pdev->dev, NULL);
 865        if (IS_ERR(sdev->rstc_bus)) {
 866                dev_err(&pdev->dev, "Cannot get reset controller\n");
 867                return PTR_ERR(sdev->rstc_bus);
 868        }
 869
 870        irq = platform_get_irq(pdev, 0);
 871        if (irq < 0)
 872                return -ENXIO;
 873
 874        ret = devm_request_irq(&pdev->dev, irq, sun6i_csi_isr, 0, MODULE_NAME,
 875                               sdev);
 876        if (ret) {
 877                dev_err(&pdev->dev, "Cannot request csi IRQ\n");
 878                return ret;
 879        }
 880
 881        return 0;
 882}
 883
 884static int sun6i_csi_probe(struct platform_device *pdev)
 885{
 886        struct sun6i_csi_dev *sdev;
 887        int ret;
 888
 889        sdev = devm_kzalloc(&pdev->dev, sizeof(*sdev), GFP_KERNEL);
 890        if (!sdev)
 891                return -ENOMEM;
 892
 893        sdev->dev = &pdev->dev;
 894
 895        ret = sun6i_csi_resource_request(sdev, pdev);
 896        if (ret)
 897                return ret;
 898
 899        platform_set_drvdata(pdev, sdev);
 900
 901        sdev->csi.dev = &pdev->dev;
 902        return sun6i_csi_v4l2_init(&sdev->csi);
 903}
 904
 905static int sun6i_csi_remove(struct platform_device *pdev)
 906{
 907        struct sun6i_csi_dev *sdev = platform_get_drvdata(pdev);
 908
 909        sun6i_csi_v4l2_cleanup(&sdev->csi);
 910
 911        return 0;
 912}
 913
 914static const struct of_device_id sun6i_csi_of_match[] = {
 915        { .compatible = "allwinner,sun6i-a31-csi", },
 916        { .compatible = "allwinner,sun8i-a83t-csi", },
 917        { .compatible = "allwinner,sun8i-h3-csi", },
 918        { .compatible = "allwinner,sun8i-v3s-csi", },
 919        { .compatible = "allwinner,sun50i-a64-csi", },
 920        {},
 921};
 922MODULE_DEVICE_TABLE(of, sun6i_csi_of_match);
 923
 924static struct platform_driver sun6i_csi_platform_driver = {
 925        .probe = sun6i_csi_probe,
 926        .remove = sun6i_csi_remove,
 927        .driver = {
 928                .name = MODULE_NAME,
 929                .of_match_table = of_match_ptr(sun6i_csi_of_match),
 930        },
 931};
 932module_platform_driver(sun6i_csi_platform_driver);
 933
 934MODULE_DESCRIPTION("Allwinner V3s Camera Sensor Interface driver");
 935MODULE_AUTHOR("Yong Deng <yong.deng@magewell.com>");
 936MODULE_LICENSE("GPL");
 937