18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * ispcsi2.c 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * TI OMAP3 ISP - CSI2 module 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * Copyright (C) 2010 Nokia Corporation 88c2ecf20Sopenharmony_ci * Copyright (C) 2009 Texas Instruments, Inc. 98c2ecf20Sopenharmony_ci * 108c2ecf20Sopenharmony_ci * Contacts: Laurent Pinchart <laurent.pinchart@ideasonboard.com> 118c2ecf20Sopenharmony_ci * Sakari Ailus <sakari.ailus@iki.fi> 128c2ecf20Sopenharmony_ci */ 138c2ecf20Sopenharmony_ci#include <linux/delay.h> 148c2ecf20Sopenharmony_ci#include <media/v4l2-common.h> 158c2ecf20Sopenharmony_ci#include <linux/v4l2-mediabus.h> 168c2ecf20Sopenharmony_ci#include <linux/mm.h> 178c2ecf20Sopenharmony_ci 188c2ecf20Sopenharmony_ci#include "isp.h" 198c2ecf20Sopenharmony_ci#include "ispreg.h" 208c2ecf20Sopenharmony_ci#include "ispcsi2.h" 218c2ecf20Sopenharmony_ci 228c2ecf20Sopenharmony_ci/* 238c2ecf20Sopenharmony_ci * csi2_if_enable - Enable CSI2 Receiver interface. 248c2ecf20Sopenharmony_ci * @enable: enable flag 258c2ecf20Sopenharmony_ci * 268c2ecf20Sopenharmony_ci */ 278c2ecf20Sopenharmony_cistatic void csi2_if_enable(struct isp_device *isp, 288c2ecf20Sopenharmony_ci struct isp_csi2_device *csi2, u8 enable) 298c2ecf20Sopenharmony_ci{ 308c2ecf20Sopenharmony_ci struct isp_csi2_ctrl_cfg *currctrl = &csi2->ctrl; 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_ci isp_reg_clr_set(isp, csi2->regs1, ISPCSI2_CTRL, ISPCSI2_CTRL_IF_EN, 338c2ecf20Sopenharmony_ci enable ? ISPCSI2_CTRL_IF_EN : 0); 348c2ecf20Sopenharmony_ci 358c2ecf20Sopenharmony_ci currctrl->if_enable = enable; 368c2ecf20Sopenharmony_ci} 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_ci/* 398c2ecf20Sopenharmony_ci * csi2_recv_config - CSI2 receiver module configuration. 408c2ecf20Sopenharmony_ci * @currctrl: isp_csi2_ctrl_cfg structure 418c2ecf20Sopenharmony_ci * 428c2ecf20Sopenharmony_ci */ 438c2ecf20Sopenharmony_cistatic void csi2_recv_config(struct isp_device *isp, 448c2ecf20Sopenharmony_ci struct isp_csi2_device *csi2, 458c2ecf20Sopenharmony_ci struct isp_csi2_ctrl_cfg *currctrl) 468c2ecf20Sopenharmony_ci{ 478c2ecf20Sopenharmony_ci u32 reg; 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_ci reg = isp_reg_readl(isp, csi2->regs1, ISPCSI2_CTRL); 508c2ecf20Sopenharmony_ci 518c2ecf20Sopenharmony_ci if (currctrl->frame_mode) 528c2ecf20Sopenharmony_ci reg |= ISPCSI2_CTRL_FRAME; 538c2ecf20Sopenharmony_ci else 548c2ecf20Sopenharmony_ci reg &= ~ISPCSI2_CTRL_FRAME; 558c2ecf20Sopenharmony_ci 568c2ecf20Sopenharmony_ci if (currctrl->vp_clk_enable) 578c2ecf20Sopenharmony_ci reg |= ISPCSI2_CTRL_VP_CLK_EN; 588c2ecf20Sopenharmony_ci else 598c2ecf20Sopenharmony_ci reg &= ~ISPCSI2_CTRL_VP_CLK_EN; 608c2ecf20Sopenharmony_ci 618c2ecf20Sopenharmony_ci if (currctrl->vp_only_enable) 628c2ecf20Sopenharmony_ci reg |= ISPCSI2_CTRL_VP_ONLY_EN; 638c2ecf20Sopenharmony_ci else 648c2ecf20Sopenharmony_ci reg &= ~ISPCSI2_CTRL_VP_ONLY_EN; 658c2ecf20Sopenharmony_ci 668c2ecf20Sopenharmony_ci reg &= ~ISPCSI2_CTRL_VP_OUT_CTRL_MASK; 678c2ecf20Sopenharmony_ci reg |= currctrl->vp_out_ctrl << ISPCSI2_CTRL_VP_OUT_CTRL_SHIFT; 688c2ecf20Sopenharmony_ci 698c2ecf20Sopenharmony_ci if (currctrl->ecc_enable) 708c2ecf20Sopenharmony_ci reg |= ISPCSI2_CTRL_ECC_EN; 718c2ecf20Sopenharmony_ci else 728c2ecf20Sopenharmony_ci reg &= ~ISPCSI2_CTRL_ECC_EN; 738c2ecf20Sopenharmony_ci 748c2ecf20Sopenharmony_ci isp_reg_writel(isp, reg, csi2->regs1, ISPCSI2_CTRL); 758c2ecf20Sopenharmony_ci} 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_cistatic const unsigned int csi2_input_fmts[] = { 788c2ecf20Sopenharmony_ci MEDIA_BUS_FMT_SGRBG10_1X10, 798c2ecf20Sopenharmony_ci MEDIA_BUS_FMT_SGRBG10_DPCM8_1X8, 808c2ecf20Sopenharmony_ci MEDIA_BUS_FMT_SRGGB10_1X10, 818c2ecf20Sopenharmony_ci MEDIA_BUS_FMT_SRGGB10_DPCM8_1X8, 828c2ecf20Sopenharmony_ci MEDIA_BUS_FMT_SBGGR10_1X10, 838c2ecf20Sopenharmony_ci MEDIA_BUS_FMT_SBGGR10_DPCM8_1X8, 848c2ecf20Sopenharmony_ci MEDIA_BUS_FMT_SGBRG10_1X10, 858c2ecf20Sopenharmony_ci MEDIA_BUS_FMT_SGBRG10_DPCM8_1X8, 868c2ecf20Sopenharmony_ci MEDIA_BUS_FMT_YUYV8_2X8, 878c2ecf20Sopenharmony_ci}; 888c2ecf20Sopenharmony_ci 898c2ecf20Sopenharmony_ci/* To set the format on the CSI2 requires a mapping function that takes 908c2ecf20Sopenharmony_ci * the following inputs: 918c2ecf20Sopenharmony_ci * - 3 different formats (at this time) 928c2ecf20Sopenharmony_ci * - 2 destinations (mem, vp+mem) (vp only handled separately) 938c2ecf20Sopenharmony_ci * - 2 decompression options (on, off) 948c2ecf20Sopenharmony_ci * - 2 isp revisions (certain format must be handled differently on OMAP3630) 958c2ecf20Sopenharmony_ci * Output should be CSI2 frame format code 968c2ecf20Sopenharmony_ci * Array indices as follows: [format][dest][decompr][is_3630] 978c2ecf20Sopenharmony_ci * Not all combinations are valid. 0 means invalid. 988c2ecf20Sopenharmony_ci */ 998c2ecf20Sopenharmony_cistatic const u16 __csi2_fmt_map[3][2][2][2] = { 1008c2ecf20Sopenharmony_ci /* RAW10 formats */ 1018c2ecf20Sopenharmony_ci { 1028c2ecf20Sopenharmony_ci /* Output to memory */ 1038c2ecf20Sopenharmony_ci { 1048c2ecf20Sopenharmony_ci /* No DPCM decompression */ 1058c2ecf20Sopenharmony_ci { CSI2_PIX_FMT_RAW10_EXP16, CSI2_PIX_FMT_RAW10_EXP16 }, 1068c2ecf20Sopenharmony_ci /* DPCM decompression */ 1078c2ecf20Sopenharmony_ci { 0, 0 }, 1088c2ecf20Sopenharmony_ci }, 1098c2ecf20Sopenharmony_ci /* Output to both */ 1108c2ecf20Sopenharmony_ci { 1118c2ecf20Sopenharmony_ci /* No DPCM decompression */ 1128c2ecf20Sopenharmony_ci { CSI2_PIX_FMT_RAW10_EXP16_VP, 1138c2ecf20Sopenharmony_ci CSI2_PIX_FMT_RAW10_EXP16_VP }, 1148c2ecf20Sopenharmony_ci /* DPCM decompression */ 1158c2ecf20Sopenharmony_ci { 0, 0 }, 1168c2ecf20Sopenharmony_ci }, 1178c2ecf20Sopenharmony_ci }, 1188c2ecf20Sopenharmony_ci /* RAW10 DPCM8 formats */ 1198c2ecf20Sopenharmony_ci { 1208c2ecf20Sopenharmony_ci /* Output to memory */ 1218c2ecf20Sopenharmony_ci { 1228c2ecf20Sopenharmony_ci /* No DPCM decompression */ 1238c2ecf20Sopenharmony_ci { CSI2_PIX_FMT_RAW8, CSI2_USERDEF_8BIT_DATA1 }, 1248c2ecf20Sopenharmony_ci /* DPCM decompression */ 1258c2ecf20Sopenharmony_ci { CSI2_PIX_FMT_RAW8_DPCM10_EXP16, 1268c2ecf20Sopenharmony_ci CSI2_USERDEF_8BIT_DATA1_DPCM10 }, 1278c2ecf20Sopenharmony_ci }, 1288c2ecf20Sopenharmony_ci /* Output to both */ 1298c2ecf20Sopenharmony_ci { 1308c2ecf20Sopenharmony_ci /* No DPCM decompression */ 1318c2ecf20Sopenharmony_ci { CSI2_PIX_FMT_RAW8_VP, 1328c2ecf20Sopenharmony_ci CSI2_PIX_FMT_RAW8_VP }, 1338c2ecf20Sopenharmony_ci /* DPCM decompression */ 1348c2ecf20Sopenharmony_ci { CSI2_PIX_FMT_RAW8_DPCM10_VP, 1358c2ecf20Sopenharmony_ci CSI2_USERDEF_8BIT_DATA1_DPCM10_VP }, 1368c2ecf20Sopenharmony_ci }, 1378c2ecf20Sopenharmony_ci }, 1388c2ecf20Sopenharmony_ci /* YUYV8 2X8 formats */ 1398c2ecf20Sopenharmony_ci { 1408c2ecf20Sopenharmony_ci /* Output to memory */ 1418c2ecf20Sopenharmony_ci { 1428c2ecf20Sopenharmony_ci /* No DPCM decompression */ 1438c2ecf20Sopenharmony_ci { CSI2_PIX_FMT_YUV422_8BIT, 1448c2ecf20Sopenharmony_ci CSI2_PIX_FMT_YUV422_8BIT }, 1458c2ecf20Sopenharmony_ci /* DPCM decompression */ 1468c2ecf20Sopenharmony_ci { 0, 0 }, 1478c2ecf20Sopenharmony_ci }, 1488c2ecf20Sopenharmony_ci /* Output to both */ 1498c2ecf20Sopenharmony_ci { 1508c2ecf20Sopenharmony_ci /* No DPCM decompression */ 1518c2ecf20Sopenharmony_ci { CSI2_PIX_FMT_YUV422_8BIT_VP, 1528c2ecf20Sopenharmony_ci CSI2_PIX_FMT_YUV422_8BIT_VP }, 1538c2ecf20Sopenharmony_ci /* DPCM decompression */ 1548c2ecf20Sopenharmony_ci { 0, 0 }, 1558c2ecf20Sopenharmony_ci }, 1568c2ecf20Sopenharmony_ci }, 1578c2ecf20Sopenharmony_ci}; 1588c2ecf20Sopenharmony_ci 1598c2ecf20Sopenharmony_ci/* 1608c2ecf20Sopenharmony_ci * csi2_ctx_map_format - Map CSI2 sink media bus format to CSI2 format ID 1618c2ecf20Sopenharmony_ci * @csi2: ISP CSI2 device 1628c2ecf20Sopenharmony_ci * 1638c2ecf20Sopenharmony_ci * Returns CSI2 physical format id 1648c2ecf20Sopenharmony_ci */ 1658c2ecf20Sopenharmony_cistatic u16 csi2_ctx_map_format(struct isp_csi2_device *csi2) 1668c2ecf20Sopenharmony_ci{ 1678c2ecf20Sopenharmony_ci const struct v4l2_mbus_framefmt *fmt = &csi2->formats[CSI2_PAD_SINK]; 1688c2ecf20Sopenharmony_ci int fmtidx, destidx, is_3630; 1698c2ecf20Sopenharmony_ci 1708c2ecf20Sopenharmony_ci switch (fmt->code) { 1718c2ecf20Sopenharmony_ci case MEDIA_BUS_FMT_SGRBG10_1X10: 1728c2ecf20Sopenharmony_ci case MEDIA_BUS_FMT_SRGGB10_1X10: 1738c2ecf20Sopenharmony_ci case MEDIA_BUS_FMT_SBGGR10_1X10: 1748c2ecf20Sopenharmony_ci case MEDIA_BUS_FMT_SGBRG10_1X10: 1758c2ecf20Sopenharmony_ci fmtidx = 0; 1768c2ecf20Sopenharmony_ci break; 1778c2ecf20Sopenharmony_ci case MEDIA_BUS_FMT_SGRBG10_DPCM8_1X8: 1788c2ecf20Sopenharmony_ci case MEDIA_BUS_FMT_SRGGB10_DPCM8_1X8: 1798c2ecf20Sopenharmony_ci case MEDIA_BUS_FMT_SBGGR10_DPCM8_1X8: 1808c2ecf20Sopenharmony_ci case MEDIA_BUS_FMT_SGBRG10_DPCM8_1X8: 1818c2ecf20Sopenharmony_ci fmtidx = 1; 1828c2ecf20Sopenharmony_ci break; 1838c2ecf20Sopenharmony_ci case MEDIA_BUS_FMT_YUYV8_2X8: 1848c2ecf20Sopenharmony_ci fmtidx = 2; 1858c2ecf20Sopenharmony_ci break; 1868c2ecf20Sopenharmony_ci default: 1878c2ecf20Sopenharmony_ci WARN(1, KERN_ERR "CSI2: pixel format %08x unsupported!\n", 1888c2ecf20Sopenharmony_ci fmt->code); 1898c2ecf20Sopenharmony_ci return 0; 1908c2ecf20Sopenharmony_ci } 1918c2ecf20Sopenharmony_ci 1928c2ecf20Sopenharmony_ci if (!(csi2->output & CSI2_OUTPUT_CCDC) && 1938c2ecf20Sopenharmony_ci !(csi2->output & CSI2_OUTPUT_MEMORY)) { 1948c2ecf20Sopenharmony_ci /* Neither output enabled is a valid combination */ 1958c2ecf20Sopenharmony_ci return CSI2_PIX_FMT_OTHERS; 1968c2ecf20Sopenharmony_ci } 1978c2ecf20Sopenharmony_ci 1988c2ecf20Sopenharmony_ci /* If we need to skip frames at the beginning of the stream disable the 1998c2ecf20Sopenharmony_ci * video port to avoid sending the skipped frames to the CCDC. 2008c2ecf20Sopenharmony_ci */ 2018c2ecf20Sopenharmony_ci destidx = csi2->frame_skip ? 0 : !!(csi2->output & CSI2_OUTPUT_CCDC); 2028c2ecf20Sopenharmony_ci is_3630 = csi2->isp->revision == ISP_REVISION_15_0; 2038c2ecf20Sopenharmony_ci 2048c2ecf20Sopenharmony_ci return __csi2_fmt_map[fmtidx][destidx][csi2->dpcm_decompress][is_3630]; 2058c2ecf20Sopenharmony_ci} 2068c2ecf20Sopenharmony_ci 2078c2ecf20Sopenharmony_ci/* 2088c2ecf20Sopenharmony_ci * csi2_set_outaddr - Set memory address to save output image 2098c2ecf20Sopenharmony_ci * @csi2: Pointer to ISP CSI2a device. 2108c2ecf20Sopenharmony_ci * @addr: ISP MMU Mapped 32-bit memory address aligned on 32 byte boundary. 2118c2ecf20Sopenharmony_ci * 2128c2ecf20Sopenharmony_ci * Sets the memory address where the output will be saved. 2138c2ecf20Sopenharmony_ci * 2148c2ecf20Sopenharmony_ci * Returns 0 if successful, or -EINVAL if the address is not in the 32 byte 2158c2ecf20Sopenharmony_ci * boundary. 2168c2ecf20Sopenharmony_ci */ 2178c2ecf20Sopenharmony_cistatic void csi2_set_outaddr(struct isp_csi2_device *csi2, u32 addr) 2188c2ecf20Sopenharmony_ci{ 2198c2ecf20Sopenharmony_ci struct isp_device *isp = csi2->isp; 2208c2ecf20Sopenharmony_ci struct isp_csi2_ctx_cfg *ctx = &csi2->contexts[0]; 2218c2ecf20Sopenharmony_ci 2228c2ecf20Sopenharmony_ci ctx->ping_addr = addr; 2238c2ecf20Sopenharmony_ci ctx->pong_addr = addr; 2248c2ecf20Sopenharmony_ci isp_reg_writel(isp, ctx->ping_addr, 2258c2ecf20Sopenharmony_ci csi2->regs1, ISPCSI2_CTX_DAT_PING_ADDR(ctx->ctxnum)); 2268c2ecf20Sopenharmony_ci isp_reg_writel(isp, ctx->pong_addr, 2278c2ecf20Sopenharmony_ci csi2->regs1, ISPCSI2_CTX_DAT_PONG_ADDR(ctx->ctxnum)); 2288c2ecf20Sopenharmony_ci} 2298c2ecf20Sopenharmony_ci 2308c2ecf20Sopenharmony_ci/* 2318c2ecf20Sopenharmony_ci * is_usr_def_mapping - Checks whether USER_DEF_MAPPING should 2328c2ecf20Sopenharmony_ci * be enabled by CSI2. 2338c2ecf20Sopenharmony_ci * @format_id: mapped format id 2348c2ecf20Sopenharmony_ci * 2358c2ecf20Sopenharmony_ci */ 2368c2ecf20Sopenharmony_cistatic inline int is_usr_def_mapping(u32 format_id) 2378c2ecf20Sopenharmony_ci{ 2388c2ecf20Sopenharmony_ci return (format_id & 0x40) ? 1 : 0; 2398c2ecf20Sopenharmony_ci} 2408c2ecf20Sopenharmony_ci 2418c2ecf20Sopenharmony_ci/* 2428c2ecf20Sopenharmony_ci * csi2_ctx_enable - Enable specified CSI2 context 2438c2ecf20Sopenharmony_ci * @ctxnum: Context number, valid between 0 and 7 values. 2448c2ecf20Sopenharmony_ci * @enable: enable 2458c2ecf20Sopenharmony_ci * 2468c2ecf20Sopenharmony_ci */ 2478c2ecf20Sopenharmony_cistatic void csi2_ctx_enable(struct isp_device *isp, 2488c2ecf20Sopenharmony_ci struct isp_csi2_device *csi2, u8 ctxnum, u8 enable) 2498c2ecf20Sopenharmony_ci{ 2508c2ecf20Sopenharmony_ci struct isp_csi2_ctx_cfg *ctx = &csi2->contexts[ctxnum]; 2518c2ecf20Sopenharmony_ci unsigned int skip = 0; 2528c2ecf20Sopenharmony_ci u32 reg; 2538c2ecf20Sopenharmony_ci 2548c2ecf20Sopenharmony_ci reg = isp_reg_readl(isp, csi2->regs1, ISPCSI2_CTX_CTRL1(ctxnum)); 2558c2ecf20Sopenharmony_ci 2568c2ecf20Sopenharmony_ci if (enable) { 2578c2ecf20Sopenharmony_ci if (csi2->frame_skip) 2588c2ecf20Sopenharmony_ci skip = csi2->frame_skip; 2598c2ecf20Sopenharmony_ci else if (csi2->output & CSI2_OUTPUT_MEMORY) 2608c2ecf20Sopenharmony_ci skip = 1; 2618c2ecf20Sopenharmony_ci 2628c2ecf20Sopenharmony_ci reg &= ~ISPCSI2_CTX_CTRL1_COUNT_MASK; 2638c2ecf20Sopenharmony_ci reg |= ISPCSI2_CTX_CTRL1_COUNT_UNLOCK 2648c2ecf20Sopenharmony_ci | (skip << ISPCSI2_CTX_CTRL1_COUNT_SHIFT) 2658c2ecf20Sopenharmony_ci | ISPCSI2_CTX_CTRL1_CTX_EN; 2668c2ecf20Sopenharmony_ci } else { 2678c2ecf20Sopenharmony_ci reg &= ~ISPCSI2_CTX_CTRL1_CTX_EN; 2688c2ecf20Sopenharmony_ci } 2698c2ecf20Sopenharmony_ci 2708c2ecf20Sopenharmony_ci isp_reg_writel(isp, reg, csi2->regs1, ISPCSI2_CTX_CTRL1(ctxnum)); 2718c2ecf20Sopenharmony_ci ctx->enabled = enable; 2728c2ecf20Sopenharmony_ci} 2738c2ecf20Sopenharmony_ci 2748c2ecf20Sopenharmony_ci/* 2758c2ecf20Sopenharmony_ci * csi2_ctx_config - CSI2 context configuration. 2768c2ecf20Sopenharmony_ci * @ctx: context configuration 2778c2ecf20Sopenharmony_ci * 2788c2ecf20Sopenharmony_ci */ 2798c2ecf20Sopenharmony_cistatic void csi2_ctx_config(struct isp_device *isp, 2808c2ecf20Sopenharmony_ci struct isp_csi2_device *csi2, 2818c2ecf20Sopenharmony_ci struct isp_csi2_ctx_cfg *ctx) 2828c2ecf20Sopenharmony_ci{ 2838c2ecf20Sopenharmony_ci u32 reg; 2848c2ecf20Sopenharmony_ci 2858c2ecf20Sopenharmony_ci /* Set up CSI2_CTx_CTRL1 */ 2868c2ecf20Sopenharmony_ci reg = isp_reg_readl(isp, csi2->regs1, ISPCSI2_CTX_CTRL1(ctx->ctxnum)); 2878c2ecf20Sopenharmony_ci 2888c2ecf20Sopenharmony_ci if (ctx->eof_enabled) 2898c2ecf20Sopenharmony_ci reg |= ISPCSI2_CTX_CTRL1_EOF_EN; 2908c2ecf20Sopenharmony_ci else 2918c2ecf20Sopenharmony_ci reg &= ~ISPCSI2_CTX_CTRL1_EOF_EN; 2928c2ecf20Sopenharmony_ci 2938c2ecf20Sopenharmony_ci if (ctx->eol_enabled) 2948c2ecf20Sopenharmony_ci reg |= ISPCSI2_CTX_CTRL1_EOL_EN; 2958c2ecf20Sopenharmony_ci else 2968c2ecf20Sopenharmony_ci reg &= ~ISPCSI2_CTX_CTRL1_EOL_EN; 2978c2ecf20Sopenharmony_ci 2988c2ecf20Sopenharmony_ci if (ctx->checksum_enabled) 2998c2ecf20Sopenharmony_ci reg |= ISPCSI2_CTX_CTRL1_CS_EN; 3008c2ecf20Sopenharmony_ci else 3018c2ecf20Sopenharmony_ci reg &= ~ISPCSI2_CTX_CTRL1_CS_EN; 3028c2ecf20Sopenharmony_ci 3038c2ecf20Sopenharmony_ci isp_reg_writel(isp, reg, csi2->regs1, ISPCSI2_CTX_CTRL1(ctx->ctxnum)); 3048c2ecf20Sopenharmony_ci 3058c2ecf20Sopenharmony_ci /* Set up CSI2_CTx_CTRL2 */ 3068c2ecf20Sopenharmony_ci reg = isp_reg_readl(isp, csi2->regs1, ISPCSI2_CTX_CTRL2(ctx->ctxnum)); 3078c2ecf20Sopenharmony_ci 3088c2ecf20Sopenharmony_ci reg &= ~(ISPCSI2_CTX_CTRL2_VIRTUAL_ID_MASK); 3098c2ecf20Sopenharmony_ci reg |= ctx->virtual_id << ISPCSI2_CTX_CTRL2_VIRTUAL_ID_SHIFT; 3108c2ecf20Sopenharmony_ci 3118c2ecf20Sopenharmony_ci reg &= ~(ISPCSI2_CTX_CTRL2_FORMAT_MASK); 3128c2ecf20Sopenharmony_ci reg |= ctx->format_id << ISPCSI2_CTX_CTRL2_FORMAT_SHIFT; 3138c2ecf20Sopenharmony_ci 3148c2ecf20Sopenharmony_ci if (ctx->dpcm_decompress) { 3158c2ecf20Sopenharmony_ci if (ctx->dpcm_predictor) 3168c2ecf20Sopenharmony_ci reg |= ISPCSI2_CTX_CTRL2_DPCM_PRED; 3178c2ecf20Sopenharmony_ci else 3188c2ecf20Sopenharmony_ci reg &= ~ISPCSI2_CTX_CTRL2_DPCM_PRED; 3198c2ecf20Sopenharmony_ci } 3208c2ecf20Sopenharmony_ci 3218c2ecf20Sopenharmony_ci if (is_usr_def_mapping(ctx->format_id)) { 3228c2ecf20Sopenharmony_ci reg &= ~ISPCSI2_CTX_CTRL2_USER_DEF_MAP_MASK; 3238c2ecf20Sopenharmony_ci reg |= 2 << ISPCSI2_CTX_CTRL2_USER_DEF_MAP_SHIFT; 3248c2ecf20Sopenharmony_ci } 3258c2ecf20Sopenharmony_ci 3268c2ecf20Sopenharmony_ci isp_reg_writel(isp, reg, csi2->regs1, ISPCSI2_CTX_CTRL2(ctx->ctxnum)); 3278c2ecf20Sopenharmony_ci 3288c2ecf20Sopenharmony_ci /* Set up CSI2_CTx_CTRL3 */ 3298c2ecf20Sopenharmony_ci reg = isp_reg_readl(isp, csi2->regs1, ISPCSI2_CTX_CTRL3(ctx->ctxnum)); 3308c2ecf20Sopenharmony_ci reg &= ~(ISPCSI2_CTX_CTRL3_ALPHA_MASK); 3318c2ecf20Sopenharmony_ci reg |= (ctx->alpha << ISPCSI2_CTX_CTRL3_ALPHA_SHIFT); 3328c2ecf20Sopenharmony_ci 3338c2ecf20Sopenharmony_ci isp_reg_writel(isp, reg, csi2->regs1, ISPCSI2_CTX_CTRL3(ctx->ctxnum)); 3348c2ecf20Sopenharmony_ci 3358c2ecf20Sopenharmony_ci /* Set up CSI2_CTx_DAT_OFST */ 3368c2ecf20Sopenharmony_ci reg = isp_reg_readl(isp, csi2->regs1, 3378c2ecf20Sopenharmony_ci ISPCSI2_CTX_DAT_OFST(ctx->ctxnum)); 3388c2ecf20Sopenharmony_ci reg &= ~ISPCSI2_CTX_DAT_OFST_OFST_MASK; 3398c2ecf20Sopenharmony_ci reg |= ctx->data_offset << ISPCSI2_CTX_DAT_OFST_OFST_SHIFT; 3408c2ecf20Sopenharmony_ci isp_reg_writel(isp, reg, csi2->regs1, 3418c2ecf20Sopenharmony_ci ISPCSI2_CTX_DAT_OFST(ctx->ctxnum)); 3428c2ecf20Sopenharmony_ci 3438c2ecf20Sopenharmony_ci isp_reg_writel(isp, ctx->ping_addr, 3448c2ecf20Sopenharmony_ci csi2->regs1, ISPCSI2_CTX_DAT_PING_ADDR(ctx->ctxnum)); 3458c2ecf20Sopenharmony_ci 3468c2ecf20Sopenharmony_ci isp_reg_writel(isp, ctx->pong_addr, 3478c2ecf20Sopenharmony_ci csi2->regs1, ISPCSI2_CTX_DAT_PONG_ADDR(ctx->ctxnum)); 3488c2ecf20Sopenharmony_ci} 3498c2ecf20Sopenharmony_ci 3508c2ecf20Sopenharmony_ci/* 3518c2ecf20Sopenharmony_ci * csi2_timing_config - CSI2 timing configuration. 3528c2ecf20Sopenharmony_ci * @timing: csi2_timing_cfg structure 3538c2ecf20Sopenharmony_ci */ 3548c2ecf20Sopenharmony_cistatic void csi2_timing_config(struct isp_device *isp, 3558c2ecf20Sopenharmony_ci struct isp_csi2_device *csi2, 3568c2ecf20Sopenharmony_ci struct isp_csi2_timing_cfg *timing) 3578c2ecf20Sopenharmony_ci{ 3588c2ecf20Sopenharmony_ci u32 reg; 3598c2ecf20Sopenharmony_ci 3608c2ecf20Sopenharmony_ci reg = isp_reg_readl(isp, csi2->regs1, ISPCSI2_TIMING); 3618c2ecf20Sopenharmony_ci 3628c2ecf20Sopenharmony_ci if (timing->force_rx_mode) 3638c2ecf20Sopenharmony_ci reg |= ISPCSI2_TIMING_FORCE_RX_MODE_IO(timing->ionum); 3648c2ecf20Sopenharmony_ci else 3658c2ecf20Sopenharmony_ci reg &= ~ISPCSI2_TIMING_FORCE_RX_MODE_IO(timing->ionum); 3668c2ecf20Sopenharmony_ci 3678c2ecf20Sopenharmony_ci if (timing->stop_state_16x) 3688c2ecf20Sopenharmony_ci reg |= ISPCSI2_TIMING_STOP_STATE_X16_IO(timing->ionum); 3698c2ecf20Sopenharmony_ci else 3708c2ecf20Sopenharmony_ci reg &= ~ISPCSI2_TIMING_STOP_STATE_X16_IO(timing->ionum); 3718c2ecf20Sopenharmony_ci 3728c2ecf20Sopenharmony_ci if (timing->stop_state_4x) 3738c2ecf20Sopenharmony_ci reg |= ISPCSI2_TIMING_STOP_STATE_X4_IO(timing->ionum); 3748c2ecf20Sopenharmony_ci else 3758c2ecf20Sopenharmony_ci reg &= ~ISPCSI2_TIMING_STOP_STATE_X4_IO(timing->ionum); 3768c2ecf20Sopenharmony_ci 3778c2ecf20Sopenharmony_ci reg &= ~ISPCSI2_TIMING_STOP_STATE_COUNTER_IO_MASK(timing->ionum); 3788c2ecf20Sopenharmony_ci reg |= timing->stop_state_counter << 3798c2ecf20Sopenharmony_ci ISPCSI2_TIMING_STOP_STATE_COUNTER_IO_SHIFT(timing->ionum); 3808c2ecf20Sopenharmony_ci 3818c2ecf20Sopenharmony_ci isp_reg_writel(isp, reg, csi2->regs1, ISPCSI2_TIMING); 3828c2ecf20Sopenharmony_ci} 3838c2ecf20Sopenharmony_ci 3848c2ecf20Sopenharmony_ci/* 3858c2ecf20Sopenharmony_ci * csi2_irq_ctx_set - Enables CSI2 Context IRQs. 3868c2ecf20Sopenharmony_ci * @enable: Enable/disable CSI2 Context interrupts 3878c2ecf20Sopenharmony_ci */ 3888c2ecf20Sopenharmony_cistatic void csi2_irq_ctx_set(struct isp_device *isp, 3898c2ecf20Sopenharmony_ci struct isp_csi2_device *csi2, int enable) 3908c2ecf20Sopenharmony_ci{ 3918c2ecf20Sopenharmony_ci int i; 3928c2ecf20Sopenharmony_ci 3938c2ecf20Sopenharmony_ci for (i = 0; i < 8; i++) { 3948c2ecf20Sopenharmony_ci isp_reg_writel(isp, ISPCSI2_CTX_IRQSTATUS_FE_IRQ, csi2->regs1, 3958c2ecf20Sopenharmony_ci ISPCSI2_CTX_IRQSTATUS(i)); 3968c2ecf20Sopenharmony_ci if (enable) 3978c2ecf20Sopenharmony_ci isp_reg_set(isp, csi2->regs1, ISPCSI2_CTX_IRQENABLE(i), 3988c2ecf20Sopenharmony_ci ISPCSI2_CTX_IRQSTATUS_FE_IRQ); 3998c2ecf20Sopenharmony_ci else 4008c2ecf20Sopenharmony_ci isp_reg_clr(isp, csi2->regs1, ISPCSI2_CTX_IRQENABLE(i), 4018c2ecf20Sopenharmony_ci ISPCSI2_CTX_IRQSTATUS_FE_IRQ); 4028c2ecf20Sopenharmony_ci } 4038c2ecf20Sopenharmony_ci} 4048c2ecf20Sopenharmony_ci 4058c2ecf20Sopenharmony_ci/* 4068c2ecf20Sopenharmony_ci * csi2_irq_complexio1_set - Enables CSI2 ComplexIO IRQs. 4078c2ecf20Sopenharmony_ci * @enable: Enable/disable CSI2 ComplexIO #1 interrupts 4088c2ecf20Sopenharmony_ci */ 4098c2ecf20Sopenharmony_cistatic void csi2_irq_complexio1_set(struct isp_device *isp, 4108c2ecf20Sopenharmony_ci struct isp_csi2_device *csi2, int enable) 4118c2ecf20Sopenharmony_ci{ 4128c2ecf20Sopenharmony_ci u32 reg; 4138c2ecf20Sopenharmony_ci reg = ISPCSI2_PHY_IRQENABLE_STATEALLULPMEXIT | 4148c2ecf20Sopenharmony_ci ISPCSI2_PHY_IRQENABLE_STATEALLULPMENTER | 4158c2ecf20Sopenharmony_ci ISPCSI2_PHY_IRQENABLE_STATEULPM5 | 4168c2ecf20Sopenharmony_ci ISPCSI2_PHY_IRQENABLE_ERRCONTROL5 | 4178c2ecf20Sopenharmony_ci ISPCSI2_PHY_IRQENABLE_ERRESC5 | 4188c2ecf20Sopenharmony_ci ISPCSI2_PHY_IRQENABLE_ERRSOTSYNCHS5 | 4198c2ecf20Sopenharmony_ci ISPCSI2_PHY_IRQENABLE_ERRSOTHS5 | 4208c2ecf20Sopenharmony_ci ISPCSI2_PHY_IRQENABLE_STATEULPM4 | 4218c2ecf20Sopenharmony_ci ISPCSI2_PHY_IRQENABLE_ERRCONTROL4 | 4228c2ecf20Sopenharmony_ci ISPCSI2_PHY_IRQENABLE_ERRESC4 | 4238c2ecf20Sopenharmony_ci ISPCSI2_PHY_IRQENABLE_ERRSOTSYNCHS4 | 4248c2ecf20Sopenharmony_ci ISPCSI2_PHY_IRQENABLE_ERRSOTHS4 | 4258c2ecf20Sopenharmony_ci ISPCSI2_PHY_IRQENABLE_STATEULPM3 | 4268c2ecf20Sopenharmony_ci ISPCSI2_PHY_IRQENABLE_ERRCONTROL3 | 4278c2ecf20Sopenharmony_ci ISPCSI2_PHY_IRQENABLE_ERRESC3 | 4288c2ecf20Sopenharmony_ci ISPCSI2_PHY_IRQENABLE_ERRSOTSYNCHS3 | 4298c2ecf20Sopenharmony_ci ISPCSI2_PHY_IRQENABLE_ERRSOTHS3 | 4308c2ecf20Sopenharmony_ci ISPCSI2_PHY_IRQENABLE_STATEULPM2 | 4318c2ecf20Sopenharmony_ci ISPCSI2_PHY_IRQENABLE_ERRCONTROL2 | 4328c2ecf20Sopenharmony_ci ISPCSI2_PHY_IRQENABLE_ERRESC2 | 4338c2ecf20Sopenharmony_ci ISPCSI2_PHY_IRQENABLE_ERRSOTSYNCHS2 | 4348c2ecf20Sopenharmony_ci ISPCSI2_PHY_IRQENABLE_ERRSOTHS2 | 4358c2ecf20Sopenharmony_ci ISPCSI2_PHY_IRQENABLE_STATEULPM1 | 4368c2ecf20Sopenharmony_ci ISPCSI2_PHY_IRQENABLE_ERRCONTROL1 | 4378c2ecf20Sopenharmony_ci ISPCSI2_PHY_IRQENABLE_ERRESC1 | 4388c2ecf20Sopenharmony_ci ISPCSI2_PHY_IRQENABLE_ERRSOTSYNCHS1 | 4398c2ecf20Sopenharmony_ci ISPCSI2_PHY_IRQENABLE_ERRSOTHS1; 4408c2ecf20Sopenharmony_ci isp_reg_writel(isp, reg, csi2->regs1, ISPCSI2_PHY_IRQSTATUS); 4418c2ecf20Sopenharmony_ci if (enable) 4428c2ecf20Sopenharmony_ci reg |= isp_reg_readl(isp, csi2->regs1, ISPCSI2_PHY_IRQENABLE); 4438c2ecf20Sopenharmony_ci else 4448c2ecf20Sopenharmony_ci reg = 0; 4458c2ecf20Sopenharmony_ci isp_reg_writel(isp, reg, csi2->regs1, ISPCSI2_PHY_IRQENABLE); 4468c2ecf20Sopenharmony_ci} 4478c2ecf20Sopenharmony_ci 4488c2ecf20Sopenharmony_ci/* 4498c2ecf20Sopenharmony_ci * csi2_irq_status_set - Enables CSI2 Status IRQs. 4508c2ecf20Sopenharmony_ci * @enable: Enable/disable CSI2 Status interrupts 4518c2ecf20Sopenharmony_ci */ 4528c2ecf20Sopenharmony_cistatic void csi2_irq_status_set(struct isp_device *isp, 4538c2ecf20Sopenharmony_ci struct isp_csi2_device *csi2, int enable) 4548c2ecf20Sopenharmony_ci{ 4558c2ecf20Sopenharmony_ci u32 reg; 4568c2ecf20Sopenharmony_ci reg = ISPCSI2_IRQSTATUS_OCP_ERR_IRQ | 4578c2ecf20Sopenharmony_ci ISPCSI2_IRQSTATUS_SHORT_PACKET_IRQ | 4588c2ecf20Sopenharmony_ci ISPCSI2_IRQSTATUS_ECC_CORRECTION_IRQ | 4598c2ecf20Sopenharmony_ci ISPCSI2_IRQSTATUS_ECC_NO_CORRECTION_IRQ | 4608c2ecf20Sopenharmony_ci ISPCSI2_IRQSTATUS_COMPLEXIO2_ERR_IRQ | 4618c2ecf20Sopenharmony_ci ISPCSI2_IRQSTATUS_COMPLEXIO1_ERR_IRQ | 4628c2ecf20Sopenharmony_ci ISPCSI2_IRQSTATUS_FIFO_OVF_IRQ | 4638c2ecf20Sopenharmony_ci ISPCSI2_IRQSTATUS_CONTEXT(0); 4648c2ecf20Sopenharmony_ci isp_reg_writel(isp, reg, csi2->regs1, ISPCSI2_IRQSTATUS); 4658c2ecf20Sopenharmony_ci if (enable) 4668c2ecf20Sopenharmony_ci reg |= isp_reg_readl(isp, csi2->regs1, ISPCSI2_IRQENABLE); 4678c2ecf20Sopenharmony_ci else 4688c2ecf20Sopenharmony_ci reg = 0; 4698c2ecf20Sopenharmony_ci 4708c2ecf20Sopenharmony_ci isp_reg_writel(isp, reg, csi2->regs1, ISPCSI2_IRQENABLE); 4718c2ecf20Sopenharmony_ci} 4728c2ecf20Sopenharmony_ci 4738c2ecf20Sopenharmony_ci/* 4748c2ecf20Sopenharmony_ci * omap3isp_csi2_reset - Resets the CSI2 module. 4758c2ecf20Sopenharmony_ci * 4768c2ecf20Sopenharmony_ci * Must be called with the phy lock held. 4778c2ecf20Sopenharmony_ci * 4788c2ecf20Sopenharmony_ci * Returns 0 if successful, or -EBUSY if power command didn't respond. 4798c2ecf20Sopenharmony_ci */ 4808c2ecf20Sopenharmony_ciint omap3isp_csi2_reset(struct isp_csi2_device *csi2) 4818c2ecf20Sopenharmony_ci{ 4828c2ecf20Sopenharmony_ci struct isp_device *isp = csi2->isp; 4838c2ecf20Sopenharmony_ci u8 soft_reset_retries = 0; 4848c2ecf20Sopenharmony_ci u32 reg; 4858c2ecf20Sopenharmony_ci int i; 4868c2ecf20Sopenharmony_ci 4878c2ecf20Sopenharmony_ci if (!csi2->available) 4888c2ecf20Sopenharmony_ci return -ENODEV; 4898c2ecf20Sopenharmony_ci 4908c2ecf20Sopenharmony_ci if (csi2->phy->entity) 4918c2ecf20Sopenharmony_ci return -EBUSY; 4928c2ecf20Sopenharmony_ci 4938c2ecf20Sopenharmony_ci isp_reg_set(isp, csi2->regs1, ISPCSI2_SYSCONFIG, 4948c2ecf20Sopenharmony_ci ISPCSI2_SYSCONFIG_SOFT_RESET); 4958c2ecf20Sopenharmony_ci 4968c2ecf20Sopenharmony_ci do { 4978c2ecf20Sopenharmony_ci reg = isp_reg_readl(isp, csi2->regs1, ISPCSI2_SYSSTATUS) & 4988c2ecf20Sopenharmony_ci ISPCSI2_SYSSTATUS_RESET_DONE; 4998c2ecf20Sopenharmony_ci if (reg == ISPCSI2_SYSSTATUS_RESET_DONE) 5008c2ecf20Sopenharmony_ci break; 5018c2ecf20Sopenharmony_ci soft_reset_retries++; 5028c2ecf20Sopenharmony_ci if (soft_reset_retries < 5) 5038c2ecf20Sopenharmony_ci udelay(100); 5048c2ecf20Sopenharmony_ci } while (soft_reset_retries < 5); 5058c2ecf20Sopenharmony_ci 5068c2ecf20Sopenharmony_ci if (soft_reset_retries == 5) { 5078c2ecf20Sopenharmony_ci dev_err(isp->dev, "CSI2: Soft reset try count exceeded!\n"); 5088c2ecf20Sopenharmony_ci return -EBUSY; 5098c2ecf20Sopenharmony_ci } 5108c2ecf20Sopenharmony_ci 5118c2ecf20Sopenharmony_ci if (isp->revision == ISP_REVISION_15_0) 5128c2ecf20Sopenharmony_ci isp_reg_set(isp, csi2->regs1, ISPCSI2_PHY_CFG, 5138c2ecf20Sopenharmony_ci ISPCSI2_PHY_CFG_RESET_CTRL); 5148c2ecf20Sopenharmony_ci 5158c2ecf20Sopenharmony_ci i = 100; 5168c2ecf20Sopenharmony_ci do { 5178c2ecf20Sopenharmony_ci reg = isp_reg_readl(isp, csi2->phy->phy_regs, ISPCSIPHY_REG1) 5188c2ecf20Sopenharmony_ci & ISPCSIPHY_REG1_RESET_DONE_CTRLCLK; 5198c2ecf20Sopenharmony_ci if (reg == ISPCSIPHY_REG1_RESET_DONE_CTRLCLK) 5208c2ecf20Sopenharmony_ci break; 5218c2ecf20Sopenharmony_ci udelay(100); 5228c2ecf20Sopenharmony_ci } while (--i > 0); 5238c2ecf20Sopenharmony_ci 5248c2ecf20Sopenharmony_ci if (i == 0) { 5258c2ecf20Sopenharmony_ci dev_err(isp->dev, 5268c2ecf20Sopenharmony_ci "CSI2: Reset for CSI2_96M_FCLK domain Failed!\n"); 5278c2ecf20Sopenharmony_ci return -EBUSY; 5288c2ecf20Sopenharmony_ci } 5298c2ecf20Sopenharmony_ci 5308c2ecf20Sopenharmony_ci if (isp->autoidle) 5318c2ecf20Sopenharmony_ci isp_reg_clr_set(isp, csi2->regs1, ISPCSI2_SYSCONFIG, 5328c2ecf20Sopenharmony_ci ISPCSI2_SYSCONFIG_MSTANDBY_MODE_MASK | 5338c2ecf20Sopenharmony_ci ISPCSI2_SYSCONFIG_AUTO_IDLE, 5348c2ecf20Sopenharmony_ci ISPCSI2_SYSCONFIG_MSTANDBY_MODE_SMART | 5358c2ecf20Sopenharmony_ci ((isp->revision == ISP_REVISION_15_0) ? 5368c2ecf20Sopenharmony_ci ISPCSI2_SYSCONFIG_AUTO_IDLE : 0)); 5378c2ecf20Sopenharmony_ci else 5388c2ecf20Sopenharmony_ci isp_reg_clr_set(isp, csi2->regs1, ISPCSI2_SYSCONFIG, 5398c2ecf20Sopenharmony_ci ISPCSI2_SYSCONFIG_MSTANDBY_MODE_MASK | 5408c2ecf20Sopenharmony_ci ISPCSI2_SYSCONFIG_AUTO_IDLE, 5418c2ecf20Sopenharmony_ci ISPCSI2_SYSCONFIG_MSTANDBY_MODE_NO); 5428c2ecf20Sopenharmony_ci 5438c2ecf20Sopenharmony_ci return 0; 5448c2ecf20Sopenharmony_ci} 5458c2ecf20Sopenharmony_ci 5468c2ecf20Sopenharmony_cistatic int csi2_configure(struct isp_csi2_device *csi2) 5478c2ecf20Sopenharmony_ci{ 5488c2ecf20Sopenharmony_ci struct isp_pipeline *pipe = to_isp_pipeline(&csi2->subdev.entity); 5498c2ecf20Sopenharmony_ci const struct isp_bus_cfg *buscfg; 5508c2ecf20Sopenharmony_ci struct isp_device *isp = csi2->isp; 5518c2ecf20Sopenharmony_ci struct isp_csi2_timing_cfg *timing = &csi2->timing[0]; 5528c2ecf20Sopenharmony_ci struct v4l2_subdev *sensor; 5538c2ecf20Sopenharmony_ci struct media_pad *pad; 5548c2ecf20Sopenharmony_ci 5558c2ecf20Sopenharmony_ci /* 5568c2ecf20Sopenharmony_ci * CSI2 fields that can be updated while the context has 5578c2ecf20Sopenharmony_ci * been enabled or the interface has been enabled are not 5588c2ecf20Sopenharmony_ci * updated dynamically currently. So we do not allow to 5598c2ecf20Sopenharmony_ci * reconfigure if either has been enabled 5608c2ecf20Sopenharmony_ci */ 5618c2ecf20Sopenharmony_ci if (csi2->contexts[0].enabled || csi2->ctrl.if_enable) 5628c2ecf20Sopenharmony_ci return -EBUSY; 5638c2ecf20Sopenharmony_ci 5648c2ecf20Sopenharmony_ci pad = media_entity_remote_pad(&csi2->pads[CSI2_PAD_SINK]); 5658c2ecf20Sopenharmony_ci sensor = media_entity_to_v4l2_subdev(pad->entity); 5668c2ecf20Sopenharmony_ci buscfg = v4l2_subdev_to_bus_cfg(pipe->external); 5678c2ecf20Sopenharmony_ci 5688c2ecf20Sopenharmony_ci csi2->frame_skip = 0; 5698c2ecf20Sopenharmony_ci v4l2_subdev_call(sensor, sensor, g_skip_frames, &csi2->frame_skip); 5708c2ecf20Sopenharmony_ci 5718c2ecf20Sopenharmony_ci csi2->ctrl.vp_out_ctrl = 5728c2ecf20Sopenharmony_ci clamp_t(unsigned int, pipe->l3_ick / pipe->external_rate - 1, 5738c2ecf20Sopenharmony_ci 1, 3); 5748c2ecf20Sopenharmony_ci dev_dbg(isp->dev, "%s: l3_ick %lu, external_rate %u, vp_out_ctrl %u\n", 5758c2ecf20Sopenharmony_ci __func__, pipe->l3_ick, pipe->external_rate, 5768c2ecf20Sopenharmony_ci csi2->ctrl.vp_out_ctrl); 5778c2ecf20Sopenharmony_ci csi2->ctrl.frame_mode = ISP_CSI2_FRAME_IMMEDIATE; 5788c2ecf20Sopenharmony_ci csi2->ctrl.ecc_enable = buscfg->bus.csi2.crc; 5798c2ecf20Sopenharmony_ci 5808c2ecf20Sopenharmony_ci timing->ionum = 1; 5818c2ecf20Sopenharmony_ci timing->force_rx_mode = 1; 5828c2ecf20Sopenharmony_ci timing->stop_state_16x = 1; 5838c2ecf20Sopenharmony_ci timing->stop_state_4x = 1; 5848c2ecf20Sopenharmony_ci timing->stop_state_counter = 0x1FF; 5858c2ecf20Sopenharmony_ci 5868c2ecf20Sopenharmony_ci /* 5878c2ecf20Sopenharmony_ci * The CSI2 receiver can't do any format conversion except DPCM 5888c2ecf20Sopenharmony_ci * decompression, so every set_format call configures both pads 5898c2ecf20Sopenharmony_ci * and enables DPCM decompression as a special case: 5908c2ecf20Sopenharmony_ci */ 5918c2ecf20Sopenharmony_ci if (csi2->formats[CSI2_PAD_SINK].code != 5928c2ecf20Sopenharmony_ci csi2->formats[CSI2_PAD_SOURCE].code) 5938c2ecf20Sopenharmony_ci csi2->dpcm_decompress = true; 5948c2ecf20Sopenharmony_ci else 5958c2ecf20Sopenharmony_ci csi2->dpcm_decompress = false; 5968c2ecf20Sopenharmony_ci 5978c2ecf20Sopenharmony_ci csi2->contexts[0].format_id = csi2_ctx_map_format(csi2); 5988c2ecf20Sopenharmony_ci 5998c2ecf20Sopenharmony_ci if (csi2->video_out.bpl_padding == 0) 6008c2ecf20Sopenharmony_ci csi2->contexts[0].data_offset = 0; 6018c2ecf20Sopenharmony_ci else 6028c2ecf20Sopenharmony_ci csi2->contexts[0].data_offset = csi2->video_out.bpl_value; 6038c2ecf20Sopenharmony_ci 6048c2ecf20Sopenharmony_ci /* 6058c2ecf20Sopenharmony_ci * Enable end of frame and end of line signals generation for 6068c2ecf20Sopenharmony_ci * context 0. These signals are generated from CSI2 receiver to 6078c2ecf20Sopenharmony_ci * qualify the last pixel of a frame and the last pixel of a line. 6088c2ecf20Sopenharmony_ci * Without enabling the signals CSI2 receiver writes data to memory 6098c2ecf20Sopenharmony_ci * beyond buffer size and/or data line offset is not handled correctly. 6108c2ecf20Sopenharmony_ci */ 6118c2ecf20Sopenharmony_ci csi2->contexts[0].eof_enabled = 1; 6128c2ecf20Sopenharmony_ci csi2->contexts[0].eol_enabled = 1; 6138c2ecf20Sopenharmony_ci 6148c2ecf20Sopenharmony_ci csi2_irq_complexio1_set(isp, csi2, 1); 6158c2ecf20Sopenharmony_ci csi2_irq_ctx_set(isp, csi2, 1); 6168c2ecf20Sopenharmony_ci csi2_irq_status_set(isp, csi2, 1); 6178c2ecf20Sopenharmony_ci 6188c2ecf20Sopenharmony_ci /* Set configuration (timings, format and links) */ 6198c2ecf20Sopenharmony_ci csi2_timing_config(isp, csi2, timing); 6208c2ecf20Sopenharmony_ci csi2_recv_config(isp, csi2, &csi2->ctrl); 6218c2ecf20Sopenharmony_ci csi2_ctx_config(isp, csi2, &csi2->contexts[0]); 6228c2ecf20Sopenharmony_ci 6238c2ecf20Sopenharmony_ci return 0; 6248c2ecf20Sopenharmony_ci} 6258c2ecf20Sopenharmony_ci 6268c2ecf20Sopenharmony_ci/* 6278c2ecf20Sopenharmony_ci * csi2_print_status - Prints CSI2 debug information. 6288c2ecf20Sopenharmony_ci */ 6298c2ecf20Sopenharmony_ci#define CSI2_PRINT_REGISTER(isp, regs, name)\ 6308c2ecf20Sopenharmony_ci dev_dbg(isp->dev, "###CSI2 " #name "=0x%08x\n", \ 6318c2ecf20Sopenharmony_ci isp_reg_readl(isp, regs, ISPCSI2_##name)) 6328c2ecf20Sopenharmony_ci 6338c2ecf20Sopenharmony_cistatic void csi2_print_status(struct isp_csi2_device *csi2) 6348c2ecf20Sopenharmony_ci{ 6358c2ecf20Sopenharmony_ci struct isp_device *isp = csi2->isp; 6368c2ecf20Sopenharmony_ci 6378c2ecf20Sopenharmony_ci if (!csi2->available) 6388c2ecf20Sopenharmony_ci return; 6398c2ecf20Sopenharmony_ci 6408c2ecf20Sopenharmony_ci dev_dbg(isp->dev, "-------------CSI2 Register dump-------------\n"); 6418c2ecf20Sopenharmony_ci 6428c2ecf20Sopenharmony_ci CSI2_PRINT_REGISTER(isp, csi2->regs1, SYSCONFIG); 6438c2ecf20Sopenharmony_ci CSI2_PRINT_REGISTER(isp, csi2->regs1, SYSSTATUS); 6448c2ecf20Sopenharmony_ci CSI2_PRINT_REGISTER(isp, csi2->regs1, IRQENABLE); 6458c2ecf20Sopenharmony_ci CSI2_PRINT_REGISTER(isp, csi2->regs1, IRQSTATUS); 6468c2ecf20Sopenharmony_ci CSI2_PRINT_REGISTER(isp, csi2->regs1, CTRL); 6478c2ecf20Sopenharmony_ci CSI2_PRINT_REGISTER(isp, csi2->regs1, DBG_H); 6488c2ecf20Sopenharmony_ci CSI2_PRINT_REGISTER(isp, csi2->regs1, GNQ); 6498c2ecf20Sopenharmony_ci CSI2_PRINT_REGISTER(isp, csi2->regs1, PHY_CFG); 6508c2ecf20Sopenharmony_ci CSI2_PRINT_REGISTER(isp, csi2->regs1, PHY_IRQSTATUS); 6518c2ecf20Sopenharmony_ci CSI2_PRINT_REGISTER(isp, csi2->regs1, SHORT_PACKET); 6528c2ecf20Sopenharmony_ci CSI2_PRINT_REGISTER(isp, csi2->regs1, PHY_IRQENABLE); 6538c2ecf20Sopenharmony_ci CSI2_PRINT_REGISTER(isp, csi2->regs1, DBG_P); 6548c2ecf20Sopenharmony_ci CSI2_PRINT_REGISTER(isp, csi2->regs1, TIMING); 6558c2ecf20Sopenharmony_ci CSI2_PRINT_REGISTER(isp, csi2->regs1, CTX_CTRL1(0)); 6568c2ecf20Sopenharmony_ci CSI2_PRINT_REGISTER(isp, csi2->regs1, CTX_CTRL2(0)); 6578c2ecf20Sopenharmony_ci CSI2_PRINT_REGISTER(isp, csi2->regs1, CTX_DAT_OFST(0)); 6588c2ecf20Sopenharmony_ci CSI2_PRINT_REGISTER(isp, csi2->regs1, CTX_DAT_PING_ADDR(0)); 6598c2ecf20Sopenharmony_ci CSI2_PRINT_REGISTER(isp, csi2->regs1, CTX_DAT_PONG_ADDR(0)); 6608c2ecf20Sopenharmony_ci CSI2_PRINT_REGISTER(isp, csi2->regs1, CTX_IRQENABLE(0)); 6618c2ecf20Sopenharmony_ci CSI2_PRINT_REGISTER(isp, csi2->regs1, CTX_IRQSTATUS(0)); 6628c2ecf20Sopenharmony_ci CSI2_PRINT_REGISTER(isp, csi2->regs1, CTX_CTRL3(0)); 6638c2ecf20Sopenharmony_ci 6648c2ecf20Sopenharmony_ci dev_dbg(isp->dev, "--------------------------------------------\n"); 6658c2ecf20Sopenharmony_ci} 6668c2ecf20Sopenharmony_ci 6678c2ecf20Sopenharmony_ci/* ----------------------------------------------------------------------------- 6688c2ecf20Sopenharmony_ci * Interrupt handling 6698c2ecf20Sopenharmony_ci */ 6708c2ecf20Sopenharmony_ci 6718c2ecf20Sopenharmony_ci/* 6728c2ecf20Sopenharmony_ci * csi2_isr_buffer - Does buffer handling at end-of-frame 6738c2ecf20Sopenharmony_ci * when writing to memory. 6748c2ecf20Sopenharmony_ci */ 6758c2ecf20Sopenharmony_cistatic void csi2_isr_buffer(struct isp_csi2_device *csi2) 6768c2ecf20Sopenharmony_ci{ 6778c2ecf20Sopenharmony_ci struct isp_device *isp = csi2->isp; 6788c2ecf20Sopenharmony_ci struct isp_buffer *buffer; 6798c2ecf20Sopenharmony_ci 6808c2ecf20Sopenharmony_ci csi2_ctx_enable(isp, csi2, 0, 0); 6818c2ecf20Sopenharmony_ci 6828c2ecf20Sopenharmony_ci buffer = omap3isp_video_buffer_next(&csi2->video_out); 6838c2ecf20Sopenharmony_ci 6848c2ecf20Sopenharmony_ci /* 6858c2ecf20Sopenharmony_ci * Let video queue operation restart engine if there is an underrun 6868c2ecf20Sopenharmony_ci * condition. 6878c2ecf20Sopenharmony_ci */ 6888c2ecf20Sopenharmony_ci if (buffer == NULL) 6898c2ecf20Sopenharmony_ci return; 6908c2ecf20Sopenharmony_ci 6918c2ecf20Sopenharmony_ci csi2_set_outaddr(csi2, buffer->dma); 6928c2ecf20Sopenharmony_ci csi2_ctx_enable(isp, csi2, 0, 1); 6938c2ecf20Sopenharmony_ci} 6948c2ecf20Sopenharmony_ci 6958c2ecf20Sopenharmony_cistatic void csi2_isr_ctx(struct isp_csi2_device *csi2, 6968c2ecf20Sopenharmony_ci struct isp_csi2_ctx_cfg *ctx) 6978c2ecf20Sopenharmony_ci{ 6988c2ecf20Sopenharmony_ci struct isp_device *isp = csi2->isp; 6998c2ecf20Sopenharmony_ci unsigned int n = ctx->ctxnum; 7008c2ecf20Sopenharmony_ci u32 status; 7018c2ecf20Sopenharmony_ci 7028c2ecf20Sopenharmony_ci status = isp_reg_readl(isp, csi2->regs1, ISPCSI2_CTX_IRQSTATUS(n)); 7038c2ecf20Sopenharmony_ci isp_reg_writel(isp, status, csi2->regs1, ISPCSI2_CTX_IRQSTATUS(n)); 7048c2ecf20Sopenharmony_ci 7058c2ecf20Sopenharmony_ci if (!(status & ISPCSI2_CTX_IRQSTATUS_FE_IRQ)) 7068c2ecf20Sopenharmony_ci return; 7078c2ecf20Sopenharmony_ci 7088c2ecf20Sopenharmony_ci /* Skip interrupts until we reach the frame skip count. The CSI2 will be 7098c2ecf20Sopenharmony_ci * automatically disabled, as the frame skip count has been programmed 7108c2ecf20Sopenharmony_ci * in the CSI2_CTx_CTRL1::COUNT field, so re-enable it. 7118c2ecf20Sopenharmony_ci * 7128c2ecf20Sopenharmony_ci * It would have been nice to rely on the FRAME_NUMBER interrupt instead 7138c2ecf20Sopenharmony_ci * but it turned out that the interrupt is only generated when the CSI2 7148c2ecf20Sopenharmony_ci * writes to memory (the CSI2_CTx_CTRL1::COUNT field is decreased 7158c2ecf20Sopenharmony_ci * correctly and reaches 0 when data is forwarded to the video port only 7168c2ecf20Sopenharmony_ci * but no interrupt arrives). Maybe a CSI2 hardware bug. 7178c2ecf20Sopenharmony_ci */ 7188c2ecf20Sopenharmony_ci if (csi2->frame_skip) { 7198c2ecf20Sopenharmony_ci csi2->frame_skip--; 7208c2ecf20Sopenharmony_ci if (csi2->frame_skip == 0) { 7218c2ecf20Sopenharmony_ci ctx->format_id = csi2_ctx_map_format(csi2); 7228c2ecf20Sopenharmony_ci csi2_ctx_config(isp, csi2, ctx); 7238c2ecf20Sopenharmony_ci csi2_ctx_enable(isp, csi2, n, 1); 7248c2ecf20Sopenharmony_ci } 7258c2ecf20Sopenharmony_ci return; 7268c2ecf20Sopenharmony_ci } 7278c2ecf20Sopenharmony_ci 7288c2ecf20Sopenharmony_ci if (csi2->output & CSI2_OUTPUT_MEMORY) 7298c2ecf20Sopenharmony_ci csi2_isr_buffer(csi2); 7308c2ecf20Sopenharmony_ci} 7318c2ecf20Sopenharmony_ci 7328c2ecf20Sopenharmony_ci/* 7338c2ecf20Sopenharmony_ci * omap3isp_csi2_isr - CSI2 interrupt handling. 7348c2ecf20Sopenharmony_ci */ 7358c2ecf20Sopenharmony_civoid omap3isp_csi2_isr(struct isp_csi2_device *csi2) 7368c2ecf20Sopenharmony_ci{ 7378c2ecf20Sopenharmony_ci struct isp_pipeline *pipe = to_isp_pipeline(&csi2->subdev.entity); 7388c2ecf20Sopenharmony_ci u32 csi2_irqstatus, cpxio1_irqstatus; 7398c2ecf20Sopenharmony_ci struct isp_device *isp = csi2->isp; 7408c2ecf20Sopenharmony_ci 7418c2ecf20Sopenharmony_ci if (!csi2->available) 7428c2ecf20Sopenharmony_ci return; 7438c2ecf20Sopenharmony_ci 7448c2ecf20Sopenharmony_ci csi2_irqstatus = isp_reg_readl(isp, csi2->regs1, ISPCSI2_IRQSTATUS); 7458c2ecf20Sopenharmony_ci isp_reg_writel(isp, csi2_irqstatus, csi2->regs1, ISPCSI2_IRQSTATUS); 7468c2ecf20Sopenharmony_ci 7478c2ecf20Sopenharmony_ci /* Failure Cases */ 7488c2ecf20Sopenharmony_ci if (csi2_irqstatus & ISPCSI2_IRQSTATUS_COMPLEXIO1_ERR_IRQ) { 7498c2ecf20Sopenharmony_ci cpxio1_irqstatus = isp_reg_readl(isp, csi2->regs1, 7508c2ecf20Sopenharmony_ci ISPCSI2_PHY_IRQSTATUS); 7518c2ecf20Sopenharmony_ci isp_reg_writel(isp, cpxio1_irqstatus, 7528c2ecf20Sopenharmony_ci csi2->regs1, ISPCSI2_PHY_IRQSTATUS); 7538c2ecf20Sopenharmony_ci dev_dbg(isp->dev, "CSI2: ComplexIO Error IRQ %x\n", 7548c2ecf20Sopenharmony_ci cpxio1_irqstatus); 7558c2ecf20Sopenharmony_ci pipe->error = true; 7568c2ecf20Sopenharmony_ci } 7578c2ecf20Sopenharmony_ci 7588c2ecf20Sopenharmony_ci if (csi2_irqstatus & (ISPCSI2_IRQSTATUS_OCP_ERR_IRQ | 7598c2ecf20Sopenharmony_ci ISPCSI2_IRQSTATUS_SHORT_PACKET_IRQ | 7608c2ecf20Sopenharmony_ci ISPCSI2_IRQSTATUS_ECC_NO_CORRECTION_IRQ | 7618c2ecf20Sopenharmony_ci ISPCSI2_IRQSTATUS_COMPLEXIO2_ERR_IRQ | 7628c2ecf20Sopenharmony_ci ISPCSI2_IRQSTATUS_FIFO_OVF_IRQ)) { 7638c2ecf20Sopenharmony_ci dev_dbg(isp->dev, 7648c2ecf20Sopenharmony_ci "CSI2 Err: OCP:%d, Short_pack:%d, ECC:%d, CPXIO2:%d, FIFO_OVF:%d,\n", 7658c2ecf20Sopenharmony_ci (csi2_irqstatus & 7668c2ecf20Sopenharmony_ci ISPCSI2_IRQSTATUS_OCP_ERR_IRQ) ? 1 : 0, 7678c2ecf20Sopenharmony_ci (csi2_irqstatus & 7688c2ecf20Sopenharmony_ci ISPCSI2_IRQSTATUS_SHORT_PACKET_IRQ) ? 1 : 0, 7698c2ecf20Sopenharmony_ci (csi2_irqstatus & 7708c2ecf20Sopenharmony_ci ISPCSI2_IRQSTATUS_ECC_NO_CORRECTION_IRQ) ? 1 : 0, 7718c2ecf20Sopenharmony_ci (csi2_irqstatus & 7728c2ecf20Sopenharmony_ci ISPCSI2_IRQSTATUS_COMPLEXIO2_ERR_IRQ) ? 1 : 0, 7738c2ecf20Sopenharmony_ci (csi2_irqstatus & 7748c2ecf20Sopenharmony_ci ISPCSI2_IRQSTATUS_FIFO_OVF_IRQ) ? 1 : 0); 7758c2ecf20Sopenharmony_ci pipe->error = true; 7768c2ecf20Sopenharmony_ci } 7778c2ecf20Sopenharmony_ci 7788c2ecf20Sopenharmony_ci if (omap3isp_module_sync_is_stopping(&csi2->wait, &csi2->stopping)) 7798c2ecf20Sopenharmony_ci return; 7808c2ecf20Sopenharmony_ci 7818c2ecf20Sopenharmony_ci /* Successful cases */ 7828c2ecf20Sopenharmony_ci if (csi2_irqstatus & ISPCSI2_IRQSTATUS_CONTEXT(0)) 7838c2ecf20Sopenharmony_ci csi2_isr_ctx(csi2, &csi2->contexts[0]); 7848c2ecf20Sopenharmony_ci 7858c2ecf20Sopenharmony_ci if (csi2_irqstatus & ISPCSI2_IRQSTATUS_ECC_CORRECTION_IRQ) 7868c2ecf20Sopenharmony_ci dev_dbg(isp->dev, "CSI2: ECC correction done\n"); 7878c2ecf20Sopenharmony_ci} 7888c2ecf20Sopenharmony_ci 7898c2ecf20Sopenharmony_ci/* ----------------------------------------------------------------------------- 7908c2ecf20Sopenharmony_ci * ISP video operations 7918c2ecf20Sopenharmony_ci */ 7928c2ecf20Sopenharmony_ci 7938c2ecf20Sopenharmony_ci/* 7948c2ecf20Sopenharmony_ci * csi2_queue - Queues the first buffer when using memory output 7958c2ecf20Sopenharmony_ci * @video: The video node 7968c2ecf20Sopenharmony_ci * @buffer: buffer to queue 7978c2ecf20Sopenharmony_ci */ 7988c2ecf20Sopenharmony_cistatic int csi2_queue(struct isp_video *video, struct isp_buffer *buffer) 7998c2ecf20Sopenharmony_ci{ 8008c2ecf20Sopenharmony_ci struct isp_device *isp = video->isp; 8018c2ecf20Sopenharmony_ci struct isp_csi2_device *csi2 = &isp->isp_csi2a; 8028c2ecf20Sopenharmony_ci 8038c2ecf20Sopenharmony_ci csi2_set_outaddr(csi2, buffer->dma); 8048c2ecf20Sopenharmony_ci 8058c2ecf20Sopenharmony_ci /* 8068c2ecf20Sopenharmony_ci * If streaming was enabled before there was a buffer queued 8078c2ecf20Sopenharmony_ci * or underrun happened in the ISR, the hardware was not enabled 8088c2ecf20Sopenharmony_ci * and DMA queue flag ISP_VIDEO_DMAQUEUE_UNDERRUN is still set. 8098c2ecf20Sopenharmony_ci * Enable it now. 8108c2ecf20Sopenharmony_ci */ 8118c2ecf20Sopenharmony_ci if (csi2->video_out.dmaqueue_flags & ISP_VIDEO_DMAQUEUE_UNDERRUN) { 8128c2ecf20Sopenharmony_ci /* Enable / disable context 0 and IRQs */ 8138c2ecf20Sopenharmony_ci csi2_if_enable(isp, csi2, 1); 8148c2ecf20Sopenharmony_ci csi2_ctx_enable(isp, csi2, 0, 1); 8158c2ecf20Sopenharmony_ci isp_video_dmaqueue_flags_clr(&csi2->video_out); 8168c2ecf20Sopenharmony_ci } 8178c2ecf20Sopenharmony_ci 8188c2ecf20Sopenharmony_ci return 0; 8198c2ecf20Sopenharmony_ci} 8208c2ecf20Sopenharmony_ci 8218c2ecf20Sopenharmony_cistatic const struct isp_video_operations csi2_ispvideo_ops = { 8228c2ecf20Sopenharmony_ci .queue = csi2_queue, 8238c2ecf20Sopenharmony_ci}; 8248c2ecf20Sopenharmony_ci 8258c2ecf20Sopenharmony_ci/* ----------------------------------------------------------------------------- 8268c2ecf20Sopenharmony_ci * V4L2 subdev operations 8278c2ecf20Sopenharmony_ci */ 8288c2ecf20Sopenharmony_ci 8298c2ecf20Sopenharmony_cistatic struct v4l2_mbus_framefmt * 8308c2ecf20Sopenharmony_ci__csi2_get_format(struct isp_csi2_device *csi2, struct v4l2_subdev_pad_config *cfg, 8318c2ecf20Sopenharmony_ci unsigned int pad, enum v4l2_subdev_format_whence which) 8328c2ecf20Sopenharmony_ci{ 8338c2ecf20Sopenharmony_ci if (which == V4L2_SUBDEV_FORMAT_TRY) 8348c2ecf20Sopenharmony_ci return v4l2_subdev_get_try_format(&csi2->subdev, cfg, pad); 8358c2ecf20Sopenharmony_ci else 8368c2ecf20Sopenharmony_ci return &csi2->formats[pad]; 8378c2ecf20Sopenharmony_ci} 8388c2ecf20Sopenharmony_ci 8398c2ecf20Sopenharmony_cistatic void 8408c2ecf20Sopenharmony_cicsi2_try_format(struct isp_csi2_device *csi2, struct v4l2_subdev_pad_config *cfg, 8418c2ecf20Sopenharmony_ci unsigned int pad, struct v4l2_mbus_framefmt *fmt, 8428c2ecf20Sopenharmony_ci enum v4l2_subdev_format_whence which) 8438c2ecf20Sopenharmony_ci{ 8448c2ecf20Sopenharmony_ci u32 pixelcode; 8458c2ecf20Sopenharmony_ci struct v4l2_mbus_framefmt *format; 8468c2ecf20Sopenharmony_ci const struct isp_format_info *info; 8478c2ecf20Sopenharmony_ci unsigned int i; 8488c2ecf20Sopenharmony_ci 8498c2ecf20Sopenharmony_ci switch (pad) { 8508c2ecf20Sopenharmony_ci case CSI2_PAD_SINK: 8518c2ecf20Sopenharmony_ci /* Clamp the width and height to valid range (1-8191). */ 8528c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(csi2_input_fmts); i++) { 8538c2ecf20Sopenharmony_ci if (fmt->code == csi2_input_fmts[i]) 8548c2ecf20Sopenharmony_ci break; 8558c2ecf20Sopenharmony_ci } 8568c2ecf20Sopenharmony_ci 8578c2ecf20Sopenharmony_ci /* If not found, use SGRBG10 as default */ 8588c2ecf20Sopenharmony_ci if (i >= ARRAY_SIZE(csi2_input_fmts)) 8598c2ecf20Sopenharmony_ci fmt->code = MEDIA_BUS_FMT_SGRBG10_1X10; 8608c2ecf20Sopenharmony_ci 8618c2ecf20Sopenharmony_ci fmt->width = clamp_t(u32, fmt->width, 1, 8191); 8628c2ecf20Sopenharmony_ci fmt->height = clamp_t(u32, fmt->height, 1, 8191); 8638c2ecf20Sopenharmony_ci break; 8648c2ecf20Sopenharmony_ci 8658c2ecf20Sopenharmony_ci case CSI2_PAD_SOURCE: 8668c2ecf20Sopenharmony_ci /* Source format same as sink format, except for DPCM 8678c2ecf20Sopenharmony_ci * compression. 8688c2ecf20Sopenharmony_ci */ 8698c2ecf20Sopenharmony_ci pixelcode = fmt->code; 8708c2ecf20Sopenharmony_ci format = __csi2_get_format(csi2, cfg, CSI2_PAD_SINK, which); 8718c2ecf20Sopenharmony_ci memcpy(fmt, format, sizeof(*fmt)); 8728c2ecf20Sopenharmony_ci 8738c2ecf20Sopenharmony_ci /* 8748c2ecf20Sopenharmony_ci * Only Allow DPCM decompression, and check that the 8758c2ecf20Sopenharmony_ci * pattern is preserved 8768c2ecf20Sopenharmony_ci */ 8778c2ecf20Sopenharmony_ci info = omap3isp_video_format_info(fmt->code); 8788c2ecf20Sopenharmony_ci if (info->uncompressed == pixelcode) 8798c2ecf20Sopenharmony_ci fmt->code = pixelcode; 8808c2ecf20Sopenharmony_ci break; 8818c2ecf20Sopenharmony_ci } 8828c2ecf20Sopenharmony_ci 8838c2ecf20Sopenharmony_ci /* RGB, non-interlaced */ 8848c2ecf20Sopenharmony_ci fmt->colorspace = V4L2_COLORSPACE_SRGB; 8858c2ecf20Sopenharmony_ci fmt->field = V4L2_FIELD_NONE; 8868c2ecf20Sopenharmony_ci} 8878c2ecf20Sopenharmony_ci 8888c2ecf20Sopenharmony_ci/* 8898c2ecf20Sopenharmony_ci * csi2_enum_mbus_code - Handle pixel format enumeration 8908c2ecf20Sopenharmony_ci * @sd : pointer to v4l2 subdev structure 8918c2ecf20Sopenharmony_ci * @cfg: V4L2 subdev pad configuration 8928c2ecf20Sopenharmony_ci * @code : pointer to v4l2_subdev_mbus_code_enum structure 8938c2ecf20Sopenharmony_ci * return -EINVAL or zero on success 8948c2ecf20Sopenharmony_ci */ 8958c2ecf20Sopenharmony_cistatic int csi2_enum_mbus_code(struct v4l2_subdev *sd, 8968c2ecf20Sopenharmony_ci struct v4l2_subdev_pad_config *cfg, 8978c2ecf20Sopenharmony_ci struct v4l2_subdev_mbus_code_enum *code) 8988c2ecf20Sopenharmony_ci{ 8998c2ecf20Sopenharmony_ci struct isp_csi2_device *csi2 = v4l2_get_subdevdata(sd); 9008c2ecf20Sopenharmony_ci struct v4l2_mbus_framefmt *format; 9018c2ecf20Sopenharmony_ci const struct isp_format_info *info; 9028c2ecf20Sopenharmony_ci 9038c2ecf20Sopenharmony_ci if (code->pad == CSI2_PAD_SINK) { 9048c2ecf20Sopenharmony_ci if (code->index >= ARRAY_SIZE(csi2_input_fmts)) 9058c2ecf20Sopenharmony_ci return -EINVAL; 9068c2ecf20Sopenharmony_ci 9078c2ecf20Sopenharmony_ci code->code = csi2_input_fmts[code->index]; 9088c2ecf20Sopenharmony_ci } else { 9098c2ecf20Sopenharmony_ci format = __csi2_get_format(csi2, cfg, CSI2_PAD_SINK, 9108c2ecf20Sopenharmony_ci code->which); 9118c2ecf20Sopenharmony_ci switch (code->index) { 9128c2ecf20Sopenharmony_ci case 0: 9138c2ecf20Sopenharmony_ci /* Passthrough sink pad code */ 9148c2ecf20Sopenharmony_ci code->code = format->code; 9158c2ecf20Sopenharmony_ci break; 9168c2ecf20Sopenharmony_ci case 1: 9178c2ecf20Sopenharmony_ci /* Uncompressed code */ 9188c2ecf20Sopenharmony_ci info = omap3isp_video_format_info(format->code); 9198c2ecf20Sopenharmony_ci if (info->uncompressed == format->code) 9208c2ecf20Sopenharmony_ci return -EINVAL; 9218c2ecf20Sopenharmony_ci 9228c2ecf20Sopenharmony_ci code->code = info->uncompressed; 9238c2ecf20Sopenharmony_ci break; 9248c2ecf20Sopenharmony_ci default: 9258c2ecf20Sopenharmony_ci return -EINVAL; 9268c2ecf20Sopenharmony_ci } 9278c2ecf20Sopenharmony_ci } 9288c2ecf20Sopenharmony_ci 9298c2ecf20Sopenharmony_ci return 0; 9308c2ecf20Sopenharmony_ci} 9318c2ecf20Sopenharmony_ci 9328c2ecf20Sopenharmony_cistatic int csi2_enum_frame_size(struct v4l2_subdev *sd, 9338c2ecf20Sopenharmony_ci struct v4l2_subdev_pad_config *cfg, 9348c2ecf20Sopenharmony_ci struct v4l2_subdev_frame_size_enum *fse) 9358c2ecf20Sopenharmony_ci{ 9368c2ecf20Sopenharmony_ci struct isp_csi2_device *csi2 = v4l2_get_subdevdata(sd); 9378c2ecf20Sopenharmony_ci struct v4l2_mbus_framefmt format; 9388c2ecf20Sopenharmony_ci 9398c2ecf20Sopenharmony_ci if (fse->index != 0) 9408c2ecf20Sopenharmony_ci return -EINVAL; 9418c2ecf20Sopenharmony_ci 9428c2ecf20Sopenharmony_ci format.code = fse->code; 9438c2ecf20Sopenharmony_ci format.width = 1; 9448c2ecf20Sopenharmony_ci format.height = 1; 9458c2ecf20Sopenharmony_ci csi2_try_format(csi2, cfg, fse->pad, &format, fse->which); 9468c2ecf20Sopenharmony_ci fse->min_width = format.width; 9478c2ecf20Sopenharmony_ci fse->min_height = format.height; 9488c2ecf20Sopenharmony_ci 9498c2ecf20Sopenharmony_ci if (format.code != fse->code) 9508c2ecf20Sopenharmony_ci return -EINVAL; 9518c2ecf20Sopenharmony_ci 9528c2ecf20Sopenharmony_ci format.code = fse->code; 9538c2ecf20Sopenharmony_ci format.width = -1; 9548c2ecf20Sopenharmony_ci format.height = -1; 9558c2ecf20Sopenharmony_ci csi2_try_format(csi2, cfg, fse->pad, &format, fse->which); 9568c2ecf20Sopenharmony_ci fse->max_width = format.width; 9578c2ecf20Sopenharmony_ci fse->max_height = format.height; 9588c2ecf20Sopenharmony_ci 9598c2ecf20Sopenharmony_ci return 0; 9608c2ecf20Sopenharmony_ci} 9618c2ecf20Sopenharmony_ci 9628c2ecf20Sopenharmony_ci/* 9638c2ecf20Sopenharmony_ci * csi2_get_format - Handle get format by pads subdev method 9648c2ecf20Sopenharmony_ci * @sd : pointer to v4l2 subdev structure 9658c2ecf20Sopenharmony_ci * @cfg: V4L2 subdev pad configuration 9668c2ecf20Sopenharmony_ci * @fmt: pointer to v4l2 subdev format structure 9678c2ecf20Sopenharmony_ci * return -EINVAL or zero on success 9688c2ecf20Sopenharmony_ci */ 9698c2ecf20Sopenharmony_cistatic int csi2_get_format(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg, 9708c2ecf20Sopenharmony_ci struct v4l2_subdev_format *fmt) 9718c2ecf20Sopenharmony_ci{ 9728c2ecf20Sopenharmony_ci struct isp_csi2_device *csi2 = v4l2_get_subdevdata(sd); 9738c2ecf20Sopenharmony_ci struct v4l2_mbus_framefmt *format; 9748c2ecf20Sopenharmony_ci 9758c2ecf20Sopenharmony_ci format = __csi2_get_format(csi2, cfg, fmt->pad, fmt->which); 9768c2ecf20Sopenharmony_ci if (format == NULL) 9778c2ecf20Sopenharmony_ci return -EINVAL; 9788c2ecf20Sopenharmony_ci 9798c2ecf20Sopenharmony_ci fmt->format = *format; 9808c2ecf20Sopenharmony_ci return 0; 9818c2ecf20Sopenharmony_ci} 9828c2ecf20Sopenharmony_ci 9838c2ecf20Sopenharmony_ci/* 9848c2ecf20Sopenharmony_ci * csi2_set_format - Handle set format by pads subdev method 9858c2ecf20Sopenharmony_ci * @sd : pointer to v4l2 subdev structure 9868c2ecf20Sopenharmony_ci * @cfg: V4L2 subdev pad configuration 9878c2ecf20Sopenharmony_ci * @fmt: pointer to v4l2 subdev format structure 9888c2ecf20Sopenharmony_ci * return -EINVAL or zero on success 9898c2ecf20Sopenharmony_ci */ 9908c2ecf20Sopenharmony_cistatic int csi2_set_format(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg, 9918c2ecf20Sopenharmony_ci struct v4l2_subdev_format *fmt) 9928c2ecf20Sopenharmony_ci{ 9938c2ecf20Sopenharmony_ci struct isp_csi2_device *csi2 = v4l2_get_subdevdata(sd); 9948c2ecf20Sopenharmony_ci struct v4l2_mbus_framefmt *format; 9958c2ecf20Sopenharmony_ci 9968c2ecf20Sopenharmony_ci format = __csi2_get_format(csi2, cfg, fmt->pad, fmt->which); 9978c2ecf20Sopenharmony_ci if (format == NULL) 9988c2ecf20Sopenharmony_ci return -EINVAL; 9998c2ecf20Sopenharmony_ci 10008c2ecf20Sopenharmony_ci csi2_try_format(csi2, cfg, fmt->pad, &fmt->format, fmt->which); 10018c2ecf20Sopenharmony_ci *format = fmt->format; 10028c2ecf20Sopenharmony_ci 10038c2ecf20Sopenharmony_ci /* Propagate the format from sink to source */ 10048c2ecf20Sopenharmony_ci if (fmt->pad == CSI2_PAD_SINK) { 10058c2ecf20Sopenharmony_ci format = __csi2_get_format(csi2, cfg, CSI2_PAD_SOURCE, 10068c2ecf20Sopenharmony_ci fmt->which); 10078c2ecf20Sopenharmony_ci *format = fmt->format; 10088c2ecf20Sopenharmony_ci csi2_try_format(csi2, cfg, CSI2_PAD_SOURCE, format, fmt->which); 10098c2ecf20Sopenharmony_ci } 10108c2ecf20Sopenharmony_ci 10118c2ecf20Sopenharmony_ci return 0; 10128c2ecf20Sopenharmony_ci} 10138c2ecf20Sopenharmony_ci 10148c2ecf20Sopenharmony_ci/* 10158c2ecf20Sopenharmony_ci * csi2_init_formats - Initialize formats on all pads 10168c2ecf20Sopenharmony_ci * @sd: ISP CSI2 V4L2 subdevice 10178c2ecf20Sopenharmony_ci * @fh: V4L2 subdev file handle 10188c2ecf20Sopenharmony_ci * 10198c2ecf20Sopenharmony_ci * Initialize all pad formats with default values. If fh is not NULL, try 10208c2ecf20Sopenharmony_ci * formats are initialized on the file handle. Otherwise active formats are 10218c2ecf20Sopenharmony_ci * initialized on the device. 10228c2ecf20Sopenharmony_ci */ 10238c2ecf20Sopenharmony_cistatic int csi2_init_formats(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) 10248c2ecf20Sopenharmony_ci{ 10258c2ecf20Sopenharmony_ci struct v4l2_subdev_format format; 10268c2ecf20Sopenharmony_ci 10278c2ecf20Sopenharmony_ci memset(&format, 0, sizeof(format)); 10288c2ecf20Sopenharmony_ci format.pad = CSI2_PAD_SINK; 10298c2ecf20Sopenharmony_ci format.which = fh ? V4L2_SUBDEV_FORMAT_TRY : V4L2_SUBDEV_FORMAT_ACTIVE; 10308c2ecf20Sopenharmony_ci format.format.code = MEDIA_BUS_FMT_SGRBG10_1X10; 10318c2ecf20Sopenharmony_ci format.format.width = 4096; 10328c2ecf20Sopenharmony_ci format.format.height = 4096; 10338c2ecf20Sopenharmony_ci csi2_set_format(sd, fh ? fh->pad : NULL, &format); 10348c2ecf20Sopenharmony_ci 10358c2ecf20Sopenharmony_ci return 0; 10368c2ecf20Sopenharmony_ci} 10378c2ecf20Sopenharmony_ci 10388c2ecf20Sopenharmony_ci/* 10398c2ecf20Sopenharmony_ci * csi2_set_stream - Enable/Disable streaming on the CSI2 module 10408c2ecf20Sopenharmony_ci * @sd: ISP CSI2 V4L2 subdevice 10418c2ecf20Sopenharmony_ci * @enable: ISP pipeline stream state 10428c2ecf20Sopenharmony_ci * 10438c2ecf20Sopenharmony_ci * Return 0 on success or a negative error code otherwise. 10448c2ecf20Sopenharmony_ci */ 10458c2ecf20Sopenharmony_cistatic int csi2_set_stream(struct v4l2_subdev *sd, int enable) 10468c2ecf20Sopenharmony_ci{ 10478c2ecf20Sopenharmony_ci struct isp_csi2_device *csi2 = v4l2_get_subdevdata(sd); 10488c2ecf20Sopenharmony_ci struct isp_device *isp = csi2->isp; 10498c2ecf20Sopenharmony_ci struct isp_video *video_out = &csi2->video_out; 10508c2ecf20Sopenharmony_ci 10518c2ecf20Sopenharmony_ci switch (enable) { 10528c2ecf20Sopenharmony_ci case ISP_PIPELINE_STREAM_CONTINUOUS: 10538c2ecf20Sopenharmony_ci if (omap3isp_csiphy_acquire(csi2->phy, &sd->entity) < 0) 10548c2ecf20Sopenharmony_ci return -ENODEV; 10558c2ecf20Sopenharmony_ci if (csi2->output & CSI2_OUTPUT_MEMORY) 10568c2ecf20Sopenharmony_ci omap3isp_sbl_enable(isp, OMAP3_ISP_SBL_CSI2A_WRITE); 10578c2ecf20Sopenharmony_ci csi2_configure(csi2); 10588c2ecf20Sopenharmony_ci csi2_print_status(csi2); 10598c2ecf20Sopenharmony_ci 10608c2ecf20Sopenharmony_ci /* 10618c2ecf20Sopenharmony_ci * When outputting to memory with no buffer available, let the 10628c2ecf20Sopenharmony_ci * buffer queue handler start the hardware. A DMA queue flag 10638c2ecf20Sopenharmony_ci * ISP_VIDEO_DMAQUEUE_QUEUED will be set as soon as there is 10648c2ecf20Sopenharmony_ci * a buffer available. 10658c2ecf20Sopenharmony_ci */ 10668c2ecf20Sopenharmony_ci if (csi2->output & CSI2_OUTPUT_MEMORY && 10678c2ecf20Sopenharmony_ci !(video_out->dmaqueue_flags & ISP_VIDEO_DMAQUEUE_QUEUED)) 10688c2ecf20Sopenharmony_ci break; 10698c2ecf20Sopenharmony_ci /* Enable context 0 and IRQs */ 10708c2ecf20Sopenharmony_ci atomic_set(&csi2->stopping, 0); 10718c2ecf20Sopenharmony_ci csi2_ctx_enable(isp, csi2, 0, 1); 10728c2ecf20Sopenharmony_ci csi2_if_enable(isp, csi2, 1); 10738c2ecf20Sopenharmony_ci isp_video_dmaqueue_flags_clr(video_out); 10748c2ecf20Sopenharmony_ci break; 10758c2ecf20Sopenharmony_ci 10768c2ecf20Sopenharmony_ci case ISP_PIPELINE_STREAM_STOPPED: 10778c2ecf20Sopenharmony_ci if (csi2->state == ISP_PIPELINE_STREAM_STOPPED) 10788c2ecf20Sopenharmony_ci return 0; 10798c2ecf20Sopenharmony_ci if (omap3isp_module_sync_idle(&sd->entity, &csi2->wait, 10808c2ecf20Sopenharmony_ci &csi2->stopping)) 10818c2ecf20Sopenharmony_ci dev_dbg(isp->dev, "%s: module stop timeout.\n", 10828c2ecf20Sopenharmony_ci sd->name); 10838c2ecf20Sopenharmony_ci csi2_ctx_enable(isp, csi2, 0, 0); 10848c2ecf20Sopenharmony_ci csi2_if_enable(isp, csi2, 0); 10858c2ecf20Sopenharmony_ci csi2_irq_ctx_set(isp, csi2, 0); 10868c2ecf20Sopenharmony_ci omap3isp_csiphy_release(csi2->phy); 10878c2ecf20Sopenharmony_ci isp_video_dmaqueue_flags_clr(video_out); 10888c2ecf20Sopenharmony_ci omap3isp_sbl_disable(isp, OMAP3_ISP_SBL_CSI2A_WRITE); 10898c2ecf20Sopenharmony_ci break; 10908c2ecf20Sopenharmony_ci } 10918c2ecf20Sopenharmony_ci 10928c2ecf20Sopenharmony_ci csi2->state = enable; 10938c2ecf20Sopenharmony_ci return 0; 10948c2ecf20Sopenharmony_ci} 10958c2ecf20Sopenharmony_ci 10968c2ecf20Sopenharmony_ci/* subdev video operations */ 10978c2ecf20Sopenharmony_cistatic const struct v4l2_subdev_video_ops csi2_video_ops = { 10988c2ecf20Sopenharmony_ci .s_stream = csi2_set_stream, 10998c2ecf20Sopenharmony_ci}; 11008c2ecf20Sopenharmony_ci 11018c2ecf20Sopenharmony_ci/* subdev pad operations */ 11028c2ecf20Sopenharmony_cistatic const struct v4l2_subdev_pad_ops csi2_pad_ops = { 11038c2ecf20Sopenharmony_ci .enum_mbus_code = csi2_enum_mbus_code, 11048c2ecf20Sopenharmony_ci .enum_frame_size = csi2_enum_frame_size, 11058c2ecf20Sopenharmony_ci .get_fmt = csi2_get_format, 11068c2ecf20Sopenharmony_ci .set_fmt = csi2_set_format, 11078c2ecf20Sopenharmony_ci}; 11088c2ecf20Sopenharmony_ci 11098c2ecf20Sopenharmony_ci/* subdev operations */ 11108c2ecf20Sopenharmony_cistatic const struct v4l2_subdev_ops csi2_ops = { 11118c2ecf20Sopenharmony_ci .video = &csi2_video_ops, 11128c2ecf20Sopenharmony_ci .pad = &csi2_pad_ops, 11138c2ecf20Sopenharmony_ci}; 11148c2ecf20Sopenharmony_ci 11158c2ecf20Sopenharmony_ci/* subdev internal operations */ 11168c2ecf20Sopenharmony_cistatic const struct v4l2_subdev_internal_ops csi2_internal_ops = { 11178c2ecf20Sopenharmony_ci .open = csi2_init_formats, 11188c2ecf20Sopenharmony_ci}; 11198c2ecf20Sopenharmony_ci 11208c2ecf20Sopenharmony_ci/* ----------------------------------------------------------------------------- 11218c2ecf20Sopenharmony_ci * Media entity operations 11228c2ecf20Sopenharmony_ci */ 11238c2ecf20Sopenharmony_ci 11248c2ecf20Sopenharmony_ci/* 11258c2ecf20Sopenharmony_ci * csi2_link_setup - Setup CSI2 connections. 11268c2ecf20Sopenharmony_ci * @entity : Pointer to media entity structure 11278c2ecf20Sopenharmony_ci * @local : Pointer to local pad array 11288c2ecf20Sopenharmony_ci * @remote : Pointer to remote pad array 11298c2ecf20Sopenharmony_ci * @flags : Link flags 11308c2ecf20Sopenharmony_ci * return -EINVAL or zero on success 11318c2ecf20Sopenharmony_ci */ 11328c2ecf20Sopenharmony_cistatic int csi2_link_setup(struct media_entity *entity, 11338c2ecf20Sopenharmony_ci const struct media_pad *local, 11348c2ecf20Sopenharmony_ci const struct media_pad *remote, u32 flags) 11358c2ecf20Sopenharmony_ci{ 11368c2ecf20Sopenharmony_ci struct v4l2_subdev *sd = media_entity_to_v4l2_subdev(entity); 11378c2ecf20Sopenharmony_ci struct isp_csi2_device *csi2 = v4l2_get_subdevdata(sd); 11388c2ecf20Sopenharmony_ci struct isp_csi2_ctrl_cfg *ctrl = &csi2->ctrl; 11398c2ecf20Sopenharmony_ci unsigned int index = local->index; 11408c2ecf20Sopenharmony_ci 11418c2ecf20Sopenharmony_ci /* 11428c2ecf20Sopenharmony_ci * The ISP core doesn't support pipelines with multiple video outputs. 11438c2ecf20Sopenharmony_ci * Revisit this when it will be implemented, and return -EBUSY for now. 11448c2ecf20Sopenharmony_ci */ 11458c2ecf20Sopenharmony_ci 11468c2ecf20Sopenharmony_ci /* FIXME: this is actually a hack! */ 11478c2ecf20Sopenharmony_ci if (is_media_entity_v4l2_subdev(remote->entity)) 11488c2ecf20Sopenharmony_ci index |= 2 << 16; 11498c2ecf20Sopenharmony_ci 11508c2ecf20Sopenharmony_ci switch (index) { 11518c2ecf20Sopenharmony_ci case CSI2_PAD_SOURCE: 11528c2ecf20Sopenharmony_ci if (flags & MEDIA_LNK_FL_ENABLED) { 11538c2ecf20Sopenharmony_ci if (csi2->output & ~CSI2_OUTPUT_MEMORY) 11548c2ecf20Sopenharmony_ci return -EBUSY; 11558c2ecf20Sopenharmony_ci csi2->output |= CSI2_OUTPUT_MEMORY; 11568c2ecf20Sopenharmony_ci } else { 11578c2ecf20Sopenharmony_ci csi2->output &= ~CSI2_OUTPUT_MEMORY; 11588c2ecf20Sopenharmony_ci } 11598c2ecf20Sopenharmony_ci break; 11608c2ecf20Sopenharmony_ci 11618c2ecf20Sopenharmony_ci case CSI2_PAD_SOURCE | 2 << 16: 11628c2ecf20Sopenharmony_ci if (flags & MEDIA_LNK_FL_ENABLED) { 11638c2ecf20Sopenharmony_ci if (csi2->output & ~CSI2_OUTPUT_CCDC) 11648c2ecf20Sopenharmony_ci return -EBUSY; 11658c2ecf20Sopenharmony_ci csi2->output |= CSI2_OUTPUT_CCDC; 11668c2ecf20Sopenharmony_ci } else { 11678c2ecf20Sopenharmony_ci csi2->output &= ~CSI2_OUTPUT_CCDC; 11688c2ecf20Sopenharmony_ci } 11698c2ecf20Sopenharmony_ci break; 11708c2ecf20Sopenharmony_ci 11718c2ecf20Sopenharmony_ci default: 11728c2ecf20Sopenharmony_ci /* Link from camera to CSI2 is fixed... */ 11738c2ecf20Sopenharmony_ci return -EINVAL; 11748c2ecf20Sopenharmony_ci } 11758c2ecf20Sopenharmony_ci 11768c2ecf20Sopenharmony_ci ctrl->vp_only_enable = 11778c2ecf20Sopenharmony_ci (csi2->output & CSI2_OUTPUT_MEMORY) ? false : true; 11788c2ecf20Sopenharmony_ci ctrl->vp_clk_enable = !!(csi2->output & CSI2_OUTPUT_CCDC); 11798c2ecf20Sopenharmony_ci 11808c2ecf20Sopenharmony_ci return 0; 11818c2ecf20Sopenharmony_ci} 11828c2ecf20Sopenharmony_ci 11838c2ecf20Sopenharmony_ci/* media operations */ 11848c2ecf20Sopenharmony_cistatic const struct media_entity_operations csi2_media_ops = { 11858c2ecf20Sopenharmony_ci .link_setup = csi2_link_setup, 11868c2ecf20Sopenharmony_ci .link_validate = v4l2_subdev_link_validate, 11878c2ecf20Sopenharmony_ci}; 11888c2ecf20Sopenharmony_ci 11898c2ecf20Sopenharmony_civoid omap3isp_csi2_unregister_entities(struct isp_csi2_device *csi2) 11908c2ecf20Sopenharmony_ci{ 11918c2ecf20Sopenharmony_ci v4l2_device_unregister_subdev(&csi2->subdev); 11928c2ecf20Sopenharmony_ci omap3isp_video_unregister(&csi2->video_out); 11938c2ecf20Sopenharmony_ci} 11948c2ecf20Sopenharmony_ci 11958c2ecf20Sopenharmony_ciint omap3isp_csi2_register_entities(struct isp_csi2_device *csi2, 11968c2ecf20Sopenharmony_ci struct v4l2_device *vdev) 11978c2ecf20Sopenharmony_ci{ 11988c2ecf20Sopenharmony_ci int ret; 11998c2ecf20Sopenharmony_ci 12008c2ecf20Sopenharmony_ci /* Register the subdev and video nodes. */ 12018c2ecf20Sopenharmony_ci csi2->subdev.dev = vdev->mdev->dev; 12028c2ecf20Sopenharmony_ci ret = v4l2_device_register_subdev(vdev, &csi2->subdev); 12038c2ecf20Sopenharmony_ci if (ret < 0) 12048c2ecf20Sopenharmony_ci goto error; 12058c2ecf20Sopenharmony_ci 12068c2ecf20Sopenharmony_ci ret = omap3isp_video_register(&csi2->video_out, vdev); 12078c2ecf20Sopenharmony_ci if (ret < 0) 12088c2ecf20Sopenharmony_ci goto error; 12098c2ecf20Sopenharmony_ci 12108c2ecf20Sopenharmony_ci return 0; 12118c2ecf20Sopenharmony_ci 12128c2ecf20Sopenharmony_cierror: 12138c2ecf20Sopenharmony_ci omap3isp_csi2_unregister_entities(csi2); 12148c2ecf20Sopenharmony_ci return ret; 12158c2ecf20Sopenharmony_ci} 12168c2ecf20Sopenharmony_ci 12178c2ecf20Sopenharmony_ci/* ----------------------------------------------------------------------------- 12188c2ecf20Sopenharmony_ci * ISP CSI2 initialisation and cleanup 12198c2ecf20Sopenharmony_ci */ 12208c2ecf20Sopenharmony_ci 12218c2ecf20Sopenharmony_ci/* 12228c2ecf20Sopenharmony_ci * csi2_init_entities - Initialize subdev and media entity. 12238c2ecf20Sopenharmony_ci * @csi2: Pointer to csi2 structure. 12248c2ecf20Sopenharmony_ci * return -ENOMEM or zero on success 12258c2ecf20Sopenharmony_ci */ 12268c2ecf20Sopenharmony_cistatic int csi2_init_entities(struct isp_csi2_device *csi2) 12278c2ecf20Sopenharmony_ci{ 12288c2ecf20Sopenharmony_ci struct v4l2_subdev *sd = &csi2->subdev; 12298c2ecf20Sopenharmony_ci struct media_pad *pads = csi2->pads; 12308c2ecf20Sopenharmony_ci struct media_entity *me = &sd->entity; 12318c2ecf20Sopenharmony_ci int ret; 12328c2ecf20Sopenharmony_ci 12338c2ecf20Sopenharmony_ci v4l2_subdev_init(sd, &csi2_ops); 12348c2ecf20Sopenharmony_ci sd->internal_ops = &csi2_internal_ops; 12358c2ecf20Sopenharmony_ci strscpy(sd->name, "OMAP3 ISP CSI2a", sizeof(sd->name)); 12368c2ecf20Sopenharmony_ci 12378c2ecf20Sopenharmony_ci sd->grp_id = 1 << 16; /* group ID for isp subdevs */ 12388c2ecf20Sopenharmony_ci v4l2_set_subdevdata(sd, csi2); 12398c2ecf20Sopenharmony_ci sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; 12408c2ecf20Sopenharmony_ci 12418c2ecf20Sopenharmony_ci pads[CSI2_PAD_SOURCE].flags = MEDIA_PAD_FL_SOURCE; 12428c2ecf20Sopenharmony_ci pads[CSI2_PAD_SINK].flags = MEDIA_PAD_FL_SINK 12438c2ecf20Sopenharmony_ci | MEDIA_PAD_FL_MUST_CONNECT; 12448c2ecf20Sopenharmony_ci 12458c2ecf20Sopenharmony_ci me->ops = &csi2_media_ops; 12468c2ecf20Sopenharmony_ci ret = media_entity_pads_init(me, CSI2_PADS_NUM, pads); 12478c2ecf20Sopenharmony_ci if (ret < 0) 12488c2ecf20Sopenharmony_ci return ret; 12498c2ecf20Sopenharmony_ci 12508c2ecf20Sopenharmony_ci csi2_init_formats(sd, NULL); 12518c2ecf20Sopenharmony_ci 12528c2ecf20Sopenharmony_ci /* Video device node */ 12538c2ecf20Sopenharmony_ci csi2->video_out.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 12548c2ecf20Sopenharmony_ci csi2->video_out.ops = &csi2_ispvideo_ops; 12558c2ecf20Sopenharmony_ci csi2->video_out.bpl_alignment = 32; 12568c2ecf20Sopenharmony_ci csi2->video_out.bpl_zero_padding = 1; 12578c2ecf20Sopenharmony_ci csi2->video_out.bpl_max = 0x1ffe0; 12588c2ecf20Sopenharmony_ci csi2->video_out.isp = csi2->isp; 12598c2ecf20Sopenharmony_ci csi2->video_out.capture_mem = PAGE_ALIGN(4096 * 4096) * 3; 12608c2ecf20Sopenharmony_ci 12618c2ecf20Sopenharmony_ci ret = omap3isp_video_init(&csi2->video_out, "CSI2a"); 12628c2ecf20Sopenharmony_ci if (ret < 0) 12638c2ecf20Sopenharmony_ci goto error_video; 12648c2ecf20Sopenharmony_ci 12658c2ecf20Sopenharmony_ci return 0; 12668c2ecf20Sopenharmony_ci 12678c2ecf20Sopenharmony_cierror_video: 12688c2ecf20Sopenharmony_ci media_entity_cleanup(&csi2->subdev.entity); 12698c2ecf20Sopenharmony_ci return ret; 12708c2ecf20Sopenharmony_ci} 12718c2ecf20Sopenharmony_ci 12728c2ecf20Sopenharmony_ci/* 12738c2ecf20Sopenharmony_ci * omap3isp_csi2_init - Routine for module driver init 12748c2ecf20Sopenharmony_ci */ 12758c2ecf20Sopenharmony_ciint omap3isp_csi2_init(struct isp_device *isp) 12768c2ecf20Sopenharmony_ci{ 12778c2ecf20Sopenharmony_ci struct isp_csi2_device *csi2a = &isp->isp_csi2a; 12788c2ecf20Sopenharmony_ci struct isp_csi2_device *csi2c = &isp->isp_csi2c; 12798c2ecf20Sopenharmony_ci int ret; 12808c2ecf20Sopenharmony_ci 12818c2ecf20Sopenharmony_ci csi2a->isp = isp; 12828c2ecf20Sopenharmony_ci csi2a->available = 1; 12838c2ecf20Sopenharmony_ci csi2a->regs1 = OMAP3_ISP_IOMEM_CSI2A_REGS1; 12848c2ecf20Sopenharmony_ci csi2a->regs2 = OMAP3_ISP_IOMEM_CSI2A_REGS2; 12858c2ecf20Sopenharmony_ci csi2a->phy = &isp->isp_csiphy2; 12868c2ecf20Sopenharmony_ci csi2a->state = ISP_PIPELINE_STREAM_STOPPED; 12878c2ecf20Sopenharmony_ci init_waitqueue_head(&csi2a->wait); 12888c2ecf20Sopenharmony_ci 12898c2ecf20Sopenharmony_ci ret = csi2_init_entities(csi2a); 12908c2ecf20Sopenharmony_ci if (ret < 0) 12918c2ecf20Sopenharmony_ci return ret; 12928c2ecf20Sopenharmony_ci 12938c2ecf20Sopenharmony_ci if (isp->revision == ISP_REVISION_15_0) { 12948c2ecf20Sopenharmony_ci csi2c->isp = isp; 12958c2ecf20Sopenharmony_ci csi2c->available = 1; 12968c2ecf20Sopenharmony_ci csi2c->regs1 = OMAP3_ISP_IOMEM_CSI2C_REGS1; 12978c2ecf20Sopenharmony_ci csi2c->regs2 = OMAP3_ISP_IOMEM_CSI2C_REGS2; 12988c2ecf20Sopenharmony_ci csi2c->phy = &isp->isp_csiphy1; 12998c2ecf20Sopenharmony_ci csi2c->state = ISP_PIPELINE_STREAM_STOPPED; 13008c2ecf20Sopenharmony_ci init_waitqueue_head(&csi2c->wait); 13018c2ecf20Sopenharmony_ci } 13028c2ecf20Sopenharmony_ci 13038c2ecf20Sopenharmony_ci return 0; 13048c2ecf20Sopenharmony_ci} 13058c2ecf20Sopenharmony_ci 13068c2ecf20Sopenharmony_ci/* 13078c2ecf20Sopenharmony_ci * omap3isp_csi2_cleanup - Routine for module driver cleanup 13088c2ecf20Sopenharmony_ci */ 13098c2ecf20Sopenharmony_civoid omap3isp_csi2_cleanup(struct isp_device *isp) 13108c2ecf20Sopenharmony_ci{ 13118c2ecf20Sopenharmony_ci struct isp_csi2_device *csi2a = &isp->isp_csi2a; 13128c2ecf20Sopenharmony_ci 13138c2ecf20Sopenharmony_ci omap3isp_video_cleanup(&csi2a->video_out); 13148c2ecf20Sopenharmony_ci media_entity_cleanup(&csi2a->subdev.entity); 13158c2ecf20Sopenharmony_ci} 1316