cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

sc.c (7413B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 * Scaler library
      4 *
      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 DUMPREG
     54}
     55EXPORT_SYMBOL(sc_dump_regs);
     56
     57/*
     58 * set the horizontal scaler coefficients according to the ratio of output to
     59 * input widths, after accounting for up to two levels of decimation
     60 */
     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 coefficients
     95		 * in it's memory. For the horizontal scaler, we copy the first
     96		 * 7 coefficients and skip the last slot to move to the next
     97		 * row to hold coefficients for the next phase
     98		 */
     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 to
    108 * input heights
    109 */
    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 and
    137		 * skip the last 3 slots to move to the next row to hold
    138		 * coefficients for the next phase
    139		 */
    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 first
    163	 * register in the mmr address data block
    164	 */
    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");