linux/drivers/media/platform/qcom/camss/camss-csid-4-1.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/*
   3 * camss-csid-4-1.c
   4 *
   5 * Qualcomm MSM Camera Subsystem - CSID (CSI Decoder) Module
   6 *
   7 * Copyright (C) 2020 Linaro Ltd.
   8 */
   9
  10#include <linux/completion.h>
  11#include <linux/interrupt.h>
  12#include <linux/io.h>
  13#include <linux/kernel.h>
  14#include <linux/of.h>
  15
  16#include "camss-csid.h"
  17#include "camss-csid-gen1.h"
  18#include "camss.h"
  19
  20#define CAMSS_CSID_HW_VERSION           0x0
  21#define CAMSS_CSID_CORE_CTRL_0          0x004
  22#define CAMSS_CSID_CORE_CTRL_1          0x008
  23#define CAMSS_CSID_RST_CMD              0x00c
  24#define CAMSS_CSID_CID_LUT_VC_n(n)      (0x010 + 0x4 * (n))
  25#define CAMSS_CSID_CID_n_CFG(n)         (0x020 + 0x4 * (n))
  26#define CAMSS_CSID_CID_n_CFG_ISPIF_EN   BIT(0)
  27#define CAMSS_CSID_CID_n_CFG_RDI_EN     BIT(1)
  28#define CAMSS_CSID_CID_n_CFG_DECODE_FORMAT_SHIFT        4
  29#define CAMSS_CSID_CID_n_CFG_PLAIN_FORMAT_8             (PLAIN_FORMAT_PLAIN8 << 8)
  30#define CAMSS_CSID_CID_n_CFG_PLAIN_FORMAT_16            (PLAIN_FORMAT_PLAIN16 << 8)
  31#define CAMSS_CSID_CID_n_CFG_PLAIN_ALIGNMENT_LSB        (0 << 9)
  32#define CAMSS_CSID_CID_n_CFG_PLAIN_ALIGNMENT_MSB        (1 << 9)
  33#define CAMSS_CSID_CID_n_CFG_RDI_MODE_RAW_DUMP          (0 << 10)
  34#define CAMSS_CSID_CID_n_CFG_RDI_MODE_PLAIN_PACKING     (1 << 10)
  35#define CAMSS_CSID_IRQ_CLEAR_CMD        0x060
  36#define CAMSS_CSID_IRQ_MASK             0x064
  37#define CAMSS_CSID_IRQ_STATUS           0x068
  38#define CAMSS_CSID_TG_CTRL              0x0a0
  39#define CAMSS_CSID_TG_CTRL_DISABLE      0xa06436
  40#define CAMSS_CSID_TG_CTRL_ENABLE       0xa06437
  41#define CAMSS_CSID_TG_VC_CFG            0x0a4
  42#define CAMSS_CSID_TG_VC_CFG_H_BLANKING         0x3ff
  43#define CAMSS_CSID_TG_VC_CFG_V_BLANKING         0x7f
  44#define CAMSS_CSID_TG_DT_n_CGG_0(n)     (0x0ac + 0xc * (n))
  45#define CAMSS_CSID_TG_DT_n_CGG_1(n)     (0x0b0 + 0xc * (n))
  46#define CAMSS_CSID_TG_DT_n_CGG_2(n)     (0x0b4 + 0xc * (n))
  47
  48static const struct csid_format csid_formats[] = {
  49        {
  50                MEDIA_BUS_FMT_UYVY8_2X8,
  51                DATA_TYPE_YUV422_8BIT,
  52                DECODE_FORMAT_UNCOMPRESSED_8_BIT,
  53                8,
  54                2,
  55        },
  56        {
  57                MEDIA_BUS_FMT_VYUY8_2X8,
  58                DATA_TYPE_YUV422_8BIT,
  59                DECODE_FORMAT_UNCOMPRESSED_8_BIT,
  60                8,
  61                2,
  62        },
  63        {
  64                MEDIA_BUS_FMT_YUYV8_2X8,
  65                DATA_TYPE_YUV422_8BIT,
  66                DECODE_FORMAT_UNCOMPRESSED_8_BIT,
  67                8,
  68                2,
  69        },
  70        {
  71                MEDIA_BUS_FMT_YVYU8_2X8,
  72                DATA_TYPE_YUV422_8BIT,
  73                DECODE_FORMAT_UNCOMPRESSED_8_BIT,
  74                8,
  75                2,
  76        },
  77        {
  78                MEDIA_BUS_FMT_SBGGR8_1X8,
  79                DATA_TYPE_RAW_8BIT,
  80                DECODE_FORMAT_UNCOMPRESSED_8_BIT,
  81                8,
  82                1,
  83        },
  84        {
  85                MEDIA_BUS_FMT_SGBRG8_1X8,
  86                DATA_TYPE_RAW_8BIT,
  87                DECODE_FORMAT_UNCOMPRESSED_8_BIT,
  88                8,
  89                1,
  90        },
  91        {
  92                MEDIA_BUS_FMT_SGRBG8_1X8,
  93                DATA_TYPE_RAW_8BIT,
  94                DECODE_FORMAT_UNCOMPRESSED_8_BIT,
  95                8,
  96                1,
  97        },
  98        {
  99                MEDIA_BUS_FMT_SRGGB8_1X8,
 100                DATA_TYPE_RAW_8BIT,
 101                DECODE_FORMAT_UNCOMPRESSED_8_BIT,
 102                8,
 103                1,
 104        },
 105        {
 106                MEDIA_BUS_FMT_SBGGR10_1X10,
 107                DATA_TYPE_RAW_10BIT,
 108                DECODE_FORMAT_UNCOMPRESSED_10_BIT,
 109                10,
 110                1,
 111        },
 112        {
 113                MEDIA_BUS_FMT_SGBRG10_1X10,
 114                DATA_TYPE_RAW_10BIT,
 115                DECODE_FORMAT_UNCOMPRESSED_10_BIT,
 116                10,
 117                1,
 118        },
 119        {
 120                MEDIA_BUS_FMT_SGRBG10_1X10,
 121                DATA_TYPE_RAW_10BIT,
 122                DECODE_FORMAT_UNCOMPRESSED_10_BIT,
 123                10,
 124                1,
 125        },
 126        {
 127                MEDIA_BUS_FMT_SRGGB10_1X10,
 128                DATA_TYPE_RAW_10BIT,
 129                DECODE_FORMAT_UNCOMPRESSED_10_BIT,
 130                10,
 131                1,
 132        },
 133        {
 134                MEDIA_BUS_FMT_SBGGR12_1X12,
 135                DATA_TYPE_RAW_12BIT,
 136                DECODE_FORMAT_UNCOMPRESSED_12_BIT,
 137                12,
 138                1,
 139        },
 140        {
 141                MEDIA_BUS_FMT_SGBRG12_1X12,
 142                DATA_TYPE_RAW_12BIT,
 143                DECODE_FORMAT_UNCOMPRESSED_12_BIT,
 144                12,
 145                1,
 146        },
 147        {
 148                MEDIA_BUS_FMT_SGRBG12_1X12,
 149                DATA_TYPE_RAW_12BIT,
 150                DECODE_FORMAT_UNCOMPRESSED_12_BIT,
 151                12,
 152                1,
 153        },
 154        {
 155                MEDIA_BUS_FMT_SRGGB12_1X12,
 156                DATA_TYPE_RAW_12BIT,
 157                DECODE_FORMAT_UNCOMPRESSED_12_BIT,
 158                12,
 159                1,
 160        },
 161        {
 162                MEDIA_BUS_FMT_Y10_1X10,
 163                DATA_TYPE_RAW_10BIT,
 164                DECODE_FORMAT_UNCOMPRESSED_10_BIT,
 165                10,
 166                1,
 167        },
 168};
 169
 170static void csid_configure_stream(struct csid_device *csid, u8 enable)
 171{
 172        struct csid_testgen_config *tg = &csid->testgen;
 173        u32 val;
 174
 175        if (enable) {
 176                struct v4l2_mbus_framefmt *input_format;
 177                const struct csid_format *format;
 178                u8 vc = 0; /* Virtual Channel 0 */
 179                u8 cid = vc * 4; /* id of Virtual Channel and Data Type set */
 180                u8 dt_shift;
 181
 182                if (tg->enabled) {
 183                        /* Config Test Generator */
 184                        u32 num_lines, num_bytes_per_line;
 185
 186                        input_format = &csid->fmt[MSM_CSID_PAD_SRC];
 187                        format = csid_get_fmt_entry(csid->formats, csid->nformats,
 188                                                    input_format->code);
 189                        num_bytes_per_line = input_format->width * format->bpp * format->spp / 8;
 190                        num_lines = input_format->height;
 191
 192                        /* 31:24 V blank, 23:13 H blank, 3:2 num of active DT */
 193                        /* 1:0 VC */
 194                        val = ((CAMSS_CSID_TG_VC_CFG_V_BLANKING & 0xff) << 24) |
 195                                  ((CAMSS_CSID_TG_VC_CFG_H_BLANKING & 0x7ff) << 13);
 196                        writel_relaxed(val, csid->base + CAMSS_CSID_TG_VC_CFG);
 197
 198                        /* 28:16 bytes per lines, 12:0 num of lines */
 199                        val = ((num_bytes_per_line & 0x1fff) << 16) |
 200                                  (num_lines & 0x1fff);
 201                        writel_relaxed(val, csid->base + CAMSS_CSID_TG_DT_n_CGG_0(0));
 202
 203                        /* 5:0 data type */
 204                        val = format->data_type;
 205                        writel_relaxed(val, csid->base + CAMSS_CSID_TG_DT_n_CGG_1(0));
 206
 207                        /* 2:0 output test pattern */
 208                        val = tg->mode - 1;
 209                        writel_relaxed(val, csid->base + CAMSS_CSID_TG_DT_n_CGG_2(0));
 210                } else {
 211                        struct csid_phy_config *phy = &csid->phy;
 212
 213                        input_format = &csid->fmt[MSM_CSID_PAD_SINK];
 214                        format = csid_get_fmt_entry(csid->formats, csid->nformats,
 215                                                    input_format->code);
 216
 217                        val = phy->lane_cnt - 1;
 218                        val |= phy->lane_assign << 4;
 219
 220                        writel_relaxed(val, csid->base + CAMSS_CSID_CORE_CTRL_0);
 221
 222                        val = phy->csiphy_id << 17;
 223                        val |= 0x9;
 224
 225                        writel_relaxed(val, csid->base + CAMSS_CSID_CORE_CTRL_1);
 226                }
 227
 228                /* Config LUT */
 229
 230                dt_shift = (cid % 4) * 8;
 231                val = readl_relaxed(csid->base + CAMSS_CSID_CID_LUT_VC_n(vc));
 232                val &= ~(0xff << dt_shift);
 233                val |= format->data_type << dt_shift;
 234                writel_relaxed(val, csid->base + CAMSS_CSID_CID_LUT_VC_n(vc));
 235
 236                val = CAMSS_CSID_CID_n_CFG_ISPIF_EN;
 237                val |= CAMSS_CSID_CID_n_CFG_RDI_EN;
 238                val |= format->decode_format << CAMSS_CSID_CID_n_CFG_DECODE_FORMAT_SHIFT;
 239                val |= CAMSS_CSID_CID_n_CFG_RDI_MODE_RAW_DUMP;
 240                writel_relaxed(val, csid->base + CAMSS_CSID_CID_n_CFG(cid));
 241
 242                if (tg->enabled) {
 243                        val = CAMSS_CSID_TG_CTRL_ENABLE;
 244                        writel_relaxed(val, csid->base + CAMSS_CSID_TG_CTRL);
 245                }
 246        } else {
 247                if (tg->enabled) {
 248                        val = CAMSS_CSID_TG_CTRL_DISABLE;
 249                        writel_relaxed(val, csid->base + CAMSS_CSID_TG_CTRL);
 250                }
 251        }
 252}
 253
 254static int csid_configure_testgen_pattern(struct csid_device *csid, s32 val)
 255{
 256        if (val > 0 && val <= csid->testgen.nmodes)
 257                csid->testgen.mode = val;
 258
 259        return 0;
 260}
 261
 262static u32 csid_hw_version(struct csid_device *csid)
 263{
 264        u32 hw_version = readl_relaxed(csid->base + CAMSS_CSID_HW_VERSION);
 265
 266        dev_dbg(csid->camss->dev, "CSID HW Version = 0x%08x\n", hw_version);
 267
 268        return hw_version;
 269}
 270
 271static irqreturn_t csid_isr(int irq, void *dev)
 272{
 273        struct csid_device *csid = dev;
 274        u32 value;
 275
 276        value = readl_relaxed(csid->base + CAMSS_CSID_IRQ_STATUS);
 277        writel_relaxed(value, csid->base + CAMSS_CSID_IRQ_CLEAR_CMD);
 278
 279        if ((value >> 11) & 0x1)
 280                complete(&csid->reset_complete);
 281
 282        return IRQ_HANDLED;
 283}
 284
 285static int csid_reset(struct csid_device *csid)
 286{
 287        unsigned long time;
 288
 289        reinit_completion(&csid->reset_complete);
 290
 291        writel_relaxed(0x7fff, csid->base + CAMSS_CSID_RST_CMD);
 292
 293        time = wait_for_completion_timeout(&csid->reset_complete,
 294                                           msecs_to_jiffies(CSID_RESET_TIMEOUT_MS));
 295        if (!time) {
 296                dev_err(csid->camss->dev, "CSID reset timeout\n");
 297                return -EIO;
 298        }
 299
 300        return 0;
 301}
 302
 303static u32 csid_src_pad_code(struct csid_device *csid, u32 sink_code,
 304                             unsigned int match_format_idx, u32 match_code)
 305{
 306        if (match_format_idx > 0)
 307                return 0;
 308
 309        return sink_code;
 310}
 311
 312static void csid_subdev_init(struct csid_device *csid)
 313{
 314        csid->formats = csid_formats;
 315        csid->nformats = ARRAY_SIZE(csid_formats);
 316        csid->testgen.modes = csid_testgen_modes;
 317        csid->testgen.nmodes = CSID_PAYLOAD_MODE_NUM_SUPPORTED_GEN1;
 318}
 319
 320const struct csid_hw_ops csid_ops_4_1 = {
 321        .configure_stream = csid_configure_stream,
 322        .configure_testgen_pattern = csid_configure_testgen_pattern,
 323        .hw_version = csid_hw_version,
 324        .isr = csid_isr,
 325        .reset = csid_reset,
 326        .src_pad_code = csid_src_pad_code,
 327        .subdev_init = csid_subdev_init,
 328};
 329