Commit 1809d055 authored by Oleg Dzhimiev's avatar Oleg Dzhimiev

Merge branch 'master' of https://github.com/Elphel/linux-elphel

parents 892b1912 2fd99c36
......@@ -83,6 +83,10 @@ static struct device *g_dev_ptr;
static const struct of_device_id elphel393_circbuf_of_match[];
/* debug code */
//extern long long zero_counter[IMAGE_CHN_NUM];
/* end of debug code*/
int init_ccam_dma_buf_ptr(struct platform_device *pdev)
{
int i;
......@@ -107,7 +111,7 @@ int init_ccam_dma_buf_ptr(struct platform_device *pdev)
}
// set circular buffer size in bytes
set_globalParam(G_CIRCBUFSIZE, CCAM_DMA_SIZE);
// set_globalParam(G_CIRCBUFSIZE, CCAM_DMA_SIZE);
for (i = 0; i < IMAGE_CHN_NUM; i++) {
circbuf_priv[i].buf_ptr = ccam_dma_buf_ptr + BYTE2DW(CIRCBUF_START_OFFSET + i * CCAM_DMA_SIZE);
......@@ -268,25 +272,39 @@ int circbuf_open(struct inode *inode, struct file *filp)
return 0;
}
void dump_interframe_params(struct interframe_params_t *params, int offset)
void dump_interframe_params(struct interframe_params_t *params, int offset, unsigned int chn)
{
dev_dbg(g_dev_ptr, "Dump of interframe parameters at offset 0x%x:\n", offset);
dev_dbg(g_dev_ptr, "Dump of interframe parameters at offset 0x%x [chn %u]:\n", offset, chn);
print_hex_dump_bytes("", DUMP_PREFIX_OFFSET, params, sizeof(struct interframe_params_t) - 4);
}
/**
* @brief
* @brief Get the length of an image before given pointer
*/
unsigned long get_image_length(int byte_offset, unsigned int chn, int *last_chunk_offset)
{
unsigned int offset;
unsigned long len32;
int last_image_chunk = byte_offset - OFFSET_X40;
if (last_image_chunk < 0)
last_image_chunk += CCAM_DMA_SIZE;
len32 = circbuf_priv[chn].buf_ptr[BYTE2DW(last_image_chunk + (CHUNK_SIZE - CCAM_MMAP_META_LENGTH))];
int last_image_chunk = X393_BUFFSUB(byte_offset, OFFSET_X40);
offset = X393_BUFFADD(last_image_chunk, CHUNK_SIZE - CCAM_MMAP_META_LENGTH);
len32 = circbuf_priv[chn].buf_ptr[BYTE2DW(offset)];
dev_dbg(g_dev_ptr, "[chn %d] byte_offset = 0x%x, calculated offset = 0x%x, len32 = 0x%lx\n", chn, byte_offset, offset, len32);
if ((len32 & MARKER_FF) != MARKER_FF) {
dev_dbg(g_dev_ptr, "[chn %u] failed to get 0xff marker at offset 0x%x\n", chn, offset);
// byte_offset = X393_BUFFSUB(byte_offset, CHUNK_SIZE);
last_image_chunk = X393_BUFFSUB(byte_offset, OFFSET_X40 + CHUNK_SIZE);
offset = X393_BUFFADD(last_image_chunk, CHUNK_SIZE - CCAM_MMAP_META_LENGTH);
len32 = circbuf_priv[chn].buf_ptr[BYTE2DW(offset)];
if ((len32 & MARKER_FF) != MARKER_FF) {
dev_dbg(g_dev_ptr, "[chn %u] failed to get 0xff marker at CORRECTED offset 0x%x\n", chn, offset);
return 0;
}
}
dev_dbg(g_dev_ptr, "got len32 = 0x%lx at 0x%x\n", len32, last_image_chunk + (CHUNK_SIZE - CCAM_MMAP_META_LENGTH));
dev_dbg(g_dev_ptr, "[chn %u] got len32 = 0x%lx at 0x%x\n", chn, len32, offset);
if (last_chunk_offset != NULL)
*last_chunk_offset = last_image_chunk;
......@@ -301,17 +319,19 @@ unsigned long get_image_length(int byte_offset, unsigned int chn, int *last_chun
* frame header before \e rp and will point to its parameters
* @param[in] chn specify compressor channel number which pointer should be checked
* @return 0 if the pointer is for the frame yet to be acquired, 1 if there is a valid frame at this address,
* 2 if file pointer should be advanced by 32 bytes,
* -1 if there is no frame at this index, -2 if the pointer is not 32-bytes aligned
* sets *fpp to the frame header, including signature and length
*/
int circbuf_valid_ptr(int rp, struct interframe_params_t **fpp, unsigned int chn)
int circbuf_valid_ptr(loff_t *rp_offset, struct interframe_params_t **fpp, unsigned int chn)
{
int rp = *rp_offset;
int last_image_chunk;
unsigned int sec;
unsigned int usec;
int wp = camseq_get_jpeg_wp(chn);
unsigned int len32 = get_image_length(DW2BYTE(wp), chn, &last_image_chunk);
struct interframe_params_t *fp;
struct interframe_params_t *fp, *fp_off;
if (rp & 0x1f) {
// rp is not 32-bytes aligned
......@@ -321,20 +341,41 @@ int circbuf_valid_ptr(int rp, struct interframe_params_t **fpp, unsigned int chn
fp = (struct interframe_params_t *) &circbuf_priv[chn].buf_ptr[BYTE2DW(X393_BUFFSUB(rp, sizeof(struct interframe_params_t) - 4))];
*fpp = fp;
dump_interframe_params(fp, X393_BUFFSUB(rp, sizeof(struct interframe_params_t) - 4));
dump_interframe_params(fp, X393_BUFFSUB(rp, sizeof(struct interframe_params_t) - 4), chn);
if (BYTE2DW(rp) == wp)
// read pointer and write pointer coincide, frame not yet acquired
return 0;
if (fp->signffff != MARKER_FFFF) {
dev_dbg(g_dev_ptr, "interframe signature is overwritten\n");
return -1;
dev_dbg(g_dev_ptr, "[chn %u] interframe signature is overwritten, signffff = 0x%x\n", chn, fp->signffff);
fp_off = (struct interframe_params_t *) &circbuf_priv[chn].buf_ptr[BYTE2DW(rp)];
if (fp_off->signffff != MARKER_FFFF) {
dev_dbg(g_dev_ptr, "[chn %u] interframe signature is overwritten at CORRECTED offset, signffff = 0x%x\n", chn, fp_off->signffff);
return -1;
} else {
dev_dbg(g_dev_ptr, "[chn %u] interframe pointer and file ponter is advanced by 0x20\n", chn);
*fpp = fp_off;
*rp_offset = X393_BUFFADD(*rp_offset, CHUNK_SIZE);
dump_interframe_params(fp_off, rp, chn);
return 2;
}
}
return 1;
}
/**
* @brief Get image start offset pointed by its last data chunk
* @param[in] last_chunk_offset offset of the last image data chunk
* @param[in] len32 length of image
* @return image start offset
*/
inline int get_image_start(int last_chunk_offset, unsigned int len32)
{
return X393_BUFFSUB(last_chunk_offset + CHUNK_SIZE - INSERTED_BYTES(len32) - CCAM_MMAP_META, len32);
}
/**
* @brief Reposition read/write file offset
*
......@@ -380,10 +421,65 @@ int circbuf_valid_ptr(int rp, struct interframe_params_t **fpp, unsigned int chn
* @param[in] orig origin
* @return current file pointer position if operation was successful and error code otherwise
*/
/* debug code follows */
void stop_compressor(unsigned int chn)
{
x393_cmprs_mode_t mode;
mode.run = 1;
mode.run_set = 1;
x393_cmprs_control_reg(mode, chn);
}
void dump_state(unsigned int chn)
{
int img_start, last_image_chunk;
int len32;
int prev_ptr, prevprev_ptr;
int read_ptr = DW2BYTE(camseq_get_jpeg_wp(chn));
unsigned int nf, nz;
struct interframe_params_t *fp;
nf = 0;
nz = 1;
printk(KERN_DEBUG "=== start of state dump, chn = %d ===\n", chn);
printk(KERN_DEBUG "hardware pointer at 0x%x\n", read_ptr);
// move to the beginning of last frame
len32 = get_image_length(read_ptr, chn, &last_image_chunk);
if ((len32 & MARKER_FF) != MARKER_FF) {
printk(KERN_DEBUG "last acquired frame at location 0x%x is damaged\n", read_ptr);
return;
}
len32 &= FRAME_LENGTH_MASK;
//img_start = X393_BUFFSUB(last_image_chunk + CHUNK_SIZE - INSERTED_BYTES(len32) - CCAM_MMAP_META, len32);
img_start = get_image_start(last_image_chunk, len32);
read_ptr = img_start;
// move back in history
while ((circbuf_valid_ptr(&read_ptr, &fp, chn) >= 0) && (nz >= 0)) {
printk(KERN_DEBUG "analyzing frame starting at 0x%x\n", read_ptr);
//printk(KERN_DEBUG "mem dump of 0x40 bytes at (pointer - 0x20) = 0x%x:\n", read_ptr - OFFSET_X40 / 2);
//print_hex_dump_bytes("\t\t", DUMP_PREFIX_OFFSET, &circbuf_priv[chn].buf_ptr[BYTE2DW(read_ptr - OFFSET_X40 / 2)], OFFSET_X40);
nf++;
prevprev_ptr = prev_ptr;
prev_ptr = read_ptr;
len32 = get_image_length(read_ptr, chn, &last_image_chunk);
if ((len32 & MARKER_FF) != MARKER_FF) {
printk(KERN_DEBUG "\t\tno image before 0x%x\n", read_ptr);
break;
}
len32 &= FRAME_LENGTH_MASK;
//printk(KERN_DEBUG "\t\tgot len32 = 0x%x", len32);
//img_start = X393_BUFFSUB(last_image_chunk + CHUNK_SIZE - INSERTED_BYTES(len32) - CCAM_MMAP_META, len32);
img_start = get_image_start(last_image_chunk, len32);
read_ptr = img_start;
if (read_ptr > prev_ptr)
nz--;
}
printk(KERN_DEBUG "=== end of state dump, %d frame(s) analyzed ===\n", nf);
}
/* end of debug code */
loff_t circbuf_lseek(struct file *file, loff_t offset, int orig)
{
unsigned int len32 = 0;
int inserted_bytes;
int last_image_chunk;
int img_start, next_img, padded_frame;
unsigned int minor = MINOR(file->f_inode->i_rdev);
......@@ -391,7 +487,7 @@ loff_t circbuf_lseek(struct file *file, loff_t offset, int orig)
struct interframe_params_t * fp;
int fvld = -1;
int rp, bp;
dev_dbg(g_dev_ptr, "start processing LSEEK operation: offset = 0x%x, orig = 0x%x\n",(int) offset, (int) orig);
dev_dbg(g_dev_ptr, "start processing LSEEK operation: offset = 0x%x, orig = 0x%x, file->f_pos = 0x%llx\n",(int) offset, (int) orig, file->f_pos);
switch (orig) {
case SEEK_SET:
......@@ -399,7 +495,7 @@ loff_t circbuf_lseek(struct file *file, loff_t offset, int orig)
break;
case SEEK_CUR:
if (offset) file->f_pos += offset;
else if (circbuf_valid_ptr(file->f_pos, &fp, chn) < 0 ) return -EINVAL; //!no frames at the specified location or pointer is not 32-byte aligned
else if (circbuf_valid_ptr(&file->f_pos, &fp, chn) < 0 ) return -EINVAL; //!no frames at the specified location or pointer is not 32-byte aligned
break;
case SEEK_END:
if (offset <= 0) {
......@@ -416,16 +512,28 @@ loff_t circbuf_lseek(struct file *file, loff_t offset, int orig)
case LSEEK_CIRC_READY:
case LSEEK_CIRC_FREE:
case LSEEK_CIRC_USED:
if ((fvld = circbuf_valid_ptr(file->f_pos, &fp, chn)) < 0)
if ((fvld = circbuf_valid_ptr(&file->f_pos, &fp, chn)) < 0)
return -EINVAL; // no frames at the specified location
break;
/* debug code follows */
case LSEEK_CIRC_STOP_COMPRESSOR:
{
int s;
dev_dbg(g_dev_ptr, "stopping all compressors, current channel %d, fvld = %d, file->f_pos = 0x%llx\n", chn, fvld, file->f_pos);
for (s = 0; s < IMAGE_CHN_NUM; s++)
stop_compressor(s);
dump_state(chn);
}
break;
/* end of debug code */
}
switch (offset) {
case LSEEK_CIRC_FREE:
dev_dbg(g_dev_ptr, "LSEEK_CIRC_FREE: checking remaining memory in circbuf\n");
dev_dbg(g_dev_ptr, "[chn %u] LSEEK_CIRC_FREE: checking remaining memory in circbuf\n", chn);
bp = file->f_pos - (camseq_get_jpeg_wp(chn) << 2);
return (file->f_pos = (bp > 0) ? bp : (bp + CCAM_DMA_SIZE)); //!Has a side effect of moving a file pointer!
case LSEEK_CIRC_USED:
dev_dbg(g_dev_ptr, "LSEEK_CIRC_USED: checking used memory in circbuf\n");
dev_dbg(g_dev_ptr, "[chn %u] LSEEK_CIRC_USED: checking used memory in circbuf\n", chn);
bp = (camseq_get_jpeg_wp(chn) << 2) - file->f_pos;
return (file->f_pos = (bp > 0) ? bp : (bp + CCAM_DMA_SIZE)); //!Has a side effect of moving a file pointer!
case LSEEK_CIRC_TORP:
......@@ -437,100 +545,113 @@ loff_t circbuf_lseek(struct file *file, loff_t offset, int orig)
case LSEEK_CIRC_LAST:
next_img = camseq_get_jpeg_wp(chn) << 2;
dev_dbg(g_dev_ptr, "LSEEK_CIRC_LAST: next_img = 0x%x, fvld = %d\n", next_img, fvld);
dev_dbg(g_dev_ptr, "mem dump of last 0x40 bytes in buffer number %d\n", chn);
dev_dbg(g_dev_ptr, "[chn %u] LSEEK_CIRC_LAST: next_img = 0x%x, fvld = %d\n", chn, next_img, fvld);
dev_dbg(g_dev_ptr, "[chn %u] mem dump of last 0x40 bytes in buffer\n", chn);
print_hex_dump_bytes("", DUMP_PREFIX_OFFSET, &circbuf_priv[chn].buf_ptr[BYTE2DW(next_img - OFFSET_X40)], OFFSET_X40);
len32 = get_image_length(next_img, chn, &last_image_chunk);
if ((len32 & MARKER_FF) != MARKER_FF) {
// we should not be here as the position was checked in circbufValidPointer
dev_dbg(g_dev_ptr, "failed to get marker 0xFF at 0x%x, len32: 0x%x\n", next_img, len32);
dev_dbg(g_dev_ptr, "[chn %u] failed to get marker 0xFF at 0x%x, len32: 0x%x\n", chn, next_img, len32);
return -EOVERFLOW;
}
len32 &= FRAME_LENGTH_MASK;
img_start = X393_BUFFSUB(last_image_chunk + CHUNK_SIZE - INSERTED_BYTES(len32) - CCAM_MMAP_META, len32);
dev_dbg(g_dev_ptr, "calculated start address = 0x%x, length = 0x%x\n", img_start, len32);
if (circbuf_valid_ptr(img_start, &fp, chn) < 0)
//img_start = X393_BUFFSUB(last_image_chunk + CHUNK_SIZE - INSERTED_BYTES(len32) - CCAM_MMAP_META, len32);
img_start = get_image_start(last_image_chunk, len32);
dev_dbg(g_dev_ptr, "[chn %u] calculated start address = 0x%x, length = 0x%x\n", chn, img_start, len32);
if (circbuf_valid_ptr(&img_start, &fp, chn) < 0)
return -EOVERFLOW;
file->f_pos = img_start;
dev_dbg(g_dev_ptr, "LSEEK_CIRC_LAST: moving file->f_pos to 0x%llx\n", file->f_pos);
dev_dbg(g_dev_ptr, "[chn %u] LSEEK_CIRC_LAST: moving file->f_pos to 0x%llx\n", chn, file->f_pos);
break;
case LSEEK_CIRC_PREV:
rp = file->f_pos;
fvld = circbuf_valid_ptr(rp, &fp, chn);
fvld = circbuf_valid_ptr(&rp, &fp, chn);
dev_dbg(g_dev_ptr, "LSEEK_CIRC_PREV: rp = 0x%x, fvld = %d\n", rp, fvld);
dev_dbg(g_dev_ptr, "mem dump of last 0x40 bytes in buffer number %d\n", chn);
dev_dbg(g_dev_ptr, "[chn %u] LSEEK_CIRC_PREV: rp = 0x%x, fvld = %d\n", chn, rp, fvld);
dev_dbg(g_dev_ptr, "[chn %u] mem dump of last 0x40 bytes in buffer number %d\n", chn, chn);
print_hex_dump_bytes("", DUMP_PREFIX_OFFSET, &circbuf_priv[chn].buf_ptr[BYTE2DW(rp - OFFSET_X40)], OFFSET_X40);
len32 = get_image_length(rp, chn, &last_image_chunk);
if ((len32 & MARKER_FF) != MARKER_FF) {
// we should not be here as the position was checked in circbufValidPointer
dev_dbg(g_dev_ptr, "failed to get marker 0xFF at 0x%x, len32: 0x%x\n", rp, len32);
dev_dbg(g_dev_ptr, "[chn %u] failed to get marker 0xFF at 0x%x, len32: 0x%x\n", chn, rp, len32);
return -EOVERFLOW;
}
len32 &= FRAME_LENGTH_MASK;
img_start = X393_BUFFSUB(last_image_chunk + CHUNK_SIZE - INSERTED_BYTES(len32) - CCAM_MMAP_META, len32);
dev_dbg(g_dev_ptr, "LSEEK_CIRC_PREV: calculated start address = 0x%x, length = 0x%x\n", img_start, len32);
//img_start = X393_BUFFSUB(last_image_chunk + CHUNK_SIZE - INSERTED_BYTES(len32) - CCAM_MMAP_META, len32);
img_start = get_image_start(last_image_chunk, len32);
dev_dbg(g_dev_ptr, "[chn %u] LSEEK_CIRC_PREV: calculated start address = 0x%x, length = 0x%x\n", chn, img_start, len32);
// move file pointer only if previous frame valid
len32 = get_image_length(img_start, chn, NULL);
if (circbuf_valid_ptr(img_start, &fp, chn) < 0)
if (circbuf_valid_ptr(&img_start, &fp, chn) < 0)
return -EOVERFLOW;
file->f_pos = img_start;
break;
case LSEEK_CIRC_NEXT:
dev_dbg(g_dev_ptr, "LSEEK_CIRC_NEXT: file->f_pos = 0x%lx, fvld = %d, fp->len32 = 0x%lx\n", file->f_pos, fvld, fp->frame_length);
if (fvld <= 0)
dev_dbg(g_dev_ptr, "[chn %u] LSEEK_CIRC_NEXT: file->f_pos = 0x%llx, fvld = %d, fp->len32 = 0x%lx\n", chn,
file->f_pos, fvld, fp->frame_length);
if (fvld <= 0) {
return -EOVERFLOW; //! no frames after current
} else if (fvld == 2) {
//file->f_pos += CHUNK_SIZE;
dev_dbg(g_dev_ptr, "[chn %u] read pointer file->f_pos was advanced by 0x20 bytes\n", chn);
}
// calculate the full length of current frame and advance file pointer by this value
padded_frame = fp->frame_length + INSERTED_BYTES(fp->frame_length) + CHUNK_SIZE + CCAM_MMAP_META;
file->f_pos = X393_BUFFADD(file->f_pos, padded_frame); // do it even if the next frame does not yet exist
dev_dbg(g_dev_ptr, "LSEEK_CIRC_NEXT: moving file->f_pos to 0x%llx\n", file->f_pos);
dev_dbg(g_dev_ptr, "[chn %u] LSEEK_CIRC_NEXT: padded_frame = %d; moving file->f_pos to 0x%llx\n", chn, padded_frame, file->f_pos);
break;
case LSEEK_CIRC_FIRST:
case LSEEK_CIRC_SCND:
{
int nf = 0; // number of frames;
int nz = 1; // number of start crossing of the circular buffer (counter to prevent looping forever)
int rp_b;
int prev_p, preprev_p;
// starting from the write pointer to be able to count all the frames in the buffer
rp = camseq_get_jpeg_wp(chn);
prev_p = preprev_p = rp;
prev_p = preprev_p = DW2BYTE(rp);
file->f_pos = DW2BYTE(rp);
while (((fvld = circbuf_valid_ptr(DW2BYTE(rp), &fp, chn)) >= 0) & (nz >= 0)) {
rp_b = DW2BYTE(rp);
while (((fvld = circbuf_valid_ptr(&rp_b, &fp, chn)) >= 0) & (nz >= 0)) {
nf++;
preprev_p = prev_p; // second known good (at least first one)
prev_p=rp; // now - current, known good
len32 = get_image_length(DW2BYTE(rp), chn, &last_image_chunk);
dev_dbg(g_dev_ptr, "LSEEK_CIRC_FIRST or LSEEK_CIRC_SCND: number of frames = %d, rp = 0x%x, fvld = %d, len32 = 0x%x", nf, rp, fvld, len32);
prev_p=rp_b; // now - current, known good
len32 = get_image_length(rp_b, chn, &last_image_chunk);
dev_dbg(g_dev_ptr, "[chn %u] LSEEK_CIRC_FIRST or LSEEK_CIRC_SCND: number of frames = %d, rp_b = 0x%x, fvld = %d, len32 = 0x%x", chn,
nf, rp_b, fvld, len32);
if ((len32 & MARKER_FF) != MARKER_FF ) break; //! no frames before rp (==prev_p)
//! move rp to the previous frame
len32 &= FRAME_LENGTH_MASK;
img_start = X393_BUFFSUB(last_image_chunk + CHUNK_SIZE - INSERTED_BYTES(len32) - CCAM_MMAP_META, len32);
dev_dbg(g_dev_ptr, "LSEEK_CIRC_FIRST or LSEEK_CIRC_SCND: calculated start address = 0x%x, length = 0x%x\n", img_start, len32);
rp = BYTE2DW(img_start);
if (rp > prev_p) nz--; // rolled through zero - make sure we'll not stuck in this loop forever
//img_start = X393_BUFFSUB(last_image_chunk + CHUNK_SIZE - INSERTED_BYTES(len32) - CCAM_MMAP_META, len32);
img_start = get_image_start(last_image_chunk, len32);
dev_dbg(g_dev_ptr, "[chn %u] LSEEK_CIRC_FIRST or LSEEK_CIRC_SCND: calculated start address = 0x%x, length = 0x%x\n", chn,
img_start, len32);
rp_b = img_start;
if (rp_b > prev_p) nz--; // rolled through zero - make sure we'll not stuck in this loop forever
}
dev_dbg(g_dev_ptr, "LSEEK_CIRC_FIRST or LSEEK_CIRC_SCND: finish stepping back through frames, number of frames = %d, rp = 0x%x, fvld = %d, len32 = 0x%x", nf, rp, fvld, len32);
dev_dbg(g_dev_ptr, "[chn %u] LSEEK_CIRC_FIRST or LSEEK_CIRC_SCND: finish stepping back through frames, number of frames = %d, rp = 0x%x, fvld = %d, len32 = 0x%x",
chn, nf, rp, fvld, len32);
file->f_pos = ((offset == LSEEK_CIRC_SCND) ? preprev_p : prev_p) << 2;
break;
}
case LSEEK_CIRC_SETP:
dev_dbg(g_dev_ptr, "LSEK_CIRC_SETP: Setting jpeg_rp for channel %d to file->f_pos = 0x%llx\n", chn, file->f_pos);
dev_dbg(g_dev_ptr, "[chn %u] LSEK_CIRC_SETP: Setting jpeg_rp for channel %d to file->f_pos = 0x%llx\n", chn, chn, file->f_pos);
camseq_set_jpeg_rp(chn, file->f_pos >> 2);
break;
case LSEEK_CIRC_VALID:
// no actions to be done here, the pointer was checked on previous step
dev_dbg(g_dev_ptr, "LSEEK_CIRC_VALID: no action required\n");
dev_dbg(g_dev_ptr, "[chn %u] LSEEK_CIRC_VALID: no action required, fvld = %d, file->f_pos = 0x%llx\n", chn, fvld, file->f_pos);
break;
case LSEEK_CIRC_READY:
dev_dbg(g_dev_ptr, "LSEEK_CIRC_READY: checking fvld, fvld = %d\n", fvld);
dev_dbg(g_dev_ptr, "[chn %u] LSEEK_CIRC_READY: checking fvld, fvld = %d, file->f_pos = 0x%llx\n", chn, fvld, file->f_pos);
if (fvld <= 0) return -EINVAL; // no frame is available better code?
break;
case LSEEK_CIRC_WAIT:
dev_dbg(g_dev_ptr, "LSEEK_CIRC_WAIT\n");
while (((fvld=circbuf_valid_ptr(file->f_pos, &fp, chn)))==0) { // only while not ready, ready or BAD - return
dev_dbg(g_dev_ptr, "[chn %u] LSEEK_CIRC_WAIT: fvld = %d, file->f_pos = 0x%llx\n", chn, fvld, file->f_pos);
while (((fvld=circbuf_valid_ptr(&file->f_pos, &fp, chn)))==0) { // only while not ready, ready or BAD - return
wait_event_interruptible(circbuf_wait_queue, (camseq_get_jpeg_wp(chn) << 2) != file->f_pos);
}
if (fvld < 0) return -ESPIPE; // invalid seek - have better code?
......@@ -540,6 +661,7 @@ loff_t circbuf_lseek(struct file *file, loff_t offset, int orig)
wait_event_interruptible(circbuf_wait_queue, get_imageParamsThis(P_DAEMON_EN) & (1<<(offset & 0x1f)));
}
}
dev_dbg(g_dev_ptr, "[chn %u] finish SEEK_END processing; return file->f_pos = %lld\n", chn, file->f_pos);
return ( file->f_pos ); // file position >= 0
}
break;
......@@ -550,6 +672,7 @@ loff_t circbuf_lseek(struct file *file, loff_t offset, int orig)
while (file->f_pos < 0) file->f_pos += CCAM_DMA_SIZE;
while (file->f_pos > CCAM_DMA_SIZE) file->f_pos -= CCAM_DMA_SIZE;
if ((orig !=SEEK_END) && (file->f_pos == CCAM_DMA_SIZE)) file->f_pos=0; // only for lseek(fd,0,SEEK_END) the result will be file size, others will roll to 0
dev_dbg(g_dev_ptr, "[chn %u] return file->f_pos = %lld\n", chn, file->f_pos);
return file->f_pos ;
}
......@@ -562,12 +685,17 @@ loff_t circbuf_lseek(struct file *file, loff_t offset, int orig)
* @param[in] off offset
* @return number of bytes read form \e buf
*/
unsigned short circbuf_quality = 100;
ssize_t circbuf_write(struct file *file, const char *buf, size_t count, loff_t *off)
{
unsigned long p;
unsigned int minor = MINOR(file->f_inode->i_rdev);
unsigned int chn = minor_to_chn(minor, NULL);
dev_dbg(g_dev_ptr, "minor = 0x%x, count = 0x%x, off = 0x%lx", minor, count, off);
int i;
int ret;
long val;
char *buf_copy = (char *)buf;
dev_dbg(g_dev_ptr, "minor = 0x%x, count = 0x%x, off = 0x%llx", minor, count, off);
/* debug code follows*/
switch (buf[0] - 0x30) {
......@@ -577,6 +705,41 @@ ssize_t circbuf_write(struct file *file, const char *buf, size_t count, loff_t *
case 1:
camera_interrupts(1);
break;
case 3:
buf_copy[count - 1] = 0;
ret = kstrtol(&buf_copy[2], 10, &val);
dev_dbg(g_dev_ptr, "ret: %d, buf[2]: %s\n", ret, &buf_copy[2]);
if (count > 2 && ret == 0) {
if (val > 0 && val <= 100) {
circbuf_quality = val;
dev_dbg(g_dev_ptr, "set quality %d\n", circbuf_quality);
}
} else {
dev_dbg(g_dev_ptr, "error, unable to process quality parameter\n");
}
break;
case 4:
for (i = 0; i < IMAGE_CHN_NUM; i++)
stop_compressor(i);
dump_state(chn);
break;
case 5:
{
int j, cntr;
long long res;
for (i = 0; i < IMAGE_CHN_NUM; i++) {
cntr = get_zero_counter(i);
printk(KERN_DEBUG "channel = %d, hw pointer = 0x%x, zero_counter = %d, corrected_offset = %d, frame_counter = %lld\n",
i, DW2BYTE(camseq_get_jpeg_wp(i)), cntr, get_corrected_offset(i), get_frame_counter(i));
if (cntr != 0) {
for (j = 0; j < cntr; j++) {
res = get_frame_pos(i, j);
printk(KERN_DEBUG "\t\tzero cross frame number: %lld\n", res);
}
}
}
}
break;
}
/* debug code end */
......@@ -669,7 +832,7 @@ unsigned int circbuf_poll (struct file *file, poll_table *wait)
int rslt;
dev_dbg(g_dev_ptr, "minor = 0x%x\n", minor);
rslt = circbuf_valid_ptr(file->f_pos, &fp, chn);
rslt = circbuf_valid_ptr(&file->f_pos, &fp, chn);
if (rslt < 0) {
// not a valid read pointer, probable buffer overrun
dev_dbg(g_dev_ptr, "invalid pointer file->f_pos = 0x%llx\n", file->f_pos);
......
......@@ -42,4 +42,8 @@ struct circbuf_priv_t {
};
extern struct circbuf_priv_t *circbuf_priv_ptr;
/* debug code follows */
extern unsigned short circbuf_quality;
/* end of debug code */
#endif /* _CIRCBUF_H */
......@@ -683,7 +683,7 @@ void jpeg_htable_fpga_pgm(unsigned int chn)
table_addr.type = 3;
local_irq_save(flags);
x393_cmprs_tables_address(table_addr, chn);
for (i = 0; i < sizeof(huff_tables->fpga_huffman_table); i++) {
for (i = 0; i < sizeof(huff_tables->fpga_huffman_table) / sizeof(huff_tables->fpga_huffman_table[0]); i++) {
x393_cmprs_tables_data((u32)huff_tables->fpga_huffman_table[i], chn);
}
local_irq_restore(flags);
......
......@@ -41,6 +41,8 @@
//#include <linux/of.h>
//#include <linux/of_device.h>
#include <asm/outercache.h>
#include <asm/cacheflush.h>
//#include <asm/system.h>
//#include <asm/byteorder.h> // endians
......@@ -114,6 +116,30 @@ struct image_acq_pd_t {
int minor;
struct jpeg_ptr_t jpeg_ptr[IMAGE_CHN_NUM];
};
/* debug code follows */
long long zero_counter[IMAGE_CHN_NUM] = {0};
long long corrected_offset[IMAGE_CHN_NUM] = {0};
long long frame_counter[IMAGE_CHN_NUM] = {0};
long long frame_pos[IMAGE_CHN_NUM][1000] = {0};
long long get_zero_counter(unsigned int chn)
{
return zero_counter[chn];
}
long long get_corrected_offset(unsigned int chn)
{
return corrected_offset[chn];
}
long long get_frame_counter(unsigned int chn)
{
return frame_counter[chn];
}
long long get_frame_pos(unsigned int chn, unsigned int pos)
{
if (chn < IMAGE_CHN_NUM && pos < 1000)
return frame_pos[chn][pos];
return 0;
}
/* end of debug code */
static struct image_acq_pd_t image_acq_priv;
......@@ -163,32 +189,6 @@ void camseq_set_jpeg_rp(unsigned int chn, int ptr)
End of compressor-related code - TODO: move to a separate file?
*/
static void dump_priv_data(int chn)
{
int i;
if (chn < IMAGE_CHN_NUM) {
printk(KERN_DEBUG "jpeg_wp (in bytes): 0x%x\n", image_acq_priv.jpeg_ptr[chn].jpeg_wp << 2);
printk(KERN_DEBUG "jpeg_rp (in bytes): 0x%x\n", image_acq_priv.jpeg_ptr[chn].jpeg_rp << 2);
printk(KERN_DEBUG "fpga_cntr_prev: 0x%x\n", image_acq_priv.jpeg_ptr[chn].fpga_cntr_prev);
printk(KERN_DEBUG "irq_num_comp: 0x%x\n", image_acq_priv.jpeg_ptr[chn].irq_num_comp);
printk(KERN_DEBUG "irq_num_sens: 0x%x\n", image_acq_priv.jpeg_ptr[chn].irq_num_sens);
printk(KERN_DEBUG "chn_num: 0x%x\n", image_acq_priv.jpeg_ptr[chn].chn_num);
printk(KERN_DEBUG "flags: 0x%x\n", image_acq_priv.jpeg_ptr[chn].flags);
} else {
for (i = 0; i < IMAGE_CHN_NUM; i++) {
printk(KERN_DEBUG "jpeg_wp: 0x%x\n", image_acq_priv.jpeg_ptr[i].jpeg_wp);
printk(KERN_DEBUG "jpeg_rp: 0x%x\n", image_acq_priv.jpeg_ptr[i].jpeg_rp);
printk(KERN_DEBUG "fpga_cntr_prev: 0x%x\n", image_acq_priv.jpeg_ptr[i].fpga_cntr_prev);
printk(KERN_DEBUG "irq_num_comp: 0x%x\n", image_acq_priv.jpeg_ptr[i].irq_num_comp);
printk(KERN_DEBUG "irq_num_sens: 0x%x\n", image_acq_priv.jpeg_ptr[i].irq_num_sens);
printk(KERN_DEBUG "chn_num: 0x%x\n", image_acq_priv.jpeg_ptr[i].chn_num);
printk(KERN_DEBUG "flags: 0x%x\n", image_acq_priv.jpeg_ptr[i].flags);
}
}
}
static const struct of_device_id elphel393_sensor_of_match[];
static struct sensorproc_t s_sensorproc; // sensor parameters and functions to call
struct sensorproc_t * sensorproc = NULL;
......@@ -242,19 +242,45 @@ DECLARE_TASKLET(tasklet_fpga, tasklet_fpga_function, 0); /// 0 - no arguments fo
*/
static inline int updateIRQJPEG_wp(struct jpeg_ptr_t *jptr)
{
phys_addr_t phys_addr;
void *virt_addr;
int xferred; /// number of 32-byte chunks transferred since compressor was reset
x393_afimux_status_t stat = x393_afimux0_status(jptr->chn_num);
//int circbuf_size = get_globalParam(G_CIRCBUFSIZE) >> 2;
int circbuf_size = get_globalParam(G_CIRCBUFSIZE);
xferred = stat.offset256 - jptr->fpga_cntr_prev;
if (xferred == 0)
return 0; /// no advance (compressor was off?)
return 0; /// no advance (compressor was off?)
jptr->flags |= SENS_FLAG_IRQ;
jptr->fpga_cntr_prev = stat.offset256;
// increment in 32 bit words
jptr->jpeg_wp += (xferred << 3);
jptr->jpeg_wp = (stat.offset256 << 3);
/* debug code follows */
frame_counter[jptr->chn_num] += 1;
if (jptr->jpeg_wp == 0) {
zero_counter[jptr->chn_num] += 1;
if (zero_counter[jptr->chn_num] < 1000)
frame_pos[jptr->chn_num][zero_counter[jptr->chn_num] - 1] = frame_counter[jptr->chn_num];
}
/* end of debug code */
/* Looks like compressor is reporting HW pointer with offset when last frame ends precisely at the
* end of buffer and 32 zero bytes start from the beginning of the buffer. HW pointer in this case should
* be 0x20, but it is 0x00 in fact. Try to detect this situation and correct the offset.
*/
if (jptr->jpeg_wp == 0 &&
circbuf_priv_ptr[jptr->chn_num].buf_ptr[jptr->jpeg_wp] == 0x00 &&
(circbuf_priv_ptr[jptr->chn_num].buf_ptr[jptr->jpeg_wp - 1] & MARKER_FF) == MARKER_FF) {
jptr->jpeg_wp += INTERFRAME_PARAMS_SZ;
corrected_offset[jptr->chn_num] += 1;
}
// invalidate CPU L1 and L2 caches
// the code below was used to find cache coherence issues
phys_addr = circbuf_priv_ptr[jptr->chn_num].phys_addr + DW2BYTE(jptr->jpeg_wp) - CHUNK_SIZE;
virt_addr = circbuf_priv_ptr[jptr->chn_num].buf_ptr + jptr->jpeg_wp - INTERFRAME_PARAMS_SZ;
outer_inv_range(phys_addr, phys_addr + (CHUNK_SIZE - 1));
__cpuc_flush_dcache_area(virt_addr, CHUNK_SIZE);
return 1;
}
......@@ -289,44 +315,51 @@ inline static void set_default_interframe(struct interframe_params_t *params)
params->width = 2592;
params->byrshift = 3;
params->color = 0;
params->quality2 = 100;
params->quality2 = circbuf_quality;
//params->quality2 = 100;
}
/**
* @brief Locate area between frames in the circular buffer
* @return pointer to interframe parameters structure
*/
inline struct interframe_params_t* updateIRQ_interframe(struct jpeg_ptr_t *jptr) {
// int circbuf_size=get_globalParam (G_CIRCBUFSIZE)>>2;
// int alen = JPEG_wp-9; if (alen<0) alen+=circbuf_size;
// int jpeg_len=ccam_dma_buf_ptr[alen] & 0xffffff;
// set_globalParam(G_FRAME_SIZE,jpeg_len);
// int aframe_params=(alen & 0xfffffff8)-
// (((jpeg_len + CCAM_MMAP_META + 3) & 0xffffffe0)>>2) /// multiple of 32-byte chunks to subtract
// -8; /// size of the storage area to be filled before the frame
// if(aframe_params < 0) aframe_params += circbuf_size;
// struct interframe_params_t* interframe= (struct interframe_params_t*) &ccam_dma_buf_ptr[aframe_params];
///// should we use memcpy as before here?
// interframe->frame_length=jpeg_len;
// interframe->signffff=0xffff;
//#if ELPHEL_DEBUG_THIS
// set_globalParam (0x306,get_globalParam (0x306)+1);
//#endif
struct interframe_params_t *interframe;
int len_offset = X393_BUFFSUB(jptr->jpeg_wp, INTERFRAME_PARAMS_SZ + 1);
int jpeg_len = circbuf_priv_ptr[jptr->chn_num].buf_ptr[len_offset] & FRAME_LENGTH_MASK;
inline struct interframe_params_t* updateIRQ_interframe(struct jpeg_ptr_t *jptr)
{
dma_addr_t phys_addr;
void *virt_addr;
struct interframe_params_t *interframe = NULL;
int len_offset = X393_BUFFSUB(DW2BYTE(jptr->jpeg_wp), CHUNK_SIZE + 4);
int jpeg_len = circbuf_priv_ptr[jptr->chn_num].buf_ptr[BYTE2DW(len_offset)] & FRAME_LENGTH_MASK;
int jpeg_start = X393_BUFFSUB(DW2BYTE(jptr->jpeg_wp) - CHUNK_SIZE - INSERTED_BYTES(jpeg_len) - CCAM_MMAP_META, jpeg_len);
// frame_params_offset points to interframe_params_t area before current frame (this parameters belong to the frame below in memory, not the previous)
int frame_params_offset = BYTE2DW(X393_BUFFSUB(jpeg_start, CHUNK_SIZE));
int prev_len32_off = X393_BUFFSUB(jpeg_start, CHUNK_SIZE + 4);
int prev_len32 = circbuf_priv_ptr[jptr->chn_num].buf_ptr[BYTE2DW(prev_len32_off)];
if ((prev_len32 & MARKER_FF) != MARKER_FF) {
// try to correct offset
prev_len32_off = X393_BUFFSUB(prev_len32_off, 0x20);
prev_len32 = circbuf_priv_ptr[jptr->chn_num].buf_ptr[BYTE2DW(prev_len32_off)];
if ((prev_len32 & MARKER_FF) == MARKER_FF) {
frame_params_offset = BYTE2DW(X393_BUFFADD(prev_len32_off, 4));
}
}
interframe = (struct interframe_params_t *) &circbuf_priv_ptr[jptr->chn_num].buf_ptr[frame_params_offset];
interframe->frame_length = jpeg_len;
interframe->signffff = 0xffff;
/* debug code follows */
set_default_interframe(interframe);
/* end of debug code */
set_globalParam(G_FRAME_SIZE, jpeg_len);
// set_globalParam(G_FRAME_SIZE, jpeg_len);
// invalidate CPU L1 and L2 caches (in this order)
phys_addr = circbuf_priv_ptr[jptr->chn_num].phys_addr + DW2BYTE(frame_params_offset);
virt_addr = interframe;
__cpuc_flush_dcache_area(virt_addr, CHUNK_SIZE);
outer_inv_range(phys_addr, phys_addr + (CHUNK_SIZE - 1));
return interframe;
}
......@@ -468,21 +501,24 @@ static irqreturn_t frame_sync_irq_handler(int irq, void *dev_id)
static irqreturn_t compressor_irq_handler(int irq, void *dev_id)
{
struct jpeg_ptr_t *priv = dev_id;
struct interframe_params_t *interframe;
struct interframe_params_t *interframe = NULL;
x393_cmprs_interrupts_t irq_ctrl;
unsigned long flag;
local_irq_save(flag);
if (updateIRQJPEG_wp(priv)) {
update_irq_circbuf(priv);
updateIRQFocus(priv);
// update_irq_circbuf(priv);
// updateIRQFocus(priv);
interframe = updateIRQ_interframe(priv);
//updateIRQ_Exif(interframe);
wake_up_interruptible(&circbuf_wait_queue);
}
//wake_up_interruptible(&framepars_wait_queue);
tasklet_schedule(&tasklet_fpga);
// tasklet_schedule(&tasklet_fpga);
irq_ctrl.interrupt_cmd = IRQ_CLEAR;
x393_cmprs_interrupts(irq_ctrl, priv->chn_num);
local_irq_restore(flag);
return IRQ_HANDLED;
}
......@@ -520,11 +556,6 @@ void tasklet_fpga_function(unsigned long arg) {
unsigned long * hash32p=&(framepars[(thisFrameNumber-1) & PARS_FRAMES_MASK].pars[P_GTAB_R]);
unsigned long * framep= &(framepars[(thisFrameNumber-1) & PARS_FRAMES_MASK].pars[P_FRAME]);
int i, j;
int last_image_chunk;
int len32;
#ifdef TEST_DISABLE_CODE
/// Time is out?
if ((getThisFrameNumber() ^ X3X3_I2C_FRAME) & PARS_FRAMES_MASK) return; /// already next frame
......@@ -630,7 +661,6 @@ GLOBALPARS(0x1044)=thisFrameNumber;
*/
void reset_compressor(unsigned int chn)
{
int i;
unsigned long flags;
local_irq_save(flags);
......
......@@ -56,4 +56,11 @@ int image_acq_init(struct platform_device *pdev);
// got 0x20 more than start of the new image
#define OFFSET_X40 0x40
/* debug code follows */
long long get_zero_counter(unsigned int chn);
long long get_corrected_offset(unsigned int chn);
long long get_frame_counter(unsigned int chn);
long long get_frame_pos(unsigned int chn, unsigned int pos);
/* end of debug code */
#endif
......@@ -1361,6 +1361,7 @@ struct p_names_t {
#define LSEEK_CIRC_WAIT 11
#define LSEEK_CIRC_FREE 12
#define LSEEK_CIRC_USED 13
#define LSEEK_CIRC_STOP_COMPRESSOR 14
#define LSEEK_HUFFMAN_DC0 1
#define LSEEK_HUFFMAN_AC0 2
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment