brintos

brintos / linux-shallow public Read only

0
0
Text · 76.7 KiB · dd375c4 Raw
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