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