Commit 1b1c1244 authored by Andrey Filippov's avatar Andrey Filippov

start of merging with master

parent 03c34e84
......@@ -21,7 +21,7 @@
* -----------------------------------------------------------------------------**
*/
#define DEBUG 1
//#define DEBUG 1
#include <linux/device.h>
#include <linux/module.h>
......@@ -69,36 +69,43 @@
#include "circbuf.h"
#include "exif.h"
#include "x393_macro.h"
#include "x393.h"
//#include "x393.h"
#include "x393_helpers.h"
#define CIRCBUF_DRIVER_NAME "circbuf driver"
/** Wait queue for the processes waiting for a new frame to appear in the circular buffer */
wait_queue_head_t circbuf_wait_queue;
struct circbuf_priv_t circbuf_priv[IMAGE_CHN_NUM];
struct circbuf_priv_t circbuf_priv[SENSOR_PORTS];
struct circbuf_priv_t *circbuf_priv_ptr = circbuf_priv;
static struct device *g_dev_ptr;
static const struct of_device_id elphel393_circbuf_of_match[];
unsigned long *ccam_dma_buf_ptr[SENSOR_PORTS] = {NULL};
/* 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;
dma_addr_t dma_handle;
const size_t dma_size = (CCAM_DMA_SIZE + (PAGE_SIZE >> 2)) * sizeof(int);
struct device *dev = &pdev->dev;
unsigned long *ccam_dma_buf_ptr = NULL;
unsigned long *dma_buf_ptr = NULL;
// use Elphel_buf if it was allocated
if (pElphel_buf != NULL) {
ccam_dma_buf_ptr = pElphel_buf->vaddr;
dma_buf_ptr = pElphel_buf->vaddr;
dma_handle = pElphel_buf->paddr;
dev_info(dev, "using %lu bytes of DMA memory from pElphel_buf at address 0x%08x", pElphel_buf->size * PAGE_SIZE, dma_handle);
} else {
ccam_dma_buf_ptr = dmam_alloc_coherent(dev, dma_size, &dma_handle, GFP_KERNEL);
if (!ccam_dma_buf_ptr) {
dma_buf_ptr = dmam_alloc_coherent(dev, dma_size, &dma_handle, GFP_KERNEL);
if (!dma_buf_ptr) {
dev_err(dev, "unable to allocate DMA buffer\n");
return -ENOMEM;
} else {
......@@ -106,12 +113,12 @@ int init_ccam_dma_buf_ptr(struct platform_device *pdev)
}
}
// set circular buffer size in bytes
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);
for (i = 0; i < SENSOR_PORTS; i++) {
circbuf_priv[i].buf_ptr = dma_buf_ptr + BYTE2DW(CIRCBUF_START_OFFSET + i * CCAM_DMA_SIZE);
circbuf_priv[i].phys_addr = dma_handle + CIRCBUF_START_OFFSET + i * CCAM_DMA_SIZE;
ccam_dma_buf_ptr[i] = circbuf_priv[i].buf_ptr;
// set circular buffer size in bytes
set_globalParam(i, G_CIRCBUFSIZE, CCAM_DMA_SIZE);
}
return 0;
......@@ -180,8 +187,8 @@ loff_t circbuf_all_lseek(struct file *file, loff_t offset, int orig)
return circbuf_lseek(file, offset, orig);
case JPEGHEAD_MINOR:
if (orig == SEEK_END && offset > 0) {
rp = BYTE2DW(offset) & (~7); // convert to index to long, align to 32-bytes
fp = (struct interframe_params_t *) &circbuf_priv[chn].buf_ptr[X393_BUFFSUB(rp, 8)];
rp = BYTE2DW(X393_BUFFSUB(offset, CHUNK_SIZE)) & (~7); // convert to index to long, align to 32-bytes
fp = (struct interframe_params_t *) &circbuf_priv[chn].buf_ptr[rp];
}
return jpeghead_lseek(file, offset, orig, fp);
case HUFFMAN_MINOR:
......@@ -268,25 +275,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);
print_hex_dump_bytes("", DUMP_PREFIX_OFFSET, params, sizeof(struct interframe_params_t));
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;
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)];
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))];
dev_dbg(g_dev_ptr, "[chn %d] byte_offset = 0x%x, calculated offset = 0x%x, len32 = 0x%lx\n", chn, byte_offset, offset, len32);
dev_dbg(g_dev_ptr, "got len32 = 0x%lx at 0x%x\n", len32, last_image_chunk + (CHUNK_SIZE - CCAM_MMAP_META_LENGTH));
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, "[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,40 +322,63 @@ 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
dev_dbg(g_dev_ptr, "misaligned pointer rp = 0x%x for channel %d\n", rp, chn);
return -2;
}
fp = (struct interframe_params_t *) &circbuf_priv[chn].buf_ptr[BYTE2DW(X393_BUFFSUB(rp, sizeof(struct interframe_params_t)))];
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)));
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");
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
*
......@@ -375,15 +419,72 @@ int circbuf_valid_ptr(int rp, struct interframe_params_t **fpp, unsigned int chn
* free memory may be less by a whole frame if compressor is running.
* LSEEK_CIRC_USED - returns memory used in the in circbuf from the current file pointer,
* or -EINVAL if the pointer is invalid
* The following command is used for profiling from user space applications. It does not change file pointer:
* LSEEK_CIRC_UTIME return current value of microsecond counter.
* @param[in] file pointer to \e file structure
* @param[in] offset offset inside buffer in bytes
* @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 +492,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 +500,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 +517,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 < SENSOR_PORTS; 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,109 +550,126 @@ 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?
return file->f_pos ; // data already available, return file pointer
case LSEEK_CIRC_UTIME:
return get_rtc_usec();
break;
default:
if ((offset & ~0x1f)==LSEEK_DAEMON_CIRCBUF) {
wait_event_interruptible(circbuf_wait_queue, get_imageParamsThis(P_DAEMON_EN) & (1<<(offset & 0x1f)));
wait_event_interruptible(circbuf_wait_queue, get_imageParamsThis(chn, 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 +680,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 +693,20 @@ 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;
unsigned short circbuf_height = 1936;
unsigned short circbuf_width = 2592;
unsigned char circbuf_byrshift = 3;
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 +716,66 @@ ssize_t circbuf_write(struct file *file, const char *buf, size_t count, loff_t *
case 1:
camera_interrupts(1);
break;
case 3:
/* update image quality */
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 < SENSOR_PORTS; i++)
stop_compressor(i);
dump_state(chn);
break;
case 5:
/* print debug statistics */
{
int j, cntr;
long long res;
for (i = 0; i < SENSOR_PORTS; 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;
case 6:
/* update frame size */
{
unsigned int w, h;
int res = sscanf(&buf[2], "%u:%u", &w, &h);
if (res == 2) {
circbuf_width = w;
circbuf_height = h;
dev_dbg(g_dev_ptr, "set image size %u x %u\n", w, h);
}
}
break;
case 7:
/* update Bayer shift */
{
unsigned char val;
int res = sscanf(&buf[2], "%u", &val);
if (res == 1) {
circbuf_byrshift = val;
dev_dbg(g_dev_ptr, "set new bayer shift: %u\n", val);
}
}
break;
}
/* debug code end */
......@@ -641,6 +840,17 @@ int circbuf_mmap(struct file *file, struct vm_area_struct *vma)
vma->vm_end - vma->vm_start,
vma->vm_page_prot);
// ret = dma_common_mmap(g_dev_ptr, vma,
// circbuf_priv[chn].buf_ptr,
// circbuf_priv[chn].phys_addr,
// pElphel_buf->size * PAGE_SIZE);
//
// ret = arm_dma_mmap(g_dev_ptr, vma,
// circbuf_priv[chn].buf_ptr,
// circbuf_priv[chn].phys_addr,
// pElphel_buf->size * PAGE_SIZE,
// NULL);
dev_dbg(g_dev_ptr, "remap_pfn_range returned 0x%x\n", ret);
if (ret) return -EAGAIN;
......@@ -669,7 +879,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);
......@@ -724,16 +934,6 @@ static int circbuf_all_init(struct platform_device *pdev)
}
dev_info(dev, "registered MAJOR: %d\n", CIRCBUF_MAJOR);
res = init_ccam_dma_buf_ptr(pdev);
if (res < 0) {
dev_err(dev, "ERROR allocating coherent DMA buffer\n");
return -ENOMEM;
}
dev_dbg(dev, "initialize circbuf wait queue\n");
init_waitqueue_head(&circbuf_wait_queue);
dev_dbg(dev, "initialize Huffman tables with default data\n");
res = jpeghead_init(pdev);
if (res < 0) {
dev_err(dev, "unable to initialize jpeghead module\n");
......@@ -744,6 +944,15 @@ static int circbuf_all_init(struct platform_device *pdev)
dev_err(dev, "unable to initialize sensor_common module\n");
return res;
}
res = init_ccam_dma_buf_ptr(pdev);
if (res < 0) {
dev_err(dev, "ERROR allocating coherent DMA buffer\n");
return -ENOMEM;
}
dev_dbg(dev, "initialize circbuf wait queue\n");
init_waitqueue_head(&circbuf_wait_queue);
dev_dbg(dev, "initialize Huffman tables with default data\n");
g_dev_ptr = dev;
......
......@@ -31,9 +31,6 @@ unsigned int circbuf_poll (struct file *file, poll_table *wait);
*!======================================================================================*/
extern wait_queue_head_t circbuf_wait_queue;
extern unsigned long *ccam_dma_buf_ptr;
//unsigned long *circbuf_get_ccam_ptr(void);
// private data
struct circbuf_priv_t {
int minor;
......@@ -42,4 +39,11 @@ struct circbuf_priv_t {
};
extern struct circbuf_priv_t *circbuf_priv_ptr;
/* debug code follows */
extern unsigned short circbuf_quality;
extern unsigned short circbuf_height;
extern unsigned short circbuf_width;
extern unsigned char circbuf_byrshift;
/* end of debug code */
#endif /* _CIRCBUF_H */
......@@ -415,12 +415,12 @@ static int elphel393_clock10359_probe(struct platform_device *pdev)
static int elphel393_clock10359_remove(struct platform_device *pdev)
{
dev_info(&pdev->dev,"Removing elphel393-sensor-i2c");
dev_info(&pdev->dev,"Removing elphel393_clock10359");
return 0;
}
static struct of_device_id elphel393_clock10359_of_match[] = {
{ .compatible = "elphel,elphel393-sensor-i2c-1.00", },
{ .compatible = "elphel,elphel393_clock10359-1.00", },
{ /* end of table */}
};
......@@ -430,7 +430,7 @@ static struct platform_driver elphel393_clock10359 = {
.probe = elphel393_clock10359_probe,
.remove = elphel393_clock10359_remove,
.driver = {
.name = "elphel393-sensor-i2c",
.name = DRV_NAME,
.owner = THIS_MODULE,
.of_match_table = elphel393_clock10359_of_match,
.pm = NULL, /* power management */
......@@ -440,7 +440,7 @@ static struct platform_driver elphel393_clock10359 = {
module_platform_driver(elphel393_clock10359);
MODULE_AUTHOR("Andrey Filippov <andrey@elphel.com>");
MODULE_DESCRIPTION("Elphel 10393 sensor ports i2c");
MODULE_DESCRIPTION("Elphel 10393 10359");
MODULE_LICENSE("GPL");
......@@ -176,12 +176,24 @@ ssize_t minor_file_size(int minor) { //return current file size for different mi
}
ssize_t minor_max_size(int minor) { //return max file size for different minors
switch (minor) {
case X3X3_EXIF_TEMPLATE: return MAX_EXIF_SIZE;
case X3X3_EXIF_EXIF: return MAX_EXIF_SIZE * (MAX_EXIF_FRAMES+1);
case X3X3_EXIF_META: return MAX_EXIF_SIZE;
case X3X3_EXIF_METADIR: return MAX_EXIF_FIELDS * sizeof(struct exif_dir_table_t);
case X3X3_EXIF_TIME: return sizeof(struct exif_time_t);
default:return 0;
case X3X3_EXIF_TEMPLATE:
return MAX_EXIF_SIZE;
case X3X3_EXIF_EXIF_CHN_0:
case X3X3_EXIF_EXIF_CHN_1:
case X3X3_EXIF_EXIF_CHN_2:
case X3X3_EXIF_EXIF_CHN_3:
return MAX_EXIF_SIZE * (MAX_EXIF_FRAMES+1);
case X3X3_EXIF_META_CHN_0:
case X3X3_EXIF_META_CHN_1:
case X3X3_EXIF_META_CHN_2:
case X3X3_EXIF_META_CHN_3:
return MAX_EXIF_SIZE;
case X3X3_EXIF_METADIR:
return MAX_EXIF_FIELDS * sizeof(struct exif_dir_table_t);
case X3X3_EXIF_TIME:
return sizeof(struct exif_time_t);
default:
return 0;
}
}
void exif_invalidate(void) { // 393: OK, only invalidates all ayt once
......@@ -231,6 +243,7 @@ int exif_rebuild_chn(int sensor_port, int frames) {
return -1;
}
memset(meta_buffer, 0, aexif_meta_size[sensor_port] * (MAX_EXIF_FRAMES+1));
ameta_buffer[sensor_port] = meta_buffer;
aexif_valid[sensor_port] = 1;
return 0;
}
......@@ -507,7 +520,6 @@ static loff_t exif_lseek (struct file * file, loff_t offset, int orig) {
int maxsize=minor_max_size(p);
// int sensor_port;
int fp;
switch (orig) {
case SEEK_SET:
file->f_pos = offset;
......
......@@ -25,10 +25,10 @@ int exif_enable_chn(int sensor_port, int en); // enable/disable Exif process
int exif_enable(int en); // For all sensor ports
int dir_find_tag (unsigned long tag); //!find location of the tag field in meta page using long tag (Exif tag and tag group)
inline void write_meta_raw_irq(int sensor_port, char * data, int offset, int len); //write data to meta, called from IRQ
inline int write_meta_irq(int sensor_port, char * data, int * indx, unsigned long ltag, int len); //write data to meta, called from IRQ(len==0 => use field length)
inline void putlong_meta_raw_irq(int sensor_port, unsigned long data, int offset); //write data to meta (4 bytes, big endian), called from IRQ
inline int putlong_meta_irq(int sensor_port, unsigned long data, int * indx, unsigned long ltag); //write data to meta (4 bytes, big endian), from IRQ
void write_meta_raw_irq(int sensor_port, char * data, int offset, int len); //write data to meta, called from IRQ
int write_meta_irq(int sensor_port, char * data, int * indx, unsigned long ltag, int len); //write data to meta, called from IRQ(len==0 => use field length)
void putlong_meta_raw_irq(int sensor_port, unsigned long data, int offset); //write data to meta (4 bytes, big endian), called from IRQ
int putlong_meta_irq(int sensor_port, unsigned long data, int * indx, unsigned long ltag); //write data to meta (4 bytes, big endian), from IRQ
//void write_meta_raw_irq(char * data, int offset, int len); //write data to meta, called from IRQ
//int write_meta_irq(char * data, int * indx, unsigned long ltag, int len); //write data to meta, called from IRQ(len==0 => use field length). Returns index of the written data, -1 if not written
......@@ -37,7 +37,7 @@ int write_meta(int sensor_port, char * data, int * indx, unsigned long ltag, in
void putlong_meta_raw(int sensor_port, unsigned long data, int offset); //write data to meta (4 bytes, big endian), called from outside IRQ (atomic)
int putlong_meta(int sensor_port, unsigned long data, int * indx, unsigned long ltag); //write data to meta (4 bytes, big endian), from outside IRQ (atomic). Returns index of the written data, -1 if not written
char * encode_time(unsigned long sec, unsigned long usec);
char * encode_time(char buf[27], unsigned long sec, unsigned long usec);
int store_meta(int sensor_port); //called from IRQ service - put current metadata to meta_buffer, return page index
......
......@@ -19,7 +19,7 @@
*/
//copied from cxi2c.c - TODO:remove unneeded
#undef JTAG_BRANCH
#include <linux/types.h> /// div for 64
#include <asm/div64.h> /// div for 64
......@@ -147,7 +147,9 @@ wait_queue_head_t aframepars_wait_queue[SENSOR_PORTS];/// used to wait for
/* Remove after compilation OK */
struct sensorproc_t * sensorproc = NULL;
#ifdef JTAG_BRANCH
void camera_interrupts (int on) {}
#endif
#if 0
#define wait_event_interruptible(wq, condition) \
({ \
......@@ -1340,7 +1342,7 @@ int framepars_remove(struct platform_device *pdev)
return 0;
}
#ifdef JTAG_BRANCH
static const struct of_device_id elphel393_framepars_of_match[] = {
{ .compatible = "elphel,elphel393-framepars-1.00" },
{ /* end of list */ }
......@@ -1361,3 +1363,4 @@ module_platform_driver(elphel393_framepars);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Andrey Filippov <andrey@elphel.com>.");
MODULE_DESCRIPTION(X3X3_FRAMEPARS_DRIVER_NAME);
#endif
\ No newline at end of file
......@@ -7,8 +7,9 @@
* - interrupts handling
* - tasklets
* - device driver that includes waiting for the next frame regardless of compression
*
* Copyright (C) 2016 Elphel, Inc.
*/
/* Copyright (C) 2016 Elphel, Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
......@@ -41,6 +42,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
......@@ -73,12 +76,14 @@
//#include "gamma_tables.h"
#include "quantization_tables.h"
#include "x393_macro.h"
#include "x393.h"
//#include "x393.h"
#include "x393_helpers.h"
/**
* @brief driver name to display in log messages
*/
/** @brief Driver name to display in log messages. */
#define IMAGEACQ_DRIVER_NAME "Elphel (R) Model 393 Image Acquisition device driver"
/** @brief The size in bytes of L2 cache invalidation area. This size must be aligned to cache line size.
* 16 kbytes seems to be good starting point. */
#define L2_INVAL_SIZE (32 * 1024)
/**@struct jpeg_ptr_t
* @brief \e jpeg_ptr_t structure contains read and write pointers along with
......@@ -89,7 +94,7 @@
* JPEG read pointer in 32 bit words
* @var jpeg_ptr_t::fpga_cntr_prev
* This field contains previous value of the FPGA transfer counter which is used
* to find out if it has changed
* to find out if it has changed. This pointer is in 32 bit words.
* @var jpeg_ptr_t::irq_num_comp
* IRQ number associated with compressor
* @var jpeg_ptr_t::irq_num_sens
......@@ -112,82 +117,81 @@ struct jpeg_ptr_t {
*/
struct image_acq_pd_t {
int minor;
struct jpeg_ptr_t jpeg_ptr[IMAGE_CHN_NUM];
struct jpeg_ptr_t jpeg_ptr[SENSOR_PORTS];
};
/* debug code follows */
long long zero_counter[SENSOR_PORTS] = {0};
long long corrected_offset[SENSOR_PORTS] = {0};
long long frame_counter[SENSOR_PORTS] = {0};
long long frame_pos[SENSOR_PORTS][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 < SENSOR_PORTS && pos < 1000)
return frame_pos[chn][pos];
return 0;
}
/* end of debug code */
static struct image_acq_pd_t aimage_acq_priv[SENSOR_PORTS];
static struct image_acq_pd_t image_acq_priv;
static volatile int aJPEG_wp[SENSOR_PORTS];
static volatile int aJPEG_rp;
static int afpga_counter_prev[SENSOR_PORTS]; /// Previous value of the FPGA transfer counter (to find out if it did change)
static struct meta_offsets_t { // works like a cache to time save on looking for tags in the directory (forced to recalcualte if does not match)
static volatile int JPEG_wp;
static volatile int JPEG_rp;
static int fpga_counter_prev=0; /// Previous value of the FPGA transfer counter (to find out if it did change)
static struct meta_offsets_t { // works like a cache to time save on looking for tags in the directory (forced to recalculate if does not match)
int Image_DateTime; // will have offset of the Exif_Image_DateTime data in meta page (Exif_Photo_SubSecTime should go immediately after in meta page)
int Photo_DateTimeOriginal;
int Photo_ExposureTime;
int Image_FrameNumber;
int Image_ImageNumber;
int Image_Orientation;
int Photo_MakerNote;
int PageNumber;
} meta_offsets;
//#ifdef TEST_DISABLE_CODE
int camSeqGetJPEG_wp(int sensor_port) {return aJPEG_wp[sensor_port];}
int camSeqGetJPEG_rp(int sensor_port) {return aJPEG_rp[sensor_port];}
void camSeqSetJPEG_rp(int sensor_port, int p) {
aJPEG_rp[sensor_port]=p;
set_globalParam(sensor_port, G_CIRCBUFRP, p<< 2);
set_globalParam(sensor_port, G_FREECIRCBUF,
(((get_globalParam(sensor_port, G_CIRCBUFRP) <= get_globalParam(sensor_port, G_CIRCBUFWP))?
get_globalParam(sensor_port, G_CIRCBUFSIZE):0)+ get_globalParam(sensor_port, G_CIRCBUFRP))
- get_globalParam(sensor_port, G_CIRCBUFWP));
}
//#endif /* TEST_DISABLE_CODE */
#ifdef TEST_DISABLE_CODE
int camSeqGetJPEG_wp(void) {return JPEG_wp;}
int camSeqGetJPEG_rp(void) {return JPEG_rp;}
void camSeqSetJPEG_rp(int p) {
JPEG_rp=p;
set_globalParam(G_CIRCBUFRP, p<< 2);
set_globalParam(G_FREECIRCBUF,
(((get_globalParam(G_CIRCBUFRP) <= get_globalParam(G_CIRCBUFWP))?
get_globalParam(G_CIRCBUFSIZE):0)+ get_globalParam(G_CIRCBUFRP))
- get_globalParam(G_CIRCBUFWP));
}
#endif /* TEST_DISABLE_CODE */
int camseq_get_jpeg_wp(int sensor_port, unsigned int chn)
int camseq_get_jpeg_wp(unsigned int chn)
{
return (chn < IMAGE_CHN_NUM) ? aimage_acq_priv.jpeg_ptr[chn].jpeg_wp : 0;
return (chn < SENSOR_PORTS) ? image_acq_priv.jpeg_ptr[chn].jpeg_wp : 0;
}
int camseq_get_jpeg_rp(int sensor_port, unsigned int chn)
int camseq_get_jpeg_rp(unsigned int chn)
{
return (chn < IMAGE_CHN_NUM) ? aimage_acq_priv[sensor_port].jpeg_ptr[chn].jpeg_rp : 0;
return (chn < SENSOR_PORTS) ? image_acq_priv.jpeg_ptr[chn].jpeg_rp : 0;
}
void camseq_set_jpeg_rp(int sensor_port, unsigned int chn, int ptr)
void camseq_set_jpeg_rp(unsigned int chn, int ptr)
{
if (chn < IMAGE_CHN_NUM) {
aimage_acq_priv[sensor_port].jpeg_ptr[chn].jpeg_rp = ptr;
if (chn < SENSOR_PORTS) {
image_acq_priv.jpeg_ptr[chn].jpeg_rp = ptr;
}
}
/*!
End of compressor-related code - TODO: move to a separate file?
*/
static void dump_priv_data(int sensor_port, int chn)
{
int i;
if (chn < IMAGE_CHN_NUM) {
printk(KERN_DEBUG "jpeg_wp (in bytes): 0x%x\n", aimage_acq_priv[sensor_port].jpeg_ptr[chn].jpeg_wp << 2);
printk(KERN_DEBUG "jpeg_rp (in bytes): 0x%x\n", aimage_acq_priv[sensor_port].jpeg_ptr[chn].jpeg_rp << 2);
printk(KERN_DEBUG "fpga_cntr_prev: 0x%x\n", aimage_acq_priv[sensor_port].jpeg_ptr[chn].fpga_cntr_prev);
printk(KERN_DEBUG "irq_num_comp: 0x%x\n", aimage_acq_priv[sensor_port].jpeg_ptr[chn].irq_num_comp);
printk(KERN_DEBUG "irq_num_sens: 0x%x\n", aimage_acq_priv[sensor_port].jpeg_ptr[chn].irq_num_sens);
printk(KERN_DEBUG "chn_num: 0x%x\n", aimage_acq_priv[sensor_port].jpeg_ptr[chn].chn_num);
printk(KERN_DEBUG "flags: 0x%x\n", aimage_acq_priv[sensor_port].jpeg_ptr[chn].flags);
} else {
for (i = 0; i < IMAGE_CHN_NUM; i++) {
printk(KERN_DEBUG "jpeg_wp: 0x%x\n", aimage_acq_priv[sensor_port].jpeg_ptr[i].jpeg_wp);
printk(KERN_DEBUG "jpeg_rp: 0x%x\n", aimage_acq_priv[sensor_port].jpeg_ptr[i].jpeg_rp);
printk(KERN_DEBUG "fpga_cntr_prev: 0x%x\n", aimage_acq_priv[sensor_port].jpeg_ptr[i].fpga_cntr_prev);
printk(KERN_DEBUG "irq_num_comp: 0x%x\n", aimage_acq_priv[sensor_port].jpeg_ptr[i].irq_num_comp);
printk(KERN_DEBUG "irq_num_sens: 0x%x\n", aimage_acq_priv[sensor_port].jpeg_ptr[i].irq_num_sens);
printk(KERN_DEBUG "chn_num: 0x%x\n", aimage_acq_priv[sensor_port].jpeg_ptr[i].chn_num);
printk(KERN_DEBUG "flags: 0x%x\n", aimage_acq_priv[sensor_port].jpeg_ptr[i].flags);
}
}
}
*/
static const struct of_device_id elphel393_sensor_of_match[];
static struct sensorproc_t as_sensorproc[SENSOR_PORTS]; // sensor parameters and functions to call
......@@ -196,10 +200,7 @@ struct sensorproc_t * asensorproc = NULL;
//wait_queue_head_t image_acq_wait_queue; /// queue for the sensor frame interrupts
void tasklet_fpga_function_chn0(unsigned long arg);
void tasklet_fpga_function_chn1(unsigned long arg);
void tasklet_fpga_function_chn2(unsigned long arg);
void tasklet_fpga_function_chn3(unsigned long arg);
void tasklet_fpga_function(unsigned long arg);
/**
* @brief Copy #sensorproc structure, needed for multisensor board to be able
......@@ -210,7 +211,7 @@ void tasklet_fpga_function_chn3(unsigned long arg);
struct sensorproc_t * copy_sensorproc (int sensor_port, struct sensorproc_t * copy)
{
/** copy sensor functions */
memcpy(copy, asensorproc[sensor_port], sizeof(struct sensorproc_t));
memcpy(copy, &asensorproc[sensor_port], sizeof(struct sensorproc_t));
return copy;
}
......@@ -230,11 +231,12 @@ struct sensorproc_t * copy_sensorproc (int sensor_port, struct sensorproc_t * co
///
int init_acq_sensor(void); // Never used?
DECLARE_TASKLET(tasklet_fpga_chn0, tasklet_fpga_function_chn0, 0); /// 0 - no arguments for now
DECLARE_TASKLET(tasklet_fpga_chn1, tasklet_fpga_function_chn1, 1); /// 0 - no arguments for now
DECLARE_TASKLET(tasklet_fpga_chn2, tasklet_fpga_function_chn2, 2); /// 0 - no arguments for now
DECLARE_TASKLET(tasklet_fpga_chn3, tasklet_fpga_function_chn3, 3); /// 0 - no arguments for now
//DECLARE_TASKLET(tasklet_fpga, tasklet_fpga_function, 0); /// 0 - no arguments for now
DECLARE_TASKLET(tasklet_fpga_0, tasklet_fpga_function, 0); /// 0 - no arguments for now
DECLARE_TASKLET(tasklet_fpga_1, tasklet_fpga_function, 1); /// 0 - no arguments for now
DECLARE_TASKLET(tasklet_fpga_2, tasklet_fpga_function, 2); /// 0 - no arguments for now
DECLARE_TASKLET(tasklet_fpga_3, tasklet_fpga_function, 3); /// 0 - no arguments for now
static struct tasklet_struct *tasklets[SENSOR_PORTS] = {&tasklet_fpga_0, &tasklet_fpga_1, &tasklet_fpga_2, &tasklet_fpga_3};
/**
......@@ -248,18 +250,86 @@ DECLARE_TASKLET(tasklet_fpga_chn3, tasklet_fpga_function_chn3, 3); /// 0 - no ar
*/
static inline int updateIRQJPEG_wp(struct jpeg_ptr_t *jptr)
{
phys_addr_t phys_addr;
void *virt_addr;
// int prev_dword;
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(jptr->chn_num, G_CIRCBUFSIZE);
xferred = stat.offset256 - jptr->fpga_cntr_prev;
xferred = stat.offset256 - (jptr->fpga_cntr_prev >> 3);
if (xferred == 0)
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->fpga_cntr_prev = jptr->jpeg_wp;
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 */
/* Correct frame length and re-adjust interframe params.
* This operations was scheduled on previous interrupt.
*/
// if (jptr->flags & SENS_FLAG_HW_OFF) {
// int len32;
// int len32_ptr = jptr->jpeg_wp - INTERFRAME_PARAMS_SZ - 1;
// 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);
// len32 = circbuf_priv_ptr[jptr->chn_num].buf_ptr[len32_ptr];
// len32 -= INTERFRAME_PARAMS_SZ;
// circbuf_priv_ptr[jptr->chn_num].buf_ptr[len32_ptr] = len32;
// __cpuc_flush_dcache_area(virt_addr, CHUNK_SIZE);
// outer_inv_range(phys_addr, phys_addr + (CHUNK_SIZE - 1));
// jptr->flags &= ~SENS_FLAG_HW_OFF;
// }
/* Looks like compressor is not writing 32 zero bytes when last frame ends precisely at the
* end of buffer. Try to detect this situation and set a flag so that we can overwrite first
* 32 bytes of the buffer on next interrupt. These bytes will be used as interframe parameters and current frame length
* will be decreased by these 32 bytes. Such a measure will corrupt the frame but preserve the structure.
*/
// if (jptr->jpeg_wp == 0) {
// // we need to invalidate two cache lines in order to
// // estimate the situation correctly: one line after the pointer, which should be the line of
// // 32 bytes of newly compressed frame(or zero bytes?), and one line before the pointer, which should be the last line of the frame. If this is not done
// // then the data read from memory can be incorrect and error detection will give false result. Barrier is set to
// // prevent compiler from reordering operations.
// phys_addr = circbuf_priv_ptr[jptr->chn_num].phys_addr;
// virt_addr = circbuf_priv_ptr[jptr->chn_num].buf_ptr;
// dev_dbg(NULL, "from updateIRQJPEG_wp: phys_addr = 0x%x, virt_addr = 0x%p\n", phys_addr, virt_addr);
// outer_inv_range(phys_addr, phys_addr + (CHUNK_SIZE - 1));
// __cpuc_flush_dcache_area(virt_addr, CHUNK_SIZE);
// phys_addr = circbuf_priv_ptr[jptr->chn_num].phys_addr + CCAM_DMA_SIZE - CHUNK_SIZE;
// virt_addr = circbuf_priv_ptr[jptr->chn_num].buf_ptr + BYTE2DW(CCAM_DMA_SIZE - CHUNK_SIZE);
// outer_inv_range(phys_addr, phys_addr + (CHUNK_SIZE - 1));
// __cpuc_flush_dcache_area(virt_addr, CHUNK_SIZE);
// dev_dbg(NULL, "from updateIRQJPEG_wp: phys_addr = 0x%x, virt_addr = 0x%p\n", phys_addr, virt_addr);
// barrier();
// prev_dword = X393_BUFFSUB(DW2BYTE(jptr->jpeg_wp), 4);
// dev_dbg(NULL, "circbuf_priv_ptr[jptr->chn_num].buf_ptr[jptr->jpeg_wp] = 0x%x\n", circbuf_priv_ptr[jptr->chn_num].buf_ptr[jptr->jpeg_wp]);
// dev_dbg(NULL, "circbuf_priv_ptr[jptr->chn_num].buf_ptr[BYTE2DW(prev_dword)] = 0x%x\n", circbuf_priv_ptr[jptr->chn_num].buf_ptr[BYTE2DW(prev_dword)]);
//// if (circbuf_priv_ptr[jptr->chn_num].buf_ptr[jptr->jpeg_wp] == 0x00 &&
// if ((circbuf_priv_ptr[jptr->chn_num].buf_ptr[BYTE2DW(prev_dword)] & MARKER_FF) == MARKER_FF) {
//// jptr->jpeg_wp += INTERFRAME_PARAMS_SZ;
// jptr->flags |= SENS_FLAG_HW_OFF;
// 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;
}
......@@ -272,9 +342,9 @@ inline void update_irq_circbuf(struct jpeg_ptr_t *jptr) {
set_globalParam (G_FREECIRCBUF, (((get_globalParam (G_CIRCBUFRP) <= get_globalParam (G_CIRCBUFWP))? get_globalParam (G_CIRCBUFSIZE):0)+
get_globalParam (G_CIRCBUFRP)) - get_globalParam (G_CIRCBUFWP));*/
/* the concept of global parameters will be changed, use one channel only for testing */
set_globalParam(G_CIRCBUFWP, jptr->jpeg_wp);
set_globalParam (G_FREECIRCBUF, (((get_globalParam (G_CIRCBUFRP) <= get_globalParam (G_CIRCBUFWP))? get_globalParam (G_CIRCBUFSIZE):0)+
get_globalParam (G_CIRCBUFRP)) - get_globalParam (G_CIRCBUFWP));
set_globalParam(jptr->chn_num, G_CIRCBUFWP, jptr->jpeg_wp);
set_globalParam (jptr->chn_num, G_FREECIRCBUF, (((get_globalParam (jptr->chn_num, G_CIRCBUFRP) <= get_globalParam (jptr->chn_num, G_CIRCBUFWP))? get_globalParam (jptr->chn_num, G_CIRCBUFSIZE):0)+
get_globalParam (jptr->chn_num, G_CIRCBUFRP)) - get_globalParam (jptr->chn_num, G_CIRCBUFWP));
}
/**
......@@ -292,49 +362,59 @@ inline void updateIRQFocus(struct jpeg_ptr_t *jptr)
inline static void set_default_interframe(struct interframe_params_t *params)
{
params->height = 1936;
params->width = 2592;
params->byrshift = 3;
// params->height = 1936;
// params->width = 2592;
params->height = circbuf_height;
params->width = circbuf_width;
// params->byrshift = 3;
params->byrshift = circbuf_byrshift;
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(jptr->chn_num, 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;
}
......@@ -342,70 +422,71 @@ inline struct interframe_params_t* updateIRQ_interframe(struct jpeg_ptr_t *jptr)
* @brief Fill exif data with the current frame data, save pointer to Exif page in the interframe area
* @param interframe pointer to interframe parameters structure
*/
inline void updateIRQ_Exif(int sensor_port, struct interframe_params_t* interframe) {
int index_time = aJPEG_wp-11[sensor_port]; if (index_time<0) index_time+=get_globalParam (sensor_port, G_CIRCBUFSIZE)>>2;
// struct exif_datetime_t
//#ifdef TES_DISABLE_CODE
/// calculates datetime([20] and subsec[7], returns pointer to char[27]
char * exif_meta_time_string=encode_time(ccam_dma_buf_ptr[index_time], ccam_dma_buf_ptr[index_time+1]);
/// may be split in datetime/subsec - now it will not notice missing subseq field in template
write_meta_irq(exif_meta_time_string, &meta_offsets.Photo_DateTimeOriginal, Exif_Photo_DateTimeOriginal, 27);
write_meta_irq(exif_meta_time_string, &meta_offsets.Image_DateTime, Exif_Image_DateTime, 20); // may use 27 if room is provided
putlong_meta_irq(get_imageParamsThis(P_EXPOS), &meta_offsets.Photo_ExposureTime, Exif_Photo_ExposureTime);
putlong_meta_irq(get_imageParamsThis(P_FRAME), &meta_offsets.Image_FrameNumber, Exif_Image_FrameNumber);
//Exif_Photo_MakerNote
int global_flips=(get_imageParamsThis(P_FLIPH) & 1) | ((get_imageParamsThis(P_FLIPV)<<1) & 2);
inline void updateIRQ_Exif(struct jpeg_ptr_t *jptr, struct interframe_params_t* interframe) {
unsigned char short_buff[2];
unsigned int sensor_port = jptr->chn_num;
int index_time = jptr->jpeg_wp - 11; if (index_time<0) index_time+=get_globalParam (sensor_port, G_CIRCBUFSIZE)>>2;
// struct exif_datetime_t
/// calculates datetime([20] and subsec[7], returns pointer to char[27]
char time_buff[27];
char * exif_meta_time_string=encode_time(time_buff, ccam_dma_buf_ptr[sensor_port][index_time], ccam_dma_buf_ptr[sensor_port][index_time+1]);
/// may be split in datetime/subsec - now it will not notice missing subseq field in template
write_meta_irq(sensor_port, exif_meta_time_string, &meta_offsets.Photo_DateTimeOriginal, Exif_Photo_DateTimeOriginal, 27);
write_meta_irq(sensor_port, exif_meta_time_string, &meta_offsets.Image_DateTime, Exif_Image_DateTime, 20); // may use 27 if room is provided
putlong_meta_irq(sensor_port, get_imageParamsThis(sensor_port, P_EXPOS), &meta_offsets.Photo_ExposureTime, Exif_Photo_ExposureTime);
putlong_meta_irq(sensor_port, get_imageParamsThis(sensor_port, P_FRAME), &meta_offsets.Image_ImageNumber, Exif_Image_ImageNumber);
//Exif_Photo_MakerNote
int global_flips=(get_imageParamsThis(sensor_port, P_FLIPH) & 1) | ((get_imageParamsThis(sensor_port, P_FLIPV)<<1) & 2);
int extra_flips=0;
if (get_imageParamsThis(P_MULTI_MODE)!=0) {
extra_flips=get_imageParamsThis(P_MULTI_MODE_FLIPS);
if (get_imageParamsThis(sensor_port, P_MULTI_MODE)!=0) {
extra_flips=get_imageParamsThis(sensor_port, P_MULTI_MODE_FLIPS);
global_flips=extra_flips & 3;
}
/* unsigned char orientations[]={1,6,3,8,
2,7,4,5,
4,5,2,7,
3,8,1,6};
*/
unsigned char orientations[]="1638274545273816";
unsigned char orientations[]="1638274545273816";
unsigned char orientation_short[2];
orientation_short[0]=0;
orientation_short[1]=0xf & orientations[(get_imageParamsThis(P_PORTRAIT)&3) | (global_flips<<2)];
write_meta_irq(orientation_short, &meta_offsets.Image_Orientation, Exif_Image_Orientation, 2);
orientation_short[1]=0xf & orientations[(get_imageParamsThis(sensor_port, P_PORTRAIT)&3) | (global_flips<<2)];
write_meta_irq(sensor_port, orientation_short, &meta_offsets.Image_Orientation, Exif_Image_Orientation, 2);
//TODO - use memcpy
// write sensor number
// short_buff[0] = 0xf & (jptr->chn_num >> 8);
short_buff[0] = 0;
short_buff[1] = 0xf & sensor_port;
write_meta_irq(sensor_port, short_buff, &meta_offsets.PageNumber, Exif_Image_PageNumber, 2);
//TODO - use memcpy
int maker_offset;
maker_offset=putlong_meta_irq(get_imageParamsThis(P_GAINR), &meta_offsets.Photo_MakerNote, Exif_Photo_MakerNote);
maker_offset=putlong_meta_irq(sensor_port, get_imageParamsThis(sensor_port, P_GAINR), &meta_offsets.Photo_MakerNote, Exif_Photo_MakerNote);
if (maker_offset>0) {
putlong_meta_raw_irq(get_imageParamsThis(P_GAING), maker_offset+4);
putlong_meta_raw_irq(get_imageParamsThis(P_GAINGB), maker_offset+8);
putlong_meta_raw_irq(get_imageParamsThis(P_GAINB), maker_offset+12);
putlong_meta_raw_irq(get_imageParamsThis(P_GTAB_R), maker_offset+16);
putlong_meta_raw_irq(get_imageParamsThis(P_GTAB_G), maker_offset+20);
putlong_meta_raw_irq(get_imageParamsThis(P_GTAB_GB), maker_offset+24);
putlong_meta_raw_irq(get_imageParamsThis(P_GTAB_B), maker_offset+28);
putlong_meta_raw_irq(get_imageParamsThis(P_WOI_LEFT) | (get_imageParamsThis(P_WOI_WIDTH)<<16), maker_offset+32);
putlong_meta_raw_irq(get_imageParamsThis(P_WOI_TOP) | (get_imageParamsThis(P_WOI_HEIGHT)<<16), maker_offset+36);
putlong_meta_raw_irq( global_flips |
((get_imageParamsThis(P_BAYER)<<2) & 0xc) |
((get_imageParamsThis(P_COLOR)<<4) & 0xF0) |
((get_imageParamsThis(P_DCM_HOR)<<8) & 0xF00) |
((get_imageParamsThis(P_DCM_VERT)<<12) & 0xF000) |
((get_imageParamsThis(P_BIN_HOR)<<16) & 0xF0000) |
((get_imageParamsThis(P_BIN_VERT)<<20) & 0xF00000) |
putlong_meta_raw_irq(sensor_port, get_imageParamsThis(sensor_port, P_GAING), maker_offset+4);
putlong_meta_raw_irq(sensor_port, get_imageParamsThis(sensor_port, P_GAINGB), maker_offset+8);
putlong_meta_raw_irq(sensor_port, get_imageParamsThis(sensor_port, P_GAINB), maker_offset+12);
putlong_meta_raw_irq(sensor_port, get_imageParamsThis(sensor_port, P_GTAB_R), maker_offset+16);
putlong_meta_raw_irq(sensor_port, get_imageParamsThis(sensor_port, P_GTAB_G), maker_offset+20);
putlong_meta_raw_irq(sensor_port, get_imageParamsThis(sensor_port, P_GTAB_GB), maker_offset+24);
putlong_meta_raw_irq(sensor_port, get_imageParamsThis(sensor_port, P_GTAB_B), maker_offset+28);
putlong_meta_raw_irq(sensor_port, get_imageParamsThis(sensor_port, P_WOI_LEFT) | (get_imageParamsThis(sensor_port, P_WOI_WIDTH)<<16), maker_offset+32);
putlong_meta_raw_irq(sensor_port, get_imageParamsThis(sensor_port, P_WOI_TOP) | (get_imageParamsThis(sensor_port, P_WOI_HEIGHT)<<16), maker_offset+36);
putlong_meta_raw_irq(sensor_port, global_flips |
((get_imageParamsThis(sensor_port, P_BAYER)<<2) & 0xc) |
((get_imageParamsThis(sensor_port, P_COLOR)<<4) & 0xF0) |
((get_imageParamsThis(sensor_port, P_DCM_HOR)<<8) & 0xF00) |
((get_imageParamsThis(sensor_port, P_DCM_VERT)<<12) & 0xF000) |
((get_imageParamsThis(sensor_port, P_BIN_HOR)<<16) & 0xF0000) |
((get_imageParamsThis(sensor_port, P_BIN_VERT)<<20) & 0xF00000) |
(extra_flips <<24) , maker_offset+40);
putlong_meta_raw_irq(get_imageParamsThis(P_MULTI_HEIGHT_BLANK1), maker_offset+44);
putlong_meta_raw_irq(get_imageParamsThis(P_MULTI_HEIGHT_BLANK2), maker_offset+48);
// putlong_meta_raw_irq(0x1234567, maker_offset+52); // just testing
putlong_meta_raw_irq(get_imageParamsThis(P_QUALITY) | ((get_imageParamsThis(P_PORTRAIT)&1)<<7) | (get_imageParamsThis(P_CORING_INDEX)<<16), maker_offset+52);
putlong_meta_raw_irq(get_globalParam(G_TEMPERATURE01), maker_offset+56); // data should be provided by a running daemon
putlong_meta_raw_irq(get_globalParam(G_TEMPERATURE23), maker_offset+60);
//get_globalParam(G_TASKLET_CTL)
// left 1 long spare (+44)
putlong_meta_raw_irq(sensor_port, get_imageParamsThis(sensor_port, P_MULTI_HEIGHT_BLANK1), maker_offset+44);
putlong_meta_raw_irq(sensor_port, get_imageParamsThis(sensor_port, P_MULTI_HEIGHT_BLANK2), maker_offset+48);
// putlong_meta_raw_irq(0x1234567, maker_offset+52); // just testing
putlong_meta_raw_irq(sensor_port, get_imageParamsThis(sensor_port, P_QUALITY) | ((get_imageParamsThis(sensor_port, P_PORTRAIT)&1)<<7) | (get_imageParamsThis(sensor_port, P_CORING_INDEX)<<16), maker_offset+52);
putlong_meta_raw_irq(sensor_port, get_globalParam(sensor_port, G_TEMPERATURE01), maker_offset+56); // data should be provided by a running daemon
putlong_meta_raw_irq(sensor_port, get_globalParam(sensor_port, G_TEMPERATURE23), maker_offset+60);
//get_globalParam(G_TASKLET_CTL)
// left 1 long spare (+44)
}
interframe->meta_index=store_meta();
interframe->meta_index=store_meta(sensor_port);
//#endif /* TES_DISABLE_CODE */
}
......@@ -416,8 +497,7 @@ inline void updateIRQ_Exif(int sensor_port, struct interframe_params_t* interfra
* @param dev_id
* @return
*/
#ifdef X353
static irqreturn_t elphel_FPGA_interrupt(int irq, void *dev_id) {
/*static irqreturn_t elphel_FPGA_interrupt(int irq, void *dev_id) {
unsigned long irq_state;
irq_state = X313_IRQSTATE; //!making dummy read - see c353.h
......@@ -445,8 +525,8 @@ static irqreturn_t elphel_FPGA_interrupt(int irq, void *dev_id) {
EN_INTERRUPT(SMART);
return IRQ_HANDLED;
}
#endif
}*/
/**
* @brief Handle interrupts from sensor channels. This handler is installed without SA_INTERRUPT
* flag meaning that interrupts are enabled during processing. Such behavior is recommended in LDD3.
......@@ -459,9 +539,10 @@ static irqreturn_t frame_sync_irq_handler(int irq, void *dev_id)
{
struct jpeg_ptr_t *jptr = dev_id;
update_frame_pars();
// update_frame_pars();
wake_up_interruptible(&aframepars_wait_queue[jptr->chn_num]);
tasklet_schedule(&tasklet_fpga);
// tasklet_schedule(&tasklet_fpga);
tasklet_schedule(tasklets[jptr->chn_num]);
return IRQ_HANDLED;
}
......@@ -471,27 +552,31 @@ static irqreturn_t frame_sync_irq_handler(int irq, void *dev_id)
* flag meaning that interrupts are enabled during processing. Such behavior is recommended in LDD3.
* @param[in] irq interrupt number
* @param[in] dev_id pointer to driver's private data structure #jpeg_ptr_t corresponding to
* the channel which raise interrupt
* the channel which raised interrupt
* @return \e IRQ_HANDLED if interrupt was processed and \e IRQ_NONE otherwise
*/
static irqreturn_t compressor_irq_handler(int irq, void *dev_id)
{
struct jpeg_ptr_t *priv = dev_id;
struct interframe_params_t *interframe;
struct jpeg_ptr_t *jptr = dev_id;
struct interframe_params_t *interframe = NULL;
x393_cmprs_interrupts_t irq_ctrl;
if (updateIRQJPEG_wp(priv)) {
update_irq_circbuf(priv);
updateIRQFocus(priv);
interframe = updateIRQ_interframe(priv);
//updateIRQ_Exif(interframe);
unsigned long flag;
local_irq_save(flag);
if (updateIRQJPEG_wp(jptr)) {
update_irq_circbuf(jptr);
updateIRQFocus(jptr);
interframe = updateIRQ_interframe(jptr);
updateIRQ_Exif(jptr, interframe);
wake_up_interruptible(&circbuf_wait_queue);
}
//wake_up_interruptible(&framepars_wait_queue);
tasklet_schedule(&tasklet_fpga);
// tasklet_schedule(&tasklet_fpga);
tasklet_schedule(tasklets[jptr->chn_num]);
irq_ctrl.interrupt_cmd = IRQ_CLEAR;
x393_cmprs_interrupts(irq_ctrl, priv->chn_num);
x393_cmprs_interrupts(irq_ctrl, jptr->chn_num);
local_irq_restore(flag);
return IRQ_HANDLED;
}
......@@ -516,123 +601,141 @@ Modify waiting (LSEEK_*) for histogrames so they will only unfreeze if the histo
For displaying histograms - try use latest available - not waiting fro a particular frame.
*/
*/
/// HISTOGRAMS_WAKEUP_ALWAYS if 0 will only wakeup processes waiting for histograms when they become available, maybe never if they are disabled
/// if defined 1 - will wakeup each frame, regardless of the availability of the histograms
//#define HISTOGRAMS_WAKEUP_ALWAYS 0
void tasklet_fpga_function(unsigned long arg) {
int hist_en;
int tasklet_disable=get_globalParam(G_TASKLET_CTL);
unsigned long thisFrameNumber=getThisFrameNumber();
int sensor_port = image_acq_priv.jpeg_ptr[arg].chn_num;
int tasklet_disable=get_globalParam(sensor_port, G_TASKLET_CTL);
unsigned long thisFrameNumber=getThisFrameNumber(sensor_port);
unsigned long prevFrameNumber=thisFrameNumber-1;
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;
int circbuf_size = get_globalParam(G_CIRCBUFSIZE);
unsigned long *buf_ptr;
printk(KERN_DEBUG "%s: get_globalParam(G_CIRCBUFSIZE) = %d\n", __func__, circbuf_size);
unsigned long * hash32p=&(aframepars[sensor_port][(thisFrameNumber-1) & PARS_FRAMES_MASK].pars[P_GTAB_R]);
unsigned long * framep= &(aframepars[sensor_port][(thisFrameNumber-1) & PARS_FRAMES_MASK].pars[P_FRAME]);
const struct jpeg_ptr_t *jptr = &image_acq_priv.jpeg_ptr[arg];
dma_addr_t phys_addr_start, phys_addr_end;
void *virt_addr_start;
unsigned int sz;
/* invalidate L2 cache lines in the beginning of current frame */
phys_addr_start = circbuf_priv_ptr[jptr->chn_num].phys_addr + DW2BYTE(jptr->fpga_cntr_prev);
virt_addr_start = circbuf_priv_ptr[jptr->chn_num].buf_ptr + jptr->fpga_cntr_prev;
sz = DW2BYTE(jptr->fpga_cntr_prev) + L2_INVAL_SIZE;
if (sz < CCAM_DMA_SIZE) {
phys_addr_end = phys_addr_start + L2_INVAL_SIZE - 1;
outer_inv_range(phys_addr_start, phys_addr_end);
__cpuc_flush_dcache_area(virt_addr_start, L2_INVAL_SIZE);
} else {
phys_addr_end = phys_addr_start + (CCAM_DMA_SIZE - DW2BYTE(jptr->fpga_cntr_prev) - 1);
outer_inv_range(phys_addr_start, phys_addr_end);
__cpuc_flush_dcache_area(virt_addr_start, CCAM_DMA_SIZE - DW2BYTE(jptr->fpga_cntr_prev));
phys_addr_start = circbuf_priv_ptr[jptr->chn_num].phys_addr;
phys_addr_end = phys_addr_start + (sz - CCAM_DMA_SIZE - 1);
virt_addr_start = circbuf_priv_ptr[jptr->chn_num].buf_ptr;
outer_inv_range(phys_addr_start, phys_addr_end);
__cpuc_flush_dcache_area(virt_addr_start, sz - CCAM_DMA_SIZE);
}
#ifdef TEST_DISABLE_CODE
/// Time is out?
/// Time is out?
if ((getThisFrameNumber() ^ X3X3_I2C_FRAME) & PARS_FRAMES_MASK) return; /// already next frame
#endif /* TEST_DISABLE_CODE */
/// Histograms are available for the previous frame (that is already in circbuf if compressor was running)
/// Is Y histogram needed?
/// Histograms are available for the previous frame (that is already in circbuf if compressor was running)
/// Is Y histogram needed?
PROFILE_NOW(2);
switch ((tasklet_disable >> TASKLET_CTL_HISTY_BIT) & 7) {
case TASKLET_HIST_NEVER: /// never calculate
hist_en=0;
break;
case TASKLET_HIST_HALF: /// calculate each even (0,2,4,6 frme of 8)
hist_en= ((thisFrameNumber & 1) ==0) || (get_imageParamsPrev(P_HISTRQ) & (1<<HISTRQ_BIT_Y));
hist_en= ((thisFrameNumber & 1) ==0) || (get_imageParamsPrev(sensor_port, P_HISTRQ) & (1<<HISTRQ_BIT_Y));
break;
case TASKLET_HIST_QUATER: /// calculate twice per 8 (0, 4)
hist_en= ((thisFrameNumber & 3) ==0) || (get_imageParamsPrev(P_HISTRQ) & (1<<HISTRQ_BIT_Y));
hist_en= ((thisFrameNumber & 3) ==0) || (get_imageParamsPrev(sensor_port, P_HISTRQ) & (1<<HISTRQ_BIT_Y));
break;
case TASKLET_HIST_ONCE: /// calculate once per 8 (0)
hist_en= ((thisFrameNumber & 7) ==0) || (get_imageParamsPrev(P_HISTRQ) & (1<<HISTRQ_BIT_Y));
hist_en= ((thisFrameNumber & 7) ==0) || (get_imageParamsPrev(sensor_port, P_HISTRQ) & (1<<HISTRQ_BIT_Y));
break;
case TASKLET_HIST_RQONLY: /// calculate only when specifically requested
hist_en= (get_imageParamsPrev(P_HISTRQ) & (1<<HISTRQ_BIT_Y));
hist_en= (get_imageParamsPrev(sensor_port, P_HISTRQ) & (1<<HISTRQ_BIT_Y));
break;
case TASKLET_HIST_ALL: /// calculate each frame
default: /// calculate always (safer)
hist_en=1;
}
//#ifdef TEST_DISABLE_CODE
#ifdef TEST_DISABLE_CODE
if (hist_en) {
/// after updateFramePars gammaHash are from framepars[this-1]
/// after updateFramePars gammaHash are from framepars[this-1]
set_histograms (prevFrameNumber, (1 << COLOR_Y_NUMBER), hash32p, framep); /// 0x2 Green1
GLOBALPARS(G_HIST_Y_FRAME)=prevFrameNumber; /// histogram corresponds to previous frame
PROFILE_NOW(3);
/// Time is out?
/// Time is out?
if ((getThisFrameNumber() ^ X3X3_I2C_FRAME) & PARS_FRAMES_MASK) return; /// already next frame
#if HISTOGRAMS_WAKEUP_ALWAYS
}
wake_up_interruptible(&hist_y_wait_queue); /// wait queue for the G1 histogram (used as Y)
#else
wake_up_interruptible(&hist_y_wait_queue); /// wait queue for the G1 histogram (used as Y)
}
}
#endif
//#endif /* TEST_DISABLE_CODE */
#endif /* TEST_DISABLE_CODE */
/// Process parameters
if ((tasklet_disable & (1 << TASKLET_CTL_PGM)) == 0) {
processPars (sensorproc, getThisFrameNumber(), get_globalParam(G_MAXAHEAD)); /// program parameters
if ((tasklet_disable & (1 << TASKLET_CTL_PGM)) == 0) {
processPars (sensor_port, sensorproc, getThisFrameNumber(sensor_port), get_globalParam(sensor_port, G_MAXAHEAD)); /// program parameters
PROFILE_NOW(4);
}
//#ifdef TEST_DISABLE_CODE
}
#ifdef TEST_DISABLE_CODE
/// Time is out?
if ((getThisFrameNumber() ^ X3X3_I2C_FRAME) & PARS_FRAMES_MASK) return; /// already next frame
if ((getThisFrameNumber() ^ X3X3_I2C_FRAME) & PARS_FRAMES_MASK) return; /// already next frame
/// Are C histograms needed?
//#endif /* TEST_DISABLE_CODE */
switch ((tasklet_disable >> TASKLET_CTL_HISTC_BIT) & 7) {
case TASKLET_HIST_NEVER: /// never calculate
#endif /* TEST_DISABLE_CODE */
switch ((tasklet_disable >> TASKLET_CTL_HISTC_BIT) & 7) {
case TASKLET_HIST_NEVER: /// never calculate
hist_en=0;
break;
case TASKLET_HIST_HALF: /// calculate each even (0,2,4,6 frme of 8)
hist_en= ((thisFrameNumber & 1) ==0) || (get_imageParamsPrev(P_HISTRQ) & (1<<HISTRQ_BIT_C));
case TASKLET_HIST_HALF: /// calculate each even (0,2,4,6 frme of 8)
hist_en= ((thisFrameNumber & 1) ==0) || (get_imageParamsPrev(sensor_port, P_HISTRQ) & (1<<HISTRQ_BIT_C));
break;
case TASKLET_HIST_QUATER: /// calculate twice per 8 (0, 4)
hist_en= ((thisFrameNumber & 3) ==0) || (get_imageParamsPrev(P_HISTRQ) & (1<<HISTRQ_BIT_C));
case TASKLET_HIST_QUATER: /// calculate twice per 8 (0, 4)
hist_en= ((thisFrameNumber & 3) ==0) || (get_imageParamsPrev(sensor_port, P_HISTRQ) & (1<<HISTRQ_BIT_C));
break;
case TASKLET_HIST_ONCE: /// calculate once per 8 (0)
hist_en= ((thisFrameNumber & 7) ==0) || (get_imageParamsPrev(P_HISTRQ) & (1<<HISTRQ_BIT_C));
case TASKLET_HIST_ONCE: /// calculate once per 8 (0)
hist_en= ((thisFrameNumber & 7) ==0) || (get_imageParamsPrev(sensor_port, P_HISTRQ) & (1<<HISTRQ_BIT_C));
break;
case TASKLET_HIST_RQONLY: /// calculate only when specifically requested
hist_en= (get_imageParamsPrev(P_HISTRQ) & (1<<HISTRQ_BIT_C));
case TASKLET_HIST_RQONLY: /// calculate only when specifically requested
hist_en= (get_imageParamsPrev(sensor_port, P_HISTRQ) & (1<<HISTRQ_BIT_C));
break;
case TASKLET_HIST_ALL: /// calculate each frame
default: /// calculate always (safer)
case TASKLET_HIST_ALL: /// calculate each frame
default: /// calculate always (safer)
hist_en=1;
}
}
/*
GLOBALPARS(0x1040)=((thisFrameNumber & 1) ==0);
GLOBALPARS(0x1041)=((thisFrameNumber & 3) ==0);
GLOBALPARS(0x1042)=((thisFrameNumber & 7) ==0);
GLOBALPARS(0x1043)=hist_en;
GLOBALPARS(0x1044)=thisFrameNumber;
*/
//#ifdef TEST_DISABLE_CODE
if (hist_en) {
/// after updateFramePars gammaHash are from framepars[this-1]
*/
#ifdef TEST_DISABLE_CODE
if (hist_en) {
/// after updateFramePars gammaHash are from framepars[this-1]
set_histograms (prevFrameNumber, 0xf, hash32p, framep); /// all 4 colors, including Y (it will be skipped)
GLOBALPARS(G_HIST_C_FRAME)=prevFrameNumber; /// histogram corresponds to previous frame
PROFILE_NOW(5);
/// Time is out?
/// Time is out?
if ((getThisFrameNumber() ^ X3X3_I2C_FRAME) & PARS_FRAMES_MASK) return; /// already next frame
#if HISTOGRAMS_WAKEUP_ALWAYS
}
wake_up_interruptible(&hist_c_wait_queue); /// wait queue for all the other (R,G2,B) histograms (color)
}
wake_up_interruptible(&hist_c_wait_queue); /// wait queue for all the other (R,G2,B) histograms (color)
#else
wake_up_interruptible(&hist_c_wait_queue); /// wait queue for all the other (R,G2,B) histograms (color)
}
wake_up_interruptible(&hist_c_wait_queue); /// wait queue for all the other (R,G2,B) histograms (color)
}
#endif
//#endif /* TEST_DISABLE_CODE */
#endif /* TEST_DISABLE_CODE */
}
//#endif /* TEST_DISABLE_CODE */
......@@ -642,7 +745,6 @@ GLOBALPARS(0x1044)=thisFrameNumber;
*/
void reset_compressor(unsigned int chn)
{
int i;
unsigned long flags;
local_irq_save(flags);
......@@ -686,7 +788,7 @@ void camera_interrupts (int on) {
#endif /* TEST_DISABLE_CODE */
irq_ctrl.interrupt_cmd = on ? IRQ_ENABLE : IRQ_DISABLE;
for (i = 0; i < IMAGE_CHN_NUM; i++) {
for (i = 0; i < SENSOR_PORTS; i++) {
x393_cmprs_interrupts(irq_ctrl, i);
}
}
......@@ -718,7 +820,7 @@ int image_acq_init(struct platform_device *pdev)
//MDD1(printk("sensorproc=0x%x\n",(int) sensorproc));
dev_dbg(dev, "sensorproc address: 0x%x\n", (int)sensorproc);
for (i = 0; i < IMAGE_CHN_NUM; i++) {
for (i = 0; i < SENSOR_PORTS; i++) {
irq = platform_get_irq_byname(pdev, frame_sync_irq_names[i]);
if (request_irq(irq,
frame_sync_irq_handler,
......@@ -764,7 +866,7 @@ int image_acq_init(struct platform_device *pdev)
dev_dbg(dev, "Elphel FPGA interrupts initialized\n");
dev_dbg(dev, "reset all compressors\n");
for (i = 0; i < IMAGE_CHN_NUM; i++) {
for (i = 0; i < SENSOR_PORTS; i++) {
reset_compressor(i);
}
//reset_compressor(); /// reset compressor and buffer pointers
......
......@@ -4,13 +4,13 @@
*/
#ifndef _ASM_CMOSCAM_H
#define _ASM_CMOSCAM_HPARS_FRAMES
#define _ASM_CMOSCAM_H
#define SAFE_CHECK 1 // perform more verification on the paremeters
//#define ELPHEL_DEBUG 0 //global debug on/off in multiple files
//#define ELPHEL_DEBUG_STARTUP 000a4c00 ;
//#define ELPHEL_DEBUG_STARTUP 0 ; // removed - add write to fpga init script
//#define ELPHEL_DEBUG 0 //global debug on/off in multiple files
#define ELPHEL_DEBUG 1 //global debug on/off in multiple files
#define ELPHEL_DEBUG 0 //global debug on/off in multiple files
#define ELPHEL_DEBUG_DELAY 100000 //delay after some printk-s
#define ELP_KERR(x) printk("%s:%d:%s: ERROR ",__FILE__,__LINE__,__FUNCTION__);x
#define ELP_FERR(x) fprintf(stderr,"%s:%d:%s: ERROR ",__FILE__,__LINE__,__FUNCTION__);x
......@@ -1377,6 +1377,8 @@ 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_CIRC_UTIME 15
#define LSEEK_HUFFMAN_DC0 1
#define LSEEK_HUFFMAN_AC0 2
......@@ -1525,7 +1527,7 @@ struct p_names_t {
/* For past compatibility, CCMA_DMA_SIZE...
*/
//#define CCAM_DMA_SIZE CCAM_WORDS_PER_DMABUF
#define CCAM_DMA_SIZE 0x1000000
#define CCAM_DMA_SIZE 0x4000000
#define CIRCBUF_START_OFFSET 0x100000
/*
......
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