1 /*
2 * Allwinner SoCs display driver.
3 *
4 * Copyright (C) 2016 Allwinner.
5 *
6 * This file is licensed under the terms of the GNU General Public
7 * License version 2. This program is licensed "as is" without any
8 * warranty of any kind, whether express or implied.
9 */
10
11 /*****************************************************************************
12 *All Winner Tech, All Right Reserved. 2014-2015 Copyright (c)
13 *
14 *File name : de_ccsc.c
15 *
16 *Description : display engine 2.0 device csc basic function definition
17 *
18 *History : 2014/05/19 vito cheng v0.1 Initial version
19 *****************************************************************************/
20
21 #include "de_rtmx.h"
22 #include "de_csc_type.h"
23 #include "de_csc.h"
24
25 #define DCSC_OFST 0xB0000
26 #define CSC_ENHANCE_MODE_NUM 3
27 /* must equal to ENHANCE_MODE_NUM */
28
29 static volatile struct __csc_reg_t *dcsc_dev[DE_NUM];
30 static volatile struct __csc2_reg_t *dcsc2_dev[DE_NUM];
31 static struct de_reg_blocks dcsc_coeff_block[DE_NUM];
32 static struct de_reg_blocks dcsc_enable_block[DE_NUM];
33 static struct disp_csc_config g_dcsc_config[DE_NUM];
34
35 static unsigned int is_in_smbl[DE_NUM];
36 /* device csc and smbl in the same module or not */
37
de_dcsc_set_reg_base(unsigned int sel,void * base)38 static int de_dcsc_set_reg_base(unsigned int sel, void *base)
39 {
40 DE_INF("sel=%d, base=0x%p\n", sel, base);
41 if (is_in_smbl[sel])
42 dcsc2_dev[sel] = (struct __csc2_reg_t *) base;
43 else
44 dcsc_dev[sel] = (struct __csc_reg_t *) base;
45
46 return 0;
47 }
48
49 int _csc_enhance_setting[CSC_ENHANCE_MODE_NUM][4] = {
50 {50, 50, 50, 50},
51 /* normal */
52 {50, 50, 50, 50},
53 /* vivid */
54 {50, 40, 50, 50},
55 /* soft */
56 };
57
de_dcsc_apply(unsigned int sel,struct disp_csc_config * config)58 int de_dcsc_apply(unsigned int sel, struct disp_csc_config *config)
59 {
60 int csc_coeff[12];
61 unsigned int enhance_mode;
62
63 config->enhance_mode =
64 (config->enhance_mode > CSC_ENHANCE_MODE_NUM - 1)
65 ? g_dcsc_config[sel].enhance_mode : config->enhance_mode;
66 enhance_mode = config->enhance_mode;
67 config->brightness = _csc_enhance_setting[enhance_mode][0];
68 config->contrast = _csc_enhance_setting[enhance_mode][1];
69 config->saturation = _csc_enhance_setting[enhance_mode][2];
70 config->hue = _csc_enhance_setting[enhance_mode][3];
71
72 DE_INF("sel=%d, in_fmt=%d, mode=%d, out_fmt=%d, mode=%d, range=%d\n",
73 sel, config->in_fmt, config->in_mode, config->out_fmt,
74 config->out_mode, config->out_color_range);
75
76 memcpy(&g_dcsc_config[sel], config, sizeof(struct disp_csc_config));
77 de_csc_coeff_calc(config->in_fmt, config->in_mode, config->out_fmt,
78 config->out_mode, config->brightness,
79 config->contrast, config->saturation, config->hue,
80 config->out_color_range, csc_coeff);
81
82 if (is_in_smbl[sel]) {
83 dcsc2_dev[sel]->c00.dwval = *(csc_coeff);
84 dcsc2_dev[sel]->c01.dwval = *(csc_coeff + 1);
85 dcsc2_dev[sel]->c02.dwval = *(csc_coeff + 2);
86 dcsc2_dev[sel]->c03.dwval = *(csc_coeff + 3) >> 6;
87 dcsc2_dev[sel]->c10.dwval = *(csc_coeff + 4);
88 dcsc2_dev[sel]->c11.dwval = *(csc_coeff + 5);
89 dcsc2_dev[sel]->c12.dwval = *(csc_coeff + 6);
90 dcsc2_dev[sel]->c13.dwval = *(csc_coeff + 7) >> 6;
91 dcsc2_dev[sel]->c20.dwval = *(csc_coeff + 8);
92 dcsc2_dev[sel]->c21.dwval = *(csc_coeff + 9);
93 dcsc2_dev[sel]->c22.dwval = *(csc_coeff + 10);
94 dcsc2_dev[sel]->c23.dwval = *(csc_coeff + 11) >> 6;
95 dcsc2_dev[sel]->bypass.bits.enable = 1;
96 /* always enable csc */
97 } else {
98 dcsc_dev[sel]->c00.dwval = *(csc_coeff);
99 dcsc_dev[sel]->c01.dwval = *(csc_coeff + 1);
100 dcsc_dev[sel]->c02.dwval = *(csc_coeff + 2);
101 dcsc_dev[sel]->c03.dwval = *(csc_coeff + 3) + 0x200;
102 dcsc_dev[sel]->c10.dwval = *(csc_coeff + 4);
103 dcsc_dev[sel]->c11.dwval = *(csc_coeff + 5);
104 dcsc_dev[sel]->c12.dwval = *(csc_coeff + 6);
105 dcsc_dev[sel]->c13.dwval = *(csc_coeff + 7) + 0x200;
106 dcsc_dev[sel]->c20.dwval = *(csc_coeff + 8);
107 dcsc_dev[sel]->c21.dwval = *(csc_coeff + 9);
108 dcsc_dev[sel]->c22.dwval = *(csc_coeff + 10);
109 dcsc_dev[sel]->c23.dwval = *(csc_coeff + 11) + 0x200;
110 dcsc_dev[sel]->bypass.bits.enable = 1;
111 /* always enable csc */
112 }
113
114 dcsc_coeff_block[sel].dirty = 1;
115 dcsc_enable_block[sel].dirty = 1;
116
117 return 0;
118 }
119
de_dcsc_get_config(unsigned int sel,struct disp_csc_config * config)120 int de_dcsc_get_config(unsigned int sel, struct disp_csc_config *config)
121 {
122 memcpy(config, &g_dcsc_config[sel], sizeof(struct disp_csc_config));
123
124 return 0;
125 }
126
de_dcsc_update_regs(unsigned int sel)127 int de_dcsc_update_regs(unsigned int sel)
128 {
129 unsigned int reg_val;
130
131 if (dcsc_enable_block[sel].dirty == 0x1) {
132 if (is_in_smbl[sel]) {
133 reg_val =
134 readl((void *)dcsc_enable_block[sel].off);
135 reg_val &= 0xfffffffd;
136 reg_val |=
137 (*((unsigned int *)dcsc_enable_block[sel].val));
138 writel(reg_val,
139 (void *)dcsc_enable_block[sel].off);
140 } else {
141 regwrite((void *)dcsc_enable_block[sel].off,
142 dcsc_enable_block[sel].val,
143 dcsc_enable_block[sel].size);
144 }
145 dcsc_enable_block[sel].dirty = 0x0;
146 }
147
148 if (dcsc_coeff_block[sel].dirty == 0x1) {
149 regwrite((void *)dcsc_coeff_block[sel].off,
150 dcsc_coeff_block[sel].val, dcsc_coeff_block[sel].size);
151 dcsc_coeff_block[sel].dirty = 0x0;
152 }
153
154 return 0;
155 }
156
de_dcsc_init(struct disp_bsp_init_para * para)157 int de_dcsc_init(struct disp_bsp_init_para *para)
158 {
159 uintptr_t base;
160 void *memory;
161 int screen_id, device_num;
162
163 device_num = de_feat_get_num_screens();
164
165 for (screen_id = 0; screen_id < device_num; screen_id++) {
166 is_in_smbl[screen_id] = de_feat_is_support_smbl(screen_id);
167
168 #if defined(CONFIG_ARCH_SUN50IW10)
169 base = para->reg_base[DISP_MOD_DE + screen_id]
170 + (screen_id + 1) * 0x00100000 + DCSC_OFST;
171 if (screen_id)
172 base = base - 0x00100000;
173 #else
174 base = para->reg_base[DISP_MOD_DE]
175 + (screen_id + 1) * 0x00100000 + DCSC_OFST;
176 #endif
177 DE_INF("sel %d, Dcsc_base=0x%p\n", screen_id, (void *)base);
178
179 if (is_in_smbl[screen_id]) {
180 memory = disp_sys_malloc(sizeof(struct __csc2_reg_t));
181 if (memory == NULL) {
182 DE_WRN("disp_sys_malloc Ccsc[%d] mm fail! size=0x%x\n",
183 screen_id,
184 (unsigned int)sizeof(struct __csc2_reg_t));
185 return -1;
186 }
187
188 dcsc_enable_block[screen_id].off = base;
189 dcsc_enable_block[screen_id].val = memory;
190 dcsc_enable_block[screen_id].size = 0x04;
191 dcsc_enable_block[screen_id].dirty = 0;
192
193 dcsc_coeff_block[screen_id].off = base + 0x80;
194 dcsc_coeff_block[screen_id].val = memory + 0x80;
195 dcsc_coeff_block[screen_id].size = 0x30;
196 dcsc_coeff_block[screen_id].dirty = 0;
197
198 } else {
199 memory = disp_sys_malloc(sizeof(struct __csc_reg_t));
200 if (memory == NULL) {
201 DE_WRN("disp_sys_malloc Ccsc[%d] mm fail! size=0x%x\n",
202 screen_id,
203 (unsigned int)sizeof(struct __csc_reg_t));
204 return -1;
205 }
206
207 dcsc_enable_block[screen_id].off = base;
208 dcsc_enable_block[screen_id].val = memory;
209 dcsc_enable_block[screen_id].size = 0x04;
210 dcsc_enable_block[screen_id].dirty = 0;
211
212 dcsc_coeff_block[screen_id].off = base + 0x10;
213 dcsc_coeff_block[screen_id].val = memory + 0x10;
214 dcsc_coeff_block[screen_id].size = 0x30;
215 dcsc_coeff_block[screen_id].dirty = 0;
216 }
217 g_dcsc_config[screen_id].enhance_mode = 0;
218 de_dcsc_set_reg_base(screen_id, memory);
219 }
220
221 return 0;
222 }
223
de_dcsc_exit(void)224 int de_dcsc_exit(void)
225 {
226 int screen_id, device_num;
227
228 device_num = de_feat_get_num_screens();
229
230 for (screen_id = 0; screen_id < device_num; screen_id++) {
231 is_in_smbl[screen_id] = de_feat_is_support_smbl(screen_id);
232
233 if (is_in_smbl[screen_id])
234 disp_sys_free(dcsc_enable_block[screen_id].val);
235 else
236 disp_sys_free(dcsc_enable_block[screen_id].val);
237 }
238
239 return 0;
240 }
241
242