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 32 struct 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 44 static 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 */ 50 bool 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_NV12_16L16: 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_NV12_16L16: 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 164 int 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 208 clk_ram_disable: 209 clk_disable_unprepare(sdev->clk_ram); 210 clk_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 217 static 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 239 static 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_NV12_16L16: 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 306 static 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_NV12_16L16: 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 373 static 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 462 static 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 497 static 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_NV12_16L16: 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 571 int 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 588 void 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 602 void 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 */ 629 static 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 666 static 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 691 static const struct v4l2_async_notifier_operations sun6i_csi_async_ops = { 692 .complete = sun6i_subdev_notify_complete, 693 }; 694 695 static 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 717 static void sun6i_csi_v4l2_cleanup(struct sun6i_csi *csi) 718 { 719 media_device_unregister(&csi->media_dev); 720 v4l2_async_nf_unregister(&csi->notifier); 721 v4l2_async_nf_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 728 static 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_nf_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_nf_parse_fwnode_endpoints(csi->dev, 763 &csi->notifier, 764 sizeof(struct 765 v4l2_async_subdev), 766 sun6i_csi_fwnode_parse); 767 if (ret) 768 goto clean_video; 769 770 csi->notifier.ops = &sun6i_csi_async_ops; 771 772 ret = v4l2_async_nf_register(&csi->v4l2_dev, &csi->notifier); 773 if (ret) { 774 dev_err(csi->dev, "notifier registration failed\n"); 775 goto clean_video; 776 } 777 778 return 0; 779 780 clean_video: 781 sun6i_video_cleanup(&csi->video); 782 unreg_v4l2: 783 v4l2_device_unregister(&csi->v4l2_dev); 784 free_ctrl: 785 v4l2_ctrl_handler_free(&csi->ctrl_handler); 786 clean_media: 787 v4l2_async_nf_cleanup(&csi->notifier); 788 media_device_cleanup(&csi->media_dev); 789 790 return ret; 791 } 792 793 /* ----------------------------------------------------------------------------- 794 * Resources and IRQ 795 */ 796 static irqreturn_t sun6i_csi_isr(int irq, void *dev_id) 797 { 798 struct sun6i_csi_dev *sdev = (struct sun6i_csi_dev *)dev_id; 799 struct regmap *regmap = sdev->regmap; 800 u32 status; 801 802 regmap_read(regmap, CSI_CH_INT_STA_REG, &status); 803 804 if (!(status & 0xFF)) 805 return IRQ_NONE; 806 807 if ((status & CSI_CH_INT_STA_FIFO0_OF_PD) || 808 (status & CSI_CH_INT_STA_FIFO1_OF_PD) || 809 (status & CSI_CH_INT_STA_FIFO2_OF_PD) || 810 (status & CSI_CH_INT_STA_HB_OF_PD)) { 811 regmap_write(regmap, CSI_CH_INT_STA_REG, status); 812 regmap_update_bits(regmap, CSI_EN_REG, CSI_EN_CSI_EN, 0); 813 regmap_update_bits(regmap, CSI_EN_REG, CSI_EN_CSI_EN, 814 CSI_EN_CSI_EN); 815 return IRQ_HANDLED; 816 } 817 818 if (status & CSI_CH_INT_STA_FD_PD) 819 sun6i_video_frame_done(&sdev->csi.video); 820 821 regmap_write(regmap, CSI_CH_INT_STA_REG, status); 822 823 return IRQ_HANDLED; 824 } 825 826 static const struct regmap_config sun6i_csi_regmap_config = { 827 .reg_bits = 32, 828 .reg_stride = 4, 829 .val_bits = 32, 830 .max_register = 0x9c, 831 }; 832 833 static int sun6i_csi_resource_request(struct sun6i_csi_dev *sdev, 834 struct platform_device *pdev) 835 { 836 void __iomem *io_base; 837 int ret; 838 int irq; 839 840 io_base = devm_platform_ioremap_resource(pdev, 0); 841 if (IS_ERR(io_base)) 842 return PTR_ERR(io_base); 843 844 sdev->regmap = devm_regmap_init_mmio_clk(&pdev->dev, "bus", io_base, 845 &sun6i_csi_regmap_config); 846 if (IS_ERR(sdev->regmap)) { 847 dev_err(&pdev->dev, "Failed to init register map\n"); 848 return PTR_ERR(sdev->regmap); 849 } 850 851 sdev->clk_mod = devm_clk_get(&pdev->dev, "mod"); 852 if (IS_ERR(sdev->clk_mod)) { 853 dev_err(&pdev->dev, "Unable to acquire csi clock\n"); 854 return PTR_ERR(sdev->clk_mod); 855 } 856 857 sdev->clk_ram = devm_clk_get(&pdev->dev, "ram"); 858 if (IS_ERR(sdev->clk_ram)) { 859 dev_err(&pdev->dev, "Unable to acquire dram-csi clock\n"); 860 return PTR_ERR(sdev->clk_ram); 861 } 862 863 sdev->rstc_bus = devm_reset_control_get_shared(&pdev->dev, NULL); 864 if (IS_ERR(sdev->rstc_bus)) { 865 dev_err(&pdev->dev, "Cannot get reset controller\n"); 866 return PTR_ERR(sdev->rstc_bus); 867 } 868 869 irq = platform_get_irq(pdev, 0); 870 if (irq < 0) 871 return -ENXIO; 872 873 ret = devm_request_irq(&pdev->dev, irq, sun6i_csi_isr, 0, MODULE_NAME, 874 sdev); 875 if (ret) { 876 dev_err(&pdev->dev, "Cannot request csi IRQ\n"); 877 return ret; 878 } 879 880 return 0; 881 } 882 883 static int sun6i_csi_probe(struct platform_device *pdev) 884 { 885 struct sun6i_csi_dev *sdev; 886 int ret; 887 888 sdev = devm_kzalloc(&pdev->dev, sizeof(*sdev), GFP_KERNEL); 889 if (!sdev) 890 return -ENOMEM; 891 892 sdev->dev = &pdev->dev; 893 894 ret = sun6i_csi_resource_request(sdev, pdev); 895 if (ret) 896 return ret; 897 898 platform_set_drvdata(pdev, sdev); 899 900 sdev->csi.dev = &pdev->dev; 901 return sun6i_csi_v4l2_init(&sdev->csi); 902 } 903 904 static int sun6i_csi_remove(struct platform_device *pdev) 905 { 906 struct sun6i_csi_dev *sdev = platform_get_drvdata(pdev); 907 908 sun6i_csi_v4l2_cleanup(&sdev->csi); 909 910 return 0; 911 } 912 913 static const struct of_device_id sun6i_csi_of_match[] = { 914 { .compatible = "allwinner,sun6i-a31-csi", }, 915 { .compatible = "allwinner,sun8i-a83t-csi", }, 916 { .compatible = "allwinner,sun8i-h3-csi", }, 917 { .compatible = "allwinner,sun8i-v3s-csi", }, 918 { .compatible = "allwinner,sun50i-a64-csi", }, 919 {}, 920 }; 921 MODULE_DEVICE_TABLE(of, sun6i_csi_of_match); 922 923 static struct platform_driver sun6i_csi_platform_driver = { 924 .probe = sun6i_csi_probe, 925 .remove = sun6i_csi_remove, 926 .driver = { 927 .name = MODULE_NAME, 928 .of_match_table = of_match_ptr(sun6i_csi_of_match), 929 }, 930 }; 931 module_platform_driver(sun6i_csi_platform_driver); 932 933 MODULE_DESCRIPTION("Allwinner V3s Camera Sensor Interface driver"); 934 MODULE_AUTHOR("Yong Deng <yong.deng@magewell.com>"); 935 MODULE_LICENSE("GPL"); 936