diff options
Diffstat (limited to 'meta/recipes-kernel/linux/linux-omap-2.6.29/isp/omap3camera/0007-omap3isp-Add-CSI2-interface-support.patch')
-rw-r--r-- | meta/recipes-kernel/linux/linux-omap-2.6.29/isp/omap3camera/0007-omap3isp-Add-CSI2-interface-support.patch | 2384 |
1 files changed, 2384 insertions, 0 deletions
diff --git a/meta/recipes-kernel/linux/linux-omap-2.6.29/isp/omap3camera/0007-omap3isp-Add-CSI2-interface-support.patch b/meta/recipes-kernel/linux/linux-omap-2.6.29/isp/omap3camera/0007-omap3isp-Add-CSI2-interface-support.patch new file mode 100644 index 0000000000..842f395388 --- /dev/null +++ b/meta/recipes-kernel/linux/linux-omap-2.6.29/isp/omap3camera/0007-omap3isp-Add-CSI2-interface-support.patch | |||
@@ -0,0 +1,2384 @@ | |||
1 | From 9fbe7b786427d981cac890a7407da09232f5d1e2 Mon Sep 17 00:00:00 2001 | ||
2 | From: Sakari Ailus <sakari.ailus@maxwell.research.nokia.com> | ||
3 | Date: Tue, 10 Mar 2009 10:49:02 +0200 | ||
4 | Subject: [PATCH] omap3isp: Add CSI2 interface support | ||
5 | |||
6 | Signed-off-by: Sakari Ailus <sakari.ailus@maxwell.research.nokia.com> | ||
7 | --- | ||
8 | drivers/media/video/isp/ispcsi2.c | 2124 +++++++++++++++++++++++++++++++++++++ | ||
9 | drivers/media/video/isp/ispcsi2.h | 232 ++++ | ||
10 | 2 files changed, 2356 insertions(+), 0 deletions(-) | ||
11 | create mode 100644 drivers/media/video/isp/ispcsi2.c | ||
12 | create mode 100644 drivers/media/video/isp/ispcsi2.h | ||
13 | |||
14 | diff --git a/drivers/media/video/isp/ispcsi2.c b/drivers/media/video/isp/ispcsi2.c | ||
15 | new file mode 100644 | ||
16 | index 0000000..5141b5a | ||
17 | --- /dev/null | ||
18 | +++ b/drivers/media/video/isp/ispcsi2.c | ||
19 | @@ -0,0 +1,2124 @@ | ||
20 | +/* | ||
21 | + * ispcsi2.c | ||
22 | + * | ||
23 | + * Driver Library for ISP CSI Control module in TI's OMAP3 Camera ISP | ||
24 | + * ISP CSI interface and IRQ related APIs are defined here. | ||
25 | + * | ||
26 | + * Copyright (C) 2009 Texas Instruments. | ||
27 | + * | ||
28 | + * Contributors: | ||
29 | + * Sergio Aguirre <saaguirre@ti.com> | ||
30 | + * Dominic Curran <dcurran@ti.com> | ||
31 | + * | ||
32 | + * This package is free software; you can redistribute it and/or modify | ||
33 | + * it under the terms of the GNU General Public License version 2 as | ||
34 | + * published by the Free Software Foundation. | ||
35 | + * | ||
36 | + * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR | ||
37 | + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED | ||
38 | + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. | ||
39 | + */ | ||
40 | + | ||
41 | +#include <linux/delay.h> | ||
42 | +#include <media/v4l2-common.h> | ||
43 | + | ||
44 | +#include "isp.h" | ||
45 | +#include "ispreg.h" | ||
46 | +#include "ispcsi2.h" | ||
47 | + | ||
48 | +static struct isp_csi2_cfg current_csi2_cfg; | ||
49 | +static struct isp_csi2_cfg_update current_csi2_cfg_update; | ||
50 | + | ||
51 | +static bool update_complexio_cfg1; | ||
52 | +static bool update_phy_cfg0; | ||
53 | +static bool update_phy_cfg1; | ||
54 | +static bool update_ctx_ctrl1[8]; | ||
55 | +static bool update_ctx_ctrl2[8]; | ||
56 | +static bool update_ctx_ctrl3[8]; | ||
57 | +static bool update_timing; | ||
58 | +static bool update_ctrl; | ||
59 | +static bool uses_videoport; | ||
60 | + | ||
61 | +/** | ||
62 | + * isp_csi2_complexio_lanes_config - Configuration of CSI2 ComplexIO lanes. | ||
63 | + * @reqcfg: Pointer to structure containing desired lane configuration | ||
64 | + * | ||
65 | + * Validates and saves to internal driver memory the passed configuration. | ||
66 | + * Returns 0 if successful, or -EINVAL if null pointer is passed, invalid | ||
67 | + * lane position or polarity is set, and if 2 lanes try to occupy the same | ||
68 | + * position. To apply this settings, use the isp_csi2_complexio_lanes_update() | ||
69 | + * function just after calling this function. | ||
70 | + **/ | ||
71 | +int isp_csi2_complexio_lanes_config(struct isp_csi2_lanes_cfg *reqcfg) | ||
72 | +{ | ||
73 | + int i; | ||
74 | + bool pos_occupied[5] = {false, false, false, false, false}; | ||
75 | + struct isp_csi2_lanes_cfg *currlanes = ¤t_csi2_cfg.lanes; | ||
76 | + struct isp_csi2_lanes_cfg_update *currlanes_u = | ||
77 | + ¤t_csi2_cfg_update.lanes; | ||
78 | + | ||
79 | + /* Validating parameters sent by driver */ | ||
80 | + if (reqcfg == NULL) { | ||
81 | + printk(KERN_ERR "Invalid Complex IO Configuration sent by" | ||
82 | + " sensor\n"); | ||
83 | + goto err_einval; | ||
84 | + } | ||
85 | + | ||
86 | + /* Data lanes verification */ | ||
87 | + for (i = 0; i < 4; i++) { | ||
88 | + if ((reqcfg->data[i].pol > 1) || (reqcfg->data[i].pos > 5)) { | ||
89 | + printk(KERN_ERR "Invalid CSI-2 Complex IO configuration" | ||
90 | + " parameters for data lane #%d\n", i); | ||
91 | + goto err_einval; | ||
92 | + } | ||
93 | + if (pos_occupied[reqcfg->data[i].pos - 1] && | ||
94 | + reqcfg->data[i].pos > 0) { | ||
95 | + printk(KERN_ERR "Lane #%d already occupied\n", | ||
96 | + reqcfg->data[i].pos); | ||
97 | + goto err_einval; | ||
98 | + } else | ||
99 | + pos_occupied[reqcfg->data[i].pos - 1] = true; | ||
100 | + } | ||
101 | + | ||
102 | + /* Clock lane verification */ | ||
103 | + if ((reqcfg->clk.pol > 1) || (reqcfg->clk.pos > 5) || | ||
104 | + (reqcfg->clk.pos == 0)) { | ||
105 | + printk(KERN_ERR "Invalid CSI-2 Complex IO configuration" | ||
106 | + " parameters for clock lane\n"); | ||
107 | + goto err_einval; | ||
108 | + } | ||
109 | + if (pos_occupied[reqcfg->clk.pos - 1]) { | ||
110 | + printk(KERN_ERR "Lane #%d already occupied", | ||
111 | + reqcfg->clk.pos); | ||
112 | + goto err_einval; | ||
113 | + } else | ||
114 | + pos_occupied[reqcfg->clk.pos - 1] = true; | ||
115 | + | ||
116 | + for (i = 0; i < 4; i++) { | ||
117 | + if (currlanes->data[i].pos != reqcfg->data[i].pos) { | ||
118 | + currlanes->data[i].pos = reqcfg->data[i].pos; | ||
119 | + currlanes_u->data[i] = true; | ||
120 | + update_complexio_cfg1 = true; | ||
121 | + } | ||
122 | + if (currlanes->data[i].pol != reqcfg->data[i].pol) { | ||
123 | + currlanes->data[i].pol = reqcfg->data[i].pol; | ||
124 | + currlanes_u->data[i] = true; | ||
125 | + update_complexio_cfg1 = true; | ||
126 | + } | ||
127 | + } | ||
128 | + | ||
129 | + if (currlanes->clk.pos != reqcfg->clk.pos) { | ||
130 | + currlanes->clk.pos = reqcfg->clk.pos; | ||
131 | + currlanes_u->clk = true; | ||
132 | + update_complexio_cfg1 = true; | ||
133 | + } | ||
134 | + if (currlanes->clk.pol != reqcfg->clk.pol) { | ||
135 | + currlanes->clk.pol = reqcfg->clk.pol; | ||
136 | + currlanes_u->clk = true; | ||
137 | + update_complexio_cfg1 = true; | ||
138 | + } | ||
139 | + return 0; | ||
140 | +err_einval: | ||
141 | + return -EINVAL; | ||
142 | +} | ||
143 | + | ||
144 | +/** | ||
145 | + * isp_csi2_complexio_lanes_update - Applies CSI2 ComplexIO lanes configuration. | ||
146 | + * @force_update: Flag to force rewrite of registers, even if they haven't been | ||
147 | + * updated with the isp_csi2_complexio_lanes_config() function. | ||
148 | + * | ||
149 | + * It only saves settings when they were previously updated using the | ||
150 | + * isp_csi2_complexio_lanes_config() function, unless the force_update flag is | ||
151 | + * set to true. | ||
152 | + * Always returns 0. | ||
153 | + **/ | ||
154 | +int isp_csi2_complexio_lanes_update(bool force_update) | ||
155 | +{ | ||
156 | + struct isp_csi2_lanes_cfg *currlanes = ¤t_csi2_cfg.lanes; | ||
157 | + struct isp_csi2_lanes_cfg_update *currlanes_u = | ||
158 | + ¤t_csi2_cfg_update.lanes; | ||
159 | + u32 reg; | ||
160 | + int i; | ||
161 | + | ||
162 | + if (!update_complexio_cfg1 && !force_update) | ||
163 | + return 0; | ||
164 | + | ||
165 | + reg = isp_reg_readl(OMAP3_ISP_IOMEM_CSI2A, ISPCSI2_COMPLEXIO_CFG1); | ||
166 | + for (i = 0; i < 4; i++) { | ||
167 | + if (currlanes_u->data[i] || force_update) { | ||
168 | + reg &= ~(ISPCSI2_COMPLEXIO_CFG1_DATA_POL_MASK(i + 1) | | ||
169 | + ISPCSI2_COMPLEXIO_CFG1_DATA_POSITION_MASK(i + | ||
170 | + 1)); | ||
171 | + reg |= (currlanes->data[i].pol << | ||
172 | + ISPCSI2_COMPLEXIO_CFG1_DATA_POL_SHIFT(i + 1)); | ||
173 | + reg |= (currlanes->data[i].pos << | ||
174 | + ISPCSI2_COMPLEXIO_CFG1_DATA_POSITION_SHIFT(i + | ||
175 | + 1)); | ||
176 | + currlanes_u->data[i] = false; | ||
177 | + } | ||
178 | + } | ||
179 | + | ||
180 | + if (currlanes_u->clk || force_update) { | ||
181 | + reg &= ~(ISPCSI2_COMPLEXIO_CFG1_CLOCK_POL_MASK | | ||
182 | + ISPCSI2_COMPLEXIO_CFG1_CLOCK_POSITION_MASK); | ||
183 | + reg |= (currlanes->clk.pol << | ||
184 | + ISPCSI2_COMPLEXIO_CFG1_CLOCK_POL_SHIFT); | ||
185 | + reg |= (currlanes->clk.pos << | ||
186 | + ISPCSI2_COMPLEXIO_CFG1_CLOCK_POSITION_SHIFT); | ||
187 | + currlanes_u->clk = false; | ||
188 | + } | ||
189 | + isp_reg_writel(reg, OMAP3_ISP_IOMEM_CSI2A, ISPCSI2_COMPLEXIO_CFG1); | ||
190 | + | ||
191 | + update_complexio_cfg1 = false; | ||
192 | + return 0; | ||
193 | +} | ||
194 | + | ||
195 | +/** | ||
196 | + * isp_csi2_complexio_lanes_get - Gets CSI2 ComplexIO lanes configuration. | ||
197 | + * | ||
198 | + * Gets settings from HW registers and fills in the internal driver memory | ||
199 | + * Always returns 0. | ||
200 | + **/ | ||
201 | +int isp_csi2_complexio_lanes_get(void) | ||
202 | +{ | ||
203 | + struct isp_csi2_lanes_cfg *currlanes = ¤t_csi2_cfg.lanes; | ||
204 | + struct isp_csi2_lanes_cfg_update *currlanes_u = | ||
205 | + ¤t_csi2_cfg_update.lanes; | ||
206 | + u32 reg; | ||
207 | + int i; | ||
208 | + | ||
209 | + reg = isp_reg_readl(OMAP3_ISP_IOMEM_CSI2A, ISPCSI2_COMPLEXIO_CFG1); | ||
210 | + for (i = 0; i < 4; i++) { | ||
211 | + currlanes->data[i].pol = (reg & | ||
212 | + ISPCSI2_COMPLEXIO_CFG1_DATA_POL_MASK(i + 1)) >> | ||
213 | + ISPCSI2_COMPLEXIO_CFG1_DATA_POL_SHIFT(i + 1); | ||
214 | + currlanes->data[i].pos = (reg & | ||
215 | + ISPCSI2_COMPLEXIO_CFG1_DATA_POSITION_MASK(i + 1)) >> | ||
216 | + ISPCSI2_COMPLEXIO_CFG1_DATA_POSITION_SHIFT(i + 1); | ||
217 | + currlanes_u->data[i] = false; | ||
218 | + } | ||
219 | + currlanes->clk.pol = (reg & ISPCSI2_COMPLEXIO_CFG1_CLOCK_POL_MASK) >> | ||
220 | + ISPCSI2_COMPLEXIO_CFG1_CLOCK_POL_SHIFT; | ||
221 | + currlanes->clk.pos = (reg & | ||
222 | + ISPCSI2_COMPLEXIO_CFG1_CLOCK_POSITION_MASK) >> | ||
223 | + ISPCSI2_COMPLEXIO_CFG1_CLOCK_POSITION_SHIFT; | ||
224 | + currlanes_u->clk = false; | ||
225 | + | ||
226 | + update_complexio_cfg1 = false; | ||
227 | + return 0; | ||
228 | +} | ||
229 | + | ||
230 | +/** | ||
231 | + * isp_csi2_complexio_power_status - Gets CSI2 ComplexIO power status. | ||
232 | + * | ||
233 | + * Returns 3 possible valid states: ISP_CSI2_POWER_OFF, ISP_CSI2_POWER_ON, | ||
234 | + * and ISP_CSI2_POWER_ULPW. | ||
235 | + **/ | ||
236 | +static enum isp_csi2_power_cmds isp_csi2_complexio_power_status(void) | ||
237 | +{ | ||
238 | + enum isp_csi2_power_cmds ret; | ||
239 | + u32 reg; | ||
240 | + | ||
241 | + reg = isp_reg_readl(OMAP3_ISP_IOMEM_CSI2A, ISPCSI2_COMPLEXIO_CFG1) & | ||
242 | + ISPCSI2_COMPLEXIO_CFG1_PWR_STATUS_MASK; | ||
243 | + switch (reg) { | ||
244 | + case ISPCSI2_COMPLEXIO_CFG1_PWR_STATUS_OFF: | ||
245 | + ret = ISP_CSI2_POWER_OFF; | ||
246 | + break; | ||
247 | + case ISPCSI2_COMPLEXIO_CFG1_PWR_STATUS_ON: | ||
248 | + ret = ISP_CSI2_POWER_ON; | ||
249 | + break; | ||
250 | + case ISPCSI2_COMPLEXIO_CFG1_PWR_STATUS_ULPW: | ||
251 | + ret = ISP_CSI2_POWER_ULPW; | ||
252 | + break; | ||
253 | + default: | ||
254 | + return -EINVAL; | ||
255 | + } | ||
256 | + return ret; | ||
257 | +} | ||
258 | + | ||
259 | +/** | ||
260 | + * isp_csi2_complexio_power_autoswitch - Sets CSI2 ComplexIO power autoswitch. | ||
261 | + * @enable: Sets or clears the autoswitch function enable flag. | ||
262 | + * | ||
263 | + * Always returns 0. | ||
264 | + **/ | ||
265 | +int isp_csi2_complexio_power_autoswitch(bool enable) | ||
266 | +{ | ||
267 | + u32 reg; | ||
268 | + | ||
269 | + reg = isp_reg_readl(OMAP3_ISP_IOMEM_CSI2A, ISPCSI2_COMPLEXIO_CFG1); | ||
270 | + reg &= ~ISPCSI2_COMPLEXIO_CFG1_PWR_AUTO_MASK; | ||
271 | + | ||
272 | + if (enable) | ||
273 | + reg |= ISPCSI2_COMPLEXIO_CFG1_PWR_AUTO_ENABLE; | ||
274 | + else | ||
275 | + reg |= ISPCSI2_COMPLEXIO_CFG1_PWR_AUTO_DISABLE; | ||
276 | + | ||
277 | + isp_reg_writel(reg, OMAP3_ISP_IOMEM_CSI2A, ISPCSI2_COMPLEXIO_CFG1); | ||
278 | + return 0; | ||
279 | +} | ||
280 | + | ||
281 | +/** | ||
282 | + * isp_csi2_complexio_power - Sets the desired power command for CSI2 ComplexIO. | ||
283 | + * @power_cmd: Power command to be set. | ||
284 | + * | ||
285 | + * Returns 0 if successful, or -EBUSY if the retry count is exceeded. | ||
286 | + **/ | ||
287 | +int isp_csi2_complexio_power(enum isp_csi2_power_cmds power_cmd) | ||
288 | +{ | ||
289 | + enum isp_csi2_power_cmds current_state; | ||
290 | + u32 reg; | ||
291 | + u8 retry_count; | ||
292 | + | ||
293 | + reg = isp_reg_readl(OMAP3_ISP_IOMEM_CSI2A, ISPCSI2_COMPLEXIO_CFG1) & | ||
294 | + ~ISPCSI2_COMPLEXIO_CFG1_PWR_CMD_MASK; | ||
295 | + switch (power_cmd) { | ||
296 | + case ISP_CSI2_POWER_OFF: | ||
297 | + reg |= ISPCSI2_COMPLEXIO_CFG1_PWR_CMD_OFF; | ||
298 | + break; | ||
299 | + case ISP_CSI2_POWER_ON: | ||
300 | + reg |= ISPCSI2_COMPLEXIO_CFG1_PWR_CMD_ON; | ||
301 | + break; | ||
302 | + case ISP_CSI2_POWER_ULPW: | ||
303 | + reg |= ISPCSI2_COMPLEXIO_CFG1_PWR_CMD_ULPW; | ||
304 | + break; | ||
305 | + default: | ||
306 | + printk(KERN_ERR "CSI2: ERROR - Wrong Power command!\n"); | ||
307 | + return -EINVAL; | ||
308 | + } | ||
309 | + isp_reg_writel(reg, OMAP3_ISP_IOMEM_CSI2A, ISPCSI2_COMPLEXIO_CFG1); | ||
310 | + | ||
311 | + retry_count = 0; | ||
312 | + do { | ||
313 | + udelay(50); | ||
314 | + current_state = isp_csi2_complexio_power_status(); | ||
315 | + | ||
316 | + if (current_state != power_cmd) { | ||
317 | + printk(KERN_DEBUG "CSI2: Complex IO power command not" | ||
318 | + " yet taken."); | ||
319 | + if (++retry_count < 100) { | ||
320 | + printk(KERN_DEBUG " Retrying...\n"); | ||
321 | + udelay(50); | ||
322 | + } else { | ||
323 | + printk(KERN_DEBUG " Retry count exceeded!\n"); | ||
324 | + } | ||
325 | + } | ||
326 | + } while ((current_state != power_cmd) && (retry_count < 100)); | ||
327 | + | ||
328 | + if (retry_count == 100) | ||
329 | + return -EBUSY; | ||
330 | + | ||
331 | + return 0; | ||
332 | +} | ||
333 | + | ||
334 | +/** | ||
335 | + * isp_csi2_ctrl_config_frame_mode - Configure if_en behaviour for CSI2 | ||
336 | + * @frame_mode: Desired action for IF_EN switch off. 0 - disable IF immediately | ||
337 | + * 1 - disable after all Frame end Code is received in all | ||
338 | + * contexts. | ||
339 | + * | ||
340 | + * Validates and saves to internal driver memory the passed configuration. | ||
341 | + * Always returns 0. | ||
342 | + **/ | ||
343 | +int isp_csi2_ctrl_config_frame_mode(enum isp_csi2_frame_mode frame_mode) | ||
344 | +{ | ||
345 | + struct isp_csi2_ctrl_cfg *currctrl = ¤t_csi2_cfg.ctrl; | ||
346 | + struct isp_csi2_ctrl_cfg_update *currctrl_u = | ||
347 | + ¤t_csi2_cfg_update.ctrl; | ||
348 | + | ||
349 | + if (currctrl->frame_mode != frame_mode) { | ||
350 | + currctrl->frame_mode = frame_mode; | ||
351 | + currctrl_u->frame_mode = true; | ||
352 | + update_ctrl = true; | ||
353 | + } | ||
354 | + return 0; | ||
355 | +} | ||
356 | + | ||
357 | +/** | ||
358 | + * isp_csi2_ctrl_config_vp_clk_enable - Enables/disables CSI2 Videoport clock. | ||
359 | + * @vp_clk_enable: Boolean value to specify the Videoport clock state. | ||
360 | + * | ||
361 | + * Validates and saves to internal driver memory the passed configuration. | ||
362 | + * Always returns 0. | ||
363 | + **/ | ||
364 | +int isp_csi2_ctrl_config_vp_clk_enable(bool vp_clk_enable) | ||
365 | +{ | ||
366 | + struct isp_csi2_ctrl_cfg *currctrl = ¤t_csi2_cfg.ctrl; | ||
367 | + struct isp_csi2_ctrl_cfg_update *currctrl_u = | ||
368 | + ¤t_csi2_cfg_update.ctrl; | ||
369 | + | ||
370 | + if (currctrl->vp_clk_enable != vp_clk_enable) { | ||
371 | + currctrl->vp_clk_enable = vp_clk_enable; | ||
372 | + currctrl_u->vp_clk_enable = true; | ||
373 | + update_ctrl = true; | ||
374 | + } | ||
375 | + return 0; | ||
376 | +} | ||
377 | + | ||
378 | +/** | ||
379 | + * isp_csi2_ctrl_config_vp_only_enable - Sets CSI2 Videoport clock as exclusive | ||
380 | + * @vp_only_enable: Boolean value to specify if the Videoport clock is | ||
381 | + * exclusive, setting the OCP port as disabled. | ||
382 | + * | ||
383 | + * Validates and saves to internal driver memory the passed configuration. | ||
384 | + * Always returns 0. | ||
385 | + **/ | ||
386 | +int isp_csi2_ctrl_config_vp_only_enable(bool vp_only_enable) | ||
387 | +{ | ||
388 | + struct isp_csi2_ctrl_cfg *currctrl = ¤t_csi2_cfg.ctrl; | ||
389 | + struct isp_csi2_ctrl_cfg_update *currctrl_u = | ||
390 | + ¤t_csi2_cfg_update.ctrl; | ||
391 | + | ||
392 | + if (currctrl->vp_only_enable != vp_only_enable) { | ||
393 | + currctrl->vp_only_enable = vp_only_enable; | ||
394 | + currctrl_u->vp_only_enable = true; | ||
395 | + update_ctrl = true; | ||
396 | + } | ||
397 | + return 0; | ||
398 | +} | ||
399 | + | ||
400 | +/** | ||
401 | + * isp_csi2_ctrl_config_vp_out_ctrl - Sets CSI2 Videoport clock divider | ||
402 | + * @vp_out_ctrl: Divider value for setting videoport clock frequency based on | ||
403 | + * OCP port frequency, valid dividers are between 1 and 4. | ||
404 | + * | ||
405 | + * Validates and saves to internal driver memory the passed configuration. | ||
406 | + * Returns 0 if successful, or -EINVAL if wrong divider value is passed. | ||
407 | + **/ | ||
408 | +int isp_csi2_ctrl_config_vp_out_ctrl(u8 vp_out_ctrl) | ||
409 | +{ | ||
410 | + struct isp_csi2_ctrl_cfg *currctrl = ¤t_csi2_cfg.ctrl; | ||
411 | + struct isp_csi2_ctrl_cfg_update *currctrl_u = | ||
412 | + ¤t_csi2_cfg_update.ctrl; | ||
413 | + | ||
414 | + if ((vp_out_ctrl == 0) || (vp_out_ctrl > 4)) { | ||
415 | + printk(KERN_ERR "CSI2: Wrong divisor value. Must be between" | ||
416 | + " 1 and 4"); | ||
417 | + return -EINVAL; | ||
418 | + } | ||
419 | + | ||
420 | + if (currctrl->vp_out_ctrl != vp_out_ctrl) { | ||
421 | + currctrl->vp_out_ctrl = vp_out_ctrl; | ||
422 | + currctrl_u->vp_out_ctrl = true; | ||
423 | + update_ctrl = true; | ||
424 | + } | ||
425 | + return 0; | ||
426 | +} | ||
427 | + | ||
428 | +/** | ||
429 | + * isp_csi2_ctrl_config_debug_enable - Sets CSI2 debug | ||
430 | + * @debug_enable: Boolean for setting debug configuration on CSI2. | ||
431 | + * | ||
432 | + * Always returns 0. | ||
433 | + **/ | ||
434 | +int isp_csi2_ctrl_config_debug_enable(bool debug_enable) | ||
435 | +{ | ||
436 | + struct isp_csi2_ctrl_cfg *currctrl = ¤t_csi2_cfg.ctrl; | ||
437 | + struct isp_csi2_ctrl_cfg_update *currctrl_u = | ||
438 | + ¤t_csi2_cfg_update.ctrl; | ||
439 | + | ||
440 | + if (currctrl->debug_enable != debug_enable) { | ||
441 | + currctrl->debug_enable = debug_enable; | ||
442 | + currctrl_u->debug_enable = true; | ||
443 | + update_ctrl = true; | ||
444 | + } | ||
445 | + return 0; | ||
446 | +} | ||
447 | + | ||
448 | +/** | ||
449 | + * isp_csi2_ctrl_config_burst_size - Sets CSI2 burst size. | ||
450 | + * @burst_size: Burst size of the memory saving capability of receiver. | ||
451 | + * | ||
452 | + * Returns 0 if successful, or -EINVAL if burst size is wrong. | ||
453 | + **/ | ||
454 | +int isp_csi2_ctrl_config_burst_size(u8 burst_size) | ||
455 | +{ | ||
456 | + struct isp_csi2_ctrl_cfg *currctrl = ¤t_csi2_cfg.ctrl; | ||
457 | + struct isp_csi2_ctrl_cfg_update *currctrl_u = | ||
458 | + ¤t_csi2_cfg_update.ctrl; | ||
459 | + if (burst_size > 3) { | ||
460 | + printk(KERN_ERR "CSI2: Wrong burst size. Must be between" | ||
461 | + " 0 and 3"); | ||
462 | + return -EINVAL; | ||
463 | + } | ||
464 | + | ||
465 | + if (currctrl->burst_size != burst_size) { | ||
466 | + currctrl->burst_size = burst_size; | ||
467 | + currctrl_u->burst_size = true; | ||
468 | + update_ctrl = true; | ||
469 | + } | ||
470 | + return 0; | ||
471 | +} | ||
472 | + | ||
473 | +/** | ||
474 | + * isp_csi2_ctrl_config_ecc_enable - Enables ECC on CSI2 Receiver | ||
475 | + * @ecc_enable: Boolean to enable/disable the CSI2 receiver ECC handling. | ||
476 | + * | ||
477 | + * Always returns 0. | ||
478 | + **/ | ||
479 | +int isp_csi2_ctrl_config_ecc_enable(bool ecc_enable) | ||
480 | +{ | ||
481 | + struct isp_csi2_ctrl_cfg *currctrl = ¤t_csi2_cfg.ctrl; | ||
482 | + struct isp_csi2_ctrl_cfg_update *currctrl_u = | ||
483 | + ¤t_csi2_cfg_update.ctrl; | ||
484 | + | ||
485 | + if (currctrl->ecc_enable != ecc_enable) { | ||
486 | + currctrl->ecc_enable = ecc_enable; | ||
487 | + currctrl_u->ecc_enable = true; | ||
488 | + update_ctrl = true; | ||
489 | + } | ||
490 | + return 0; | ||
491 | +} | ||
492 | + | ||
493 | +/** | ||
494 | + * isp_csi2_ctrl_config_ecc_enable - Enables ECC on CSI2 Receiver | ||
495 | + * @ecc_enable: Boolean to enable/disable the CSI2 receiver ECC handling. | ||
496 | + * | ||
497 | + * Always returns 0. | ||
498 | + **/ | ||
499 | +int isp_csi2_ctrl_config_secure_mode(bool secure_mode) | ||
500 | +{ | ||
501 | + struct isp_csi2_ctrl_cfg *currctrl = ¤t_csi2_cfg.ctrl; | ||
502 | + struct isp_csi2_ctrl_cfg_update *currctrl_u = | ||
503 | + ¤t_csi2_cfg_update.ctrl; | ||
504 | + | ||
505 | + if (currctrl->secure_mode != secure_mode) { | ||
506 | + currctrl->secure_mode = secure_mode; | ||
507 | + currctrl_u->secure_mode = true; | ||
508 | + update_ctrl = true; | ||
509 | + } | ||
510 | + return 0; | ||
511 | +} | ||
512 | + | ||
513 | +/** | ||
514 | + * isp_csi2_ctrl_config_if_enable - Enables CSI2 Receiver interface. | ||
515 | + * @if_enable: Boolean to enable/disable the CSI2 receiver interface. | ||
516 | + * | ||
517 | + * Always returns 0. | ||
518 | + **/ | ||
519 | +int isp_csi2_ctrl_config_if_enable(bool if_enable) | ||
520 | +{ | ||
521 | + struct isp_csi2_ctrl_cfg *currctrl = ¤t_csi2_cfg.ctrl; | ||
522 | + struct isp_csi2_ctrl_cfg_update *currctrl_u = | ||
523 | + ¤t_csi2_cfg_update.ctrl; | ||
524 | + | ||
525 | + if (currctrl->if_enable != if_enable) { | ||
526 | + currctrl->if_enable = if_enable; | ||
527 | + currctrl_u->if_enable = true; | ||
528 | + update_ctrl = true; | ||
529 | + } | ||
530 | + return 0; | ||
531 | +} | ||
532 | + | ||
533 | +/** | ||
534 | + * isp_csi2_ctrl_update - Applies CSI2 control configuration. | ||
535 | + * @force_update: Flag to force rewrite of registers, even if they haven't been | ||
536 | + * updated with the isp_csi2_ctrl_config_*() functions. | ||
537 | + * | ||
538 | + * It only saves settings when they were previously updated using the | ||
539 | + * isp_csi2_ctrl_config_*() functions, unless the force_update flag is | ||
540 | + * set to true. | ||
541 | + * Always returns 0. | ||
542 | + **/ | ||
543 | +int isp_csi2_ctrl_update(bool force_update) | ||
544 | +{ | ||
545 | + struct isp_csi2_ctrl_cfg *currctrl = ¤t_csi2_cfg.ctrl; | ||
546 | + struct isp_csi2_ctrl_cfg_update *currctrl_u = | ||
547 | + ¤t_csi2_cfg_update.ctrl; | ||
548 | + u32 reg; | ||
549 | + | ||
550 | + if (update_ctrl || force_update) { | ||
551 | + reg = isp_reg_readl(OMAP3_ISP_IOMEM_CSI2A, ISPCSI2_CTRL); | ||
552 | + if (currctrl_u->frame_mode || force_update) { | ||
553 | + reg &= ~ISPCSI2_CTRL_FRAME_MASK; | ||
554 | + if (currctrl->frame_mode) | ||
555 | + reg |= ISPCSI2_CTRL_FRAME_DISABLE_FEC; | ||
556 | + else | ||
557 | + reg |= ISPCSI2_CTRL_FRAME_DISABLE_IMM; | ||
558 | + currctrl_u->frame_mode = false; | ||
559 | + } | ||
560 | + if (currctrl_u->vp_clk_enable || force_update) { | ||
561 | + reg &= ~ISPCSI2_CTRL_VP_CLK_EN_MASK; | ||
562 | + if (currctrl->vp_clk_enable) | ||
563 | + reg |= ISPCSI2_CTRL_VP_CLK_EN_ENABLE; | ||
564 | + else | ||
565 | + reg |= ISPCSI2_CTRL_VP_CLK_EN_DISABLE; | ||
566 | + currctrl_u->vp_clk_enable = false; | ||
567 | + } | ||
568 | + if (currctrl_u->vp_only_enable || force_update) { | ||
569 | + reg &= ~ISPCSI2_CTRL_VP_ONLY_EN_MASK; | ||
570 | + uses_videoport = currctrl->vp_only_enable; | ||
571 | + if (currctrl->vp_only_enable) | ||
572 | + reg |= ISPCSI2_CTRL_VP_ONLY_EN_ENABLE; | ||
573 | + else | ||
574 | + reg |= ISPCSI2_CTRL_VP_ONLY_EN_DISABLE; | ||
575 | + currctrl_u->vp_only_enable = false; | ||
576 | + } | ||
577 | + if (currctrl_u->vp_out_ctrl || force_update) { | ||
578 | + reg &= ~ISPCSI2_CTRL_VP_OUT_CTRL_MASK; | ||
579 | + reg |= (currctrl->vp_out_ctrl - 1) << | ||
580 | + ISPCSI2_CTRL_VP_OUT_CTRL_SHIFT; | ||
581 | + currctrl_u->vp_out_ctrl = false; | ||
582 | + } | ||
583 | + if (currctrl_u->debug_enable || force_update) { | ||
584 | + reg &= ~ISPCSI2_CTRL_DBG_EN_MASK; | ||
585 | + if (currctrl->debug_enable) | ||
586 | + reg |= ISPCSI2_CTRL_DBG_EN_ENABLE; | ||
587 | + else | ||
588 | + reg |= ISPCSI2_CTRL_DBG_EN_DISABLE; | ||
589 | + currctrl_u->debug_enable = false; | ||
590 | + } | ||
591 | + if (currctrl_u->burst_size || force_update) { | ||
592 | + reg &= ~ISPCSI2_CTRL_BURST_SIZE_MASK; | ||
593 | + reg |= currctrl->burst_size << | ||
594 | + ISPCSI2_CTRL_BURST_SIZE_SHIFT; | ||
595 | + currctrl_u->burst_size = false; | ||
596 | + } | ||
597 | + if (currctrl_u->ecc_enable || force_update) { | ||
598 | + reg &= ~ISPCSI2_CTRL_ECC_EN_MASK; | ||
599 | + if (currctrl->ecc_enable) | ||
600 | + reg |= ISPCSI2_CTRL_ECC_EN_ENABLE; | ||
601 | + else | ||
602 | + reg |= ISPCSI2_CTRL_ECC_EN_DISABLE; | ||
603 | + currctrl_u->ecc_enable = false; | ||
604 | + } | ||
605 | + if (currctrl_u->secure_mode || force_update) { | ||
606 | + reg &= ~ISPCSI2_CTRL_SECURE_MASK; | ||
607 | + if (currctrl->secure_mode) | ||
608 | + reg |= ISPCSI2_CTRL_SECURE_ENABLE; | ||
609 | + else | ||
610 | + reg |= ISPCSI2_CTRL_SECURE_DISABLE; | ||
611 | + currctrl_u->secure_mode = false; | ||
612 | + } | ||
613 | + if (currctrl_u->if_enable || force_update) { | ||
614 | + reg &= ~ISPCSI2_CTRL_IF_EN_MASK; | ||
615 | + if (currctrl->if_enable) | ||
616 | + reg |= ISPCSI2_CTRL_IF_EN_ENABLE; | ||
617 | + else | ||
618 | + reg |= ISPCSI2_CTRL_IF_EN_DISABLE; | ||
619 | + currctrl_u->if_enable = false; | ||
620 | + } | ||
621 | + isp_reg_writel(reg, OMAP3_ISP_IOMEM_CSI2A, ISPCSI2_CTRL); | ||
622 | + update_ctrl = false; | ||
623 | + } | ||
624 | + return 0; | ||
625 | +} | ||
626 | + | ||
627 | +/** | ||
628 | + * isp_csi2_ctrl_get - Gets CSI2 control configuration | ||
629 | + * | ||
630 | + * Always returns 0. | ||
631 | + **/ | ||
632 | +int isp_csi2_ctrl_get(void) | ||
633 | +{ | ||
634 | + struct isp_csi2_ctrl_cfg *currctrl = ¤t_csi2_cfg.ctrl; | ||
635 | + struct isp_csi2_ctrl_cfg_update *currctrl_u = | ||
636 | + ¤t_csi2_cfg_update.ctrl; | ||
637 | + u32 reg; | ||
638 | + | ||
639 | + reg = isp_reg_readl(OMAP3_ISP_IOMEM_CSI2A, ISPCSI2_CTRL); | ||
640 | + currctrl->frame_mode = (reg & ISPCSI2_CTRL_FRAME_MASK) >> | ||
641 | + ISPCSI2_CTRL_FRAME_SHIFT; | ||
642 | + currctrl_u->frame_mode = false; | ||
643 | + | ||
644 | + if ((reg & ISPCSI2_CTRL_VP_CLK_EN_MASK) == | ||
645 | + ISPCSI2_CTRL_VP_CLK_EN_ENABLE) | ||
646 | + currctrl->vp_clk_enable = true; | ||
647 | + else | ||
648 | + currctrl->vp_clk_enable = false; | ||
649 | + currctrl_u->vp_clk_enable = false; | ||
650 | + | ||
651 | + if ((reg & ISPCSI2_CTRL_VP_ONLY_EN_MASK) == | ||
652 | + ISPCSI2_CTRL_VP_ONLY_EN_ENABLE) | ||
653 | + currctrl->vp_only_enable = true; | ||
654 | + else | ||
655 | + currctrl->vp_only_enable = false; | ||
656 | + uses_videoport = currctrl->vp_only_enable; | ||
657 | + currctrl_u->vp_only_enable = false; | ||
658 | + | ||
659 | + currctrl->vp_out_ctrl = ((reg & ISPCSI2_CTRL_VP_OUT_CTRL_MASK) >> | ||
660 | + ISPCSI2_CTRL_VP_OUT_CTRL_SHIFT) + 1; | ||
661 | + currctrl_u->vp_out_ctrl = false; | ||
662 | + | ||
663 | + if ((reg & ISPCSI2_CTRL_DBG_EN_MASK) == ISPCSI2_CTRL_DBG_EN_ENABLE) | ||
664 | + currctrl->debug_enable = true; | ||
665 | + else | ||
666 | + currctrl->debug_enable = false; | ||
667 | + currctrl_u->debug_enable = false; | ||
668 | + | ||
669 | + currctrl->burst_size = (reg & ISPCSI2_CTRL_BURST_SIZE_MASK) >> | ||
670 | + ISPCSI2_CTRL_BURST_SIZE_SHIFT; | ||
671 | + currctrl_u->burst_size = false; | ||
672 | + | ||
673 | + if ((reg & ISPCSI2_CTRL_ECC_EN_MASK) == ISPCSI2_CTRL_ECC_EN_ENABLE) | ||
674 | + currctrl->ecc_enable = true; | ||
675 | + else | ||
676 | + currctrl->ecc_enable = false; | ||
677 | + currctrl_u->ecc_enable = false; | ||
678 | + | ||
679 | + if ((reg & ISPCSI2_CTRL_SECURE_MASK) == ISPCSI2_CTRL_SECURE_ENABLE) | ||
680 | + currctrl->secure_mode = true; | ||
681 | + else | ||
682 | + currctrl->secure_mode = false; | ||
683 | + currctrl_u->secure_mode = false; | ||
684 | + | ||
685 | + if ((reg & ISPCSI2_CTRL_IF_EN_MASK) == ISPCSI2_CTRL_IF_EN_ENABLE) | ||
686 | + currctrl->if_enable = true; | ||
687 | + else | ||
688 | + currctrl->if_enable = false; | ||
689 | + currctrl_u->if_enable = false; | ||
690 | + | ||
691 | + update_ctrl = false; | ||
692 | + return 0; | ||
693 | +} | ||
694 | + | ||
695 | +/** | ||
696 | + * isp_csi2_ctx_validate - Validates the context number value | ||
697 | + * @ctxnum: Pointer to variable containing context number. | ||
698 | + * | ||
699 | + * If the value is not in range (3 bits), it is being ANDed with 0x7 to force | ||
700 | + * it to be on range. | ||
701 | + **/ | ||
702 | +static void isp_csi2_ctx_validate(u8 *ctxnum) | ||
703 | +{ | ||
704 | + if (*ctxnum > 7) { | ||
705 | + printk(KERN_ERR "Invalid context number. Forcing valid" | ||
706 | + " value...\n"); | ||
707 | + *ctxnum &= ~(0x7); | ||
708 | + } | ||
709 | +} | ||
710 | + | ||
711 | +/** | ||
712 | + * isp_csi2_ctx_config_virtual_id - Maps a virtual ID with a CSI2 Rx context | ||
713 | + * @ctxnum: Context number, valid between 0 and 7 values. | ||
714 | + * @virtual_id: CSI2 Virtual ID to associate with specified context number. | ||
715 | + * | ||
716 | + * Returns 0 if successful, or -EINVAL if Virtual ID is not in range (0-3). | ||
717 | + **/ | ||
718 | +int isp_csi2_ctx_config_virtual_id(u8 ctxnum, u8 virtual_id) | ||
719 | +{ | ||
720 | + struct isp_csi2_ctx_cfg *selected_ctx; | ||
721 | + struct isp_csi2_ctx_cfg_update *selected_ctx_u; | ||
722 | + | ||
723 | + isp_csi2_ctx_validate(&ctxnum); | ||
724 | + | ||
725 | + if (virtual_id > 3) { | ||
726 | + printk(KERN_ERR "Wrong requested virtual_id\n"); | ||
727 | + return -EINVAL; | ||
728 | + } | ||
729 | + | ||
730 | + selected_ctx = ¤t_csi2_cfg.contexts[ctxnum]; | ||
731 | + selected_ctx_u = ¤t_csi2_cfg_update.contexts[ctxnum]; | ||
732 | + | ||
733 | + if (selected_ctx->virtual_id != virtual_id) { | ||
734 | + selected_ctx->virtual_id = virtual_id; | ||
735 | + selected_ctx_u->virtual_id = true; | ||
736 | + update_ctx_ctrl2[ctxnum] = true; | ||
737 | + } | ||
738 | + | ||
739 | + return 0; | ||
740 | +} | ||
741 | + | ||
742 | +/** | ||
743 | + * isp_csi2_ctx_config_frame_count - Sets frame count to be received in CSI2 Rx. | ||
744 | + * @ctxnum: Context number, valid between 0 and 7 values. | ||
745 | + * @frame_count: Number of frames to acquire. | ||
746 | + * | ||
747 | + * Always returns 0. | ||
748 | + **/ | ||
749 | +int isp_csi2_ctx_config_frame_count(u8 ctxnum, u8 frame_count) | ||
750 | +{ | ||
751 | + struct isp_csi2_ctx_cfg *selected_ctx; | ||
752 | + struct isp_csi2_ctx_cfg_update *selected_ctx_u; | ||
753 | + | ||
754 | + isp_csi2_ctx_validate(&ctxnum); | ||
755 | + | ||
756 | + selected_ctx = ¤t_csi2_cfg.contexts[ctxnum]; | ||
757 | + selected_ctx_u = ¤t_csi2_cfg_update.contexts[ctxnum]; | ||
758 | + | ||
759 | + if (selected_ctx->frame_count != frame_count) { | ||
760 | + selected_ctx->frame_count = frame_count; | ||
761 | + selected_ctx_u->frame_count = true; | ||
762 | + update_ctx_ctrl1[ctxnum] = true; | ||
763 | + } | ||
764 | + | ||
765 | + return 0; | ||
766 | +} | ||
767 | + | ||
768 | +/** | ||
769 | + * isp_csi2_ctx_config_format - Maps a pixel format to a specified context. | ||
770 | + * @ctxnum: Context number, valid between 0 and 7 values. | ||
771 | + * @pixformat: V4L2 structure for pixel format. | ||
772 | + * | ||
773 | + * Returns 0 if successful, or -EINVAL if the format is not supported by the | ||
774 | + * receiver. | ||
775 | + **/ | ||
776 | +int isp_csi2_ctx_config_format(u8 ctxnum, u32 pixformat) | ||
777 | +{ | ||
778 | + struct isp_csi2_ctx_cfg *selected_ctx; | ||
779 | + struct isp_csi2_ctx_cfg_update *selected_ctx_u; | ||
780 | + struct v4l2_pix_format pix; | ||
781 | + | ||
782 | + isp_csi2_ctx_validate(&ctxnum); | ||
783 | + | ||
784 | + pix.pixelformat = pixformat; | ||
785 | + switch (pix.pixelformat) { | ||
786 | + case V4L2_PIX_FMT_RGB565: | ||
787 | + case V4L2_PIX_FMT_RGB565X: | ||
788 | + case V4L2_PIX_FMT_YUYV: | ||
789 | + case V4L2_PIX_FMT_UYVY: | ||
790 | + case V4L2_PIX_FMT_RGB555: | ||
791 | + case V4L2_PIX_FMT_RGB555X: | ||
792 | + case V4L2_PIX_FMT_SGRBG10: | ||
793 | + break; | ||
794 | + default: | ||
795 | + printk(KERN_ERR "Context config pixel format unsupported\n"); | ||
796 | + return -EINVAL; | ||
797 | + } | ||
798 | + | ||
799 | + selected_ctx = ¤t_csi2_cfg.contexts[ctxnum]; | ||
800 | + selected_ctx_u = ¤t_csi2_cfg_update.contexts[ctxnum]; | ||
801 | + | ||
802 | + selected_ctx->format = pix; | ||
803 | + selected_ctx_u->format = true; | ||
804 | + update_ctx_ctrl2[ctxnum] = true; | ||
805 | + | ||
806 | + return 0; | ||
807 | +} | ||
808 | + | ||
809 | +/** | ||
810 | + * isp_csi2_ctx_config_alpha - Sets the alpha value for pixel format | ||
811 | + * @ctxnum: Context number, valid between 0 and 7 values. | ||
812 | + * @alpha: Alpha value. | ||
813 | + * | ||
814 | + * Returns 0 if successful, or -EINVAL if the alpha value is bigger than 16383. | ||
815 | + **/ | ||
816 | +int isp_csi2_ctx_config_alpha(u8 ctxnum, u16 alpha) | ||
817 | +{ | ||
818 | + struct isp_csi2_ctx_cfg *selected_ctx; | ||
819 | + struct isp_csi2_ctx_cfg_update *selected_ctx_u; | ||
820 | + | ||
821 | + isp_csi2_ctx_validate(&ctxnum); | ||
822 | + | ||
823 | + if (alpha > 0x3FFF) { | ||
824 | + printk(KERN_ERR "Wrong alpha value\n"); | ||
825 | + return -EINVAL; | ||
826 | + } | ||
827 | + | ||
828 | + selected_ctx = ¤t_csi2_cfg.contexts[ctxnum]; | ||
829 | + selected_ctx_u = ¤t_csi2_cfg_update.contexts[ctxnum]; | ||
830 | + | ||
831 | + if (selected_ctx->alpha != alpha) { | ||
832 | + selected_ctx->alpha = alpha; | ||
833 | + selected_ctx_u->alpha = true; | ||
834 | + update_ctx_ctrl3[ctxnum] = true; | ||
835 | + } | ||
836 | + return 0; | ||
837 | +} | ||
838 | + | ||
839 | +/** | ||
840 | + * isp_csi2_ctx_config_data_offset - Sets the offset between received lines | ||
841 | + * @ctxnum: Context number, valid between 0 and 7 values. | ||
842 | + * @data_offset: Offset between first pixel of each 2 contiguous lines. | ||
843 | + * | ||
844 | + * Returns 0 if successful, or -EINVAL if the line offset is bigger than 1023. | ||
845 | + **/ | ||
846 | +int isp_csi2_ctx_config_data_offset(u8 ctxnum, u16 data_offset) | ||
847 | +{ | ||
848 | + struct isp_csi2_ctx_cfg *selected_ctx; | ||
849 | + struct isp_csi2_ctx_cfg_update *selected_ctx_u; | ||
850 | + | ||
851 | + isp_csi2_ctx_validate(&ctxnum); | ||
852 | + | ||
853 | + if (data_offset > 0x3FF) { | ||
854 | + printk(KERN_ERR "Wrong line offset\n"); | ||
855 | + return -EINVAL; | ||
856 | + } | ||
857 | + | ||
858 | + selected_ctx = ¤t_csi2_cfg.contexts[ctxnum]; | ||
859 | + selected_ctx_u = ¤t_csi2_cfg_update.contexts[ctxnum]; | ||
860 | + | ||
861 | + if (selected_ctx->data_offset != data_offset) { | ||
862 | + selected_ctx->data_offset = data_offset; | ||
863 | + selected_ctx_u->data_offset = true; | ||
864 | + } | ||
865 | + return 0; | ||
866 | +} | ||
867 | + | ||
868 | +/** | ||
869 | + * isp_csi2_ctx_config_ping_addr - Sets Ping address for CSI2 Rx. buffer saving | ||
870 | + * @ctxnum: Context number, valid between 0 and 7 values. | ||
871 | + * @ping_addr: 32 bit ISP MMU mapped address. | ||
872 | + * | ||
873 | + * Always returns 0. | ||
874 | + **/ | ||
875 | +int isp_csi2_ctx_config_ping_addr(u8 ctxnum, u32 ping_addr) | ||
876 | +{ | ||
877 | + struct isp_csi2_ctx_cfg *selected_ctx; | ||
878 | + struct isp_csi2_ctx_cfg_update *selected_ctx_u; | ||
879 | + | ||
880 | + isp_csi2_ctx_validate(&ctxnum); | ||
881 | + | ||
882 | + ping_addr &= ~(0x1F); | ||
883 | + | ||
884 | + selected_ctx = ¤t_csi2_cfg.contexts[ctxnum]; | ||
885 | + selected_ctx_u = ¤t_csi2_cfg_update.contexts[ctxnum]; | ||
886 | + | ||
887 | + if (selected_ctx->ping_addr != ping_addr) { | ||
888 | + selected_ctx->ping_addr = ping_addr; | ||
889 | + selected_ctx_u->ping_addr = true; | ||
890 | + } | ||
891 | + return 0; | ||
892 | +} | ||
893 | + | ||
894 | +/** | ||
895 | + * isp_csi2_ctx_config_pong_addr - Sets Pong address for CSI2 Rx. buffer saving | ||
896 | + * @ctxnum: Context number, valid between 0 and 7 values. | ||
897 | + * @pong_addr: 32 bit ISP MMU mapped address. | ||
898 | + * | ||
899 | + * Always returns 0. | ||
900 | + **/ | ||
901 | +int isp_csi2_ctx_config_pong_addr(u8 ctxnum, u32 pong_addr) | ||
902 | +{ | ||
903 | + struct isp_csi2_ctx_cfg *selected_ctx; | ||
904 | + struct isp_csi2_ctx_cfg_update *selected_ctx_u; | ||
905 | + | ||
906 | + isp_csi2_ctx_validate(&ctxnum); | ||
907 | + | ||
908 | + pong_addr &= ~(0x1F); | ||
909 | + | ||
910 | + selected_ctx = ¤t_csi2_cfg.contexts[ctxnum]; | ||
911 | + selected_ctx_u = ¤t_csi2_cfg_update.contexts[ctxnum]; | ||
912 | + | ||
913 | + if (selected_ctx->pong_addr != pong_addr) { | ||
914 | + selected_ctx->pong_addr = pong_addr; | ||
915 | + selected_ctx_u->pong_addr = true; | ||
916 | + } | ||
917 | + return 0; | ||
918 | +} | ||
919 | + | ||
920 | +/** | ||
921 | + * isp_csi2_ctx_config_eof_enabled - Enables EOF signal assertion | ||
922 | + * @ctxnum: Context number, valid between 0 and 7 values. | ||
923 | + * @eof_enabled: Boolean to enable/disable EOF signal assertion on received | ||
924 | + * packets. | ||
925 | + * | ||
926 | + * Always returns 0. | ||
927 | + **/ | ||
928 | +int isp_csi2_ctx_config_eof_enabled(u8 ctxnum, bool eof_enabled) | ||
929 | +{ | ||
930 | + struct isp_csi2_ctx_cfg *selected_ctx; | ||
931 | + struct isp_csi2_ctx_cfg_update *selected_ctx_u; | ||
932 | + | ||
933 | + isp_csi2_ctx_validate(&ctxnum); | ||
934 | + | ||
935 | + selected_ctx = ¤t_csi2_cfg.contexts[ctxnum]; | ||
936 | + selected_ctx_u = ¤t_csi2_cfg_update.contexts[ctxnum]; | ||
937 | + | ||
938 | + if (selected_ctx->eof_enabled != eof_enabled) { | ||
939 | + selected_ctx->eof_enabled = eof_enabled; | ||
940 | + selected_ctx_u->eof_enabled = true; | ||
941 | + update_ctx_ctrl1[ctxnum] = true; | ||
942 | + } | ||
943 | + return 0; | ||
944 | +} | ||
945 | + | ||
946 | +/** | ||
947 | + * isp_csi2_ctx_config_eol_enabled - Enables EOL signal assertion | ||
948 | + * @ctxnum: Context number, valid between 0 and 7 values. | ||
949 | + * @eol_enabled: Boolean to enable/disable EOL signal assertion on received | ||
950 | + * packets. | ||
951 | + * | ||
952 | + * Always returns 0. | ||
953 | + **/ | ||
954 | +int isp_csi2_ctx_config_eol_enabled(u8 ctxnum, bool eol_enabled) | ||
955 | +{ | ||
956 | + struct isp_csi2_ctx_cfg *selected_ctx; | ||
957 | + struct isp_csi2_ctx_cfg_update *selected_ctx_u; | ||
958 | + | ||
959 | + isp_csi2_ctx_validate(&ctxnum); | ||
960 | + | ||
961 | + selected_ctx = ¤t_csi2_cfg.contexts[ctxnum]; | ||
962 | + selected_ctx_u = ¤t_csi2_cfg_update.contexts[ctxnum]; | ||
963 | + | ||
964 | + if (selected_ctx->eol_enabled != eol_enabled) { | ||
965 | + selected_ctx->eol_enabled = eol_enabled; | ||
966 | + selected_ctx_u->eol_enabled = true; | ||
967 | + update_ctx_ctrl1[ctxnum] = true; | ||
968 | + } | ||
969 | + return 0; | ||
970 | +} | ||
971 | + | ||
972 | +/** | ||
973 | + * isp_csi2_ctx_config_checksum_enabled - Enables Checksum check in rcvd packets | ||
974 | + * @ctxnum: Context number, valid between 0 and 7 values. | ||
975 | + * @checksum_enabled: Boolean to enable/disable Checksum check on received | ||
976 | + * packets | ||
977 | + * | ||
978 | + * Always returns 0. | ||
979 | + **/ | ||
980 | +int isp_csi2_ctx_config_checksum_enabled(u8 ctxnum, bool checksum_enabled) | ||
981 | +{ | ||
982 | + struct isp_csi2_ctx_cfg *selected_ctx; | ||
983 | + struct isp_csi2_ctx_cfg_update *selected_ctx_u; | ||
984 | + | ||
985 | + isp_csi2_ctx_validate(&ctxnum); | ||
986 | + | ||
987 | + selected_ctx = ¤t_csi2_cfg.contexts[ctxnum]; | ||
988 | + selected_ctx_u = ¤t_csi2_cfg_update.contexts[ctxnum]; | ||
989 | + | ||
990 | + if (selected_ctx->checksum_enabled != checksum_enabled) { | ||
991 | + selected_ctx->checksum_enabled = checksum_enabled; | ||
992 | + selected_ctx_u->checksum_enabled = true; | ||
993 | + update_ctx_ctrl1[ctxnum] = true; | ||
994 | + } | ||
995 | + return 0; | ||
996 | +} | ||
997 | + | ||
998 | +/** | ||
999 | + * isp_csi2_ctx_config_enabled - Enables specified CSI2 context | ||
1000 | + * @ctxnum: Context number, valid between 0 and 7 values. | ||
1001 | + * @enabled: Boolean to enable/disable specified context. | ||
1002 | + * | ||
1003 | + * Always returns 0. | ||
1004 | + **/ | ||
1005 | +int isp_csi2_ctx_config_enabled(u8 ctxnum, bool enabled) | ||
1006 | +{ | ||
1007 | + struct isp_csi2_ctx_cfg *selected_ctx; | ||
1008 | + struct isp_csi2_ctx_cfg_update *selected_ctx_u; | ||
1009 | + | ||
1010 | + isp_csi2_ctx_validate(&ctxnum); | ||
1011 | + | ||
1012 | + selected_ctx = ¤t_csi2_cfg.contexts[ctxnum]; | ||
1013 | + selected_ctx_u = ¤t_csi2_cfg_update.contexts[ctxnum]; | ||
1014 | + | ||
1015 | + if (selected_ctx->enabled != enabled) { | ||
1016 | + selected_ctx->enabled = enabled; | ||
1017 | + selected_ctx_u->enabled = true; | ||
1018 | + update_ctx_ctrl1[ctxnum] = true; | ||
1019 | + } | ||
1020 | + return 0; | ||
1021 | +} | ||
1022 | + | ||
1023 | +/** | ||
1024 | + * isp_csi2_ctx_update - Applies CSI2 context configuration. | ||
1025 | + * @ctxnum: Context number, valid between 0 and 7 values. | ||
1026 | + * @force_update: Flag to force rewrite of registers, even if they haven't been | ||
1027 | + * updated with the isp_csi2_ctx_config_*() functions. | ||
1028 | + * | ||
1029 | + * It only saves settings when they were previously updated using the | ||
1030 | + * isp_csi2_ctx_config_*() functions, unless the force_update flag is | ||
1031 | + * set to true. | ||
1032 | + * Always returns 0. | ||
1033 | + **/ | ||
1034 | +int isp_csi2_ctx_update(u8 ctxnum, bool force_update) | ||
1035 | +{ | ||
1036 | + struct isp_csi2_ctx_cfg *selected_ctx; | ||
1037 | + struct isp_csi2_ctx_cfg_update *selected_ctx_u; | ||
1038 | + u32 reg; | ||
1039 | + | ||
1040 | + isp_csi2_ctx_validate(&ctxnum); | ||
1041 | + | ||
1042 | + selected_ctx = ¤t_csi2_cfg.contexts[ctxnum]; | ||
1043 | + selected_ctx_u = ¤t_csi2_cfg_update.contexts[ctxnum]; | ||
1044 | + | ||
1045 | + if (update_ctx_ctrl1[ctxnum] || force_update) { | ||
1046 | + reg = isp_reg_readl(OMAP3_ISP_IOMEM_CSI2A, | ||
1047 | + ISPCSI2_CTX_CTRL1(ctxnum)); | ||
1048 | + if (selected_ctx_u->frame_count || force_update) { | ||
1049 | + reg &= ~(ISPCSI2_CTX_CTRL1_COUNT_MASK); | ||
1050 | + reg |= selected_ctx->frame_count << | ||
1051 | + ISPCSI2_CTX_CTRL1_COUNT_SHIFT; | ||
1052 | + selected_ctx_u->frame_count = false; | ||
1053 | + } | ||
1054 | + if (selected_ctx_u->eof_enabled || force_update) { | ||
1055 | + reg &= ~(ISPCSI2_CTX_CTRL1_EOF_EN_MASK); | ||
1056 | + if (selected_ctx->eof_enabled) | ||
1057 | + reg |= ISPCSI2_CTX_CTRL1_EOF_EN_ENABLE; | ||
1058 | + else | ||
1059 | + reg |= ISPCSI2_CTX_CTRL1_EOF_EN_DISABLE; | ||
1060 | + selected_ctx_u->eof_enabled = false; | ||
1061 | + } | ||
1062 | + if (selected_ctx_u->eol_enabled || force_update) { | ||
1063 | + reg &= ~(ISPCSI2_CTX_CTRL1_EOL_EN_MASK); | ||
1064 | + if (selected_ctx->eol_enabled) | ||
1065 | + reg |= ISPCSI2_CTX_CTRL1_EOL_EN_ENABLE; | ||
1066 | + else | ||
1067 | + reg |= ISPCSI2_CTX_CTRL1_EOL_EN_DISABLE; | ||
1068 | + selected_ctx_u->eol_enabled = false; | ||
1069 | + } | ||
1070 | + if (selected_ctx_u->checksum_enabled || force_update) { | ||
1071 | + reg &= ~(ISPCSI2_CTX_CTRL1_CS_EN_MASK); | ||
1072 | + if (selected_ctx->checksum_enabled) | ||
1073 | + reg |= ISPCSI2_CTX_CTRL1_CS_EN_ENABLE; | ||
1074 | + else | ||
1075 | + reg |= ISPCSI2_CTX_CTRL1_CS_EN_DISABLE; | ||
1076 | + selected_ctx_u->checksum_enabled = false; | ||
1077 | + } | ||
1078 | + if (selected_ctx_u->enabled || force_update) { | ||
1079 | + reg &= ~(ISPCSI2_CTX_CTRL1_CTX_EN_MASK); | ||
1080 | + if (selected_ctx->enabled) | ||
1081 | + reg |= ISPCSI2_CTX_CTRL1_CTX_EN_ENABLE; | ||
1082 | + else | ||
1083 | + reg |= ISPCSI2_CTX_CTRL1_CTX_EN_DISABLE; | ||
1084 | + selected_ctx_u->enabled = false; | ||
1085 | + } | ||
1086 | + isp_reg_writel(reg, OMAP3_ISP_IOMEM_CSI2A, | ||
1087 | + ISPCSI2_CTX_CTRL1(ctxnum)); | ||
1088 | + update_ctx_ctrl1[ctxnum] = false; | ||
1089 | + } | ||
1090 | + | ||
1091 | + if (update_ctx_ctrl2[ctxnum] || force_update) { | ||
1092 | + reg = isp_reg_readl(OMAP3_ISP_IOMEM_CSI2A, | ||
1093 | + ISPCSI2_CTX_CTRL2(ctxnum)); | ||
1094 | + if (selected_ctx_u->virtual_id || force_update) { | ||
1095 | + reg &= ~(ISPCSI2_CTX_CTRL2_VIRTUAL_ID_MASK); | ||
1096 | + reg |= selected_ctx->virtual_id << | ||
1097 | + ISPCSI2_CTX_CTRL2_VIRTUAL_ID_SHIFT; | ||
1098 | + selected_ctx_u->virtual_id = false; | ||
1099 | + } | ||
1100 | + | ||
1101 | + if (selected_ctx_u->format || force_update) { | ||
1102 | + struct v4l2_pix_format *pix; | ||
1103 | + u16 new_format = 0; | ||
1104 | + | ||
1105 | + reg &= ~(ISPCSI2_CTX_CTRL2_FORMAT_MASK); | ||
1106 | + pix = &selected_ctx->format; | ||
1107 | + switch (pix->pixelformat) { | ||
1108 | + case V4L2_PIX_FMT_RGB565: | ||
1109 | + case V4L2_PIX_FMT_RGB565X: | ||
1110 | + new_format = 0x22; | ||
1111 | + break; | ||
1112 | + case V4L2_PIX_FMT_YUYV: | ||
1113 | + case V4L2_PIX_FMT_UYVY: | ||
1114 | + if (uses_videoport) | ||
1115 | + new_format = 0x9E; | ||
1116 | + else | ||
1117 | + new_format = 0x1E; | ||
1118 | + break; | ||
1119 | + case V4L2_PIX_FMT_RGB555: | ||
1120 | + case V4L2_PIX_FMT_RGB555X: | ||
1121 | + new_format = 0xA1; | ||
1122 | + break; | ||
1123 | + case V4L2_PIX_FMT_SGRBG10: | ||
1124 | + if (uses_videoport) | ||
1125 | + new_format = 0x12F; | ||
1126 | + else | ||
1127 | + new_format = 0xAB; | ||
1128 | + break; | ||
1129 | + } | ||
1130 | + reg |= (new_format << ISPCSI2_CTX_CTRL2_FORMAT_SHIFT); | ||
1131 | + selected_ctx_u->format = false; | ||
1132 | + } | ||
1133 | + isp_reg_writel(reg, OMAP3_ISP_IOMEM_CSI2A, | ||
1134 | + ISPCSI2_CTX_CTRL2(ctxnum)); | ||
1135 | + update_ctx_ctrl2[ctxnum] = false; | ||
1136 | + } | ||
1137 | + | ||
1138 | + if (update_ctx_ctrl3[ctxnum] || force_update) { | ||
1139 | + reg = isp_reg_readl(OMAP3_ISP_IOMEM_CSI2A, | ||
1140 | + ISPCSI2_CTX_CTRL3(ctxnum)); | ||
1141 | + if (selected_ctx_u->alpha || force_update) { | ||
1142 | + reg &= ~(ISPCSI2_CTX_CTRL3_ALPHA_MASK); | ||
1143 | + reg |= (selected_ctx->alpha << | ||
1144 | + ISPCSI2_CTX_CTRL3_ALPHA_SHIFT); | ||
1145 | + selected_ctx_u->alpha = false; | ||
1146 | + } | ||
1147 | + isp_reg_writel(reg, OMAP3_ISP_IOMEM_CSI2A, | ||
1148 | + ISPCSI2_CTX_CTRL3(ctxnum)); | ||
1149 | + update_ctx_ctrl3[ctxnum] = false; | ||
1150 | + } | ||
1151 | + | ||
1152 | + if (selected_ctx_u->data_offset) { | ||
1153 | + reg = isp_reg_readl(OMAP3_ISP_IOMEM_CSI2A, | ||
1154 | + ISPCSI2_CTX_DAT_OFST(ctxnum)); | ||
1155 | + reg &= ~ISPCSI2_CTX_DAT_OFST_OFST_MASK; | ||
1156 | + reg |= selected_ctx->data_offset << | ||
1157 | + ISPCSI2_CTX_DAT_OFST_OFST_SHIFT; | ||
1158 | + isp_reg_writel(reg, OMAP3_ISP_IOMEM_CSI2A, | ||
1159 | + ISPCSI2_CTX_DAT_OFST(ctxnum)); | ||
1160 | + selected_ctx_u->data_offset = false; | ||
1161 | + } | ||
1162 | + | ||
1163 | + if (selected_ctx_u->ping_addr) { | ||
1164 | + reg = selected_ctx->ping_addr; | ||
1165 | + isp_reg_writel(reg, OMAP3_ISP_IOMEM_CSI2A, | ||
1166 | + ISPCSI2_CTX_DAT_PING_ADDR(ctxnum)); | ||
1167 | + selected_ctx_u->ping_addr = false; | ||
1168 | + } | ||
1169 | + | ||
1170 | + if (selected_ctx_u->pong_addr) { | ||
1171 | + reg = selected_ctx->pong_addr; | ||
1172 | + isp_reg_writel(reg, OMAP3_ISP_IOMEM_CSI2A, | ||
1173 | + ISPCSI2_CTX_DAT_PONG_ADDR(ctxnum)); | ||
1174 | + selected_ctx_u->pong_addr = false; | ||
1175 | + } | ||
1176 | + return 0; | ||
1177 | +} | ||
1178 | + | ||
1179 | +/** | ||
1180 | + * isp_csi2_ctx_get - Gets specific CSI2 Context configuration | ||
1181 | + * @ctxnum: Context number, valid between 0 and 7 values. | ||
1182 | + * | ||
1183 | + * Always returns 0. | ||
1184 | + **/ | ||
1185 | +int isp_csi2_ctx_get(u8 ctxnum) | ||
1186 | +{ | ||
1187 | + struct isp_csi2_ctx_cfg *selected_ctx; | ||
1188 | + struct isp_csi2_ctx_cfg_update *selected_ctx_u; | ||
1189 | + u32 reg; | ||
1190 | + | ||
1191 | + isp_csi2_ctx_validate(&ctxnum); | ||
1192 | + | ||
1193 | + selected_ctx = ¤t_csi2_cfg.contexts[ctxnum]; | ||
1194 | + selected_ctx_u = ¤t_csi2_cfg_update.contexts[ctxnum]; | ||
1195 | + | ||
1196 | + reg = isp_reg_readl(OMAP3_ISP_IOMEM_CSI2A, ISPCSI2_CTX_CTRL1(ctxnum)); | ||
1197 | + selected_ctx->frame_count = (reg & ISPCSI2_CTX_CTRL1_COUNT_MASK) >> | ||
1198 | + ISPCSI2_CTX_CTRL1_COUNT_SHIFT; | ||
1199 | + selected_ctx_u->frame_count = false; | ||
1200 | + | ||
1201 | + if ((reg & ISPCSI2_CTX_CTRL1_EOF_EN_MASK) == | ||
1202 | + ISPCSI2_CTX_CTRL1_EOF_EN_ENABLE) | ||
1203 | + selected_ctx->eof_enabled = true; | ||
1204 | + else | ||
1205 | + selected_ctx->eof_enabled = false; | ||
1206 | + selected_ctx_u->eof_enabled = false; | ||
1207 | + | ||
1208 | + if ((reg & ISPCSI2_CTX_CTRL1_EOL_EN_MASK) == | ||
1209 | + ISPCSI2_CTX_CTRL1_EOL_EN_ENABLE) | ||
1210 | + selected_ctx->eol_enabled = true; | ||
1211 | + else | ||
1212 | + selected_ctx->eol_enabled = false; | ||
1213 | + selected_ctx_u->eol_enabled = false; | ||
1214 | + | ||
1215 | + if ((reg & ISPCSI2_CTX_CTRL1_CS_EN_MASK) == | ||
1216 | + ISPCSI2_CTX_CTRL1_CS_EN_ENABLE) | ||
1217 | + selected_ctx->checksum_enabled = true; | ||
1218 | + else | ||
1219 | + selected_ctx->checksum_enabled = false; | ||
1220 | + selected_ctx_u->checksum_enabled = false; | ||
1221 | + | ||
1222 | + if ((reg & ISPCSI2_CTX_CTRL1_CTX_EN_MASK) == | ||
1223 | + ISPCSI2_CTX_CTRL1_CTX_EN_ENABLE) | ||
1224 | + selected_ctx->enabled = true; | ||
1225 | + else | ||
1226 | + selected_ctx->enabled = false; | ||
1227 | + selected_ctx_u->enabled = false; | ||
1228 | + update_ctx_ctrl1[ctxnum] = false; | ||
1229 | + | ||
1230 | + reg = isp_reg_readl(OMAP3_ISP_IOMEM_CSI2A, ISPCSI2_CTX_CTRL2(ctxnum)); | ||
1231 | + | ||
1232 | + selected_ctx->virtual_id = (reg & ISPCSI2_CTX_CTRL2_VIRTUAL_ID_MASK) >> | ||
1233 | + ISPCSI2_CTX_CTRL2_VIRTUAL_ID_SHIFT; | ||
1234 | + selected_ctx_u->virtual_id = false; | ||
1235 | + | ||
1236 | + switch ((reg & ISPCSI2_CTX_CTRL2_FORMAT_MASK) >> | ||
1237 | + ISPCSI2_CTX_CTRL2_FORMAT_SHIFT) { | ||
1238 | + case 0x22: | ||
1239 | + selected_ctx->format.pixelformat = V4L2_PIX_FMT_RGB565; | ||
1240 | + break; | ||
1241 | + case 0x9E: | ||
1242 | + case 0x1E: | ||
1243 | + selected_ctx->format.pixelformat = V4L2_PIX_FMT_YUYV; | ||
1244 | + break; | ||
1245 | + case 0xA1: | ||
1246 | + selected_ctx->format.pixelformat = V4L2_PIX_FMT_RGB555; | ||
1247 | + break; | ||
1248 | + case 0xAB: | ||
1249 | + case 0x12F: | ||
1250 | + selected_ctx->format.pixelformat = V4L2_PIX_FMT_SGRBG10; | ||
1251 | + break; | ||
1252 | + } | ||
1253 | + selected_ctx_u->format = false; | ||
1254 | + update_ctx_ctrl2[ctxnum] = false; | ||
1255 | + | ||
1256 | + selected_ctx->alpha = (isp_reg_readl(OMAP3_ISP_IOMEM_CSI2A, | ||
1257 | + ISPCSI2_CTX_CTRL3(ctxnum)) & | ||
1258 | + ISPCSI2_CTX_CTRL3_ALPHA_MASK) >> | ||
1259 | + ISPCSI2_CTX_CTRL3_ALPHA_SHIFT; | ||
1260 | + selected_ctx_u->alpha = false; | ||
1261 | + update_ctx_ctrl3[ctxnum] = false; | ||
1262 | + | ||
1263 | + selected_ctx->data_offset = (isp_reg_readl(OMAP3_ISP_IOMEM_CSI2A, | ||
1264 | + ISPCSI2_CTX_DAT_OFST(ctxnum)) & | ||
1265 | + ISPCSI2_CTX_DAT_OFST_OFST_MASK) >> | ||
1266 | + ISPCSI2_CTX_DAT_OFST_OFST_SHIFT; | ||
1267 | + selected_ctx_u->data_offset = false; | ||
1268 | + | ||
1269 | + selected_ctx->ping_addr = isp_reg_readl(OMAP3_ISP_IOMEM_CSI2A, | ||
1270 | + ISPCSI2_CTX_DAT_PING_ADDR(ctxnum)); | ||
1271 | + selected_ctx_u->ping_addr = false; | ||
1272 | + | ||
1273 | + selected_ctx->pong_addr = isp_reg_readl(OMAP3_ISP_IOMEM_CSI2A, | ||
1274 | + ISPCSI2_CTX_DAT_PONG_ADDR(ctxnum)); | ||
1275 | + selected_ctx_u->pong_addr = false; | ||
1276 | + return 0; | ||
1277 | +} | ||
1278 | + | ||
1279 | +/** | ||
1280 | + * isp_csi2_ctx_update_all - Applies all CSI2 context configuration. | ||
1281 | + * @force_update: Flag to force rewrite of registers, even if they haven't been | ||
1282 | + * updated with the isp_csi2_ctx_config_*() functions. | ||
1283 | + * | ||
1284 | + * It only saves settings when they were previously updated using the | ||
1285 | + * isp_csi2_ctx_config_*() functions, unless the force_update flag is | ||
1286 | + * set to true. | ||
1287 | + * Always returns 0. | ||
1288 | + **/ | ||
1289 | +int isp_csi2_ctx_update_all(bool force_update) | ||
1290 | +{ | ||
1291 | + u8 ctxnum; | ||
1292 | + | ||
1293 | + for (ctxnum = 0; ctxnum < 8; ctxnum++) | ||
1294 | + isp_csi2_ctx_update(ctxnum, force_update); | ||
1295 | + | ||
1296 | + return 0; | ||
1297 | +} | ||
1298 | + | ||
1299 | +/** | ||
1300 | + * isp_csi2_ctx_get_all - Gets all CSI2 Context configurations | ||
1301 | + * | ||
1302 | + * Always returns 0. | ||
1303 | + **/ | ||
1304 | +int isp_csi2_ctx_get_all(void) | ||
1305 | +{ | ||
1306 | + u8 ctxnum; | ||
1307 | + | ||
1308 | + for (ctxnum = 0; ctxnum < 8; ctxnum++) | ||
1309 | + isp_csi2_ctx_get(ctxnum); | ||
1310 | + | ||
1311 | + return 0; | ||
1312 | +} | ||
1313 | + | ||
1314 | +int isp_csi2_phy_config(struct isp_csi2_phy_cfg *desiredphyconfig) | ||
1315 | +{ | ||
1316 | + struct isp_csi2_phy_cfg *currphy = ¤t_csi2_cfg.phy; | ||
1317 | + struct isp_csi2_phy_cfg_update *currphy_u = | ||
1318 | + ¤t_csi2_cfg_update.phy; | ||
1319 | + | ||
1320 | + if ((desiredphyconfig->tclk_term > 0x7f) || | ||
1321 | + (desiredphyconfig->tclk_miss > 0x3)) { | ||
1322 | + printk(KERN_ERR "Invalid PHY configuration sent by the" | ||
1323 | + " driver\n"); | ||
1324 | + return -EINVAL; | ||
1325 | + } | ||
1326 | + | ||
1327 | + if (currphy->ths_term != desiredphyconfig->ths_term) { | ||
1328 | + currphy->ths_term = desiredphyconfig->ths_term; | ||
1329 | + currphy_u->ths_term = true; | ||
1330 | + update_phy_cfg0 = true; | ||
1331 | + } | ||
1332 | + if (currphy->ths_settle != desiredphyconfig->ths_settle) { | ||
1333 | + currphy->ths_settle = desiredphyconfig->ths_settle; | ||
1334 | + currphy_u->ths_settle = true; | ||
1335 | + update_phy_cfg0 = true; | ||
1336 | + } | ||
1337 | + if (currphy->tclk_term != desiredphyconfig->tclk_term) { | ||
1338 | + currphy->tclk_term = desiredphyconfig->tclk_term; | ||
1339 | + currphy_u->tclk_term = true; | ||
1340 | + update_phy_cfg1 = true; | ||
1341 | + } | ||
1342 | + if (currphy->tclk_miss != desiredphyconfig->tclk_miss) { | ||
1343 | + currphy->tclk_miss = desiredphyconfig->tclk_miss; | ||
1344 | + currphy_u->tclk_miss = true; | ||
1345 | + update_phy_cfg1 = true; | ||
1346 | + } | ||
1347 | + if (currphy->tclk_settle != desiredphyconfig->tclk_settle) { | ||
1348 | + currphy->tclk_settle = desiredphyconfig->tclk_settle; | ||
1349 | + currphy_u->tclk_settle = true; | ||
1350 | + update_phy_cfg1 = true; | ||
1351 | + } | ||
1352 | + return 0; | ||
1353 | +} | ||
1354 | + | ||
1355 | +/** | ||
1356 | + * isp_csi2_calc_phy_cfg0 - Calculates D-PHY config based on the MIPIClk speed. | ||
1357 | + * @mipiclk: MIPI clock frequency being used with CSI2 sensor. | ||
1358 | + * @lbound_hs_settle: Lower bound for CSI2 High Speed Settle transition. | ||
1359 | + * @ubound_hs_settle: Upper bound for CSI2 High Speed Settle transition. | ||
1360 | + * | ||
1361 | + * From TRM, we have the same calculation for HS Termination signal. | ||
1362 | + * THS_TERM = ceil( 12.5ns / DDRCLK period ) - 1 | ||
1363 | + * But for Settle, we use the mid value between the two passed boundaries from | ||
1364 | + * sensor: | ||
1365 | + * THS_SETTLE = (Upper bound + Lower bound) / 2 | ||
1366 | + * | ||
1367 | + * Always returns 0. | ||
1368 | + */ | ||
1369 | +int isp_csi2_calc_phy_cfg0(u32 mipiclk, u32 lbound_hs_settle, | ||
1370 | + u32 ubound_hs_settle) | ||
1371 | +{ | ||
1372 | + struct isp_csi2_phy_cfg *currphy = ¤t_csi2_cfg.phy; | ||
1373 | + struct isp_csi2_phy_cfg_update *currphy_u = | ||
1374 | + ¤t_csi2_cfg_update.phy; | ||
1375 | + u32 tmp, ddrclk = mipiclk >> 1; | ||
1376 | + | ||
1377 | + /* Calculate THS_TERM */ | ||
1378 | + tmp = ddrclk / 80000000; | ||
1379 | + if ((ddrclk % 80000000) > 0) | ||
1380 | + tmp++; | ||
1381 | + currphy->ths_term = tmp - 1; | ||
1382 | + currphy_u->ths_term = true; | ||
1383 | + | ||
1384 | + /* Calculate THS_SETTLE */ | ||
1385 | + currphy->ths_settle = (ubound_hs_settle + lbound_hs_settle) / 2; | ||
1386 | + | ||
1387 | + currphy_u->ths_settle = true; | ||
1388 | + isp_csi2_phy_update(true); | ||
1389 | + return 0; | ||
1390 | +} | ||
1391 | +EXPORT_SYMBOL(isp_csi2_calc_phy_cfg0); | ||
1392 | + | ||
1393 | +/** | ||
1394 | + * isp_csi2_phy_update - Applies CSI2 D-PHY configuration. | ||
1395 | + * @force_update: Flag to force rewrite of registers, even if they haven't been | ||
1396 | + * updated with the isp_csi2_phy_config_*() functions. | ||
1397 | + * | ||
1398 | + * It only saves settings when they were previously updated using the | ||
1399 | + * isp_csi2_phy_config_*() functions, unless the force_update flag is | ||
1400 | + * set to true. | ||
1401 | + * Always returns 0. | ||
1402 | + **/ | ||
1403 | +int isp_csi2_phy_update(bool force_update) | ||
1404 | +{ | ||
1405 | + struct isp_csi2_phy_cfg *currphy = ¤t_csi2_cfg.phy; | ||
1406 | + struct isp_csi2_phy_cfg_update *currphy_u = | ||
1407 | + ¤t_csi2_cfg_update.phy; | ||
1408 | + u32 reg; | ||
1409 | + | ||
1410 | + if (update_phy_cfg0 || force_update) { | ||
1411 | + reg = isp_reg_readl(OMAP3_ISP_IOMEM_CSI2PHY, ISPCSI2PHY_CFG0); | ||
1412 | + if (currphy_u->ths_term || force_update) { | ||
1413 | + reg &= ~ISPCSI2PHY_CFG0_THS_TERM_MASK; | ||
1414 | + reg |= (currphy->ths_term << | ||
1415 | + ISPCSI2PHY_CFG0_THS_TERM_SHIFT); | ||
1416 | + currphy_u->ths_term = false; | ||
1417 | + } | ||
1418 | + if (currphy_u->ths_settle || force_update) { | ||
1419 | + reg &= ~ISPCSI2PHY_CFG0_THS_SETTLE_MASK; | ||
1420 | + reg |= (currphy->ths_settle << | ||
1421 | + ISPCSI2PHY_CFG0_THS_SETTLE_SHIFT); | ||
1422 | + currphy_u->ths_settle = false; | ||
1423 | + } | ||
1424 | + isp_reg_writel(reg, OMAP3_ISP_IOMEM_CSI2PHY, ISPCSI2PHY_CFG0); | ||
1425 | + update_phy_cfg0 = false; | ||
1426 | + } | ||
1427 | + | ||
1428 | + if (update_phy_cfg1 || force_update) { | ||
1429 | + reg = isp_reg_readl(OMAP3_ISP_IOMEM_CSI2PHY, ISPCSI2PHY_CFG1); | ||
1430 | + if (currphy_u->tclk_term || force_update) { | ||
1431 | + reg &= ~ISPCSI2PHY_CFG1_TCLK_TERM_MASK; | ||
1432 | + reg |= (currphy->tclk_term << | ||
1433 | + ISPCSI2PHY_CFG1_TCLK_TERM_SHIFT); | ||
1434 | + currphy_u->tclk_term = false; | ||
1435 | + } | ||
1436 | + if (currphy_u->tclk_miss || force_update) { | ||
1437 | + reg &= ~ISPCSI2PHY_CFG1_TCLK_MISS_MASK; | ||
1438 | + reg |= (currphy->tclk_miss << | ||
1439 | + ISPCSI2PHY_CFG1_TCLK_MISS_SHIFT); | ||
1440 | + currphy_u->tclk_miss = false; | ||
1441 | + } | ||
1442 | + if (currphy_u->tclk_settle || force_update) { | ||
1443 | + reg &= ~ISPCSI2PHY_CFG1_TCLK_SETTLE_MASK; | ||
1444 | + reg |= (currphy->tclk_settle << | ||
1445 | + ISPCSI2PHY_CFG1_TCLK_SETTLE_SHIFT); | ||
1446 | + currphy_u->tclk_settle = false; | ||
1447 | + } | ||
1448 | + isp_reg_writel(reg, OMAP3_ISP_IOMEM_CSI2PHY, ISPCSI2PHY_CFG1); | ||
1449 | + update_phy_cfg1 = false; | ||
1450 | + } | ||
1451 | + return 0; | ||
1452 | +} | ||
1453 | + | ||
1454 | +/** | ||
1455 | + * isp_csi2_phy_get - Gets CSI2 D-PHY configuration | ||
1456 | + * | ||
1457 | + * Gets settings from HW registers and fills in the internal driver memory | ||
1458 | + * Always returns 0. | ||
1459 | + **/ | ||
1460 | +int isp_csi2_phy_get(void) | ||
1461 | +{ | ||
1462 | + struct isp_csi2_phy_cfg *currphy = ¤t_csi2_cfg.phy; | ||
1463 | + struct isp_csi2_phy_cfg_update *currphy_u = | ||
1464 | + ¤t_csi2_cfg_update.phy; | ||
1465 | + u32 reg; | ||
1466 | + | ||
1467 | + reg = isp_reg_readl(OMAP3_ISP_IOMEM_CSI2PHY, ISPCSI2PHY_CFG0); | ||
1468 | + currphy->ths_term = (reg & ISPCSI2PHY_CFG0_THS_TERM_MASK) >> | ||
1469 | + ISPCSI2PHY_CFG0_THS_TERM_SHIFT; | ||
1470 | + currphy_u->ths_term = false; | ||
1471 | + | ||
1472 | + currphy->ths_settle = (reg & ISPCSI2PHY_CFG0_THS_SETTLE_MASK) >> | ||
1473 | + ISPCSI2PHY_CFG0_THS_SETTLE_SHIFT; | ||
1474 | + currphy_u->ths_settle = false; | ||
1475 | + update_phy_cfg0 = false; | ||
1476 | + | ||
1477 | + reg = isp_reg_readl(OMAP3_ISP_IOMEM_CSI2PHY, ISPCSI2PHY_CFG1); | ||
1478 | + | ||
1479 | + currphy->tclk_term = (reg & ISPCSI2PHY_CFG1_TCLK_TERM_MASK) >> | ||
1480 | + ISPCSI2PHY_CFG1_TCLK_TERM_SHIFT; | ||
1481 | + currphy_u->tclk_term = false; | ||
1482 | + | ||
1483 | + currphy->tclk_miss = (reg & ISPCSI2PHY_CFG1_TCLK_MISS_MASK) >> | ||
1484 | + ISPCSI2PHY_CFG1_TCLK_MISS_SHIFT; | ||
1485 | + currphy_u->tclk_miss = false; | ||
1486 | + | ||
1487 | + currphy->tclk_settle = (reg & ISPCSI2PHY_CFG1_TCLK_SETTLE_MASK) >> | ||
1488 | + ISPCSI2PHY_CFG1_TCLK_SETTLE_SHIFT; | ||
1489 | + currphy_u->tclk_settle = false; | ||
1490 | + | ||
1491 | + update_phy_cfg1 = false; | ||
1492 | + return 0; | ||
1493 | +} | ||
1494 | + | ||
1495 | +/** | ||
1496 | + * isp_csi2_timings_config_forcerxmode - Sets Force Rx mode on stop state count | ||
1497 | + * @force_rx_mode: Boolean to enable/disable forcing Rx mode in CSI2 receiver | ||
1498 | + * | ||
1499 | + * Returns 0 if successful, or -EINVAL if wrong ComplexIO number is selected. | ||
1500 | + **/ | ||
1501 | +int isp_csi2_timings_config_forcerxmode(u8 io, bool force_rx_mode) | ||
1502 | +{ | ||
1503 | + struct isp_csi2_timings_cfg *currtimings; | ||
1504 | + struct isp_csi2_timings_cfg_update *currtimings_u; | ||
1505 | + | ||
1506 | + if (io < 1 || io > 2) { | ||
1507 | + printk(KERN_ERR "CSI2 - Timings config: Invalid IO number\n"); | ||
1508 | + return -EINVAL; | ||
1509 | + } | ||
1510 | + | ||
1511 | + currtimings = ¤t_csi2_cfg.timings[io - 1]; | ||
1512 | + currtimings_u = ¤t_csi2_cfg_update.timings[io - 1]; | ||
1513 | + if (currtimings->force_rx_mode != force_rx_mode) { | ||
1514 | + currtimings->force_rx_mode = force_rx_mode; | ||
1515 | + currtimings_u->force_rx_mode = true; | ||
1516 | + update_timing = true; | ||
1517 | + } | ||
1518 | + return 0; | ||
1519 | +} | ||
1520 | + | ||
1521 | +/** | ||
1522 | + * isp_csi2_timings_config_stopstate_16x - Sets 16x factor for L3 cycles | ||
1523 | + * @stop_state_16x: Boolean to use or not use the 16x multiplier for stop count | ||
1524 | + * | ||
1525 | + * Returns 0 if successful, or -EINVAL if wrong ComplexIO number is selected. | ||
1526 | + **/ | ||
1527 | +int isp_csi2_timings_config_stopstate_16x(u8 io, bool stop_state_16x) | ||
1528 | +{ | ||
1529 | + struct isp_csi2_timings_cfg *currtimings; | ||
1530 | + struct isp_csi2_timings_cfg_update *currtimings_u; | ||
1531 | + | ||
1532 | + if (io < 1 || io > 2) { | ||
1533 | + printk(KERN_ERR "CSI2 - Timings config: Invalid IO number\n"); | ||
1534 | + return -EINVAL; | ||
1535 | + } | ||
1536 | + | ||
1537 | + currtimings = ¤t_csi2_cfg.timings[io - 1]; | ||
1538 | + currtimings_u = ¤t_csi2_cfg_update.timings[io - 1]; | ||
1539 | + if (currtimings->stop_state_16x != stop_state_16x) { | ||
1540 | + currtimings->stop_state_16x = stop_state_16x; | ||
1541 | + currtimings_u->stop_state_16x = true; | ||
1542 | + update_timing = true; | ||
1543 | + } | ||
1544 | + return 0; | ||
1545 | +} | ||
1546 | + | ||
1547 | +/** | ||
1548 | + * isp_csi2_timings_config_stopstate_4x - Sets 4x factor for L3 cycles | ||
1549 | + * @stop_state_4x: Boolean to use or not use the 4x multiplier for stop count | ||
1550 | + * | ||
1551 | + * Returns 0 if successful, or -EINVAL if wrong ComplexIO number is selected. | ||
1552 | + **/ | ||
1553 | +int isp_csi2_timings_config_stopstate_4x(u8 io, bool stop_state_4x) | ||
1554 | +{ | ||
1555 | + struct isp_csi2_timings_cfg *currtimings; | ||
1556 | + struct isp_csi2_timings_cfg_update *currtimings_u; | ||
1557 | + | ||
1558 | + if (io < 1 || io > 2) { | ||
1559 | + printk(KERN_ERR "CSI2 - Timings config: Invalid IO number\n"); | ||
1560 | + return -EINVAL; | ||
1561 | + } | ||
1562 | + | ||
1563 | + currtimings = ¤t_csi2_cfg.timings[io - 1]; | ||
1564 | + currtimings_u = ¤t_csi2_cfg_update.timings[io - 1]; | ||
1565 | + if (currtimings->stop_state_4x != stop_state_4x) { | ||
1566 | + currtimings->stop_state_4x = stop_state_4x; | ||
1567 | + currtimings_u->stop_state_4x = true; | ||
1568 | + update_timing = true; | ||
1569 | + } | ||
1570 | + return 0; | ||
1571 | +} | ||
1572 | + | ||
1573 | +/** | ||
1574 | + * isp_csi2_timings_config_stopstate_cnt - Sets L3 cycles | ||
1575 | + * @stop_state_counter: Stop state counter value for L3 cycles | ||
1576 | + * | ||
1577 | + * Returns 0 if successful, or -EINVAL if wrong ComplexIO number is selected. | ||
1578 | + **/ | ||
1579 | +int isp_csi2_timings_config_stopstate_cnt(u8 io, u16 stop_state_counter) | ||
1580 | +{ | ||
1581 | + struct isp_csi2_timings_cfg *currtimings; | ||
1582 | + struct isp_csi2_timings_cfg_update *currtimings_u; | ||
1583 | + | ||
1584 | + if (io < 1 || io > 2) { | ||
1585 | + printk(KERN_ERR "CSI2 - Timings config: Invalid IO number\n"); | ||
1586 | + return -EINVAL; | ||
1587 | + } | ||
1588 | + | ||
1589 | + currtimings = ¤t_csi2_cfg.timings[io - 1]; | ||
1590 | + currtimings_u = ¤t_csi2_cfg_update.timings[io - 1]; | ||
1591 | + if (currtimings->stop_state_counter != stop_state_counter) { | ||
1592 | + currtimings->stop_state_counter = (stop_state_counter & 0x1FFF); | ||
1593 | + currtimings_u->stop_state_counter = true; | ||
1594 | + update_timing = true; | ||
1595 | + } | ||
1596 | + return 0; | ||
1597 | +} | ||
1598 | + | ||
1599 | +/** | ||
1600 | + * isp_csi2_timings_update - Applies specified CSI2 timing configuration. | ||
1601 | + * @io: IO number (1 or 2) which specifies which ComplexIO are we updating | ||
1602 | + * @force_update: Flag to force rewrite of registers, even if they haven't been | ||
1603 | + * updated with the isp_csi2_timings_config_*() functions. | ||
1604 | + * | ||
1605 | + * It only saves settings when they were previously updated using the | ||
1606 | + * isp_csi2_timings_config_*() functions, unless the force_update flag is | ||
1607 | + * set to true. | ||
1608 | + * Returns 0 if successful, or -EINVAL if invalid IO number is passed. | ||
1609 | + **/ | ||
1610 | +int isp_csi2_timings_update(u8 io, bool force_update) | ||
1611 | +{ | ||
1612 | + struct isp_csi2_timings_cfg *currtimings; | ||
1613 | + struct isp_csi2_timings_cfg_update *currtimings_u; | ||
1614 | + u32 reg; | ||
1615 | + | ||
1616 | + if (io < 1 || io > 2) { | ||
1617 | + printk(KERN_ERR "CSI2 - Timings config: Invalid IO number\n"); | ||
1618 | + return -EINVAL; | ||
1619 | + } | ||
1620 | + | ||
1621 | + currtimings = ¤t_csi2_cfg.timings[io - 1]; | ||
1622 | + currtimings_u = ¤t_csi2_cfg_update.timings[io - 1]; | ||
1623 | + | ||
1624 | + if (update_timing || force_update) { | ||
1625 | + reg = isp_reg_readl(OMAP3_ISP_IOMEM_CSI2A, ISPCSI2_TIMING); | ||
1626 | + if (currtimings_u->force_rx_mode || force_update) { | ||
1627 | + reg &= ~ISPCSI2_TIMING_FORCE_RX_MODE_IO_MASK(io); | ||
1628 | + if (currtimings->force_rx_mode) | ||
1629 | + reg |= ISPCSI2_TIMING_FORCE_RX_MODE_IO_ENABLE | ||
1630 | + (io); | ||
1631 | + else | ||
1632 | + reg |= ISPCSI2_TIMING_FORCE_RX_MODE_IO_DISABLE | ||
1633 | + (io); | ||
1634 | + currtimings_u->force_rx_mode = false; | ||
1635 | + } | ||
1636 | + if (currtimings_u->stop_state_16x || force_update) { | ||
1637 | + reg &= ~ISPCSI2_TIMING_STOP_STATE_X16_IO_MASK(io); | ||
1638 | + if (currtimings->stop_state_16x) | ||
1639 | + reg |= ISPCSI2_TIMING_STOP_STATE_X16_IO_ENABLE | ||
1640 | + (io); | ||
1641 | + else | ||
1642 | + reg |= ISPCSI2_TIMING_STOP_STATE_X16_IO_DISABLE | ||
1643 | + (io); | ||
1644 | + currtimings_u->stop_state_16x = false; | ||
1645 | + } | ||
1646 | + if (currtimings_u->stop_state_4x || force_update) { | ||
1647 | + reg &= ~ISPCSI2_TIMING_STOP_STATE_X4_IO_MASK(io); | ||
1648 | + if (currtimings->stop_state_4x) { | ||
1649 | + reg |= ISPCSI2_TIMING_STOP_STATE_X4_IO_ENABLE | ||
1650 | + (io); | ||
1651 | + } else { | ||
1652 | + reg |= ISPCSI2_TIMING_STOP_STATE_X4_IO_DISABLE | ||
1653 | + (io); | ||
1654 | + } | ||
1655 | + currtimings_u->stop_state_4x = false; | ||
1656 | + } | ||
1657 | + if (currtimings_u->stop_state_counter || force_update) { | ||
1658 | + reg &= ~ISPCSI2_TIMING_STOP_STATE_COUNTER_IO_MASK(io); | ||
1659 | + reg |= currtimings->stop_state_counter << | ||
1660 | + ISPCSI2_TIMING_STOP_STATE_COUNTER_IO_SHIFT(io); | ||
1661 | + currtimings_u->stop_state_counter = false; | ||
1662 | + } | ||
1663 | + isp_reg_writel(reg, OMAP3_ISP_IOMEM_CSI2A, ISPCSI2_TIMING); | ||
1664 | + update_timing = false; | ||
1665 | + } | ||
1666 | + return 0; | ||
1667 | +} | ||
1668 | + | ||
1669 | +/** | ||
1670 | + * isp_csi2_timings_get - Gets specific CSI2 ComplexIO timing configuration | ||
1671 | + * @io: IO number (1 or 2) which specifies which ComplexIO are we getting | ||
1672 | + * | ||
1673 | + * Gets settings from HW registers and fills in the internal driver memory | ||
1674 | + * Returns 0 if successful, or -EINVAL if invalid IO number is passed. | ||
1675 | + **/ | ||
1676 | +int isp_csi2_timings_get(u8 io) | ||
1677 | +{ | ||
1678 | + struct isp_csi2_timings_cfg *currtimings; | ||
1679 | + struct isp_csi2_timings_cfg_update *currtimings_u; | ||
1680 | + u32 reg; | ||
1681 | + | ||
1682 | + if (io < 1 || io > 2) { | ||
1683 | + printk(KERN_ERR "CSI2 - Timings config: Invalid IO number\n"); | ||
1684 | + return -EINVAL; | ||
1685 | + } | ||
1686 | + | ||
1687 | + currtimings = ¤t_csi2_cfg.timings[io - 1]; | ||
1688 | + currtimings_u = ¤t_csi2_cfg_update.timings[io - 1]; | ||
1689 | + | ||
1690 | + reg = isp_reg_readl(OMAP3_ISP_IOMEM_CSI2A, ISPCSI2_TIMING); | ||
1691 | + if ((reg & ISPCSI2_TIMING_FORCE_RX_MODE_IO_MASK(io)) == | ||
1692 | + ISPCSI2_TIMING_FORCE_RX_MODE_IO_ENABLE(io)) | ||
1693 | + currtimings->force_rx_mode = true; | ||
1694 | + else | ||
1695 | + currtimings->force_rx_mode = false; | ||
1696 | + currtimings_u->force_rx_mode = false; | ||
1697 | + | ||
1698 | + if ((reg & ISPCSI2_TIMING_STOP_STATE_X16_IO_MASK(io)) == | ||
1699 | + ISPCSI2_TIMING_STOP_STATE_X16_IO_ENABLE(io)) | ||
1700 | + currtimings->stop_state_16x = true; | ||
1701 | + else | ||
1702 | + currtimings->stop_state_16x = false; | ||
1703 | + currtimings_u->stop_state_16x = false; | ||
1704 | + | ||
1705 | + if ((reg & ISPCSI2_TIMING_STOP_STATE_X4_IO_MASK(io)) == | ||
1706 | + ISPCSI2_TIMING_STOP_STATE_X4_IO_ENABLE(io)) | ||
1707 | + currtimings->stop_state_4x = true; | ||
1708 | + else | ||
1709 | + currtimings->stop_state_4x = false; | ||
1710 | + currtimings_u->stop_state_4x = false; | ||
1711 | + | ||
1712 | + currtimings->stop_state_counter = (reg & | ||
1713 | + ISPCSI2_TIMING_STOP_STATE_COUNTER_IO_MASK(io)) >> | ||
1714 | + ISPCSI2_TIMING_STOP_STATE_COUNTER_IO_SHIFT(io); | ||
1715 | + currtimings_u->stop_state_counter = false; | ||
1716 | + update_timing = false; | ||
1717 | + return 0; | ||
1718 | +} | ||
1719 | + | ||
1720 | +/** | ||
1721 | + * isp_csi2_timings_update_all - Applies specified CSI2 timing configuration. | ||
1722 | + * @force_update: Flag to force rewrite of registers, even if they haven't been | ||
1723 | + * updated with the isp_csi2_timings_config_*() functions. | ||
1724 | + * | ||
1725 | + * It only saves settings when they were previously updated using the | ||
1726 | + * isp_csi2_timings_config_*() functions, unless the force_update flag is | ||
1727 | + * set to true. | ||
1728 | + * Always returns 0. | ||
1729 | + **/ | ||
1730 | +int isp_csi2_timings_update_all(bool force_update) | ||
1731 | +{ | ||
1732 | + int i; | ||
1733 | + | ||
1734 | + for (i = 1; i < 3; i++) | ||
1735 | + isp_csi2_timings_update(i, force_update); | ||
1736 | + return 0; | ||
1737 | +} | ||
1738 | + | ||
1739 | +/** | ||
1740 | + * isp_csi2_timings_get_all - Gets all CSI2 ComplexIO timing configurations | ||
1741 | + * | ||
1742 | + * Always returns 0. | ||
1743 | + **/ | ||
1744 | +int isp_csi2_timings_get_all(void) | ||
1745 | +{ | ||
1746 | + int i; | ||
1747 | + | ||
1748 | + for (i = 1; i < 3; i++) | ||
1749 | + isp_csi2_timings_get(i); | ||
1750 | + return 0; | ||
1751 | +} | ||
1752 | + | ||
1753 | +/** | ||
1754 | + * isp_csi2_isr - CSI2 interrupt handling. | ||
1755 | + **/ | ||
1756 | +void isp_csi2_isr(void) | ||
1757 | +{ | ||
1758 | + u32 csi2_irqstatus, cpxio1_irqstatus, ctxirqstatus; | ||
1759 | + | ||
1760 | + csi2_irqstatus = isp_reg_readl(OMAP3_ISP_IOMEM_CSI2A, | ||
1761 | + ISPCSI2_IRQSTATUS); | ||
1762 | + isp_reg_writel(csi2_irqstatus, OMAP3_ISP_IOMEM_CSI2A, | ||
1763 | + ISPCSI2_IRQSTATUS); | ||
1764 | + | ||
1765 | + if (csi2_irqstatus & ISPCSI2_IRQSTATUS_COMPLEXIO1_ERR_IRQ) { | ||
1766 | + cpxio1_irqstatus = isp_reg_readl(OMAP3_ISP_IOMEM_CSI2A, | ||
1767 | + ISPCSI2_COMPLEXIO1_IRQSTATUS); | ||
1768 | + isp_reg_writel(cpxio1_irqstatus, OMAP3_ISP_IOMEM_CSI2A, | ||
1769 | + ISPCSI2_COMPLEXIO1_IRQSTATUS); | ||
1770 | + printk(KERN_ERR "CSI2: ComplexIO Error IRQ %x\n", | ||
1771 | + cpxio1_irqstatus); | ||
1772 | + } | ||
1773 | + | ||
1774 | + if (csi2_irqstatus & ISPCSI2_IRQSTATUS_CONTEXT(0)) { | ||
1775 | + ctxirqstatus = isp_reg_readl(OMAP3_ISP_IOMEM_CSI2A, | ||
1776 | + ISPCSI2_CTX_IRQSTATUS(0)); | ||
1777 | + isp_reg_writel(ctxirqstatus, OMAP3_ISP_IOMEM_CSI2A, | ||
1778 | + ISPCSI2_CTX_IRQSTATUS(0)); | ||
1779 | + } | ||
1780 | + | ||
1781 | + if (csi2_irqstatus & ISPCSI2_IRQSTATUS_OCP_ERR_IRQ) | ||
1782 | + printk(KERN_ERR "CSI2: OCP Transmission Error\n"); | ||
1783 | + | ||
1784 | + if (csi2_irqstatus & ISPCSI2_IRQSTATUS_SHORT_PACKET_IRQ) | ||
1785 | + printk(KERN_ERR "CSI2: Short packet receive error\n"); | ||
1786 | + | ||
1787 | + if (csi2_irqstatus & ISPCSI2_IRQSTATUS_ECC_CORRECTION_IRQ) | ||
1788 | + printk(KERN_DEBUG "CSI2: ECC correction done\n"); | ||
1789 | + | ||
1790 | + if (csi2_irqstatus & ISPCSI2_IRQSTATUS_ECC_NO_CORRECTION_IRQ) | ||
1791 | + printk(KERN_ERR "CSI2: ECC correction failed\n"); | ||
1792 | + | ||
1793 | + if (csi2_irqstatus & ISPCSI2_IRQSTATUS_COMPLEXIO2_ERR_IRQ) | ||
1794 | + printk(KERN_ERR "CSI2: ComplexIO #2 failed\n"); | ||
1795 | + | ||
1796 | + if (csi2_irqstatus & ISPCSI2_IRQSTATUS_FIFO_OVF_IRQ) | ||
1797 | + printk(KERN_ERR "CSI2: FIFO overflow error\n"); | ||
1798 | + | ||
1799 | + return; | ||
1800 | +} | ||
1801 | +EXPORT_SYMBOL(isp_csi2_isr); | ||
1802 | + | ||
1803 | +/** | ||
1804 | + * isp_csi2_irq_complexio1_set - Enables CSI2 ComplexIO IRQs. | ||
1805 | + * @enable: Enable/disable CSI2 ComplexIO #1 interrupts | ||
1806 | + **/ | ||
1807 | +void isp_csi2_irq_complexio1_set(int enable) | ||
1808 | +{ | ||
1809 | + u32 reg; | ||
1810 | + reg = ISPCSI2_COMPLEXIO1_IRQENABLE_STATEALLULPMEXIT | | ||
1811 | + ISPCSI2_COMPLEXIO1_IRQENABLE_STATEALLULPMENTER | | ||
1812 | + ISPCSI2_COMPLEXIO1_IRQENABLE_STATEULPM5 | | ||
1813 | + ISPCSI2_COMPLEXIO1_IRQENABLE_ERRCONTROL5 | | ||
1814 | + ISPCSI2_COMPLEXIO1_IRQENABLE_ERRESC5 | | ||
1815 | + ISPCSI2_COMPLEXIO1_IRQENABLE_ERRSOTSYNCHS5 | | ||
1816 | + ISPCSI2_COMPLEXIO1_IRQENABLE_ERRSOTHS5 | | ||
1817 | + ISPCSI2_COMPLEXIO1_IRQENABLE_STATEULPM4 | | ||
1818 | + ISPCSI2_COMPLEXIO1_IRQENABLE_ERRCONTROL4 | | ||
1819 | + ISPCSI2_COMPLEXIO1_IRQENABLE_ERRESC4 | | ||
1820 | + ISPCSI2_COMPLEXIO1_IRQENABLE_ERRSOTSYNCHS4 | | ||
1821 | + ISPCSI2_COMPLEXIO1_IRQENABLE_ERRSOTHS4 | | ||
1822 | + ISPCSI2_COMPLEXIO1_IRQENABLE_STATEULPM3 | | ||
1823 | + ISPCSI2_COMPLEXIO1_IRQENABLE_ERRCONTROL3 | | ||
1824 | + ISPCSI2_COMPLEXIO1_IRQENABLE_ERRESC3 | | ||
1825 | + ISPCSI2_COMPLEXIO1_IRQENABLE_ERRSOTSYNCHS3 | | ||
1826 | + ISPCSI2_COMPLEXIO1_IRQENABLE_ERRSOTHS3 | | ||
1827 | + ISPCSI2_COMPLEXIO1_IRQENABLE_STATEULPM2 | | ||
1828 | + ISPCSI2_COMPLEXIO1_IRQENABLE_ERRCONTROL2 | | ||
1829 | + ISPCSI2_COMPLEXIO1_IRQENABLE_ERRESC2 | | ||
1830 | + ISPCSI2_COMPLEXIO1_IRQENABLE_ERRSOTSYNCHS2 | | ||
1831 | + ISPCSI2_COMPLEXIO1_IRQENABLE_ERRSOTHS2 | | ||
1832 | + ISPCSI2_COMPLEXIO1_IRQENABLE_STATEULPM1 | | ||
1833 | + ISPCSI2_COMPLEXIO1_IRQENABLE_ERRCONTROL1 | | ||
1834 | + ISPCSI2_COMPLEXIO1_IRQENABLE_ERRESC1 | | ||
1835 | + ISPCSI2_COMPLEXIO1_IRQENABLE_ERRSOTSYNCHS1 | | ||
1836 | + ISPCSI2_COMPLEXIO1_IRQENABLE_ERRSOTHS1; | ||
1837 | + isp_reg_writel(reg, OMAP3_ISP_IOMEM_CSI2A, | ||
1838 | + ISPCSI2_COMPLEXIO1_IRQSTATUS); | ||
1839 | + if (enable) { | ||
1840 | + reg |= isp_reg_readl(OMAP3_ISP_IOMEM_CSI2A, | ||
1841 | + ISPCSI2_COMPLEXIO1_IRQENABLE); | ||
1842 | + } else | ||
1843 | + reg = 0; | ||
1844 | + isp_reg_writel(reg, OMAP3_ISP_IOMEM_CSI2A, | ||
1845 | + ISPCSI2_COMPLEXIO1_IRQENABLE); | ||
1846 | +} | ||
1847 | +EXPORT_SYMBOL(isp_csi2_irq_complexio1_set); | ||
1848 | + | ||
1849 | +/** | ||
1850 | + * isp_csi2_irq_ctx_set - Enables CSI2 Context IRQs. | ||
1851 | + * @enable: Enable/disable CSI2 Context interrupts | ||
1852 | + **/ | ||
1853 | +void isp_csi2_irq_ctx_set(int enable) | ||
1854 | +{ | ||
1855 | + u32 reg; | ||
1856 | + int i; | ||
1857 | + | ||
1858 | + reg = ISPCSI2_CTX_IRQSTATUS_FS_IRQ | ISPCSI2_CTX_IRQSTATUS_FE_IRQ; | ||
1859 | + for (i = 0; i < 8; i++) { | ||
1860 | + isp_reg_writel(reg, OMAP3_ISP_IOMEM_CSI2A, | ||
1861 | + ISPCSI2_CTX_IRQSTATUS(i)); | ||
1862 | + if (enable) { | ||
1863 | + isp_reg_or(OMAP3_ISP_IOMEM_CSI2A, | ||
1864 | + ISPCSI2_CTX_IRQENABLE(i), reg); | ||
1865 | + } else { | ||
1866 | + isp_reg_writel(0, OMAP3_ISP_IOMEM_CSI2A, | ||
1867 | + ISPCSI2_CTX_IRQENABLE(i)); | ||
1868 | + } | ||
1869 | + } | ||
1870 | + | ||
1871 | +} | ||
1872 | +EXPORT_SYMBOL(isp_csi2_irq_ctx_set); | ||
1873 | + | ||
1874 | +/** | ||
1875 | + * isp_csi2_irq_status_set - Enables CSI2 Status IRQs. | ||
1876 | + * @enable: Enable/disable CSI2 Status interrupts | ||
1877 | + **/ | ||
1878 | +void isp_csi2_irq_status_set(int enable) | ||
1879 | +{ | ||
1880 | + u32 reg; | ||
1881 | + reg = ISPCSI2_IRQSTATUS_OCP_ERR_IRQ | | ||
1882 | + ISPCSI2_IRQSTATUS_SHORT_PACKET_IRQ | | ||
1883 | + ISPCSI2_IRQSTATUS_ECC_CORRECTION_IRQ | | ||
1884 | + ISPCSI2_IRQSTATUS_ECC_NO_CORRECTION_IRQ | | ||
1885 | + ISPCSI2_IRQSTATUS_COMPLEXIO2_ERR_IRQ | | ||
1886 | + ISPCSI2_IRQSTATUS_COMPLEXIO1_ERR_IRQ | | ||
1887 | + ISPCSI2_IRQSTATUS_FIFO_OVF_IRQ | | ||
1888 | + ISPCSI2_IRQSTATUS_CONTEXT(0); | ||
1889 | + isp_reg_writel(reg, OMAP3_ISP_IOMEM_CSI2A, ISPCSI2_IRQSTATUS); | ||
1890 | + if (enable) | ||
1891 | + reg |= isp_reg_readl(OMAP3_ISP_IOMEM_CSI2A, ISPCSI2_IRQENABLE); | ||
1892 | + else | ||
1893 | + reg = 0; | ||
1894 | + | ||
1895 | + isp_reg_writel(reg, OMAP3_ISP_IOMEM_CSI2A, ISPCSI2_IRQENABLE); | ||
1896 | +} | ||
1897 | +EXPORT_SYMBOL(isp_csi2_irq_status_set); | ||
1898 | + | ||
1899 | +/** | ||
1900 | + * isp_csi2_irq_status_set - Enables main CSI2 IRQ. | ||
1901 | + * @enable: Enable/disable main CSI2 interrupt | ||
1902 | + **/ | ||
1903 | +void isp_csi2_irq_set(int enable) | ||
1904 | +{ | ||
1905 | + isp_reg_writel(IRQ0STATUS_CSIA_IRQ, OMAP3_ISP_IOMEM_MAIN, | ||
1906 | + ISP_IRQ0STATUS); | ||
1907 | + isp_reg_and_or(OMAP3_ISP_IOMEM_MAIN, ISP_IRQ0ENABLE, | ||
1908 | + ~IRQ0ENABLE_CSIA_IRQ, | ||
1909 | + (enable ? IRQ0ENABLE_CSIA_IRQ : 0)); | ||
1910 | +} | ||
1911 | +EXPORT_SYMBOL(isp_csi2_irq_set); | ||
1912 | + | ||
1913 | +/** | ||
1914 | + * isp_csi2_irq_all_set - Enable/disable CSI2 interrupts. | ||
1915 | + * @enable: 0-Disable, 1-Enable. | ||
1916 | + **/ | ||
1917 | +void isp_csi2_irq_all_set(int enable) | ||
1918 | +{ | ||
1919 | + if (enable) { | ||
1920 | + isp_csi2_irq_complexio1_set(enable); | ||
1921 | + isp_csi2_irq_ctx_set(enable); | ||
1922 | + isp_csi2_irq_status_set(enable); | ||
1923 | + isp_csi2_irq_set(enable); | ||
1924 | + } else { | ||
1925 | + isp_csi2_irq_set(enable); | ||
1926 | + isp_csi2_irq_status_set(enable); | ||
1927 | + isp_csi2_irq_ctx_set(enable); | ||
1928 | + isp_csi2_irq_complexio1_set(enable); | ||
1929 | + } | ||
1930 | + return; | ||
1931 | +} | ||
1932 | +EXPORT_SYMBOL(isp_csi2_irq_all_set); | ||
1933 | + | ||
1934 | +/** | ||
1935 | + * isp_csi2_reset - Resets the CSI2 module. | ||
1936 | + * | ||
1937 | + * Returns 0 if successful, or -EBUSY if power command didn't respond. | ||
1938 | + **/ | ||
1939 | +int isp_csi2_reset(void) | ||
1940 | +{ | ||
1941 | + u32 reg; | ||
1942 | + u8 soft_reset_retries = 0; | ||
1943 | + int i; | ||
1944 | + | ||
1945 | + reg = isp_reg_readl(OMAP3_ISP_IOMEM_CSI2A, ISPCSI2_SYSCONFIG); | ||
1946 | + reg |= ISPCSI2_SYSCONFIG_SOFT_RESET_RESET; | ||
1947 | + isp_reg_writel(reg, OMAP3_ISP_IOMEM_CSI2A, ISPCSI2_SYSCONFIG); | ||
1948 | + | ||
1949 | + do { | ||
1950 | + reg = isp_reg_readl(OMAP3_ISP_IOMEM_CSI2A, ISPCSI2_SYSSTATUS) & | ||
1951 | + ISPCSI2_SYSSTATUS_RESET_DONE_MASK; | ||
1952 | + if (reg == ISPCSI2_SYSSTATUS_RESET_DONE_DONE) | ||
1953 | + break; | ||
1954 | + soft_reset_retries++; | ||
1955 | + if (soft_reset_retries < 5) | ||
1956 | + udelay(100); | ||
1957 | + } while (soft_reset_retries < 5); | ||
1958 | + | ||
1959 | + if (soft_reset_retries == 5) { | ||
1960 | + printk(KERN_ERR "CSI2: Soft reset try count exceeded!\n"); | ||
1961 | + return -EBUSY; | ||
1962 | + } | ||
1963 | + | ||
1964 | + reg = isp_reg_readl(OMAP3_ISP_IOMEM_CSI2A, ISPCSI2_SYSCONFIG); | ||
1965 | + reg &= ~ISPCSI2_SYSCONFIG_MSTANDBY_MODE_MASK; | ||
1966 | + reg |= ISPCSI2_SYSCONFIG_MSTANDBY_MODE_NO; | ||
1967 | + reg &= ~ISPCSI2_SYSCONFIG_AUTO_IDLE_MASK; | ||
1968 | + isp_reg_writel(reg, OMAP3_ISP_IOMEM_CSI2A, ISPCSI2_SYSCONFIG); | ||
1969 | + | ||
1970 | + uses_videoport = false; | ||
1971 | + update_complexio_cfg1 = false; | ||
1972 | + update_phy_cfg0 = false; | ||
1973 | + update_phy_cfg1 = false; | ||
1974 | + for (i = 0; i < 8; i++) { | ||
1975 | + update_ctx_ctrl1[i] = false; | ||
1976 | + update_ctx_ctrl2[i] = false; | ||
1977 | + update_ctx_ctrl3[i] = false; | ||
1978 | + } | ||
1979 | + update_timing = false; | ||
1980 | + update_ctrl = false; | ||
1981 | + | ||
1982 | + isp_csi2_complexio_lanes_get(); | ||
1983 | + isp_csi2_ctrl_get(); | ||
1984 | + isp_csi2_ctx_get_all(); | ||
1985 | + isp_csi2_phy_get(); | ||
1986 | + isp_csi2_timings_get_all(); | ||
1987 | + | ||
1988 | + isp_csi2_complexio_power_autoswitch(true); | ||
1989 | + isp_csi2_complexio_power(ISP_CSI2_POWER_ON); | ||
1990 | + | ||
1991 | + isp_csi2_timings_config_forcerxmode(1, true); | ||
1992 | + isp_csi2_timings_config_stopstate_cnt(1, 0x1FF); | ||
1993 | + isp_csi2_timings_update_all(true); | ||
1994 | + | ||
1995 | + return 0; | ||
1996 | +} | ||
1997 | + | ||
1998 | +/** | ||
1999 | + * isp_csi2_enable - Enables the CSI2 module. | ||
2000 | + * @enable: Enables/disables the CSI2 module. | ||
2001 | + **/ | ||
2002 | +void isp_csi2_enable(int enable) | ||
2003 | +{ | ||
2004 | + if (enable) { | ||
2005 | + isp_csi2_ctx_config_enabled(0, true); | ||
2006 | + isp_csi2_ctx_config_eof_enabled(0, true); | ||
2007 | + isp_csi2_ctx_config_checksum_enabled(0, true); | ||
2008 | + isp_csi2_ctx_update(0, false); | ||
2009 | + | ||
2010 | + isp_csi2_ctrl_config_ecc_enable(true); | ||
2011 | + isp_csi2_ctrl_config_if_enable(true); | ||
2012 | + isp_csi2_ctrl_update(false); | ||
2013 | + } else { | ||
2014 | + isp_csi2_ctx_config_enabled(0, false); | ||
2015 | + isp_csi2_ctx_config_eof_enabled(0, false); | ||
2016 | + isp_csi2_ctx_config_checksum_enabled(0, false); | ||
2017 | + isp_csi2_ctx_update(0, false); | ||
2018 | + | ||
2019 | + isp_csi2_ctrl_config_ecc_enable(false); | ||
2020 | + isp_csi2_ctrl_config_if_enable(false); | ||
2021 | + isp_csi2_ctrl_update(false); | ||
2022 | + } | ||
2023 | +} | ||
2024 | +EXPORT_SYMBOL(isp_csi2_enable); | ||
2025 | + | ||
2026 | +/** | ||
2027 | + * isp_csi2_regdump - Prints CSI2 debug information. | ||
2028 | + **/ | ||
2029 | +void isp_csi2_regdump(void) | ||
2030 | +{ | ||
2031 | + printk(KERN_DEBUG "-------------Register dump-------------\n"); | ||
2032 | + | ||
2033 | + printk(KERN_DEBUG "ISP_CTRL: %x\n", | ||
2034 | + isp_reg_readl(OMAP3_ISP_IOMEM_MAIN, ISP_CTRL)); | ||
2035 | + printk(KERN_DEBUG "ISP_TCTRL_CTRL: %x\n", | ||
2036 | + isp_reg_readl(OMAP3_ISP_IOMEM_MAIN, ISP_TCTRL_CTRL)); | ||
2037 | + | ||
2038 | + printk(KERN_DEBUG "ISPCCDC_SDR_ADDR: %x\n", | ||
2039 | + isp_reg_readl(OMAP3_ISP_IOMEM_CCDC, ISPCCDC_SDR_ADDR)); | ||
2040 | + printk(KERN_DEBUG "ISPCCDC_SYN_MODE: %x\n", | ||
2041 | + isp_reg_readl(OMAP3_ISP_IOMEM_CCDC, ISPCCDC_SYN_MODE)); | ||
2042 | + printk(KERN_DEBUG "ISPCCDC_CFG: %x\n", | ||
2043 | + isp_reg_readl(OMAP3_ISP_IOMEM_CCDC, ISPCCDC_CFG)); | ||
2044 | + printk(KERN_DEBUG "ISPCCDC_FMTCFG: %x\n", | ||
2045 | + isp_reg_readl(OMAP3_ISP_IOMEM_CCDC, ISPCCDC_FMTCFG)); | ||
2046 | + printk(KERN_DEBUG "ISPCCDC_HSIZE_OFF: %x\n", | ||
2047 | + isp_reg_readl(OMAP3_ISP_IOMEM_CCDC, ISPCCDC_HSIZE_OFF)); | ||
2048 | + printk(KERN_DEBUG "ISPCCDC_HORZ_INFO: %x\n", | ||
2049 | + isp_reg_readl(OMAP3_ISP_IOMEM_CCDC, ISPCCDC_HORZ_INFO)); | ||
2050 | + printk(KERN_DEBUG "ISPCCDC_VERT_START: %x\n", | ||
2051 | + isp_reg_readl(OMAP3_ISP_IOMEM_CCDC, | ||
2052 | + ISPCCDC_VERT_START)); | ||
2053 | + printk(KERN_DEBUG "ISPCCDC_VERT_LINES: %x\n", | ||
2054 | + isp_reg_readl(OMAP3_ISP_IOMEM_CCDC, | ||
2055 | + ISPCCDC_VERT_LINES)); | ||
2056 | + | ||
2057 | + printk(KERN_DEBUG "ISPCSI2_COMPLEXIO_CFG1: %x\n", | ||
2058 | + isp_reg_readl(OMAP3_ISP_IOMEM_CSI2A, | ||
2059 | + ISPCSI2_COMPLEXIO_CFG1)); | ||
2060 | + printk(KERN_DEBUG "ISPCSI2_SYSSTATUS: %x\n", | ||
2061 | + isp_reg_readl(OMAP3_ISP_IOMEM_CSI2A, | ||
2062 | + ISPCSI2_SYSSTATUS)); | ||
2063 | + printk(KERN_DEBUG "ISPCSI2_SYSCONFIG: %x\n", | ||
2064 | + isp_reg_readl(OMAP3_ISP_IOMEM_CSI2A, | ||
2065 | + ISPCSI2_SYSCONFIG)); | ||
2066 | + printk(KERN_DEBUG "ISPCSI2_IRQENABLE: %x\n", | ||
2067 | + isp_reg_readl(OMAP3_ISP_IOMEM_CSI2A, | ||
2068 | + ISPCSI2_IRQENABLE)); | ||
2069 | + printk(KERN_DEBUG "ISPCSI2_IRQSTATUS: %x\n", | ||
2070 | + isp_reg_readl(OMAP3_ISP_IOMEM_CSI2A, | ||
2071 | + ISPCSI2_IRQSTATUS)); | ||
2072 | + | ||
2073 | + printk(KERN_DEBUG "ISPCSI2_CTX_IRQENABLE(0): %x\n", | ||
2074 | + isp_reg_readl(OMAP3_ISP_IOMEM_CSI2A, | ||
2075 | + ISPCSI2_CTX_IRQENABLE(0))); | ||
2076 | + printk(KERN_DEBUG "ISPCSI2_CTX_IRQSTATUS(0): %x\n", | ||
2077 | + isp_reg_readl(OMAP3_ISP_IOMEM_CSI2A, | ||
2078 | + ISPCSI2_CTX_IRQSTATUS(0))); | ||
2079 | + printk(KERN_DEBUG "ISPCSI2_TIMING: %x\n", | ||
2080 | + isp_reg_readl(OMAP3_ISP_IOMEM_CSI2A, ISPCSI2_TIMING)); | ||
2081 | + printk(KERN_DEBUG "ISPCSI2PHY_CFG0: %x\n", | ||
2082 | + isp_reg_readl(OMAP3_ISP_IOMEM_CSI2PHY, | ||
2083 | + ISPCSI2PHY_CFG0)); | ||
2084 | + printk(KERN_DEBUG "ISPCSI2PHY_CFG1: %x\n", | ||
2085 | + isp_reg_readl(OMAP3_ISP_IOMEM_CSI2PHY, | ||
2086 | + ISPCSI2PHY_CFG1)); | ||
2087 | + printk(KERN_DEBUG "ISPCSI2_CTX_CTRL1(0): %x\n", | ||
2088 | + isp_reg_readl(OMAP3_ISP_IOMEM_CSI2A, | ||
2089 | + ISPCSI2_CTX_CTRL1(0))); | ||
2090 | + printk(KERN_DEBUG "ISPCSI2_CTX_CTRL2(0): %x\n", | ||
2091 | + isp_reg_readl(OMAP3_ISP_IOMEM_CSI2A, | ||
2092 | + ISPCSI2_CTX_CTRL2(0))); | ||
2093 | + printk(KERN_DEBUG "ISPCSI2_CTX_CTRL3(0): %x\n", | ||
2094 | + isp_reg_readl(OMAP3_ISP_IOMEM_CSI2A, | ||
2095 | + ISPCSI2_CTX_CTRL3(0))); | ||
2096 | + printk(KERN_DEBUG "ISPCSI2_CTX_DAT_OFST(0): %x\n", | ||
2097 | + isp_reg_readl(OMAP3_ISP_IOMEM_CSI2A, | ||
2098 | + ISPCSI2_CTX_DAT_OFST(0))); | ||
2099 | + printk(KERN_DEBUG "ISPCSI2_CTX_DAT_PING_ADDR(0): %x\n", | ||
2100 | + isp_reg_readl(OMAP3_ISP_IOMEM_CSI2A, | ||
2101 | + ISPCSI2_CTX_DAT_PING_ADDR(0))); | ||
2102 | + printk(KERN_DEBUG "ISPCSI2_CTX_DAT_PONG_ADDR(0): %x\n", | ||
2103 | + isp_reg_readl(OMAP3_ISP_IOMEM_CSI2A, | ||
2104 | + ISPCSI2_CTX_DAT_PONG_ADDR(0))); | ||
2105 | + printk(KERN_DEBUG "ISPCSI2_CTRL: %x\n", | ||
2106 | + isp_reg_readl(OMAP3_ISP_IOMEM_CSI2A, ISPCSI2_CTRL)); | ||
2107 | + printk(KERN_DEBUG "---------------------------------------\n"); | ||
2108 | +} | ||
2109 | + | ||
2110 | +/** | ||
2111 | + * isp_csi2_cleanup - Routine for module driver cleanup | ||
2112 | + **/ | ||
2113 | +void isp_csi2_cleanup(void) | ||
2114 | +{ | ||
2115 | + return; | ||
2116 | +} | ||
2117 | + | ||
2118 | +/** | ||
2119 | + * isp_csi2_init - Routine for module driver init | ||
2120 | + **/ | ||
2121 | +int __init isp_csi2_init(void) | ||
2122 | +{ | ||
2123 | + int i; | ||
2124 | + | ||
2125 | + update_complexio_cfg1 = false; | ||
2126 | + update_phy_cfg0 = false; | ||
2127 | + update_phy_cfg1 = false; | ||
2128 | + for (i = 0; i < 8; i++) { | ||
2129 | + update_ctx_ctrl1[i] = false; | ||
2130 | + update_ctx_ctrl2[i] = false; | ||
2131 | + update_ctx_ctrl3[i] = false; | ||
2132 | + } | ||
2133 | + update_timing = false; | ||
2134 | + update_ctrl = false; | ||
2135 | + | ||
2136 | + memset(¤t_csi2_cfg, 0, sizeof(current_csi2_cfg)); | ||
2137 | + memset(¤t_csi2_cfg_update, 0, sizeof(current_csi2_cfg_update)); | ||
2138 | + return 0; | ||
2139 | +} | ||
2140 | + | ||
2141 | +MODULE_AUTHOR("Texas Instruments"); | ||
2142 | +MODULE_DESCRIPTION("ISP CSI2 Receiver Module"); | ||
2143 | +MODULE_LICENSE("GPL"); | ||
2144 | diff --git a/drivers/media/video/isp/ispcsi2.h b/drivers/media/video/isp/ispcsi2.h | ||
2145 | new file mode 100644 | ||
2146 | index 0000000..4582c96 | ||
2147 | --- /dev/null | ||
2148 | +++ b/drivers/media/video/isp/ispcsi2.h | ||
2149 | @@ -0,0 +1,232 @@ | ||
2150 | +/* | ||
2151 | + * ispcsi2.h | ||
2152 | + * | ||
2153 | + * Copyright (C) 2009 Texas Instruments. | ||
2154 | + * | ||
2155 | + * Contributors: | ||
2156 | + * Sergio Aguirre <saaguirre@ti.com> | ||
2157 | + * Dominic Curran <dcurran@ti.com> | ||
2158 | + * | ||
2159 | + * This package is free software; you can redistribute it and/or modify | ||
2160 | + * it under the terms of the GNU General Public License version 2 as | ||
2161 | + * published by the Free Software Foundation. | ||
2162 | + * | ||
2163 | + * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR | ||
2164 | + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED | ||
2165 | + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. | ||
2166 | + */ | ||
2167 | + | ||
2168 | +#ifndef OMAP_ISP_CSI2_API_H | ||
2169 | +#define OMAP_ISP_CSI2_API_H | ||
2170 | +#include <linux/videodev2.h> | ||
2171 | + | ||
2172 | +enum isp_csi2_irqevents { | ||
2173 | + OCP_ERR_IRQ = 0x4000, | ||
2174 | + SHORT_PACKET_IRQ = 0x2000, | ||
2175 | + ECC_CORRECTION_IRQ = 0x1000, | ||
2176 | + ECC_NO_CORRECTION_IRQ = 0x800, | ||
2177 | + COMPLEXIO2_ERR_IRQ = 0x400, | ||
2178 | + COMPLEXIO1_ERR_IRQ = 0x200, | ||
2179 | + FIFO_OVF_IRQ = 0x100, | ||
2180 | + CONTEXT7 = 0x80, | ||
2181 | + CONTEXT6 = 0x40, | ||
2182 | + CONTEXT5 = 0x20, | ||
2183 | + CONTEXT4 = 0x10, | ||
2184 | + CONTEXT3 = 0x8, | ||
2185 | + CONTEXT2 = 0x4, | ||
2186 | + CONTEXT1 = 0x2, | ||
2187 | + CONTEXT0 = 0x1, | ||
2188 | +}; | ||
2189 | + | ||
2190 | +enum isp_csi2_ctx_irqevents { | ||
2191 | + CTX_ECC_CORRECTION = 0x100, | ||
2192 | + CTX_LINE_NUMBER = 0x80, | ||
2193 | + CTX_FRAME_NUMBER = 0x40, | ||
2194 | + CTX_CS = 0x20, | ||
2195 | + CTX_LE = 0x8, | ||
2196 | + CTX_LS = 0x4, | ||
2197 | + CTX_FE = 0x2, | ||
2198 | + CTX_FS = 0x1, | ||
2199 | +}; | ||
2200 | + | ||
2201 | +enum isp_csi2_power_cmds { | ||
2202 | + ISP_CSI2_POWER_OFF, | ||
2203 | + ISP_CSI2_POWER_ON, | ||
2204 | + ISP_CSI2_POWER_ULPW, | ||
2205 | +}; | ||
2206 | + | ||
2207 | +enum isp_csi2_frame_mode { | ||
2208 | + ISP_CSI2_FRAME_IMMEDIATE, | ||
2209 | + ISP_CSI2_FRAME_AFTERFEC, | ||
2210 | +}; | ||
2211 | + | ||
2212 | +struct csi2_lanecfg { | ||
2213 | + u8 pos; | ||
2214 | + u8 pol; | ||
2215 | +}; | ||
2216 | + | ||
2217 | +struct isp_csi2_lanes_cfg { | ||
2218 | + struct csi2_lanecfg data[4]; | ||
2219 | + struct csi2_lanecfg clk; | ||
2220 | +}; | ||
2221 | + | ||
2222 | +struct isp_csi2_lanes_cfg_update { | ||
2223 | + bool data[4]; | ||
2224 | + bool clk; | ||
2225 | +}; | ||
2226 | + | ||
2227 | +struct isp_csi2_phy_cfg { | ||
2228 | + u8 ths_term; | ||
2229 | + u8 ths_settle; | ||
2230 | + u8 tclk_term; | ||
2231 | + unsigned tclk_miss:1; | ||
2232 | + u8 tclk_settle; | ||
2233 | +}; | ||
2234 | + | ||
2235 | +struct isp_csi2_phy_cfg_update { | ||
2236 | + bool ths_term; | ||
2237 | + bool ths_settle; | ||
2238 | + bool tclk_term; | ||
2239 | + bool tclk_miss; | ||
2240 | + bool tclk_settle; | ||
2241 | +}; | ||
2242 | + | ||
2243 | +struct isp_csi2_ctx_cfg { | ||
2244 | + u8 virtual_id; | ||
2245 | + u8 frame_count; | ||
2246 | + struct v4l2_pix_format format; | ||
2247 | + u16 alpha; | ||
2248 | + u16 data_offset; | ||
2249 | + u32 ping_addr; | ||
2250 | + u32 pong_addr; | ||
2251 | + bool eof_enabled; | ||
2252 | + bool eol_enabled; | ||
2253 | + bool checksum_enabled; | ||
2254 | + bool enabled; | ||
2255 | +}; | ||
2256 | + | ||
2257 | +struct isp_csi2_ctx_cfg_update { | ||
2258 | + bool virtual_id; | ||
2259 | + bool frame_count; | ||
2260 | + bool format; | ||
2261 | + bool alpha; | ||
2262 | + bool data_offset; | ||
2263 | + bool ping_addr; | ||
2264 | + bool pong_addr; | ||
2265 | + bool eof_enabled; | ||
2266 | + bool eol_enabled; | ||
2267 | + bool checksum_enabled; | ||
2268 | + bool enabled; | ||
2269 | +}; | ||
2270 | + | ||
2271 | +struct isp_csi2_timings_cfg { | ||
2272 | + bool force_rx_mode; | ||
2273 | + bool stop_state_16x; | ||
2274 | + bool stop_state_4x; | ||
2275 | + u16 stop_state_counter; | ||
2276 | +}; | ||
2277 | + | ||
2278 | +struct isp_csi2_timings_cfg_update { | ||
2279 | + bool force_rx_mode; | ||
2280 | + bool stop_state_16x; | ||
2281 | + bool stop_state_4x; | ||
2282 | + bool stop_state_counter; | ||
2283 | +}; | ||
2284 | + | ||
2285 | +struct isp_csi2_ctrl_cfg { | ||
2286 | + bool vp_clk_enable; | ||
2287 | + bool vp_only_enable; | ||
2288 | + u8 vp_out_ctrl; | ||
2289 | + bool debug_enable; | ||
2290 | + u8 burst_size; | ||
2291 | + enum isp_csi2_frame_mode frame_mode; | ||
2292 | + bool ecc_enable; | ||
2293 | + bool secure_mode; | ||
2294 | + bool if_enable; | ||
2295 | +}; | ||
2296 | + | ||
2297 | +struct isp_csi2_ctrl_cfg_update { | ||
2298 | + bool vp_clk_enable; | ||
2299 | + bool vp_only_enable; | ||
2300 | + bool vp_out_ctrl; | ||
2301 | + bool debug_enable; | ||
2302 | + bool burst_size; | ||
2303 | + bool frame_mode; | ||
2304 | + bool ecc_enable; | ||
2305 | + bool secure_mode; | ||
2306 | + bool if_enable; | ||
2307 | +}; | ||
2308 | + | ||
2309 | +struct isp_csi2_cfg { | ||
2310 | + struct isp_csi2_lanes_cfg lanes; | ||
2311 | + struct isp_csi2_phy_cfg phy; | ||
2312 | + struct isp_csi2_ctx_cfg contexts[8]; | ||
2313 | + struct isp_csi2_timings_cfg timings[2]; | ||
2314 | + struct isp_csi2_ctrl_cfg ctrl; | ||
2315 | +}; | ||
2316 | + | ||
2317 | +struct isp_csi2_cfg_update { | ||
2318 | + struct isp_csi2_lanes_cfg_update lanes; | ||
2319 | + struct isp_csi2_phy_cfg_update phy; | ||
2320 | + struct isp_csi2_ctx_cfg_update contexts[8]; | ||
2321 | + struct isp_csi2_timings_cfg_update timings[2]; | ||
2322 | + struct isp_csi2_ctrl_cfg_update ctrl; | ||
2323 | +}; | ||
2324 | + | ||
2325 | +int isp_csi2_complexio_lanes_config(struct isp_csi2_lanes_cfg *reqcfg); | ||
2326 | +int isp_csi2_complexio_lanes_update(bool force_update); | ||
2327 | +int isp_csi2_complexio_lanes_get(void); | ||
2328 | +int isp_csi2_complexio_power_autoswitch(bool enable); | ||
2329 | +int isp_csi2_complexio_power(enum isp_csi2_power_cmds power_cmd); | ||
2330 | +int isp_csi2_ctrl_config_frame_mode(enum isp_csi2_frame_mode frame_mode); | ||
2331 | +int isp_csi2_ctrl_config_vp_clk_enable(bool vp_clk_enable); | ||
2332 | +int isp_csi2_ctrl_config_vp_only_enable(bool vp_only_enable); | ||
2333 | +int isp_csi2_ctrl_config_debug_enable(bool debug_enable); | ||
2334 | +int isp_csi2_ctrl_config_burst_size(u8 burst_size); | ||
2335 | +int isp_csi2_ctrl_config_ecc_enable(bool ecc_enable); | ||
2336 | +int isp_csi2_ctrl_config_secure_mode(bool secure_mode); | ||
2337 | +int isp_csi2_ctrl_config_if_enable(bool if_enable); | ||
2338 | +int isp_csi2_ctrl_config_vp_out_ctrl(u8 vp_out_ctrl); | ||
2339 | +int isp_csi2_ctrl_update(bool force_update); | ||
2340 | +int isp_csi2_ctrl_get(void); | ||
2341 | +int isp_csi2_ctx_config_virtual_id(u8 ctxnum, u8 virtual_id); | ||
2342 | +int isp_csi2_ctx_config_frame_count(u8 ctxnum, u8 frame_count); | ||
2343 | +int isp_csi2_ctx_config_format(u8 ctxnum, u32 pixformat); | ||
2344 | +int isp_csi2_ctx_config_alpha(u8 ctxnum, u16 alpha); | ||
2345 | +int isp_csi2_ctx_config_data_offset(u8 ctxnum, u16 data_offset); | ||
2346 | +int isp_csi2_ctx_config_ping_addr(u8 ctxnum, u32 ping_addr); | ||
2347 | +int isp_csi2_ctx_config_pong_addr(u8 ctxnum, u32 pong_addr); | ||
2348 | +int isp_csi2_ctx_config_eof_enabled(u8 ctxnum, bool eof_enabled); | ||
2349 | +int isp_csi2_ctx_config_eol_enabled(u8 ctxnum, bool eol_enabled); | ||
2350 | +int isp_csi2_ctx_config_checksum_enabled(u8 ctxnum, bool checksum_enabled); | ||
2351 | +int isp_csi2_ctx_config_enabled(u8 ctxnum, bool enabled); | ||
2352 | +int isp_csi2_ctx_update(u8 ctxnum, bool force_update); | ||
2353 | +int isp_csi2_ctx_get(u8 ctxnum); | ||
2354 | +int isp_csi2_ctx_update_all(bool force_update); | ||
2355 | +int isp_csi2_ctx_get_all(void); | ||
2356 | +int isp_csi2_phy_config(struct isp_csi2_phy_cfg *desiredphyconfig); | ||
2357 | +int isp_csi2_calc_phy_cfg0(u32 mipiclk, u32 lbound_hs_settle, | ||
2358 | + u32 ubound_hs_settle); | ||
2359 | +int isp_csi2_phy_update(bool force_update); | ||
2360 | +int isp_csi2_phy_get(void); | ||
2361 | +int isp_csi2_timings_config_forcerxmode(u8 io, bool force_rx_mode); | ||
2362 | +int isp_csi2_timings_config_stopstate_16x(u8 io, bool stop_state_16x); | ||
2363 | +int isp_csi2_timings_config_stopstate_4x(u8 io, bool stop_state_4x); | ||
2364 | +int isp_csi2_timings_config_stopstate_cnt(u8 io, u16 stop_state_counter); | ||
2365 | +int isp_csi2_timings_update(u8 io, bool force_update); | ||
2366 | +int isp_csi2_timings_get(u8 io); | ||
2367 | +int isp_csi2_timings_update_all(bool force_update); | ||
2368 | +int isp_csi2_timings_get_all(void); | ||
2369 | +void isp_csi2_irq_complexio1_set(int enable); | ||
2370 | +void isp_csi2_irq_ctx_set(int enable); | ||
2371 | +void isp_csi2_irq_status_set(int enable); | ||
2372 | +void isp_csi2_irq_set(int enable); | ||
2373 | +void isp_csi2_irq_all_set(int enable); | ||
2374 | + | ||
2375 | +void isp_csi2_isr(void); | ||
2376 | +int isp_csi2_reset(void); | ||
2377 | +void isp_csi2_enable(int enable); | ||
2378 | +void isp_csi2_regdump(void); | ||
2379 | + | ||
2380 | +#endif /* OMAP_ISP_CSI2_H */ | ||
2381 | + | ||
2382 | -- | ||
2383 | 1.5.6.5 | ||
2384 | |||