brintos

brintos / linux-shallow public Read only

0
0
Text · 10.9 KiB · de7b116 Raw
406 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * isph3a_af.c4 *5 * TI OMAP3 ISP - H3A AF module6 *7 * Copyright (C) 2010 Nokia Corporation8 * Copyright (C) 2009 Texas Instruments, Inc.9 *10 * Contacts: David Cohen <dacohen@gmail.com>11 *	     Laurent Pinchart <laurent.pinchart@ideasonboard.com>12 *	     Sakari Ailus <sakari.ailus@iki.fi>13 */14 15/* Linux specific include files */16#include <linux/device.h>17#include <linux/slab.h>18 19#include "isp.h"20#include "isph3a.h"21#include "ispstat.h"22 23#define IS_OUT_OF_BOUNDS(value, min, max)		\24	((((unsigned int)value) < (min)) || (((unsigned int)value) > (max)))25 26static void h3a_af_setup_regs(struct ispstat *af, void *priv)27{28	struct omap3isp_h3a_af_config *conf = priv;29	u32 pcr;30	u32 pax1;31	u32 pax2;32	u32 paxstart;33	u32 coef;34	u32 base_coef_set0;35	u32 base_coef_set1;36	int index;37 38	if (af->state == ISPSTAT_DISABLED)39		return;40 41	isp_reg_writel(af->isp, af->active_buf->dma_addr, OMAP3_ISP_IOMEM_H3A,42		       ISPH3A_AFBUFST);43 44	if (!af->update)45		return;46 47	/* Configure Hardware Registers */48	pax1 = ((conf->paxel.width >> 1) - 1) << AF_PAXW_SHIFT;49	/* Set height in AFPAX1 */50	pax1 |= (conf->paxel.height >> 1) - 1;51	isp_reg_writel(af->isp, pax1, OMAP3_ISP_IOMEM_H3A, ISPH3A_AFPAX1);52 53	/* Configure AFPAX2 Register */54	/* Set Line Increment in AFPAX2 Register */55	pax2 = ((conf->paxel.line_inc >> 1) - 1) << AF_LINE_INCR_SHIFT;56	/* Set Vertical Count */57	pax2 |= (conf->paxel.v_cnt - 1) << AF_VT_COUNT_SHIFT;58	/* Set Horizontal Count */59	pax2 |= (conf->paxel.h_cnt - 1);60	isp_reg_writel(af->isp, pax2, OMAP3_ISP_IOMEM_H3A, ISPH3A_AFPAX2);61 62	/* Configure PAXSTART Register */63	/*Configure Horizontal Start */64	paxstart = conf->paxel.h_start << AF_HZ_START_SHIFT;65	/* Configure Vertical Start */66	paxstart |= conf->paxel.v_start;67	isp_reg_writel(af->isp, paxstart, OMAP3_ISP_IOMEM_H3A,68		       ISPH3A_AFPAXSTART);69 70	/*SetIIRSH Register */71	isp_reg_writel(af->isp, conf->iir.h_start,72		       OMAP3_ISP_IOMEM_H3A, ISPH3A_AFIIRSH);73 74	base_coef_set0 = ISPH3A_AFCOEF010;75	base_coef_set1 = ISPH3A_AFCOEF110;76	for (index = 0; index <= 8; index += 2) {77		/*Set IIR Filter0 Coefficients */78		coef = 0;79		coef |= conf->iir.coeff_set0[index];80		coef |= conf->iir.coeff_set0[index + 1] <<81			AF_COEF_SHIFT;82		isp_reg_writel(af->isp, coef, OMAP3_ISP_IOMEM_H3A,83			       base_coef_set0);84		base_coef_set0 += AFCOEF_OFFSET;85 86		/*Set IIR Filter1 Coefficients */87		coef = 0;88		coef |= conf->iir.coeff_set1[index];89		coef |= conf->iir.coeff_set1[index + 1] <<90			AF_COEF_SHIFT;91		isp_reg_writel(af->isp, coef, OMAP3_ISP_IOMEM_H3A,92			       base_coef_set1);93		base_coef_set1 += AFCOEF_OFFSET;94	}95	/* set AFCOEF0010 Register */96	isp_reg_writel(af->isp, conf->iir.coeff_set0[10],97		       OMAP3_ISP_IOMEM_H3A, ISPH3A_AFCOEF0010);98	/* set AFCOEF1010 Register */99	isp_reg_writel(af->isp, conf->iir.coeff_set1[10],100		       OMAP3_ISP_IOMEM_H3A, ISPH3A_AFCOEF1010);101 102	/* PCR Register */103	/* Set RGB Position */104	pcr = conf->rgb_pos << AF_RGBPOS_SHIFT;105	/* Set Accumulator Mode */106	if (conf->fvmode == OMAP3ISP_AF_MODE_PEAK)107		pcr |= AF_FVMODE;108	/* Set A-law */109	if (conf->alaw_enable)110		pcr |= AF_ALAW_EN;111	/* HMF Configurations */112	if (conf->hmf.enable) {113		/* Enable HMF */114		pcr |= AF_MED_EN;115		/* Set Median Threshold */116		pcr |= conf->hmf.threshold << AF_MED_TH_SHIFT;117	}118	/* Set PCR Register */119	isp_reg_clr_set(af->isp, OMAP3_ISP_IOMEM_H3A, ISPH3A_PCR,120			AF_PCR_MASK, pcr);121 122	af->update = 0;123	af->config_counter += af->inc_config;124	af->inc_config = 0;125	af->buf_size = conf->buf_size;126}127 128static void h3a_af_enable(struct ispstat *af, int enable)129{130	if (enable) {131		isp_reg_set(af->isp, OMAP3_ISP_IOMEM_H3A, ISPH3A_PCR,132			    ISPH3A_PCR_AF_EN);133		omap3isp_subclk_enable(af->isp, OMAP3_ISP_SUBCLK_AF);134	} else {135		isp_reg_clr(af->isp, OMAP3_ISP_IOMEM_H3A, ISPH3A_PCR,136			    ISPH3A_PCR_AF_EN);137		omap3isp_subclk_disable(af->isp, OMAP3_ISP_SUBCLK_AF);138	}139}140 141static int h3a_af_busy(struct ispstat *af)142{143	return isp_reg_readl(af->isp, OMAP3_ISP_IOMEM_H3A, ISPH3A_PCR)144						& ISPH3A_PCR_BUSYAF;145}146 147static u32 h3a_af_get_buf_size(struct omap3isp_h3a_af_config *conf)148{149	return conf->paxel.h_cnt * conf->paxel.v_cnt * OMAP3ISP_AF_PAXEL_SIZE;150}151 152/* Function to check paxel parameters */153static int h3a_af_validate_params(struct ispstat *af, void *new_conf)154{155	struct omap3isp_h3a_af_config *user_cfg = new_conf;156	struct omap3isp_h3a_af_paxel *paxel_cfg = &user_cfg->paxel;157	struct omap3isp_h3a_af_iir *iir_cfg = &user_cfg->iir;158	int index;159	u32 buf_size;160 161	/* Check horizontal Count */162	if (IS_OUT_OF_BOUNDS(paxel_cfg->h_cnt,163			     OMAP3ISP_AF_PAXEL_HORIZONTAL_COUNT_MIN,164			     OMAP3ISP_AF_PAXEL_HORIZONTAL_COUNT_MAX))165		return -EINVAL;166 167	/* Check Vertical Count */168	if (IS_OUT_OF_BOUNDS(paxel_cfg->v_cnt,169			     OMAP3ISP_AF_PAXEL_VERTICAL_COUNT_MIN,170			     OMAP3ISP_AF_PAXEL_VERTICAL_COUNT_MAX))171		return -EINVAL;172 173	if (IS_OUT_OF_BOUNDS(paxel_cfg->height, OMAP3ISP_AF_PAXEL_HEIGHT_MIN,174			     OMAP3ISP_AF_PAXEL_HEIGHT_MAX) ||175	    paxel_cfg->height % 2)176		return -EINVAL;177 178	/* Check width */179	if (IS_OUT_OF_BOUNDS(paxel_cfg->width, OMAP3ISP_AF_PAXEL_WIDTH_MIN,180			     OMAP3ISP_AF_PAXEL_WIDTH_MAX) ||181	    paxel_cfg->width % 2)182		return -EINVAL;183 184	/* Check Line Increment */185	if (IS_OUT_OF_BOUNDS(paxel_cfg->line_inc,186			     OMAP3ISP_AF_PAXEL_INCREMENT_MIN,187			     OMAP3ISP_AF_PAXEL_INCREMENT_MAX) ||188	    paxel_cfg->line_inc % 2)189		return -EINVAL;190 191	/* Check Horizontal Start */192	if ((paxel_cfg->h_start < iir_cfg->h_start) ||193	    IS_OUT_OF_BOUNDS(paxel_cfg->h_start,194			     OMAP3ISP_AF_PAXEL_HZSTART_MIN,195			     OMAP3ISP_AF_PAXEL_HZSTART_MAX))196		return -EINVAL;197 198	/* Check IIR */199	for (index = 0; index < OMAP3ISP_AF_NUM_COEF; index++) {200		if ((iir_cfg->coeff_set0[index]) > OMAP3ISP_AF_COEF_MAX)201			return -EINVAL;202 203		if ((iir_cfg->coeff_set1[index]) > OMAP3ISP_AF_COEF_MAX)204			return -EINVAL;205	}206 207	if (IS_OUT_OF_BOUNDS(iir_cfg->h_start, OMAP3ISP_AF_IIRSH_MIN,208			     OMAP3ISP_AF_IIRSH_MAX))209		return -EINVAL;210 211	/* Hack: If paxel size is 12, the 10th AF window may be corrupted */212	if ((paxel_cfg->h_cnt * paxel_cfg->v_cnt > 9) &&213	    (paxel_cfg->width * paxel_cfg->height == 12))214		return -EINVAL;215 216	buf_size = h3a_af_get_buf_size(user_cfg);217	if (buf_size > user_cfg->buf_size)218		/* User buf_size request wasn't enough */219		user_cfg->buf_size = buf_size;220	else if (user_cfg->buf_size > OMAP3ISP_AF_MAX_BUF_SIZE)221		user_cfg->buf_size = OMAP3ISP_AF_MAX_BUF_SIZE;222 223	return 0;224}225 226/* Update local parameters */227static void h3a_af_set_params(struct ispstat *af, void *new_conf)228{229	struct omap3isp_h3a_af_config *user_cfg = new_conf;230	struct omap3isp_h3a_af_config *cur_cfg = af->priv;231	int update = 0;232	int index;233 234	/* alaw */235	if (cur_cfg->alaw_enable != user_cfg->alaw_enable) {236		update = 1;237		goto out;238	}239 240	/* hmf */241	if (cur_cfg->hmf.enable != user_cfg->hmf.enable) {242		update = 1;243		goto out;244	}245	if (cur_cfg->hmf.threshold != user_cfg->hmf.threshold) {246		update = 1;247		goto out;248	}249 250	/* rgbpos */251	if (cur_cfg->rgb_pos != user_cfg->rgb_pos) {252		update = 1;253		goto out;254	}255 256	/* iir */257	if (cur_cfg->iir.h_start != user_cfg->iir.h_start) {258		update = 1;259		goto out;260	}261	for (index = 0; index < OMAP3ISP_AF_NUM_COEF; index++) {262		if (cur_cfg->iir.coeff_set0[index] !=263				user_cfg->iir.coeff_set0[index]) {264			update = 1;265			goto out;266		}267		if (cur_cfg->iir.coeff_set1[index] !=268				user_cfg->iir.coeff_set1[index]) {269			update = 1;270			goto out;271		}272	}273 274	/* paxel */275	if ((cur_cfg->paxel.width != user_cfg->paxel.width) ||276	    (cur_cfg->paxel.height != user_cfg->paxel.height) ||277	    (cur_cfg->paxel.h_start != user_cfg->paxel.h_start) ||278	    (cur_cfg->paxel.v_start != user_cfg->paxel.v_start) ||279	    (cur_cfg->paxel.h_cnt != user_cfg->paxel.h_cnt) ||280	    (cur_cfg->paxel.v_cnt != user_cfg->paxel.v_cnt) ||281	    (cur_cfg->paxel.line_inc != user_cfg->paxel.line_inc)) {282		update = 1;283		goto out;284	}285 286	/* af_mode */287	if (cur_cfg->fvmode != user_cfg->fvmode)288		update = 1;289 290out:291	if (update || !af->configured) {292		memcpy(cur_cfg, user_cfg, sizeof(*cur_cfg));293		af->inc_config++;294		af->update = 1;295		/*296		 * User might be asked for a bigger buffer than necessary for297		 * this configuration. In order to return the right amount of298		 * data during buffer request, let's calculate the size here299		 * instead of stick with user_cfg->buf_size.300		 */301		cur_cfg->buf_size = h3a_af_get_buf_size(cur_cfg);302	}303}304 305static long h3a_af_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg)306{307	struct ispstat *stat = v4l2_get_subdevdata(sd);308 309	switch (cmd) {310	case VIDIOC_OMAP3ISP_AF_CFG:311		return omap3isp_stat_config(stat, arg);312	case VIDIOC_OMAP3ISP_STAT_REQ:313		return omap3isp_stat_request_statistics(stat, arg);314	case VIDIOC_OMAP3ISP_STAT_REQ_TIME32:315		return omap3isp_stat_request_statistics_time32(stat, arg);316	case VIDIOC_OMAP3ISP_STAT_EN: {317		int *en = arg;318		return omap3isp_stat_enable(stat, !!*en);319	}320	}321 322	return -ENOIOCTLCMD;323 324}325 326static const struct ispstat_ops h3a_af_ops = {327	.validate_params	= h3a_af_validate_params,328	.set_params		= h3a_af_set_params,329	.setup_regs		= h3a_af_setup_regs,330	.enable			= h3a_af_enable,331	.busy			= h3a_af_busy,332};333 334static const struct v4l2_subdev_core_ops h3a_af_subdev_core_ops = {335	.ioctl = h3a_af_ioctl,336	.subscribe_event = omap3isp_stat_subscribe_event,337	.unsubscribe_event = omap3isp_stat_unsubscribe_event,338};339 340static const struct v4l2_subdev_video_ops h3a_af_subdev_video_ops = {341	.s_stream = omap3isp_stat_s_stream,342};343 344static const struct v4l2_subdev_ops h3a_af_subdev_ops = {345	.core = &h3a_af_subdev_core_ops,346	.video = &h3a_af_subdev_video_ops,347};348 349/* Function to register the AF character device driver. */350int omap3isp_h3a_af_init(struct isp_device *isp)351{352	struct ispstat *af = &isp->isp_af;353	struct omap3isp_h3a_af_config *af_cfg;354	struct omap3isp_h3a_af_config *af_recover_cfg = NULL;355	int ret;356 357	af_cfg = kzalloc(sizeof(*af_cfg), GFP_KERNEL);358	if (af_cfg == NULL)359		return -ENOMEM;360 361	af->ops = &h3a_af_ops;362	af->priv = af_cfg;363	af->event_type = V4L2_EVENT_OMAP3ISP_AF;364	af->isp = isp;365 366	/* Set recover state configuration */367	af_recover_cfg = kzalloc(sizeof(*af_recover_cfg), GFP_KERNEL);368	if (!af_recover_cfg) {369		dev_err(af->isp->dev,370			"AF: cannot allocate memory for recover configuration.\n");371		ret = -ENOMEM;372		goto err;373	}374 375	af_recover_cfg->paxel.h_start = OMAP3ISP_AF_PAXEL_HZSTART_MIN;376	af_recover_cfg->paxel.width = OMAP3ISP_AF_PAXEL_WIDTH_MIN;377	af_recover_cfg->paxel.height = OMAP3ISP_AF_PAXEL_HEIGHT_MIN;378	af_recover_cfg->paxel.h_cnt = OMAP3ISP_AF_PAXEL_HORIZONTAL_COUNT_MIN;379	af_recover_cfg->paxel.v_cnt = OMAP3ISP_AF_PAXEL_VERTICAL_COUNT_MIN;380	af_recover_cfg->paxel.line_inc = OMAP3ISP_AF_PAXEL_INCREMENT_MIN;381	if (h3a_af_validate_params(af, af_recover_cfg)) {382		dev_err(af->isp->dev,383			"AF: recover configuration is invalid.\n");384		ret = -EINVAL;385		goto err;386	}387 388	af_recover_cfg->buf_size = h3a_af_get_buf_size(af_recover_cfg);389	af->recover_priv = af_recover_cfg;390 391	ret = omap3isp_stat_init(af, "AF", &h3a_af_subdev_ops);392 393err:394	if (ret) {395		kfree(af_cfg);396		kfree(af_recover_cfg);397	}398 399	return ret;400}401 402void omap3isp_h3a_af_cleanup(struct isp_device *isp)403{404	omap3isp_stat_cleanup(&isp->isp_af);405}406