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/platform_device.h>
18 #include <linux/slab.h>
23 void sc_dump_regs(struct sc_data
*sc
)
25 struct device
*dev
= &sc
->pdev
->dev
;
27 #define DUMPREG(r) dev_dbg(dev, "%-35s %08x\n", #r, \
28 ioread32(sc->base + CFG_##r))
57 * set the horizontal scaler coefficients according to the ratio of output to
58 * input widths, after accounting for up to two levels of decimation
60 void sc_set_hs_coeffs(struct sc_data
*sc
, void *addr
, unsigned int src_w
,
72 if ((dst_w
<< 1) < src_w
)
73 dst_w
<<= 1; /* first level decimation */
74 if ((dst_w
<< 1) < src_w
)
75 dst_w
<<= 1; /* second level decimation */
78 idx
= HS_LE_16_16_SCALE
;
80 sixteenths
= (dst_w
<< 4) / src_w
;
83 idx
= HS_LT_9_16_SCALE
+ sixteenths
- 8;
87 if (idx
== sc
->hs_index
)
90 cp
= scaler_hs_coeffs
[idx
];
92 for (i
= 0; i
< SC_NUM_PHASES
* 2; i
++) {
93 for (j
= 0; j
< SC_H_NUM_TAPS
; j
++)
96 * for each phase, the scaler expects space for 8 coefficients
97 * in it's memory. For the horizontal scaler, we copy the first
98 * 7 coefficients and skip the last slot to move to the next
99 * row to hold coefficients for the next phase
101 coeff_h
+= SC_NUM_TAPS_MEM_ALIGN
- SC_H_NUM_TAPS
;
106 sc
->load_coeff_h
= true;
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 if (idx
== sc
->vs_index
)
136 cp
= scaler_vs_coeffs
[idx
];
138 for (i
= 0; i
< SC_NUM_PHASES
* 2; i
++) {
139 for (j
= 0; j
< SC_V_NUM_TAPS
; j
++)
142 * for the vertical scaler, we copy the first 5 coefficients and
143 * skip the last 3 slots to move to the next row to hold
144 * coefficients for the next phase
146 coeff_v
+= SC_NUM_TAPS_MEM_ALIGN
- SC_V_NUM_TAPS
;
150 sc
->load_coeff_v
= true;
153 void sc_config_scaler(struct sc_data
*sc
, u32
*sc_reg0
, u32
*sc_reg8
,
154 u32
*sc_reg17
, unsigned int src_w
, unsigned int src_h
,
155 unsigned int dst_w
, unsigned int dst_h
)
157 struct device
*dev
= &sc
->pdev
->dev
;
159 int dcm_x
, dcm_shift
;
162 u32 lin_acc_inc
, lin_acc_inc_u
;
165 int row_acc_init_rav
= 0, row_acc_init_rav_b
= 0;
166 u32 row_acc_inc
= 0, row_acc_offset
= 0, row_acc_offset_b
= 0;
168 * location of SC register in payload memory with respect to the first
169 * register in the mmr address data block
171 u32
*sc_reg9
= sc_reg8
+ 1;
172 u32
*sc_reg12
= sc_reg8
+ 4;
173 u32
*sc_reg13
= sc_reg8
+ 5;
174 u32
*sc_reg24
= sc_reg17
+ 7;
178 /* clear all the features(they may get enabled elsewhere later) */
179 val
&= ~(CFG_SELFGEN_FID
| CFG_TRIM
| CFG_ENABLE_SIN2_VER_INTP
|
180 CFG_INTERLACE_I
| CFG_DCM_4X
| CFG_DCM_2X
| CFG_AUTO_HS
|
181 CFG_ENABLE_EV
| CFG_USE_RAV
| CFG_INVT_FID
| CFG_SC_BYPASS
|
182 CFG_INTERLACE_O
| CFG_Y_PK_EN
| CFG_HP_BYPASS
| CFG_LINEAR
);
184 if (src_w
== dst_w
&& src_h
== dst_h
) {
185 val
|= CFG_SC_BYPASS
;
190 /* we only support linear scaling for now */
193 /* configure horizontal scaler */
195 /* enable 2X or 4X decimation */
196 dcm_x
= src_w
/ dst_w
;
200 } else if (dcm_x
> 2) {
208 lin_acc_inc
= div64_u64(((u64
)(src_w
>> dcm_shift
) - 1) << 24, lltmp
);
212 dev_dbg(dev
, "hs config: src_w = %d, dst_w = %d, decimation = %s, lin_acc_inc = %08x\n",
213 src_w
, dst_w
, dcm_shift
== 2 ? "4x" :
214 (dcm_shift
== 1 ? "2x" : "none"), lin_acc_inc
);
216 /* configure vertical scaler */
218 /* use RAV for vertical scaler if vertical downscaling is > 4x */
219 if (dst_h
< (src_h
>> 2)) {
228 factor
= (u16
) ((dst_h
<< 10) / src_h
);
230 row_acc_init_rav
= factor
+ ((1 + factor
) >> 1);
231 if (row_acc_init_rav
>= 1024)
232 row_acc_init_rav
-= 1024;
234 row_acc_init_rav_b
= row_acc_init_rav
+
235 (1 + (row_acc_init_rav
>> 1)) -
238 if (row_acc_init_rav_b
< 0) {
239 row_acc_init_rav_b
+= row_acc_init_rav
;
240 row_acc_init_rav
*= 2;
243 dev_dbg(dev
, "vs config(RAV): src_h = %d, dst_h = %d, factor = %d, acc_init = %08x, acc_init_b = %08x\n",
244 src_h
, dst_h
, factor
, row_acc_init_rav
,
248 row_acc_inc
= ((src_h
- 1) << 16) / (dst_h
- 1);
250 row_acc_offset_b
= 0;
252 dev_dbg(dev
, "vs config(POLY): src_h = %d, dst_h = %d,row_acc_inc = %08x\n",
253 src_h
, dst_h
, row_acc_inc
);
258 sc_reg0
[1] = row_acc_inc
;
259 sc_reg0
[2] = row_acc_offset
;
260 sc_reg0
[3] = row_acc_offset_b
;
262 sc_reg0
[4] = ((lin_acc_inc_u
& CFG_LIN_ACC_INC_U_MASK
) <<
263 CFG_LIN_ACC_INC_U_SHIFT
) | (dst_w
<< CFG_TAR_W_SHIFT
) |
264 (dst_h
<< CFG_TAR_H_SHIFT
);
266 sc_reg0
[5] = (src_w
<< CFG_SRC_W_SHIFT
) | (src_h
<< CFG_SRC_H_SHIFT
);
268 sc_reg0
[6] = (row_acc_init_rav_b
<< CFG_ROW_ACC_INIT_RAV_B_SHIFT
) |
269 (row_acc_init_rav
<< CFG_ROW_ACC_INIT_RAV_SHIFT
);
271 *sc_reg9
= lin_acc_inc
;
273 *sc_reg12
= col_acc_offset
<< CFG_COL_ACC_OFFSET_SHIFT
;
277 *sc_reg24
= (src_w
<< CFG_ORG_W_SHIFT
) | (src_h
<< CFG_ORG_H_SHIFT
);
280 struct sc_data
*sc_create(struct platform_device
*pdev
)
284 dev_dbg(&pdev
->dev
, "sc_create\n");
286 sc
= devm_kzalloc(&pdev
->dev
, sizeof(*sc
), GFP_KERNEL
);
288 dev_err(&pdev
->dev
, "couldn't alloc sc_data\n");
289 return ERR_PTR(-ENOMEM
);
294 sc
->res
= platform_get_resource_byname(pdev
, IORESOURCE_MEM
, "sc");
296 dev_err(&pdev
->dev
, "missing platform resources data\n");
297 return ERR_PTR(-ENODEV
);
300 sc
->base
= devm_ioremap_resource(&pdev
->dev
, sc
->res
);
301 if (IS_ERR(sc
->base
)) {
302 dev_err(&pdev
->dev
, "failed to ioremap\n");
303 return ERR_CAST(sc
->base
);