Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

[media] omap3isp: CCP2/CSI2 receivers

The OMAP3 ISP CCP2 and CSI2 receivers provide an interface to connect
serial MIPI sensors to the device.

Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Signed-off-by: Sakari Ailus <sakari.ailus@iki.fi>
Signed-off-by: David Cohen <dacohen@gmail.com>
Signed-off-by: Stanimir Varbanov <svarbanov@mm-sol.com>
Signed-off-by: Vimarsh Zutshi <vimarsh.zutshi@gmail.com>
Signed-off-by: Tuukka Toivonen <tuukkat76@gmail.com>
Signed-off-by: Sergio Aguirre <saaguirre@ti.com>
Signed-off-by: Antti Koskipaa <akoskipa@gmail.com>
Signed-off-by: Ivan T. Ivanov <iivanov@mm-sol.com>
Signed-off-by: RaniSuneela <r-m@ti.com>
Signed-off-by: Atanas Filipov <afilipov@mm-sol.com>
Signed-off-by: Gjorgji Rosikopulos <grosikopulos@mm-sol.com>
Signed-off-by: Hiroshi DOYU <Hiroshi.DOYU@nokia.com>
Signed-off-by: Nayden Kanchev <nkanchev@mm-sol.com>
Signed-off-by: Phil Carmody <ext-phil.2.carmody@nokia.com>
Signed-off-by: Artem Bityutskiy <Artem.Bityutskiy@nokia.com>
Signed-off-by: Dominic Curran <dcurran@ti.com>
Signed-off-by: Ilkka Myllyperkio <ilkka.myllyperkio@sofica.fi>
Signed-off-by: Pallavi Kulkarni <p-kulkarni@ti.com>
Signed-off-by: Vaibhav Hiremath <hvaibhav@ti.com>
Acked-by: Hans Verkuil <hverkuil@xs4all.nl>
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>

authored by

Laurent Pinchart and committed by
Mauro Carvalho Chehab
121e9f1c ad614acb

