Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
awilliam
GitHub Repository: awilliam/linux-vfio
Path: blob/master/drivers/media/video/davinci/isif.c
17621 views
1
/*
2
* Copyright (C) 2008-2009 Texas Instruments Inc
3
*
4
* This program is free software; you can redistribute it and/or modify
5
* it under the terms of the GNU General Public License as published by
6
* the Free Software Foundation; either version 2 of the License, or
7
* (at your option) any later version.
8
*
9
* This program is distributed in the hope that it will be useful,
10
* but WITHOUT ANY WARRANTY; without even the implied warranty of
11
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
* GNU General Public License for more details.
13
*
14
* You should have received a copy of the GNU General Public License
15
* along with this program; if not, write to the Free Software
16
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17
*
18
* Image Sensor Interface (ISIF) driver
19
*
20
* This driver is for configuring the ISIF IP available on DM365 or any other
21
* TI SoCs. This is used for capturing yuv or bayer video or image data
22
* from a decoder or sensor. This IP is similar to the CCDC IP on DM355
23
* and DM6446, but with enhanced or additional ip blocks. The driver
24
* configures the ISIF upon commands from the vpfe bridge driver through
25
* ccdc_hw_device interface.
26
*
27
* TODO: 1) Raw bayer parameter settings and bayer capture
28
* 2) Add support for control ioctl
29
*/
30
#include <linux/delay.h>
31
#include <linux/platform_device.h>
32
#include <linux/uaccess.h>
33
#include <linux/io.h>
34
#include <linux/videodev2.h>
35
#include <linux/clk.h>
36
#include <linux/err.h>
37
38
#include <mach/mux.h>
39
40
#include <media/davinci/isif.h>
41
#include <media/davinci/vpss.h>
42
43
#include "isif_regs.h"
44
#include "ccdc_hw_device.h"
45
46
/* Defaults for module configuration parameters */
47
static struct isif_config_params_raw isif_config_defaults = {
48
.linearize = {
49
.en = 0,
50
.corr_shft = ISIF_NO_SHIFT,
51
.scale_fact = {1, 0},
52
},
53
.df_csc = {
54
.df_or_csc = 0,
55
.csc = {
56
.en = 0,
57
},
58
},
59
.dfc = {
60
.en = 0,
61
},
62
.bclamp = {
63
.en = 0,
64
},
65
.gain_offset = {
66
.gain = {
67
.r_ye = {1, 0},
68
.gr_cy = {1, 0},
69
.gb_g = {1, 0},
70
.b_mg = {1, 0},
71
},
72
},
73
.culling = {
74
.hcpat_odd = 0xff,
75
.hcpat_even = 0xff,
76
.vcpat = 0xff,
77
},
78
.compress = {
79
.alg = ISIF_ALAW,
80
},
81
};
82
83
/* ISIF operation configuration */
84
static struct isif_oper_config {
85
struct device *dev;
86
enum vpfe_hw_if_type if_type;
87
struct isif_ycbcr_config ycbcr;
88
struct isif_params_raw bayer;
89
enum isif_data_pack data_pack;
90
/* Master clock */
91
struct clk *mclk;
92
/* ISIF base address */
93
void __iomem *base_addr;
94
/* ISIF Linear Table 0 */
95
void __iomem *linear_tbl0_addr;
96
/* ISIF Linear Table 1 */
97
void __iomem *linear_tbl1_addr;
98
} isif_cfg = {
99
.ycbcr = {
100
.pix_fmt = CCDC_PIXFMT_YCBCR_8BIT,
101
.frm_fmt = CCDC_FRMFMT_INTERLACED,
102
.win = ISIF_WIN_NTSC,
103
.fid_pol = VPFE_PINPOL_POSITIVE,
104
.vd_pol = VPFE_PINPOL_POSITIVE,
105
.hd_pol = VPFE_PINPOL_POSITIVE,
106
.pix_order = CCDC_PIXORDER_CBYCRY,
107
.buf_type = CCDC_BUFTYPE_FLD_INTERLEAVED,
108
},
109
.bayer = {
110
.pix_fmt = CCDC_PIXFMT_RAW,
111
.frm_fmt = CCDC_FRMFMT_PROGRESSIVE,
112
.win = ISIF_WIN_VGA,
113
.fid_pol = VPFE_PINPOL_POSITIVE,
114
.vd_pol = VPFE_PINPOL_POSITIVE,
115
.hd_pol = VPFE_PINPOL_POSITIVE,
116
.gain = {
117
.r_ye = {1, 0},
118
.gr_cy = {1, 0},
119
.gb_g = {1, 0},
120
.b_mg = {1, 0},
121
},
122
.cfa_pat = ISIF_CFA_PAT_MOSAIC,
123
.data_msb = ISIF_BIT_MSB_11,
124
.config_params = {
125
.data_shift = ISIF_NO_SHIFT,
126
.col_pat_field0 = {
127
.olop = ISIF_GREEN_BLUE,
128
.olep = ISIF_BLUE,
129
.elop = ISIF_RED,
130
.elep = ISIF_GREEN_RED,
131
},
132
.col_pat_field1 = {
133
.olop = ISIF_GREEN_BLUE,
134
.olep = ISIF_BLUE,
135
.elop = ISIF_RED,
136
.elep = ISIF_GREEN_RED,
137
},
138
.test_pat_gen = 0,
139
},
140
},
141
.data_pack = ISIF_DATA_PACK8,
142
};
143
144
/* Raw Bayer formats */
145
static const u32 isif_raw_bayer_pix_formats[] = {
146
V4L2_PIX_FMT_SBGGR8, V4L2_PIX_FMT_SBGGR16};
147
148
/* Raw YUV formats */
149
static const u32 isif_raw_yuv_pix_formats[] = {
150
V4L2_PIX_FMT_UYVY, V4L2_PIX_FMT_YUYV};
151
152
/* register access routines */
153
static inline u32 regr(u32 offset)
154
{
155
return __raw_readl(isif_cfg.base_addr + offset);
156
}
157
158
static inline void regw(u32 val, u32 offset)
159
{
160
__raw_writel(val, isif_cfg.base_addr + offset);
161
}
162
163
/* reg_modify() - read, modify and write register */
164
static inline u32 reg_modify(u32 mask, u32 val, u32 offset)
165
{
166
u32 new_val = (regr(offset) & ~mask) | (val & mask);
167
168
regw(new_val, offset);
169
return new_val;
170
}
171
172
static inline void regw_lin_tbl(u32 val, u32 offset, int i)
173
{
174
if (!i)
175
__raw_writel(val, isif_cfg.linear_tbl0_addr + offset);
176
else
177
__raw_writel(val, isif_cfg.linear_tbl1_addr + offset);
178
}
179
180
static void isif_disable_all_modules(void)
181
{
182
/* disable BC */
183
regw(0, CLAMPCFG);
184
/* disable vdfc */
185
regw(0, DFCCTL);
186
/* disable CSC */
187
regw(0, CSCCTL);
188
/* disable linearization */
189
regw(0, LINCFG0);
190
/* disable other modules here as they are supported */
191
}
192
193
static void isif_enable(int en)
194
{
195
if (!en) {
196
/* Before disable isif, disable all ISIF modules */
197
isif_disable_all_modules();
198
/*
199
* wait for next VD. Assume lowest scan rate is 12 Hz. So
200
* 100 msec delay is good enough
201
*/
202
msleep(100);
203
}
204
reg_modify(ISIF_SYNCEN_VDHDEN_MASK, en, SYNCEN);
205
}
206
207
static void isif_enable_output_to_sdram(int en)
208
{
209
reg_modify(ISIF_SYNCEN_WEN_MASK, en << ISIF_SYNCEN_WEN_SHIFT, SYNCEN);
210
}
211
212
static void isif_config_culling(struct isif_cul *cul)
213
{
214
u32 val;
215
216
/* Horizontal pattern */
217
val = (cul->hcpat_even << CULL_PAT_EVEN_LINE_SHIFT) | cul->hcpat_odd;
218
regw(val, CULH);
219
220
/* vertical pattern */
221
regw(cul->vcpat, CULV);
222
223
/* LPF */
224
reg_modify(ISIF_LPF_MASK << ISIF_LPF_SHIFT,
225
cul->en_lpf << ISIF_LPF_SHIFT, MODESET);
226
}
227
228
static void isif_config_gain_offset(void)
229
{
230
struct isif_gain_offsets_adj *gain_off_p =
231
&isif_cfg.bayer.config_params.gain_offset;
232
u32 val;
233
234
val = (!!gain_off_p->gain_sdram_en << GAIN_SDRAM_EN_SHIFT) |
235
(!!gain_off_p->gain_ipipe_en << GAIN_IPIPE_EN_SHIFT) |
236
(!!gain_off_p->gain_h3a_en << GAIN_H3A_EN_SHIFT) |
237
(!!gain_off_p->offset_sdram_en << OFST_SDRAM_EN_SHIFT) |
238
(!!gain_off_p->offset_ipipe_en << OFST_IPIPE_EN_SHIFT) |
239
(!!gain_off_p->offset_h3a_en << OFST_H3A_EN_SHIFT);
240
241
reg_modify(GAIN_OFFSET_EN_MASK, val, CGAMMAWD);
242
243
val = (gain_off_p->gain.r_ye.integer << GAIN_INTEGER_SHIFT) |
244
gain_off_p->gain.r_ye.decimal;
245
regw(val, CRGAIN);
246
247
val = (gain_off_p->gain.gr_cy.integer << GAIN_INTEGER_SHIFT) |
248
gain_off_p->gain.gr_cy.decimal;
249
regw(val, CGRGAIN);
250
251
val = (gain_off_p->gain.gb_g.integer << GAIN_INTEGER_SHIFT) |
252
gain_off_p->gain.gb_g.decimal;
253
regw(val, CGBGAIN);
254
255
val = (gain_off_p->gain.b_mg.integer << GAIN_INTEGER_SHIFT) |
256
gain_off_p->gain.b_mg.decimal;
257
regw(val, CBGAIN);
258
259
regw(gain_off_p->offset, COFSTA);
260
}
261
262
static void isif_restore_defaults(void)
263
{
264
enum vpss_ccdc_source_sel source = VPSS_CCDCIN;
265
266
dev_dbg(isif_cfg.dev, "\nstarting isif_restore_defaults...");
267
isif_cfg.bayer.config_params = isif_config_defaults;
268
/* Enable clock to ISIF, IPIPEIF and BL */
269
vpss_enable_clock(VPSS_CCDC_CLOCK, 1);
270
vpss_enable_clock(VPSS_IPIPEIF_CLOCK, 1);
271
vpss_enable_clock(VPSS_BL_CLOCK, 1);
272
/* Set default offset and gain */
273
isif_config_gain_offset();
274
vpss_select_ccdc_source(source);
275
dev_dbg(isif_cfg.dev, "\nEnd of isif_restore_defaults...");
276
}
277
278
static int isif_open(struct device *device)
279
{
280
isif_restore_defaults();
281
return 0;
282
}
283
284
/* This function will configure the window size to be capture in ISIF reg */
285
static void isif_setwin(struct v4l2_rect *image_win,
286
enum ccdc_frmfmt frm_fmt, int ppc)
287
{
288
int horz_start, horz_nr_pixels;
289
int vert_start, vert_nr_lines;
290
int mid_img = 0;
291
292
dev_dbg(isif_cfg.dev, "\nStarting isif_setwin...");
293
/*
294
* ppc - per pixel count. indicates how many pixels per cell
295
* output to SDRAM. example, for ycbcr, it is one y and one c, so 2.
296
* raw capture this is 1
297
*/
298
horz_start = image_win->left << (ppc - 1);
299
horz_nr_pixels = ((image_win->width) << (ppc - 1)) - 1;
300
301
/* Writing the horizontal info into the registers */
302
regw(horz_start & START_PX_HOR_MASK, SPH);
303
regw(horz_nr_pixels & NUM_PX_HOR_MASK, LNH);
304
vert_start = image_win->top;
305
306
if (frm_fmt == CCDC_FRMFMT_INTERLACED) {
307
vert_nr_lines = (image_win->height >> 1) - 1;
308
vert_start >>= 1;
309
/* To account for VD since line 0 doesn't have any data */
310
vert_start += 1;
311
} else {
312
/* To account for VD since line 0 doesn't have any data */
313
vert_start += 1;
314
vert_nr_lines = image_win->height - 1;
315
/* configure VDINT0 and VDINT1 */
316
mid_img = vert_start + (image_win->height / 2);
317
regw(mid_img, VDINT1);
318
}
319
320
regw(0, VDINT0);
321
regw(vert_start & START_VER_ONE_MASK, SLV0);
322
regw(vert_start & START_VER_TWO_MASK, SLV1);
323
regw(vert_nr_lines & NUM_LINES_VER, LNV);
324
}
325
326
static void isif_config_bclamp(struct isif_black_clamp *bc)
327
{
328
u32 val;
329
330
/*
331
* DC Offset is always added to image data irrespective of bc enable
332
* status
333
*/
334
regw(bc->dc_offset, CLDCOFST);
335
336
if (bc->en) {
337
val = bc->bc_mode_color << ISIF_BC_MODE_COLOR_SHIFT;
338
339
/* Enable BC and horizontal clamp caculation paramaters */
340
val = val | 1 | (bc->horz.mode << ISIF_HORZ_BC_MODE_SHIFT);
341
342
regw(val, CLAMPCFG);
343
344
if (bc->horz.mode != ISIF_HORZ_BC_DISABLE) {
345
/*
346
* Window count for calculation
347
* Base window selection
348
* pixel limit
349
* Horizontal size of window
350
* vertical size of the window
351
* Horizontal start position of the window
352
* Vertical start position of the window
353
*/
354
val = bc->horz.win_count_calc |
355
((!!bc->horz.base_win_sel_calc) <<
356
ISIF_HORZ_BC_WIN_SEL_SHIFT) |
357
((!!bc->horz.clamp_pix_limit) <<
358
ISIF_HORZ_BC_PIX_LIMIT_SHIFT) |
359
(bc->horz.win_h_sz_calc <<
360
ISIF_HORZ_BC_WIN_H_SIZE_SHIFT) |
361
(bc->horz.win_v_sz_calc <<
362
ISIF_HORZ_BC_WIN_V_SIZE_SHIFT);
363
regw(val, CLHWIN0);
364
365
regw(bc->horz.win_start_h_calc, CLHWIN1);
366
regw(bc->horz.win_start_v_calc, CLHWIN2);
367
}
368
369
/* vertical clamp caculation paramaters */
370
371
/* Reset clamp value sel for previous line */
372
val |=
373
(bc->vert.reset_val_sel << ISIF_VERT_BC_RST_VAL_SEL_SHIFT) |
374
(bc->vert.line_ave_coef << ISIF_VERT_BC_LINE_AVE_COEF_SHIFT);
375
regw(val, CLVWIN0);
376
377
/* Optical Black horizontal start position */
378
regw(bc->vert.ob_start_h, CLVWIN1);
379
/* Optical Black vertical start position */
380
regw(bc->vert.ob_start_v, CLVWIN2);
381
/* Optical Black vertical size for calculation */
382
regw(bc->vert.ob_v_sz_calc, CLVWIN3);
383
/* Vertical start position for BC subtraction */
384
regw(bc->vert_start_sub, CLSV);
385
}
386
}
387
388
static void isif_config_linearization(struct isif_linearize *linearize)
389
{
390
u32 val, i;
391
392
if (!linearize->en) {
393
regw(0, LINCFG0);
394
return;
395
}
396
397
/* shift value for correction & enable linearization (set lsb) */
398
val = (linearize->corr_shft << ISIF_LIN_CORRSFT_SHIFT) | 1;
399
regw(val, LINCFG0);
400
401
/* Scale factor */
402
val = ((!!linearize->scale_fact.integer) <<
403
ISIF_LIN_SCALE_FACT_INTEG_SHIFT) |
404
linearize->scale_fact.decimal;
405
regw(val, LINCFG1);
406
407
for (i = 0; i < ISIF_LINEAR_TAB_SIZE; i++) {
408
if (i % 2)
409
regw_lin_tbl(linearize->table[i], ((i >> 1) << 2), 1);
410
else
411
regw_lin_tbl(linearize->table[i], ((i >> 1) << 2), 0);
412
}
413
}
414
415
static int isif_config_dfc(struct isif_dfc *vdfc)
416
{
417
/* initialize retries to loop for max ~ 250 usec */
418
u32 val, count, retries = loops_per_jiffy / (4000/HZ);
419
int i;
420
421
if (!vdfc->en)
422
return 0;
423
424
/* Correction mode */
425
val = (vdfc->corr_mode << ISIF_VDFC_CORR_MOD_SHIFT);
426
427
/* Correct whole line or partial */
428
if (vdfc->corr_whole_line)
429
val |= 1 << ISIF_VDFC_CORR_WHOLE_LN_SHIFT;
430
431
/* level shift value */
432
val |= vdfc->def_level_shift << ISIF_VDFC_LEVEL_SHFT_SHIFT;
433
434
regw(val, DFCCTL);
435
436
/* Defect saturation level */
437
regw(vdfc->def_sat_level, VDFSATLV);
438
439
regw(vdfc->table[0].pos_vert, DFCMEM0);
440
regw(vdfc->table[0].pos_horz, DFCMEM1);
441
if (vdfc->corr_mode == ISIF_VDFC_NORMAL ||
442
vdfc->corr_mode == ISIF_VDFC_HORZ_INTERPOL_IF_SAT) {
443
regw(vdfc->table[0].level_at_pos, DFCMEM2);
444
regw(vdfc->table[0].level_up_pixels, DFCMEM3);
445
regw(vdfc->table[0].level_low_pixels, DFCMEM4);
446
}
447
448
/* set DFCMARST and set DFCMWR */
449
val = regr(DFCMEMCTL) | (1 << ISIF_DFCMEMCTL_DFCMARST_SHIFT) | 1;
450
regw(val, DFCMEMCTL);
451
452
count = retries;
453
while (count && (regr(DFCMEMCTL) & 0x1))
454
count--;
455
456
if (!count) {
457
dev_dbg(isif_cfg.dev, "defect table write timeout !!!\n");
458
return -1;
459
}
460
461
for (i = 1; i < vdfc->num_vdefects; i++) {
462
regw(vdfc->table[i].pos_vert, DFCMEM0);
463
regw(vdfc->table[i].pos_horz, DFCMEM1);
464
if (vdfc->corr_mode == ISIF_VDFC_NORMAL ||
465
vdfc->corr_mode == ISIF_VDFC_HORZ_INTERPOL_IF_SAT) {
466
regw(vdfc->table[i].level_at_pos, DFCMEM2);
467
regw(vdfc->table[i].level_up_pixels, DFCMEM3);
468
regw(vdfc->table[i].level_low_pixels, DFCMEM4);
469
}
470
val = regr(DFCMEMCTL);
471
/* clear DFCMARST and set DFCMWR */
472
val &= ~BIT(ISIF_DFCMEMCTL_DFCMARST_SHIFT);
473
val |= 1;
474
regw(val, DFCMEMCTL);
475
476
count = retries;
477
while (count && (regr(DFCMEMCTL) & 0x1))
478
count--;
479
480
if (!count) {
481
dev_err(isif_cfg.dev,
482
"defect table write timeout !!!\n");
483
return -1;
484
}
485
}
486
if (vdfc->num_vdefects < ISIF_VDFC_TABLE_SIZE) {
487
/* Extra cycle needed */
488
regw(0, DFCMEM0);
489
regw(0x1FFF, DFCMEM1);
490
regw(1, DFCMEMCTL);
491
}
492
493
/* enable VDFC */
494
reg_modify((1 << ISIF_VDFC_EN_SHIFT), (1 << ISIF_VDFC_EN_SHIFT),
495
DFCCTL);
496
return 0;
497
}
498
499
static void isif_config_csc(struct isif_df_csc *df_csc)
500
{
501
u32 val1 = 0, val2 = 0, i;
502
503
if (!df_csc->csc.en) {
504
regw(0, CSCCTL);
505
return;
506
}
507
for (i = 0; i < ISIF_CSC_NUM_COEFF; i++) {
508
if ((i % 2) == 0) {
509
/* CSCM - LSB */
510
val1 = (df_csc->csc.coeff[i].integer <<
511
ISIF_CSC_COEF_INTEG_SHIFT) |
512
df_csc->csc.coeff[i].decimal;
513
} else {
514
515
/* CSCM - MSB */
516
val2 = (df_csc->csc.coeff[i].integer <<
517
ISIF_CSC_COEF_INTEG_SHIFT) |
518
df_csc->csc.coeff[i].decimal;
519
val2 <<= ISIF_CSCM_MSB_SHIFT;
520
val2 |= val1;
521
regw(val2, (CSCM0 + ((i - 1) << 1)));
522
}
523
}
524
525
/* program the active area */
526
regw(df_csc->start_pix, FMTSPH);
527
/*
528
* one extra pixel as required for CSC. Actually number of
529
* pixel - 1 should be configured in this register. So we
530
* need to subtract 1 before writing to FMTSPH, but we will
531
* not do this since csc requires one extra pixel
532
*/
533
regw(df_csc->num_pixels, FMTLNH);
534
regw(df_csc->start_line, FMTSLV);
535
/*
536
* one extra line as required for CSC. See reason documented for
537
* num_pixels
538
*/
539
regw(df_csc->num_lines, FMTLNV);
540
541
/* Enable CSC */
542
regw(1, CSCCTL);
543
}
544
545
static int isif_config_raw(void)
546
{
547
struct isif_params_raw *params = &isif_cfg.bayer;
548
struct isif_config_params_raw *module_params =
549
&isif_cfg.bayer.config_params;
550
struct vpss_pg_frame_size frame_size;
551
struct vpss_sync_pol sync;
552
u32 val;
553
554
dev_dbg(isif_cfg.dev, "\nStarting isif_config_raw..\n");
555
556
/*
557
* Configure CCDCFG register:-
558
* Set CCD Not to swap input since input is RAW data
559
* Set FID detection function to Latch at V-Sync
560
* Set WENLOG - isif valid area
561
* Set TRGSEL
562
* Set EXTRG
563
* Packed to 8 or 16 bits
564
*/
565
566
val = ISIF_YCINSWP_RAW | ISIF_CCDCFG_FIDMD_LATCH_VSYNC |
567
ISIF_CCDCFG_WENLOG_AND | ISIF_CCDCFG_TRGSEL_WEN |
568
ISIF_CCDCFG_EXTRG_DISABLE | isif_cfg.data_pack;
569
570
dev_dbg(isif_cfg.dev, "Writing 0x%x to ...CCDCFG \n", val);
571
regw(val, CCDCFG);
572
573
/*
574
* Configure the vertical sync polarity(MODESET.VDPOL)
575
* Configure the horizontal sync polarity (MODESET.HDPOL)
576
* Configure frame id polarity (MODESET.FLDPOL)
577
* Configure data polarity
578
* Configure External WEN Selection
579
* Configure frame format(progressive or interlace)
580
* Configure pixel format (Input mode)
581
* Configure the data shift
582
*/
583
584
val = ISIF_VDHDOUT_INPUT | (params->vd_pol << ISIF_VD_POL_SHIFT) |
585
(params->hd_pol << ISIF_HD_POL_SHIFT) |
586
(params->fid_pol << ISIF_FID_POL_SHIFT) |
587
(ISIF_DATAPOL_NORMAL << ISIF_DATAPOL_SHIFT) |
588
(ISIF_EXWEN_DISABLE << ISIF_EXWEN_SHIFT) |
589
(params->frm_fmt << ISIF_FRM_FMT_SHIFT) |
590
(params->pix_fmt << ISIF_INPUT_SHIFT) |
591
(params->config_params.data_shift << ISIF_DATASFT_SHIFT);
592
593
regw(val, MODESET);
594
dev_dbg(isif_cfg.dev, "Writing 0x%x to MODESET...\n", val);
595
596
/*
597
* Configure GAMMAWD register
598
* CFA pattern setting
599
*/
600
val = params->cfa_pat << ISIF_GAMMAWD_CFA_SHIFT;
601
602
/* Gamma msb */
603
if (module_params->compress.alg == ISIF_ALAW)
604
val |= ISIF_ALAW_ENABLE;
605
606
val |= (params->data_msb << ISIF_ALAW_GAMA_WD_SHIFT);
607
regw(val, CGAMMAWD);
608
609
/* Configure DPCM compression settings */
610
if (module_params->compress.alg == ISIF_DPCM) {
611
val = BIT(ISIF_DPCM_EN_SHIFT) |
612
(module_params->compress.pred <<
613
ISIF_DPCM_PREDICTOR_SHIFT);
614
}
615
616
regw(val, MISC);
617
618
/* Configure Gain & Offset */
619
isif_config_gain_offset();
620
621
/* Configure Color pattern */
622
val = (params->config_params.col_pat_field0.olop) |
623
(params->config_params.col_pat_field0.olep << 2) |
624
(params->config_params.col_pat_field0.elop << 4) |
625
(params->config_params.col_pat_field0.elep << 6) |
626
(params->config_params.col_pat_field1.olop << 8) |
627
(params->config_params.col_pat_field1.olep << 10) |
628
(params->config_params.col_pat_field1.elop << 12) |
629
(params->config_params.col_pat_field1.elep << 14);
630
regw(val, CCOLP);
631
dev_dbg(isif_cfg.dev, "Writing %x to CCOLP ...\n", val);
632
633
/* Configure HSIZE register */
634
val = (!!params->horz_flip_en) << ISIF_HSIZE_FLIP_SHIFT;
635
636
/* calculate line offset in 32 bytes based on pack value */
637
if (isif_cfg.data_pack == ISIF_PACK_8BIT)
638
val |= ((params->win.width + 31) >> 5);
639
else if (isif_cfg.data_pack == ISIF_PACK_12BIT)
640
val |= (((params->win.width +
641
(params->win.width >> 2)) + 31) >> 5);
642
else
643
val |= (((params->win.width * 2) + 31) >> 5);
644
regw(val, HSIZE);
645
646
/* Configure SDOFST register */
647
if (params->frm_fmt == CCDC_FRMFMT_INTERLACED) {
648
if (params->image_invert_en) {
649
/* For interlace inverse mode */
650
regw(0x4B6D, SDOFST);
651
dev_dbg(isif_cfg.dev, "Writing 0x4B6D to SDOFST...\n");
652
} else {
653
/* For interlace non inverse mode */
654
regw(0x0B6D, SDOFST);
655
dev_dbg(isif_cfg.dev, "Writing 0x0B6D to SDOFST...\n");
656
}
657
} else if (params->frm_fmt == CCDC_FRMFMT_PROGRESSIVE) {
658
if (params->image_invert_en) {
659
/* For progressive inverse mode */
660
regw(0x4000, SDOFST);
661
dev_dbg(isif_cfg.dev, "Writing 0x4000 to SDOFST...\n");
662
} else {
663
/* For progressive non inverse mode */
664
regw(0x0000, SDOFST);
665
dev_dbg(isif_cfg.dev, "Writing 0x0000 to SDOFST...\n");
666
}
667
}
668
669
/* Configure video window */
670
isif_setwin(&params->win, params->frm_fmt, 1);
671
672
/* Configure Black Clamp */
673
isif_config_bclamp(&module_params->bclamp);
674
675
/* Configure Vertical Defection Pixel Correction */
676
if (isif_config_dfc(&module_params->dfc) < 0)
677
return -EFAULT;
678
679
if (!module_params->df_csc.df_or_csc)
680
/* Configure Color Space Conversion */
681
isif_config_csc(&module_params->df_csc);
682
683
isif_config_linearization(&module_params->linearize);
684
685
/* Configure Culling */
686
isif_config_culling(&module_params->culling);
687
688
/* Configure horizontal and vertical offsets(DFC,LSC,Gain) */
689
regw(module_params->horz_offset, DATAHOFST);
690
regw(module_params->vert_offset, DATAVOFST);
691
692
/* Setup test pattern if enabled */
693
if (params->config_params.test_pat_gen) {
694
/* Use the HD/VD pol settings from user */
695
sync.ccdpg_hdpol = params->hd_pol;
696
sync.ccdpg_vdpol = params->vd_pol;
697
dm365_vpss_set_sync_pol(sync);
698
frame_size.hlpfr = isif_cfg.bayer.win.width;
699
frame_size.pplen = isif_cfg.bayer.win.height;
700
dm365_vpss_set_pg_frame_size(frame_size);
701
vpss_select_ccdc_source(VPSS_PGLPBK);
702
}
703
704
dev_dbg(isif_cfg.dev, "\nEnd of isif_config_ycbcr...\n");
705
return 0;
706
}
707
708
static int isif_set_buftype(enum ccdc_buftype buf_type)
709
{
710
if (isif_cfg.if_type == VPFE_RAW_BAYER)
711
isif_cfg.bayer.buf_type = buf_type;
712
else
713
isif_cfg.ycbcr.buf_type = buf_type;
714
715
return 0;
716
717
}
718
static enum ccdc_buftype isif_get_buftype(void)
719
{
720
if (isif_cfg.if_type == VPFE_RAW_BAYER)
721
return isif_cfg.bayer.buf_type;
722
723
return isif_cfg.ycbcr.buf_type;
724
}
725
726
static int isif_enum_pix(u32 *pix, int i)
727
{
728
int ret = -EINVAL;
729
730
if (isif_cfg.if_type == VPFE_RAW_BAYER) {
731
if (i < ARRAY_SIZE(isif_raw_bayer_pix_formats)) {
732
*pix = isif_raw_bayer_pix_formats[i];
733
ret = 0;
734
}
735
} else {
736
if (i < ARRAY_SIZE(isif_raw_yuv_pix_formats)) {
737
*pix = isif_raw_yuv_pix_formats[i];
738
ret = 0;
739
}
740
}
741
742
return ret;
743
}
744
745
static int isif_set_pixel_format(unsigned int pixfmt)
746
{
747
if (isif_cfg.if_type == VPFE_RAW_BAYER) {
748
if (pixfmt == V4L2_PIX_FMT_SBGGR8) {
749
if ((isif_cfg.bayer.config_params.compress.alg !=
750
ISIF_ALAW) &&
751
(isif_cfg.bayer.config_params.compress.alg !=
752
ISIF_DPCM)) {
753
dev_dbg(isif_cfg.dev,
754
"Either configure A-Law or DPCM\n");
755
return -EINVAL;
756
}
757
isif_cfg.data_pack = ISIF_PACK_8BIT;
758
} else if (pixfmt == V4L2_PIX_FMT_SBGGR16) {
759
isif_cfg.bayer.config_params.compress.alg =
760
ISIF_NO_COMPRESSION;
761
isif_cfg.data_pack = ISIF_PACK_16BIT;
762
} else
763
return -EINVAL;
764
isif_cfg.bayer.pix_fmt = CCDC_PIXFMT_RAW;
765
} else {
766
if (pixfmt == V4L2_PIX_FMT_YUYV)
767
isif_cfg.ycbcr.pix_order = CCDC_PIXORDER_YCBYCR;
768
else if (pixfmt == V4L2_PIX_FMT_UYVY)
769
isif_cfg.ycbcr.pix_order = CCDC_PIXORDER_CBYCRY;
770
else
771
return -EINVAL;
772
isif_cfg.data_pack = ISIF_PACK_8BIT;
773
}
774
return 0;
775
}
776
777
static u32 isif_get_pixel_format(void)
778
{
779
u32 pixfmt;
780
781
if (isif_cfg.if_type == VPFE_RAW_BAYER)
782
if (isif_cfg.bayer.config_params.compress.alg == ISIF_ALAW ||
783
isif_cfg.bayer.config_params.compress.alg == ISIF_DPCM)
784
pixfmt = V4L2_PIX_FMT_SBGGR8;
785
else
786
pixfmt = V4L2_PIX_FMT_SBGGR16;
787
else {
788
if (isif_cfg.ycbcr.pix_order == CCDC_PIXORDER_YCBYCR)
789
pixfmt = V4L2_PIX_FMT_YUYV;
790
else
791
pixfmt = V4L2_PIX_FMT_UYVY;
792
}
793
return pixfmt;
794
}
795
796
static int isif_set_image_window(struct v4l2_rect *win)
797
{
798
if (isif_cfg.if_type == VPFE_RAW_BAYER) {
799
isif_cfg.bayer.win.top = win->top;
800
isif_cfg.bayer.win.left = win->left;
801
isif_cfg.bayer.win.width = win->width;
802
isif_cfg.bayer.win.height = win->height;
803
} else {
804
isif_cfg.ycbcr.win.top = win->top;
805
isif_cfg.ycbcr.win.left = win->left;
806
isif_cfg.ycbcr.win.width = win->width;
807
isif_cfg.ycbcr.win.height = win->height;
808
}
809
return 0;
810
}
811
812
static void isif_get_image_window(struct v4l2_rect *win)
813
{
814
if (isif_cfg.if_type == VPFE_RAW_BAYER)
815
*win = isif_cfg.bayer.win;
816
else
817
*win = isif_cfg.ycbcr.win;
818
}
819
820
static unsigned int isif_get_line_length(void)
821
{
822
unsigned int len;
823
824
if (isif_cfg.if_type == VPFE_RAW_BAYER) {
825
if (isif_cfg.data_pack == ISIF_PACK_8BIT)
826
len = ((isif_cfg.bayer.win.width));
827
else if (isif_cfg.data_pack == ISIF_PACK_12BIT)
828
len = (((isif_cfg.bayer.win.width * 2) +
829
(isif_cfg.bayer.win.width >> 2)));
830
else
831
len = (((isif_cfg.bayer.win.width * 2)));
832
} else
833
len = (((isif_cfg.ycbcr.win.width * 2)));
834
return ALIGN(len, 32);
835
}
836
837
static int isif_set_frame_format(enum ccdc_frmfmt frm_fmt)
838
{
839
if (isif_cfg.if_type == VPFE_RAW_BAYER)
840
isif_cfg.bayer.frm_fmt = frm_fmt;
841
else
842
isif_cfg.ycbcr.frm_fmt = frm_fmt;
843
return 0;
844
}
845
static enum ccdc_frmfmt isif_get_frame_format(void)
846
{
847
if (isif_cfg.if_type == VPFE_RAW_BAYER)
848
return isif_cfg.bayer.frm_fmt;
849
return isif_cfg.ycbcr.frm_fmt;
850
}
851
852
static int isif_getfid(void)
853
{
854
return (regr(MODESET) >> 15) & 0x1;
855
}
856
857
/* misc operations */
858
static void isif_setfbaddr(unsigned long addr)
859
{
860
regw((addr >> 21) & 0x07ff, CADU);
861
regw((addr >> 5) & 0x0ffff, CADL);
862
}
863
864
static int isif_set_hw_if_params(struct vpfe_hw_if_param *params)
865
{
866
isif_cfg.if_type = params->if_type;
867
868
switch (params->if_type) {
869
case VPFE_BT656:
870
case VPFE_BT656_10BIT:
871
case VPFE_YCBCR_SYNC_8:
872
isif_cfg.ycbcr.pix_fmt = CCDC_PIXFMT_YCBCR_8BIT;
873
isif_cfg.ycbcr.pix_order = CCDC_PIXORDER_CBYCRY;
874
break;
875
case VPFE_BT1120:
876
case VPFE_YCBCR_SYNC_16:
877
isif_cfg.ycbcr.pix_fmt = CCDC_PIXFMT_YCBCR_16BIT;
878
isif_cfg.ycbcr.pix_order = CCDC_PIXORDER_CBYCRY;
879
break;
880
case VPFE_RAW_BAYER:
881
isif_cfg.bayer.pix_fmt = CCDC_PIXFMT_RAW;
882
break;
883
default:
884
dev_dbg(isif_cfg.dev, "Invalid interface type\n");
885
return -EINVAL;
886
}
887
888
return 0;
889
}
890
891
/* This function will configure ISIF for YCbCr parameters. */
892
static int isif_config_ycbcr(void)
893
{
894
struct isif_ycbcr_config *params = &isif_cfg.ycbcr;
895
struct vpss_pg_frame_size frame_size;
896
u32 modeset = 0, ccdcfg = 0;
897
struct vpss_sync_pol sync;
898
899
dev_dbg(isif_cfg.dev, "\nStarting isif_config_ycbcr...");
900
901
/* configure pixel format or input mode */
902
modeset = modeset | (params->pix_fmt << ISIF_INPUT_SHIFT) |
903
(params->frm_fmt << ISIF_FRM_FMT_SHIFT) |
904
(params->fid_pol << ISIF_FID_POL_SHIFT) |
905
(params->hd_pol << ISIF_HD_POL_SHIFT) |
906
(params->vd_pol << ISIF_VD_POL_SHIFT);
907
908
/* pack the data to 8-bit ISIFCFG */
909
switch (isif_cfg.if_type) {
910
case VPFE_BT656:
911
if (params->pix_fmt != CCDC_PIXFMT_YCBCR_8BIT) {
912
dev_dbg(isif_cfg.dev, "Invalid pix_fmt(input mode)\n");
913
return -EINVAL;
914
}
915
modeset |= (VPFE_PINPOL_NEGATIVE << ISIF_VD_POL_SHIFT);
916
regw(3, REC656IF);
917
ccdcfg = ccdcfg | ISIF_DATA_PACK8 | ISIF_YCINSWP_YCBCR;
918
break;
919
case VPFE_BT656_10BIT:
920
if (params->pix_fmt != CCDC_PIXFMT_YCBCR_8BIT) {
921
dev_dbg(isif_cfg.dev, "Invalid pix_fmt(input mode)\n");
922
return -EINVAL;
923
}
924
/* setup BT.656, embedded sync */
925
regw(3, REC656IF);
926
/* enable 10 bit mode in ccdcfg */
927
ccdcfg = ccdcfg | ISIF_DATA_PACK8 | ISIF_YCINSWP_YCBCR |
928
ISIF_BW656_ENABLE;
929
break;
930
case VPFE_BT1120:
931
if (params->pix_fmt != CCDC_PIXFMT_YCBCR_16BIT) {
932
dev_dbg(isif_cfg.dev, "Invalid pix_fmt(input mode)\n");
933
return -EINVAL;
934
}
935
regw(3, REC656IF);
936
break;
937
938
case VPFE_YCBCR_SYNC_8:
939
ccdcfg |= ISIF_DATA_PACK8;
940
ccdcfg |= ISIF_YCINSWP_YCBCR;
941
if (params->pix_fmt != CCDC_PIXFMT_YCBCR_8BIT) {
942
dev_dbg(isif_cfg.dev, "Invalid pix_fmt(input mode)\n");
943
return -EINVAL;
944
}
945
break;
946
case VPFE_YCBCR_SYNC_16:
947
if (params->pix_fmt != CCDC_PIXFMT_YCBCR_16BIT) {
948
dev_dbg(isif_cfg.dev, "Invalid pix_fmt(input mode)\n");
949
return -EINVAL;
950
}
951
break;
952
default:
953
/* should never come here */
954
dev_dbg(isif_cfg.dev, "Invalid interface type\n");
955
return -EINVAL;
956
}
957
958
regw(modeset, MODESET);
959
960
/* Set up pix order */
961
ccdcfg |= params->pix_order << ISIF_PIX_ORDER_SHIFT;
962
963
regw(ccdcfg, CCDCFG);
964
965
/* configure video window */
966
if ((isif_cfg.if_type == VPFE_BT1120) ||
967
(isif_cfg.if_type == VPFE_YCBCR_SYNC_16))
968
isif_setwin(&params->win, params->frm_fmt, 1);
969
else
970
isif_setwin(&params->win, params->frm_fmt, 2);
971
972
/*
973
* configure the horizontal line offset
974
* this is done by rounding up width to a multiple of 16 pixels
975
* and multiply by two to account for y:cb:cr 4:2:2 data
976
*/
977
regw(((((params->win.width * 2) + 31) & 0xffffffe0) >> 5), HSIZE);
978
979
/* configure the memory line offset */
980
if ((params->frm_fmt == CCDC_FRMFMT_INTERLACED) &&
981
(params->buf_type == CCDC_BUFTYPE_FLD_INTERLEAVED))
982
/* two fields are interleaved in memory */
983
regw(0x00000249, SDOFST);
984
985
/* Setup test pattern if enabled */
986
if (isif_cfg.bayer.config_params.test_pat_gen) {
987
sync.ccdpg_hdpol = params->hd_pol;
988
sync.ccdpg_vdpol = params->vd_pol;
989
dm365_vpss_set_sync_pol(sync);
990
dm365_vpss_set_pg_frame_size(frame_size);
991
}
992
return 0;
993
}
994
995
static int isif_configure(void)
996
{
997
if (isif_cfg.if_type == VPFE_RAW_BAYER)
998
return isif_config_raw();
999
return isif_config_ycbcr();
1000
}
1001
1002
static int isif_close(struct device *device)
1003
{
1004
/* copy defaults to module params */
1005
isif_cfg.bayer.config_params = isif_config_defaults;
1006
return 0;
1007
}
1008
1009
static struct ccdc_hw_device isif_hw_dev = {
1010
.name = "ISIF",
1011
.owner = THIS_MODULE,
1012
.hw_ops = {
1013
.open = isif_open,
1014
.close = isif_close,
1015
.enable = isif_enable,
1016
.enable_out_to_sdram = isif_enable_output_to_sdram,
1017
.set_hw_if_params = isif_set_hw_if_params,
1018
.configure = isif_configure,
1019
.set_buftype = isif_set_buftype,
1020
.get_buftype = isif_get_buftype,
1021
.enum_pix = isif_enum_pix,
1022
.set_pixel_format = isif_set_pixel_format,
1023
.get_pixel_format = isif_get_pixel_format,
1024
.set_frame_format = isif_set_frame_format,
1025
.get_frame_format = isif_get_frame_format,
1026
.set_image_window = isif_set_image_window,
1027
.get_image_window = isif_get_image_window,
1028
.get_line_length = isif_get_line_length,
1029
.setfbaddr = isif_setfbaddr,
1030
.getfid = isif_getfid,
1031
},
1032
};
1033
1034
static int __init isif_probe(struct platform_device *pdev)
1035
{
1036
void (*setup_pinmux)(void);
1037
struct resource *res;
1038
void *__iomem addr;
1039
int status = 0, i;
1040
1041
/*
1042
* first try to register with vpfe. If not correct platform, then we
1043
* don't have to iomap
1044
*/
1045
status = vpfe_register_ccdc_device(&isif_hw_dev);
1046
if (status < 0)
1047
return status;
1048
1049
/* Get and enable Master clock */
1050
isif_cfg.mclk = clk_get(&pdev->dev, "master");
1051
if (IS_ERR(isif_cfg.mclk)) {
1052
status = PTR_ERR(isif_cfg.mclk);
1053
goto fail_mclk;
1054
}
1055
if (clk_enable(isif_cfg.mclk)) {
1056
status = -ENODEV;
1057
goto fail_mclk;
1058
}
1059
1060
/* Platform data holds setup_pinmux function ptr */
1061
if (NULL == pdev->dev.platform_data) {
1062
status = -ENODEV;
1063
goto fail_mclk;
1064
}
1065
setup_pinmux = pdev->dev.platform_data;
1066
/*
1067
* setup Mux configuration for ccdc which may be different for
1068
* different SoCs using this CCDC
1069
*/
1070
setup_pinmux();
1071
1072
i = 0;
1073
/* Get the ISIF base address, linearization table0 and table1 addr. */
1074
while (i < 3) {
1075
res = platform_get_resource(pdev, IORESOURCE_MEM, i);
1076
if (!res) {
1077
status = -ENODEV;
1078
goto fail_nobase_res;
1079
}
1080
res = request_mem_region(res->start, resource_size(res),
1081
res->name);
1082
if (!res) {
1083
status = -EBUSY;
1084
goto fail_nobase_res;
1085
}
1086
addr = ioremap_nocache(res->start, resource_size(res));
1087
if (!addr) {
1088
status = -ENOMEM;
1089
goto fail_base_iomap;
1090
}
1091
switch (i) {
1092
case 0:
1093
/* ISIF base address */
1094
isif_cfg.base_addr = addr;
1095
break;
1096
case 1:
1097
/* ISIF linear tbl0 address */
1098
isif_cfg.linear_tbl0_addr = addr;
1099
break;
1100
default:
1101
/* ISIF linear tbl0 address */
1102
isif_cfg.linear_tbl1_addr = addr;
1103
break;
1104
}
1105
i++;
1106
}
1107
isif_cfg.dev = &pdev->dev;
1108
1109
printk(KERN_NOTICE "%s is registered with vpfe.\n",
1110
isif_hw_dev.name);
1111
return 0;
1112
fail_base_iomap:
1113
release_mem_region(res->start, resource_size(res));
1114
i--;
1115
fail_nobase_res:
1116
if (isif_cfg.base_addr)
1117
iounmap(isif_cfg.base_addr);
1118
if (isif_cfg.linear_tbl0_addr)
1119
iounmap(isif_cfg.linear_tbl0_addr);
1120
1121
while (i >= 0) {
1122
res = platform_get_resource(pdev, IORESOURCE_MEM, i);
1123
release_mem_region(res->start, resource_size(res));
1124
i--;
1125
}
1126
fail_mclk:
1127
clk_put(isif_cfg.mclk);
1128
vpfe_unregister_ccdc_device(&isif_hw_dev);
1129
return status;
1130
}
1131
1132
static int isif_remove(struct platform_device *pdev)
1133
{
1134
struct resource *res;
1135
int i = 0;
1136
1137
iounmap(isif_cfg.base_addr);
1138
iounmap(isif_cfg.linear_tbl0_addr);
1139
iounmap(isif_cfg.linear_tbl1_addr);
1140
while (i < 3) {
1141
res = platform_get_resource(pdev, IORESOURCE_MEM, i);
1142
if (res)
1143
release_mem_region(res->start, resource_size(res));
1144
i++;
1145
}
1146
vpfe_unregister_ccdc_device(&isif_hw_dev);
1147
return 0;
1148
}
1149
1150
static struct platform_driver isif_driver = {
1151
.driver = {
1152
.name = "isif",
1153
.owner = THIS_MODULE,
1154
},
1155
.remove = __devexit_p(isif_remove),
1156
.probe = isif_probe,
1157
};
1158
1159
static int __init isif_init(void)
1160
{
1161
return platform_driver_register(&isif_driver);
1162
}
1163
1164
static void isif_exit(void)
1165
{
1166
platform_driver_unregister(&isif_driver);
1167
}
1168
1169
module_init(isif_init);
1170
module_exit(isif_exit);
1171
1172
MODULE_LICENSE("GPL");
1173
1174