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