Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
awilliam
GitHub Repository: awilliam/linux-vfio
Path: blob/master/drivers/media/video/davinci/dm355_ccdc.c
17633 views
1
/*
2
* Copyright (C) 2005-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
* CCDC hardware module for DM355
19
* ------------------------------
20
*
21
* This module is for configuring DM355 CCD controller of VPFE to capture
22
* Raw yuv or Bayer RGB data from a decoder. CCDC has several modules
23
* such as Defect Pixel Correction, Color Space Conversion etc to
24
* pre-process the Bayer RGB data, before writing it to SDRAM. This
25
* module also allows application to configure individual
26
* module parameters through VPFE_CMD_S_CCDC_RAW_PARAMS IOCTL.
27
* To do so, application include dm355_ccdc.h and vpfe_capture.h header
28
* files. The setparams() API is called by vpfe_capture driver
29
* to configure module parameters
30
*
31
* TODO: 1) Raw bayer parameter settings and bayer capture
32
* 2) Split module parameter structure to module specific ioctl structs
33
* 3) add support for lense shading correction
34
* 4) investigate if enum used for user space type definition
35
* to be replaced by #defines or integer
36
*/
37
#include <linux/platform_device.h>
38
#include <linux/uaccess.h>
39
#include <linux/videodev2.h>
40
#include <linux/clk.h>
41
#include <linux/err.h>
42
43
#include <media/davinci/dm355_ccdc.h>
44
#include <media/davinci/vpss.h>
45
46
#include "dm355_ccdc_regs.h"
47
#include "ccdc_hw_device.h"
48
49
MODULE_LICENSE("GPL");
50
MODULE_DESCRIPTION("CCDC Driver for DM355");
51
MODULE_AUTHOR("Texas Instruments");
52
53
static struct ccdc_oper_config {
54
struct device *dev;
55
/* CCDC interface type */
56
enum vpfe_hw_if_type if_type;
57
/* Raw Bayer configuration */
58
struct ccdc_params_raw bayer;
59
/* YCbCr configuration */
60
struct ccdc_params_ycbcr ycbcr;
61
/* Master clock */
62
struct clk *mclk;
63
/* slave clock */
64
struct clk *sclk;
65
/* ccdc base address */
66
void __iomem *base_addr;
67
} ccdc_cfg = {
68
/* Raw configurations */
69
.bayer = {
70
.pix_fmt = CCDC_PIXFMT_RAW,
71
.frm_fmt = CCDC_FRMFMT_PROGRESSIVE,
72
.win = CCDC_WIN_VGA,
73
.fid_pol = VPFE_PINPOL_POSITIVE,
74
.vd_pol = VPFE_PINPOL_POSITIVE,
75
.hd_pol = VPFE_PINPOL_POSITIVE,
76
.gain = {
77
.r_ye = 256,
78
.gb_g = 256,
79
.gr_cy = 256,
80
.b_mg = 256
81
},
82
.config_params = {
83
.datasft = 2,
84
.mfilt1 = CCDC_NO_MEDIAN_FILTER1,
85
.mfilt2 = CCDC_NO_MEDIAN_FILTER2,
86
.alaw = {
87
.gama_wd = 2,
88
},
89
.blk_clamp = {
90
.sample_pixel = 1,
91
.dc_sub = 25
92
},
93
.col_pat_field0 = {
94
.olop = CCDC_GREEN_BLUE,
95
.olep = CCDC_BLUE,
96
.elop = CCDC_RED,
97
.elep = CCDC_GREEN_RED
98
},
99
.col_pat_field1 = {
100
.olop = CCDC_GREEN_BLUE,
101
.olep = CCDC_BLUE,
102
.elop = CCDC_RED,
103
.elep = CCDC_GREEN_RED
104
},
105
},
106
},
107
/* YCbCr configuration */
108
.ycbcr = {
109
.win = CCDC_WIN_PAL,
110
.pix_fmt = CCDC_PIXFMT_YCBCR_8BIT,
111
.frm_fmt = CCDC_FRMFMT_INTERLACED,
112
.fid_pol = VPFE_PINPOL_POSITIVE,
113
.vd_pol = VPFE_PINPOL_POSITIVE,
114
.hd_pol = VPFE_PINPOL_POSITIVE,
115
.bt656_enable = 1,
116
.pix_order = CCDC_PIXORDER_CBYCRY,
117
.buf_type = CCDC_BUFTYPE_FLD_INTERLEAVED
118
},
119
};
120
121
122
/* Raw Bayer formats */
123
static u32 ccdc_raw_bayer_pix_formats[] =
124
{V4L2_PIX_FMT_SBGGR8, V4L2_PIX_FMT_SBGGR16};
125
126
/* Raw YUV formats */
127
static u32 ccdc_raw_yuv_pix_formats[] =
128
{V4L2_PIX_FMT_UYVY, V4L2_PIX_FMT_YUYV};
129
130
/* register access routines */
131
static inline u32 regr(u32 offset)
132
{
133
return __raw_readl(ccdc_cfg.base_addr + offset);
134
}
135
136
static inline void regw(u32 val, u32 offset)
137
{
138
__raw_writel(val, ccdc_cfg.base_addr + offset);
139
}
140
141
static void ccdc_enable(int en)
142
{
143
unsigned int temp;
144
temp = regr(SYNCEN);
145
temp &= (~CCDC_SYNCEN_VDHDEN_MASK);
146
temp |= (en & CCDC_SYNCEN_VDHDEN_MASK);
147
regw(temp, SYNCEN);
148
}
149
150
static void ccdc_enable_output_to_sdram(int en)
151
{
152
unsigned int temp;
153
temp = regr(SYNCEN);
154
temp &= (~(CCDC_SYNCEN_WEN_MASK));
155
temp |= ((en << CCDC_SYNCEN_WEN_SHIFT) & CCDC_SYNCEN_WEN_MASK);
156
regw(temp, SYNCEN);
157
}
158
159
static void ccdc_config_gain_offset(void)
160
{
161
/* configure gain */
162
regw(ccdc_cfg.bayer.gain.r_ye, RYEGAIN);
163
regw(ccdc_cfg.bayer.gain.gr_cy, GRCYGAIN);
164
regw(ccdc_cfg.bayer.gain.gb_g, GBGGAIN);
165
regw(ccdc_cfg.bayer.gain.b_mg, BMGGAIN);
166
/* configure offset */
167
regw(ccdc_cfg.bayer.ccdc_offset, OFFSET);
168
}
169
170
/*
171
* ccdc_restore_defaults()
172
* This function restore power on defaults in the ccdc registers
173
*/
174
static int ccdc_restore_defaults(void)
175
{
176
int i;
177
178
dev_dbg(ccdc_cfg.dev, "\nstarting ccdc_restore_defaults...");
179
/* set all registers to zero */
180
for (i = 0; i <= CCDC_REG_LAST; i += 4)
181
regw(0, i);
182
183
/* now override the values with power on defaults in registers */
184
regw(MODESET_DEFAULT, MODESET);
185
/* no culling support */
186
regw(CULH_DEFAULT, CULH);
187
regw(CULV_DEFAULT, CULV);
188
/* Set default Gain and Offset */
189
ccdc_cfg.bayer.gain.r_ye = GAIN_DEFAULT;
190
ccdc_cfg.bayer.gain.gb_g = GAIN_DEFAULT;
191
ccdc_cfg.bayer.gain.gr_cy = GAIN_DEFAULT;
192
ccdc_cfg.bayer.gain.b_mg = GAIN_DEFAULT;
193
ccdc_config_gain_offset();
194
regw(OUTCLIP_DEFAULT, OUTCLIP);
195
regw(LSCCFG2_DEFAULT, LSCCFG2);
196
/* select ccdc input */
197
if (vpss_select_ccdc_source(VPSS_CCDCIN)) {
198
dev_dbg(ccdc_cfg.dev, "\ncouldn't select ccdc input source");
199
return -EFAULT;
200
}
201
/* select ccdc clock */
202
if (vpss_enable_clock(VPSS_CCDC_CLOCK, 1) < 0) {
203
dev_dbg(ccdc_cfg.dev, "\ncouldn't enable ccdc clock");
204
return -EFAULT;
205
}
206
dev_dbg(ccdc_cfg.dev, "\nEnd of ccdc_restore_defaults...");
207
return 0;
208
}
209
210
static int ccdc_open(struct device *device)
211
{
212
return ccdc_restore_defaults();
213
}
214
215
static int ccdc_close(struct device *device)
216
{
217
/* disable clock */
218
vpss_enable_clock(VPSS_CCDC_CLOCK, 0);
219
/* do nothing for now */
220
return 0;
221
}
222
/*
223
* ccdc_setwin()
224
* This function will configure the window size to
225
* be capture in CCDC reg.
226
*/
227
static void ccdc_setwin(struct v4l2_rect *image_win,
228
enum ccdc_frmfmt frm_fmt, int ppc)
229
{
230
int horz_start, horz_nr_pixels;
231
int vert_start, vert_nr_lines;
232
int mid_img = 0;
233
234
dev_dbg(ccdc_cfg.dev, "\nStarting ccdc_setwin...");
235
236
/*
237
* ppc - per pixel count. indicates how many pixels per cell
238
* output to SDRAM. example, for ycbcr, it is one y and one c, so 2.
239
* raw capture this is 1
240
*/
241
horz_start = image_win->left << (ppc - 1);
242
horz_nr_pixels = ((image_win->width) << (ppc - 1)) - 1;
243
244
/* Writing the horizontal info into the registers */
245
regw(horz_start, SPH);
246
regw(horz_nr_pixels, NPH);
247
vert_start = image_win->top;
248
249
if (frm_fmt == CCDC_FRMFMT_INTERLACED) {
250
vert_nr_lines = (image_win->height >> 1) - 1;
251
vert_start >>= 1;
252
/* Since first line doesn't have any data */
253
vert_start += 1;
254
/* configure VDINT0 and VDINT1 */
255
regw(vert_start, VDINT0);
256
} else {
257
/* Since first line doesn't have any data */
258
vert_start += 1;
259
vert_nr_lines = image_win->height - 1;
260
/* configure VDINT0 and VDINT1 */
261
mid_img = vert_start + (image_win->height / 2);
262
regw(vert_start, VDINT0);
263
regw(mid_img, VDINT1);
264
}
265
regw(vert_start & CCDC_START_VER_ONE_MASK, SLV0);
266
regw(vert_start & CCDC_START_VER_TWO_MASK, SLV1);
267
regw(vert_nr_lines & CCDC_NUM_LINES_VER, NLV);
268
dev_dbg(ccdc_cfg.dev, "\nEnd of ccdc_setwin...");
269
}
270
271
static int validate_ccdc_param(struct ccdc_config_params_raw *ccdcparam)
272
{
273
if (ccdcparam->datasft < CCDC_DATA_NO_SHIFT ||
274
ccdcparam->datasft > CCDC_DATA_SHIFT_6BIT) {
275
dev_dbg(ccdc_cfg.dev, "Invalid value of data shift\n");
276
return -EINVAL;
277
}
278
279
if (ccdcparam->mfilt1 < CCDC_NO_MEDIAN_FILTER1 ||
280
ccdcparam->mfilt1 > CCDC_MEDIAN_FILTER1) {
281
dev_dbg(ccdc_cfg.dev, "Invalid value of median filter1\n");
282
return -EINVAL;
283
}
284
285
if (ccdcparam->mfilt2 < CCDC_NO_MEDIAN_FILTER2 ||
286
ccdcparam->mfilt2 > CCDC_MEDIAN_FILTER2) {
287
dev_dbg(ccdc_cfg.dev, "Invalid value of median filter2\n");
288
return -EINVAL;
289
}
290
291
if ((ccdcparam->med_filt_thres < 0) ||
292
(ccdcparam->med_filt_thres > CCDC_MED_FILT_THRESH)) {
293
dev_dbg(ccdc_cfg.dev,
294
"Invalid value of median filter thresold\n");
295
return -EINVAL;
296
}
297
298
if (ccdcparam->data_sz < CCDC_DATA_16BITS ||
299
ccdcparam->data_sz > CCDC_DATA_8BITS) {
300
dev_dbg(ccdc_cfg.dev, "Invalid value of data size\n");
301
return -EINVAL;
302
}
303
304
if (ccdcparam->alaw.enable) {
305
if (ccdcparam->alaw.gama_wd < CCDC_GAMMA_BITS_13_4 ||
306
ccdcparam->alaw.gama_wd > CCDC_GAMMA_BITS_09_0) {
307
dev_dbg(ccdc_cfg.dev, "Invalid value of ALAW\n");
308
return -EINVAL;
309
}
310
}
311
312
if (ccdcparam->blk_clamp.b_clamp_enable) {
313
if (ccdcparam->blk_clamp.sample_pixel < CCDC_SAMPLE_1PIXELS ||
314
ccdcparam->blk_clamp.sample_pixel > CCDC_SAMPLE_16PIXELS) {
315
dev_dbg(ccdc_cfg.dev,
316
"Invalid value of sample pixel\n");
317
return -EINVAL;
318
}
319
if (ccdcparam->blk_clamp.sample_ln < CCDC_SAMPLE_1LINES ||
320
ccdcparam->blk_clamp.sample_ln > CCDC_SAMPLE_16LINES) {
321
dev_dbg(ccdc_cfg.dev,
322
"Invalid value of sample lines\n");
323
return -EINVAL;
324
}
325
}
326
return 0;
327
}
328
329
/* Parameter operations */
330
static int ccdc_set_params(void __user *params)
331
{
332
struct ccdc_config_params_raw ccdc_raw_params;
333
int x;
334
335
/* only raw module parameters can be set through the IOCTL */
336
if (ccdc_cfg.if_type != VPFE_RAW_BAYER)
337
return -EINVAL;
338
339
x = copy_from_user(&ccdc_raw_params, params, sizeof(ccdc_raw_params));
340
if (x) {
341
dev_dbg(ccdc_cfg.dev, "ccdc_set_params: error in copying ccdc"
342
"params, %d\n", x);
343
return -EFAULT;
344
}
345
346
if (!validate_ccdc_param(&ccdc_raw_params)) {
347
memcpy(&ccdc_cfg.bayer.config_params,
348
&ccdc_raw_params,
349
sizeof(ccdc_raw_params));
350
return 0;
351
}
352
return -EINVAL;
353
}
354
355
/* This function will configure CCDC for YCbCr video capture */
356
static void ccdc_config_ycbcr(void)
357
{
358
struct ccdc_params_ycbcr *params = &ccdc_cfg.ycbcr;
359
u32 temp;
360
361
/* first set the CCDC power on defaults values in all registers */
362
dev_dbg(ccdc_cfg.dev, "\nStarting ccdc_config_ycbcr...");
363
ccdc_restore_defaults();
364
365
/* configure pixel format & video frame format */
366
temp = (((params->pix_fmt & CCDC_INPUT_MODE_MASK) <<
367
CCDC_INPUT_MODE_SHIFT) |
368
((params->frm_fmt & CCDC_FRM_FMT_MASK) <<
369
CCDC_FRM_FMT_SHIFT));
370
371
/* setup BT.656 sync mode */
372
if (params->bt656_enable) {
373
regw(CCDC_REC656IF_BT656_EN, REC656IF);
374
/*
375
* configure the FID, VD, HD pin polarity fld,hd pol positive,
376
* vd negative, 8-bit pack mode
377
*/
378
temp |= CCDC_VD_POL_NEGATIVE;
379
} else { /* y/c external sync mode */
380
temp |= (((params->fid_pol & CCDC_FID_POL_MASK) <<
381
CCDC_FID_POL_SHIFT) |
382
((params->hd_pol & CCDC_HD_POL_MASK) <<
383
CCDC_HD_POL_SHIFT) |
384
((params->vd_pol & CCDC_VD_POL_MASK) <<
385
CCDC_VD_POL_SHIFT));
386
}
387
388
/* pack the data to 8-bit */
389
temp |= CCDC_DATA_PACK_ENABLE;
390
391
regw(temp, MODESET);
392
393
/* configure video window */
394
ccdc_setwin(&params->win, params->frm_fmt, 2);
395
396
/* configure the order of y cb cr in SD-RAM */
397
temp = (params->pix_order << CCDC_Y8POS_SHIFT);
398
temp |= CCDC_LATCH_ON_VSYNC_DISABLE | CCDC_CCDCFG_FIDMD_NO_LATCH_VSYNC;
399
regw(temp, CCDCFG);
400
401
/*
402
* configure the horizontal line offset. This is done by rounding up
403
* width to a multiple of 16 pixels and multiply by two to account for
404
* y:cb:cr 4:2:2 data
405
*/
406
regw(((params->win.width * 2 + 31) >> 5), HSIZE);
407
408
/* configure the memory line offset */
409
if (params->buf_type == CCDC_BUFTYPE_FLD_INTERLEAVED) {
410
/* two fields are interleaved in memory */
411
regw(CCDC_SDOFST_FIELD_INTERLEAVED, SDOFST);
412
}
413
414
dev_dbg(ccdc_cfg.dev, "\nEnd of ccdc_config_ycbcr...\n");
415
}
416
417
/*
418
* ccdc_config_black_clamp()
419
* configure parameters for Optical Black Clamp
420
*/
421
static void ccdc_config_black_clamp(struct ccdc_black_clamp *bclamp)
422
{
423
u32 val;
424
425
if (!bclamp->b_clamp_enable) {
426
/* configure DCSub */
427
regw(bclamp->dc_sub & CCDC_BLK_DC_SUB_MASK, DCSUB);
428
regw(0x0000, CLAMP);
429
return;
430
}
431
/* Enable the Black clamping, set sample lines and pixels */
432
val = (bclamp->start_pixel & CCDC_BLK_ST_PXL_MASK) |
433
((bclamp->sample_pixel & CCDC_BLK_SAMPLE_LN_MASK) <<
434
CCDC_BLK_SAMPLE_LN_SHIFT) | CCDC_BLK_CLAMP_ENABLE;
435
regw(val, CLAMP);
436
437
/* If Black clamping is enable then make dcsub 0 */
438
val = (bclamp->sample_ln & CCDC_NUM_LINE_CALC_MASK)
439
<< CCDC_NUM_LINE_CALC_SHIFT;
440
regw(val, DCSUB);
441
}
442
443
/*
444
* ccdc_config_black_compense()
445
* configure parameters for Black Compensation
446
*/
447
static void ccdc_config_black_compense(struct ccdc_black_compensation *bcomp)
448
{
449
u32 val;
450
451
val = (bcomp->b & CCDC_BLK_COMP_MASK) |
452
((bcomp->gb & CCDC_BLK_COMP_MASK) <<
453
CCDC_BLK_COMP_GB_COMP_SHIFT);
454
regw(val, BLKCMP1);
455
456
val = ((bcomp->gr & CCDC_BLK_COMP_MASK) <<
457
CCDC_BLK_COMP_GR_COMP_SHIFT) |
458
((bcomp->r & CCDC_BLK_COMP_MASK) <<
459
CCDC_BLK_COMP_R_COMP_SHIFT);
460
regw(val, BLKCMP0);
461
}
462
463
/*
464
* ccdc_write_dfc_entry()
465
* write an entry in the dfc table.
466
*/
467
int ccdc_write_dfc_entry(int index, struct ccdc_vertical_dft *dfc)
468
{
469
/* TODO This is to be re-visited and adjusted */
470
#define DFC_WRITE_WAIT_COUNT 1000
471
u32 val, count = DFC_WRITE_WAIT_COUNT;
472
473
regw(dfc->dft_corr_vert[index], DFCMEM0);
474
regw(dfc->dft_corr_horz[index], DFCMEM1);
475
regw(dfc->dft_corr_sub1[index], DFCMEM2);
476
regw(dfc->dft_corr_sub2[index], DFCMEM3);
477
regw(dfc->dft_corr_sub3[index], DFCMEM4);
478
/* set WR bit to write */
479
val = regr(DFCMEMCTL) | CCDC_DFCMEMCTL_DFCMWR_MASK;
480
regw(val, DFCMEMCTL);
481
482
/*
483
* Assume, it is very short. If we get an error, we need to
484
* adjust this value
485
*/
486
while (regr(DFCMEMCTL) & CCDC_DFCMEMCTL_DFCMWR_MASK)
487
count--;
488
/*
489
* TODO We expect the count to be non-zero to be successful. Adjust
490
* the count if write requires more time
491
*/
492
493
if (count) {
494
dev_err(ccdc_cfg.dev, "defect table write timeout !!!\n");
495
return -1;
496
}
497
return 0;
498
}
499
500
/*
501
* ccdc_config_vdfc()
502
* configure parameters for Vertical Defect Correction
503
*/
504
static int ccdc_config_vdfc(struct ccdc_vertical_dft *dfc)
505
{
506
u32 val;
507
int i;
508
509
/* Configure General Defect Correction. The table used is from IPIPE */
510
val = dfc->gen_dft_en & CCDC_DFCCTL_GDFCEN_MASK;
511
512
/* Configure Vertical Defect Correction if needed */
513
if (!dfc->ver_dft_en) {
514
/* Enable only General Defect Correction */
515
regw(val, DFCCTL);
516
return 0;
517
}
518
519
if (dfc->table_size > CCDC_DFT_TABLE_SIZE)
520
return -EINVAL;
521
522
val |= CCDC_DFCCTL_VDFC_DISABLE;
523
val |= (dfc->dft_corr_ctl.vdfcsl & CCDC_DFCCTL_VDFCSL_MASK) <<
524
CCDC_DFCCTL_VDFCSL_SHIFT;
525
val |= (dfc->dft_corr_ctl.vdfcuda & CCDC_DFCCTL_VDFCUDA_MASK) <<
526
CCDC_DFCCTL_VDFCUDA_SHIFT;
527
val |= (dfc->dft_corr_ctl.vdflsft & CCDC_DFCCTL_VDFLSFT_MASK) <<
528
CCDC_DFCCTL_VDFLSFT_SHIFT;
529
regw(val , DFCCTL);
530
531
/* clear address ptr to offset 0 */
532
val = CCDC_DFCMEMCTL_DFCMARST_MASK << CCDC_DFCMEMCTL_DFCMARST_SHIFT;
533
534
/* write defect table entries */
535
for (i = 0; i < dfc->table_size; i++) {
536
/* increment address for non zero index */
537
if (i != 0)
538
val = CCDC_DFCMEMCTL_INC_ADDR;
539
regw(val, DFCMEMCTL);
540
if (ccdc_write_dfc_entry(i, dfc) < 0)
541
return -EFAULT;
542
}
543
544
/* update saturation level and enable dfc */
545
regw(dfc->saturation_ctl & CCDC_VDC_DFCVSAT_MASK, DFCVSAT);
546
val = regr(DFCCTL) | (CCDC_DFCCTL_VDFCEN_MASK <<
547
CCDC_DFCCTL_VDFCEN_SHIFT);
548
regw(val, DFCCTL);
549
return 0;
550
}
551
552
/*
553
* ccdc_config_csc()
554
* configure parameters for color space conversion
555
* Each register CSCM0-7 has two values in S8Q5 format.
556
*/
557
static void ccdc_config_csc(struct ccdc_csc *csc)
558
{
559
u32 val1, val2;
560
int i;
561
562
if (!csc->enable)
563
return;
564
565
/* Enable the CSC sub-module */
566
regw(CCDC_CSC_ENABLE, CSCCTL);
567
568
/* Converting the co-eff as per the format of the register */
569
for (i = 0; i < CCDC_CSC_COEFF_TABLE_SIZE; i++) {
570
if ((i % 2) == 0) {
571
/* CSCM - LSB */
572
val1 = (csc->coeff[i].integer &
573
CCDC_CSC_COEF_INTEG_MASK)
574
<< CCDC_CSC_COEF_INTEG_SHIFT;
575
/*
576
* convert decimal part to binary. Use 2 decimal
577
* precision, user values range from .00 - 0.99
578
*/
579
val1 |= (((csc->coeff[i].decimal &
580
CCDC_CSC_COEF_DECIMAL_MASK) *
581
CCDC_CSC_DEC_MAX) / 100);
582
} else {
583
584
/* CSCM - MSB */
585
val2 = (csc->coeff[i].integer &
586
CCDC_CSC_COEF_INTEG_MASK)
587
<< CCDC_CSC_COEF_INTEG_SHIFT;
588
val2 |= (((csc->coeff[i].decimal &
589
CCDC_CSC_COEF_DECIMAL_MASK) *
590
CCDC_CSC_DEC_MAX) / 100);
591
val2 <<= CCDC_CSCM_MSB_SHIFT;
592
val2 |= val1;
593
regw(val2, (CSCM0 + ((i - 1) << 1)));
594
}
595
}
596
}
597
598
/*
599
* ccdc_config_color_patterns()
600
* configure parameters for color patterns
601
*/
602
static void ccdc_config_color_patterns(struct ccdc_col_pat *pat0,
603
struct ccdc_col_pat *pat1)
604
{
605
u32 val;
606
607
val = (pat0->olop | (pat0->olep << 2) | (pat0->elop << 4) |
608
(pat0->elep << 6) | (pat1->olop << 8) | (pat1->olep << 10) |
609
(pat1->elop << 12) | (pat1->elep << 14));
610
regw(val, COLPTN);
611
}
612
613
/* This function will configure CCDC for Raw mode image capture */
614
static int ccdc_config_raw(void)
615
{
616
struct ccdc_params_raw *params = &ccdc_cfg.bayer;
617
struct ccdc_config_params_raw *config_params =
618
&ccdc_cfg.bayer.config_params;
619
unsigned int val;
620
621
dev_dbg(ccdc_cfg.dev, "\nStarting ccdc_config_raw...");
622
623
/* restore power on defaults to register */
624
ccdc_restore_defaults();
625
626
/* CCDCFG register:
627
* set CCD Not to swap input since input is RAW data
628
* set FID detection function to Latch at V-Sync
629
* set WENLOG - ccdc valid area to AND
630
* set TRGSEL to WENBIT
631
* set EXTRG to DISABLE
632
* disable latching function on VSYNC - shadowed registers
633
*/
634
regw(CCDC_YCINSWP_RAW | CCDC_CCDCFG_FIDMD_LATCH_VSYNC |
635
CCDC_CCDCFG_WENLOG_AND | CCDC_CCDCFG_TRGSEL_WEN |
636
CCDC_CCDCFG_EXTRG_DISABLE | CCDC_LATCH_ON_VSYNC_DISABLE, CCDCFG);
637
638
/*
639
* Set VDHD direction to input, input type to raw input
640
* normal data polarity, do not use external WEN
641
*/
642
val = (CCDC_VDHDOUT_INPUT | CCDC_RAW_IP_MODE | CCDC_DATAPOL_NORMAL |
643
CCDC_EXWEN_DISABLE);
644
645
/*
646
* Configure the vertical sync polarity (MODESET.VDPOL), horizontal
647
* sync polarity (MODESET.HDPOL), field id polarity (MODESET.FLDPOL),
648
* frame format(progressive or interlace), & pixel format (Input mode)
649
*/
650
val |= (((params->vd_pol & CCDC_VD_POL_MASK) << CCDC_VD_POL_SHIFT) |
651
((params->hd_pol & CCDC_HD_POL_MASK) << CCDC_HD_POL_SHIFT) |
652
((params->fid_pol & CCDC_FID_POL_MASK) << CCDC_FID_POL_SHIFT) |
653
((params->frm_fmt & CCDC_FRM_FMT_MASK) << CCDC_FRM_FMT_SHIFT) |
654
((params->pix_fmt & CCDC_PIX_FMT_MASK) << CCDC_PIX_FMT_SHIFT));
655
656
/* set pack for alaw compression */
657
if ((config_params->data_sz == CCDC_DATA_8BITS) ||
658
config_params->alaw.enable)
659
val |= CCDC_DATA_PACK_ENABLE;
660
661
/* Configure for LPF */
662
if (config_params->lpf_enable)
663
val |= (config_params->lpf_enable & CCDC_LPF_MASK) <<
664
CCDC_LPF_SHIFT;
665
666
/* Configure the data shift */
667
val |= (config_params->datasft & CCDC_DATASFT_MASK) <<
668
CCDC_DATASFT_SHIFT;
669
regw(val , MODESET);
670
dev_dbg(ccdc_cfg.dev, "\nWriting 0x%x to MODESET...\n", val);
671
672
/* Configure the Median Filter threshold */
673
regw((config_params->med_filt_thres) & CCDC_MED_FILT_THRESH, MEDFILT);
674
675
/* Configure GAMMAWD register. defaur 11-2, and Mosaic cfa pattern */
676
val = CCDC_GAMMA_BITS_11_2 << CCDC_GAMMAWD_INPUT_SHIFT |
677
CCDC_CFA_MOSAIC;
678
679
/* Enable and configure aLaw register if needed */
680
if (config_params->alaw.enable) {
681
val |= (CCDC_ALAW_ENABLE |
682
((config_params->alaw.gama_wd &
683
CCDC_ALAW_GAMA_WD_MASK) <<
684
CCDC_GAMMAWD_INPUT_SHIFT));
685
}
686
687
/* Configure Median filter1 & filter2 */
688
val |= ((config_params->mfilt1 << CCDC_MFILT1_SHIFT) |
689
(config_params->mfilt2 << CCDC_MFILT2_SHIFT));
690
691
regw(val, GAMMAWD);
692
dev_dbg(ccdc_cfg.dev, "\nWriting 0x%x to GAMMAWD...\n", val);
693
694
/* configure video window */
695
ccdc_setwin(&params->win, params->frm_fmt, 1);
696
697
/* Optical Clamp Averaging */
698
ccdc_config_black_clamp(&config_params->blk_clamp);
699
700
/* Black level compensation */
701
ccdc_config_black_compense(&config_params->blk_comp);
702
703
/* Vertical Defect Correction if needed */
704
if (ccdc_config_vdfc(&config_params->vertical_dft) < 0)
705
return -EFAULT;
706
707
/* color space conversion */
708
ccdc_config_csc(&config_params->csc);
709
710
/* color pattern */
711
ccdc_config_color_patterns(&config_params->col_pat_field0,
712
&config_params->col_pat_field1);
713
714
/* Configure the Gain & offset control */
715
ccdc_config_gain_offset();
716
717
dev_dbg(ccdc_cfg.dev, "\nWriting %x to COLPTN...\n", val);
718
719
/* Configure DATAOFST register */
720
val = (config_params->data_offset.horz_offset & CCDC_DATAOFST_MASK) <<
721
CCDC_DATAOFST_H_SHIFT;
722
val |= (config_params->data_offset.vert_offset & CCDC_DATAOFST_MASK) <<
723
CCDC_DATAOFST_V_SHIFT;
724
regw(val, DATAOFST);
725
726
/* configuring HSIZE register */
727
val = (params->horz_flip_enable & CCDC_HSIZE_FLIP_MASK) <<
728
CCDC_HSIZE_FLIP_SHIFT;
729
730
/* If pack 8 is enable then 1 pixel will take 1 byte */
731
if ((config_params->data_sz == CCDC_DATA_8BITS) ||
732
config_params->alaw.enable) {
733
val |= (((params->win.width) + 31) >> 5) &
734
CCDC_HSIZE_VAL_MASK;
735
736
/* adjust to multiple of 32 */
737
dev_dbg(ccdc_cfg.dev, "\nWriting 0x%x to HSIZE...\n",
738
(((params->win.width) + 31) >> 5) &
739
CCDC_HSIZE_VAL_MASK);
740
} else {
741
/* else one pixel will take 2 byte */
742
val |= (((params->win.width * 2) + 31) >> 5) &
743
CCDC_HSIZE_VAL_MASK;
744
745
dev_dbg(ccdc_cfg.dev, "\nWriting 0x%x to HSIZE...\n",
746
(((params->win.width * 2) + 31) >> 5) &
747
CCDC_HSIZE_VAL_MASK);
748
}
749
regw(val, HSIZE);
750
751
/* Configure SDOFST register */
752
if (params->frm_fmt == CCDC_FRMFMT_INTERLACED) {
753
if (params->image_invert_enable) {
754
/* For interlace inverse mode */
755
regw(CCDC_SDOFST_INTERLACE_INVERSE, SDOFST);
756
dev_dbg(ccdc_cfg.dev, "\nWriting %x to SDOFST...\n",
757
CCDC_SDOFST_INTERLACE_INVERSE);
758
} else {
759
/* For interlace non inverse mode */
760
regw(CCDC_SDOFST_INTERLACE_NORMAL, SDOFST);
761
dev_dbg(ccdc_cfg.dev, "\nWriting %x to SDOFST...\n",
762
CCDC_SDOFST_INTERLACE_NORMAL);
763
}
764
} else if (params->frm_fmt == CCDC_FRMFMT_PROGRESSIVE) {
765
if (params->image_invert_enable) {
766
/* For progessive inverse mode */
767
regw(CCDC_SDOFST_PROGRESSIVE_INVERSE, SDOFST);
768
dev_dbg(ccdc_cfg.dev, "\nWriting %x to SDOFST...\n",
769
CCDC_SDOFST_PROGRESSIVE_INVERSE);
770
} else {
771
/* For progessive non inverse mode */
772
regw(CCDC_SDOFST_PROGRESSIVE_NORMAL, SDOFST);
773
dev_dbg(ccdc_cfg.dev, "\nWriting %x to SDOFST...\n",
774
CCDC_SDOFST_PROGRESSIVE_NORMAL);
775
}
776
}
777
dev_dbg(ccdc_cfg.dev, "\nend of ccdc_config_raw...");
778
return 0;
779
}
780
781
static int ccdc_configure(void)
782
{
783
if (ccdc_cfg.if_type == VPFE_RAW_BAYER)
784
return ccdc_config_raw();
785
else
786
ccdc_config_ycbcr();
787
return 0;
788
}
789
790
static int ccdc_set_buftype(enum ccdc_buftype buf_type)
791
{
792
if (ccdc_cfg.if_type == VPFE_RAW_BAYER)
793
ccdc_cfg.bayer.buf_type = buf_type;
794
else
795
ccdc_cfg.ycbcr.buf_type = buf_type;
796
return 0;
797
}
798
static enum ccdc_buftype ccdc_get_buftype(void)
799
{
800
if (ccdc_cfg.if_type == VPFE_RAW_BAYER)
801
return ccdc_cfg.bayer.buf_type;
802
return ccdc_cfg.ycbcr.buf_type;
803
}
804
805
static int ccdc_enum_pix(u32 *pix, int i)
806
{
807
int ret = -EINVAL;
808
if (ccdc_cfg.if_type == VPFE_RAW_BAYER) {
809
if (i < ARRAY_SIZE(ccdc_raw_bayer_pix_formats)) {
810
*pix = ccdc_raw_bayer_pix_formats[i];
811
ret = 0;
812
}
813
} else {
814
if (i < ARRAY_SIZE(ccdc_raw_yuv_pix_formats)) {
815
*pix = ccdc_raw_yuv_pix_formats[i];
816
ret = 0;
817
}
818
}
819
return ret;
820
}
821
822
static int ccdc_set_pixel_format(u32 pixfmt)
823
{
824
struct ccdc_a_law *alaw = &ccdc_cfg.bayer.config_params.alaw;
825
826
if (ccdc_cfg.if_type == VPFE_RAW_BAYER) {
827
ccdc_cfg.bayer.pix_fmt = CCDC_PIXFMT_RAW;
828
if (pixfmt == V4L2_PIX_FMT_SBGGR8)
829
alaw->enable = 1;
830
else if (pixfmt != V4L2_PIX_FMT_SBGGR16)
831
return -EINVAL;
832
} else {
833
if (pixfmt == V4L2_PIX_FMT_YUYV)
834
ccdc_cfg.ycbcr.pix_order = CCDC_PIXORDER_YCBYCR;
835
else if (pixfmt == V4L2_PIX_FMT_UYVY)
836
ccdc_cfg.ycbcr.pix_order = CCDC_PIXORDER_CBYCRY;
837
else
838
return -EINVAL;
839
}
840
return 0;
841
}
842
static u32 ccdc_get_pixel_format(void)
843
{
844
struct ccdc_a_law *alaw = &ccdc_cfg.bayer.config_params.alaw;
845
u32 pixfmt;
846
847
if (ccdc_cfg.if_type == VPFE_RAW_BAYER)
848
if (alaw->enable)
849
pixfmt = V4L2_PIX_FMT_SBGGR8;
850
else
851
pixfmt = V4L2_PIX_FMT_SBGGR16;
852
else {
853
if (ccdc_cfg.ycbcr.pix_order == CCDC_PIXORDER_YCBYCR)
854
pixfmt = V4L2_PIX_FMT_YUYV;
855
else
856
pixfmt = V4L2_PIX_FMT_UYVY;
857
}
858
return pixfmt;
859
}
860
static int ccdc_set_image_window(struct v4l2_rect *win)
861
{
862
if (ccdc_cfg.if_type == VPFE_RAW_BAYER)
863
ccdc_cfg.bayer.win = *win;
864
else
865
ccdc_cfg.ycbcr.win = *win;
866
return 0;
867
}
868
869
static void ccdc_get_image_window(struct v4l2_rect *win)
870
{
871
if (ccdc_cfg.if_type == VPFE_RAW_BAYER)
872
*win = ccdc_cfg.bayer.win;
873
else
874
*win = ccdc_cfg.ycbcr.win;
875
}
876
877
static unsigned int ccdc_get_line_length(void)
878
{
879
struct ccdc_config_params_raw *config_params =
880
&ccdc_cfg.bayer.config_params;
881
unsigned int len;
882
883
if (ccdc_cfg.if_type == VPFE_RAW_BAYER) {
884
if ((config_params->alaw.enable) ||
885
(config_params->data_sz == CCDC_DATA_8BITS))
886
len = ccdc_cfg.bayer.win.width;
887
else
888
len = ccdc_cfg.bayer.win.width * 2;
889
} else
890
len = ccdc_cfg.ycbcr.win.width * 2;
891
return ALIGN(len, 32);
892
}
893
894
static int ccdc_set_frame_format(enum ccdc_frmfmt frm_fmt)
895
{
896
if (ccdc_cfg.if_type == VPFE_RAW_BAYER)
897
ccdc_cfg.bayer.frm_fmt = frm_fmt;
898
else
899
ccdc_cfg.ycbcr.frm_fmt = frm_fmt;
900
return 0;
901
}
902
903
static enum ccdc_frmfmt ccdc_get_frame_format(void)
904
{
905
if (ccdc_cfg.if_type == VPFE_RAW_BAYER)
906
return ccdc_cfg.bayer.frm_fmt;
907
else
908
return ccdc_cfg.ycbcr.frm_fmt;
909
}
910
911
static int ccdc_getfid(void)
912
{
913
return (regr(MODESET) >> 15) & 1;
914
}
915
916
/* misc operations */
917
static inline void ccdc_setfbaddr(unsigned long addr)
918
{
919
regw((addr >> 21) & 0x007f, STADRH);
920
regw((addr >> 5) & 0x0ffff, STADRL);
921
}
922
923
static int ccdc_set_hw_if_params(struct vpfe_hw_if_param *params)
924
{
925
ccdc_cfg.if_type = params->if_type;
926
927
switch (params->if_type) {
928
case VPFE_BT656:
929
case VPFE_YCBCR_SYNC_16:
930
case VPFE_YCBCR_SYNC_8:
931
ccdc_cfg.ycbcr.vd_pol = params->vdpol;
932
ccdc_cfg.ycbcr.hd_pol = params->hdpol;
933
break;
934
default:
935
/* TODO add support for raw bayer here */
936
return -EINVAL;
937
}
938
return 0;
939
}
940
941
static struct ccdc_hw_device ccdc_hw_dev = {
942
.name = "DM355 CCDC",
943
.owner = THIS_MODULE,
944
.hw_ops = {
945
.open = ccdc_open,
946
.close = ccdc_close,
947
.enable = ccdc_enable,
948
.enable_out_to_sdram = ccdc_enable_output_to_sdram,
949
.set_hw_if_params = ccdc_set_hw_if_params,
950
.set_params = ccdc_set_params,
951
.configure = ccdc_configure,
952
.set_buftype = ccdc_set_buftype,
953
.get_buftype = ccdc_get_buftype,
954
.enum_pix = ccdc_enum_pix,
955
.set_pixel_format = ccdc_set_pixel_format,
956
.get_pixel_format = ccdc_get_pixel_format,
957
.set_frame_format = ccdc_set_frame_format,
958
.get_frame_format = ccdc_get_frame_format,
959
.set_image_window = ccdc_set_image_window,
960
.get_image_window = ccdc_get_image_window,
961
.get_line_length = ccdc_get_line_length,
962
.setfbaddr = ccdc_setfbaddr,
963
.getfid = ccdc_getfid,
964
},
965
};
966
967
static int __init dm355_ccdc_probe(struct platform_device *pdev)
968
{
969
void (*setup_pinmux)(void);
970
struct resource *res;
971
int status = 0;
972
973
/*
974
* first try to register with vpfe. If not correct platform, then we
975
* don't have to iomap
976
*/
977
status = vpfe_register_ccdc_device(&ccdc_hw_dev);
978
if (status < 0)
979
return status;
980
981
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
982
if (!res) {
983
status = -ENODEV;
984
goto fail_nores;
985
}
986
987
res = request_mem_region(res->start, resource_size(res), res->name);
988
if (!res) {
989
status = -EBUSY;
990
goto fail_nores;
991
}
992
993
ccdc_cfg.base_addr = ioremap_nocache(res->start, resource_size(res));
994
if (!ccdc_cfg.base_addr) {
995
status = -ENOMEM;
996
goto fail_nomem;
997
}
998
999
/* Get and enable Master clock */
1000
ccdc_cfg.mclk = clk_get(&pdev->dev, "master");
1001
if (IS_ERR(ccdc_cfg.mclk)) {
1002
status = PTR_ERR(ccdc_cfg.mclk);
1003
goto fail_nomap;
1004
}
1005
if (clk_enable(ccdc_cfg.mclk)) {
1006
status = -ENODEV;
1007
goto fail_mclk;
1008
}
1009
1010
/* Get and enable Slave clock */
1011
ccdc_cfg.sclk = clk_get(&pdev->dev, "slave");
1012
if (IS_ERR(ccdc_cfg.sclk)) {
1013
status = PTR_ERR(ccdc_cfg.sclk);
1014
goto fail_mclk;
1015
}
1016
if (clk_enable(ccdc_cfg.sclk)) {
1017
status = -ENODEV;
1018
goto fail_sclk;
1019
}
1020
1021
/* Platform data holds setup_pinmux function ptr */
1022
if (NULL == pdev->dev.platform_data) {
1023
status = -ENODEV;
1024
goto fail_sclk;
1025
}
1026
setup_pinmux = pdev->dev.platform_data;
1027
/*
1028
* setup Mux configuration for ccdc which may be different for
1029
* different SoCs using this CCDC
1030
*/
1031
setup_pinmux();
1032
ccdc_cfg.dev = &pdev->dev;
1033
printk(KERN_NOTICE "%s is registered with vpfe.\n", ccdc_hw_dev.name);
1034
return 0;
1035
fail_sclk:
1036
clk_put(ccdc_cfg.sclk);
1037
fail_mclk:
1038
clk_put(ccdc_cfg.mclk);
1039
fail_nomap:
1040
iounmap(ccdc_cfg.base_addr);
1041
fail_nomem:
1042
release_mem_region(res->start, resource_size(res));
1043
fail_nores:
1044
vpfe_unregister_ccdc_device(&ccdc_hw_dev);
1045
return status;
1046
}
1047
1048
static int dm355_ccdc_remove(struct platform_device *pdev)
1049
{
1050
struct resource *res;
1051
1052
clk_put(ccdc_cfg.mclk);
1053
clk_put(ccdc_cfg.sclk);
1054
iounmap(ccdc_cfg.base_addr);
1055
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
1056
if (res)
1057
release_mem_region(res->start, resource_size(res));
1058
vpfe_unregister_ccdc_device(&ccdc_hw_dev);
1059
return 0;
1060
}
1061
1062
static struct platform_driver dm355_ccdc_driver = {
1063
.driver = {
1064
.name = "dm355_ccdc",
1065
.owner = THIS_MODULE,
1066
},
1067
.remove = __devexit_p(dm355_ccdc_remove),
1068
.probe = dm355_ccdc_probe,
1069
};
1070
1071
static int __init dm355_ccdc_init(void)
1072
{
1073
return platform_driver_register(&dm355_ccdc_driver);
1074
}
1075
1076
static void __exit dm355_ccdc_exit(void)
1077
{
1078
platform_driver_unregister(&dm355_ccdc_driver);
1079
}
1080
1081
module_init(dm355_ccdc_init);
1082
module_exit(dm355_ccdc_exit);
1083
1084