1b862a648SJernej Skrabec /*
2b862a648SJernej Skrabec  * Copyright (C) 2017 Jernej Skrabec <jernej.skrabec@siol.net>
3b862a648SJernej Skrabec  *
4b862a648SJernej Skrabec  * Coefficients are taken from BSP driver, which is:
5b862a648SJernej Skrabec  * Copyright (C) 2014-2015 Allwinner
6b862a648SJernej Skrabec  *
7b862a648SJernej Skrabec  * This file is licensed under the terms of the GNU General Public
8b862a648SJernej Skrabec  * License version 2.  This program is licensed "as is" without any
9b862a648SJernej Skrabec  * warranty of any kind, whether express or implied.
10b862a648SJernej Skrabec  */
11b862a648SJernej Skrabec 
12b862a648SJernej Skrabec #include "sun8i_ui_scaler.h"
134b09c073SJernej Skrabec #include "sun8i_vi_scaler.h"
14b862a648SJernej Skrabec 
15b862a648SJernej Skrabec static const u32 lan2coefftab16[240] = {
16b862a648SJernej Skrabec 	0x00004000, 0x00033ffe, 0x00063efc, 0x000a3bfb,
17b862a648SJernej Skrabec 	0xff0f37fb, 0xfe1433fb, 0xfd192ffb, 0xfd1f29fb,
18b862a648SJernej Skrabec 	0xfc2424fc, 0xfb291ffd, 0xfb2f19fd, 0xfb3314fe,
19b862a648SJernej Skrabec 	0xfb370fff, 0xfb3b0a00, 0xfc3e0600, 0xfe3f0300,
20b862a648SJernej Skrabec 
21b862a648SJernej Skrabec 	0xff053804, 0xff083801, 0xff0a3700, 0xff0e34ff,
22b862a648SJernej Skrabec 	0xff1232fd, 0xfe162ffd, 0xfd1b2cfc, 0xfd1f28fc,
23b862a648SJernej Skrabec 	0xfd2323fd, 0xfc281ffd, 0xfc2c1bfd, 0xfd2f16fe,
24b862a648SJernej Skrabec 	0xfd3212ff, 0xff340eff, 0x00360a00, 0x02370700,
25b862a648SJernej Skrabec 
26b862a648SJernej Skrabec 	0xff083207, 0xff0a3205, 0xff0d3103, 0xfe113001,
27b862a648SJernej Skrabec 	0xfe142e00, 0xfe182bff, 0xfe1b29fe, 0xfe1f25fe,
28b862a648SJernej Skrabec 	0xfe2222fe, 0xfe251ffe, 0xfe291bfe, 0xff2b18fe,
29b862a648SJernej Skrabec 	0x002e14fe, 0x013010ff, 0x03310dff, 0x05310a00,
30b862a648SJernej Skrabec 
31b862a648SJernej Skrabec 	0xff0a2e09, 0xff0c2e07, 0xff0f2d05, 0xff122c03,
32b862a648SJernej Skrabec 	0xfe152b02, 0xfe182901, 0xfe1b2700, 0xff1e24ff,
33b862a648SJernej Skrabec 	0xff2121ff, 0xff241eff, 0x00261bff, 0x012818ff,
34b862a648SJernej Skrabec 	0x022a15ff, 0x032c12ff, 0x052d0fff, 0x072d0c00,
35b862a648SJernej Skrabec 
36b862a648SJernej Skrabec 	0xff0c2a0b, 0xff0e2a09, 0xff102a07, 0xff132905,
37b862a648SJernej Skrabec 	0xff162803, 0xff182702, 0xff1b2501, 0xff1e2300,
38b862a648SJernej Skrabec 	0x00202000, 0x01221d00, 0x01251bff, 0x032618ff,
39b862a648SJernej Skrabec 	0x042815ff, 0x052913ff, 0x072a10ff, 0x092a0d00,
40b862a648SJernej Skrabec 
41b862a648SJernej Skrabec 	0xff0d280c, 0xff0f280a, 0xff112808, 0xff142706,
42b862a648SJernej Skrabec 	0xff162605, 0xff192503, 0x001b2302, 0x001d2201,
43b862a648SJernej Skrabec 	0x011f1f01, 0x01221d00, 0x02231b00, 0x04241800,
44b862a648SJernej Skrabec 	0x052616ff, 0x072713ff, 0x08271100, 0x0a280e00,
45b862a648SJernej Skrabec 
46b862a648SJernej Skrabec 	0xff0e260d, 0xff10260b, 0xff122609, 0xff142508,
47b862a648SJernej Skrabec 	0x00152506, 0x00182305, 0x001b2203, 0x011d2002,
48b862a648SJernej Skrabec 	0x011f1f01, 0x02201d01, 0x03221b00, 0x04231801,
49b862a648SJernej Skrabec 	0x06241600, 0x08251300, 0x09261100, 0x0b260f00,
50b862a648SJernej Skrabec 
51b862a648SJernej Skrabec 	0xff0e250e, 0xff10250c, 0x0011250a, 0x00142408,
52b862a648SJernej Skrabec 	0x00162307, 0x00182206, 0x011a2104, 0x011c2003,
53b862a648SJernej Skrabec 	0x021e1e02, 0x03201c01, 0x04211a01, 0x05221801,
54b862a648SJernej Skrabec 	0x07231600, 0x08241400, 0x0a241200, 0x0c241000,
55b862a648SJernej Skrabec 
56b862a648SJernej Skrabec 	0x000e240e, 0x0010240c, 0x0013230a, 0x00142309,
57b862a648SJernej Skrabec 	0x00162208, 0x01182106, 0x011a2005, 0x021b1f04,
58b862a648SJernej Skrabec 	0x031d1d03, 0x041e1c02, 0x05201a01, 0x06211801,
59b862a648SJernej Skrabec 	0x07221601, 0x09231400, 0x0a231300, 0x0c231100,
60b862a648SJernej Skrabec 
61b862a648SJernej Skrabec 	0x000f220f, 0x0011220d, 0x0013220b, 0x0015210a,
62b862a648SJernej Skrabec 	0x01162108, 0x01182007, 0x02191f06, 0x031a1e05,
63b862a648SJernej Skrabec 	0x041c1c04, 0x051d1b03, 0x061f1902, 0x07201801,
64b862a648SJernej Skrabec 	0x08211601, 0x0a211500, 0x0b221300, 0x0d221100,
65b862a648SJernej Skrabec 
66b862a648SJernej Skrabec 	0x0010210f, 0x0011210e, 0x0013210c, 0x0114200b,
67b862a648SJernej Skrabec 	0x01161f0a, 0x02171f08, 0x03181e07, 0x031a1d06,
68b862a648SJernej Skrabec 	0x041c1c04, 0x051d1a04, 0x071d1903, 0x081e1802,
69b862a648SJernej Skrabec 	0x091f1602, 0x0b1f1501, 0x0c211300, 0x0e201200,
70b862a648SJernej Skrabec 
71b862a648SJernej Skrabec 	0x00102010, 0x0012200e, 0x0013200d, 0x01151f0b,
72b862a648SJernej Skrabec 	0x01161f0a, 0x02171e09, 0x03191d07, 0x041a1c06,
73b862a648SJernej Skrabec 	0x051b1b05, 0x061c1a04, 0x071d1903, 0x081e1703,
74b862a648SJernej Skrabec 	0x0a1f1601, 0x0b1f1501, 0x0d201300, 0x0e201200,
75b862a648SJernej Skrabec 
76b862a648SJernej Skrabec 	0x00102010, 0x00121f0f, 0x00141f0d, 0x01141f0c,
77b862a648SJernej Skrabec 	0x02161e0a, 0x03171d09, 0x03181d08, 0x041a1c06,
78b862a648SJernej Skrabec 	0x051b1b05, 0x061c1a04, 0x081c1903, 0x091d1703,
79b862a648SJernej Skrabec 	0x0a1e1602, 0x0c1e1501, 0x0d1f1400, 0x0e1f1201,
80b862a648SJernej Skrabec 
81b862a648SJernej Skrabec 	0x00111e11, 0x00131e0f, 0x01131e0e, 0x02151d0c,
82b862a648SJernej Skrabec 	0x02161d0b, 0x03171c0a, 0x04181b09, 0x05191b07,
83b862a648SJernej Skrabec 	0x061a1a06, 0x071b1905, 0x091b1804, 0x0a1c1703,
84b862a648SJernej Skrabec 	0x0b1d1602, 0x0c1d1502, 0x0e1d1401, 0x0f1e1300,
85b862a648SJernej Skrabec 
86b862a648SJernej Skrabec 	0x00111e11, 0x00131d10, 0x01141d0e, 0x02151c0d,
87b862a648SJernej Skrabec 	0x03161c0b, 0x04171b0a, 0x05171b09, 0x06181a08,
88b862a648SJernej Skrabec 	0x07191907, 0x081a1806, 0x091a1805, 0x0a1b1704,
89b862a648SJernej Skrabec 	0x0b1c1603, 0x0d1c1502, 0x0e1d1401, 0x0f1d1301,
90b862a648SJernej Skrabec };
91b862a648SJernej Skrabec 
sun8i_ui_scaler_base(struct sun8i_mixer * mixer,int channel)924b09c073SJernej Skrabec static u32 sun8i_ui_scaler_base(struct sun8i_mixer *mixer, int channel)
934b09c073SJernej Skrabec {
944b09c073SJernej Skrabec 	int vi_num = mixer->cfg->vi_num;
954b09c073SJernej Skrabec 
96c50519e6SJernej Skrabec 	if (mixer->cfg->is_de3)
97c50519e6SJernej Skrabec 		return DE3_VI_SCALER_UNIT_BASE +
98c50519e6SJernej Skrabec 		       DE3_VI_SCALER_UNIT_SIZE * vi_num +
99c50519e6SJernej Skrabec 		       DE3_UI_SCALER_UNIT_SIZE * (channel - vi_num);
100c50519e6SJernej Skrabec 	else
101c50519e6SJernej Skrabec 		return DE2_VI_SCALER_UNIT_BASE +
102c50519e6SJernej Skrabec 		       DE2_VI_SCALER_UNIT_SIZE * vi_num +
1034b09c073SJernej Skrabec 		       DE2_UI_SCALER_UNIT_SIZE * (channel - vi_num);
1044b09c073SJernej Skrabec }
1054b09c073SJernej Skrabec 
sun8i_ui_scaler_coef_index(unsigned int step)106b862a648SJernej Skrabec static int sun8i_ui_scaler_coef_index(unsigned int step)
107b862a648SJernej Skrabec {
108b862a648SJernej Skrabec 	unsigned int scale, int_part, float_part;
109b862a648SJernej Skrabec 
110b862a648SJernej Skrabec 	scale = step >> (SUN8I_UI_SCALER_SCALE_FRAC - 3);
111b862a648SJernej Skrabec 	int_part = scale >> 3;
112b862a648SJernej Skrabec 	float_part = scale & 0x7;
113b862a648SJernej Skrabec 
114b862a648SJernej Skrabec 	switch (int_part) {
115b862a648SJernej Skrabec 	case 0:
116b862a648SJernej Skrabec 		return 0;
117b862a648SJernej Skrabec 	case 1:
118b862a648SJernej Skrabec 		return float_part;
119b862a648SJernej Skrabec 	case 2:
120b862a648SJernej Skrabec 		return 8 + (float_part >> 1);
121b862a648SJernej Skrabec 	case 3:
122b862a648SJernej Skrabec 		return 12;
123b862a648SJernej Skrabec 	case 4:
124b862a648SJernej Skrabec 		return 13;
125b862a648SJernej Skrabec 	default:
126b862a648SJernej Skrabec 		return 14;
127b862a648SJernej Skrabec 	}
128b862a648SJernej Skrabec }
129b862a648SJernej Skrabec 
sun8i_ui_scaler_enable(struct sun8i_mixer * mixer,int layer,bool enable)130b862a648SJernej Skrabec void sun8i_ui_scaler_enable(struct sun8i_mixer *mixer, int layer, bool enable)
131b862a648SJernej Skrabec {
1324b09c073SJernej Skrabec 	u32 val, base;
133b862a648SJernej Skrabec 
1344b09c073SJernej Skrabec 	if (WARN_ON(layer < mixer->cfg->vi_num))
135b862a648SJernej Skrabec 		return;
136b862a648SJernej Skrabec 
1374b09c073SJernej Skrabec 	base = sun8i_ui_scaler_base(mixer, layer);
1384b09c073SJernej Skrabec 
139b862a648SJernej Skrabec 	if (enable)
140b862a648SJernej Skrabec 		val = SUN8I_SCALER_GSU_CTRL_EN |
141b862a648SJernej Skrabec 		      SUN8I_SCALER_GSU_CTRL_COEFF_RDY;
142b862a648SJernej Skrabec 	else
143b862a648SJernej Skrabec 		val = 0;
144b862a648SJernej Skrabec 
1454b09c073SJernej Skrabec 	regmap_write(mixer->engine.regs, SUN8I_SCALER_GSU_CTRL(base), val);
146b862a648SJernej Skrabec }
147b862a648SJernej Skrabec 
sun8i_ui_scaler_setup(struct sun8i_mixer * mixer,int layer,u32 src_w,u32 src_h,u32 dst_w,u32 dst_h,u32 hscale,u32 vscale,u32 hphase,u32 vphase)148b862a648SJernej Skrabec void sun8i_ui_scaler_setup(struct sun8i_mixer *mixer, int layer,
149b862a648SJernej Skrabec 			   u32 src_w, u32 src_h, u32 dst_w, u32 dst_h,
150b862a648SJernej Skrabec 			   u32 hscale, u32 vscale, u32 hphase, u32 vphase)
151b862a648SJernej Skrabec {
152b862a648SJernej Skrabec 	u32 insize, outsize;
153b862a648SJernej Skrabec 	int i, offset;
1544b09c073SJernej Skrabec 	u32 base;
155b862a648SJernej Skrabec 
1564b09c073SJernej Skrabec 	if (WARN_ON(layer < mixer->cfg->vi_num))
157b862a648SJernej Skrabec 		return;
158b862a648SJernej Skrabec 
1594b09c073SJernej Skrabec 	base = sun8i_ui_scaler_base(mixer, layer);
1604b09c073SJernej Skrabec 
161b862a648SJernej Skrabec 	hphase <<= SUN8I_UI_SCALER_PHASE_FRAC - 16;
162b862a648SJernej Skrabec 	vphase <<= SUN8I_UI_SCALER_PHASE_FRAC - 16;
163b862a648SJernej Skrabec 	hscale <<= SUN8I_UI_SCALER_SCALE_FRAC - 16;
164b862a648SJernej Skrabec 	vscale <<= SUN8I_UI_SCALER_SCALE_FRAC - 16;
165b862a648SJernej Skrabec 
166b862a648SJernej Skrabec 	insize = SUN8I_UI_SCALER_SIZE(src_w, src_h);
167b862a648SJernej Skrabec 	outsize = SUN8I_UI_SCALER_SIZE(dst_w, dst_h);
168b862a648SJernej Skrabec 
169b862a648SJernej Skrabec 	regmap_write(mixer->engine.regs,
1704b09c073SJernej Skrabec 		     SUN8I_SCALER_GSU_OUTSIZE(base), outsize);
171b862a648SJernej Skrabec 	regmap_write(mixer->engine.regs,
1724b09c073SJernej Skrabec 		     SUN8I_SCALER_GSU_INSIZE(base), insize);
173b862a648SJernej Skrabec 	regmap_write(mixer->engine.regs,
1744b09c073SJernej Skrabec 		     SUN8I_SCALER_GSU_HSTEP(base), hscale);
175b862a648SJernej Skrabec 	regmap_write(mixer->engine.regs,
1764b09c073SJernej Skrabec 		     SUN8I_SCALER_GSU_VSTEP(base), vscale);
177b862a648SJernej Skrabec 	regmap_write(mixer->engine.regs,
1784b09c073SJernej Skrabec 		     SUN8I_SCALER_GSU_HPHASE(base), hphase);
179b862a648SJernej Skrabec 	regmap_write(mixer->engine.regs,
1804b09c073SJernej Skrabec 		     SUN8I_SCALER_GSU_VPHASE(base), vphase);
181b862a648SJernej Skrabec 	offset = sun8i_ui_scaler_coef_index(hscale) *
182b862a648SJernej Skrabec 			SUN8I_UI_SCALER_COEFF_COUNT;
183b862a648SJernej Skrabec 	for (i = 0; i < SUN8I_UI_SCALER_COEFF_COUNT; i++)
184b862a648SJernej Skrabec 		regmap_write(mixer->engine.regs,
1854b09c073SJernej Skrabec 			     SUN8I_SCALER_GSU_HCOEFF(base, i),
186b862a648SJernej Skrabec 			     lan2coefftab16[offset + i]);
187b862a648SJernej Skrabec }
188