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