brintos

brintos / linux-shallow public Read only

0
0
Text · 7.2 KiB · 0202d27 Raw
307 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * Scaler library4 *5 * Copyright (c) 2013 Texas Instruments Inc.6 *7 * David Griego, <dagriego@biglakesoftware.com>8 * Dale Farnsworth, <dale@farnsworth.org>9 * Archit Taneja, <archit@ti.com>10 */11 12#include <linux/err.h>13#include <linux/io.h>14#include <linux/module.h>15#include <linux/platform_device.h>16#include <linux/slab.h>17 18#include "sc.h"19#include "sc_coeff.h"20 21void sc_dump_regs(struct sc_data *sc)22{23	struct device *dev = &sc->pdev->dev;24 25#define DUMPREG(r) dev_dbg(dev, "%-35s %08x\n", #r, \26	ioread32(sc->base + CFG_##r))27 28	dev_dbg(dev, "SC Registers @ %pa:\n", &sc->res->start);29 30	DUMPREG(SC0);31	DUMPREG(SC1);32	DUMPREG(SC2);33	DUMPREG(SC3);34	DUMPREG(SC4);35	DUMPREG(SC5);36	DUMPREG(SC6);37	DUMPREG(SC8);38	DUMPREG(SC9);39	DUMPREG(SC10);40	DUMPREG(SC11);41	DUMPREG(SC12);42	DUMPREG(SC13);43	DUMPREG(SC17);44	DUMPREG(SC18);45	DUMPREG(SC19);46	DUMPREG(SC20);47	DUMPREG(SC21);48	DUMPREG(SC22);49	DUMPREG(SC23);50	DUMPREG(SC24);51	DUMPREG(SC25);52 53#undef DUMPREG54}55EXPORT_SYMBOL(sc_dump_regs);56 57/*58 * set the horizontal scaler coefficients according to the ratio of output to59 * input widths, after accounting for up to two levels of decimation60 */61void sc_set_hs_coeffs(struct sc_data *sc, void *addr, unsigned int src_w,62		unsigned int dst_w)63{64	int sixteenths;65	int idx;66	int i, j;67	u16 *coeff_h = addr;68	const u16 *cp;69 70	if (dst_w > src_w) {71		idx = HS_UP_SCALE;72	} else {73		if ((dst_w << 1) < src_w)74			dst_w <<= 1;	/* first level decimation */75		if ((dst_w << 1) < src_w)76			dst_w <<= 1;	/* second level decimation */77 78		if (dst_w == src_w) {79			idx = HS_LE_16_16_SCALE;80		} else {81			sixteenths = (dst_w << 4) / src_w;82			if (sixteenths < 8)83				sixteenths = 8;84			idx = HS_LT_9_16_SCALE + sixteenths - 8;85		}86	}87 88	cp = scaler_hs_coeffs[idx];89 90	for (i = 0; i < SC_NUM_PHASES * 2; i++) {91		for (j = 0; j < SC_H_NUM_TAPS; j++)92			*coeff_h++ = *cp++;93		/*94		 * for each phase, the scaler expects space for 8 coefficients95		 * in it's memory. For the horizontal scaler, we copy the first96		 * 7 coefficients and skip the last slot to move to the next97		 * row to hold coefficients for the next phase98		 */99		coeff_h += SC_NUM_TAPS_MEM_ALIGN - SC_H_NUM_TAPS;100	}101 102	sc->load_coeff_h = true;103}104EXPORT_SYMBOL(sc_set_hs_coeffs);105 106/*107 * set the vertical scaler coefficients according to the ratio of output to108 * input heights109 */110void sc_set_vs_coeffs(struct sc_data *sc, void *addr, unsigned int src_h,111		unsigned int dst_h)112{113	int sixteenths;114	int idx;115	int i, j;116	u16 *coeff_v = addr;117	const u16 *cp;118 119	if (dst_h > src_h) {120		idx = VS_UP_SCALE;121	} else if (dst_h == src_h) {122		idx = VS_1_TO_1_SCALE;123	} else {124		sixteenths = (dst_h << 4) / src_h;125		if (sixteenths < 8)126			sixteenths = 8;127		idx = VS_LT_9_16_SCALE + sixteenths - 8;128	}129 130	cp = scaler_vs_coeffs[idx];131 132	for (i = 0; i < SC_NUM_PHASES * 2; i++) {133		for (j = 0; j < SC_V_NUM_TAPS; j++)134			*coeff_v++ = *cp++;135		/*136		 * for the vertical scaler, we copy the first 5 coefficients and137		 * skip the last 3 slots to move to the next row to hold138		 * coefficients for the next phase139		 */140		coeff_v += SC_NUM_TAPS_MEM_ALIGN - SC_V_NUM_TAPS;141	}142 143	sc->load_coeff_v = true;144}145EXPORT_SYMBOL(sc_set_vs_coeffs);146 147void sc_config_scaler(struct sc_data *sc, u32 *sc_reg0, u32 *sc_reg8,148		u32 *sc_reg17, unsigned int src_w, unsigned int src_h,149		unsigned int dst_w, unsigned int dst_h)150{151	struct device *dev = &sc->pdev->dev;152	u32 val;153	int dcm_x, dcm_shift;154	bool use_rav;155	unsigned long lltmp;156	u32 lin_acc_inc, lin_acc_inc_u;157	u32 col_acc_offset;158	u16 factor = 0;159	int row_acc_init_rav = 0, row_acc_init_rav_b = 0;160	u32 row_acc_inc = 0, row_acc_offset = 0, row_acc_offset_b = 0;161	/*162	 * location of SC register in payload memory with respect to the first163	 * register in the mmr address data block164	 */165	u32 *sc_reg9 = sc_reg8 + 1;166	u32 *sc_reg12 = sc_reg8 + 4;167	u32 *sc_reg13 = sc_reg8 + 5;168	u32 *sc_reg24 = sc_reg17 + 7;169 170	val = sc_reg0[0];171 172	/* clear all the features(they may get enabled elsewhere later) */173	val &= ~(CFG_SELFGEN_FID | CFG_TRIM | CFG_ENABLE_SIN2_VER_INTP |174		CFG_INTERLACE_I | CFG_DCM_4X | CFG_DCM_2X | CFG_AUTO_HS |175		CFG_ENABLE_EV | CFG_USE_RAV | CFG_INVT_FID | CFG_SC_BYPASS |176		CFG_INTERLACE_O | CFG_Y_PK_EN | CFG_HP_BYPASS | CFG_LINEAR);177 178	if (src_w == dst_w && src_h == dst_h) {179		val |= CFG_SC_BYPASS;180		sc_reg0[0] = val;181		return;182	}183 184	/* we only support linear scaling for now */185	val |= CFG_LINEAR;186 187	/* configure horizontal scaler */188 189	/* enable 2X or 4X decimation */190	dcm_x = src_w / dst_w;191	if (dcm_x > 4) {192		val |= CFG_DCM_4X;193		dcm_shift = 2;194	} else if (dcm_x > 2) {195		val |= CFG_DCM_2X;196		dcm_shift = 1;197	} else {198		dcm_shift = 0;199	}200 201	lltmp = dst_w - 1;202	lin_acc_inc = div64_u64(((u64)(src_w >> dcm_shift) - 1) << 24, lltmp);203	lin_acc_inc_u = 0;204	col_acc_offset = 0;205 206	dev_dbg(dev, "hs config: src_w = %d, dst_w = %d, decimation = %s, lin_acc_inc = %08x\n",207		src_w, dst_w, dcm_shift == 2 ? "4x" :208		(dcm_shift == 1 ? "2x" : "none"), lin_acc_inc);209 210	/* configure vertical scaler */211 212	/* use RAV for vertical scaler if vertical downscaling is > 4x */213	if (dst_h < (src_h >> 2)) {214		use_rav = true;215		val |= CFG_USE_RAV;216	} else {217		use_rav = false;218	}219 220	if (use_rav) {221		/* use RAV */222		factor = (u16) ((dst_h << 10) / src_h);223 224		row_acc_init_rav = factor + ((1 + factor) >> 1);225		if (row_acc_init_rav >= 1024)226			row_acc_init_rav -= 1024;227 228		row_acc_init_rav_b = row_acc_init_rav +229				(1 + (row_acc_init_rav >> 1)) -230				(1024 >> 1);231 232		if (row_acc_init_rav_b < 0) {233			row_acc_init_rav_b += row_acc_init_rav;234			row_acc_init_rav *= 2;235		}236 237		dev_dbg(dev, "vs config(RAV): src_h = %d, dst_h = %d, factor = %d, acc_init = %08x, acc_init_b = %08x\n",238			src_h, dst_h, factor, row_acc_init_rav,239			row_acc_init_rav_b);240	} else {241		/* use polyphase */242		row_acc_inc = ((src_h - 1) << 16) / (dst_h - 1);243		row_acc_offset = 0;244		row_acc_offset_b = 0;245 246		dev_dbg(dev, "vs config(POLY): src_h = %d, dst_h = %d,row_acc_inc = %08x\n",247			src_h, dst_h, row_acc_inc);248	}249 250 251	sc_reg0[0] = val;252	sc_reg0[1] = row_acc_inc;253	sc_reg0[2] = row_acc_offset;254	sc_reg0[3] = row_acc_offset_b;255 256	sc_reg0[4] = ((lin_acc_inc_u & CFG_LIN_ACC_INC_U_MASK) <<257			CFG_LIN_ACC_INC_U_SHIFT) | (dst_w << CFG_TAR_W_SHIFT) |258			(dst_h << CFG_TAR_H_SHIFT);259 260	sc_reg0[5] = (src_w << CFG_SRC_W_SHIFT) | (src_h << CFG_SRC_H_SHIFT);261 262	sc_reg0[6] = (row_acc_init_rav_b << CFG_ROW_ACC_INIT_RAV_B_SHIFT) |263		(row_acc_init_rav << CFG_ROW_ACC_INIT_RAV_SHIFT);264 265	*sc_reg9 = lin_acc_inc;266 267	*sc_reg12 = col_acc_offset << CFG_COL_ACC_OFFSET_SHIFT;268 269	*sc_reg13 = factor;270 271	*sc_reg24 = (src_w << CFG_ORG_W_SHIFT) | (src_h << CFG_ORG_H_SHIFT);272}273EXPORT_SYMBOL(sc_config_scaler);274 275struct sc_data *sc_create(struct platform_device *pdev, const char *res_name)276{277	struct sc_data *sc;278 279	dev_dbg(&pdev->dev, "sc_create\n");280 281	sc = devm_kzalloc(&pdev->dev, sizeof(*sc), GFP_KERNEL);282	if (!sc) {283		dev_err(&pdev->dev, "couldn't alloc sc_data\n");284		return ERR_PTR(-ENOMEM);285	}286 287	sc->pdev = pdev;288 289	sc->res = platform_get_resource_byname(pdev, IORESOURCE_MEM, res_name);290	if (!sc->res) {291		dev_err(&pdev->dev, "missing '%s' platform resources data\n",292			res_name);293		return ERR_PTR(-ENODEV);294	}295 296	sc->base = devm_ioremap_resource(&pdev->dev, sc->res);297	if (IS_ERR(sc->base))298		return ERR_CAST(sc->base);299 300	return sc;301}302EXPORT_SYMBOL(sc_create);303 304MODULE_DESCRIPTION("TI VIP/VPE Scaler");305MODULE_AUTHOR("Texas Instruments Inc.");306MODULE_LICENSE("GPL v2");307