4 * Copyright (c) 2013 Texas Instruments Inc.
6 * David Griego, <dagriego@biglakesoftware.com>
7 * Dale Farnsworth, <dale@farnsworth.org>
8 * Archit Taneja, <archit@ti.com>
10 * This program is free software; you can redistribute it and/or modify it
11 * under the terms of the GNU General Public License version 2 as published by
12 * the Free Software Foundation.
15 #include <linux/err.h>
17 #include <linux/module.h>
18 #include <linux/platform_device.h>
19 #include <linux/slab.h>
24 void sc_dump_regs(struct sc_data
*sc
)
26 struct device
*dev
= &sc
->pdev
->dev
;
28 #define DUMPREG(r) dev_dbg(dev, "%-35s %08x\n", #r, \
29 ioread32(sc->base + CFG_##r))
31 dev_dbg(dev
, "SC Registers @ %pa:\n", &sc
->res
->start
);
58 EXPORT_SYMBOL(sc_dump_regs
);
61 * set the horizontal scaler coefficients according to the ratio of output to
62 * input widths, after accounting for up to two levels of decimation
64 void sc_set_hs_coeffs(struct sc_data
*sc
, void *addr
, unsigned int src_w
,
76 if ((dst_w
<< 1) < src_w
)
77 dst_w
<<= 1; /* first level decimation */
78 if ((dst_w
<< 1) < src_w
)
79 dst_w
<<= 1; /* second level decimation */
82 idx
= HS_LE_16_16_SCALE
;
84 sixteenths
= (dst_w
<< 4) / src_w
;
87 idx
= HS_LT_9_16_SCALE
+ sixteenths
- 8;
91 cp
= scaler_hs_coeffs
[idx
];
93 for (i
= 0; i
< SC_NUM_PHASES
* 2; i
++) {
94 for (j
= 0; j
< SC_H_NUM_TAPS
; j
++)
97 * for each phase, the scaler expects space for 8 coefficients
98 * in it's memory. For the horizontal scaler, we copy the first
99 * 7 coefficients and skip the last slot to move to the next
100 * row to hold coefficients for the next phase
102 coeff_h
+= SC_NUM_TAPS_MEM_ALIGN
- SC_H_NUM_TAPS
;
105 sc
->load_coeff_h
= true;
107 EXPORT_SYMBOL(sc_set_hs_coeffs
);
110 * set the vertical scaler coefficients according to the ratio of output to
113 void sc_set_vs_coeffs(struct sc_data
*sc
, void *addr
, unsigned int src_h
,
124 } else if (dst_h
== src_h
) {
125 idx
= VS_1_TO_1_SCALE
;
127 sixteenths
= (dst_h
<< 4) / src_h
;
130 idx
= VS_LT_9_16_SCALE
+ sixteenths
- 8;
133 cp
= scaler_vs_coeffs
[idx
];
135 for (i
= 0; i
< SC_NUM_PHASES
* 2; i
++) {
136 for (j
= 0; j
< SC_V_NUM_TAPS
; j
++)
139 * for the vertical scaler, we copy the first 5 coefficients and
140 * skip the last 3 slots to move to the next row to hold
141 * coefficients for the next phase
143 coeff_v
+= SC_NUM_TAPS_MEM_ALIGN
- SC_V_NUM_TAPS
;
146 sc
->load_coeff_v
= true;
148 EXPORT_SYMBOL(sc_set_vs_coeffs
);
150 void sc_config_scaler(struct sc_data
*sc
, u32
*sc_reg0
, u32
*sc_reg8
,
151 u32
*sc_reg17
, unsigned int src_w
, unsigned int src_h
,
152 unsigned int dst_w
, unsigned int dst_h
)
154 struct device
*dev
= &sc
->pdev
->dev
;
156 int dcm_x
, dcm_shift
;
159 u32 lin_acc_inc
, lin_acc_inc_u
;
162 int row_acc_init_rav
= 0, row_acc_init_rav_b
= 0;
163 u32 row_acc_inc
= 0, row_acc_offset
= 0, row_acc_offset_b
= 0;
165 * location of SC register in payload memory with respect to the first
166 * register in the mmr address data block
168 u32
*sc_reg9
= sc_reg8
+ 1;
169 u32
*sc_reg12
= sc_reg8
+ 4;
170 u32
*sc_reg13
= sc_reg8
+ 5;
171 u32
*sc_reg24
= sc_reg17
+ 7;
175 /* clear all the features(they may get enabled elsewhere later) */
176 val
&= ~(CFG_SELFGEN_FID
| CFG_TRIM
| CFG_ENABLE_SIN2_VER_INTP
|
177 CFG_INTERLACE_I
| CFG_DCM_4X
| CFG_DCM_2X
| CFG_AUTO_HS
|
178 CFG_ENABLE_EV
| CFG_USE_RAV
| CFG_INVT_FID
| CFG_SC_BYPASS
|
179 CFG_INTERLACE_O
| CFG_Y_PK_EN
| CFG_HP_BYPASS
| CFG_LINEAR
);
181 if (src_w
== dst_w
&& src_h
== dst_h
) {
182 val
|= CFG_SC_BYPASS
;
187 /* we only support linear scaling for now */
190 /* configure horizontal scaler */
192 /* enable 2X or 4X decimation */
193 dcm_x
= src_w
/ dst_w
;
197 } else if (dcm_x
> 2) {
205 lin_acc_inc
= div64_u64(((u64
)(src_w
>> dcm_shift
) - 1) << 24, lltmp
);
209 dev_dbg(dev
, "hs config: src_w = %d, dst_w = %d, decimation = %s, lin_acc_inc = %08x\n",
210 src_w
, dst_w
, dcm_shift
== 2 ? "4x" :
211 (dcm_shift
== 1 ? "2x" : "none"), lin_acc_inc
);
213 /* configure vertical scaler */
215 /* use RAV for vertical scaler if vertical downscaling is > 4x */
216 if (dst_h
< (src_h
>> 2)) {
225 factor
= (u16
) ((dst_h
<< 10) / src_h
);
227 row_acc_init_rav
= factor
+ ((1 + factor
) >> 1);
228 if (row_acc_init_rav
>= 1024)
229 row_acc_init_rav
-= 1024;
231 row_acc_init_rav_b
= row_acc_init_rav
+
232 (1 + (row_acc_init_rav
>> 1)) -
235 if (row_acc_init_rav_b
< 0) {
236 row_acc_init_rav_b
+= row_acc_init_rav
;
237 row_acc_init_rav
*= 2;
240 dev_dbg(dev
, "vs config(RAV): src_h = %d, dst_h = %d, factor = %d, acc_init = %08x, acc_init_b = %08x\n",
241 src_h
, dst_h
, factor
, row_acc_init_rav
,
245 row_acc_inc
= ((src_h
- 1) << 16) / (dst_h
- 1);
247 row_acc_offset_b
= 0;
249 dev_dbg(dev
, "vs config(POLY): src_h = %d, dst_h = %d,row_acc_inc = %08x\n",
250 src_h
, dst_h
, row_acc_inc
);
255 sc_reg0
[1] = row_acc_inc
;
256 sc_reg0
[2] = row_acc_offset
;
257 sc_reg0
[3] = row_acc_offset_b
;
259 sc_reg0
[4] = ((lin_acc_inc_u
& CFG_LIN_ACC_INC_U_MASK
) <<
260 CFG_LIN_ACC_INC_U_SHIFT
) | (dst_w
<< CFG_TAR_W_SHIFT
) |
261 (dst_h
<< CFG_TAR_H_SHIFT
);
263 sc_reg0
[5] = (src_w
<< CFG_SRC_W_SHIFT
) | (src_h
<< CFG_SRC_H_SHIFT
);
265 sc_reg0
[6] = (row_acc_init_rav_b
<< CFG_ROW_ACC_INIT_RAV_B_SHIFT
) |
266 (row_acc_init_rav
<< CFG_ROW_ACC_INIT_RAV_SHIFT
);
268 *sc_reg9
= lin_acc_inc
;
270 *sc_reg12
= col_acc_offset
<< CFG_COL_ACC_OFFSET_SHIFT
;
274 *sc_reg24
= (src_w
<< CFG_ORG_W_SHIFT
) | (src_h
<< CFG_ORG_H_SHIFT
);
276 EXPORT_SYMBOL(sc_config_scaler
);
278 struct sc_data
*sc_create(struct platform_device
*pdev
, const char *res_name
)
282 dev_dbg(&pdev
->dev
, "sc_create\n");
284 sc
= devm_kzalloc(&pdev
->dev
, sizeof(*sc
), GFP_KERNEL
);
286 dev_err(&pdev
->dev
, "couldn't alloc sc_data\n");
287 return ERR_PTR(-ENOMEM
);
292 sc
->res
= platform_get_resource_byname(pdev
, IORESOURCE_MEM
, res_name
);
294 dev_err(&pdev
->dev
, "missing '%s' platform resources data\n",
296 return ERR_PTR(-ENODEV
);
299 sc
->base
= devm_ioremap_resource(&pdev
->dev
, sc
->res
);
300 if (IS_ERR(sc
->base
)) {
301 dev_err(&pdev
->dev
, "failed to ioremap\n");
302 return ERR_CAST(sc
->base
);
307 EXPORT_SYMBOL(sc_create
);
309 MODULE_DESCRIPTION("TI VIP/VPE Scaler");
310 MODULE_AUTHOR("Texas Instruments Inc.");
311 MODULE_LICENSE("GPL v2");