+3075
+1173
drivers/media/video/omap3isp/ispccp2.c
··· 1 + /* 2 + * ispccp2.c 3 + * 4 + * TI OMAP3 ISP - CCP2 module 5 + * 6 + * Copyright (C) 2010 Nokia Corporation 7 + * Copyright (C) 2010 Texas Instruments, Inc. 8 + * 9 + * Contacts: Laurent Pinchart <laurent.pinchart@ideasonboard.com> 10 + * Sakari Ailus <sakari.ailus@iki.fi> 11 + * 12 + * This program is free software; you can redistribute it and/or modify 13 + * it under the terms of the GNU General Public License version 2 as 14 + * published by the Free Software Foundation. 15 + * 16 + * This program is distributed in the hope that it will be useful, but 17 + * WITHOUT ANY WARRANTY; without even the implied warranty of 18 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 19 + * General Public License for more details. 20 + * 21 + * You should have received a copy of the GNU General Public License 22 + * along with this program; if not, write to the Free Software 23 + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 24 + * 02110-1301 USA 25 + */ 26 + 27 + #include <linux/delay.h> 28 + #include <linux/device.h> 29 + #include <linux/mm.h> 30 + #include <linux/module.h> 31 + #include <linux/mutex.h> 32 + #include <linux/uaccess.h> 33 + 34 + #include "isp.h" 35 + #include "ispreg.h" 36 + #include "ispccp2.h" 37 + 38 + /* Number of LCX channels */ 39 + #define CCP2_LCx_CHANS_NUM 3 40 + /* Max/Min size for CCP2 video port */ 41 + #define ISPCCP2_DAT_START_MIN 0 42 + #define ISPCCP2_DAT_START_MAX 4095 43 + #define ISPCCP2_DAT_SIZE_MIN 0 44 + #define ISPCCP2_DAT_SIZE_MAX 4095 45 + #define ISPCCP2_VPCLK_FRACDIV 65536 46 + #define ISPCCP2_LCx_CTRL_FORMAT_RAW8_DPCM10_VP 0x12 47 + #define ISPCCP2_LCx_CTRL_FORMAT_RAW10_VP 0x16 48 + /* Max/Min size for CCP2 memory channel */ 49 + #define ISPCCP2_LCM_HSIZE_COUNT_MIN 16 50 + #define ISPCCP2_LCM_HSIZE_COUNT_MAX 8191 51 + #define ISPCCP2_LCM_HSIZE_SKIP_MIN 0 52 + #define ISPCCP2_LCM_HSIZE_SKIP_MAX 8191 53 + #define ISPCCP2_LCM_VSIZE_MIN 1 54 + #define ISPCCP2_LCM_VSIZE_MAX 8191 55 + #define ISPCCP2_LCM_HWORDS_MIN 1 56 + #define ISPCCP2_LCM_HWORDS_MAX 4095 57 + #define ISPCCP2_LCM_CTRL_BURST_SIZE_32X 5 58 + #define ISPCCP2_LCM_CTRL_READ_THROTTLE_FULL 0 59 + #define ISPCCP2_LCM_CTRL_SRC_DECOMPR_DPCM10 2 60 + #define ISPCCP2_LCM_CTRL_SRC_FORMAT_RAW8 2 61 + #define ISPCCP2_LCM_CTRL_SRC_FORMAT_RAW10 3 62 + #define ISPCCP2_LCM_CTRL_DST_FORMAT_RAW10 3 63 + #define ISPCCP2_LCM_CTRL_DST_PORT_VP 0 64 + #define ISPCCP2_LCM_CTRL_DST_PORT_MEM 1 65 + 66 + /* Set only the required bits */ 67 + #define BIT_SET(var, shift, mask, val) \ 68 + do { \ 69 + var = ((var) & ~((mask) << (shift))) \ 70 + | ((val) << (shift)); \ 71 + } while (0) 72 + 73 + /* 74 + * ccp2_print_status - Print current CCP2 module register values. 75 + */ 76 + #define CCP2_PRINT_REGISTER(isp, name)\ 77 + dev_dbg(isp->dev, "###CCP2 " #name "=0x%08x\n", \ 78 + isp_reg_readl(isp, OMAP3_ISP_IOMEM_CCP2, ISPCCP2_##name)) 79 + 80 + static void ccp2_print_status(struct isp_ccp2_device *ccp2) 81 + { 82 + struct isp_device *isp = to_isp_device(ccp2); 83 + 84 + dev_dbg(isp->dev, "-------------CCP2 Register dump-------------\n"); 85 + 86 + CCP2_PRINT_REGISTER(isp, SYSCONFIG); 87 + CCP2_PRINT_REGISTER(isp, SYSSTATUS); 88 + CCP2_PRINT_REGISTER(isp, LC01_IRQENABLE); 89 + CCP2_PRINT_REGISTER(isp, LC01_IRQSTATUS); 90 + CCP2_PRINT_REGISTER(isp, LC23_IRQENABLE); 91 + CCP2_PRINT_REGISTER(isp, LC23_IRQSTATUS); 92 + CCP2_PRINT_REGISTER(isp, LCM_IRQENABLE); 93 + CCP2_PRINT_REGISTER(isp, LCM_IRQSTATUS); 94 + CCP2_PRINT_REGISTER(isp, CTRL); 95 + CCP2_PRINT_REGISTER(isp, LCx_CTRL(0)); 96 + CCP2_PRINT_REGISTER(isp, LCx_CODE(0)); 97 + CCP2_PRINT_REGISTER(isp, LCx_STAT_START(0)); 98 + CCP2_PRINT_REGISTER(isp, LCx_STAT_SIZE(0)); 99 + CCP2_PRINT_REGISTER(isp, LCx_SOF_ADDR(0)); 100 + CCP2_PRINT_REGISTER(isp, LCx_EOF_ADDR(0)); 101 + CCP2_PRINT_REGISTER(isp, LCx_DAT_START(0)); 102 + CCP2_PRINT_REGISTER(isp, LCx_DAT_SIZE(0)); 103 + CCP2_PRINT_REGISTER(isp, LCx_DAT_PING_ADDR(0)); 104 + CCP2_PRINT_REGISTER(isp, LCx_DAT_PONG_ADDR(0)); 105 + CCP2_PRINT_REGISTER(isp, LCx_DAT_OFST(0)); 106 + CCP2_PRINT_REGISTER(isp, LCM_CTRL); 107 + CCP2_PRINT_REGISTER(isp, LCM_VSIZE); 108 + CCP2_PRINT_REGISTER(isp, LCM_HSIZE); 109 + CCP2_PRINT_REGISTER(isp, LCM_PREFETCH); 110 + CCP2_PRINT_REGISTER(isp, LCM_SRC_ADDR); 111 + CCP2_PRINT_REGISTER(isp, LCM_SRC_OFST); 112 + CCP2_PRINT_REGISTER(isp, LCM_DST_ADDR); 113 + CCP2_PRINT_REGISTER(isp, LCM_DST_OFST); 114 + 115 + dev_dbg(isp->dev, "--------------------------------------------\n"); 116 + } 117 + 118 + /* 119 + * ccp2_reset - Reset the CCP2 120 + * @ccp2: pointer to ISP CCP2 device 121 + */ 122 + static void ccp2_reset(struct isp_ccp2_device *ccp2) 123 + { 124 + struct isp_device *isp = to_isp_device(ccp2); 125 + int i = 0; 126 + 127 + /* Reset the CSI1/CCP2B and wait for reset to complete */ 128 + isp_reg_set(isp, OMAP3_ISP_IOMEM_CCP2, ISPCCP2_SYSCONFIG, 129 + ISPCCP2_SYSCONFIG_SOFT_RESET); 130 + while (!(isp_reg_readl(isp, OMAP3_ISP_IOMEM_CCP2, ISPCCP2_SYSSTATUS) & 131 + ISPCCP2_SYSSTATUS_RESET_DONE)) { 132 + udelay(10); 133 + if (i++ > 10) { /* try read 10 times */ 134 + dev_warn(isp->dev, 135 + "omap3_isp: timeout waiting for ccp2 reset\n"); 136 + break; 137 + } 138 + } 139 + } 140 + 141 + /* 142 + * ccp2_pwr_cfg - Configure the power mode settings 143 + * @ccp2: pointer to ISP CCP2 device 144 + */ 145 + static void ccp2_pwr_cfg(struct isp_ccp2_device *ccp2) 146 + { 147 + struct isp_device *isp = to_isp_device(ccp2); 148 + 149 + isp_reg_writel(isp, ISPCCP2_SYSCONFIG_MSTANDBY_MODE_SMART | 150 + ((isp->revision == ISP_REVISION_15_0 && isp->autoidle) ? 151 + ISPCCP2_SYSCONFIG_AUTO_IDLE : 0), 152 + OMAP3_ISP_IOMEM_CCP2, ISPCCP2_SYSCONFIG); 153 + } 154 + 155 + /* 156 + * ccp2_if_enable - Enable CCP2 interface. 157 + * @ccp2: pointer to ISP CCP2 device 158 + * @enable: enable/disable flag 159 + */ 160 + static void ccp2_if_enable(struct isp_ccp2_device *ccp2, u8 enable) 161 + { 162 + struct isp_device *isp = to_isp_device(ccp2); 163 + struct isp_pipeline *pipe = to_isp_pipeline(&ccp2->subdev.entity); 164 + int i; 165 + 166 + /* Enable/Disable all the LCx channels */ 167 + for (i = 0; i < CCP2_LCx_CHANS_NUM; i++) 168 + isp_reg_clr_set(isp, OMAP3_ISP_IOMEM_CCP2, ISPCCP2_LCx_CTRL(i), 169 + ISPCCP2_LCx_CTRL_CHAN_EN, 170 + enable ? ISPCCP2_LCx_CTRL_CHAN_EN : 0); 171 + 172 + /* Enable/Disable ccp2 interface in ccp2 mode */ 173 + isp_reg_clr_set(isp, OMAP3_ISP_IOMEM_CCP2, ISPCCP2_CTRL, 174 + ISPCCP2_CTRL_MODE | ISPCCP2_CTRL_IF_EN, 175 + enable ? (ISPCCP2_CTRL_MODE | ISPCCP2_CTRL_IF_EN) : 0); 176 + 177 + /* For frame count propagation */ 178 + if (pipe->do_propagation) { 179 + /* We may want the Frame Start IRQ from LC0 */ 180 + if (enable) 181 + isp_reg_set(isp, OMAP3_ISP_IOMEM_CCP2, 182 + ISPCCP2_LC01_IRQENABLE, 183 + ISPCCP2_LC01_IRQSTATUS_LC0_FS_IRQ); 184 + else 185 + isp_reg_clr(isp, OMAP3_ISP_IOMEM_CCP2, 186 + ISPCCP2_LC01_IRQENABLE, 187 + ISPCCP2_LC01_IRQSTATUS_LC0_FS_IRQ); 188 + } 189 + } 190 + 191 + /* 192 + * ccp2_mem_enable - Enable CCP2 memory interface. 193 + * @ccp2: pointer to ISP CCP2 device 194 + * @enable: enable/disable flag 195 + */ 196 + static void ccp2_mem_enable(struct isp_ccp2_device *ccp2, u8 enable) 197 + { 198 + struct isp_device *isp = to_isp_device(ccp2); 199 + 200 + if (enable) 201 + ccp2_if_enable(ccp2, 0); 202 + 203 + /* Enable/Disable ccp2 interface in ccp2 mode */ 204 + isp_reg_clr_set(isp, OMAP3_ISP_IOMEM_CCP2, ISPCCP2_CTRL, 205 + ISPCCP2_CTRL_MODE, enable ? ISPCCP2_CTRL_MODE : 0); 206 + 207 + isp_reg_clr_set(isp, OMAP3_ISP_IOMEM_CCP2, ISPCCP2_LCM_CTRL, 208 + ISPCCP2_LCM_CTRL_CHAN_EN, 209 + enable ? ISPCCP2_LCM_CTRL_CHAN_EN : 0); 210 + } 211 + 212 + /* 213 + * ccp2_phyif_config - Initialize CCP2 phy interface config 214 + * @ccp2: Pointer to ISP CCP2 device 215 + * @config: CCP2 platform data 216 + * 217 + * Configure the CCP2 physical interface module from platform data. 218 + * 219 + * Returns -EIO if strobe is chosen in CSI1 mode, or 0 on success. 220 + */ 221 + static int ccp2_phyif_config(struct isp_ccp2_device *ccp2, 222 + const struct isp_ccp2_platform_data *pdata) 223 + { 224 + struct isp_device *isp = to_isp_device(ccp2); 225 + u32 val; 226 + 227 + /* CCP2B mode */ 228 + val = isp_reg_readl(isp, OMAP3_ISP_IOMEM_CCP2, ISPCCP2_CTRL) | 229 + ISPCCP2_CTRL_IO_OUT_SEL | ISPCCP2_CTRL_MODE; 230 + /* Data/strobe physical layer */ 231 + BIT_SET(val, ISPCCP2_CTRL_PHY_SEL_SHIFT, ISPCCP2_CTRL_PHY_SEL_MASK, 232 + pdata->phy_layer); 233 + BIT_SET(val, ISPCCP2_CTRL_INV_SHIFT, ISPCCP2_CTRL_INV_MASK, 234 + pdata->strobe_clk_pol); 235 + isp_reg_writel(isp, val, OMAP3_ISP_IOMEM_CCP2, ISPCCP2_CTRL); 236 + 237 + val = isp_reg_readl(isp, OMAP3_ISP_IOMEM_CCP2, ISPCCP2_CTRL); 238 + if (!(val & ISPCCP2_CTRL_MODE)) { 239 + if (pdata->ccp2_mode) 240 + dev_warn(isp->dev, "OMAP3 CCP2 bus not available\n"); 241 + if (pdata->phy_layer == ISPCCP2_CTRL_PHY_SEL_STROBE) 242 + /* Strobe mode requires CCP2 */ 243 + return -EIO; 244 + } 245 + 246 + return 0; 247 + } 248 + 249 + /* 250 + * ccp2_vp_config - Initialize CCP2 video port interface. 251 + * @ccp2: Pointer to ISP CCP2 device 252 + * @vpclk_div: Video port divisor 253 + * 254 + * Configure the CCP2 video port with the given clock divisor. The valid divisor 255 + * values depend on the ISP revision: 256 + * 257 + * - revision 1.0 and 2.0 1 to 4 258 + * - revision 15.0 1 to 65536 259 + * 260 + * The exact divisor value used might differ from the requested value, as ISP 261 + * revision 15.0 represent the divisor by 65536 divided by an integer. 262 + */ 263 + static void ccp2_vp_config(struct isp_ccp2_device *ccp2, 264 + unsigned int vpclk_div) 265 + { 266 + struct isp_device *isp = to_isp_device(ccp2); 267 + u32 val; 268 + 269 + /* ISPCCP2_CTRL Video port */ 270 + val = isp_reg_readl(isp, OMAP3_ISP_IOMEM_CCP2, ISPCCP2_CTRL); 271 + val |= ISPCCP2_CTRL_VP_ONLY_EN; /* Disable the memory write port */ 272 + 273 + if (isp->revision == ISP_REVISION_15_0) { 274 + vpclk_div = clamp_t(unsigned int, vpclk_div, 1, 65536); 275 + vpclk_div = min(ISPCCP2_VPCLK_FRACDIV / vpclk_div, 65535U); 276 + BIT_SET(val, ISPCCP2_CTRL_VPCLK_DIV_SHIFT, 277 + ISPCCP2_CTRL_VPCLK_DIV_MASK, vpclk_div); 278 + } else { 279 + vpclk_div = clamp_t(unsigned int, vpclk_div, 1, 4); 280 + BIT_SET(val, ISPCCP2_CTRL_VP_OUT_CTRL_SHIFT, 281 + ISPCCP2_CTRL_VP_OUT_CTRL_MASK, vpclk_div - 1); 282 + } 283 + 284 + isp_reg_writel(isp, val, OMAP3_ISP_IOMEM_CCP2, ISPCCP2_CTRL); 285 + } 286 + 287 + /* 288 + * ccp2_lcx_config - Initialize CCP2 logical channel interface. 289 + * @ccp2: Pointer to ISP CCP2 device 290 + * @config: Pointer to ISP LCx config structure. 291 + * 292 + * This will analyze the parameters passed by the interface config 293 + * and configure CSI1/CCP2 logical channel 294 + * 295 + */ 296 + static void ccp2_lcx_config(struct isp_ccp2_device *ccp2, 297 + struct isp_interface_lcx_config *config) 298 + { 299 + struct isp_device *isp = to_isp_device(ccp2); 300 + u32 val, format; 301 + 302 + switch (config->format) { 303 + case V4L2_MBUS_FMT_SGRBG10_DPCM8_1X8: 304 + format = ISPCCP2_LCx_CTRL_FORMAT_RAW8_DPCM10_VP; 305 + break; 306 + case V4L2_MBUS_FMT_SGRBG10_1X10: 307 + default: 308 + format = ISPCCP2_LCx_CTRL_FORMAT_RAW10_VP; /* RAW10+VP */ 309 + break; 310 + } 311 + /* ISPCCP2_LCx_CTRL logical channel #0 */ 312 + val = isp_reg_readl(isp, OMAP3_ISP_IOMEM_CCP2, ISPCCP2_LCx_CTRL(0)) 313 + | (ISPCCP2_LCx_CTRL_REGION_EN); /* Region */ 314 + 315 + if (isp->revision == ISP_REVISION_15_0) { 316 + /* CRC */ 317 + BIT_SET(val, ISPCCP2_LCx_CTRL_CRC_SHIFT_15_0, 318 + ISPCCP2_LCx_CTRL_CRC_MASK, 319 + config->crc); 320 + /* Format = RAW10+VP or RAW8+DPCM10+VP*/ 321 + BIT_SET(val, ISPCCP2_LCx_CTRL_FORMAT_SHIFT_15_0, 322 + ISPCCP2_LCx_CTRL_FORMAT_MASK_15_0, format); 323 + } else { 324 + BIT_SET(val, ISPCCP2_LCx_CTRL_CRC_SHIFT, 325 + ISPCCP2_LCx_CTRL_CRC_MASK, 326 + config->crc); 327 + 328 + BIT_SET(val, ISPCCP2_LCx_CTRL_FORMAT_SHIFT, 329 + ISPCCP2_LCx_CTRL_FORMAT_MASK, format); 330 + } 331 + isp_reg_writel(isp, val, OMAP3_ISP_IOMEM_CCP2, ISPCCP2_LCx_CTRL(0)); 332 + 333 + /* ISPCCP2_DAT_START for logical channel #0 */ 334 + isp_reg_writel(isp, config->data_start << ISPCCP2_LCx_DAT_SHIFT, 335 + OMAP3_ISP_IOMEM_CCP2, ISPCCP2_LCx_DAT_START(0)); 336 + 337 + /* ISPCCP2_DAT_SIZE for logical channel #0 */ 338 + isp_reg_writel(isp, config->data_size << ISPCCP2_LCx_DAT_SHIFT, 339 + OMAP3_ISP_IOMEM_CCP2, ISPCCP2_LCx_DAT_SIZE(0)); 340 + 341 + /* Enable error IRQs for logical channel #0 */ 342 + val = ISPCCP2_LC01_IRQSTATUS_LC0_FIFO_OVF_IRQ | 343 + ISPCCP2_LC01_IRQSTATUS_LC0_CRC_IRQ | 344 + ISPCCP2_LC01_IRQSTATUS_LC0_FSP_IRQ | 345 + ISPCCP2_LC01_IRQSTATUS_LC0_FW_IRQ | 346 + ISPCCP2_LC01_IRQSTATUS_LC0_FS_IRQ | 347 + ISPCCP2_LC01_IRQSTATUS_LC0_FSC_IRQ | 348 + ISPCCP2_LC01_IRQSTATUS_LC0_SSC_IRQ; 349 + 350 + isp_reg_writel(isp, val, OMAP3_ISP_IOMEM_CCP2, ISPCCP2_LC01_IRQSTATUS); 351 + isp_reg_set(isp, OMAP3_ISP_IOMEM_CCP2, ISPCCP2_LC01_IRQENABLE, val); 352 + } 353 + 354 + /* 355 + * ccp2_if_configure - Configure ccp2 with data from sensor 356 + * @ccp2: Pointer to ISP CCP2 device 357 + * 358 + * Return 0 on success or a negative error code 359 + */ 360 + static int ccp2_if_configure(struct isp_ccp2_device *ccp2) 361 + { 362 + const struct isp_v4l2_subdevs_group *pdata; 363 + struct v4l2_mbus_framefmt *format; 364 + struct media_pad *pad; 365 + struct v4l2_subdev *sensor; 366 + u32 lines = 0; 367 + int ret; 368 + 369 + ccp2_pwr_cfg(ccp2); 370 + 371 + pad = media_entity_remote_source(&ccp2->pads[CCP2_PAD_SINK]); 372 + sensor = media_entity_to_v4l2_subdev(pad->entity); 373 + pdata = sensor->host_priv; 374 + 375 + ret = ccp2_phyif_config(ccp2, &pdata->bus.ccp2); 376 + if (ret < 0) 377 + return ret; 378 + 379 + ccp2_vp_config(ccp2, pdata->bus.ccp2.vpclk_div + 1); 380 + 381 + v4l2_subdev_call(sensor, sensor, g_skip_top_lines, &lines); 382 + 383 + format = &ccp2->formats[CCP2_PAD_SINK]; 384 + 385 + ccp2->if_cfg.data_start = lines; 386 + ccp2->if_cfg.crc = pdata->bus.ccp2.crc; 387 + ccp2->if_cfg.format = format->code; 388 + ccp2->if_cfg.data_size = format->height; 389 + 390 + ccp2_lcx_config(ccp2, &ccp2->if_cfg); 391 + 392 + return 0; 393 + } 394 + 395 + static int ccp2_adjust_bandwidth(struct isp_ccp2_device *ccp2) 396 + { 397 + struct isp_pipeline *pipe = to_isp_pipeline(&ccp2->subdev.entity); 398 + struct isp_device *isp = to_isp_device(ccp2); 399 + const struct v4l2_mbus_framefmt *ofmt = &ccp2->formats[CCP2_PAD_SOURCE]; 400 + unsigned long l3_ick = pipe->l3_ick; 401 + struct v4l2_fract *timeperframe; 402 + unsigned int vpclk_div = 2; 403 + unsigned int value; 404 + u64 bound; 405 + u64 area; 406 + 407 + /* Compute the minimum clock divisor, based on the pipeline maximum 408 + * data rate. This is an absolute lower bound if we don't want SBL 409 + * overflows, so round the value up. 410 + */ 411 + vpclk_div = max_t(unsigned int, DIV_ROUND_UP(l3_ick, pipe->max_rate), 412 + vpclk_div); 413 + 414 + /* Compute the maximum clock divisor, based on the requested frame rate. 415 + * This is a soft lower bound to achieve a frame rate equal or higher 416 + * than the requested value, so round the value down. 417 + */ 418 + timeperframe = &pipe->max_timeperframe; 419 + 420 + if (timeperframe->numerator) { 421 + area = ofmt->width * ofmt->height; 422 + bound = div_u64(area * timeperframe->denominator, 423 + timeperframe->numerator); 424 + value = min_t(u64, bound, l3_ick); 425 + vpclk_div = max_t(unsigned int, l3_ick / value, vpclk_div); 426 + } 427 + 428 + dev_dbg(isp->dev, "%s: minimum clock divisor = %u\n", __func__, 429 + vpclk_div); 430 + 431 + return vpclk_div; 432 + } 433 + 434 + /* 435 + * ccp2_mem_configure - Initialize CCP2 memory input/output interface 436 + * @ccp2: Pointer to ISP CCP2 device 437 + * @config: Pointer to ISP mem interface config structure 438 + * 439 + * This will analyze the parameters passed by the interface config 440 + * structure, and configure the respective registers for proper 441 + * CSI1/CCP2 memory input. 442 + */ 443 + static void ccp2_mem_configure(struct isp_ccp2_device *ccp2, 444 + struct isp_interface_mem_config *config) 445 + { 446 + struct isp_device *isp = to_isp_device(ccp2); 447 + u32 sink_pixcode = ccp2->formats[CCP2_PAD_SINK].code; 448 + u32 source_pixcode = ccp2->formats[CCP2_PAD_SOURCE].code; 449 + unsigned int dpcm_decompress = 0; 450 + u32 val, hwords; 451 + 452 + if (sink_pixcode != source_pixcode && 453 + sink_pixcode == V4L2_MBUS_FMT_SGRBG10_DPCM8_1X8) 454 + dpcm_decompress = 1; 455 + 456 + ccp2_pwr_cfg(ccp2); 457 + 458 + /* Hsize, Skip */ 459 + isp_reg_writel(isp, ISPCCP2_LCM_HSIZE_SKIP_MIN | 460 + (config->hsize_count << ISPCCP2_LCM_HSIZE_SHIFT), 461 + OMAP3_ISP_IOMEM_CCP2, ISPCCP2_LCM_HSIZE); 462 + 463 + /* Vsize, no. of lines */ 464 + isp_reg_writel(isp, config->vsize_count << ISPCCP2_LCM_VSIZE_SHIFT, 465 + OMAP3_ISP_IOMEM_CCP2, ISPCCP2_LCM_VSIZE); 466 + 467 + if (ccp2->video_in.bpl_padding == 0) 468 + config->src_ofst = 0; 469 + else 470 + config->src_ofst = ccp2->video_in.bpl_value; 471 + 472 + isp_reg_writel(isp, config->src_ofst, OMAP3_ISP_IOMEM_CCP2, 473 + ISPCCP2_LCM_SRC_OFST); 474 + 475 + /* Source and Destination formats */ 476 + val = ISPCCP2_LCM_CTRL_DST_FORMAT_RAW10 << 477 + ISPCCP2_LCM_CTRL_DST_FORMAT_SHIFT; 478 + 479 + if (dpcm_decompress) { 480 + /* source format is RAW8 */ 481 + val |= ISPCCP2_LCM_CTRL_SRC_FORMAT_RAW8 << 482 + ISPCCP2_LCM_CTRL_SRC_FORMAT_SHIFT; 483 + 484 + /* RAW8 + DPCM10 - simple predictor */ 485 + val |= ISPCCP2_LCM_CTRL_SRC_DPCM_PRED; 486 + 487 + /* enable source DPCM decompression */ 488 + val |= ISPCCP2_LCM_CTRL_SRC_DECOMPR_DPCM10 << 489 + ISPCCP2_LCM_CTRL_SRC_DECOMPR_SHIFT; 490 + } else { 491 + /* source format is RAW10 */ 492 + val |= ISPCCP2_LCM_CTRL_SRC_FORMAT_RAW10 << 493 + ISPCCP2_LCM_CTRL_SRC_FORMAT_SHIFT; 494 + } 495 + 496 + /* Burst size to 32x64 */ 497 + val |= ISPCCP2_LCM_CTRL_BURST_SIZE_32X << 498 + ISPCCP2_LCM_CTRL_BURST_SIZE_SHIFT; 499 + 500 + isp_reg_writel(isp, val, OMAP3_ISP_IOMEM_CCP2, ISPCCP2_LCM_CTRL); 501 + 502 + /* Prefetch setup */ 503 + if (dpcm_decompress) 504 + hwords = (ISPCCP2_LCM_HSIZE_SKIP_MIN + 505 + config->hsize_count) >> 3; 506 + else 507 + hwords = (ISPCCP2_LCM_HSIZE_SKIP_MIN + 508 + config->hsize_count) >> 2; 509 + 510 + isp_reg_writel(isp, hwords << ISPCCP2_LCM_PREFETCH_SHIFT, 511 + OMAP3_ISP_IOMEM_CCP2, ISPCCP2_LCM_PREFETCH); 512 + 513 + /* Video port */ 514 + isp_reg_set(isp, OMAP3_ISP_IOMEM_CCP2, ISPCCP2_CTRL, 515 + ISPCCP2_CTRL_IO_OUT_SEL | ISPCCP2_CTRL_MODE); 516 + ccp2_vp_config(ccp2, ccp2_adjust_bandwidth(ccp2)); 517 + 518 + /* Clear LCM interrupts */ 519 + isp_reg_writel(isp, ISPCCP2_LCM_IRQSTATUS_OCPERROR_IRQ | 520 + ISPCCP2_LCM_IRQSTATUS_EOF_IRQ, 521 + OMAP3_ISP_IOMEM_CCP2, ISPCCP2_LCM_IRQSTATUS); 522 + 523 + /* Enable LCM interupts */ 524 + isp_reg_set(isp, OMAP3_ISP_IOMEM_CCP2, ISPCCP2_LCM_IRQENABLE, 525 + ISPCCP2_LCM_IRQSTATUS_EOF_IRQ | 526 + ISPCCP2_LCM_IRQSTATUS_OCPERROR_IRQ); 527 + } 528 + 529 + /* 530 + * ccp2_set_inaddr - Sets memory address of input frame. 531 + * @ccp2: Pointer to ISP CCP2 device 532 + * @addr: 32bit memory address aligned on 32byte boundary. 533 + * 534 + * Configures the memory address from which the input frame is to be read. 535 + */ 536 + static void ccp2_set_inaddr(struct isp_ccp2_device *ccp2, u32 addr) 537 + { 538 + struct isp_device *isp = to_isp_device(ccp2); 539 + 540 + isp_reg_writel(isp, addr, OMAP3_ISP_IOMEM_CCP2, ISPCCP2_LCM_SRC_ADDR); 541 + } 542 + 543 + /* ----------------------------------------------------------------------------- 544 + * Interrupt handling 545 + */ 546 + 547 + static void ccp2_isr_buffer(struct isp_ccp2_device *ccp2) 548 + { 549 + struct isp_pipeline *pipe = to_isp_pipeline(&ccp2->subdev.entity); 550 + struct isp_buffer *buffer; 551 + 552 + buffer = omap3isp_video_buffer_next(&ccp2->video_in, ccp2->error); 553 + if (buffer != NULL) 554 + ccp2_set_inaddr(ccp2, buffer->isp_addr); 555 + 556 + pipe->state |= ISP_PIPELINE_IDLE_INPUT; 557 + 558 + if (ccp2->state == ISP_PIPELINE_STREAM_SINGLESHOT) { 559 + if (isp_pipeline_ready(pipe)) 560 + omap3isp_pipeline_set_stream(pipe, 561 + ISP_PIPELINE_STREAM_SINGLESHOT); 562 + } 563 + 564 + ccp2->error = 0; 565 + } 566 + 567 + /* 568 + * omap3isp_ccp2_isr - Handle ISP CCP2 interrupts 569 + * @ccp2: Pointer to ISP CCP2 device 570 + * 571 + * This will handle the CCP2 interrupts 572 + * 573 + * Returns -EIO in case of error, or 0 on success. 574 + */ 575 + int omap3isp_ccp2_isr(struct isp_ccp2_device *ccp2) 576 + { 577 + struct isp_device *isp = to_isp_device(ccp2); 578 + int ret = 0; 579 + static const u32 ISPCCP2_LC01_ERROR = 580 + ISPCCP2_LC01_IRQSTATUS_LC0_FIFO_OVF_IRQ | 581 + ISPCCP2_LC01_IRQSTATUS_LC0_CRC_IRQ | 582 + ISPCCP2_LC01_IRQSTATUS_LC0_FSP_IRQ | 583 + ISPCCP2_LC01_IRQSTATUS_LC0_FW_IRQ | 584 + ISPCCP2_LC01_IRQSTATUS_LC0_FSC_IRQ | 585 + ISPCCP2_LC01_IRQSTATUS_LC0_SSC_IRQ; 586 + u32 lcx_irqstatus, lcm_irqstatus; 587 + 588 + /* First clear the interrupts */ 589 + lcx_irqstatus = isp_reg_readl(isp, OMAP3_ISP_IOMEM_CCP2, 590 + ISPCCP2_LC01_IRQSTATUS); 591 + isp_reg_writel(isp, lcx_irqstatus, OMAP3_ISP_IOMEM_CCP2, 592 + ISPCCP2_LC01_IRQSTATUS); 593 + 594 + lcm_irqstatus = isp_reg_readl(isp, OMAP3_ISP_IOMEM_CCP2, 595 + ISPCCP2_LCM_IRQSTATUS); 596 + isp_reg_writel(isp, lcm_irqstatus, OMAP3_ISP_IOMEM_CCP2, 597 + ISPCCP2_LCM_IRQSTATUS); 598 + /* Errors */ 599 + if (lcx_irqstatus & ISPCCP2_LC01_ERROR) { 600 + ccp2->error = 1; 601 + dev_dbg(isp->dev, "CCP2 err:%x\n", lcx_irqstatus); 602 + return -EIO; 603 + } 604 + 605 + if (lcm_irqstatus & ISPCCP2_LCM_IRQSTATUS_OCPERROR_IRQ) { 606 + ccp2->error = 1; 607 + dev_dbg(isp->dev, "CCP2 OCP err:%x\n", lcm_irqstatus); 608 + ret = -EIO; 609 + } 610 + 611 + if (omap3isp_module_sync_is_stopping(&ccp2->wait, &ccp2->stopping)) 612 + return 0; 613 + 614 + /* Frame number propagation */ 615 + if (lcx_irqstatus & ISPCCP2_LC01_IRQSTATUS_LC0_FS_IRQ) { 616 + struct isp_pipeline *pipe = 617 + to_isp_pipeline(&ccp2->subdev.entity); 618 + if (pipe->do_propagation) 619 + atomic_inc(&pipe->frame_number); 620 + } 621 + 622 + /* Handle queued buffers on frame end interrupts */ 623 + if (lcm_irqstatus & ISPCCP2_LCM_IRQSTATUS_EOF_IRQ) 624 + ccp2_isr_buffer(ccp2); 625 + 626 + return ret; 627 + } 628 + 629 + /* ----------------------------------------------------------------------------- 630 + * V4L2 subdev operations 631 + */ 632 + 633 + static const unsigned int ccp2_fmts[] = { 634 + V4L2_MBUS_FMT_SGRBG10_1X10, 635 + V4L2_MBUS_FMT_SGRBG10_DPCM8_1X8, 636 + }; 637 + 638 + /* 639 + * __ccp2_get_format - helper function for getting ccp2 format 640 + * @ccp2 : Pointer to ISP CCP2 device 641 + * @fh : V4L2 subdev file handle 642 + * @pad : pad number 643 + * @which : wanted subdev format 644 + * return format structure or NULL on error 645 + */ 646 + static struct v4l2_mbus_framefmt * 647 + __ccp2_get_format(struct isp_ccp2_device *ccp2, struct v4l2_subdev_fh *fh, 648 + unsigned int pad, enum v4l2_subdev_format_whence which) 649 + { 650 + if (which == V4L2_SUBDEV_FORMAT_TRY) 651 + return v4l2_subdev_get_try_format(fh, pad); 652 + else 653 + return &ccp2->formats[pad]; 654 + } 655 + 656 + /* 657 + * ccp2_try_format - Handle try format by pad subdev method 658 + * @ccp2 : Pointer to ISP CCP2 device 659 + * @fh : V4L2 subdev file handle 660 + * @pad : pad num 661 + * @fmt : pointer to v4l2 mbus format structure 662 + * @which : wanted subdev format 663 + */ 664 + static void ccp2_try_format(struct isp_ccp2_device *ccp2, 665 + struct v4l2_subdev_fh *fh, unsigned int pad, 666 + struct v4l2_mbus_framefmt *fmt, 667 + enum v4l2_subdev_format_whence which) 668 + { 669 + struct v4l2_mbus_framefmt *format; 670 + 671 + switch (pad) { 672 + case CCP2_PAD_SINK: 673 + if (fmt->code != V4L2_MBUS_FMT_SGRBG10_DPCM8_1X8) 674 + fmt->code = V4L2_MBUS_FMT_SGRBG10_1X10; 675 + 676 + if (ccp2->input == CCP2_INPUT_SENSOR) { 677 + fmt->width = clamp_t(u32, fmt->width, 678 + ISPCCP2_DAT_START_MIN, 679 + ISPCCP2_DAT_START_MAX); 680 + fmt->height = clamp_t(u32, fmt->height, 681 + ISPCCP2_DAT_SIZE_MIN, 682 + ISPCCP2_DAT_SIZE_MAX); 683 + } else if (ccp2->input == CCP2_INPUT_MEMORY) { 684 + fmt->width = clamp_t(u32, fmt->width, 685 + ISPCCP2_LCM_HSIZE_COUNT_MIN, 686 + ISPCCP2_LCM_HSIZE_COUNT_MAX); 687 + fmt->height = clamp_t(u32, fmt->height, 688 + ISPCCP2_LCM_VSIZE_MIN, 689 + ISPCCP2_LCM_VSIZE_MAX); 690 + } 691 + break; 692 + 693 + case CCP2_PAD_SOURCE: 694 + /* Source format - copy sink format and change pixel code 695 + * to SGRBG10_1X10 as we don't support CCP2 write to memory. 696 + * When CCP2 write to memory feature will be added this 697 + * should be changed properly. 698 + */ 699 + format = __ccp2_get_format(ccp2, fh, CCP2_PAD_SINK, which); 700 + memcpy(fmt, format, sizeof(*fmt)); 701 + fmt->code = V4L2_MBUS_FMT_SGRBG10_1X10; 702 + break; 703 + } 704 + 705 + fmt->field = V4L2_FIELD_NONE; 706 + fmt->colorspace = V4L2_COLORSPACE_SRGB; 707 + } 708 + 709 + /* 710 + * ccp2_enum_mbus_code - Handle pixel format enumeration 711 + * @sd : pointer to v4l2 subdev structure 712 + * @fh : V4L2 subdev file handle 713 + * @code : pointer to v4l2_subdev_mbus_code_enum structure 714 + * return -EINVAL or zero on success 715 + */ 716 + static int ccp2_enum_mbus_code(struct v4l2_subdev *sd, 717 + struct v4l2_subdev_fh *fh, 718 + struct v4l2_subdev_mbus_code_enum *code) 719 + { 720 + struct isp_ccp2_device *ccp2 = v4l2_get_subdevdata(sd); 721 + struct v4l2_mbus_framefmt *format; 722 + 723 + if (code->pad == CCP2_PAD_SINK) { 724 + if (code->index >= ARRAY_SIZE(ccp2_fmts)) 725 + return -EINVAL; 726 + 727 + code->code = ccp2_fmts[code->index]; 728 + } else { 729 + if (code->index != 0) 730 + return -EINVAL; 731 + 732 + format = __ccp2_get_format(ccp2, fh, CCP2_PAD_SINK, 733 + V4L2_SUBDEV_FORMAT_TRY); 734 + code->code = format->code; 735 + } 736 + 737 + return 0; 738 + } 739 + 740 + static int ccp2_enum_frame_size(struct v4l2_subdev *sd, 741 + struct v4l2_subdev_fh *fh, 742 + struct v4l2_subdev_frame_size_enum *fse) 743 + { 744 + struct isp_ccp2_device *ccp2 = v4l2_get_subdevdata(sd); 745 + struct v4l2_mbus_framefmt format; 746 + 747 + if (fse->index != 0) 748 + return -EINVAL; 749 + 750 + format.code = fse->code; 751 + format.width = 1; 752 + format.height = 1; 753 + ccp2_try_format(ccp2, fh, fse->pad, &format, V4L2_SUBDEV_FORMAT_TRY); 754 + fse->min_width = format.width; 755 + fse->min_height = format.height; 756 + 757 + if (format.code != fse->code) 758 + return -EINVAL; 759 + 760 + format.code = fse->code; 761 + format.width = -1; 762 + format.height = -1; 763 + ccp2_try_format(ccp2, fh, fse->pad, &format, V4L2_SUBDEV_FORMAT_TRY); 764 + fse->max_width = format.width; 765 + fse->max_height = format.height; 766 + 767 + return 0; 768 + } 769 + 770 + /* 771 + * ccp2_get_format - Handle get format by pads subdev method 772 + * @sd : pointer to v4l2 subdev structure 773 + * @fh : V4L2 subdev file handle 774 + * @fmt : pointer to v4l2 subdev format structure 775 + * return -EINVAL or zero on sucess 776 + */ 777 + static int ccp2_get_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, 778 + struct v4l2_subdev_format *fmt) 779 + { 780 + struct isp_ccp2_device *ccp2 = v4l2_get_subdevdata(sd); 781 + struct v4l2_mbus_framefmt *format; 782 + 783 + format = __ccp2_get_format(ccp2, fh, fmt->pad, fmt->which); 784 + if (format == NULL) 785 + return -EINVAL; 786 + 787 + fmt->format = *format; 788 + return 0; 789 + } 790 + 791 + /* 792 + * ccp2_set_format - Handle set format by pads subdev method 793 + * @sd : pointer to v4l2 subdev structure 794 + * @fh : V4L2 subdev file handle 795 + * @fmt : pointer to v4l2 subdev format structure 796 + * returns zero 797 + */ 798 + static int ccp2_set_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, 799 + struct v4l2_subdev_format *fmt) 800 + { 801 + struct isp_ccp2_device *ccp2 = v4l2_get_subdevdata(sd); 802 + struct v4l2_mbus_framefmt *format; 803 + 804 + format = __ccp2_get_format(ccp2, fh, fmt->pad, fmt->which); 805 + if (format == NULL) 806 + return -EINVAL; 807 + 808 + ccp2_try_format(ccp2, fh, fmt->pad, &fmt->format, fmt->which); 809 + *format = fmt->format; 810 + 811 + /* Propagate the format from sink to source */ 812 + if (fmt->pad == CCP2_PAD_SINK) { 813 + format = __ccp2_get_format(ccp2, fh, CCP2_PAD_SOURCE, 814 + fmt->which); 815 + *format = fmt->format; 816 + ccp2_try_format(ccp2, fh, CCP2_PAD_SOURCE, format, fmt->which); 817 + } 818 + 819 + return 0; 820 + } 821 + 822 + /* 823 + * ccp2_init_formats - Initialize formats on all pads 824 + * @sd: ISP CCP2 V4L2 subdevice 825 + * @fh: V4L2 subdev file handle 826 + * 827 + * Initialize all pad formats with default values. If fh is not NULL, try 828 + * formats are initialized on the file handle. Otherwise active formats are 829 + * initialized on the device. 830 + */ 831 + static int ccp2_init_formats(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) 832 + { 833 + struct v4l2_subdev_format format; 834 + 835 + memset(&format, 0, sizeof(format)); 836 + format.pad = CCP2_PAD_SINK; 837 + format.which = fh ? V4L2_SUBDEV_FORMAT_TRY : V4L2_SUBDEV_FORMAT_ACTIVE; 838 + format.format.code = V4L2_MBUS_FMT_SGRBG10_1X10; 839 + format.format.width = 4096; 840 + format.format.height = 4096; 841 + ccp2_set_format(sd, fh, &format); 842 + 843 + return 0; 844 + } 845 + 846 + /* 847 + * ccp2_s_stream - Enable/Disable streaming on ccp2 subdev 848 + * @sd : pointer to v4l2 subdev structure 849 + * @enable: 1 == Enable, 0 == Disable 850 + * return zero 851 + */ 852 + static int ccp2_s_stream(struct v4l2_subdev *sd, int enable) 853 + { 854 + struct isp_ccp2_device *ccp2 = v4l2_get_subdevdata(sd); 855 + struct isp_device *isp = to_isp_device(ccp2); 856 + struct device *dev = to_device(ccp2); 857 + int ret; 858 + 859 + if (ccp2->state == ISP_PIPELINE_STREAM_STOPPED) { 860 + if (enable == ISP_PIPELINE_STREAM_STOPPED) 861 + return 0; 862 + atomic_set(&ccp2->stopping, 0); 863 + ccp2->error = 0; 864 + } 865 + 866 + switch (enable) { 867 + case ISP_PIPELINE_STREAM_CONTINUOUS: 868 + if (ccp2->phy) { 869 + ret = omap3isp_csiphy_acquire(ccp2->phy); 870 + if (ret < 0) 871 + return ret; 872 + } 873 + 874 + ccp2_if_configure(ccp2); 875 + ccp2_print_status(ccp2); 876 + 877 + /* Enable CSI1/CCP2 interface */ 878 + ccp2_if_enable(ccp2, 1); 879 + break; 880 + 881 + case ISP_PIPELINE_STREAM_SINGLESHOT: 882 + if (ccp2->state != ISP_PIPELINE_STREAM_SINGLESHOT) { 883 + struct v4l2_mbus_framefmt *format; 884 + 885 + format = &ccp2->formats[CCP2_PAD_SINK]; 886 + 887 + ccp2->mem_cfg.hsize_count = format->width; 888 + ccp2->mem_cfg.vsize_count = format->height; 889 + ccp2->mem_cfg.src_ofst = 0; 890 + 891 + ccp2_mem_configure(ccp2, &ccp2->mem_cfg); 892 + omap3isp_sbl_enable(isp, OMAP3_ISP_SBL_CSI1_READ); 893 + ccp2_print_status(ccp2); 894 + } 895 + ccp2_mem_enable(ccp2, 1); 896 + break; 897 + 898 + case ISP_PIPELINE_STREAM_STOPPED: 899 + if (omap3isp_module_sync_idle(&sd->entity, &ccp2->wait, 900 + &ccp2->stopping)) 901 + dev_dbg(dev, "%s: module stop timeout.\n", sd->name); 902 + if (ccp2->input == CCP2_INPUT_MEMORY) { 903 + ccp2_mem_enable(ccp2, 0); 904 + omap3isp_sbl_disable(isp, OMAP3_ISP_SBL_CSI1_READ); 905 + } else if (ccp2->input == CCP2_INPUT_SENSOR) { 906 + /* Disable CSI1/CCP2 interface */ 907 + ccp2_if_enable(ccp2, 0); 908 + if (ccp2->phy) 909 + omap3isp_csiphy_release(ccp2->phy); 910 + } 911 + break; 912 + } 913 + 914 + ccp2->state = enable; 915 + return 0; 916 + } 917 + 918 + /* subdev video operations */ 919 + static const struct v4l2_subdev_video_ops ccp2_sd_video_ops = { 920 + .s_stream = ccp2_s_stream, 921 + }; 922 + 923 + /* subdev pad operations */ 924 + static const struct v4l2_subdev_pad_ops ccp2_sd_pad_ops = { 925 + .enum_mbus_code = ccp2_enum_mbus_code, 926 + .enum_frame_size = ccp2_enum_frame_size, 927 + .get_fmt = ccp2_get_format, 928 + .set_fmt = ccp2_set_format, 929 + }; 930 + 931 + /* subdev operations */ 932 + static const struct v4l2_subdev_ops ccp2_sd_ops = { 933 + .video = &ccp2_sd_video_ops, 934 + .pad = &ccp2_sd_pad_ops, 935 + }; 936 + 937 + /* subdev internal operations */ 938 + static const struct v4l2_subdev_internal_ops ccp2_sd_internal_ops = { 939 + .open = ccp2_init_formats, 940 + }; 941 + 942 + /* -------------------------------------------------------------------------- 943 + * ISP ccp2 video device node 944 + */ 945 + 946 + /* 947 + * ccp2_video_queue - Queue video buffer. 948 + * @video : Pointer to isp video structure 949 + * @buffer: Pointer to isp_buffer structure 950 + * return -EIO or zero on success 951 + */ 952 + static int ccp2_video_queue(struct isp_video *video, struct isp_buffer *buffer) 953 + { 954 + struct isp_ccp2_device *ccp2 = &video->isp->isp_ccp2; 955 + 956 + ccp2_set_inaddr(ccp2, buffer->isp_addr); 957 + return 0; 958 + } 959 + 960 + static const struct isp_video_operations ccp2_video_ops = { 961 + .queue = ccp2_video_queue, 962 + }; 963 + 964 + /* ----------------------------------------------------------------------------- 965 + * Media entity operations 966 + */ 967 + 968 + /* 969 + * ccp2_link_setup - Setup ccp2 connections. 970 + * @entity : Pointer to media entity structure 971 + * @local : Pointer to local pad array 972 + * @remote : Pointer to remote pad array 973 + * @flags : Link flags 974 + * return -EINVAL on error or zero on success 975 + */ 976 + static int ccp2_link_setup(struct media_entity *entity, 977 + const struct media_pad *local, 978 + const struct media_pad *remote, u32 flags) 979 + { 980 + struct v4l2_subdev *sd = media_entity_to_v4l2_subdev(entity); 981 + struct isp_ccp2_device *ccp2 = v4l2_get_subdevdata(sd); 982 + 983 + switch (local->index | media_entity_type(remote->entity)) { 984 + case CCP2_PAD_SINK | MEDIA_ENT_T_DEVNODE: 985 + /* read from memory */ 986 + if (flags & MEDIA_LNK_FL_ENABLED) { 987 + if (ccp2->input == CCP2_INPUT_SENSOR) 988 + return -EBUSY; 989 + ccp2->input = CCP2_INPUT_MEMORY; 990 + } else { 991 + if (ccp2->input == CCP2_INPUT_MEMORY) 992 + ccp2->input = CCP2_INPUT_NONE; 993 + } 994 + break; 995 + 996 + case CCP2_PAD_SINK | MEDIA_ENT_T_V4L2_SUBDEV: 997 + /* read from sensor/phy */ 998 + if (flags & MEDIA_LNK_FL_ENABLED) { 999 + if (ccp2->input == CCP2_INPUT_MEMORY) 1000 + return -EBUSY; 1001 + ccp2->input = CCP2_INPUT_SENSOR; 1002 + } else { 1003 + if (ccp2->input == CCP2_INPUT_SENSOR) 1004 + ccp2->input = CCP2_INPUT_NONE; 1005 + } break; 1006 + 1007 + case CCP2_PAD_SOURCE | MEDIA_ENT_T_V4L2_SUBDEV: 1008 + /* write to video port/ccdc */ 1009 + if (flags & MEDIA_LNK_FL_ENABLED) 1010 + ccp2->output = CCP2_OUTPUT_CCDC; 1011 + else 1012 + ccp2->output = CCP2_OUTPUT_NONE; 1013 + break; 1014 + 1015 + default: 1016 + return -EINVAL; 1017 + } 1018 + 1019 + return 0; 1020 + } 1021 + 1022 + /* media operations */ 1023 + static const struct media_entity_operations ccp2_media_ops = { 1024 + .link_setup = ccp2_link_setup, 1025 + }; 1026 + 1027 + /* 1028 + * ccp2_init_entities - Initialize ccp2 subdev and media entity. 1029 + * @ccp2: Pointer to ISP CCP2 device 1030 + * return negative error code or zero on success 1031 + */ 1032 + static int ccp2_init_entities(struct isp_ccp2_device *ccp2) 1033 + { 1034 + struct v4l2_subdev *sd = &ccp2->subdev; 1035 + struct media_pad *pads = ccp2->pads; 1036 + struct media_entity *me = &sd->entity; 1037 + int ret; 1038 + 1039 + ccp2->input = CCP2_INPUT_NONE; 1040 + ccp2->output = CCP2_OUTPUT_NONE; 1041 + 1042 + v4l2_subdev_init(sd, &ccp2_sd_ops); 1043 + sd->internal_ops = &ccp2_sd_internal_ops; 1044 + strlcpy(sd->name, "OMAP3 ISP CCP2", sizeof(sd->name)); 1045 + sd->grp_id = 1 << 16; /* group ID for isp subdevs */ 1046 + v4l2_set_subdevdata(sd, ccp2); 1047 + sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; 1048 + 1049 + pads[CCP2_PAD_SINK].flags = MEDIA_PAD_FL_SINK; 1050 + pads[CCP2_PAD_SOURCE].flags = MEDIA_PAD_FL_SOURCE; 1051 + 1052 + me->ops = &ccp2_media_ops; 1053 + ret = media_entity_init(me, CCP2_PADS_NUM, pads, 0); 1054 + if (ret < 0) 1055 + return ret; 1056 + 1057 + ccp2_init_formats(sd, NULL); 1058 + 1059 + /* 1060 + * The CCP2 has weird line alignment requirements, possibly caused by 1061 + * DPCM8 decompression. Line length for data read from memory must be a 1062 + * multiple of 128 bits (16 bytes) in continuous mode (when no padding 1063 + * is present at end of lines). Additionally, if padding is used, the 1064 + * padded line length must be a multiple of 32 bytes. To simplify the 1065 + * implementation we use a fixed 32 bytes alignment regardless of the 1066 + * input format and width. If strict 128 bits alignment support is 1067 + * required ispvideo will need to be made aware of this special dual 1068 + * alignement requirements. 1069 + */ 1070 + ccp2->video_in.type = V4L2_BUF_TYPE_VIDEO_OUTPUT; 1071 + ccp2->video_in.bpl_alignment = 32; 1072 + ccp2->video_in.bpl_max = 0xffffffe0; 1073 + ccp2->video_in.isp = to_isp_device(ccp2); 1074 + ccp2->video_in.ops = &ccp2_video_ops; 1075 + ccp2->video_in.capture_mem = PAGE_ALIGN(4096 * 4096) * 3; 1076 + 1077 + ret = omap3isp_video_init(&ccp2->video_in, "CCP2"); 1078 + if (ret < 0) 1079 + return ret; 1080 + 1081 + /* Connect the video node to the ccp2 subdev. */ 1082 + ret = media_entity_create_link(&ccp2->video_in.video.entity, 0, 1083 + &ccp2->subdev.entity, CCP2_PAD_SINK, 0); 1084 + if (ret < 0) 1085 + return ret; 1086 + 1087 + return 0; 1088 + } 1089 + 1090 + /* 1091 + * omap3isp_ccp2_unregister_entities - Unregister media entities: subdev 1092 + * @ccp2: Pointer to ISP CCP2 device 1093 + */ 1094 + void omap3isp_ccp2_unregister_entities(struct isp_ccp2_device *ccp2) 1095 + { 1096 + media_entity_cleanup(&ccp2->subdev.entity); 1097 + 1098 + v4l2_device_unregister_subdev(&ccp2->subdev); 1099 + omap3isp_video_unregister(&ccp2->video_in); 1100 + } 1101 + 1102 + /* 1103 + * omap3isp_ccp2_register_entities - Register the subdev media entity 1104 + * @ccp2: Pointer to ISP CCP2 device 1105 + * @vdev: Pointer to v4l device 1106 + * return negative error code or zero on success 1107 + */ 1108 + 1109 + int omap3isp_ccp2_register_entities(struct isp_ccp2_device *ccp2, 1110 + struct v4l2_device *vdev) 1111 + { 1112 + int ret; 1113 + 1114 + /* Register the subdev and video nodes. */ 1115 + ret = v4l2_device_register_subdev(vdev, &ccp2->subdev); 1116 + if (ret < 0) 1117 + goto error; 1118 + 1119 + ret = omap3isp_video_register(&ccp2->video_in, vdev); 1120 + if (ret < 0) 1121 + goto error; 1122 + 1123 + return 0; 1124 + 1125 + error: 1126 + omap3isp_ccp2_unregister_entities(ccp2); 1127 + return ret; 1128 + } 1129 + 1130 + /* ----------------------------------------------------------------------------- 1131 + * ISP ccp2 initialisation and cleanup 1132 + */ 1133 + 1134 + /* 1135 + * omap3isp_ccp2_cleanup - CCP2 un-initialization 1136 + * @isp : Pointer to ISP device 1137 + */ 1138 + void omap3isp_ccp2_cleanup(struct isp_device *isp) 1139 + { 1140 + } 1141 + 1142 + /* 1143 + * omap3isp_ccp2_init - CCP2 initialization. 1144 + * @isp : Pointer to ISP device 1145 + * return negative error code or zero on success 1146 + */ 1147 + int omap3isp_ccp2_init(struct isp_device *isp) 1148 + { 1149 + struct isp_ccp2_device *ccp2 = &isp->isp_ccp2; 1150 + int ret; 1151 + 1152 + init_waitqueue_head(&ccp2->wait); 1153 + 1154 + /* On the OMAP36xx, the CCP2 uses the CSI PHY1 or PHY2, shared with 1155 + * the CSI2c or CSI2a receivers. The PHY then needs to be explicitly 1156 + * configured. 1157 + * 1158 + * TODO: Don't hardcode the usage of PHY1 (shared with CSI2c). 1159 + */ 1160 + if (isp->revision == ISP_REVISION_15_0) 1161 + ccp2->phy = &isp->isp_csiphy1; 1162 + 1163 + ret = ccp2_init_entities(ccp2); 1164 + if (ret < 0) 1165 + goto out; 1166 + 1167 + ccp2_reset(ccp2); 1168 + out: 1169 + if (ret) 1170 + omap3isp_ccp2_cleanup(isp); 1171 + 1172 + return ret; 1173 + }
+98
drivers/media/video/omap3isp/ispccp2.h
··· 1 + /* 2 + * ispccp2.h 3 + * 4 + * TI OMAP3 ISP - CCP2 module 5 + * 6 + * Copyright (C) 2010 Nokia Corporation 7 + * Copyright (C) 2010 Texas Instruments, Inc. 8 + * 9 + * Contacts: Laurent Pinchart <laurent.pinchart@ideasonboard.com> 10 + * Sakari Ailus <sakari.ailus@iki.fi> 11 + * 12 + * This program is free software; you can redistribute it and/or modify 13 + * it under the terms of the GNU General Public License version 2 as 14 + * published by the Free Software Foundation. 15 + * 16 + * This program is distributed in the hope that it will be useful, but 17 + * WITHOUT ANY WARRANTY; without even the implied warranty of 18 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 19 + * General Public License for more details. 20 + * 21 + * You should have received a copy of the GNU General Public License 22 + * along with this program; if not, write to the Free Software 23 + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 24 + * 02110-1301 USA 25 + */ 26 + 27 + #ifndef OMAP3_ISP_CCP2_H 28 + #define OMAP3_ISP_CCP2_H 29 + 30 + #include <linux/videodev2.h> 31 + 32 + struct isp_device; 33 + struct isp_csiphy; 34 + 35 + /* Sink and source ccp2 pads */ 36 + #define CCP2_PAD_SINK 0 37 + #define CCP2_PAD_SOURCE 1 38 + #define CCP2_PADS_NUM 2 39 + 40 + /* CCP2 input media entity */ 41 + enum ccp2_input_entity { 42 + CCP2_INPUT_NONE, 43 + CCP2_INPUT_SENSOR, 44 + CCP2_INPUT_MEMORY, 45 + }; 46 + 47 + /* CCP2 output media entity */ 48 + enum ccp2_output_entity { 49 + CCP2_OUTPUT_NONE, 50 + CCP2_OUTPUT_CCDC, 51 + CCP2_OUTPUT_MEMORY, 52 + }; 53 + 54 + 55 + /* Logical channel configuration */ 56 + struct isp_interface_lcx_config { 57 + int crc; 58 + u32 data_start; 59 + u32 data_size; 60 + u32 format; 61 + }; 62 + 63 + /* Memory channel configuration */ 64 + struct isp_interface_mem_config { 65 + u32 dst_port; 66 + u32 vsize_count; 67 + u32 hsize_count; 68 + u32 src_ofst; 69 + u32 dst_ofst; 70 + }; 71 + 72 + /* CCP2 device */ 73 + struct isp_ccp2_device { 74 + struct v4l2_subdev subdev; 75 + struct v4l2_mbus_framefmt formats[CCP2_PADS_NUM]; 76 + struct media_pad pads[CCP2_PADS_NUM]; 77 + 78 + enum ccp2_input_entity input; 79 + enum ccp2_output_entity output; 80 + struct isp_interface_lcx_config if_cfg; 81 + struct isp_interface_mem_config mem_cfg; 82 + struct isp_video video_in; 83 + struct isp_csiphy *phy; 84 + unsigned int error; 85 + enum isp_pipeline_stream_state state; 86 + wait_queue_head_t wait; 87 + atomic_t stopping; 88 + }; 89 + 90 + /* Function declarations */ 91 + int omap3isp_ccp2_init(struct isp_device *isp); 92 + void omap3isp_ccp2_cleanup(struct isp_device *isp); 93 + int omap3isp_ccp2_register_entities(struct isp_ccp2_device *ccp2, 94 + struct v4l2_device *vdev); 95 + void omap3isp_ccp2_unregister_entities(struct isp_ccp2_device *ccp2); 96 + int omap3isp_ccp2_isr(struct isp_ccp2_device *ccp2); 97 + 98 + #endif /* OMAP3_ISP_CCP2_H */
+1317
drivers/media/video/omap3isp/ispcsi2.c
··· 1 + /* 2 + * ispcsi2.c 3 + * 4 + * TI OMAP3 ISP - CSI2 module 5 + * 6 + * Copyright (C) 2010 Nokia Corporation 7 + * Copyright (C) 2009 Texas Instruments, Inc. 8 + * 9 + * Contacts: Laurent Pinchart <laurent.pinchart@ideasonboard.com> 10 + * Sakari Ailus <sakari.ailus@iki.fi> 11 + * 12 + * This program is free software; you can redistribute it and/or modify 13 + * it under the terms of the GNU General Public License version 2 as 14 + * published by the Free Software Foundation. 15 + * 16 + * This program is distributed in the hope that it will be useful, but 17 + * WITHOUT ANY WARRANTY; without even the implied warranty of 18 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 19 + * General Public License for more details. 20 + * 21 + * You should have received a copy of the GNU General Public License 22 + * along with this program; if not, write to the Free Software 23 + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 24 + * 02110-1301 USA 25 + */ 26 + #include <linux/delay.h> 27 + #include <media/v4l2-common.h> 28 + #include <linux/v4l2-mediabus.h> 29 + #include <linux/mm.h> 30 + 31 + #include "isp.h" 32 + #include "ispreg.h" 33 + #include "ispcsi2.h" 34 + 35 + /* 36 + * csi2_if_enable - Enable CSI2 Receiver interface. 37 + * @enable: enable flag 38 + * 39 + */ 40 + static void csi2_if_enable(struct isp_device *isp, 41 + struct isp_csi2_device *csi2, u8 enable) 42 + { 43 + struct isp_csi2_ctrl_cfg *currctrl = &csi2->ctrl; 44 + 45 + isp_reg_clr_set(isp, csi2->regs1, ISPCSI2_CTRL, ISPCSI2_CTRL_IF_EN, 46 + enable ? ISPCSI2_CTRL_IF_EN : 0); 47 + 48 + currctrl->if_enable = enable; 49 + } 50 + 51 + /* 52 + * csi2_recv_config - CSI2 receiver module configuration. 53 + * @currctrl: isp_csi2_ctrl_cfg structure 54 + * 55 + */ 56 + static void csi2_recv_config(struct isp_device *isp, 57 + struct isp_csi2_device *csi2, 58 + struct isp_csi2_ctrl_cfg *currctrl) 59 + { 60 + u32 reg; 61 + 62 + reg = isp_reg_readl(isp, csi2->regs1, ISPCSI2_CTRL); 63 + 64 + if (currctrl->frame_mode) 65 + reg |= ISPCSI2_CTRL_FRAME; 66 + else 67 + reg &= ~ISPCSI2_CTRL_FRAME; 68 + 69 + if (currctrl->vp_clk_enable) 70 + reg |= ISPCSI2_CTRL_VP_CLK_EN; 71 + else 72 + reg &= ~ISPCSI2_CTRL_VP_CLK_EN; 73 + 74 + if (currctrl->vp_only_enable) 75 + reg |= ISPCSI2_CTRL_VP_ONLY_EN; 76 + else 77 + reg &= ~ISPCSI2_CTRL_VP_ONLY_EN; 78 + 79 + reg &= ~ISPCSI2_CTRL_VP_OUT_CTRL_MASK; 80 + reg |= currctrl->vp_out_ctrl << ISPCSI2_CTRL_VP_OUT_CTRL_SHIFT; 81 + 82 + if (currctrl->ecc_enable) 83 + reg |= ISPCSI2_CTRL_ECC_EN; 84 + else 85 + reg &= ~ISPCSI2_CTRL_ECC_EN; 86 + 87 + isp_reg_writel(isp, reg, csi2->regs1, ISPCSI2_CTRL); 88 + } 89 + 90 + static const unsigned int csi2_input_fmts[] = { 91 + V4L2_MBUS_FMT_SGRBG10_1X10, 92 + V4L2_MBUS_FMT_SGRBG10_DPCM8_1X8, 93 + V4L2_MBUS_FMT_SRGGB10_1X10, 94 + V4L2_MBUS_FMT_SRGGB10_DPCM8_1X8, 95 + V4L2_MBUS_FMT_SBGGR10_1X10, 96 + V4L2_MBUS_FMT_SBGGR10_DPCM8_1X8, 97 + V4L2_MBUS_FMT_SGBRG10_1X10, 98 + V4L2_MBUS_FMT_SGBRG10_DPCM8_1X8, 99 + }; 100 + 101 + /* To set the format on the CSI2 requires a mapping function that takes 102 + * the following inputs: 103 + * - 2 different formats (at this time) 104 + * - 2 destinations (mem, vp+mem) (vp only handled separately) 105 + * - 2 decompression options (on, off) 106 + * - 2 isp revisions (certain format must be handled differently on OMAP3630) 107 + * Output should be CSI2 frame format code 108 + * Array indices as follows: [format][dest][decompr][is_3630] 109 + * Not all combinations are valid. 0 means invalid. 110 + */ 111 + static const u16 __csi2_fmt_map[2][2][2][2] = { 112 + /* RAW10 formats */ 113 + { 114 + /* Output to memory */ 115 + { 116 + /* No DPCM decompression */ 117 + { CSI2_PIX_FMT_RAW10_EXP16, CSI2_PIX_FMT_RAW10_EXP16 }, 118 + /* DPCM decompression */ 119 + { 0, 0 }, 120 + }, 121 + /* Output to both */ 122 + { 123 + /* No DPCM decompression */ 124 + { CSI2_PIX_FMT_RAW10_EXP16_VP, 125 + CSI2_PIX_FMT_RAW10_EXP16_VP }, 126 + /* DPCM decompression */ 127 + { 0, 0 }, 128 + }, 129 + }, 130 + /* RAW10 DPCM8 formats */ 131 + { 132 + /* Output to memory */ 133 + { 134 + /* No DPCM decompression */ 135 + { CSI2_PIX_FMT_RAW8, CSI2_USERDEF_8BIT_DATA1 }, 136 + /* DPCM decompression */ 137 + { CSI2_PIX_FMT_RAW8_DPCM10_EXP16, 138 + CSI2_USERDEF_8BIT_DATA1_DPCM10 }, 139 + }, 140 + /* Output to both */ 141 + { 142 + /* No DPCM decompression */ 143 + { CSI2_PIX_FMT_RAW8_VP, 144 + CSI2_PIX_FMT_RAW8_VP }, 145 + /* DPCM decompression */ 146 + { CSI2_PIX_FMT_RAW8_DPCM10_VP, 147 + CSI2_USERDEF_8BIT_DATA1_DPCM10_VP }, 148 + }, 149 + }, 150 + }; 151 + 152 + /* 153 + * csi2_ctx_map_format - Map CSI2 sink media bus format to CSI2 format ID 154 + * @csi2: ISP CSI2 device 155 + * 156 + * Returns CSI2 physical format id 157 + */ 158 + static u16 csi2_ctx_map_format(struct isp_csi2_device *csi2) 159 + { 160 + const struct v4l2_mbus_framefmt *fmt = &csi2->formats[CSI2_PAD_SINK]; 161 + int fmtidx, destidx, is_3630; 162 + 163 + switch (fmt->code) { 164 + case V4L2_MBUS_FMT_SGRBG10_1X10: 165 + case V4L2_MBUS_FMT_SRGGB10_1X10: 166 + case V4L2_MBUS_FMT_SBGGR10_1X10: 167 + case V4L2_MBUS_FMT_SGBRG10_1X10: 168 + fmtidx = 0; 169 + break; 170 + case V4L2_MBUS_FMT_SGRBG10_DPCM8_1X8: 171 + case V4L2_MBUS_FMT_SRGGB10_DPCM8_1X8: 172 + case V4L2_MBUS_FMT_SBGGR10_DPCM8_1X8: 173 + case V4L2_MBUS_FMT_SGBRG10_DPCM8_1X8: 174 + fmtidx = 1; 175 + break; 176 + default: 177 + WARN(1, KERN_ERR "CSI2: pixel format %08x unsupported!\n", 178 + fmt->code); 179 + return 0; 180 + } 181 + 182 + if (!(csi2->output & CSI2_OUTPUT_CCDC) && 183 + !(csi2->output & CSI2_OUTPUT_MEMORY)) { 184 + /* Neither output enabled is a valid combination */ 185 + return CSI2_PIX_FMT_OTHERS; 186 + } 187 + 188 + /* If we need to skip frames at the beginning of the stream disable the 189 + * video port to avoid sending the skipped frames to the CCDC. 190 + */ 191 + destidx = csi2->frame_skip ? 0 : !!(csi2->output & CSI2_OUTPUT_CCDC); 192 + is_3630 = csi2->isp->revision == ISP_REVISION_15_0; 193 + 194 + return __csi2_fmt_map[fmtidx][destidx][csi2->dpcm_decompress][is_3630]; 195 + } 196 + 197 + /* 198 + * csi2_set_outaddr - Set memory address to save output image 199 + * @csi2: Pointer to ISP CSI2a device. 200 + * @addr: ISP MMU Mapped 32-bit memory address aligned on 32 byte boundary. 201 + * 202 + * Sets the memory address where the output will be saved. 203 + * 204 + * Returns 0 if successful, or -EINVAL if the address is not in the 32 byte 205 + * boundary. 206 + */ 207 + static void csi2_set_outaddr(struct isp_csi2_device *csi2, u32 addr) 208 + { 209 + struct isp_device *isp = csi2->isp; 210 + struct isp_csi2_ctx_cfg *ctx = &csi2->contexts[0]; 211 + 212 + ctx->ping_addr = addr; 213 + ctx->pong_addr = addr; 214 + isp_reg_writel(isp, ctx->ping_addr, 215 + csi2->regs1, ISPCSI2_CTX_DAT_PING_ADDR(ctx->ctxnum)); 216 + isp_reg_writel(isp, ctx->pong_addr, 217 + csi2->regs1, ISPCSI2_CTX_DAT_PONG_ADDR(ctx->ctxnum)); 218 + } 219 + 220 + /* 221 + * is_usr_def_mapping - Checks whether USER_DEF_MAPPING should 222 + * be enabled by CSI2. 223 + * @format_id: mapped format id 224 + * 225 + */ 226 + static inline int is_usr_def_mapping(u32 format_id) 227 + { 228 + return (format_id & 0x40) ? 1 : 0; 229 + } 230 + 231 + /* 232 + * csi2_ctx_enable - Enable specified CSI2 context 233 + * @ctxnum: Context number, valid between 0 and 7 values. 234 + * @enable: enable 235 + * 236 + */ 237 + static void csi2_ctx_enable(struct isp_device *isp, 238 + struct isp_csi2_device *csi2, u8 ctxnum, u8 enable) 239 + { 240 + struct isp_csi2_ctx_cfg *ctx = &csi2->contexts[ctxnum]; 241 + unsigned int skip = 0; 242 + u32 reg; 243 + 244 + reg = isp_reg_readl(isp, csi2->regs1, ISPCSI2_CTX_CTRL1(ctxnum)); 245 + 246 + if (enable) { 247 + if (csi2->frame_skip) 248 + skip = csi2->frame_skip; 249 + else if (csi2->output & CSI2_OUTPUT_MEMORY) 250 + skip = 1; 251 + 252 + reg &= ~ISPCSI2_CTX_CTRL1_COUNT_MASK; 253 + reg |= ISPCSI2_CTX_CTRL1_COUNT_UNLOCK 254 + | (skip << ISPCSI2_CTX_CTRL1_COUNT_SHIFT) 255 + | ISPCSI2_CTX_CTRL1_CTX_EN; 256 + } else { 257 + reg &= ~ISPCSI2_CTX_CTRL1_CTX_EN; 258 + } 259 + 260 + isp_reg_writel(isp, reg, csi2->regs1, ISPCSI2_CTX_CTRL1(ctxnum)); 261 + ctx->enabled = enable; 262 + } 263 + 264 + /* 265 + * csi2_ctx_config - CSI2 context configuration. 266 + * @ctx: context configuration 267 + * 268 + */ 269 + static void csi2_ctx_config(struct isp_device *isp, 270 + struct isp_csi2_device *csi2, 271 + struct isp_csi2_ctx_cfg *ctx) 272 + { 273 + u32 reg; 274 + 275 + /* Set up CSI2_CTx_CTRL1 */ 276 + reg = isp_reg_readl(isp, csi2->regs1, ISPCSI2_CTX_CTRL1(ctx->ctxnum)); 277 + 278 + if (ctx->eof_enabled) 279 + reg |= ISPCSI2_CTX_CTRL1_EOF_EN; 280 + else 281 + reg &= ~ISPCSI2_CTX_CTRL1_EOF_EN; 282 + 283 + if (ctx->eol_enabled) 284 + reg |= ISPCSI2_CTX_CTRL1_EOL_EN; 285 + else 286 + reg &= ~ISPCSI2_CTX_CTRL1_EOL_EN; 287 + 288 + if (ctx->checksum_enabled) 289 + reg |= ISPCSI2_CTX_CTRL1_CS_EN; 290 + else 291 + reg &= ~ISPCSI2_CTX_CTRL1_CS_EN; 292 + 293 + isp_reg_writel(isp, reg, csi2->regs1, ISPCSI2_CTX_CTRL1(ctx->ctxnum)); 294 + 295 + /* Set up CSI2_CTx_CTRL2 */ 296 + reg = isp_reg_readl(isp, csi2->regs1, ISPCSI2_CTX_CTRL2(ctx->ctxnum)); 297 + 298 + reg &= ~(ISPCSI2_CTX_CTRL2_VIRTUAL_ID_MASK); 299 + reg |= ctx->virtual_id << ISPCSI2_CTX_CTRL2_VIRTUAL_ID_SHIFT; 300 + 301 + reg &= ~(ISPCSI2_CTX_CTRL2_FORMAT_MASK); 302 + reg |= ctx->format_id << ISPCSI2_CTX_CTRL2_FORMAT_SHIFT; 303 + 304 + if (ctx->dpcm_decompress) { 305 + if (ctx->dpcm_predictor) 306 + reg |= ISPCSI2_CTX_CTRL2_DPCM_PRED; 307 + else 308 + reg &= ~ISPCSI2_CTX_CTRL2_DPCM_PRED; 309 + } 310 + 311 + if (is_usr_def_mapping(ctx->format_id)) { 312 + reg &= ~ISPCSI2_CTX_CTRL2_USER_DEF_MAP_MASK; 313 + reg |= 2 << ISPCSI2_CTX_CTRL2_USER_DEF_MAP_SHIFT; 314 + } 315 + 316 + isp_reg_writel(isp, reg, csi2->regs1, ISPCSI2_CTX_CTRL2(ctx->ctxnum)); 317 + 318 + /* Set up CSI2_CTx_CTRL3 */ 319 + reg = isp_reg_readl(isp, csi2->regs1, ISPCSI2_CTX_CTRL3(ctx->ctxnum)); 320 + reg &= ~(ISPCSI2_CTX_CTRL3_ALPHA_MASK); 321 + reg |= (ctx->alpha << ISPCSI2_CTX_CTRL3_ALPHA_SHIFT); 322 + 323 + isp_reg_writel(isp, reg, csi2->regs1, ISPCSI2_CTX_CTRL3(ctx->ctxnum)); 324 + 325 + /* Set up CSI2_CTx_DAT_OFST */ 326 + reg = isp_reg_readl(isp, csi2->regs1, 327 + ISPCSI2_CTX_DAT_OFST(ctx->ctxnum)); 328 + reg &= ~ISPCSI2_CTX_DAT_OFST_OFST_MASK; 329 + reg |= ctx->data_offset << ISPCSI2_CTX_DAT_OFST_OFST_SHIFT; 330 + isp_reg_writel(isp, reg, csi2->regs1, 331 + ISPCSI2_CTX_DAT_OFST(ctx->ctxnum)); 332 + 333 + isp_reg_writel(isp, ctx->ping_addr, 334 + csi2->regs1, ISPCSI2_CTX_DAT_PING_ADDR(ctx->ctxnum)); 335 + 336 + isp_reg_writel(isp, ctx->pong_addr, 337 + csi2->regs1, ISPCSI2_CTX_DAT_PONG_ADDR(ctx->ctxnum)); 338 + } 339 + 340 + /* 341 + * csi2_timing_config - CSI2 timing configuration. 342 + * @timing: csi2_timing_cfg structure 343 + */ 344 + static void csi2_timing_config(struct isp_device *isp, 345 + struct isp_csi2_device *csi2, 346 + struct isp_csi2_timing_cfg *timing) 347 + { 348 + u32 reg; 349 + 350 + reg = isp_reg_readl(isp, csi2->regs1, ISPCSI2_TIMING); 351 + 352 + if (timing->force_rx_mode) 353 + reg |= ISPCSI2_TIMING_FORCE_RX_MODE_IO(timing->ionum); 354 + else 355 + reg &= ~ISPCSI2_TIMING_FORCE_RX_MODE_IO(timing->ionum); 356 + 357 + if (timing->stop_state_16x) 358 + reg |= ISPCSI2_TIMING_STOP_STATE_X16_IO(timing->ionum); 359 + else 360 + reg &= ~ISPCSI2_TIMING_STOP_STATE_X16_IO(timing->ionum); 361 + 362 + if (timing->stop_state_4x) 363 + reg |= ISPCSI2_TIMING_STOP_STATE_X4_IO(timing->ionum); 364 + else 365 + reg &= ~ISPCSI2_TIMING_STOP_STATE_X4_IO(timing->ionum); 366 + 367 + reg &= ~ISPCSI2_TIMING_STOP_STATE_COUNTER_IO_MASK(timing->ionum); 368 + reg |= timing->stop_state_counter << 369 + ISPCSI2_TIMING_STOP_STATE_COUNTER_IO_SHIFT(timing->ionum); 370 + 371 + isp_reg_writel(isp, reg, csi2->regs1, ISPCSI2_TIMING); 372 + } 373 + 374 + /* 375 + * csi2_irq_ctx_set - Enables CSI2 Context IRQs. 376 + * @enable: Enable/disable CSI2 Context interrupts 377 + */ 378 + static void csi2_irq_ctx_set(struct isp_device *isp, 379 + struct isp_csi2_device *csi2, int enable) 380 + { 381 + u32 reg = ISPCSI2_CTX_IRQSTATUS_FE_IRQ; 382 + int i; 383 + 384 + if (csi2->use_fs_irq) 385 + reg |= ISPCSI2_CTX_IRQSTATUS_FS_IRQ; 386 + 387 + for (i = 0; i < 8; i++) { 388 + isp_reg_writel(isp, reg, csi2->regs1, 389 + ISPCSI2_CTX_IRQSTATUS(i)); 390 + if (enable) 391 + isp_reg_set(isp, csi2->regs1, ISPCSI2_CTX_IRQENABLE(i), 392 + reg); 393 + else 394 + isp_reg_clr(isp, csi2->regs1, ISPCSI2_CTX_IRQENABLE(i), 395 + reg); 396 + } 397 + } 398 + 399 + /* 400 + * csi2_irq_complexio1_set - Enables CSI2 ComplexIO IRQs. 401 + * @enable: Enable/disable CSI2 ComplexIO #1 interrupts 402 + */ 403 + static void csi2_irq_complexio1_set(struct isp_device *isp, 404 + struct isp_csi2_device *csi2, int enable) 405 + { 406 + u32 reg; 407 + reg = ISPCSI2_PHY_IRQENABLE_STATEALLULPMEXIT | 408 + ISPCSI2_PHY_IRQENABLE_STATEALLULPMENTER | 409 + ISPCSI2_PHY_IRQENABLE_STATEULPM5 | 410 + ISPCSI2_PHY_IRQENABLE_ERRCONTROL5 | 411 + ISPCSI2_PHY_IRQENABLE_ERRESC5 | 412 + ISPCSI2_PHY_IRQENABLE_ERRSOTSYNCHS5 | 413 + ISPCSI2_PHY_IRQENABLE_ERRSOTHS5 | 414 + ISPCSI2_PHY_IRQENABLE_STATEULPM4 | 415 + ISPCSI2_PHY_IRQENABLE_ERRCONTROL4 | 416 + ISPCSI2_PHY_IRQENABLE_ERRESC4 | 417 + ISPCSI2_PHY_IRQENABLE_ERRSOTSYNCHS4 | 418 + ISPCSI2_PHY_IRQENABLE_ERRSOTHS4 | 419 + ISPCSI2_PHY_IRQENABLE_STATEULPM3 | 420 + ISPCSI2_PHY_IRQENABLE_ERRCONTROL3 | 421 + ISPCSI2_PHY_IRQENABLE_ERRESC3 | 422 + ISPCSI2_PHY_IRQENABLE_ERRSOTSYNCHS3 | 423 + ISPCSI2_PHY_IRQENABLE_ERRSOTHS3 | 424 + ISPCSI2_PHY_IRQENABLE_STATEULPM2 | 425 + ISPCSI2_PHY_IRQENABLE_ERRCONTROL2 | 426 + ISPCSI2_PHY_IRQENABLE_ERRESC2 | 427 + ISPCSI2_PHY_IRQENABLE_ERRSOTSYNCHS2 | 428 + ISPCSI2_PHY_IRQENABLE_ERRSOTHS2 | 429 + ISPCSI2_PHY_IRQENABLE_STATEULPM1 | 430 + ISPCSI2_PHY_IRQENABLE_ERRCONTROL1 | 431 + ISPCSI2_PHY_IRQENABLE_ERRESC1 | 432 + ISPCSI2_PHY_IRQENABLE_ERRSOTSYNCHS1 | 433 + ISPCSI2_PHY_IRQENABLE_ERRSOTHS1; 434 + isp_reg_writel(isp, reg, csi2->regs1, ISPCSI2_PHY_IRQSTATUS); 435 + if (enable) 436 + reg |= isp_reg_readl(isp, csi2->regs1, ISPCSI2_PHY_IRQENABLE); 437 + else 438 + reg = 0; 439 + isp_reg_writel(isp, reg, csi2->regs1, ISPCSI2_PHY_IRQENABLE); 440 + } 441 + 442 + /* 443 + * csi2_irq_status_set - Enables CSI2 Status IRQs. 444 + * @enable: Enable/disable CSI2 Status interrupts 445 + */ 446 + static void csi2_irq_status_set(struct isp_device *isp, 447 + struct isp_csi2_device *csi2, int enable) 448 + { 449 + u32 reg; 450 + reg = ISPCSI2_IRQSTATUS_OCP_ERR_IRQ | 451 + ISPCSI2_IRQSTATUS_SHORT_PACKET_IRQ | 452 + ISPCSI2_IRQSTATUS_ECC_CORRECTION_IRQ | 453 + ISPCSI2_IRQSTATUS_ECC_NO_CORRECTION_IRQ | 454 + ISPCSI2_IRQSTATUS_COMPLEXIO2_ERR_IRQ | 455 + ISPCSI2_IRQSTATUS_COMPLEXIO1_ERR_IRQ | 456 + ISPCSI2_IRQSTATUS_FIFO_OVF_IRQ | 457 + ISPCSI2_IRQSTATUS_CONTEXT(0); 458 + isp_reg_writel(isp, reg, csi2->regs1, ISPCSI2_IRQSTATUS); 459 + if (enable) 460 + reg |= isp_reg_readl(isp, csi2->regs1, ISPCSI2_IRQENABLE); 461 + else 462 + reg = 0; 463 + 464 + isp_reg_writel(isp, reg, csi2->regs1, ISPCSI2_IRQENABLE); 465 + } 466 + 467 + /* 468 + * omap3isp_csi2_reset - Resets the CSI2 module. 469 + * 470 + * Must be called with the phy lock held. 471 + * 472 + * Returns 0 if successful, or -EBUSY if power command didn't respond. 473 + */ 474 + int omap3isp_csi2_reset(struct isp_csi2_device *csi2) 475 + { 476 + struct isp_device *isp = csi2->isp; 477 + u8 soft_reset_retries = 0; 478 + u32 reg; 479 + int i; 480 + 481 + if (!csi2->available) 482 + return -ENODEV; 483 + 484 + if (csi2->phy->phy_in_use) 485 + return -EBUSY; 486 + 487 + isp_reg_set(isp, csi2->regs1, ISPCSI2_SYSCONFIG, 488 + ISPCSI2_SYSCONFIG_SOFT_RESET); 489 + 490 + do { 491 + reg = isp_reg_readl(isp, csi2->regs1, ISPCSI2_SYSSTATUS) & 492 + ISPCSI2_SYSSTATUS_RESET_DONE; 493 + if (reg == ISPCSI2_SYSSTATUS_RESET_DONE) 494 + break; 495 + soft_reset_retries++; 496 + if (soft_reset_retries < 5) 497 + udelay(100); 498 + } while (soft_reset_retries < 5); 499 + 500 + if (soft_reset_retries == 5) { 501 + printk(KERN_ERR "CSI2: Soft reset try count exceeded!\n"); 502 + return -EBUSY; 503 + } 504 + 505 + if (isp->revision == ISP_REVISION_15_0) 506 + isp_reg_set(isp, csi2->regs1, ISPCSI2_PHY_CFG, 507 + ISPCSI2_PHY_CFG_RESET_CTRL); 508 + 509 + i = 100; 510 + do { 511 + reg = isp_reg_readl(isp, csi2->phy->phy_regs, ISPCSIPHY_REG1) 512 + & ISPCSIPHY_REG1_RESET_DONE_CTRLCLK; 513 + if (reg == ISPCSIPHY_REG1_RESET_DONE_CTRLCLK) 514 + break; 515 + udelay(100); 516 + } while (--i > 0); 517 + 518 + if (i == 0) { 519 + printk(KERN_ERR 520 + "CSI2: Reset for CSI2_96M_FCLK domain Failed!\n"); 521 + return -EBUSY; 522 + } 523 + 524 + if (isp->autoidle) 525 + isp_reg_clr_set(isp, csi2->regs1, ISPCSI2_SYSCONFIG, 526 + ISPCSI2_SYSCONFIG_MSTANDBY_MODE_MASK | 527 + ISPCSI2_SYSCONFIG_AUTO_IDLE, 528 + ISPCSI2_SYSCONFIG_MSTANDBY_MODE_SMART | 529 + ((isp->revision == ISP_REVISION_15_0) ? 530 + ISPCSI2_SYSCONFIG_AUTO_IDLE : 0)); 531 + else 532 + isp_reg_clr_set(isp, csi2->regs1, ISPCSI2_SYSCONFIG, 533 + ISPCSI2_SYSCONFIG_MSTANDBY_MODE_MASK | 534 + ISPCSI2_SYSCONFIG_AUTO_IDLE, 535 + ISPCSI2_SYSCONFIG_MSTANDBY_MODE_NO); 536 + 537 + return 0; 538 + } 539 + 540 + static int csi2_configure(struct isp_csi2_device *csi2) 541 + { 542 + const struct isp_v4l2_subdevs_group *pdata; 543 + struct isp_device *isp = csi2->isp; 544 + struct isp_csi2_timing_cfg *timing = &csi2->timing[0]; 545 + struct v4l2_subdev *sensor; 546 + struct media_pad *pad; 547 + 548 + /* 549 + * CSI2 fields that can be updated while the context has 550 + * been enabled or the interface has been enabled are not 551 + * updated dynamically currently. So we do not allow to 552 + * reconfigure if either has been enabled 553 + */ 554 + if (csi2->contexts[0].enabled || csi2->ctrl.if_enable) 555 + return -EBUSY; 556 + 557 + pad = media_entity_remote_source(&csi2->pads[CSI2_PAD_SINK]); 558 + sensor = media_entity_to_v4l2_subdev(pad->entity); 559 + pdata = sensor->host_priv; 560 + 561 + csi2->frame_skip = 0; 562 + v4l2_subdev_call(sensor, sensor, g_skip_frames, &csi2->frame_skip); 563 + 564 + csi2->ctrl.vp_out_ctrl = pdata->bus.csi2.vpclk_div; 565 + csi2->ctrl.frame_mode = ISP_CSI2_FRAME_IMMEDIATE; 566 + csi2->ctrl.ecc_enable = pdata->bus.csi2.crc; 567 + 568 + timing->ionum = 1; 569 + timing->force_rx_mode = 1; 570 + timing->stop_state_16x = 1; 571 + timing->stop_state_4x = 1; 572 + timing->stop_state_counter = 0x1FF; 573 + 574 + /* 575 + * The CSI2 receiver can't do any format conversion except DPCM 576 + * decompression, so every set_format call configures both pads 577 + * and enables DPCM decompression as a special case: 578 + */ 579 + if (csi2->formats[CSI2_PAD_SINK].code != 580 + csi2->formats[CSI2_PAD_SOURCE].code) 581 + csi2->dpcm_decompress = true; 582 + else 583 + csi2->dpcm_decompress = false; 584 + 585 + csi2->contexts[0].format_id = csi2_ctx_map_format(csi2); 586 + 587 + if (csi2->video_out.bpl_padding == 0) 588 + csi2->contexts[0].data_offset = 0; 589 + else 590 + csi2->contexts[0].data_offset = csi2->video_out.bpl_value; 591 + 592 + /* 593 + * Enable end of frame and end of line signals generation for 594 + * context 0. These signals are generated from CSI2 receiver to 595 + * qualify the last pixel of a frame and the last pixel of a line. 596 + * Without enabling the signals CSI2 receiver writes data to memory 597 + * beyond buffer size and/or data line offset is not handled correctly. 598 + */ 599 + csi2->contexts[0].eof_enabled = 1; 600 + csi2->contexts[0].eol_enabled = 1; 601 + 602 + csi2_irq_complexio1_set(isp, csi2, 1); 603 + csi2_irq_ctx_set(isp, csi2, 1); 604 + csi2_irq_status_set(isp, csi2, 1); 605 + 606 + /* Set configuration (timings, format and links) */ 607 + csi2_timing_config(isp, csi2, timing); 608 + csi2_recv_config(isp, csi2, &csi2->ctrl); 609 + csi2_ctx_config(isp, csi2, &csi2->contexts[0]); 610 + 611 + return 0; 612 + } 613 + 614 + /* 615 + * csi2_print_status - Prints CSI2 debug information. 616 + */ 617 + #define CSI2_PRINT_REGISTER(isp, regs, name)\ 618 + dev_dbg(isp->dev, "###CSI2 " #name "=0x%08x\n", \ 619 + isp_reg_readl(isp, regs, ISPCSI2_##name)) 620 + 621 + static void csi2_print_status(struct isp_csi2_device *csi2) 622 + { 623 + struct isp_device *isp = csi2->isp; 624 + 625 + if (!csi2->available) 626 + return; 627 + 628 + dev_dbg(isp->dev, "-------------CSI2 Register dump-------------\n"); 629 + 630 + CSI2_PRINT_REGISTER(isp, csi2->regs1, SYSCONFIG); 631 + CSI2_PRINT_REGISTER(isp, csi2->regs1, SYSSTATUS); 632 + CSI2_PRINT_REGISTER(isp, csi2->regs1, IRQENABLE); 633 + CSI2_PRINT_REGISTER(isp, csi2->regs1, IRQSTATUS); 634 + CSI2_PRINT_REGISTER(isp, csi2->regs1, CTRL); 635 + CSI2_PRINT_REGISTER(isp, csi2->regs1, DBG_H); 636 + CSI2_PRINT_REGISTER(isp, csi2->regs1, GNQ); 637 + CSI2_PRINT_REGISTER(isp, csi2->regs1, PHY_CFG); 638 + CSI2_PRINT_REGISTER(isp, csi2->regs1, PHY_IRQSTATUS); 639 + CSI2_PRINT_REGISTER(isp, csi2->regs1, SHORT_PACKET); 640 + CSI2_PRINT_REGISTER(isp, csi2->regs1, PHY_IRQENABLE); 641 + CSI2_PRINT_REGISTER(isp, csi2->regs1, DBG_P); 642 + CSI2_PRINT_REGISTER(isp, csi2->regs1, TIMING); 643 + CSI2_PRINT_REGISTER(isp, csi2->regs1, CTX_CTRL1(0)); 644 + CSI2_PRINT_REGISTER(isp, csi2->regs1, CTX_CTRL2(0)); 645 + CSI2_PRINT_REGISTER(isp, csi2->regs1, CTX_DAT_OFST(0)); 646 + CSI2_PRINT_REGISTER(isp, csi2->regs1, CTX_DAT_PING_ADDR(0)); 647 + CSI2_PRINT_REGISTER(isp, csi2->regs1, CTX_DAT_PONG_ADDR(0)); 648 + CSI2_PRINT_REGISTER(isp, csi2->regs1, CTX_IRQENABLE(0)); 649 + CSI2_PRINT_REGISTER(isp, csi2->regs1, CTX_IRQSTATUS(0)); 650 + CSI2_PRINT_REGISTER(isp, csi2->regs1, CTX_CTRL3(0)); 651 + 652 + dev_dbg(isp->dev, "--------------------------------------------\n"); 653 + } 654 + 655 + /* ----------------------------------------------------------------------------- 656 + * Interrupt handling 657 + */ 658 + 659 + /* 660 + * csi2_isr_buffer - Does buffer handling at end-of-frame 661 + * when writing to memory. 662 + */ 663 + static void csi2_isr_buffer(struct isp_csi2_device *csi2) 664 + { 665 + struct isp_device *isp = csi2->isp; 666 + struct isp_buffer *buffer; 667 + 668 + csi2_ctx_enable(isp, csi2, 0, 0); 669 + 670 + buffer = omap3isp_video_buffer_next(&csi2->video_out, 0); 671 + 672 + /* 673 + * Let video queue operation restart engine if there is an underrun 674 + * condition. 675 + */ 676 + if (buffer == NULL) 677 + return; 678 + 679 + csi2_set_outaddr(csi2, buffer->isp_addr); 680 + csi2_ctx_enable(isp, csi2, 0, 1); 681 + } 682 + 683 + static void csi2_isr_ctx(struct isp_csi2_device *csi2, 684 + struct isp_csi2_ctx_cfg *ctx) 685 + { 686 + struct isp_device *isp = csi2->isp; 687 + unsigned int n = ctx->ctxnum; 688 + u32 status; 689 + 690 + status = isp_reg_readl(isp, csi2->regs1, ISPCSI2_CTX_IRQSTATUS(n)); 691 + isp_reg_writel(isp, status, csi2->regs1, ISPCSI2_CTX_IRQSTATUS(n)); 692 + 693 + /* Propagate frame number */ 694 + if (status & ISPCSI2_CTX_IRQSTATUS_FS_IRQ) { 695 + struct isp_pipeline *pipe = 696 + to_isp_pipeline(&csi2->subdev.entity); 697 + if (pipe->do_propagation) 698 + atomic_inc(&pipe->frame_number); 699 + } 700 + 701 + if (!(status & ISPCSI2_CTX_IRQSTATUS_FE_IRQ)) 702 + return; 703 + 704 + /* Skip interrupts until we reach the frame skip count. The CSI2 will be 705 + * automatically disabled, as the frame skip count has been programmed 706 + * in the CSI2_CTx_CTRL1::COUNT field, so reenable it. 707 + * 708 + * It would have been nice to rely on the FRAME_NUMBER interrupt instead 709 + * but it turned out that the interrupt is only generated when the CSI2 710 + * writes to memory (the CSI2_CTx_CTRL1::COUNT field is decreased 711 + * correctly and reaches 0 when data is forwarded to the video port only 712 + * but no interrupt arrives). Maybe a CSI2 hardware bug. 713 + */ 714 + if (csi2->frame_skip) { 715 + csi2->frame_skip--; 716 + if (csi2->frame_skip == 0) { 717 + ctx->format_id = csi2_ctx_map_format(csi2); 718 + csi2_ctx_config(isp, csi2, ctx); 719 + csi2_ctx_enable(isp, csi2, n, 1); 720 + } 721 + return; 722 + } 723 + 724 + if (csi2->output & CSI2_OUTPUT_MEMORY) 725 + csi2_isr_buffer(csi2); 726 + } 727 + 728 + /* 729 + * omap3isp_csi2_isr - CSI2 interrupt handling. 730 + * 731 + * Return -EIO on Transmission error 732 + */ 733 + int omap3isp_csi2_isr(struct isp_csi2_device *csi2) 734 + { 735 + u32 csi2_irqstatus, cpxio1_irqstatus; 736 + struct isp_device *isp = csi2->isp; 737 + int retval = 0; 738 + 739 + if (!csi2->available) 740 + return -ENODEV; 741 + 742 + csi2_irqstatus = isp_reg_readl(isp, csi2->regs1, ISPCSI2_IRQSTATUS); 743 + isp_reg_writel(isp, csi2_irqstatus, csi2->regs1, ISPCSI2_IRQSTATUS); 744 + 745 + /* Failure Cases */ 746 + if (csi2_irqstatus & ISPCSI2_IRQSTATUS_COMPLEXIO1_ERR_IRQ) { 747 + cpxio1_irqstatus = isp_reg_readl(isp, csi2->regs1, 748 + ISPCSI2_PHY_IRQSTATUS); 749 + isp_reg_writel(isp, cpxio1_irqstatus, 750 + csi2->regs1, ISPCSI2_PHY_IRQSTATUS); 751 + dev_dbg(isp->dev, "CSI2: ComplexIO Error IRQ " 752 + "%x\n", cpxio1_irqstatus); 753 + retval = -EIO; 754 + } 755 + 756 + if (csi2_irqstatus & (ISPCSI2_IRQSTATUS_OCP_ERR_IRQ | 757 + ISPCSI2_IRQSTATUS_SHORT_PACKET_IRQ | 758 + ISPCSI2_IRQSTATUS_ECC_NO_CORRECTION_IRQ | 759 + ISPCSI2_IRQSTATUS_COMPLEXIO2_ERR_IRQ | 760 + ISPCSI2_IRQSTATUS_FIFO_OVF_IRQ)) { 761 + dev_dbg(isp->dev, "CSI2 Err:" 762 + " OCP:%d," 763 + " Short_pack:%d," 764 + " ECC:%d," 765 + " CPXIO2:%d," 766 + " FIFO_OVF:%d," 767 + "\n", 768 + (csi2_irqstatus & 769 + ISPCSI2_IRQSTATUS_OCP_ERR_IRQ) ? 1 : 0, 770 + (csi2_irqstatus & 771 + ISPCSI2_IRQSTATUS_SHORT_PACKET_IRQ) ? 1 : 0, 772 + (csi2_irqstatus & 773 + ISPCSI2_IRQSTATUS_ECC_NO_CORRECTION_IRQ) ? 1 : 0, 774 + (csi2_irqstatus & 775 + ISPCSI2_IRQSTATUS_COMPLEXIO2_ERR_IRQ) ? 1 : 0, 776 + (csi2_irqstatus & 777 + ISPCSI2_IRQSTATUS_FIFO_OVF_IRQ) ? 1 : 0); 778 + retval = -EIO; 779 + } 780 + 781 + if (omap3isp_module_sync_is_stopping(&csi2->wait, &csi2->stopping)) 782 + return 0; 783 + 784 + /* Successful cases */ 785 + if (csi2_irqstatus & ISPCSI2_IRQSTATUS_CONTEXT(0)) 786 + csi2_isr_ctx(csi2, &csi2->contexts[0]); 787 + 788 + if (csi2_irqstatus & ISPCSI2_IRQSTATUS_ECC_CORRECTION_IRQ) 789 + dev_dbg(isp->dev, "CSI2: ECC correction done\n"); 790 + 791 + return retval; 792 + } 793 + 794 + /* ----------------------------------------------------------------------------- 795 + * ISP video operations 796 + */ 797 + 798 + /* 799 + * csi2_queue - Queues the first buffer when using memory output 800 + * @video: The video node 801 + * @buffer: buffer to queue 802 + */ 803 + static int csi2_queue(struct isp_video *video, struct isp_buffer *buffer) 804 + { 805 + struct isp_device *isp = video->isp; 806 + struct isp_csi2_device *csi2 = &isp->isp_csi2a; 807 + 808 + csi2_set_outaddr(csi2, buffer->isp_addr); 809 + 810 + /* 811 + * If streaming was enabled before there was a buffer queued 812 + * or underrun happened in the ISR, the hardware was not enabled 813 + * and DMA queue flag ISP_VIDEO_DMAQUEUE_UNDERRUN is still set. 814 + * Enable it now. 815 + */ 816 + if (csi2->video_out.dmaqueue_flags & ISP_VIDEO_DMAQUEUE_UNDERRUN) { 817 + /* Enable / disable context 0 and IRQs */ 818 + csi2_if_enable(isp, csi2, 1); 819 + csi2_ctx_enable(isp, csi2, 0, 1); 820 + isp_video_dmaqueue_flags_clr(&csi2->video_out); 821 + } 822 + 823 + return 0; 824 + } 825 + 826 + static const struct isp_video_operations csi2_ispvideo_ops = { 827 + .queue = csi2_queue, 828 + }; 829 + 830 + /* ----------------------------------------------------------------------------- 831 + * V4L2 subdev operations 832 + */ 833 + 834 + static struct v4l2_mbus_framefmt * 835 + __csi2_get_format(struct isp_csi2_device *csi2, struct v4l2_subdev_fh *fh, 836 + unsigned int pad, enum v4l2_subdev_format_whence which) 837 + { 838 + if (which == V4L2_SUBDEV_FORMAT_TRY) 839 + return v4l2_subdev_get_try_format(fh, pad); 840 + else 841 + return &csi2->formats[pad]; 842 + } 843 + 844 + static void 845 + csi2_try_format(struct isp_csi2_device *csi2, struct v4l2_subdev_fh *fh, 846 + unsigned int pad, struct v4l2_mbus_framefmt *fmt, 847 + enum v4l2_subdev_format_whence which) 848 + { 849 + enum v4l2_mbus_pixelcode pixelcode; 850 + struct v4l2_mbus_framefmt *format; 851 + const struct isp_format_info *info; 852 + unsigned int i; 853 + 854 + switch (pad) { 855 + case CSI2_PAD_SINK: 856 + /* Clamp the width and height to valid range (1-8191). */ 857 + for (i = 0; i < ARRAY_SIZE(csi2_input_fmts); i++) { 858 + if (fmt->code == csi2_input_fmts[i]) 859 + break; 860 + } 861 + 862 + /* If not found, use SGRBG10 as default */ 863 + if (i >= ARRAY_SIZE(csi2_input_fmts)) 864 + fmt->code = V4L2_MBUS_FMT_SGRBG10_1X10; 865 + 866 + fmt->width = clamp_t(u32, fmt->width, 1, 8191); 867 + fmt->height = clamp_t(u32, fmt->height, 1, 8191); 868 + break; 869 + 870 + case CSI2_PAD_SOURCE: 871 + /* Source format same as sink format, except for DPCM 872 + * compression. 873 + */ 874 + pixelcode = fmt->code; 875 + format = __csi2_get_format(csi2, fh, CSI2_PAD_SINK, which); 876 + memcpy(fmt, format, sizeof(*fmt)); 877 + 878 + /* 879 + * Only Allow DPCM decompression, and check that the 880 + * pattern is preserved 881 + */ 882 + info = omap3isp_video_format_info(fmt->code); 883 + if (info->uncompressed == pixelcode) 884 + fmt->code = pixelcode; 885 + break; 886 + } 887 + 888 + /* RGB, non-interlaced */ 889 + fmt->colorspace = V4L2_COLORSPACE_SRGB; 890 + fmt->field = V4L2_FIELD_NONE; 891 + } 892 + 893 + /* 894 + * csi2_enum_mbus_code - Handle pixel format enumeration 895 + * @sd : pointer to v4l2 subdev structure 896 + * @fh : V4L2 subdev file handle 897 + * @code : pointer to v4l2_subdev_mbus_code_enum structure 898 + * return -EINVAL or zero on success 899 + */ 900 + static int csi2_enum_mbus_code(struct v4l2_subdev *sd, 901 + struct v4l2_subdev_fh *fh, 902 + struct v4l2_subdev_mbus_code_enum *code) 903 + { 904 + struct isp_csi2_device *csi2 = v4l2_get_subdevdata(sd); 905 + struct v4l2_mbus_framefmt *format; 906 + const struct isp_format_info *info; 907 + 908 + if (code->pad == CSI2_PAD_SINK) { 909 + if (code->index >= ARRAY_SIZE(csi2_input_fmts)) 910 + return -EINVAL; 911 + 912 + code->code = csi2_input_fmts[code->index]; 913 + } else { 914 + format = __csi2_get_format(csi2, fh, CSI2_PAD_SINK, 915 + V4L2_SUBDEV_FORMAT_TRY); 916 + switch (code->index) { 917 + case 0: 918 + /* Passthrough sink pad code */ 919 + code->code = format->code; 920 + break; 921 + case 1: 922 + /* Uncompressed code */ 923 + info = omap3isp_video_format_info(format->code); 924 + if (info->uncompressed == format->code) 925 + return -EINVAL; 926 + 927 + code->code = info->uncompressed; 928 + break; 929 + default: 930 + return -EINVAL; 931 + } 932 + } 933 + 934 + return 0; 935 + } 936 + 937 + static int csi2_enum_frame_size(struct v4l2_subdev *sd, 938 + struct v4l2_subdev_fh *fh, 939 + struct v4l2_subdev_frame_size_enum *fse) 940 + { 941 + struct isp_csi2_device *csi2 = v4l2_get_subdevdata(sd); 942 + struct v4l2_mbus_framefmt format; 943 + 944 + if (fse->index != 0) 945 + return -EINVAL; 946 + 947 + format.code = fse->code; 948 + format.width = 1; 949 + format.height = 1; 950 + csi2_try_format(csi2, fh, fse->pad, &format, V4L2_SUBDEV_FORMAT_TRY); 951 + fse->min_width = format.width; 952 + fse->min_height = format.height; 953 + 954 + if (format.code != fse->code) 955 + return -EINVAL; 956 + 957 + format.code = fse->code; 958 + format.width = -1; 959 + format.height = -1; 960 + csi2_try_format(csi2, fh, fse->pad, &format, V4L2_SUBDEV_FORMAT_TRY); 961 + fse->max_width = format.width; 962 + fse->max_height = format.height; 963 + 964 + return 0; 965 + } 966 + 967 + /* 968 + * csi2_get_format - Handle get format by pads subdev method 969 + * @sd : pointer to v4l2 subdev structure 970 + * @fh : V4L2 subdev file handle 971 + * @fmt: pointer to v4l2 subdev format structure 972 + * return -EINVAL or zero on sucess 973 + */ 974 + static int csi2_get_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, 975 + struct v4l2_subdev_format *fmt) 976 + { 977 + struct isp_csi2_device *csi2 = v4l2_get_subdevdata(sd); 978 + struct v4l2_mbus_framefmt *format; 979 + 980 + format = __csi2_get_format(csi2, fh, fmt->pad, fmt->which); 981 + if (format == NULL) 982 + return -EINVAL; 983 + 984 + fmt->format = *format; 985 + return 0; 986 + } 987 + 988 + /* 989 + * csi2_set_format - Handle set format by pads subdev method 990 + * @sd : pointer to v4l2 subdev structure 991 + * @fh : V4L2 subdev file handle 992 + * @fmt: pointer to v4l2 subdev format structure 993 + * return -EINVAL or zero on success 994 + */ 995 + static int csi2_set_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, 996 + struct v4l2_subdev_format *fmt) 997 + { 998 + struct isp_csi2_device *csi2 = v4l2_get_subdevdata(sd); 999 + struct v4l2_mbus_framefmt *format; 1000 + 1001 + format = __csi2_get_format(csi2, fh, fmt->pad, fmt->which); 1002 + if (format == NULL) 1003 + return -EINVAL; 1004 + 1005 + csi2_try_format(csi2, fh, fmt->pad, &fmt->format, fmt->which); 1006 + *format = fmt->format; 1007 + 1008 + /* Propagate the format from sink to source */ 1009 + if (fmt->pad == CSI2_PAD_SINK) { 1010 + format = __csi2_get_format(csi2, fh, CSI2_PAD_SOURCE, 1011 + fmt->which); 1012 + *format = fmt->format; 1013 + csi2_try_format(csi2, fh, CSI2_PAD_SOURCE, format, fmt->which); 1014 + } 1015 + 1016 + return 0; 1017 + } 1018 + 1019 + /* 1020 + * csi2_init_formats - Initialize formats on all pads 1021 + * @sd: ISP CSI2 V4L2 subdevice 1022 + * @fh: V4L2 subdev file handle 1023 + * 1024 + * Initialize all pad formats with default values. If fh is not NULL, try 1025 + * formats are initialized on the file handle. Otherwise active formats are 1026 + * initialized on the device. 1027 + */ 1028 + static int csi2_init_formats(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) 1029 + { 1030 + struct v4l2_subdev_format format; 1031 + 1032 + memset(&format, 0, sizeof(format)); 1033 + format.pad = CSI2_PAD_SINK; 1034 + format.which = fh ? V4L2_SUBDEV_FORMAT_TRY : V4L2_SUBDEV_FORMAT_ACTIVE; 1035 + format.format.code = V4L2_MBUS_FMT_SGRBG10_1X10; 1036 + format.format.width = 4096; 1037 + format.format.height = 4096; 1038 + csi2_set_format(sd, fh, &format); 1039 + 1040 + return 0; 1041 + } 1042 + 1043 + /* 1044 + * csi2_set_stream - Enable/Disable streaming on the CSI2 module 1045 + * @sd: ISP CSI2 V4L2 subdevice 1046 + * @enable: ISP pipeline stream state 1047 + * 1048 + * Return 0 on success or a negative error code otherwise. 1049 + */ 1050 + static int csi2_set_stream(struct v4l2_subdev *sd, int enable) 1051 + { 1052 + struct isp_csi2_device *csi2 = v4l2_get_subdevdata(sd); 1053 + struct isp_device *isp = csi2->isp; 1054 + struct isp_pipeline *pipe = to_isp_pipeline(&csi2->subdev.entity); 1055 + struct isp_video *video_out = &csi2->video_out; 1056 + 1057 + switch (enable) { 1058 + case ISP_PIPELINE_STREAM_CONTINUOUS: 1059 + if (omap3isp_csiphy_acquire(csi2->phy) < 0) 1060 + return -ENODEV; 1061 + csi2->use_fs_irq = pipe->do_propagation; 1062 + if (csi2->output & CSI2_OUTPUT_MEMORY) 1063 + omap3isp_sbl_enable(isp, OMAP3_ISP_SBL_CSI2A_WRITE); 1064 + csi2_configure(csi2); 1065 + csi2_print_status(csi2); 1066 + 1067 + /* 1068 + * When outputting to memory with no buffer available, let the 1069 + * buffer queue handler start the hardware. A DMA queue flag 1070 + * ISP_VIDEO_DMAQUEUE_QUEUED will be set as soon as there is 1071 + * a buffer available. 1072 + */ 1073 + if (csi2->output & CSI2_OUTPUT_MEMORY && 1074 + !(video_out->dmaqueue_flags & ISP_VIDEO_DMAQUEUE_QUEUED)) 1075 + break; 1076 + /* Enable context 0 and IRQs */ 1077 + atomic_set(&csi2->stopping, 0); 1078 + csi2_ctx_enable(isp, csi2, 0, 1); 1079 + csi2_if_enable(isp, csi2, 1); 1080 + isp_video_dmaqueue_flags_clr(video_out); 1081 + break; 1082 + 1083 + case ISP_PIPELINE_STREAM_STOPPED: 1084 + if (csi2->state == ISP_PIPELINE_STREAM_STOPPED) 1085 + return 0; 1086 + if (omap3isp_module_sync_idle(&sd->entity, &csi2->wait, 1087 + &csi2->stopping)) 1088 + dev_dbg(isp->dev, "%s: module stop timeout.\n", 1089 + sd->name); 1090 + csi2_ctx_enable(isp, csi2, 0, 0); 1091 + csi2_if_enable(isp, csi2, 0); 1092 + csi2_irq_ctx_set(isp, csi2, 0); 1093 + omap3isp_csiphy_release(csi2->phy); 1094 + isp_video_dmaqueue_flags_clr(video_out); 1095 + omap3isp_sbl_disable(isp, OMAP3_ISP_SBL_CSI2A_WRITE); 1096 + break; 1097 + } 1098 + 1099 + csi2->state = enable; 1100 + return 0; 1101 + } 1102 + 1103 + /* subdev video operations */ 1104 + static const struct v4l2_subdev_video_ops csi2_video_ops = { 1105 + .s_stream = csi2_set_stream, 1106 + }; 1107 + 1108 + /* subdev pad operations */ 1109 + static const struct v4l2_subdev_pad_ops csi2_pad_ops = { 1110 + .enum_mbus_code = csi2_enum_mbus_code, 1111 + .enum_frame_size = csi2_enum_frame_size, 1112 + .get_fmt = csi2_get_format, 1113 + .set_fmt = csi2_set_format, 1114 + }; 1115 + 1116 + /* subdev operations */ 1117 + static const struct v4l2_subdev_ops csi2_ops = { 1118 + .video = &csi2_video_ops, 1119 + .pad = &csi2_pad_ops, 1120 + }; 1121 + 1122 + /* subdev internal operations */ 1123 + static const struct v4l2_subdev_internal_ops csi2_internal_ops = { 1124 + .open = csi2_init_formats, 1125 + }; 1126 + 1127 + /* ----------------------------------------------------------------------------- 1128 + * Media entity operations 1129 + */ 1130 + 1131 + /* 1132 + * csi2_link_setup - Setup CSI2 connections. 1133 + * @entity : Pointer to media entity structure 1134 + * @local : Pointer to local pad array 1135 + * @remote : Pointer to remote pad array 1136 + * @flags : Link flags 1137 + * return -EINVAL or zero on success 1138 + */ 1139 + static int csi2_link_setup(struct media_entity *entity, 1140 + const struct media_pad *local, 1141 + const struct media_pad *remote, u32 flags) 1142 + { 1143 + struct v4l2_subdev *sd = media_entity_to_v4l2_subdev(entity); 1144 + struct isp_csi2_device *csi2 = v4l2_get_subdevdata(sd); 1145 + struct isp_csi2_ctrl_cfg *ctrl = &csi2->ctrl; 1146 + 1147 + /* 1148 + * The ISP core doesn't support pipelines with multiple video outputs. 1149 + * Revisit this when it will be implemented, and return -EBUSY for now. 1150 + */ 1151 + 1152 + switch (local->index | media_entity_type(remote->entity)) { 1153 + case CSI2_PAD_SOURCE | MEDIA_ENT_T_DEVNODE: 1154 + if (flags & MEDIA_LNK_FL_ENABLED) { 1155 + if (csi2->output & ~CSI2_OUTPUT_MEMORY) 1156 + return -EBUSY; 1157 + csi2->output |= CSI2_OUTPUT_MEMORY; 1158 + } else { 1159 + csi2->output &= ~CSI2_OUTPUT_MEMORY; 1160 + } 1161 + break; 1162 + 1163 + case CSI2_PAD_SOURCE | MEDIA_ENT_T_V4L2_SUBDEV: 1164 + if (flags & MEDIA_LNK_FL_ENABLED) { 1165 + if (csi2->output & ~CSI2_OUTPUT_CCDC) 1166 + return -EBUSY; 1167 + csi2->output |= CSI2_OUTPUT_CCDC; 1168 + } else { 1169 + csi2->output &= ~CSI2_OUTPUT_CCDC; 1170 + } 1171 + break; 1172 + 1173 + default: 1174 + /* Link from camera to CSI2 is fixed... */ 1175 + return -EINVAL; 1176 + } 1177 + 1178 + ctrl->vp_only_enable = 1179 + (csi2->output & CSI2_OUTPUT_MEMORY) ? false : true; 1180 + ctrl->vp_clk_enable = !!(csi2->output & CSI2_OUTPUT_CCDC); 1181 + 1182 + return 0; 1183 + } 1184 + 1185 + /* media operations */ 1186 + static const struct media_entity_operations csi2_media_ops = { 1187 + .link_setup = csi2_link_setup, 1188 + }; 1189 + 1190 + /* 1191 + * csi2_init_entities - Initialize subdev and media entity. 1192 + * @csi2: Pointer to csi2 structure. 1193 + * return -ENOMEM or zero on success 1194 + */ 1195 + static int csi2_init_entities(struct isp_csi2_device *csi2) 1196 + { 1197 + struct v4l2_subdev *sd = &csi2->subdev; 1198 + struct media_pad *pads = csi2->pads; 1199 + struct media_entity *me = &sd->entity; 1200 + int ret; 1201 + 1202 + v4l2_subdev_init(sd, &csi2_ops); 1203 + sd->internal_ops = &csi2_internal_ops; 1204 + strlcpy(sd->name, "OMAP3 ISP CSI2a", sizeof(sd->name)); 1205 + 1206 + sd->grp_id = 1 << 16; /* group ID for isp subdevs */ 1207 + v4l2_set_subdevdata(sd, csi2); 1208 + sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; 1209 + 1210 + pads[CSI2_PAD_SOURCE].flags = MEDIA_PAD_FL_SOURCE; 1211 + pads[CSI2_PAD_SINK].flags = MEDIA_PAD_FL_SINK; 1212 + 1213 + me->ops = &csi2_media_ops; 1214 + ret = media_entity_init(me, CSI2_PADS_NUM, pads, 0); 1215 + if (ret < 0) 1216 + return ret; 1217 + 1218 + csi2_init_formats(sd, NULL); 1219 + 1220 + /* Video device node */ 1221 + csi2->video_out.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 1222 + csi2->video_out.ops = &csi2_ispvideo_ops; 1223 + csi2->video_out.bpl_alignment = 32; 1224 + csi2->video_out.bpl_zero_padding = 1; 1225 + csi2->video_out.bpl_max = 0x1ffe0; 1226 + csi2->video_out.isp = csi2->isp; 1227 + csi2->video_out.capture_mem = PAGE_ALIGN(4096 * 4096) * 3; 1228 + 1229 + ret = omap3isp_video_init(&csi2->video_out, "CSI2a"); 1230 + if (ret < 0) 1231 + return ret; 1232 + 1233 + /* Connect the CSI2 subdev to the video node. */ 1234 + ret = media_entity_create_link(&csi2->subdev.entity, CSI2_PAD_SOURCE, 1235 + &csi2->video_out.video.entity, 0, 0); 1236 + if (ret < 0) 1237 + return ret; 1238 + 1239 + return 0; 1240 + } 1241 + 1242 + void omap3isp_csi2_unregister_entities(struct isp_csi2_device *csi2) 1243 + { 1244 + media_entity_cleanup(&csi2->subdev.entity); 1245 + 1246 + v4l2_device_unregister_subdev(&csi2->subdev); 1247 + omap3isp_video_unregister(&csi2->video_out); 1248 + } 1249 + 1250 + int omap3isp_csi2_register_entities(struct isp_csi2_device *csi2, 1251 + struct v4l2_device *vdev) 1252 + { 1253 + int ret; 1254 + 1255 + /* Register the subdev and video nodes. */ 1256 + ret = v4l2_device_register_subdev(vdev, &csi2->subdev); 1257 + if (ret < 0) 1258 + goto error; 1259 + 1260 + ret = omap3isp_video_register(&csi2->video_out, vdev); 1261 + if (ret < 0) 1262 + goto error; 1263 + 1264 + return 0; 1265 + 1266 + error: 1267 + omap3isp_csi2_unregister_entities(csi2); 1268 + return ret; 1269 + } 1270 + 1271 + /* ----------------------------------------------------------------------------- 1272 + * ISP CSI2 initialisation and cleanup 1273 + */ 1274 + 1275 + /* 1276 + * omap3isp_csi2_cleanup - Routine for module driver cleanup 1277 + */ 1278 + void omap3isp_csi2_cleanup(struct isp_device *isp) 1279 + { 1280 + } 1281 + 1282 + /* 1283 + * omap3isp_csi2_init - Routine for module driver init 1284 + */ 1285 + int omap3isp_csi2_init(struct isp_device *isp) 1286 + { 1287 + struct isp_csi2_device *csi2a = &isp->isp_csi2a; 1288 + struct isp_csi2_device *csi2c = &isp->isp_csi2c; 1289 + int ret; 1290 + 1291 + csi2a->isp = isp; 1292 + csi2a->available = 1; 1293 + csi2a->regs1 = OMAP3_ISP_IOMEM_CSI2A_REGS1; 1294 + csi2a->regs2 = OMAP3_ISP_IOMEM_CSI2A_REGS2; 1295 + csi2a->phy = &isp->isp_csiphy2; 1296 + csi2a->state = ISP_PIPELINE_STREAM_STOPPED; 1297 + init_waitqueue_head(&csi2a->wait); 1298 + 1299 + ret = csi2_init_entities(csi2a); 1300 + if (ret < 0) 1301 + goto fail; 1302 + 1303 + if (isp->revision == ISP_REVISION_15_0) { 1304 + csi2c->isp = isp; 1305 + csi2c->available = 1; 1306 + csi2c->regs1 = OMAP3_ISP_IOMEM_CSI2C_REGS1; 1307 + csi2c->regs2 = OMAP3_ISP_IOMEM_CSI2C_REGS2; 1308 + csi2c->phy = &isp->isp_csiphy1; 1309 + csi2c->state = ISP_PIPELINE_STREAM_STOPPED; 1310 + init_waitqueue_head(&csi2c->wait); 1311 + } 1312 + 1313 + return 0; 1314 + fail: 1315 + omap3isp_csi2_cleanup(isp); 1316 + return ret; 1317 + }
+166
drivers/media/video/omap3isp/ispcsi2.h
··· 1 + /* 2 + * ispcsi2.h 3 + * 4 + * TI OMAP3 ISP - CSI2 module 5 + * 6 + * Copyright (C) 2010 Nokia Corporation 7 + * Copyright (C) 2009 Texas Instruments, Inc. 8 + * 9 + * Contacts: Laurent Pinchart <laurent.pinchart@ideasonboard.com> 10 + * Sakari Ailus <sakari.ailus@iki.fi> 11 + * 12 + * This program is free software; you can redistribute it and/or modify 13 + * it under the terms of the GNU General Public License version 2 as 14 + * published by the Free Software Foundation. 15 + * 16 + * This program is distributed in the hope that it will be useful, but 17 + * WITHOUT ANY WARRANTY; without even the implied warranty of 18 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 19 + * General Public License for more details. 20 + * 21 + * You should have received a copy of the GNU General Public License 22 + * along with this program; if not, write to the Free Software 23 + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 24 + * 02110-1301 USA 25 + */ 26 + 27 + #ifndef OMAP3_ISP_CSI2_H 28 + #define OMAP3_ISP_CSI2_H 29 + 30 + #include <linux/types.h> 31 + #include <linux/videodev2.h> 32 + 33 + struct isp_csiphy; 34 + 35 + /* This is not an exhaustive list */ 36 + enum isp_csi2_pix_formats { 37 + CSI2_PIX_FMT_OTHERS = 0, 38 + CSI2_PIX_FMT_YUV422_8BIT = 0x1e, 39 + CSI2_PIX_FMT_YUV422_8BIT_VP = 0x9e, 40 + CSI2_PIX_FMT_RAW10_EXP16 = 0xab, 41 + CSI2_PIX_FMT_RAW10_EXP16_VP = 0x12f, 42 + CSI2_PIX_FMT_RAW8 = 0x2a, 43 + CSI2_PIX_FMT_RAW8_DPCM10_EXP16 = 0x2aa, 44 + CSI2_PIX_FMT_RAW8_DPCM10_VP = 0x32a, 45 + CSI2_PIX_FMT_RAW8_VP = 0x12a, 46 + CSI2_USERDEF_8BIT_DATA1_DPCM10_VP = 0x340, 47 + CSI2_USERDEF_8BIT_DATA1_DPCM10 = 0x2c0, 48 + CSI2_USERDEF_8BIT_DATA1 = 0x40, 49 + }; 50 + 51 + enum isp_csi2_irqevents { 52 + OCP_ERR_IRQ = 0x4000, 53 + SHORT_PACKET_IRQ = 0x2000, 54 + ECC_CORRECTION_IRQ = 0x1000, 55 + ECC_NO_CORRECTION_IRQ = 0x800, 56 + COMPLEXIO2_ERR_IRQ = 0x400, 57 + COMPLEXIO1_ERR_IRQ = 0x200, 58 + FIFO_OVF_IRQ = 0x100, 59 + CONTEXT7 = 0x80, 60 + CONTEXT6 = 0x40, 61 + CONTEXT5 = 0x20, 62 + CONTEXT4 = 0x10, 63 + CONTEXT3 = 0x8, 64 + CONTEXT2 = 0x4, 65 + CONTEXT1 = 0x2, 66 + CONTEXT0 = 0x1, 67 + }; 68 + 69 + enum isp_csi2_ctx_irqevents { 70 + CTX_ECC_CORRECTION = 0x100, 71 + CTX_LINE_NUMBER = 0x80, 72 + CTX_FRAME_NUMBER = 0x40, 73 + CTX_CS = 0x20, 74 + CTX_LE = 0x8, 75 + CTX_LS = 0x4, 76 + CTX_FE = 0x2, 77 + CTX_FS = 0x1, 78 + }; 79 + 80 + enum isp_csi2_frame_mode { 81 + ISP_CSI2_FRAME_IMMEDIATE, 82 + ISP_CSI2_FRAME_AFTERFEC, 83 + }; 84 + 85 + #define ISP_CSI2_MAX_CTX_NUM 7 86 + 87 + struct isp_csi2_ctx_cfg { 88 + u8 ctxnum; /* context number 0 - 7 */ 89 + u8 dpcm_decompress; 90 + 91 + /* Fields in CSI2_CTx_CTRL2 - locked by CSI2_CTx_CTRL1.CTX_EN */ 92 + u8 virtual_id; 93 + u16 format_id; /* as in CSI2_CTx_CTRL2[9:0] */ 94 + u8 dpcm_predictor; /* 1: simple, 0: advanced */ 95 + 96 + /* Fields in CSI2_CTx_CTRL1/3 - Shadowed */ 97 + u16 alpha; 98 + u16 data_offset; 99 + u32 ping_addr; 100 + u32 pong_addr; 101 + u8 eof_enabled; 102 + u8 eol_enabled; 103 + u8 checksum_enabled; 104 + u8 enabled; 105 + }; 106 + 107 + struct isp_csi2_timing_cfg { 108 + u8 ionum; /* IO1 or IO2 as in CSI2_TIMING */ 109 + unsigned force_rx_mode:1; 110 + unsigned stop_state_16x:1; 111 + unsigned stop_state_4x:1; 112 + u16 stop_state_counter; 113 + }; 114 + 115 + struct isp_csi2_ctrl_cfg { 116 + bool vp_clk_enable; 117 + bool vp_only_enable; 118 + u8 vp_out_ctrl; 119 + enum isp_csi2_frame_mode frame_mode; 120 + bool ecc_enable; 121 + bool if_enable; 122 + }; 123 + 124 + #define CSI2_PAD_SINK 0 125 + #define CSI2_PAD_SOURCE 1 126 + #define CSI2_PADS_NUM 2 127 + 128 + #define CSI2_OUTPUT_CCDC (1 << 0) 129 + #define CSI2_OUTPUT_MEMORY (1 << 1) 130 + 131 + struct isp_csi2_device { 132 + struct v4l2_subdev subdev; 133 + struct media_pad pads[CSI2_PADS_NUM]; 134 + struct v4l2_mbus_framefmt formats[CSI2_PADS_NUM]; 135 + 136 + struct isp_video video_out; 137 + struct isp_device *isp; 138 + 139 + u8 available; /* Is the IP present on the silicon? */ 140 + 141 + /* mem resources - enums as defined in enum isp_mem_resources */ 142 + u8 regs1; 143 + u8 regs2; 144 + 145 + u32 output; /* output to CCDC, memory or both? */ 146 + bool dpcm_decompress; 147 + unsigned int frame_skip; 148 + bool use_fs_irq; 149 + 150 + struct isp_csiphy *phy; 151 + struct isp_csi2_ctx_cfg contexts[ISP_CSI2_MAX_CTX_NUM + 1]; 152 + struct isp_csi2_timing_cfg timing[2]; 153 + struct isp_csi2_ctrl_cfg ctrl; 154 + enum isp_pipeline_stream_state state; 155 + wait_queue_head_t wait; 156 + atomic_t stopping; 157 + }; 158 + 159 + int omap3isp_csi2_isr(struct isp_csi2_device *csi2); 160 + int omap3isp_csi2_reset(struct isp_csi2_device *csi2); 161 + int omap3isp_csi2_init(struct isp_device *isp); 162 + void omap3isp_csi2_cleanup(struct isp_device *isp); 163 + void omap3isp_csi2_unregister_entities(struct isp_csi2_device *csi2); 164 + int omap3isp_csi2_register_entities(struct isp_csi2_device *csi2, 165 + struct v4l2_device *vdev); 166 + #endif /* OMAP3_ISP_CSI2_H */
+247
drivers/media/video/omap3isp/ispcsiphy.c
··· 1 + /* 2 + * ispcsiphy.c 3 + * 4 + * TI OMAP3 ISP - CSI PHY module 5 + * 6 + * Copyright (C) 2010 Nokia Corporation 7 + * Copyright (C) 2009 Texas Instruments, Inc. 8 + * 9 + * Contacts: Laurent Pinchart <laurent.pinchart@ideasonboard.com> 10 + * Sakari Ailus <sakari.ailus@iki.fi> 11 + * 12 + * This program is free software; you can redistribute it and/or modify 13 + * it under the terms of the GNU General Public License version 2 as 14 + * published by the Free Software Foundation. 15 + * 16 + * This program is distributed in the hope that it will be useful, but 17 + * WITHOUT ANY WARRANTY; without even the implied warranty of 18 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 19 + * General Public License for more details. 20 + * 21 + * You should have received a copy of the GNU General Public License 22 + * along with this program; if not, write to the Free Software 23 + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 24 + * 02110-1301 USA 25 + */ 26 + 27 + #include <linux/delay.h> 28 + #include <linux/device.h> 29 + #include <linux/regulator/consumer.h> 30 + 31 + #include "isp.h" 32 + #include "ispreg.h" 33 + #include "ispcsiphy.h" 34 + 35 + /* 36 + * csiphy_lanes_config - Configuration of CSIPHY lanes. 37 + * 38 + * Updates HW configuration. 39 + * Called with phy->mutex taken. 40 + */ 41 + static void csiphy_lanes_config(struct isp_csiphy *phy) 42 + { 43 + unsigned int i; 44 + u32 reg; 45 + 46 + reg = isp_reg_readl(phy->isp, phy->cfg_regs, ISPCSI2_PHY_CFG); 47 + 48 + for (i = 0; i < phy->num_data_lanes; i++) { 49 + reg &= ~(ISPCSI2_PHY_CFG_DATA_POL_MASK(i + 1) | 50 + ISPCSI2_PHY_CFG_DATA_POSITION_MASK(i + 1)); 51 + reg |= (phy->lanes.data[i].pol << 52 + ISPCSI2_PHY_CFG_DATA_POL_SHIFT(i + 1)); 53 + reg |= (phy->lanes.data[i].pos << 54 + ISPCSI2_PHY_CFG_DATA_POSITION_SHIFT(i + 1)); 55 + } 56 + 57 + reg &= ~(ISPCSI2_PHY_CFG_CLOCK_POL_MASK | 58 + ISPCSI2_PHY_CFG_CLOCK_POSITION_MASK); 59 + reg |= phy->lanes.clk.pol << ISPCSI2_PHY_CFG_CLOCK_POL_SHIFT; 60 + reg |= phy->lanes.clk.pos << ISPCSI2_PHY_CFG_CLOCK_POSITION_SHIFT; 61 + 62 + isp_reg_writel(phy->isp, reg, phy->cfg_regs, ISPCSI2_PHY_CFG); 63 + } 64 + 65 + /* 66 + * csiphy_power_autoswitch_enable 67 + * @enable: Sets or clears the autoswitch function enable flag. 68 + */ 69 + static void csiphy_power_autoswitch_enable(struct isp_csiphy *phy, bool enable) 70 + { 71 + isp_reg_clr_set(phy->isp, phy->cfg_regs, ISPCSI2_PHY_CFG, 72 + ISPCSI2_PHY_CFG_PWR_AUTO, 73 + enable ? ISPCSI2_PHY_CFG_PWR_AUTO : 0); 74 + } 75 + 76 + /* 77 + * csiphy_set_power 78 + * @power: Power state to be set. 79 + * 80 + * Returns 0 if successful, or -EBUSY if the retry count is exceeded. 81 + */ 82 + static int csiphy_set_power(struct isp_csiphy *phy, u32 power) 83 + { 84 + u32 reg; 85 + u8 retry_count; 86 + 87 + isp_reg_clr_set(phy->isp, phy->cfg_regs, ISPCSI2_PHY_CFG, 88 + ISPCSI2_PHY_CFG_PWR_CMD_MASK, power); 89 + 90 + retry_count = 0; 91 + do { 92 + udelay(50); 93 + reg = isp_reg_readl(phy->isp, phy->cfg_regs, ISPCSI2_PHY_CFG) & 94 + ISPCSI2_PHY_CFG_PWR_STATUS_MASK; 95 + 96 + if (reg != power >> 2) 97 + retry_count++; 98 + 99 + } while ((reg != power >> 2) && (retry_count < 100)); 100 + 101 + if (retry_count == 100) { 102 + printk(KERN_ERR "CSI2 CIO set power failed!\n"); 103 + return -EBUSY; 104 + } 105 + 106 + return 0; 107 + } 108 + 109 + /* 110 + * csiphy_dphy_config - Configure CSI2 D-PHY parameters. 111 + * 112 + * Called with phy->mutex taken. 113 + */ 114 + static void csiphy_dphy_config(struct isp_csiphy *phy) 115 + { 116 + u32 reg; 117 + 118 + /* Set up ISPCSIPHY_REG0 */ 119 + reg = isp_reg_readl(phy->isp, phy->phy_regs, ISPCSIPHY_REG0); 120 + 121 + reg &= ~(ISPCSIPHY_REG0_THS_TERM_MASK | 122 + ISPCSIPHY_REG0_THS_SETTLE_MASK); 123 + reg |= phy->dphy.ths_term << ISPCSIPHY_REG0_THS_TERM_SHIFT; 124 + reg |= phy->dphy.ths_settle << ISPCSIPHY_REG0_THS_SETTLE_SHIFT; 125 + 126 + isp_reg_writel(phy->isp, reg, phy->phy_regs, ISPCSIPHY_REG0); 127 + 128 + /* Set up ISPCSIPHY_REG1 */ 129 + reg = isp_reg_readl(phy->isp, phy->phy_regs, ISPCSIPHY_REG1); 130 + 131 + reg &= ~(ISPCSIPHY_REG1_TCLK_TERM_MASK | 132 + ISPCSIPHY_REG1_TCLK_MISS_MASK | 133 + ISPCSIPHY_REG1_TCLK_SETTLE_MASK); 134 + reg |= phy->dphy.tclk_term << ISPCSIPHY_REG1_TCLK_TERM_SHIFT; 135 + reg |= phy->dphy.tclk_miss << ISPCSIPHY_REG1_TCLK_MISS_SHIFT; 136 + reg |= phy->dphy.tclk_settle << ISPCSIPHY_REG1_TCLK_SETTLE_SHIFT; 137 + 138 + isp_reg_writel(phy->isp, reg, phy->phy_regs, ISPCSIPHY_REG1); 139 + } 140 + 141 + static int csiphy_config(struct isp_csiphy *phy, 142 + struct isp_csiphy_dphy_cfg *dphy, 143 + struct isp_csiphy_lanes_cfg *lanes) 144 + { 145 + unsigned int used_lanes = 0; 146 + unsigned int i; 147 + 148 + /* Clock and data lanes verification */ 149 + for (i = 0; i < phy->num_data_lanes; i++) { 150 + if (lanes->data[i].pol > 1 || lanes->data[i].pos > 3) 151 + return -EINVAL; 152 + 153 + if (used_lanes & (1 << lanes->data[i].pos)) 154 + return -EINVAL; 155 + 156 + used_lanes |= 1 << lanes->data[i].pos; 157 + } 158 + 159 + if (lanes->clk.pol > 1 || lanes->clk.pos > 3) 160 + return -EINVAL; 161 + 162 + if (lanes->clk.pos == 0 || used_lanes & (1 << lanes->clk.pos)) 163 + return -EINVAL; 164 + 165 + mutex_lock(&phy->mutex); 166 + phy->dphy = *dphy; 167 + phy->lanes = *lanes; 168 + mutex_unlock(&phy->mutex); 169 + 170 + return 0; 171 + } 172 + 173 + int omap3isp_csiphy_acquire(struct isp_csiphy *phy) 174 + { 175 + int rval; 176 + 177 + if (phy->vdd == NULL) { 178 + dev_err(phy->isp->dev, "Power regulator for CSI PHY not " 179 + "available\n"); 180 + return -ENODEV; 181 + } 182 + 183 + mutex_lock(&phy->mutex); 184 + 185 + rval = regulator_enable(phy->vdd); 186 + if (rval < 0) 187 + goto done; 188 + 189 + omap3isp_csi2_reset(phy->csi2); 190 + 191 + csiphy_dphy_config(phy); 192 + csiphy_lanes_config(phy); 193 + 194 + rval = csiphy_set_power(phy, ISPCSI2_PHY_CFG_PWR_CMD_ON); 195 + if (rval) { 196 + regulator_disable(phy->vdd); 197 + goto done; 198 + } 199 + 200 + csiphy_power_autoswitch_enable(phy, true); 201 + phy->phy_in_use = 1; 202 + 203 + done: 204 + mutex_unlock(&phy->mutex); 205 + return rval; 206 + } 207 + 208 + void omap3isp_csiphy_release(struct isp_csiphy *phy) 209 + { 210 + mutex_lock(&phy->mutex); 211 + if (phy->phy_in_use) { 212 + csiphy_power_autoswitch_enable(phy, false); 213 + csiphy_set_power(phy, ISPCSI2_PHY_CFG_PWR_CMD_OFF); 214 + regulator_disable(phy->vdd); 215 + phy->phy_in_use = 0; 216 + } 217 + mutex_unlock(&phy->mutex); 218 + } 219 + 220 + /* 221 + * omap3isp_csiphy_init - Initialize the CSI PHY frontends 222 + */ 223 + int omap3isp_csiphy_init(struct isp_device *isp) 224 + { 225 + struct isp_csiphy *phy1 = &isp->isp_csiphy1; 226 + struct isp_csiphy *phy2 = &isp->isp_csiphy2; 227 + 228 + isp->platform_cb.csiphy_config = csiphy_config; 229 + 230 + phy2->isp = isp; 231 + phy2->csi2 = &isp->isp_csi2a; 232 + phy2->num_data_lanes = ISP_CSIPHY2_NUM_DATA_LANES; 233 + phy2->cfg_regs = OMAP3_ISP_IOMEM_CSI2A_REGS1; 234 + phy2->phy_regs = OMAP3_ISP_IOMEM_CSIPHY2; 235 + mutex_init(&phy2->mutex); 236 + 237 + if (isp->revision == ISP_REVISION_15_0) { 238 + phy1->isp = isp; 239 + phy1->csi2 = &isp->isp_csi2c; 240 + phy1->num_data_lanes = ISP_CSIPHY1_NUM_DATA_LANES; 241 + phy1->cfg_regs = OMAP3_ISP_IOMEM_CSI2C_REGS1; 242 + phy1->phy_regs = OMAP3_ISP_IOMEM_CSIPHY1; 243 + mutex_init(&phy1->mutex); 244 + } 245 + 246 + return 0; 247 + }
+74
drivers/media/video/omap3isp/ispcsiphy.h
··· 1 + /* 2 + * ispcsiphy.h 3 + * 4 + * TI OMAP3 ISP - CSI PHY module 5 + * 6 + * Copyright (C) 2010 Nokia Corporation 7 + * Copyright (C) 2009 Texas Instruments, Inc. 8 + * 9 + * Contacts: Laurent Pinchart <laurent.pinchart@ideasonboard.com> 10 + * Sakari Ailus <sakari.ailus@iki.fi> 11 + * 12 + * This program is free software; you can redistribute it and/or modify 13 + * it under the terms of the GNU General Public License version 2 as 14 + * published by the Free Software Foundation. 15 + * 16 + * This program is distributed in the hope that it will be useful, but 17 + * WITHOUT ANY WARRANTY; without even the implied warranty of 18 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 19 + * General Public License for more details. 20 + * 21 + * You should have received a copy of the GNU General Public License 22 + * along with this program; if not, write to the Free Software 23 + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 24 + * 02110-1301 USA 25 + */ 26 + 27 + #ifndef OMAP3_ISP_CSI_PHY_H 28 + #define OMAP3_ISP_CSI_PHY_H 29 + 30 + struct isp_csi2_device; 31 + struct regulator; 32 + 33 + struct csiphy_lane { 34 + u8 pos; 35 + u8 pol; 36 + }; 37 + 38 + #define ISP_CSIPHY2_NUM_DATA_LANES 2 39 + #define ISP_CSIPHY1_NUM_DATA_LANES 1 40 + 41 + struct isp_csiphy_lanes_cfg { 42 + struct csiphy_lane data[ISP_CSIPHY2_NUM_DATA_LANES]; 43 + struct csiphy_lane clk; 44 + }; 45 + 46 + struct isp_csiphy_dphy_cfg { 47 + u8 ths_term; 48 + u8 ths_settle; 49 + u8 tclk_term; 50 + unsigned tclk_miss:1; 51 + u8 tclk_settle; 52 + }; 53 + 54 + struct isp_csiphy { 55 + struct isp_device *isp; 56 + struct mutex mutex; /* serialize csiphy configuration */ 57 + u8 phy_in_use; 58 + struct isp_csi2_device *csi2; 59 + struct regulator *vdd; 60 + 61 + /* mem resources - enums as defined in enum isp_mem_resources */ 62 + unsigned int cfg_regs; 63 + unsigned int phy_regs; 64 + 65 + u8 num_data_lanes; /* number of CSI2 Data Lanes supported */ 66 + struct isp_csiphy_lanes_cfg lanes; 67 + struct isp_csiphy_dphy_cfg dphy; 68 + }; 69 + 70 + int omap3isp_csiphy_acquire(struct isp_csiphy *phy); 71 + void omap3isp_csiphy_release(struct isp_csiphy *phy); 72 + int omap3isp_csiphy_init(struct isp_device *isp); 73 + 74 + #endif /* OMAP3_ISP_CSI_PHY_H */