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 u32
read_reg(struct sc_data
*sc
, int offset
)
29 return ioread32(sc
->base
+ offset
);
32 #define DUMPREG(r) dev_dbg(dev, "%-35s %08x\n", #r, read_reg(sc, CFG_##r))
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 if (idx
== sc
->hs_index
)
94 cp
= scaler_hs_coeffs
[idx
];
96 for (i
= 0; i
< SC_NUM_PHASES
* 2; i
++) {
97 for (j
= 0; j
< SC_H_NUM_TAPS
; j
++)
100 * for each phase, the scaler expects space for 8 coefficients
101 * in it's memory. For the horizontal scaler, we copy the first
102 * 7 coefficients and skip the last slot to move to the next
103 * row to hold coefficients for the next phase
105 coeff_h
+= SC_NUM_TAPS_MEM_ALIGN
- SC_H_NUM_TAPS
;
110 sc
->load_coeff_h
= true;
114 * set the vertical scaler coefficients according to the ratio of output to
117 void sc_set_vs_coeffs(struct sc_data
*sc
, void *addr
, unsigned int src_h
,
128 } else if (dst_h
== src_h
) {
129 idx
= VS_1_TO_1_SCALE
;
131 sixteenths
= (dst_h
<< 4) / src_h
;
134 idx
= VS_LT_9_16_SCALE
+ sixteenths
- 8;
137 if (idx
== sc
->vs_index
)
140 cp
= scaler_vs_coeffs
[idx
];
142 for (i
= 0; i
< SC_NUM_PHASES
* 2; i
++) {
143 for (j
= 0; j
< SC_V_NUM_TAPS
; j
++)
146 * for the vertical scaler, we copy the first 5 coefficients and
147 * skip the last 3 slots to move to the next row to hold
148 * coefficients for the next phase
150 coeff_v
+= SC_NUM_TAPS_MEM_ALIGN
- SC_V_NUM_TAPS
;
154 sc
->load_coeff_v
= true;
157 void sc_config_scaler(struct sc_data
*sc
, u32
*sc_reg0
, u32
*sc_reg8
,
158 u32
*sc_reg17
, unsigned int src_w
, unsigned int src_h
,
159 unsigned int dst_w
, unsigned int dst_h
)
161 struct device
*dev
= &sc
->pdev
->dev
;
163 int dcm_x
, dcm_shift
;
166 u32 lin_acc_inc
, lin_acc_inc_u
;
169 int row_acc_init_rav
= 0, row_acc_init_rav_b
= 0;
170 u32 row_acc_inc
= 0, row_acc_offset
= 0, row_acc_offset_b
= 0;
172 * location of SC register in payload memory with respect to the first
173 * register in the mmr address data block
175 u32
*sc_reg9
= sc_reg8
+ 1;
176 u32
*sc_reg12
= sc_reg8
+ 4;
177 u32
*sc_reg13
= sc_reg8
+ 5;
178 u32
*sc_reg24
= sc_reg17
+ 7;
182 /* clear all the features(they may get enabled elsewhere later) */
183 val
&= ~(CFG_SELFGEN_FID
| CFG_TRIM
| CFG_ENABLE_SIN2_VER_INTP
|
184 CFG_INTERLACE_I
| CFG_DCM_4X
| CFG_DCM_2X
| CFG_AUTO_HS
|
185 CFG_ENABLE_EV
| CFG_USE_RAV
| CFG_INVT_FID
| CFG_SC_BYPASS
|
186 CFG_INTERLACE_O
| CFG_Y_PK_EN
| CFG_HP_BYPASS
| CFG_LINEAR
);
188 if (src_w
== dst_w
&& src_h
== dst_h
) {
189 val
|= CFG_SC_BYPASS
;
194 /* we only support linear scaling for now */
197 /* configure horizontal scaler */
199 /* enable 2X or 4X decimation */
200 dcm_x
= src_w
/ dst_w
;
204 } else if (dcm_x
> 2) {
212 lin_acc_inc
= div64_u64(((u64
)(src_w
>> dcm_shift
) - 1) << 24, lltmp
);
216 dev_dbg(dev
, "hs config: src_w = %d, dst_w = %d, decimation = %s, lin_acc_inc = %08x\n",
217 src_w
, dst_w
, dcm_shift
== 2 ? "4x" :
218 (dcm_shift
== 1 ? "2x" : "none"), lin_acc_inc
);
220 /* configure vertical scaler */
222 /* use RAV for vertical scaler if vertical downscaling is > 4x */
223 if (dst_h
< (src_h
>> 2)) {
232 factor
= (u16
) ((dst_h
<< 10) / src_h
);
234 row_acc_init_rav
= factor
+ ((1 + factor
) >> 1);
235 if (row_acc_init_rav
>= 1024)
236 row_acc_init_rav
-= 1024;
238 row_acc_init_rav_b
= row_acc_init_rav
+
239 (1 + (row_acc_init_rav
>> 1)) -
242 if (row_acc_init_rav_b
< 0) {
243 row_acc_init_rav_b
+= row_acc_init_rav
;
244 row_acc_init_rav
*= 2;
247 dev_dbg(dev
, "vs config(RAV): src_h = %d, dst_h = %d, factor = %d, acc_init = %08x, acc_init_b = %08x\n",
248 src_h
, dst_h
, factor
, row_acc_init_rav
,
252 row_acc_inc
= ((src_h
- 1) << 16) / (dst_h
- 1);
254 row_acc_offset_b
= 0;
256 dev_dbg(dev
, "vs config(POLY): src_h = %d, dst_h = %d,row_acc_inc = %08x\n",
257 src_h
, dst_h
, row_acc_inc
);
262 sc_reg0
[1] = row_acc_inc
;
263 sc_reg0
[2] = row_acc_offset
;
264 sc_reg0
[3] = row_acc_offset_b
;
266 sc_reg0
[4] = ((lin_acc_inc_u
& CFG_LIN_ACC_INC_U_MASK
) <<
267 CFG_LIN_ACC_INC_U_SHIFT
) | (dst_w
<< CFG_TAR_W_SHIFT
) |
268 (dst_h
<< CFG_TAR_H_SHIFT
);
270 sc_reg0
[5] = (src_w
<< CFG_SRC_W_SHIFT
) | (src_h
<< CFG_SRC_H_SHIFT
);
272 sc_reg0
[6] = (row_acc_init_rav_b
<< CFG_ROW_ACC_INIT_RAV_B_SHIFT
) |
273 (row_acc_init_rav
<< CFG_ROW_ACC_INIT_RAV_SHIFT
);
275 *sc_reg9
= lin_acc_inc
;
277 *sc_reg12
= col_acc_offset
<< CFG_COL_ACC_OFFSET_SHIFT
;
281 *sc_reg24
= (src_w
<< CFG_ORG_W_SHIFT
) | (src_h
<< CFG_ORG_H_SHIFT
);
284 struct sc_data
*sc_create(struct platform_device
*pdev
)
288 dev_dbg(&pdev
->dev
, "sc_create\n");
290 sc
= devm_kzalloc(&pdev
->dev
, sizeof(*sc
), GFP_KERNEL
);
292 dev_err(&pdev
->dev
, "couldn't alloc sc_data\n");
293 return ERR_PTR(-ENOMEM
);
298 sc
->res
= platform_get_resource_byname(pdev
, IORESOURCE_MEM
, "sc");
300 dev_err(&pdev
->dev
, "missing platform resources data\n");
301 return ERR_PTR(-ENODEV
);
304 sc
->base
= devm_ioremap_resource(&pdev
->dev
, sc
->res
);
306 dev_err(&pdev
->dev
, "failed to ioremap\n");
307 return ERR_PTR(-ENOMEM
);