2770 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * ispccdc.c4 *5 * TI OMAP3 ISP - CCDC module6 *7 * Copyright (C) 2009-2010 Nokia Corporation8 * Copyright (C) 2009 Texas Instruments, Inc.9 *10 * Contacts: Laurent Pinchart <laurent.pinchart@ideasonboard.com>11 * Sakari Ailus <sakari.ailus@iki.fi>12 */13 14#include <linux/module.h>15#include <linux/uaccess.h>16#include <linux/delay.h>17#include <linux/device.h>18#include <linux/dma-mapping.h>19#include <linux/mm.h>20#include <linux/sched.h>21#include <linux/slab.h>22#include <media/v4l2-event.h>23 24#include "isp.h"25#include "ispreg.h"26#include "ispccdc.h"27 28#define CCDC_MIN_WIDTH 3229#define CCDC_MIN_HEIGHT 3230 31static struct v4l2_mbus_framefmt *32__ccdc_get_format(struct isp_ccdc_device *ccdc,33 struct v4l2_subdev_state *sd_state,34 unsigned int pad, enum v4l2_subdev_format_whence which);35 36static const unsigned int ccdc_fmts[] = {37 MEDIA_BUS_FMT_Y8_1X8,38 MEDIA_BUS_FMT_Y10_1X10,39 MEDIA_BUS_FMT_Y12_1X12,40 MEDIA_BUS_FMT_SGRBG8_1X8,41 MEDIA_BUS_FMT_SRGGB8_1X8,42 MEDIA_BUS_FMT_SBGGR8_1X8,43 MEDIA_BUS_FMT_SGBRG8_1X8,44 MEDIA_BUS_FMT_SGRBG10_1X10,45 MEDIA_BUS_FMT_SRGGB10_1X10,46 MEDIA_BUS_FMT_SBGGR10_1X10,47 MEDIA_BUS_FMT_SGBRG10_1X10,48 MEDIA_BUS_FMT_SGRBG12_1X12,49 MEDIA_BUS_FMT_SRGGB12_1X12,50 MEDIA_BUS_FMT_SBGGR12_1X12,51 MEDIA_BUS_FMT_SGBRG12_1X12,52 MEDIA_BUS_FMT_YUYV8_2X8,53 MEDIA_BUS_FMT_UYVY8_2X8,54};55 56/*57 * ccdc_print_status - Print current CCDC Module register values.58 * @ccdc: Pointer to ISP CCDC device.59 *60 * Also prints other debug information stored in the CCDC module.61 */62#define CCDC_PRINT_REGISTER(isp, name)\63 dev_dbg(isp->dev, "###CCDC " #name "=0x%08x\n", \64 isp_reg_readl(isp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_##name))65 66static void ccdc_print_status(struct isp_ccdc_device *ccdc)67{68 struct isp_device *isp = to_isp_device(ccdc);69 70 dev_dbg(isp->dev, "-------------CCDC Register dump-------------\n");71 72 CCDC_PRINT_REGISTER(isp, PCR);73 CCDC_PRINT_REGISTER(isp, SYN_MODE);74 CCDC_PRINT_REGISTER(isp, HD_VD_WID);75 CCDC_PRINT_REGISTER(isp, PIX_LINES);76 CCDC_PRINT_REGISTER(isp, HORZ_INFO);77 CCDC_PRINT_REGISTER(isp, VERT_START);78 CCDC_PRINT_REGISTER(isp, VERT_LINES);79 CCDC_PRINT_REGISTER(isp, CULLING);80 CCDC_PRINT_REGISTER(isp, HSIZE_OFF);81 CCDC_PRINT_REGISTER(isp, SDOFST);82 CCDC_PRINT_REGISTER(isp, SDR_ADDR);83 CCDC_PRINT_REGISTER(isp, CLAMP);84 CCDC_PRINT_REGISTER(isp, DCSUB);85 CCDC_PRINT_REGISTER(isp, COLPTN);86 CCDC_PRINT_REGISTER(isp, BLKCMP);87 CCDC_PRINT_REGISTER(isp, FPC);88 CCDC_PRINT_REGISTER(isp, FPC_ADDR);89 CCDC_PRINT_REGISTER(isp, VDINT);90 CCDC_PRINT_REGISTER(isp, ALAW);91 CCDC_PRINT_REGISTER(isp, REC656IF);92 CCDC_PRINT_REGISTER(isp, CFG);93 CCDC_PRINT_REGISTER(isp, FMTCFG);94 CCDC_PRINT_REGISTER(isp, FMT_HORZ);95 CCDC_PRINT_REGISTER(isp, FMT_VERT);96 CCDC_PRINT_REGISTER(isp, PRGEVEN0);97 CCDC_PRINT_REGISTER(isp, PRGEVEN1);98 CCDC_PRINT_REGISTER(isp, PRGODD0);99 CCDC_PRINT_REGISTER(isp, PRGODD1);100 CCDC_PRINT_REGISTER(isp, VP_OUT);101 CCDC_PRINT_REGISTER(isp, LSC_CONFIG);102 CCDC_PRINT_REGISTER(isp, LSC_INITIAL);103 CCDC_PRINT_REGISTER(isp, LSC_TABLE_BASE);104 CCDC_PRINT_REGISTER(isp, LSC_TABLE_OFFSET);105 106 dev_dbg(isp->dev, "--------------------------------------------\n");107}108 109/*110 * omap3isp_ccdc_busy - Get busy state of the CCDC.111 * @ccdc: Pointer to ISP CCDC device.112 */113int omap3isp_ccdc_busy(struct isp_ccdc_device *ccdc)114{115 struct isp_device *isp = to_isp_device(ccdc);116 117 return isp_reg_readl(isp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_PCR) &118 ISPCCDC_PCR_BUSY;119}120 121/* -----------------------------------------------------------------------------122 * Lens Shading Compensation123 */124 125/*126 * ccdc_lsc_validate_config - Check that LSC configuration is valid.127 * @ccdc: Pointer to ISP CCDC device.128 * @lsc_cfg: the LSC configuration to check.129 *130 * Returns 0 if the LSC configuration is valid, or -EINVAL if invalid.131 */132static int ccdc_lsc_validate_config(struct isp_ccdc_device *ccdc,133 struct omap3isp_ccdc_lsc_config *lsc_cfg)134{135 struct isp_device *isp = to_isp_device(ccdc);136 struct v4l2_mbus_framefmt *format;137 unsigned int paxel_width, paxel_height;138 unsigned int paxel_shift_x, paxel_shift_y;139 unsigned int min_width, min_height, min_size;140 unsigned int input_width, input_height;141 142 paxel_shift_x = lsc_cfg->gain_mode_m;143 paxel_shift_y = lsc_cfg->gain_mode_n;144 145 if ((paxel_shift_x < 2) || (paxel_shift_x > 6) ||146 (paxel_shift_y < 2) || (paxel_shift_y > 6)) {147 dev_dbg(isp->dev, "CCDC: LSC: Invalid paxel size\n");148 return -EINVAL;149 }150 151 if (lsc_cfg->offset & 3) {152 dev_dbg(isp->dev,153 "CCDC: LSC: Offset must be a multiple of 4\n");154 return -EINVAL;155 }156 157 if ((lsc_cfg->initial_x & 1) || (lsc_cfg->initial_y & 1)) {158 dev_dbg(isp->dev, "CCDC: LSC: initial_x and y must be even\n");159 return -EINVAL;160 }161 162 format = __ccdc_get_format(ccdc, NULL, CCDC_PAD_SINK,163 V4L2_SUBDEV_FORMAT_ACTIVE);164 input_width = format->width;165 input_height = format->height;166 167 /* Calculate minimum bytesize for validation */168 paxel_width = 1 << paxel_shift_x;169 min_width = ((input_width + lsc_cfg->initial_x + paxel_width - 1)170 >> paxel_shift_x) + 1;171 172 paxel_height = 1 << paxel_shift_y;173 min_height = ((input_height + lsc_cfg->initial_y + paxel_height - 1)174 >> paxel_shift_y) + 1;175 176 min_size = 4 * min_width * min_height;177 if (min_size > lsc_cfg->size) {178 dev_dbg(isp->dev, "CCDC: LSC: too small table\n");179 return -EINVAL;180 }181 if (lsc_cfg->offset < (min_width * 4)) {182 dev_dbg(isp->dev, "CCDC: LSC: Offset is too small\n");183 return -EINVAL;184 }185 if ((lsc_cfg->size / lsc_cfg->offset) < min_height) {186 dev_dbg(isp->dev, "CCDC: LSC: Wrong size/offset combination\n");187 return -EINVAL;188 }189 return 0;190}191 192/*193 * ccdc_lsc_program_table - Program Lens Shading Compensation table address.194 * @ccdc: Pointer to ISP CCDC device.195 */196static void ccdc_lsc_program_table(struct isp_ccdc_device *ccdc,197 dma_addr_t addr)198{199 isp_reg_writel(to_isp_device(ccdc), addr,200 OMAP3_ISP_IOMEM_CCDC, ISPCCDC_LSC_TABLE_BASE);201}202 203/*204 * ccdc_lsc_setup_regs - Configures the lens shading compensation module205 * @ccdc: Pointer to ISP CCDC device.206 */207static void ccdc_lsc_setup_regs(struct isp_ccdc_device *ccdc,208 struct omap3isp_ccdc_lsc_config *cfg)209{210 struct isp_device *isp = to_isp_device(ccdc);211 int reg;212 213 isp_reg_writel(isp, cfg->offset, OMAP3_ISP_IOMEM_CCDC,214 ISPCCDC_LSC_TABLE_OFFSET);215 216 reg = 0;217 reg |= cfg->gain_mode_n << ISPCCDC_LSC_GAIN_MODE_N_SHIFT;218 reg |= cfg->gain_mode_m << ISPCCDC_LSC_GAIN_MODE_M_SHIFT;219 reg |= cfg->gain_format << ISPCCDC_LSC_GAIN_FORMAT_SHIFT;220 isp_reg_writel(isp, reg, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_LSC_CONFIG);221 222 reg = 0;223 reg &= ~ISPCCDC_LSC_INITIAL_X_MASK;224 reg |= cfg->initial_x << ISPCCDC_LSC_INITIAL_X_SHIFT;225 reg &= ~ISPCCDC_LSC_INITIAL_Y_MASK;226 reg |= cfg->initial_y << ISPCCDC_LSC_INITIAL_Y_SHIFT;227 isp_reg_writel(isp, reg, OMAP3_ISP_IOMEM_CCDC,228 ISPCCDC_LSC_INITIAL);229}230 231static int ccdc_lsc_wait_prefetch(struct isp_ccdc_device *ccdc)232{233 struct isp_device *isp = to_isp_device(ccdc);234 unsigned int wait;235 236 isp_reg_writel(isp, IRQ0STATUS_CCDC_LSC_PREF_COMP_IRQ,237 OMAP3_ISP_IOMEM_MAIN, ISP_IRQ0STATUS);238 239 /* timeout 1 ms */240 for (wait = 0; wait < 1000; wait++) {241 if (isp_reg_readl(isp, OMAP3_ISP_IOMEM_MAIN, ISP_IRQ0STATUS) &242 IRQ0STATUS_CCDC_LSC_PREF_COMP_IRQ) {243 isp_reg_writel(isp, IRQ0STATUS_CCDC_LSC_PREF_COMP_IRQ,244 OMAP3_ISP_IOMEM_MAIN, ISP_IRQ0STATUS);245 return 0;246 }247 248 rmb();249 udelay(1);250 }251 252 return -ETIMEDOUT;253}254 255/*256 * __ccdc_lsc_enable - Enables/Disables the Lens Shading Compensation module.257 * @ccdc: Pointer to ISP CCDC device.258 * @enable: 0 Disables LSC, 1 Enables LSC.259 */260static int __ccdc_lsc_enable(struct isp_ccdc_device *ccdc, int enable)261{262 struct isp_device *isp = to_isp_device(ccdc);263 const struct v4l2_mbus_framefmt *format =264 __ccdc_get_format(ccdc, NULL, CCDC_PAD_SINK,265 V4L2_SUBDEV_FORMAT_ACTIVE);266 267 if ((format->code != MEDIA_BUS_FMT_SGRBG10_1X10) &&268 (format->code != MEDIA_BUS_FMT_SRGGB10_1X10) &&269 (format->code != MEDIA_BUS_FMT_SBGGR10_1X10) &&270 (format->code != MEDIA_BUS_FMT_SGBRG10_1X10))271 return -EINVAL;272 273 if (enable)274 omap3isp_sbl_enable(isp, OMAP3_ISP_SBL_CCDC_LSC_READ);275 276 isp_reg_clr_set(isp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_LSC_CONFIG,277 ISPCCDC_LSC_ENABLE, enable ? ISPCCDC_LSC_ENABLE : 0);278 279 if (enable) {280 if (ccdc_lsc_wait_prefetch(ccdc) < 0) {281 isp_reg_clr(isp, OMAP3_ISP_IOMEM_CCDC,282 ISPCCDC_LSC_CONFIG, ISPCCDC_LSC_ENABLE);283 ccdc->lsc.state = LSC_STATE_STOPPED;284 dev_warn(to_device(ccdc), "LSC prefetch timeout\n");285 return -ETIMEDOUT;286 }287 ccdc->lsc.state = LSC_STATE_RUNNING;288 } else {289 ccdc->lsc.state = LSC_STATE_STOPPING;290 }291 292 return 0;293}294 295static int ccdc_lsc_busy(struct isp_ccdc_device *ccdc)296{297 struct isp_device *isp = to_isp_device(ccdc);298 299 return isp_reg_readl(isp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_LSC_CONFIG) &300 ISPCCDC_LSC_BUSY;301}302 303/*304 * __ccdc_lsc_configure - Apply a new configuration to the LSC engine305 * @ccdc: Pointer to ISP CCDC device306 * @req: New configuration request307 */308static int __ccdc_lsc_configure(struct isp_ccdc_device *ccdc,309 struct ispccdc_lsc_config_req *req)310{311 if (!req->enable)312 return -EINVAL;313 314 if (ccdc_lsc_validate_config(ccdc, &req->config) < 0) {315 dev_dbg(to_device(ccdc), "Discard LSC configuration\n");316 return -EINVAL;317 }318 319 if (ccdc_lsc_busy(ccdc))320 return -EBUSY;321 322 ccdc_lsc_setup_regs(ccdc, &req->config);323 ccdc_lsc_program_table(ccdc, req->table.dma);324 return 0;325}326 327/*328 * ccdc_lsc_error_handler - Handle LSC prefetch error scenario.329 * @ccdc: Pointer to ISP CCDC device.330 *331 * Disables LSC, and defers enablement to shadow registers update time.332 */333static void ccdc_lsc_error_handler(struct isp_ccdc_device *ccdc)334{335 struct isp_device *isp = to_isp_device(ccdc);336 /*337 * From OMAP3 TRM: When this event is pending, the module338 * goes into transparent mode (output =input). Normal339 * operation can be resumed at the start of the next frame340 * after:341 * 1) Clearing this event342 * 2) Disabling the LSC module343 * 3) Enabling it344 */345 isp_reg_clr(isp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_LSC_CONFIG,346 ISPCCDC_LSC_ENABLE);347 ccdc->lsc.state = LSC_STATE_STOPPED;348}349 350static void ccdc_lsc_free_request(struct isp_ccdc_device *ccdc,351 struct ispccdc_lsc_config_req *req)352{353 struct isp_device *isp = to_isp_device(ccdc);354 355 if (req == NULL)356 return;357 358 if (req->table.addr) {359 sg_free_table(&req->table.sgt);360 dma_free_coherent(isp->dev, req->config.size, req->table.addr,361 req->table.dma);362 }363 364 kfree(req);365}366 367static void ccdc_lsc_free_queue(struct isp_ccdc_device *ccdc,368 struct list_head *queue)369{370 struct ispccdc_lsc_config_req *req, *n;371 unsigned long flags;372 373 spin_lock_irqsave(&ccdc->lsc.req_lock, flags);374 list_for_each_entry_safe(req, n, queue, list) {375 list_del(&req->list);376 spin_unlock_irqrestore(&ccdc->lsc.req_lock, flags);377 ccdc_lsc_free_request(ccdc, req);378 spin_lock_irqsave(&ccdc->lsc.req_lock, flags);379 }380 spin_unlock_irqrestore(&ccdc->lsc.req_lock, flags);381}382 383static void ccdc_lsc_free_table_work(struct work_struct *work)384{385 struct isp_ccdc_device *ccdc;386 struct ispccdc_lsc *lsc;387 388 lsc = container_of(work, struct ispccdc_lsc, table_work);389 ccdc = container_of(lsc, struct isp_ccdc_device, lsc);390 391 ccdc_lsc_free_queue(ccdc, &lsc->free_queue);392}393 394/*395 * ccdc_lsc_config - Configure the LSC module from a userspace request396 *397 * Store the request LSC configuration in the LSC engine request pointer. The398 * configuration will be applied to the hardware when the CCDC will be enabled,399 * or at the next LSC interrupt if the CCDC is already running.400 */401static int ccdc_lsc_config(struct isp_ccdc_device *ccdc,402 struct omap3isp_ccdc_update_config *config)403{404 struct isp_device *isp = to_isp_device(ccdc);405 struct ispccdc_lsc_config_req *req;406 unsigned long flags;407 u16 update;408 int ret;409 410 update = config->update &411 (OMAP3ISP_CCDC_CONFIG_LSC | OMAP3ISP_CCDC_TBL_LSC);412 if (!update)413 return 0;414 415 if (update != (OMAP3ISP_CCDC_CONFIG_LSC | OMAP3ISP_CCDC_TBL_LSC)) {416 dev_dbg(to_device(ccdc),417 "%s: Both LSC configuration and table need to be supplied\n",418 __func__);419 return -EINVAL;420 }421 422 req = kzalloc(sizeof(*req), GFP_KERNEL);423 if (req == NULL)424 return -ENOMEM;425 426 if (config->flag & OMAP3ISP_CCDC_CONFIG_LSC) {427 if (copy_from_user(&req->config, config->lsc_cfg,428 sizeof(req->config))) {429 ret = -EFAULT;430 goto done;431 }432 433 req->enable = 1;434 435 req->table.addr = dma_alloc_coherent(isp->dev, req->config.size,436 &req->table.dma,437 GFP_KERNEL);438 if (req->table.addr == NULL) {439 ret = -ENOMEM;440 goto done;441 }442 443 ret = dma_get_sgtable(isp->dev, &req->table.sgt,444 req->table.addr, req->table.dma,445 req->config.size);446 if (ret < 0)447 goto done;448 449 dma_sync_sg_for_cpu(isp->dev, req->table.sgt.sgl,450 req->table.sgt.nents, DMA_TO_DEVICE);451 452 if (copy_from_user(req->table.addr, config->lsc,453 req->config.size)) {454 ret = -EFAULT;455 goto done;456 }457 458 dma_sync_sg_for_device(isp->dev, req->table.sgt.sgl,459 req->table.sgt.nents, DMA_TO_DEVICE);460 }461 462 spin_lock_irqsave(&ccdc->lsc.req_lock, flags);463 if (ccdc->lsc.request) {464 list_add_tail(&ccdc->lsc.request->list, &ccdc->lsc.free_queue);465 schedule_work(&ccdc->lsc.table_work);466 }467 ccdc->lsc.request = req;468 spin_unlock_irqrestore(&ccdc->lsc.req_lock, flags);469 470 ret = 0;471 472done:473 if (ret < 0)474 ccdc_lsc_free_request(ccdc, req);475 476 return ret;477}478 479static inline int ccdc_lsc_is_configured(struct isp_ccdc_device *ccdc)480{481 unsigned long flags;482 int ret;483 484 spin_lock_irqsave(&ccdc->lsc.req_lock, flags);485 ret = ccdc->lsc.active != NULL;486 spin_unlock_irqrestore(&ccdc->lsc.req_lock, flags);487 488 return ret;489}490 491static int ccdc_lsc_enable(struct isp_ccdc_device *ccdc)492{493 struct ispccdc_lsc *lsc = &ccdc->lsc;494 495 if (lsc->state != LSC_STATE_STOPPED)496 return -EINVAL;497 498 if (lsc->active) {499 list_add_tail(&lsc->active->list, &lsc->free_queue);500 lsc->active = NULL;501 }502 503 if (__ccdc_lsc_configure(ccdc, lsc->request) < 0) {504 omap3isp_sbl_disable(to_isp_device(ccdc),505 OMAP3_ISP_SBL_CCDC_LSC_READ);506 list_add_tail(&lsc->request->list, &lsc->free_queue);507 lsc->request = NULL;508 goto done;509 }510 511 lsc->active = lsc->request;512 lsc->request = NULL;513 __ccdc_lsc_enable(ccdc, 1);514 515done:516 if (!list_empty(&lsc->free_queue))517 schedule_work(&lsc->table_work);518 519 return 0;520}521 522/* -----------------------------------------------------------------------------523 * Parameters configuration524 */525 526/*527 * ccdc_configure_clamp - Configure optical-black or digital clamping528 * @ccdc: Pointer to ISP CCDC device.529 *530 * The CCDC performs either optical-black or digital clamp. Configure and enable531 * the selected clamp method.532 */533static void ccdc_configure_clamp(struct isp_ccdc_device *ccdc)534{535 struct isp_device *isp = to_isp_device(ccdc);536 u32 clamp;537 538 if (ccdc->obclamp) {539 clamp = ccdc->clamp.obgain << ISPCCDC_CLAMP_OBGAIN_SHIFT;540 clamp |= ccdc->clamp.oblen << ISPCCDC_CLAMP_OBSLEN_SHIFT;541 clamp |= ccdc->clamp.oblines << ISPCCDC_CLAMP_OBSLN_SHIFT;542 clamp |= ccdc->clamp.obstpixel << ISPCCDC_CLAMP_OBST_SHIFT;543 isp_reg_writel(isp, clamp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_CLAMP);544 } else {545 isp_reg_writel(isp, ccdc->clamp.dcsubval,546 OMAP3_ISP_IOMEM_CCDC, ISPCCDC_DCSUB);547 }548 549 isp_reg_clr_set(isp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_CLAMP,550 ISPCCDC_CLAMP_CLAMPEN,551 ccdc->obclamp ? ISPCCDC_CLAMP_CLAMPEN : 0);552}553 554/*555 * ccdc_configure_fpc - Configure Faulty Pixel Correction556 * @ccdc: Pointer to ISP CCDC device.557 */558static void ccdc_configure_fpc(struct isp_ccdc_device *ccdc)559{560 struct isp_device *isp = to_isp_device(ccdc);561 562 isp_reg_clr(isp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_FPC, ISPCCDC_FPC_FPCEN);563 564 if (!ccdc->fpc_en)565 return;566 567 isp_reg_writel(isp, ccdc->fpc.dma, OMAP3_ISP_IOMEM_CCDC,568 ISPCCDC_FPC_ADDR);569 /* The FPNUM field must be set before enabling FPC. */570 isp_reg_writel(isp, (ccdc->fpc.fpnum << ISPCCDC_FPC_FPNUM_SHIFT),571 OMAP3_ISP_IOMEM_CCDC, ISPCCDC_FPC);572 isp_reg_writel(isp, (ccdc->fpc.fpnum << ISPCCDC_FPC_FPNUM_SHIFT) |573 ISPCCDC_FPC_FPCEN, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_FPC);574}575 576/*577 * ccdc_configure_black_comp - Configure Black Level Compensation.578 * @ccdc: Pointer to ISP CCDC device.579 */580static void ccdc_configure_black_comp(struct isp_ccdc_device *ccdc)581{582 struct isp_device *isp = to_isp_device(ccdc);583 u32 blcomp;584 585 blcomp = ccdc->blcomp.b_mg << ISPCCDC_BLKCMP_B_MG_SHIFT;586 blcomp |= ccdc->blcomp.gb_g << ISPCCDC_BLKCMP_GB_G_SHIFT;587 blcomp |= ccdc->blcomp.gr_cy << ISPCCDC_BLKCMP_GR_CY_SHIFT;588 blcomp |= ccdc->blcomp.r_ye << ISPCCDC_BLKCMP_R_YE_SHIFT;589 590 isp_reg_writel(isp, blcomp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_BLKCMP);591}592 593/*594 * ccdc_configure_lpf - Configure Low-Pass Filter (LPF).595 * @ccdc: Pointer to ISP CCDC device.596 */597static void ccdc_configure_lpf(struct isp_ccdc_device *ccdc)598{599 struct isp_device *isp = to_isp_device(ccdc);600 601 isp_reg_clr_set(isp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_SYN_MODE,602 ISPCCDC_SYN_MODE_LPF,603 ccdc->lpf ? ISPCCDC_SYN_MODE_LPF : 0);604}605 606/*607 * ccdc_configure_alaw - Configure A-law compression.608 * @ccdc: Pointer to ISP CCDC device.609 */610static void ccdc_configure_alaw(struct isp_ccdc_device *ccdc)611{612 struct isp_device *isp = to_isp_device(ccdc);613 const struct isp_format_info *info;614 u32 alaw = 0;615 616 info = omap3isp_video_format_info(ccdc->formats[CCDC_PAD_SINK].code);617 618 switch (info->width) {619 case 8:620 return;621 622 case 10:623 alaw = ISPCCDC_ALAW_GWDI_9_0;624 break;625 case 11:626 alaw = ISPCCDC_ALAW_GWDI_10_1;627 break;628 case 12:629 alaw = ISPCCDC_ALAW_GWDI_11_2;630 break;631 case 13:632 alaw = ISPCCDC_ALAW_GWDI_12_3;633 break;634 }635 636 if (ccdc->alaw)637 alaw |= ISPCCDC_ALAW_CCDTBL;638 639 isp_reg_writel(isp, alaw, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_ALAW);640}641 642/*643 * ccdc_config_imgattr - Configure sensor image specific attributes.644 * @ccdc: Pointer to ISP CCDC device.645 * @colptn: Color pattern of the sensor.646 */647static void ccdc_config_imgattr(struct isp_ccdc_device *ccdc, u32 colptn)648{649 struct isp_device *isp = to_isp_device(ccdc);650 651 isp_reg_writel(isp, colptn, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_COLPTN);652}653 654/*655 * ccdc_config - Set CCDC configuration from userspace656 * @ccdc: Pointer to ISP CCDC device.657 * @ccdc_struct: Structure containing CCDC configuration sent from userspace.658 *659 * Returns 0 if successful, -EINVAL if the pointer to the configuration660 * structure is null, or the copy_from_user function fails to copy user space661 * memory to kernel space memory.662 */663static int ccdc_config(struct isp_ccdc_device *ccdc,664 struct omap3isp_ccdc_update_config *ccdc_struct)665{666 struct isp_device *isp = to_isp_device(ccdc);667 unsigned long flags;668 669 spin_lock_irqsave(&ccdc->lock, flags);670 ccdc->shadow_update = 1;671 spin_unlock_irqrestore(&ccdc->lock, flags);672 673 if (OMAP3ISP_CCDC_ALAW & ccdc_struct->update) {674 ccdc->alaw = !!(OMAP3ISP_CCDC_ALAW & ccdc_struct->flag);675 ccdc->update |= OMAP3ISP_CCDC_ALAW;676 }677 678 if (OMAP3ISP_CCDC_LPF & ccdc_struct->update) {679 ccdc->lpf = !!(OMAP3ISP_CCDC_LPF & ccdc_struct->flag);680 ccdc->update |= OMAP3ISP_CCDC_LPF;681 }682 683 if (OMAP3ISP_CCDC_BLCLAMP & ccdc_struct->update) {684 if (copy_from_user(&ccdc->clamp, ccdc_struct->bclamp,685 sizeof(ccdc->clamp))) {686 ccdc->shadow_update = 0;687 return -EFAULT;688 }689 690 ccdc->obclamp = !!(OMAP3ISP_CCDC_BLCLAMP & ccdc_struct->flag);691 ccdc->update |= OMAP3ISP_CCDC_BLCLAMP;692 }693 694 if (OMAP3ISP_CCDC_BCOMP & ccdc_struct->update) {695 if (copy_from_user(&ccdc->blcomp, ccdc_struct->blcomp,696 sizeof(ccdc->blcomp))) {697 ccdc->shadow_update = 0;698 return -EFAULT;699 }700 701 ccdc->update |= OMAP3ISP_CCDC_BCOMP;702 }703 704 ccdc->shadow_update = 0;705 706 if (OMAP3ISP_CCDC_FPC & ccdc_struct->update) {707 struct omap3isp_ccdc_fpc fpc;708 struct ispccdc_fpc fpc_old = { .addr = NULL, };709 struct ispccdc_fpc fpc_new;710 u32 size;711 712 if (ccdc->state != ISP_PIPELINE_STREAM_STOPPED)713 return -EBUSY;714 715 ccdc->fpc_en = !!(OMAP3ISP_CCDC_FPC & ccdc_struct->flag);716 717 if (ccdc->fpc_en) {718 if (copy_from_user(&fpc, ccdc_struct->fpc, sizeof(fpc)))719 return -EFAULT;720 721 size = fpc.fpnum * 4;722 723 /*724 * The table address must be 64-bytes aligned, which is725 * guaranteed by dma_alloc_coherent().726 */727 fpc_new.fpnum = fpc.fpnum;728 fpc_new.addr = dma_alloc_coherent(isp->dev, size,729 &fpc_new.dma,730 GFP_KERNEL);731 if (fpc_new.addr == NULL)732 return -ENOMEM;733 734 if (copy_from_user(fpc_new.addr,735 (__force void __user *)(long)fpc.fpcaddr,736 size)) {737 dma_free_coherent(isp->dev, size, fpc_new.addr,738 fpc_new.dma);739 return -EFAULT;740 }741 742 fpc_old = ccdc->fpc;743 ccdc->fpc = fpc_new;744 }745 746 ccdc_configure_fpc(ccdc);747 748 if (fpc_old.addr != NULL)749 dma_free_coherent(isp->dev, fpc_old.fpnum * 4,750 fpc_old.addr, fpc_old.dma);751 }752 753 return ccdc_lsc_config(ccdc, ccdc_struct);754}755 756static void ccdc_apply_controls(struct isp_ccdc_device *ccdc)757{758 if (ccdc->update & OMAP3ISP_CCDC_ALAW) {759 ccdc_configure_alaw(ccdc);760 ccdc->update &= ~OMAP3ISP_CCDC_ALAW;761 }762 763 if (ccdc->update & OMAP3ISP_CCDC_LPF) {764 ccdc_configure_lpf(ccdc);765 ccdc->update &= ~OMAP3ISP_CCDC_LPF;766 }767 768 if (ccdc->update & OMAP3ISP_CCDC_BLCLAMP) {769 ccdc_configure_clamp(ccdc);770 ccdc->update &= ~OMAP3ISP_CCDC_BLCLAMP;771 }772 773 if (ccdc->update & OMAP3ISP_CCDC_BCOMP) {774 ccdc_configure_black_comp(ccdc);775 ccdc->update &= ~OMAP3ISP_CCDC_BCOMP;776 }777}778 779/*780 * omap3isp_ccdc_restore_context - Restore values of the CCDC module registers781 * @isp: Pointer to ISP device782 */783void omap3isp_ccdc_restore_context(struct isp_device *isp)784{785 struct isp_ccdc_device *ccdc = &isp->isp_ccdc;786 787 isp_reg_set(isp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_CFG, ISPCCDC_CFG_VDLC);788 789 ccdc->update = OMAP3ISP_CCDC_ALAW | OMAP3ISP_CCDC_LPF790 | OMAP3ISP_CCDC_BLCLAMP | OMAP3ISP_CCDC_BCOMP;791 ccdc_apply_controls(ccdc);792 ccdc_configure_fpc(ccdc);793}794 795/* -----------------------------------------------------------------------------796 * Format- and pipeline-related configuration helpers797 */798 799/*800 * ccdc_config_vp - Configure the Video Port.801 * @ccdc: Pointer to ISP CCDC device.802 */803static void ccdc_config_vp(struct isp_ccdc_device *ccdc)804{805 struct isp_pipeline *pipe = to_isp_pipeline(&ccdc->subdev.entity);806 struct isp_device *isp = to_isp_device(ccdc);807 const struct isp_format_info *info;808 struct v4l2_mbus_framefmt *format;809 unsigned long l3_ick = pipe->l3_ick;810 unsigned int max_div = isp->revision == ISP_REVISION_15_0 ? 64 : 8;811 unsigned int div = 0;812 u32 fmtcfg = ISPCCDC_FMTCFG_VPEN;813 814 format = &ccdc->formats[CCDC_PAD_SOURCE_VP];815 816 if (!format->code) {817 /* Disable the video port when the input format isn't supported.818 * This is indicated by a pixel code set to 0.819 */820 isp_reg_writel(isp, 0, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_FMTCFG);821 return;822 }823 824 isp_reg_writel(isp, (0 << ISPCCDC_FMT_HORZ_FMTSPH_SHIFT) |825 (format->width << ISPCCDC_FMT_HORZ_FMTLNH_SHIFT),826 OMAP3_ISP_IOMEM_CCDC, ISPCCDC_FMT_HORZ);827 isp_reg_writel(isp, (0 << ISPCCDC_FMT_VERT_FMTSLV_SHIFT) |828 ((format->height + 1) << ISPCCDC_FMT_VERT_FMTLNV_SHIFT),829 OMAP3_ISP_IOMEM_CCDC, ISPCCDC_FMT_VERT);830 831 isp_reg_writel(isp, (format->width << ISPCCDC_VP_OUT_HORZ_NUM_SHIFT) |832 (format->height << ISPCCDC_VP_OUT_VERT_NUM_SHIFT),833 OMAP3_ISP_IOMEM_CCDC, ISPCCDC_VP_OUT);834 835 info = omap3isp_video_format_info(ccdc->formats[CCDC_PAD_SINK].code);836 837 switch (info->width) {838 case 8:839 case 10:840 fmtcfg |= ISPCCDC_FMTCFG_VPIN_9_0;841 break;842 case 11:843 fmtcfg |= ISPCCDC_FMTCFG_VPIN_10_1;844 break;845 case 12:846 fmtcfg |= ISPCCDC_FMTCFG_VPIN_11_2;847 break;848 case 13:849 fmtcfg |= ISPCCDC_FMTCFG_VPIN_12_3;850 break;851 }852 853 if (pipe->input)854 div = DIV_ROUND_UP(l3_ick, pipe->max_rate);855 else if (pipe->external_rate)856 div = l3_ick / pipe->external_rate;857 858 div = clamp(div, 2U, max_div);859 fmtcfg |= (div - 2) << ISPCCDC_FMTCFG_VPIF_FRQ_SHIFT;860 861 isp_reg_writel(isp, fmtcfg, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_FMTCFG);862}863 864/*865 * ccdc_config_outlineoffset - Configure memory saving output line offset866 * @ccdc: Pointer to ISP CCDC device.867 * @bpl: Number of bytes per line when stored in memory.868 * @field: Field order when storing interlaced formats in memory.869 *870 * Configure the offsets for the line output control:871 *872 * - The horizontal line offset is defined as the number of bytes between the873 * start of two consecutive lines in memory. Set it to the given bytes per874 * line value.875 *876 * - The field offset value is defined as the number of lines to offset the877 * start of the field identified by FID = 1. Set it to one.878 *879 * - The line offset values are defined as the number of lines (as defined by880 * the horizontal line offset) between the start of two consecutive lines for881 * all combinations of odd/even lines in odd/even fields. When interleaving882 * fields set them all to two lines, and to one line otherwise.883 */884static void ccdc_config_outlineoffset(struct isp_ccdc_device *ccdc,885 unsigned int bpl,886 enum v4l2_field field)887{888 struct isp_device *isp = to_isp_device(ccdc);889 u32 sdofst = 0;890 891 isp_reg_writel(isp, bpl & 0xffff, OMAP3_ISP_IOMEM_CCDC,892 ISPCCDC_HSIZE_OFF);893 894 switch (field) {895 case V4L2_FIELD_INTERLACED_TB:896 case V4L2_FIELD_INTERLACED_BT:897 /* When interleaving fields in memory offset field one by one898 * line and set the line offset to two lines.899 */900 sdofst |= (1 << ISPCCDC_SDOFST_LOFST0_SHIFT)901 | (1 << ISPCCDC_SDOFST_LOFST1_SHIFT)902 | (1 << ISPCCDC_SDOFST_LOFST2_SHIFT)903 | (1 << ISPCCDC_SDOFST_LOFST3_SHIFT);904 break;905 906 default:907 /* In all other cases set the line offsets to one line. */908 break;909 }910 911 isp_reg_writel(isp, sdofst, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_SDOFST);912}913 914/*915 * ccdc_set_outaddr - Set memory address to save output image916 * @ccdc: Pointer to ISP CCDC device.917 * @addr: ISP MMU Mapped 32-bit memory address aligned on 32 byte boundary.918 *919 * Sets the memory address where the output will be saved.920 */921static void ccdc_set_outaddr(struct isp_ccdc_device *ccdc, u32 addr)922{923 struct isp_device *isp = to_isp_device(ccdc);924 925 isp_reg_writel(isp, addr, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_SDR_ADDR);926}927 928/*929 * omap3isp_ccdc_max_rate - Calculate maximum input data rate based on the input930 * @ccdc: Pointer to ISP CCDC device.931 * @max_rate: Maximum calculated data rate.932 *933 * Returns in *max_rate less value between calculated and passed934 */935void omap3isp_ccdc_max_rate(struct isp_ccdc_device *ccdc,936 unsigned int *max_rate)937{938 struct isp_pipeline *pipe = to_isp_pipeline(&ccdc->subdev.entity);939 unsigned int rate;940 941 if (pipe == NULL)942 return;943 944 /*945 * TRM says that for parallel sensors the maximum data rate946 * should be 90% form L3/2 clock, otherwise just L3/2.947 */948 if (ccdc->input == CCDC_INPUT_PARALLEL)949 rate = pipe->l3_ick / 2 * 9 / 10;950 else951 rate = pipe->l3_ick / 2;952 953 *max_rate = min(*max_rate, rate);954}955 956/*957 * ccdc_config_sync_if - Set CCDC sync interface configuration958 * @ccdc: Pointer to ISP CCDC device.959 * @parcfg: Parallel interface platform data (may be NULL)960 * @data_size: Data size961 */962static void ccdc_config_sync_if(struct isp_ccdc_device *ccdc,963 struct isp_parallel_cfg *parcfg,964 unsigned int data_size)965{966 struct isp_device *isp = to_isp_device(ccdc);967 const struct v4l2_mbus_framefmt *format;968 u32 syn_mode = ISPCCDC_SYN_MODE_VDHDEN;969 970 format = &ccdc->formats[CCDC_PAD_SINK];971 972 if (format->code == MEDIA_BUS_FMT_YUYV8_2X8 ||973 format->code == MEDIA_BUS_FMT_UYVY8_2X8) {974 /* According to the OMAP3 TRM the input mode only affects SYNC975 * mode, enabling BT.656 mode should take precedence. However,976 * in practice setting the input mode to YCbCr data on 8 bits977 * seems to be required in BT.656 mode. In SYNC mode set it to978 * YCbCr on 16 bits as the bridge is enabled in that case.979 */980 if (ccdc->bt656)981 syn_mode |= ISPCCDC_SYN_MODE_INPMOD_YCBCR8;982 else983 syn_mode |= ISPCCDC_SYN_MODE_INPMOD_YCBCR16;984 }985 986 switch (data_size) {987 case 8:988 syn_mode |= ISPCCDC_SYN_MODE_DATSIZ_8;989 break;990 case 10:991 syn_mode |= ISPCCDC_SYN_MODE_DATSIZ_10;992 break;993 case 11:994 syn_mode |= ISPCCDC_SYN_MODE_DATSIZ_11;995 break;996 case 12:997 syn_mode |= ISPCCDC_SYN_MODE_DATSIZ_12;998 break;999 }1000 1001 if (parcfg && parcfg->data_pol)1002 syn_mode |= ISPCCDC_SYN_MODE_DATAPOL;1003 1004 if (parcfg && parcfg->hs_pol)1005 syn_mode |= ISPCCDC_SYN_MODE_HDPOL;1006 1007 /* The polarity of the vertical sync signal output by the BT.6561008 * decoder is not documented and seems to be active low.1009 */1010 if ((parcfg && parcfg->vs_pol) || ccdc->bt656)1011 syn_mode |= ISPCCDC_SYN_MODE_VDPOL;1012 1013 if (parcfg && parcfg->fld_pol)1014 syn_mode |= ISPCCDC_SYN_MODE_FLDPOL;1015 1016 isp_reg_writel(isp, syn_mode, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_SYN_MODE);1017 1018 /* The CCDC_CFG.Y8POS bit is used in YCbCr8 input mode only. The1019 * hardware seems to ignore it in all other input modes.1020 */1021 if (format->code == MEDIA_BUS_FMT_UYVY8_2X8)1022 isp_reg_set(isp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_CFG,1023 ISPCCDC_CFG_Y8POS);1024 else1025 isp_reg_clr(isp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_CFG,1026 ISPCCDC_CFG_Y8POS);1027 1028 /* Enable or disable BT.656 mode, including error correction for the1029 * synchronization codes.1030 */1031 if (ccdc->bt656)1032 isp_reg_set(isp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_REC656IF,1033 ISPCCDC_REC656IF_R656ON | ISPCCDC_REC656IF_ECCFVH);1034 else1035 isp_reg_clr(isp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_REC656IF,1036 ISPCCDC_REC656IF_R656ON | ISPCCDC_REC656IF_ECCFVH);1037 1038}1039 1040/* CCDC formats descriptions */1041static const u32 ccdc_sgrbg_pattern =1042 ISPCCDC_COLPTN_Gr_Cy << ISPCCDC_COLPTN_CP0PLC0_SHIFT |1043 ISPCCDC_COLPTN_R_Ye << ISPCCDC_COLPTN_CP0PLC1_SHIFT |1044 ISPCCDC_COLPTN_Gr_Cy << ISPCCDC_COLPTN_CP0PLC2_SHIFT |1045 ISPCCDC_COLPTN_R_Ye << ISPCCDC_COLPTN_CP0PLC3_SHIFT |1046 ISPCCDC_COLPTN_B_Mg << ISPCCDC_COLPTN_CP1PLC0_SHIFT |1047 ISPCCDC_COLPTN_Gb_G << ISPCCDC_COLPTN_CP1PLC1_SHIFT |1048 ISPCCDC_COLPTN_B_Mg << ISPCCDC_COLPTN_CP1PLC2_SHIFT |1049 ISPCCDC_COLPTN_Gb_G << ISPCCDC_COLPTN_CP1PLC3_SHIFT |1050 ISPCCDC_COLPTN_Gr_Cy << ISPCCDC_COLPTN_CP2PLC0_SHIFT |1051 ISPCCDC_COLPTN_R_Ye << ISPCCDC_COLPTN_CP2PLC1_SHIFT |1052 ISPCCDC_COLPTN_Gr_Cy << ISPCCDC_COLPTN_CP2PLC2_SHIFT |1053 ISPCCDC_COLPTN_R_Ye << ISPCCDC_COLPTN_CP2PLC3_SHIFT |1054 ISPCCDC_COLPTN_B_Mg << ISPCCDC_COLPTN_CP3PLC0_SHIFT |1055 ISPCCDC_COLPTN_Gb_G << ISPCCDC_COLPTN_CP3PLC1_SHIFT |1056 ISPCCDC_COLPTN_B_Mg << ISPCCDC_COLPTN_CP3PLC2_SHIFT |1057 ISPCCDC_COLPTN_Gb_G << ISPCCDC_COLPTN_CP3PLC3_SHIFT;1058 1059static const u32 ccdc_srggb_pattern =1060 ISPCCDC_COLPTN_R_Ye << ISPCCDC_COLPTN_CP0PLC0_SHIFT |1061 ISPCCDC_COLPTN_Gr_Cy << ISPCCDC_COLPTN_CP0PLC1_SHIFT |1062 ISPCCDC_COLPTN_R_Ye << ISPCCDC_COLPTN_CP0PLC2_SHIFT |1063 ISPCCDC_COLPTN_Gr_Cy << ISPCCDC_COLPTN_CP0PLC3_SHIFT |1064 ISPCCDC_COLPTN_Gb_G << ISPCCDC_COLPTN_CP1PLC0_SHIFT |1065 ISPCCDC_COLPTN_B_Mg << ISPCCDC_COLPTN_CP1PLC1_SHIFT |1066 ISPCCDC_COLPTN_Gb_G << ISPCCDC_COLPTN_CP1PLC2_SHIFT |1067 ISPCCDC_COLPTN_B_Mg << ISPCCDC_COLPTN_CP1PLC3_SHIFT |1068 ISPCCDC_COLPTN_R_Ye << ISPCCDC_COLPTN_CP2PLC0_SHIFT |1069 ISPCCDC_COLPTN_Gr_Cy << ISPCCDC_COLPTN_CP2PLC1_SHIFT |1070 ISPCCDC_COLPTN_R_Ye << ISPCCDC_COLPTN_CP2PLC2_SHIFT |1071 ISPCCDC_COLPTN_Gr_Cy << ISPCCDC_COLPTN_CP2PLC3_SHIFT |1072 ISPCCDC_COLPTN_Gb_G << ISPCCDC_COLPTN_CP3PLC0_SHIFT |1073 ISPCCDC_COLPTN_B_Mg << ISPCCDC_COLPTN_CP3PLC1_SHIFT |1074 ISPCCDC_COLPTN_Gb_G << ISPCCDC_COLPTN_CP3PLC2_SHIFT |1075 ISPCCDC_COLPTN_B_Mg << ISPCCDC_COLPTN_CP3PLC3_SHIFT;1076 1077static const u32 ccdc_sbggr_pattern =1078 ISPCCDC_COLPTN_B_Mg << ISPCCDC_COLPTN_CP0PLC0_SHIFT |1079 ISPCCDC_COLPTN_Gb_G << ISPCCDC_COLPTN_CP0PLC1_SHIFT |1080 ISPCCDC_COLPTN_B_Mg << ISPCCDC_COLPTN_CP0PLC2_SHIFT |1081 ISPCCDC_COLPTN_Gb_G << ISPCCDC_COLPTN_CP0PLC3_SHIFT |1082 ISPCCDC_COLPTN_Gr_Cy << ISPCCDC_COLPTN_CP1PLC0_SHIFT |1083 ISPCCDC_COLPTN_R_Ye << ISPCCDC_COLPTN_CP1PLC1_SHIFT |1084 ISPCCDC_COLPTN_Gr_Cy << ISPCCDC_COLPTN_CP1PLC2_SHIFT |1085 ISPCCDC_COLPTN_R_Ye << ISPCCDC_COLPTN_CP1PLC3_SHIFT |1086 ISPCCDC_COLPTN_B_Mg << ISPCCDC_COLPTN_CP2PLC0_SHIFT |1087 ISPCCDC_COLPTN_Gb_G << ISPCCDC_COLPTN_CP2PLC1_SHIFT |1088 ISPCCDC_COLPTN_B_Mg << ISPCCDC_COLPTN_CP2PLC2_SHIFT |1089 ISPCCDC_COLPTN_Gb_G << ISPCCDC_COLPTN_CP2PLC3_SHIFT |1090 ISPCCDC_COLPTN_Gr_Cy << ISPCCDC_COLPTN_CP3PLC0_SHIFT |1091 ISPCCDC_COLPTN_R_Ye << ISPCCDC_COLPTN_CP3PLC1_SHIFT |1092 ISPCCDC_COLPTN_Gr_Cy << ISPCCDC_COLPTN_CP3PLC2_SHIFT |1093 ISPCCDC_COLPTN_R_Ye << ISPCCDC_COLPTN_CP3PLC3_SHIFT;1094 1095static const u32 ccdc_sgbrg_pattern =1096 ISPCCDC_COLPTN_Gb_G << ISPCCDC_COLPTN_CP0PLC0_SHIFT |1097 ISPCCDC_COLPTN_B_Mg << ISPCCDC_COLPTN_CP0PLC1_SHIFT |1098 ISPCCDC_COLPTN_Gb_G << ISPCCDC_COLPTN_CP0PLC2_SHIFT |1099 ISPCCDC_COLPTN_B_Mg << ISPCCDC_COLPTN_CP0PLC3_SHIFT |1100 ISPCCDC_COLPTN_R_Ye << ISPCCDC_COLPTN_CP1PLC0_SHIFT |1101 ISPCCDC_COLPTN_Gr_Cy << ISPCCDC_COLPTN_CP1PLC1_SHIFT |1102 ISPCCDC_COLPTN_R_Ye << ISPCCDC_COLPTN_CP1PLC2_SHIFT |1103 ISPCCDC_COLPTN_Gr_Cy << ISPCCDC_COLPTN_CP1PLC3_SHIFT |1104 ISPCCDC_COLPTN_Gb_G << ISPCCDC_COLPTN_CP2PLC0_SHIFT |1105 ISPCCDC_COLPTN_B_Mg << ISPCCDC_COLPTN_CP2PLC1_SHIFT |1106 ISPCCDC_COLPTN_Gb_G << ISPCCDC_COLPTN_CP2PLC2_SHIFT |1107 ISPCCDC_COLPTN_B_Mg << ISPCCDC_COLPTN_CP2PLC3_SHIFT |1108 ISPCCDC_COLPTN_R_Ye << ISPCCDC_COLPTN_CP3PLC0_SHIFT |1109 ISPCCDC_COLPTN_Gr_Cy << ISPCCDC_COLPTN_CP3PLC1_SHIFT |1110 ISPCCDC_COLPTN_R_Ye << ISPCCDC_COLPTN_CP3PLC2_SHIFT |1111 ISPCCDC_COLPTN_Gr_Cy << ISPCCDC_COLPTN_CP3PLC3_SHIFT;1112 1113static void ccdc_configure(struct isp_ccdc_device *ccdc)1114{1115 struct isp_device *isp = to_isp_device(ccdc);1116 struct isp_parallel_cfg *parcfg = NULL;1117 struct v4l2_subdev *sensor;1118 struct v4l2_mbus_framefmt *format;1119 const struct v4l2_rect *crop;1120 const struct isp_format_info *fmt_info;1121 struct v4l2_subdev_format fmt_src = {1122 .which = V4L2_SUBDEV_FORMAT_ACTIVE,1123 };1124 unsigned int depth_out;1125 unsigned int depth_in = 0;1126 struct media_pad *pad;1127 unsigned long flags;1128 unsigned int bridge;1129 unsigned int shift;1130 unsigned int nph;1131 unsigned int sph;1132 u32 syn_mode;1133 u32 ccdc_pattern;1134 1135 ccdc->bt656 = false;1136 ccdc->fields = 0;1137 1138 pad = media_pad_remote_pad_first(&ccdc->pads[CCDC_PAD_SINK]);1139 sensor = media_entity_to_v4l2_subdev(pad->entity);1140 if (ccdc->input == CCDC_INPUT_PARALLEL) {1141 struct v4l2_subdev *sd =1142 to_isp_pipeline(&ccdc->subdev.entity)->external;1143 struct isp_bus_cfg *bus_cfg;1144 1145 bus_cfg = v4l2_subdev_to_bus_cfg(sd);1146 if (WARN_ON(!bus_cfg))1147 return;1148 1149 parcfg = &bus_cfg->bus.parallel;1150 ccdc->bt656 = parcfg->bt656;1151 }1152 1153 /* CCDC_PAD_SINK */1154 format = &ccdc->formats[CCDC_PAD_SINK];1155 1156 /* Compute the lane shifter shift value and enable the bridge when the1157 * input format is a non-BT.656 YUV variant.1158 */1159 fmt_src.pad = pad->index;1160 if (!v4l2_subdev_call(sensor, pad, get_fmt, NULL, &fmt_src)) {1161 fmt_info = omap3isp_video_format_info(fmt_src.format.code);1162 depth_in = fmt_info->width;1163 }1164 1165 fmt_info = omap3isp_video_format_info(format->code);1166 depth_out = fmt_info->width;1167 shift = depth_in - depth_out;1168 1169 if (ccdc->bt656)1170 bridge = ISPCTRL_PAR_BRIDGE_DISABLE;1171 else if (fmt_info->code == MEDIA_BUS_FMT_YUYV8_2X8)1172 bridge = ISPCTRL_PAR_BRIDGE_LENDIAN;1173 else if (fmt_info->code == MEDIA_BUS_FMT_UYVY8_2X8)1174 bridge = ISPCTRL_PAR_BRIDGE_BENDIAN;1175 else1176 bridge = ISPCTRL_PAR_BRIDGE_DISABLE;1177 1178 omap3isp_configure_bridge(isp, ccdc->input, parcfg, shift, bridge);1179 1180 /* Configure the sync interface. */1181 ccdc_config_sync_if(ccdc, parcfg, depth_out);1182 1183 syn_mode = isp_reg_readl(isp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_SYN_MODE);1184 1185 /* Use the raw, unprocessed data when writing to memory. The H3A and1186 * histogram modules are still fed with lens shading corrected data.1187 */1188 syn_mode &= ~ISPCCDC_SYN_MODE_VP2SDR;1189 1190 if (ccdc->output & CCDC_OUTPUT_MEMORY)1191 syn_mode |= ISPCCDC_SYN_MODE_WEN;1192 else1193 syn_mode &= ~ISPCCDC_SYN_MODE_WEN;1194 1195 if (ccdc->output & CCDC_OUTPUT_RESIZER)1196 syn_mode |= ISPCCDC_SYN_MODE_SDR2RSZ;1197 else1198 syn_mode &= ~ISPCCDC_SYN_MODE_SDR2RSZ;1199 1200 /* Mosaic filter */1201 switch (format->code) {1202 case MEDIA_BUS_FMT_SRGGB10_1X10:1203 case MEDIA_BUS_FMT_SRGGB12_1X12:1204 ccdc_pattern = ccdc_srggb_pattern;1205 break;1206 case MEDIA_BUS_FMT_SBGGR10_1X10:1207 case MEDIA_BUS_FMT_SBGGR12_1X12:1208 ccdc_pattern = ccdc_sbggr_pattern;1209 break;1210 case MEDIA_BUS_FMT_SGBRG10_1X10:1211 case MEDIA_BUS_FMT_SGBRG12_1X12:1212 ccdc_pattern = ccdc_sgbrg_pattern;1213 break;1214 default:1215 /* Use GRBG */1216 ccdc_pattern = ccdc_sgrbg_pattern;1217 break;1218 }1219 ccdc_config_imgattr(ccdc, ccdc_pattern);1220 1221 /* Generate VD0 on the last line of the image and VD1 on the1222 * 2/3 height line.1223 */1224 isp_reg_writel(isp, ((format->height - 2) << ISPCCDC_VDINT_0_SHIFT) |1225 ((format->height * 2 / 3) << ISPCCDC_VDINT_1_SHIFT),1226 OMAP3_ISP_IOMEM_CCDC, ISPCCDC_VDINT);1227 1228 /* CCDC_PAD_SOURCE_OF */1229 format = &ccdc->formats[CCDC_PAD_SOURCE_OF];1230 crop = &ccdc->crop;1231 1232 /* The horizontal coordinates are expressed in pixel clock cycles. We1233 * need two cycles per pixel in BT.656 mode, and one cycle per pixel in1234 * SYNC mode regardless of the format as the bridge is enabled for YUV1235 * formats in that case.1236 */1237 if (ccdc->bt656) {1238 sph = crop->left * 2;1239 nph = crop->width * 2 - 1;1240 } else {1241 sph = crop->left;1242 nph = crop->width - 1;1243 }1244 1245 isp_reg_writel(isp, (sph << ISPCCDC_HORZ_INFO_SPH_SHIFT) |1246 (nph << ISPCCDC_HORZ_INFO_NPH_SHIFT),1247 OMAP3_ISP_IOMEM_CCDC, ISPCCDC_HORZ_INFO);1248 isp_reg_writel(isp, (crop->top << ISPCCDC_VERT_START_SLV0_SHIFT) |1249 (crop->top << ISPCCDC_VERT_START_SLV1_SHIFT),1250 OMAP3_ISP_IOMEM_CCDC, ISPCCDC_VERT_START);1251 isp_reg_writel(isp, (crop->height - 1)1252 << ISPCCDC_VERT_LINES_NLV_SHIFT,1253 OMAP3_ISP_IOMEM_CCDC, ISPCCDC_VERT_LINES);1254 1255 ccdc_config_outlineoffset(ccdc, ccdc->video_out.bpl_value,1256 format->field);1257 1258 /* When interleaving fields enable processing of the field input signal.1259 * This will cause the line output control module to apply the field1260 * offset to field 1.1261 */1262 if (ccdc->formats[CCDC_PAD_SINK].field == V4L2_FIELD_ALTERNATE &&1263 (format->field == V4L2_FIELD_INTERLACED_TB ||1264 format->field == V4L2_FIELD_INTERLACED_BT))1265 syn_mode |= ISPCCDC_SYN_MODE_FLDMODE;1266 1267 /* The CCDC outputs data in UYVY order by default. Swap bytes to get1268 * YUYV.1269 */1270 if (format->code == MEDIA_BUS_FMT_YUYV8_1X16)1271 isp_reg_set(isp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_CFG,1272 ISPCCDC_CFG_BSWD);1273 else1274 isp_reg_clr(isp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_CFG,1275 ISPCCDC_CFG_BSWD);1276 1277 /* Use PACK8 mode for 1byte per pixel formats. Check for BT.656 mode1278 * explicitly as the driver reports 1X16 instead of 2X8 at the OF pad1279 * for simplicity.1280 */1281 if (omap3isp_video_format_info(format->code)->width <= 8 || ccdc->bt656)1282 syn_mode |= ISPCCDC_SYN_MODE_PACK8;1283 else1284 syn_mode &= ~ISPCCDC_SYN_MODE_PACK8;1285 1286 isp_reg_writel(isp, syn_mode, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_SYN_MODE);1287 1288 /* CCDC_PAD_SOURCE_VP */1289 ccdc_config_vp(ccdc);1290 1291 /* Lens shading correction. */1292 spin_lock_irqsave(&ccdc->lsc.req_lock, flags);1293 if (ccdc->lsc.request == NULL)1294 goto unlock;1295 1296 WARN_ON(ccdc->lsc.active);1297 1298 /* Get last good LSC configuration. If it is not supported for1299 * the current active resolution discard it.1300 */1301 if (ccdc->lsc.active == NULL &&1302 __ccdc_lsc_configure(ccdc, ccdc->lsc.request) == 0) {1303 ccdc->lsc.active = ccdc->lsc.request;1304 } else {1305 list_add_tail(&ccdc->lsc.request->list, &ccdc->lsc.free_queue);1306 schedule_work(&ccdc->lsc.table_work);1307 }1308 1309 ccdc->lsc.request = NULL;1310 1311unlock:1312 spin_unlock_irqrestore(&ccdc->lsc.req_lock, flags);1313 1314 ccdc_apply_controls(ccdc);1315}1316 1317static void __ccdc_enable(struct isp_ccdc_device *ccdc, int enable)1318{1319 struct isp_device *isp = to_isp_device(ccdc);1320 1321 /* Avoid restarting the CCDC when streaming is stopping. */1322 if (enable && ccdc->stopping & CCDC_STOP_REQUEST)1323 return;1324 1325 isp_reg_clr_set(isp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_PCR,1326 ISPCCDC_PCR_EN, enable ? ISPCCDC_PCR_EN : 0);1327 1328 ccdc->running = enable;1329}1330 1331static int ccdc_disable(struct isp_ccdc_device *ccdc)1332{1333 unsigned long flags;1334 int ret = 0;1335 1336 spin_lock_irqsave(&ccdc->lock, flags);1337 if (ccdc->state == ISP_PIPELINE_STREAM_CONTINUOUS)1338 ccdc->stopping = CCDC_STOP_REQUEST;1339 if (!ccdc->running)1340 ccdc->stopping = CCDC_STOP_FINISHED;1341 spin_unlock_irqrestore(&ccdc->lock, flags);1342 1343 ret = wait_event_timeout(ccdc->wait,1344 ccdc->stopping == CCDC_STOP_FINISHED,1345 msecs_to_jiffies(2000));1346 if (ret == 0) {1347 ret = -ETIMEDOUT;1348 dev_warn(to_device(ccdc), "CCDC stop timeout!\n");1349 }1350 1351 omap3isp_sbl_disable(to_isp_device(ccdc), OMAP3_ISP_SBL_CCDC_LSC_READ);1352 1353 mutex_lock(&ccdc->ioctl_lock);1354 ccdc_lsc_free_request(ccdc, ccdc->lsc.request);1355 ccdc->lsc.request = ccdc->lsc.active;1356 ccdc->lsc.active = NULL;1357 cancel_work_sync(&ccdc->lsc.table_work);1358 ccdc_lsc_free_queue(ccdc, &ccdc->lsc.free_queue);1359 mutex_unlock(&ccdc->ioctl_lock);1360 1361 ccdc->stopping = CCDC_STOP_NOT_REQUESTED;1362 1363 return ret > 0 ? 0 : ret;1364}1365 1366static void ccdc_enable(struct isp_ccdc_device *ccdc)1367{1368 if (ccdc_lsc_is_configured(ccdc))1369 __ccdc_lsc_enable(ccdc, 1);1370 __ccdc_enable(ccdc, 1);1371}1372 1373/* -----------------------------------------------------------------------------1374 * Interrupt handling1375 */1376 1377/*1378 * ccdc_sbl_busy - Poll idle state of CCDC and related SBL memory write bits1379 * @ccdc: Pointer to ISP CCDC device.1380 *1381 * Returns zero if the CCDC is idle and the image has been written to1382 * memory, too.1383 */1384static int ccdc_sbl_busy(struct isp_ccdc_device *ccdc)1385{1386 struct isp_device *isp = to_isp_device(ccdc);1387 1388 return omap3isp_ccdc_busy(ccdc)1389 | (isp_reg_readl(isp, OMAP3_ISP_IOMEM_SBL, ISPSBL_CCDC_WR_0) &1390 ISPSBL_CCDC_WR_0_DATA_READY)1391 | (isp_reg_readl(isp, OMAP3_ISP_IOMEM_SBL, ISPSBL_CCDC_WR_1) &1392 ISPSBL_CCDC_WR_0_DATA_READY)1393 | (isp_reg_readl(isp, OMAP3_ISP_IOMEM_SBL, ISPSBL_CCDC_WR_2) &1394 ISPSBL_CCDC_WR_0_DATA_READY)1395 | (isp_reg_readl(isp, OMAP3_ISP_IOMEM_SBL, ISPSBL_CCDC_WR_3) &1396 ISPSBL_CCDC_WR_0_DATA_READY);1397}1398 1399/*1400 * ccdc_sbl_wait_idle - Wait until the CCDC and related SBL are idle1401 * @ccdc: Pointer to ISP CCDC device.1402 * @max_wait: Max retry count in us for wait for idle/busy transition.1403 */1404static int ccdc_sbl_wait_idle(struct isp_ccdc_device *ccdc,1405 unsigned int max_wait)1406{1407 unsigned int wait = 0;1408 1409 if (max_wait == 0)1410 max_wait = 10000; /* 10 ms */1411 1412 for (wait = 0; wait <= max_wait; wait++) {1413 if (!ccdc_sbl_busy(ccdc))1414 return 0;1415 1416 rmb();1417 udelay(1);1418 }1419 1420 return -EBUSY;1421}1422 1423/* ccdc_handle_stopping - Handle CCDC and/or LSC stopping sequence1424 * @ccdc: Pointer to ISP CCDC device.1425 * @event: Pointing which event trigger handler1426 *1427 * Return 1 when the event and stopping request combination is satisfied,1428 * zero otherwise.1429 */1430static int ccdc_handle_stopping(struct isp_ccdc_device *ccdc, u32 event)1431{1432 int rval = 0;1433 1434 switch ((ccdc->stopping & 3) | event) {1435 case CCDC_STOP_REQUEST | CCDC_EVENT_VD1:1436 if (ccdc->lsc.state != LSC_STATE_STOPPED)1437 __ccdc_lsc_enable(ccdc, 0);1438 __ccdc_enable(ccdc, 0);1439 ccdc->stopping = CCDC_STOP_EXECUTED;1440 return 1;1441 1442 case CCDC_STOP_EXECUTED | CCDC_EVENT_VD0:1443 ccdc->stopping |= CCDC_STOP_CCDC_FINISHED;1444 if (ccdc->lsc.state == LSC_STATE_STOPPED)1445 ccdc->stopping |= CCDC_STOP_LSC_FINISHED;1446 rval = 1;1447 break;1448 1449 case CCDC_STOP_EXECUTED | CCDC_EVENT_LSC_DONE:1450 ccdc->stopping |= CCDC_STOP_LSC_FINISHED;1451 rval = 1;1452 break;1453 1454 case CCDC_STOP_EXECUTED | CCDC_EVENT_VD1:1455 return 1;1456 }1457 1458 if (ccdc->stopping == CCDC_STOP_FINISHED) {1459 wake_up(&ccdc->wait);1460 rval = 1;1461 }1462 1463 return rval;1464}1465 1466static void ccdc_hs_vs_isr(struct isp_ccdc_device *ccdc)1467{1468 struct isp_pipeline *pipe = to_isp_pipeline(&ccdc->subdev.entity);1469 struct video_device *vdev = ccdc->subdev.devnode;1470 struct v4l2_event event;1471 1472 /* Frame number propagation */1473 atomic_inc(&pipe->frame_number);1474 1475 memset(&event, 0, sizeof(event));1476 event.type = V4L2_EVENT_FRAME_SYNC;1477 event.u.frame_sync.frame_sequence = atomic_read(&pipe->frame_number);1478 1479 v4l2_event_queue(vdev, &event);1480}1481 1482/*1483 * ccdc_lsc_isr - Handle LSC events1484 * @ccdc: Pointer to ISP CCDC device.1485 * @events: LSC events1486 */1487static void ccdc_lsc_isr(struct isp_ccdc_device *ccdc, u32 events)1488{1489 unsigned long flags;1490 1491 if (events & IRQ0STATUS_CCDC_LSC_PREF_ERR_IRQ) {1492 struct isp_pipeline *pipe =1493 to_isp_pipeline(&ccdc->subdev.entity);1494 1495 ccdc_lsc_error_handler(ccdc);1496 pipe->error = true;1497 dev_dbg(to_device(ccdc), "lsc prefetch error\n");1498 }1499 1500 if (!(events & IRQ0STATUS_CCDC_LSC_DONE_IRQ))1501 return;1502 1503 /* LSC_DONE interrupt occur, there are two cases1504 * 1. stopping for reconfiguration1505 * 2. stopping because of STREAM OFF command1506 */1507 spin_lock_irqsave(&ccdc->lsc.req_lock, flags);1508 1509 if (ccdc->lsc.state == LSC_STATE_STOPPING)1510 ccdc->lsc.state = LSC_STATE_STOPPED;1511 1512 if (ccdc_handle_stopping(ccdc, CCDC_EVENT_LSC_DONE))1513 goto done;1514 1515 if (ccdc->lsc.state != LSC_STATE_RECONFIG)1516 goto done;1517 1518 /* LSC is in STOPPING state, change to the new state */1519 ccdc->lsc.state = LSC_STATE_STOPPED;1520 1521 /* This is an exception. Start of frame and LSC_DONE interrupt1522 * have been received on the same time. Skip this event and wait1523 * for better times.1524 */1525 if (events & IRQ0STATUS_HS_VS_IRQ)1526 goto done;1527 1528 /* The LSC engine is stopped at this point. Enable it if there's a1529 * pending request.1530 */1531 if (ccdc->lsc.request == NULL)1532 goto done;1533 1534 ccdc_lsc_enable(ccdc);1535 1536done:1537 spin_unlock_irqrestore(&ccdc->lsc.req_lock, flags);1538}1539 1540/*1541 * Check whether the CCDC has captured all fields necessary to complete the1542 * buffer.1543 */1544static bool ccdc_has_all_fields(struct isp_ccdc_device *ccdc)1545{1546 struct isp_pipeline *pipe = to_isp_pipeline(&ccdc->subdev.entity);1547 struct isp_device *isp = to_isp_device(ccdc);1548 enum v4l2_field of_field = ccdc->formats[CCDC_PAD_SOURCE_OF].field;1549 enum v4l2_field field;1550 1551 /* When the input is progressive fields don't matter. */1552 if (of_field == V4L2_FIELD_NONE)1553 return true;1554 1555 /* Read the current field identifier. */1556 field = isp_reg_readl(isp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_SYN_MODE)1557 & ISPCCDC_SYN_MODE_FLDSTAT1558 ? V4L2_FIELD_BOTTOM : V4L2_FIELD_TOP;1559 1560 /* When capturing fields in alternate order just store the current field1561 * identifier in the pipeline.1562 */1563 if (of_field == V4L2_FIELD_ALTERNATE) {1564 pipe->field = field;1565 return true;1566 }1567 1568 /* The format is interlaced. Make sure we've captured both fields. */1569 ccdc->fields |= field == V4L2_FIELD_BOTTOM1570 ? CCDC_FIELD_BOTTOM : CCDC_FIELD_TOP;1571 1572 if (ccdc->fields != CCDC_FIELD_BOTH)1573 return false;1574 1575 /* Verify that the field just captured corresponds to the last field1576 * needed based on the desired field order.1577 */1578 if ((of_field == V4L2_FIELD_INTERLACED_TB && field == V4L2_FIELD_TOP) ||1579 (of_field == V4L2_FIELD_INTERLACED_BT && field == V4L2_FIELD_BOTTOM))1580 return false;1581 1582 /* The buffer can be completed, reset the fields for the next buffer. */1583 ccdc->fields = 0;1584 1585 return true;1586}1587 1588static int ccdc_isr_buffer(struct isp_ccdc_device *ccdc)1589{1590 struct isp_pipeline *pipe = to_isp_pipeline(&ccdc->subdev.entity);1591 struct isp_device *isp = to_isp_device(ccdc);1592 struct isp_buffer *buffer;1593 1594 /* The CCDC generates VD0 interrupts even when disabled (the datasheet1595 * doesn't explicitly state if that's supposed to happen or not, so it1596 * can be considered as a hardware bug or as a feature, but we have to1597 * deal with it anyway). Disabling the CCDC when no buffer is available1598 * would thus not be enough, we need to handle the situation explicitly.1599 */1600 if (list_empty(&ccdc->video_out.dmaqueue))1601 return 0;1602 1603 /* We're in continuous mode, and memory writes were disabled due to a1604 * buffer underrun. Re-enable them now that we have a buffer. The buffer1605 * address has been set in ccdc_video_queue.1606 */1607 if (ccdc->state == ISP_PIPELINE_STREAM_CONTINUOUS && ccdc->underrun) {1608 ccdc->underrun = 0;1609 return 1;1610 }1611 1612 /* Wait for the CCDC to become idle. */1613 if (ccdc_sbl_wait_idle(ccdc, 1000)) {1614 dev_info(isp->dev, "CCDC won't become idle!\n");1615 media_entity_enum_set(&isp->crashed, &ccdc->subdev.entity);1616 omap3isp_pipeline_cancel_stream(pipe);1617 return 0;1618 }1619 1620 /* Don't restart CCDC if we're just about to stop streaming. */1621 if (ccdc->state == ISP_PIPELINE_STREAM_CONTINUOUS &&1622 ccdc->stopping & CCDC_STOP_REQUEST)1623 return 0;1624 1625 if (!ccdc_has_all_fields(ccdc))1626 return 1;1627 1628 buffer = omap3isp_video_buffer_next(&ccdc->video_out);1629 if (buffer != NULL)1630 ccdc_set_outaddr(ccdc, buffer->dma);1631 1632 pipe->state |= ISP_PIPELINE_IDLE_OUTPUT;1633 1634 if (ccdc->state == ISP_PIPELINE_STREAM_SINGLESHOT &&1635 isp_pipeline_ready(pipe))1636 omap3isp_pipeline_set_stream(pipe,1637 ISP_PIPELINE_STREAM_SINGLESHOT);1638 1639 return buffer != NULL;1640}1641 1642/*1643 * ccdc_vd0_isr - Handle VD0 event1644 * @ccdc: Pointer to ISP CCDC device.1645 *1646 * Executes LSC deferred enablement before next frame starts.1647 */1648static void ccdc_vd0_isr(struct isp_ccdc_device *ccdc)1649{1650 unsigned long flags;1651 int restart = 0;1652 1653 /* In BT.656 mode the CCDC doesn't generate an HS/VS interrupt. We thus1654 * need to increment the frame counter here.1655 */1656 if (ccdc->bt656) {1657 struct isp_pipeline *pipe =1658 to_isp_pipeline(&ccdc->subdev.entity);1659 1660 atomic_inc(&pipe->frame_number);1661 }1662 1663 /* Emulate a VD1 interrupt for BT.656 mode, as we can't stop the CCDC in1664 * the VD1 interrupt handler in that mode without risking a CCDC stall1665 * if a short frame is received.1666 */1667 if (ccdc->bt656) {1668 spin_lock_irqsave(&ccdc->lock, flags);1669 if (ccdc->state == ISP_PIPELINE_STREAM_CONTINUOUS &&1670 ccdc->output & CCDC_OUTPUT_MEMORY) {1671 if (ccdc->lsc.state != LSC_STATE_STOPPED)1672 __ccdc_lsc_enable(ccdc, 0);1673 __ccdc_enable(ccdc, 0);1674 }1675 ccdc_handle_stopping(ccdc, CCDC_EVENT_VD1);1676 spin_unlock_irqrestore(&ccdc->lock, flags);1677 }1678 1679 spin_lock_irqsave(&ccdc->lock, flags);1680 if (ccdc_handle_stopping(ccdc, CCDC_EVENT_VD0)) {1681 spin_unlock_irqrestore(&ccdc->lock, flags);1682 return;1683 }1684 1685 if (ccdc->output & CCDC_OUTPUT_MEMORY)1686 restart = ccdc_isr_buffer(ccdc);1687 1688 if (!ccdc->shadow_update)1689 ccdc_apply_controls(ccdc);1690 spin_unlock_irqrestore(&ccdc->lock, flags);1691 1692 if (restart)1693 ccdc_enable(ccdc);1694}1695 1696/*1697 * ccdc_vd1_isr - Handle VD1 event1698 * @ccdc: Pointer to ISP CCDC device.1699 */1700static void ccdc_vd1_isr(struct isp_ccdc_device *ccdc)1701{1702 unsigned long flags;1703 1704 /* In BT.656 mode the synchronization signals are generated by the CCDC1705 * from the embedded sync codes. The VD0 and VD1 interrupts are thus1706 * only triggered when the CCDC is enabled, unlike external sync mode1707 * where the line counter runs even when the CCDC is stopped. We can't1708 * disable the CCDC at VD1 time, as no VD0 interrupt would be generated1709 * for a short frame, which would result in the CCDC being stopped and1710 * no VD interrupt generated anymore. The CCDC is stopped from the VD01711 * interrupt handler instead for BT.656.1712 */1713 if (ccdc->bt656)1714 return;1715 1716 spin_lock_irqsave(&ccdc->lsc.req_lock, flags);1717 1718 /*1719 * Depending on the CCDC pipeline state, CCDC stopping should be1720 * handled differently. In SINGLESHOT we emulate an internal CCDC1721 * stopping because the CCDC hw works only in continuous mode.1722 * When CONTINUOUS pipeline state is used and the CCDC writes it's1723 * data to memory the CCDC and LSC are stopped immediately but1724 * without change the CCDC stopping state machine. The CCDC1725 * stopping state machine should be used only when user request1726 * for stopping is received (SINGLESHOT is an exception).1727 */1728 switch (ccdc->state) {1729 case ISP_PIPELINE_STREAM_SINGLESHOT:1730 ccdc->stopping = CCDC_STOP_REQUEST;1731 break;1732 1733 case ISP_PIPELINE_STREAM_CONTINUOUS:1734 if (ccdc->output & CCDC_OUTPUT_MEMORY) {1735 if (ccdc->lsc.state != LSC_STATE_STOPPED)1736 __ccdc_lsc_enable(ccdc, 0);1737 __ccdc_enable(ccdc, 0);1738 }1739 break;1740 1741 case ISP_PIPELINE_STREAM_STOPPED:1742 break;1743 }1744 1745 if (ccdc_handle_stopping(ccdc, CCDC_EVENT_VD1))1746 goto done;1747 1748 if (ccdc->lsc.request == NULL)1749 goto done;1750 1751 /*1752 * LSC need to be reconfigured. Stop it here and on next LSC_DONE IRQ1753 * do the appropriate changes in registers1754 */1755 if (ccdc->lsc.state == LSC_STATE_RUNNING) {1756 __ccdc_lsc_enable(ccdc, 0);1757 ccdc->lsc.state = LSC_STATE_RECONFIG;1758 goto done;1759 }1760 1761 /* LSC has been in STOPPED state, enable it */1762 if (ccdc->lsc.state == LSC_STATE_STOPPED)1763 ccdc_lsc_enable(ccdc);1764 1765done:1766 spin_unlock_irqrestore(&ccdc->lsc.req_lock, flags);1767}1768 1769/*1770 * omap3isp_ccdc_isr - Configure CCDC during interframe time.1771 * @ccdc: Pointer to ISP CCDC device.1772 * @events: CCDC events1773 */1774int omap3isp_ccdc_isr(struct isp_ccdc_device *ccdc, u32 events)1775{1776 if (ccdc->state == ISP_PIPELINE_STREAM_STOPPED)1777 return 0;1778 1779 if (events & IRQ0STATUS_CCDC_VD1_IRQ)1780 ccdc_vd1_isr(ccdc);1781 1782 ccdc_lsc_isr(ccdc, events);1783 1784 if (events & IRQ0STATUS_CCDC_VD0_IRQ)1785 ccdc_vd0_isr(ccdc);1786 1787 if (events & IRQ0STATUS_HS_VS_IRQ)1788 ccdc_hs_vs_isr(ccdc);1789 1790 return 0;1791}1792 1793/* -----------------------------------------------------------------------------1794 * ISP video operations1795 */1796 1797static int ccdc_video_queue(struct isp_video *video, struct isp_buffer *buffer)1798{1799 struct isp_ccdc_device *ccdc = &video->isp->isp_ccdc;1800 unsigned long flags;1801 bool restart = false;1802 1803 if (!(ccdc->output & CCDC_OUTPUT_MEMORY))1804 return -ENODEV;1805 1806 ccdc_set_outaddr(ccdc, buffer->dma);1807 1808 /* We now have a buffer queued on the output, restart the pipeline1809 * on the next CCDC interrupt if running in continuous mode (or when1810 * starting the stream) in external sync mode, or immediately in BT.6561811 * sync mode as no CCDC interrupt is generated when the CCDC is stopped1812 * in that case.1813 */1814 spin_lock_irqsave(&ccdc->lock, flags);1815 if (ccdc->state == ISP_PIPELINE_STREAM_CONTINUOUS && !ccdc->running &&1816 ccdc->bt656)1817 restart = true;1818 else1819 ccdc->underrun = 1;1820 spin_unlock_irqrestore(&ccdc->lock, flags);1821 1822 if (restart)1823 ccdc_enable(ccdc);1824 1825 return 0;1826}1827 1828static const struct isp_video_operations ccdc_video_ops = {1829 .queue = ccdc_video_queue,1830};1831 1832/* -----------------------------------------------------------------------------1833 * V4L2 subdev operations1834 */1835 1836/*1837 * ccdc_ioctl - CCDC module private ioctl's1838 * @sd: ISP CCDC V4L2 subdevice1839 * @cmd: ioctl command1840 * @arg: ioctl argument1841 *1842 * Return 0 on success or a negative error code otherwise.1843 */1844static long ccdc_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg)1845{1846 struct isp_ccdc_device *ccdc = v4l2_get_subdevdata(sd);1847 int ret;1848 1849 switch (cmd) {1850 case VIDIOC_OMAP3ISP_CCDC_CFG:1851 mutex_lock(&ccdc->ioctl_lock);1852 ret = ccdc_config(ccdc, arg);1853 mutex_unlock(&ccdc->ioctl_lock);1854 break;1855 1856 default:1857 return -ENOIOCTLCMD;1858 }1859 1860 return ret;1861}1862 1863static int ccdc_subscribe_event(struct v4l2_subdev *sd, struct v4l2_fh *fh,1864 struct v4l2_event_subscription *sub)1865{1866 if (sub->type != V4L2_EVENT_FRAME_SYNC)1867 return -EINVAL;1868 1869 /* line number is zero at frame start */1870 if (sub->id != 0)1871 return -EINVAL;1872 1873 return v4l2_event_subscribe(fh, sub, OMAP3ISP_CCDC_NEVENTS, NULL);1874}1875 1876static int ccdc_unsubscribe_event(struct v4l2_subdev *sd, struct v4l2_fh *fh,1877 struct v4l2_event_subscription *sub)1878{1879 return v4l2_event_unsubscribe(fh, sub);1880}1881 1882/*1883 * ccdc_set_stream - Enable/Disable streaming on the CCDC module1884 * @sd: ISP CCDC V4L2 subdevice1885 * @enable: Enable/disable stream1886 *1887 * When writing to memory, the CCDC hardware can't be enabled without a memory1888 * buffer to write to. As the s_stream operation is called in response to a1889 * STREAMON call without any buffer queued yet, just update the enabled field1890 * and return immediately. The CCDC will be enabled in ccdc_isr_buffer().1891 *1892 * When not writing to memory enable the CCDC immediately.1893 */1894static int ccdc_set_stream(struct v4l2_subdev *sd, int enable)1895{1896 struct isp_ccdc_device *ccdc = v4l2_get_subdevdata(sd);1897 struct isp_device *isp = to_isp_device(ccdc);1898 int ret = 0;1899 1900 if (ccdc->state == ISP_PIPELINE_STREAM_STOPPED) {1901 if (enable == ISP_PIPELINE_STREAM_STOPPED)1902 return 0;1903 1904 omap3isp_subclk_enable(isp, OMAP3_ISP_SUBCLK_CCDC);1905 isp_reg_set(isp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_CFG,1906 ISPCCDC_CFG_VDLC);1907 1908 ccdc_configure(ccdc);1909 1910 ccdc_print_status(ccdc);1911 }1912 1913 switch (enable) {1914 case ISP_PIPELINE_STREAM_CONTINUOUS:1915 if (ccdc->output & CCDC_OUTPUT_MEMORY)1916 omap3isp_sbl_enable(isp, OMAP3_ISP_SBL_CCDC_WRITE);1917 1918 if (ccdc->underrun || !(ccdc->output & CCDC_OUTPUT_MEMORY))1919 ccdc_enable(ccdc);1920 1921 ccdc->underrun = 0;1922 break;1923 1924 case ISP_PIPELINE_STREAM_SINGLESHOT:1925 if (ccdc->output & CCDC_OUTPUT_MEMORY &&1926 ccdc->state != ISP_PIPELINE_STREAM_SINGLESHOT)1927 omap3isp_sbl_enable(isp, OMAP3_ISP_SBL_CCDC_WRITE);1928 1929 ccdc_enable(ccdc);1930 break;1931 1932 case ISP_PIPELINE_STREAM_STOPPED:1933 ret = ccdc_disable(ccdc);1934 if (ccdc->output & CCDC_OUTPUT_MEMORY)1935 omap3isp_sbl_disable(isp, OMAP3_ISP_SBL_CCDC_WRITE);1936 omap3isp_subclk_disable(isp, OMAP3_ISP_SUBCLK_CCDC);1937 ccdc->underrun = 0;1938 break;1939 }1940 1941 ccdc->state = enable;1942 return ret;1943}1944 1945static struct v4l2_mbus_framefmt *1946__ccdc_get_format(struct isp_ccdc_device *ccdc,1947 struct v4l2_subdev_state *sd_state,1948 unsigned int pad, enum v4l2_subdev_format_whence which)1949{1950 if (which == V4L2_SUBDEV_FORMAT_TRY)1951 return v4l2_subdev_state_get_format(sd_state, pad);1952 else1953 return &ccdc->formats[pad];1954}1955 1956static struct v4l2_rect *1957__ccdc_get_crop(struct isp_ccdc_device *ccdc,1958 struct v4l2_subdev_state *sd_state,1959 enum v4l2_subdev_format_whence which)1960{1961 if (which == V4L2_SUBDEV_FORMAT_TRY)1962 return v4l2_subdev_state_get_crop(sd_state,1963 CCDC_PAD_SOURCE_OF);1964 else1965 return &ccdc->crop;1966}1967 1968/*1969 * ccdc_try_format - Try video format on a pad1970 * @ccdc: ISP CCDC device1971 * @sd_state: V4L2 subdev state1972 * @pad: Pad number1973 * @fmt: Format1974 */1975static void1976ccdc_try_format(struct isp_ccdc_device *ccdc,1977 struct v4l2_subdev_state *sd_state,1978 unsigned int pad, struct v4l2_mbus_framefmt *fmt,1979 enum v4l2_subdev_format_whence which)1980{1981 const struct isp_format_info *info;1982 u32 pixelcode;1983 unsigned int width = fmt->width;1984 unsigned int height = fmt->height;1985 struct v4l2_rect *crop;1986 enum v4l2_field field;1987 unsigned int i;1988 1989 switch (pad) {1990 case CCDC_PAD_SINK:1991 for (i = 0; i < ARRAY_SIZE(ccdc_fmts); i++) {1992 if (fmt->code == ccdc_fmts[i])1993 break;1994 }1995 1996 /* If not found, use SGRBG10 as default */1997 if (i >= ARRAY_SIZE(ccdc_fmts))1998 fmt->code = MEDIA_BUS_FMT_SGRBG10_1X10;1999 2000 /* Clamp the input size. */2001 fmt->width = clamp_t(u32, width, 32, 4096);2002 fmt->height = clamp_t(u32, height, 32, 4096);2003 2004 /* Default to progressive field order. */2005 if (fmt->field == V4L2_FIELD_ANY)2006 fmt->field = V4L2_FIELD_NONE;2007 2008 break;2009 2010 case CCDC_PAD_SOURCE_OF:2011 pixelcode = fmt->code;2012 field = fmt->field;2013 *fmt = *__ccdc_get_format(ccdc, sd_state, CCDC_PAD_SINK,2014 which);2015 2016 /* In SYNC mode the bridge converts YUV formats from 2X8 to2017 * 1X16. In BT.656 no such conversion occurs. As we don't know2018 * at this point whether the source will use SYNC or BT.656 mode2019 * let's pretend the conversion always occurs. The CCDC will be2020 * configured to pack bytes in BT.656, hiding the inaccuracy.2021 * In all cases bytes can be swapped.2022 */2023 if (fmt->code == MEDIA_BUS_FMT_YUYV8_2X8 ||2024 fmt->code == MEDIA_BUS_FMT_UYVY8_2X8) {2025 /* Use the user requested format if YUV. */2026 if (pixelcode == MEDIA_BUS_FMT_YUYV8_2X8 ||2027 pixelcode == MEDIA_BUS_FMT_UYVY8_2X8 ||2028 pixelcode == MEDIA_BUS_FMT_YUYV8_1X16 ||2029 pixelcode == MEDIA_BUS_FMT_UYVY8_1X16)2030 fmt->code = pixelcode;2031 2032 if (fmt->code == MEDIA_BUS_FMT_YUYV8_2X8)2033 fmt->code = MEDIA_BUS_FMT_YUYV8_1X16;2034 else if (fmt->code == MEDIA_BUS_FMT_UYVY8_2X8)2035 fmt->code = MEDIA_BUS_FMT_UYVY8_1X16;2036 }2037 2038 /* Hardcode the output size to the crop rectangle size. */2039 crop = __ccdc_get_crop(ccdc, sd_state, which);2040 fmt->width = crop->width;2041 fmt->height = crop->height;2042 2043 /* When input format is interlaced with alternating fields the2044 * CCDC can interleave the fields.2045 */2046 if (fmt->field == V4L2_FIELD_ALTERNATE &&2047 (field == V4L2_FIELD_INTERLACED_TB ||2048 field == V4L2_FIELD_INTERLACED_BT)) {2049 fmt->field = field;2050 fmt->height *= 2;2051 }2052 2053 break;2054 2055 case CCDC_PAD_SOURCE_VP:2056 *fmt = *__ccdc_get_format(ccdc, sd_state, CCDC_PAD_SINK,2057 which);2058 2059 /* The video port interface truncates the data to 10 bits. */2060 info = omap3isp_video_format_info(fmt->code);2061 fmt->code = info->truncated;2062 2063 /* YUV formats are not supported by the video port. */2064 if (fmt->code == MEDIA_BUS_FMT_YUYV8_2X8 ||2065 fmt->code == MEDIA_BUS_FMT_UYVY8_2X8)2066 fmt->code = 0;2067 2068 /* The number of lines that can be clocked out from the video2069 * port output must be at least one line less than the number2070 * of input lines.2071 */2072 fmt->width = clamp_t(u32, width, 32, fmt->width);2073 fmt->height = clamp_t(u32, height, 32, fmt->height - 1);2074 break;2075 }2076 2077 /* Data is written to memory unpacked, each 10-bit or 12-bit pixel is2078 * stored on 2 bytes.2079 */2080 fmt->colorspace = V4L2_COLORSPACE_SRGB;2081}2082 2083/*2084 * ccdc_try_crop - Validate a crop rectangle2085 * @ccdc: ISP CCDC device2086 * @sink: format on the sink pad2087 * @crop: crop rectangle to be validated2088 */2089static void ccdc_try_crop(struct isp_ccdc_device *ccdc,2090 const struct v4l2_mbus_framefmt *sink,2091 struct v4l2_rect *crop)2092{2093 const struct isp_format_info *info;2094 unsigned int max_width;2095 2096 /* For Bayer formats, restrict left/top and width/height to even values2097 * to keep the Bayer pattern.2098 */2099 info = omap3isp_video_format_info(sink->code);2100 if (info->flavor != MEDIA_BUS_FMT_Y8_1X8) {2101 crop->left &= ~1;2102 crop->top &= ~1;2103 }2104 2105 crop->left = clamp_t(u32, crop->left, 0, sink->width - CCDC_MIN_WIDTH);2106 crop->top = clamp_t(u32, crop->top, 0, sink->height - CCDC_MIN_HEIGHT);2107 2108 /* The data formatter truncates the number of horizontal output pixels2109 * to a multiple of 16. To avoid clipping data, allow callers to request2110 * an output size bigger than the input size up to the nearest multiple2111 * of 16.2112 */2113 max_width = (sink->width - crop->left + 15) & ~15;2114 crop->width = clamp_t(u32, crop->width, CCDC_MIN_WIDTH, max_width)2115 & ~15;2116 crop->height = clamp_t(u32, crop->height, CCDC_MIN_HEIGHT,2117 sink->height - crop->top);2118 2119 /* Odd width/height values don't make sense for Bayer formats. */2120 if (info->flavor != MEDIA_BUS_FMT_Y8_1X8) {2121 crop->width &= ~1;2122 crop->height &= ~1;2123 }2124}2125 2126/*2127 * ccdc_enum_mbus_code - Handle pixel format enumeration2128 * @sd : pointer to v4l2 subdev structure2129 * @sd_state: V4L2 subdev state2130 * @code : pointer to v4l2_subdev_mbus_code_enum structure2131 * return -EINVAL or zero on success2132 */2133static int ccdc_enum_mbus_code(struct v4l2_subdev *sd,2134 struct v4l2_subdev_state *sd_state,2135 struct v4l2_subdev_mbus_code_enum *code)2136{2137 struct isp_ccdc_device *ccdc = v4l2_get_subdevdata(sd);2138 struct v4l2_mbus_framefmt *format;2139 2140 switch (code->pad) {2141 case CCDC_PAD_SINK:2142 if (code->index >= ARRAY_SIZE(ccdc_fmts))2143 return -EINVAL;2144 2145 code->code = ccdc_fmts[code->index];2146 break;2147 2148 case CCDC_PAD_SOURCE_OF:2149 format = __ccdc_get_format(ccdc, sd_state, code->pad,2150 code->which);2151 2152 if (format->code == MEDIA_BUS_FMT_YUYV8_2X8 ||2153 format->code == MEDIA_BUS_FMT_UYVY8_2X8) {2154 /* In YUV mode the CCDC can swap bytes. */2155 if (code->index == 0)2156 code->code = MEDIA_BUS_FMT_YUYV8_1X16;2157 else if (code->index == 1)2158 code->code = MEDIA_BUS_FMT_UYVY8_1X16;2159 else2160 return -EINVAL;2161 } else {2162 /* In raw mode, no configurable format confversion is2163 * available.2164 */2165 if (code->index == 0)2166 code->code = format->code;2167 else2168 return -EINVAL;2169 }2170 break;2171 2172 case CCDC_PAD_SOURCE_VP:2173 /* The CCDC supports no configurable format conversion2174 * compatible with the video port. Enumerate a single output2175 * format code.2176 */2177 if (code->index != 0)2178 return -EINVAL;2179 2180 format = __ccdc_get_format(ccdc, sd_state, code->pad,2181 code->which);2182 2183 /* A pixel code equal to 0 means that the video port doesn't2184 * support the input format. Don't enumerate any pixel code.2185 */2186 if (format->code == 0)2187 return -EINVAL;2188 2189 code->code = format->code;2190 break;2191 2192 default:2193 return -EINVAL;2194 }2195 2196 return 0;2197}2198 2199static int ccdc_enum_frame_size(struct v4l2_subdev *sd,2200 struct v4l2_subdev_state *sd_state,2201 struct v4l2_subdev_frame_size_enum *fse)2202{2203 struct isp_ccdc_device *ccdc = v4l2_get_subdevdata(sd);2204 struct v4l2_mbus_framefmt format;2205 2206 if (fse->index != 0)2207 return -EINVAL;2208 2209 format.code = fse->code;2210 format.width = 1;2211 format.height = 1;2212 ccdc_try_format(ccdc, sd_state, fse->pad, &format, fse->which);2213 fse->min_width = format.width;2214 fse->min_height = format.height;2215 2216 if (format.code != fse->code)2217 return -EINVAL;2218 2219 format.code = fse->code;2220 format.width = -1;2221 format.height = -1;2222 ccdc_try_format(ccdc, sd_state, fse->pad, &format, fse->which);2223 fse->max_width = format.width;2224 fse->max_height = format.height;2225 2226 return 0;2227}2228 2229/*2230 * ccdc_get_selection - Retrieve a selection rectangle on a pad2231 * @sd: ISP CCDC V4L2 subdevice2232 * @sd_state: V4L2 subdev state2233 * @sel: Selection rectangle2234 *2235 * The only supported rectangles are the crop rectangles on the output formatter2236 * source pad.2237 *2238 * Return 0 on success or a negative error code otherwise.2239 */2240static int ccdc_get_selection(struct v4l2_subdev *sd,2241 struct v4l2_subdev_state *sd_state,2242 struct v4l2_subdev_selection *sel)2243{2244 struct isp_ccdc_device *ccdc = v4l2_get_subdevdata(sd);2245 struct v4l2_mbus_framefmt *format;2246 2247 if (sel->pad != CCDC_PAD_SOURCE_OF)2248 return -EINVAL;2249 2250 switch (sel->target) {2251 case V4L2_SEL_TGT_CROP_BOUNDS:2252 sel->r.left = 0;2253 sel->r.top = 0;2254 sel->r.width = INT_MAX;2255 sel->r.height = INT_MAX;2256 2257 format = __ccdc_get_format(ccdc, sd_state, CCDC_PAD_SINK,2258 sel->which);2259 ccdc_try_crop(ccdc, format, &sel->r);2260 break;2261 2262 case V4L2_SEL_TGT_CROP:2263 sel->r = *__ccdc_get_crop(ccdc, sd_state, sel->which);2264 break;2265 2266 default:2267 return -EINVAL;2268 }2269 2270 return 0;2271}2272 2273/*2274 * ccdc_set_selection - Set a selection rectangle on a pad2275 * @sd: ISP CCDC V4L2 subdevice2276 * @sd_state: V4L2 subdev state2277 * @sel: Selection rectangle2278 *2279 * The only supported rectangle is the actual crop rectangle on the output2280 * formatter source pad.2281 *2282 * Return 0 on success or a negative error code otherwise.2283 */2284static int ccdc_set_selection(struct v4l2_subdev *sd,2285 struct v4l2_subdev_state *sd_state,2286 struct v4l2_subdev_selection *sel)2287{2288 struct isp_ccdc_device *ccdc = v4l2_get_subdevdata(sd);2289 struct v4l2_mbus_framefmt *format;2290 2291 if (sel->target != V4L2_SEL_TGT_CROP ||2292 sel->pad != CCDC_PAD_SOURCE_OF)2293 return -EINVAL;2294 2295 /* The crop rectangle can't be changed while streaming. */2296 if (ccdc->state != ISP_PIPELINE_STREAM_STOPPED)2297 return -EBUSY;2298 2299 /* Modifying the crop rectangle always changes the format on the source2300 * pad. If the KEEP_CONFIG flag is set, just return the current crop2301 * rectangle.2302 */2303 if (sel->flags & V4L2_SEL_FLAG_KEEP_CONFIG) {2304 sel->r = *__ccdc_get_crop(ccdc, sd_state, sel->which);2305 return 0;2306 }2307 2308 format = __ccdc_get_format(ccdc, sd_state, CCDC_PAD_SINK, sel->which);2309 ccdc_try_crop(ccdc, format, &sel->r);2310 *__ccdc_get_crop(ccdc, sd_state, sel->which) = sel->r;2311 2312 /* Update the source format. */2313 format = __ccdc_get_format(ccdc, sd_state, CCDC_PAD_SOURCE_OF,2314 sel->which);2315 ccdc_try_format(ccdc, sd_state, CCDC_PAD_SOURCE_OF, format,2316 sel->which);2317 2318 return 0;2319}2320 2321/*2322 * ccdc_get_format - Retrieve the video format on a pad2323 * @sd : ISP CCDC V4L2 subdevice2324 * @sd_state: V4L2 subdev state2325 * @fmt: Format2326 *2327 * Return 0 on success or -EINVAL if the pad is invalid or doesn't correspond2328 * to the format type.2329 */2330static int ccdc_get_format(struct v4l2_subdev *sd,2331 struct v4l2_subdev_state *sd_state,2332 struct v4l2_subdev_format *fmt)2333{2334 struct isp_ccdc_device *ccdc = v4l2_get_subdevdata(sd);2335 struct v4l2_mbus_framefmt *format;2336 2337 format = __ccdc_get_format(ccdc, sd_state, fmt->pad, fmt->which);2338 if (format == NULL)2339 return -EINVAL;2340 2341 fmt->format = *format;2342 return 0;2343}2344 2345/*2346 * ccdc_set_format - Set the video format on a pad2347 * @sd : ISP CCDC V4L2 subdevice2348 * @sd_state: V4L2 subdev state2349 * @fmt: Format2350 *2351 * Return 0 on success or -EINVAL if the pad is invalid or doesn't correspond2352 * to the format type.2353 */2354static int ccdc_set_format(struct v4l2_subdev *sd,2355 struct v4l2_subdev_state *sd_state,2356 struct v4l2_subdev_format *fmt)2357{2358 struct isp_ccdc_device *ccdc = v4l2_get_subdevdata(sd);2359 struct v4l2_mbus_framefmt *format;2360 struct v4l2_rect *crop;2361 2362 format = __ccdc_get_format(ccdc, sd_state, fmt->pad, fmt->which);2363 if (format == NULL)2364 return -EINVAL;2365 2366 ccdc_try_format(ccdc, sd_state, fmt->pad, &fmt->format, fmt->which);2367 *format = fmt->format;2368 2369 /* Propagate the format from sink to source */2370 if (fmt->pad == CCDC_PAD_SINK) {2371 /* Reset the crop rectangle. */2372 crop = __ccdc_get_crop(ccdc, sd_state, fmt->which);2373 crop->left = 0;2374 crop->top = 0;2375 crop->width = fmt->format.width;2376 crop->height = fmt->format.height;2377 2378 ccdc_try_crop(ccdc, &fmt->format, crop);2379 2380 /* Update the source formats. */2381 format = __ccdc_get_format(ccdc, sd_state, CCDC_PAD_SOURCE_OF,2382 fmt->which);2383 *format = fmt->format;2384 ccdc_try_format(ccdc, sd_state, CCDC_PAD_SOURCE_OF, format,2385 fmt->which);2386 2387 format = __ccdc_get_format(ccdc, sd_state, CCDC_PAD_SOURCE_VP,2388 fmt->which);2389 *format = fmt->format;2390 ccdc_try_format(ccdc, sd_state, CCDC_PAD_SOURCE_VP, format,2391 fmt->which);2392 }2393 2394 return 0;2395}2396 2397/*2398 * Decide whether desired output pixel code can be obtained with2399 * the lane shifter by shifting the input pixel code.2400 * @in: input pixelcode to shifter2401 * @out: output pixelcode from shifter2402 * @additional_shift: # of bits the sensor's LSB is offset from CAMEXT[0]2403 *2404 * return true if the combination is possible2405 * return false otherwise2406 */2407static bool ccdc_is_shiftable(u32 in, u32 out, unsigned int additional_shift)2408{2409 const struct isp_format_info *in_info, *out_info;2410 2411 if (in == out)2412 return true;2413 2414 in_info = omap3isp_video_format_info(in);2415 out_info = omap3isp_video_format_info(out);2416 2417 if ((in_info->flavor == 0) || (out_info->flavor == 0))2418 return false;2419 2420 if (in_info->flavor != out_info->flavor)2421 return false;2422 2423 return in_info->width - out_info->width + additional_shift <= 6;2424}2425 2426static int ccdc_link_validate(struct v4l2_subdev *sd,2427 struct media_link *link,2428 struct v4l2_subdev_format *source_fmt,2429 struct v4l2_subdev_format *sink_fmt)2430{2431 struct isp_ccdc_device *ccdc = v4l2_get_subdevdata(sd);2432 unsigned long parallel_shift;2433 2434 /* Check if the two ends match */2435 if (source_fmt->format.width != sink_fmt->format.width ||2436 source_fmt->format.height != sink_fmt->format.height)2437 return -EPIPE;2438 2439 /* We've got a parallel sensor here. */2440 if (ccdc->input == CCDC_INPUT_PARALLEL) {2441 struct v4l2_subdev *sd =2442 media_entity_to_v4l2_subdev(link->source->entity);2443 struct isp_bus_cfg *bus_cfg;2444 2445 bus_cfg = v4l2_subdev_to_bus_cfg(sd);2446 if (WARN_ON(!bus_cfg))2447 return -EPIPE;2448 2449 parallel_shift = bus_cfg->bus.parallel.data_lane_shift;2450 } else {2451 parallel_shift = 0;2452 }2453 2454 /* Lane shifter may be used to drop bits on CCDC sink pad */2455 if (!ccdc_is_shiftable(source_fmt->format.code,2456 sink_fmt->format.code, parallel_shift))2457 return -EPIPE;2458 2459 return 0;2460}2461 2462/*2463 * ccdc_init_formats - Initialize formats on all pads2464 * @sd: ISP CCDC V4L2 subdevice2465 * @fh: V4L2 subdev file handle2466 *2467 * Initialize all pad formats with default values. If fh is not NULL, try2468 * formats are initialized on the file handle. Otherwise active formats are2469 * initialized on the device.2470 */2471static int ccdc_init_formats(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)2472{2473 struct v4l2_subdev_format format;2474 2475 memset(&format, 0, sizeof(format));2476 format.pad = CCDC_PAD_SINK;2477 format.which = fh ? V4L2_SUBDEV_FORMAT_TRY : V4L2_SUBDEV_FORMAT_ACTIVE;2478 format.format.code = MEDIA_BUS_FMT_SGRBG10_1X10;2479 format.format.width = 4096;2480 format.format.height = 4096;2481 ccdc_set_format(sd, fh ? fh->state : NULL, &format);2482 2483 return 0;2484}2485 2486/* V4L2 subdev core operations */2487static const struct v4l2_subdev_core_ops ccdc_v4l2_core_ops = {2488 .ioctl = ccdc_ioctl,2489 .subscribe_event = ccdc_subscribe_event,2490 .unsubscribe_event = ccdc_unsubscribe_event,2491};2492 2493/* V4L2 subdev video operations */2494static const struct v4l2_subdev_video_ops ccdc_v4l2_video_ops = {2495 .s_stream = ccdc_set_stream,2496};2497 2498/* V4L2 subdev pad operations */2499static const struct v4l2_subdev_pad_ops ccdc_v4l2_pad_ops = {2500 .enum_mbus_code = ccdc_enum_mbus_code,2501 .enum_frame_size = ccdc_enum_frame_size,2502 .get_fmt = ccdc_get_format,2503 .set_fmt = ccdc_set_format,2504 .get_selection = ccdc_get_selection,2505 .set_selection = ccdc_set_selection,2506 .link_validate = ccdc_link_validate,2507};2508 2509/* V4L2 subdev operations */2510static const struct v4l2_subdev_ops ccdc_v4l2_ops = {2511 .core = &ccdc_v4l2_core_ops,2512 .video = &ccdc_v4l2_video_ops,2513 .pad = &ccdc_v4l2_pad_ops,2514};2515 2516/* V4L2 subdev internal operations */2517static const struct v4l2_subdev_internal_ops ccdc_v4l2_internal_ops = {2518 .open = ccdc_init_formats,2519};2520 2521/* -----------------------------------------------------------------------------2522 * Media entity operations2523 */2524 2525/*2526 * ccdc_link_setup - Setup CCDC connections2527 * @entity: CCDC media entity2528 * @local: Pad at the local end of the link2529 * @remote: Pad at the remote end of the link2530 * @flags: Link flags2531 *2532 * return -EINVAL or zero on success2533 */2534static int ccdc_link_setup(struct media_entity *entity,2535 const struct media_pad *local,2536 const struct media_pad *remote, u32 flags)2537{2538 struct v4l2_subdev *sd = media_entity_to_v4l2_subdev(entity);2539 struct isp_ccdc_device *ccdc = v4l2_get_subdevdata(sd);2540 struct isp_device *isp = to_isp_device(ccdc);2541 unsigned int index = local->index;2542 2543 /* FIXME: this is actually a hack! */2544 if (is_media_entity_v4l2_subdev(remote->entity))2545 index |= 2 << 16;2546 2547 switch (index) {2548 case CCDC_PAD_SINK | 2 << 16:2549 /* Read from the sensor (parallel interface), CCP2, CSI2a or2550 * CSI2c.2551 */2552 if (!(flags & MEDIA_LNK_FL_ENABLED)) {2553 ccdc->input = CCDC_INPUT_NONE;2554 break;2555 }2556 2557 if (ccdc->input != CCDC_INPUT_NONE)2558 return -EBUSY;2559 2560 if (remote->entity == &isp->isp_ccp2.subdev.entity)2561 ccdc->input = CCDC_INPUT_CCP2B;2562 else if (remote->entity == &isp->isp_csi2a.subdev.entity)2563 ccdc->input = CCDC_INPUT_CSI2A;2564 else if (remote->entity == &isp->isp_csi2c.subdev.entity)2565 ccdc->input = CCDC_INPUT_CSI2C;2566 else2567 ccdc->input = CCDC_INPUT_PARALLEL;2568 2569 break;2570 2571 /*2572 * The ISP core doesn't support pipelines with multiple video outputs.2573 * Revisit this when it will be implemented, and return -EBUSY for now.2574 */2575 2576 case CCDC_PAD_SOURCE_VP | 2 << 16:2577 /* Write to preview engine, histogram and H3A. When none of2578 * those links are active, the video port can be disabled.2579 */2580 if (flags & MEDIA_LNK_FL_ENABLED) {2581 if (ccdc->output & ~CCDC_OUTPUT_PREVIEW)2582 return -EBUSY;2583 ccdc->output |= CCDC_OUTPUT_PREVIEW;2584 } else {2585 ccdc->output &= ~CCDC_OUTPUT_PREVIEW;2586 }2587 break;2588 2589 case CCDC_PAD_SOURCE_OF:2590 /* Write to memory */2591 if (flags & MEDIA_LNK_FL_ENABLED) {2592 if (ccdc->output & ~CCDC_OUTPUT_MEMORY)2593 return -EBUSY;2594 ccdc->output |= CCDC_OUTPUT_MEMORY;2595 } else {2596 ccdc->output &= ~CCDC_OUTPUT_MEMORY;2597 }2598 break;2599 2600 case CCDC_PAD_SOURCE_OF | 2 << 16:2601 /* Write to resizer */2602 if (flags & MEDIA_LNK_FL_ENABLED) {2603 if (ccdc->output & ~CCDC_OUTPUT_RESIZER)2604 return -EBUSY;2605 ccdc->output |= CCDC_OUTPUT_RESIZER;2606 } else {2607 ccdc->output &= ~CCDC_OUTPUT_RESIZER;2608 }2609 break;2610 2611 default:2612 return -EINVAL;2613 }2614 2615 return 0;2616}2617 2618/* media operations */2619static const struct media_entity_operations ccdc_media_ops = {2620 .link_setup = ccdc_link_setup,2621 .link_validate = v4l2_subdev_link_validate,2622};2623 2624void omap3isp_ccdc_unregister_entities(struct isp_ccdc_device *ccdc)2625{2626 v4l2_device_unregister_subdev(&ccdc->subdev);2627 omap3isp_video_unregister(&ccdc->video_out);2628}2629 2630int omap3isp_ccdc_register_entities(struct isp_ccdc_device *ccdc,2631 struct v4l2_device *vdev)2632{2633 int ret;2634 2635 /* Register the subdev and video node. */2636 ccdc->subdev.dev = vdev->mdev->dev;2637 ret = v4l2_device_register_subdev(vdev, &ccdc->subdev);2638 if (ret < 0)2639 goto error;2640 2641 ret = omap3isp_video_register(&ccdc->video_out, vdev);2642 if (ret < 0)2643 goto error;2644 2645 return 0;2646 2647error:2648 omap3isp_ccdc_unregister_entities(ccdc);2649 return ret;2650}2651 2652/* -----------------------------------------------------------------------------2653 * ISP CCDC initialisation and cleanup2654 */2655 2656/*2657 * ccdc_init_entities - Initialize V4L2 subdev and media entity2658 * @ccdc: ISP CCDC module2659 *2660 * Return 0 on success and a negative error code on failure.2661 */2662static int ccdc_init_entities(struct isp_ccdc_device *ccdc)2663{2664 struct v4l2_subdev *sd = &ccdc->subdev;2665 struct media_pad *pads = ccdc->pads;2666 struct media_entity *me = &sd->entity;2667 int ret;2668 2669 ccdc->input = CCDC_INPUT_NONE;2670 2671 v4l2_subdev_init(sd, &ccdc_v4l2_ops);2672 sd->internal_ops = &ccdc_v4l2_internal_ops;2673 strscpy(sd->name, "OMAP3 ISP CCDC", sizeof(sd->name));2674 sd->grp_id = 1 << 16; /* group ID for isp subdevs */2675 v4l2_set_subdevdata(sd, ccdc);2676 sd->flags |= V4L2_SUBDEV_FL_HAS_EVENTS | V4L2_SUBDEV_FL_HAS_DEVNODE;2677 2678 pads[CCDC_PAD_SINK].flags = MEDIA_PAD_FL_SINK2679 | MEDIA_PAD_FL_MUST_CONNECT;2680 pads[CCDC_PAD_SOURCE_VP].flags = MEDIA_PAD_FL_SOURCE;2681 pads[CCDC_PAD_SOURCE_OF].flags = MEDIA_PAD_FL_SOURCE;2682 2683 me->ops = &ccdc_media_ops;2684 ret = media_entity_pads_init(me, CCDC_PADS_NUM, pads);2685 if (ret < 0)2686 return ret;2687 2688 ccdc_init_formats(sd, NULL);2689 2690 ccdc->video_out.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;2691 ccdc->video_out.ops = &ccdc_video_ops;2692 ccdc->video_out.isp = to_isp_device(ccdc);2693 ccdc->video_out.capture_mem = PAGE_ALIGN(4096 * 4096) * 3;2694 ccdc->video_out.bpl_alignment = 32;2695 2696 ret = omap3isp_video_init(&ccdc->video_out, "CCDC");2697 if (ret < 0)2698 goto error;2699 2700 return 0;2701 2702error:2703 media_entity_cleanup(me);2704 return ret;2705}2706 2707/*2708 * omap3isp_ccdc_init - CCDC module initialization.2709 * @isp: Device pointer specific to the OMAP3 ISP.2710 *2711 * TODO: Get the initialisation values from platform data.2712 *2713 * Return 0 on success or a negative error code otherwise.2714 */2715int omap3isp_ccdc_init(struct isp_device *isp)2716{2717 struct isp_ccdc_device *ccdc = &isp->isp_ccdc;2718 int ret;2719 2720 spin_lock_init(&ccdc->lock);2721 init_waitqueue_head(&ccdc->wait);2722 mutex_init(&ccdc->ioctl_lock);2723 2724 ccdc->stopping = CCDC_STOP_NOT_REQUESTED;2725 2726 INIT_WORK(&ccdc->lsc.table_work, ccdc_lsc_free_table_work);2727 ccdc->lsc.state = LSC_STATE_STOPPED;2728 INIT_LIST_HEAD(&ccdc->lsc.free_queue);2729 spin_lock_init(&ccdc->lsc.req_lock);2730 2731 ccdc->clamp.oblen = 0;2732 ccdc->clamp.dcsubval = 0;2733 2734 ccdc->update = OMAP3ISP_CCDC_BLCLAMP;2735 ccdc_apply_controls(ccdc);2736 2737 ret = ccdc_init_entities(ccdc);2738 if (ret < 0) {2739 mutex_destroy(&ccdc->ioctl_lock);2740 return ret;2741 }2742 2743 return 0;2744}2745 2746/*2747 * omap3isp_ccdc_cleanup - CCDC module cleanup.2748 * @isp: Device pointer specific to the OMAP3 ISP.2749 */2750void omap3isp_ccdc_cleanup(struct isp_device *isp)2751{2752 struct isp_ccdc_device *ccdc = &isp->isp_ccdc;2753 2754 omap3isp_video_cleanup(&ccdc->video_out);2755 media_entity_cleanup(&ccdc->subdev.entity);2756 2757 /* Free LSC requests. As the CCDC is stopped there's no active request,2758 * so only the pending request and the free queue need to be handled.2759 */2760 ccdc_lsc_free_request(ccdc, ccdc->lsc.request);2761 cancel_work_sync(&ccdc->lsc.table_work);2762 ccdc_lsc_free_queue(ccdc, &ccdc->lsc.free_queue);2763 2764 if (ccdc->fpc.addr != NULL)2765 dma_free_coherent(isp->dev, ccdc->fpc.fpnum * 4, ccdc->fpc.addr,2766 ccdc->fpc.dma);2767 2768 mutex_destroy(&ccdc->ioctl_lock);2769}2770