• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * linux-5.4/drivers/media/platform/sunxi-vin/vin-cci/csi_cci_reg.c
3  *
4  * Copyright (c) 2007-2017 Allwinnertech Co., Ltd.
5  *
6  * This software is licensed under the terms of the GNU General Public
7  * License version 2, as published by the Free Software Foundation, and
8  * may be copied, distributed, and modified under those terms.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  */
16 
17 /*
18  ******************************************************************************
19  *
20  * csi_cci_reg.c
21  *
22  * Hawkview ISP - csi_cci_reg.c module
23  *
24  * Copyright (c) 2015 by Allwinnertech Co., Ltd.  http://www.allwinnertech.com
25  *
26  * Version         Author         Date          Description
27  *
28  *   3.0         Yang Feng    2015/12/02    ISP Tuning Tools Support
29  *
30  ******************************************************************************
31  */
32 
33 #include "csi_cci_reg_i.h"
34 #include "csi_cci_reg.h"
35 
36 #include "../utility/vin_io.h"
37 
38 unsigned int fifo_last_pt[MAX_CSIC_CCI_NUM];
39 volatile void __iomem *csi_cci_base_addr[MAX_CSIC_CCI_NUM];
40 
csi_cci_set_base_addr(unsigned int sel,unsigned long addr)41 int csi_cci_set_base_addr(unsigned int sel, unsigned long addr)
42 {
43 	if (sel >= MAX_CSIC_CCI_NUM)
44 		return -1;
45 	csi_cci_base_addr[sel] = (volatile void __iomem *)addr;
46 	return 0;
47 }
48 
csi_cci_enable(unsigned int sel)49 void csi_cci_enable(unsigned int sel)
50 {
51 	vin_reg_set(csi_cci_base_addr[sel] + CCI_CTRL_OFF,
52 		    1 << CCI_CTRL_CCI_EN);
53 }
54 
csi_cci_disable(unsigned int sel)55 void csi_cci_disable(unsigned int sel)
56 {
57 	vin_reg_clr(csi_cci_base_addr[sel] + CCI_CTRL_OFF,
58 		    1 << CCI_CTRL_CCI_EN);
59 }
60 
csi_cci_reset(unsigned int sel)61 void csi_cci_reset(unsigned int sel)
62 {
63 	vin_reg_set(csi_cci_base_addr[sel] + CCI_CTRL_OFF,
64 		    1 << CCI_CTRL_SOFT_RESET);
65 	vin_reg_clr(csi_cci_base_addr[sel] + CCI_CTRL_OFF,
66 		    1 << CCI_CTRL_SOFT_RESET);
67 }
68 
csi_cci_set_clk_div(unsigned int sel,unsigned char * div_coef)69 void csi_cci_set_clk_div(unsigned int sel, unsigned char *div_coef)
70 {
71 	vin_reg_clr_set(csi_cci_base_addr[sel] + CCI_BUS_CTRL_OFF,
72 			CCI_BUS_CTRL_CLK_M_MASK,
73 			div_coef[0] << CCI_BUS_CTRL_CLK_M);
74 	vin_reg_clr_set(csi_cci_base_addr[sel] + CCI_BUS_CTRL_OFF,
75 			CCI_BUS_CTRL_CLK_N_MASK,
76 			div_coef[1] << CCI_BUS_CTRL_CLK_N);
77 }
78 
79 /*interval unit in 40 scl cycles*/
csi_cci_set_pkt_interval(unsigned int sel,unsigned char interval)80 void csi_cci_set_pkt_interval(unsigned int sel, unsigned char interval)
81 {
82 	vin_reg_clr_set(csi_cci_base_addr[sel] + CCI_CFG_OFF,
83 			CCI_CFG_INTERVAL_MASK, interval << CCI_CFG_INTERVAL);
84 }
85 
86 /*timeout unit in scl cycle*/
csi_cci_set_ack_timeout(unsigned int sel,unsigned char to_val)87 void csi_cci_set_ack_timeout(unsigned int sel, unsigned char to_val)
88 {
89 	vin_reg_clr_set(csi_cci_base_addr[sel] + CCI_CFG_OFF,
90 			CCI_CFG_TIMEOUT_N_MASK, to_val << CCI_CFG_TIMEOUT_N);
91 }
92 
93 /*trig delay unit in scl cycle*/
csi_cci_set_trig_dly(unsigned int sel,unsigned int dly)94 void csi_cci_set_trig_dly(unsigned int sel, unsigned int dly)
95 {
96 	if (dly == 0) {
97 		vin_reg_clr(csi_cci_base_addr[sel] + CCI_BUS_CTRL_OFF,
98 			    1 << CCI_BUS_CTRL_DLY_TRIG);
99 	} else {
100 		vin_reg_set(csi_cci_base_addr[sel] + CCI_BUS_CTRL_OFF,
101 			    1 << CCI_BUS_CTRL_DLY_TRIG);
102 		vin_reg_clr_set(csi_cci_base_addr[sel] + CCI_BUS_CTRL_OFF,
103 				CCI_BUS_CTRL_DLY_CYC_MASK,
104 				dly << CCI_BUS_CTRL_DLY_CYC);
105 	}
106 }
107 
csi_cci_trans_start(unsigned int sel,enum cci_trans_mode trans_mode)108 void csi_cci_trans_start(unsigned int sel, enum cci_trans_mode trans_mode)
109 {
110 	fifo_last_pt[sel] = 0;
111 	switch (trans_mode) {
112 	case SINGLE:
113 		vin_reg_clr(csi_cci_base_addr[sel] + CCI_CTRL_OFF,
114 			    1 << CCI_CTRL_REPEAT_TRAN);
115 		vin_reg_set(csi_cci_base_addr[sel] + CCI_CTRL_OFF,
116 			    1 << CCI_CTRL_SINGLE_TRAN);
117 		break;
118 	case REPEAT:
119 		vin_reg_clr(csi_cci_base_addr[sel] + CCI_CTRL_OFF,
120 			    1 << CCI_CTRL_SINGLE_TRAN);
121 		vin_reg_set(csi_cci_base_addr[sel] + CCI_CTRL_OFF,
122 			    1 << CCI_CTRL_REPEAT_TRAN);
123 		break;
124 	default:
125 		vin_reg_clr(csi_cci_base_addr[sel] + CCI_CTRL_OFF,
126 			    1 << CCI_CTRL_SINGLE_TRAN);
127 		vin_reg_clr(csi_cci_base_addr[sel] + CCI_CTRL_OFF,
128 			    1 << CCI_CTRL_REPEAT_TRAN);
129 		break;
130 	}
131 }
132 
csi_cci_get_trans_done(unsigned int sel)133 unsigned int csi_cci_get_trans_done(unsigned int sel)
134 {
135 	unsigned int reg_val, single_tran;
136 
137 	reg_val = vin_reg_readl(csi_cci_base_addr[sel] + CCI_CTRL_OFF);
138 	single_tran = (reg_val & (1 << CCI_CTRL_SINGLE_TRAN));
139 	if (single_tran == 0)
140 		return 0;
141 	else
142 		return 1;
143 }
144 
csi_cci_set_bus_fmt(unsigned int sel,struct cci_bus_fmt * bus_fmt)145 void csi_cci_set_bus_fmt(unsigned int sel, struct cci_bus_fmt *bus_fmt)
146 {
147 	if (bus_fmt->rs_mode == 0)
148 		vin_reg_clr(csi_cci_base_addr[sel] + CCI_CTRL_OFF,
149 			    1 << CCI_CTRL_RESTART_MODE);
150 	else
151 		vin_reg_set(csi_cci_base_addr[sel] + CCI_CTRL_OFF,
152 			    1 << CCI_CTRL_RESTART_MODE);
153 
154 	if (bus_fmt->rs_start == 0)
155 		vin_reg_clr(csi_cci_base_addr[sel] + CCI_CTRL_OFF,
156 			    1 << CCI_CTRL_READ_TRAN_MODE);
157 	else
158 		vin_reg_set(csi_cci_base_addr[sel] + CCI_CTRL_OFF,
159 			    1 << CCI_CTRL_READ_TRAN_MODE);
160 
161 	vin_reg_clr_set(csi_cci_base_addr[sel] + CCI_FMT_OFF,
162 			CCI_FMT_SLV_ID_MASK,
163 			bus_fmt->saddr_7bit << CCI_FMT_SLV_ID);
164 	vin_reg_clr_set(csi_cci_base_addr[sel] + CCI_FMT_OFF, CCI_FMT_CMD_MASK,
165 			bus_fmt->wr_flag << CCI_FMT_CMD);
166 	vin_reg_clr_set(csi_cci_base_addr[sel] + CCI_FMT_OFF,
167 			CCI_FMT_ADDR_BYTE_MASK,
168 			bus_fmt->addr_len << CCI_FMT_ADDR_BYTE);
169 	vin_reg_clr_set(csi_cci_base_addr[sel] + CCI_FMT_OFF,
170 			CCI_FMT_DATA_BYTE_MASK,
171 			bus_fmt->data_len << CCI_FMT_DATA_BYTE);
172 }
173 
csi_cci_set_tx_buf_mode(unsigned int sel,struct cci_tx_buf * tx_buf_mode)174 void csi_cci_set_tx_buf_mode(unsigned int sel, struct cci_tx_buf *tx_buf_mode)
175 {
176 	vin_reg_clr_set(csi_cci_base_addr[sel] + CCI_CFG_OFF,
177 			CCI_CFG_SRC_SEL_MASK,
178 			tx_buf_mode->buf_src << CCI_CFG_SRC_SEL);
179 	vin_reg_clr_set(csi_cci_base_addr[sel] + CCI_CFG_OFF,
180 			CCI_CFG_PACKET_MODE_MASK,
181 			tx_buf_mode->pkt_mode << CCI_CFG_PACKET_MODE);
182 	vin_reg_clr_set(csi_cci_base_addr[sel] + CCI_FMT_OFF,
183 			CCI_FMT_PACKET_CNT_MASK,
184 			tx_buf_mode->pkt_cnt << CCI_FMT_PACKET_CNT);
185 }
186 
csi_cci_fifo_pt_reset(unsigned int sel)187 void csi_cci_fifo_pt_reset(unsigned int sel)
188 {
189 	fifo_last_pt[sel] = 0;
190 }
191 
csi_cci_fifo_pt_add(unsigned int sel,unsigned int byte_cnt)192 void csi_cci_fifo_pt_add(unsigned int sel, unsigned int byte_cnt)
193 {
194 	fifo_last_pt[sel] += byte_cnt;
195 }
196 
csi_cci_fifo_pt_sub(unsigned int sel,unsigned int byte_cnt)197 void csi_cci_fifo_pt_sub(unsigned int sel, unsigned int byte_cnt)
198 {
199 	fifo_last_pt[sel] -= byte_cnt;
200 }
201 
cci_wr_tx_buf(unsigned int sel,unsigned int byte_index,unsigned char value)202 static void cci_wr_tx_buf(unsigned int sel, unsigned int byte_index,
203 			  unsigned char value)
204 {
205 	unsigned int index_remain, index_dw_align, tmp;
206 
207 	index_remain = (byte_index) % 4;
208 	index_dw_align = (byte_index) / 4;
209 
210 	tmp =
211 	    vin_reg_readl(csi_cci_base_addr[sel] + CCI_FIFO_ACC_OFF +
212 			  4 * index_dw_align);
213 	tmp &= ~(0xff << (index_remain << 3));
214 	tmp |= value << (index_remain << 3);
215 	vin_reg_writel(csi_cci_base_addr[sel] + CCI_FIFO_ACC_OFF +
216 		       4 * index_dw_align, tmp);
217 }
218 
cci_rd_tx_buf(unsigned int sel,unsigned int byte_index,unsigned char * value)219 static void cci_rd_tx_buf(unsigned int sel, unsigned int byte_index,
220 			  unsigned char *value)
221 {
222 	unsigned int index_remain, index_dw_align, tmp;
223 
224 	index_remain = (byte_index) % 4;
225 	index_dw_align = (byte_index) / 4;
226 	tmp =
227 	    vin_reg_readl(csi_cci_base_addr[sel] + CCI_FIFO_ACC_OFF +
228 			  4 * index_dw_align);
229 	*value = (tmp & (0xff << (index_remain << 3))) >> (index_remain << 3);
230 }
231 
csi_cci_wr_tx_buf(unsigned int sel,unsigned char * buf,unsigned int byte_cnt)232 void csi_cci_wr_tx_buf(unsigned int sel, unsigned char *buf,
233 		       unsigned int byte_cnt)
234 {
235 	unsigned int i;
236 
237 	for (i = 0; i < byte_cnt; i++, fifo_last_pt[sel]++)
238 		cci_wr_tx_buf(sel, fifo_last_pt[sel], buf[i]);
239 }
240 
csi_cci_rd_tx_buf(unsigned int sel,unsigned char * buf,unsigned int byte_cnt)241 void csi_cci_rd_tx_buf(unsigned int sel, unsigned char *buf,
242 		       unsigned int byte_cnt)
243 {
244 	unsigned int i;
245 
246 	for (i = 0; i < byte_cnt; i++, fifo_last_pt[sel]++)
247 		cci_rd_tx_buf(sel, fifo_last_pt[sel], &buf[i]);
248 }
249 
csi_cci_set_trig_mode(unsigned int sel,struct cci_tx_trig * tx_trig_mode)250 void csi_cci_set_trig_mode(unsigned int sel, struct cci_tx_trig *tx_trig_mode)
251 {
252 	vin_reg_clr_set(csi_cci_base_addr[sel] + CCI_CFG_OFF,
253 			CCI_CFG_TRIG_MODE_MASK,
254 			tx_trig_mode->trig_src << CCI_CFG_TRIG_MODE);
255 	vin_reg_clr_set(csi_cci_base_addr[sel] + CCI_CFG_OFF,
256 			CCI_CFG_CSI_TRIG_MASK,
257 			tx_trig_mode->trig_con << CCI_CFG_CSI_TRIG);
258 }
259 
csi_cci_set_trig_line_cnt(unsigned int sel,unsigned int line_cnt)260 void csi_cci_set_trig_line_cnt(unsigned int sel, unsigned int line_cnt)
261 {
262 	vin_reg_clr_set(csi_cci_base_addr[sel] + CCI_LC_TRIG_OFF,
263 			CCI_LC_TRIG_LN_CNT_MASK,
264 			line_cnt << CCI_LC_TRIG_LN_CNT);
265 }
266 
cci_int_enable(unsigned int sel,enum cci_int_sel interrupt)267 void cci_int_enable(unsigned int sel, enum cci_int_sel interrupt)
268 {
269 	vin_reg_set(csi_cci_base_addr[sel] + CCI_INT_CTRL_OFF,
270 		    ((interrupt << 16) & 0xffff0000));
271 }
272 
cci_int_disable(unsigned int sel,enum cci_int_sel interrupt)273 void cci_int_disable(unsigned int sel, enum cci_int_sel interrupt)
274 {
275 	vin_reg_clr(csi_cci_base_addr[sel] + CCI_INT_CTRL_OFF,
276 		    ((interrupt << 16) & 0xffff0000));
277 }
278 
cci_int_get_status(unsigned int sel,struct cci_int_status * status)279 void CCI_INLINE cci_int_get_status(unsigned int sel,
280 					struct cci_int_status *status)
281 {
282 	unsigned int reg_val =
283 	    vin_reg_readl(csi_cci_base_addr[sel] + CCI_INT_CTRL_OFF);
284 	status->complete = (reg_val >> CCI_INT_CTRL_S_TRAN_COM_PD) & 0x1;
285 	status->error = (reg_val >> CCI_INT_CTRL_S_TRAN_ERR_PD) & 0x1;
286 }
287 
cci_int_clear_status(unsigned int sel,enum cci_int_sel interrupt)288 void CCI_INLINE cci_int_clear_status(unsigned int sel,
289 					  enum cci_int_sel interrupt)
290 {
291 	vin_reg_clr(csi_cci_base_addr[sel] + CCI_INT_CTRL_OFF, 0xffff << 0);
292 	vin_reg_set(csi_cci_base_addr[sel] + CCI_INT_CTRL_OFF, interrupt << 0);
293 }
294 
cci_get_bus_status(unsigned int sel)295 enum cci_bus_status CCI_INLINE cci_get_bus_status(unsigned int sel)
296 {
297 	unsigned int reg_val =
298 	    vin_reg_readl(csi_cci_base_addr[sel] + CCI_CTRL_OFF);
299 	return (reg_val >> CCI_CTRL_CCI_STA) & 0xff;
300 }
301 
cci_get_line_status(unsigned int sel,struct cci_line_status * status)302 void cci_get_line_status(unsigned int sel, struct cci_line_status *status)
303 {
304 	unsigned int reg_val =
305 	    vin_reg_readl(csi_cci_base_addr[sel] + CCI_BUS_CTRL_OFF);
306 	status->cci_sck = (reg_val >> CCI_BUS_CTRL_SCL_STA) & 0x1;
307 	status->cci_sda = (reg_val >> CCI_BUS_CTRL_SDA_STA) & 0x1;
308 }
309 
cci_pad_en(unsigned int sel)310 void cci_pad_en(unsigned int sel)
311 {
312 	vin_reg_set(csi_cci_base_addr[sel] + CCI_BUS_CTRL_OFF,
313 		    1 << CCI_BUS_CTRL_SDA_PEN);
314 	vin_reg_set(csi_cci_base_addr[sel] + CCI_BUS_CTRL_OFF,
315 		    1 << CCI_BUS_CTRL_SCL_PEN);
316 }
317 
cci_stop(unsigned int sel)318 void cci_stop(unsigned int sel)
319 {
320 	vin_reg_set(csi_cci_base_addr[sel] + CCI_BUS_CTRL_OFF,
321 		    1 << CCI_BUS_CTRL_SCL_MOE);
322 	vin_reg_set(csi_cci_base_addr[sel] + CCI_BUS_CTRL_OFF,
323 		    1 << CCI_BUS_CTRL_SDA_MOE);
324 	vin_reg_set(csi_cci_base_addr[sel] + CCI_BUS_CTRL_OFF,
325 		    1 << CCI_BUS_CTRL_SCL_MOV);
326 	csi_cci_udelay(5);
327 	vin_reg_clr(csi_cci_base_addr[sel] + CCI_BUS_CTRL_OFF,
328 		    1 << CCI_BUS_CTRL_SDA_MOV);
329 	csi_cci_udelay(5);
330 	vin_reg_clr(csi_cci_base_addr[sel] + CCI_BUS_CTRL_OFF,
331 		    1 << CCI_BUS_CTRL_SCL_MOE);
332 	vin_reg_clr(csi_cci_base_addr[sel] + CCI_BUS_CTRL_OFF,
333 		    1 << CCI_BUS_CTRL_SDA_MOE);
334 }
335 
cci_sck_cycles(unsigned int sel,unsigned int cycle_times)336 void cci_sck_cycles(unsigned int sel, unsigned int cycle_times)
337 {
338 	vin_reg_set(csi_cci_base_addr[sel] + CCI_BUS_CTRL_OFF,
339 		    1 << CCI_BUS_CTRL_SCL_MOE);
340 	vin_reg_set(csi_cci_base_addr[sel] + CCI_BUS_CTRL_OFF,
341 		    1 << CCI_BUS_CTRL_SDA_MOE);
342 	while (cycle_times) {
343 		vin_reg_set(csi_cci_base_addr[sel] + CCI_BUS_CTRL_OFF,
344 			    1 << CCI_BUS_CTRL_SCL_MOV);
345 		csi_cci_udelay(5);
346 		vin_reg_clr(csi_cci_base_addr[sel] + CCI_BUS_CTRL_OFF,
347 			    1 << CCI_BUS_CTRL_SCL_MOV);
348 		csi_cci_udelay(5);
349 		cycle_times--;
350 	}
351 	vin_reg_clr(csi_cci_base_addr[sel] + CCI_BUS_CTRL_OFF,
352 		    1 << CCI_BUS_CTRL_SCL_MOE);
353 	vin_reg_clr(csi_cci_base_addr[sel] + CCI_BUS_CTRL_OFF,
354 		    1 << CCI_BUS_CTRL_SDA_MOE);
355 }
356 
cci_print_info(unsigned int sel)357 void cci_print_info(unsigned int sel)
358 {
359 	unsigned int reg_val = 0, i;
360 
361 	pr_info("Print cci regs:\n");
362 	for (i = 0; i < 32; i += 4) {
363 		reg_val = vin_reg_readl(csi_cci_base_addr[sel] + i);
364 		pr_info("0x%lx = 0x%x\n",
365 		       (unsigned long int)csi_cci_base_addr[sel] + i, reg_val);
366 	}
367 
368 	for (i = 0; i < 12; i += 4) {
369 		reg_val = vin_reg_readl(csi_cci_base_addr[sel] + 0x100 + i);
370 		pr_info("0x%lx = 0x%x\n",
371 		       (unsigned long int)csi_cci_base_addr[sel] + 0x100 + i,
372 		       reg_val);
373 	}
374 }
375