#define DEBUG // should be before linux/module.h - enables dev_dbg at boot in this file (needs "debug" in bootarg)
#include <linux/types.h> // div for 64
#include <asm/div64.h> // div for 64
#include <linux/module.h>
#include <linux/mm.h>
#include <linux/sched.h>
...
...
@@ -38,6 +37,7 @@
//#include <linux/autoconf.h>
#include <linux/vmalloc.h>
#include <linux/platform_device.h>
#include <linux/delay.h>
//#include <asm/system.h>
//#include <asm/byteorder.h> // endians
...
...
@@ -64,7 +64,7 @@
//#include "cci2c.h" // to use void i2c_reset_wait(void), reset shadow static 'i2c_hardware_on'
#include "x393_macro.h"
#include "x393.h"
#include "sensor_i2c.h" // read_xi2c_frame()
/**
* \def MDF1(x) optional debug output
*/
...
...
@@ -122,8 +122,9 @@
/* 393: sFrameParsAll is an array of 4per-port structures */
staticstructframepars_all_tsFrameParsAll[SENSOR_PORTS]__attribute__((aligned(PAGE_SIZE)));///< Sensor Parameters, currently 16 pages all and 2048 pages some, static struct
unsignedlongframeParsInitialized;// set to 0 at startup, 1 after initialization that is triggered by setParsAtomic()
#define thisFrameNumber(p) GLOBALPARS(p,G_THIS_FRAME) // Current frame number (may lag from the hardware)
unsignedlongframeParsInitialized[SENSOR_PORTS];// set to 0 at startup, 1 after initialization that is triggered by setParsAtomic()
#define thisFrameNumber(p) GLOBALPARS(p,G_THIS_FRAME) // Current frame number (may lag from the hardware)
#define thisCompressorFrameNumber(p) GLOBALPARS(p,G_COMPRESSOR_FRAME) // Current compressed frame number (lags from thisFrameNumber)
#ifdef NC353
structframepars_all_t*frameparsall=NULL;// - will be mmap-ed
...
...
@@ -146,7 +147,7 @@ unsigned long *amultiSensRvrsIndex[SENSOR_PORTS]; // reverse index (t
wait_queue_head_taframepars_wait_queue[SENSOR_PORTS];// used to wait for the frame to be acquired
for(i=0;i<P_SENSOR_NUMREGS;i++)afuncs2call[sensor_port][P_SENSOR_REGS+i]=ONCHANGE_SENSORREGS;// by default each "manual" write to any of 256 registers will trigger pgm_sensorreg function
// Same for 10359 registers - will not change anything if there is no 10359 - these registers will not be changed, and if will be it wil cause no action
for(i=0;i<P_M10359_NUMREGS;i++)afuncs2call[sensor_port][P_M10359_REGS+i]=ONCHANGE_SENSORREGS;// by default each "manual" write to any of 256 registers will trigger pgm_sensorreg function
initMultiPars(sensor_port);// initialize structures for individual per-sensor parameters. Now only works for sensor registers using G_MULTI_REGSM. Should be called after/during sensor detection
frameParsInitialized=1;
frameParsInitialized[sensor_port]=1;
dev_dbg(g_devfp_ptr,"%s port %d: DONE, frameParsInitialized[%d]=%d\n",__func__,sensor_port,sensor_port,frameParsInitialized[sensor_port]);
@@ -331,7 +347,7 @@ int initMultiPars(int sensor_port)
}
// remark: the line below is called from initFramePars, consider removing it
for(i=0;i<P_SENSOR_NUMREGS;i++)afuncs2call[sensor_port][P_SENSOR_REGS+i]=ONCHANGE_SENSORREGS;// by default each "manual" write to any of 256 registers will trigger pgm_sensorreg function
// pastParsIndex = (thisFrameNumber(sensor_port) - 1) & PASTPARS_SAVE_ENTRIES_MASK; // copying from what was past frame that might include histogram data
pastParsIndex=compressed_frame&PASTPARS_SAVE_ENTRIES_MASK;// copying from what was past frame that might include histogram data
// memcpy(interframe_pars, &framepars[findex_this].pars[P_GTAB_R], 24); // will leave some gaps, but copy [P_ACTUAL_WIDTH]
memcpy(interframe_pars,&apastpars[sensor_port][pastParsIndex].past_pars[P_GTAB_R-PARS_SAVE_FROM],24);// will leave some gaps, but copy [P_ACTUAL_WIDTH]
interframe_pars->height=apastpars[sensor_port][pastParsIndex].past_pars[P_ACTUAL_HEIGHT-PARS_SAVE_FROM];// NOTE: P_ACTUAL_WIDTH,P_QUALITY copied with memcpy
// Now update interframe_pars (interframe area) used to create JPEG headers. Interframe area survives exactly as long as the frames themselves (not like pastpars)
#ifdef NC353
if(interframe_pars){// frame was compressed, not just vsync
//TODO: get rid of *_prev, use it for the future.
memcpy(interframe_pars,&framepars[findex_this].pars[P_GTAB_R],24);// will leave some gaps, but copy [P_ACTUAL_WIDTH]
...
...
@@ -469,15 +522,16 @@ void updateFramePars(int sensor_port, int frame8, struct interframe_params_t * i
MDF7(printk("resubmitting past due functions = 0x%lx for frame=%ld (0x%x)\n",framepars[findex_this].functions,thisFrameNumber(sensor_port),findex_this));
dev_dbg(g_devfp_ptr,"%s resubmitting past due functions = 0x%lx for frame=%ld (0x%x)\n",__func__,framepars[findex_this].functions,thisFrameNumber(sensor_port),findex_this);
}else{
MDF(printk("Ignored past due functions = 0x%lx for frame=%ld (0x%x)\n",framepars[findex_this].functions,thisFrameNumber(sensor_port),findex_this));
dev_dbg(g_devfp_ptr,"%s Ignored past due functions = 0x%lx for frame=%ld (0x%x)\n",__func__,framepars[findex_this].functions,thisFrameNumber(sensor_port),findex_this);
}
}
thisFrameNumber(sensor_port)++;
...
...
@@ -517,12 +571,12 @@ void updateFramePars(int sensor_port, int frame8, struct interframe_params_t * i
* Called twice from processPars - at the beginning and at the end to finish off any derivatives (needed?)
@@ -807,35 +884,35 @@ int setFrameParsAtomic(int sensor_port, unsigned long frameno, int maxLatency, i
funcs2call[index]=val;
D5(printk(" set funcs2call[0x%x]=0x%lx\n",index,val));
// } else if ((frameno !=findex_prev) && (frameno != findex_future)) { // do not write parameters in the future otherwise
}elseif((frame8!=findex_future)||((pars[npar].num&FRAMEPAIR_JUST_THIS)==0)){// do not write "JUST_THIS" parameters in the future otherwise they'll stick
}elseif((frame16!=findex_future)||((pars[npar].num&FRAMEPAIR_JUST_THIS)==0)){// do not write "JUST_THIS" parameters in the future otherwise they'll stick
if(pars[npar].num&FRAMEPAIR_MASK_BYTES){// combine new value with the old one
// processParsSeq (sensorproc, thisFrameNumber & PARS_FRAMES_MASK, 0); //maxahead=0, the rest will be processed after frame sync, from the tasklet
MDF5(printk("\n"));
processPars(sensor_port,sensorproc,thisFrameNumber(sensor_port)&PARS_FRAMES_MASK,0);//maxahead=0, the rest will be processed after frame sync, from the tasklet
processPars(sensor_port,&asensorproc[sensor_port],thisFrameNumber(sensor_port)&PARS_FRAMES_MASK,0);//maxahead=0, the rest will be processed after frame sync, from the tasklet
}
PROFILE_NOW(7);
PROFILE_NOW(6);// 7); // no (7) in NC393
D1I(local_irq_restore(flags));
return0;
}
...
...
@@ -871,7 +948,7 @@ int setFrameParsAtomic(int sensor_port, unsigned long frameno, int maxLatency, i
@@ -988,36 +1065,36 @@ int setFramePars(int sensor_port, struct framepars_t * this_framepars, int numPa
}elseif(pars[npar].num&FRAMEPAIR_FRAME_FUNC){
funcs2call[index]=val;
// } else {
}elseif((frame8!=findex_future)||((pars[npar].num&FRAMEPAIR_JUST_THIS)==0)){// do not write "JUST_THIS" parameters in the future otherwise they'll stick
}elseif((frame16!=findex_future)||((pars[npar].num&FRAMEPAIR_JUST_THIS)==0)){// do not write "JUST_THIS" parameters in the future otherwise they'll stick
if(pars[npar].num&FRAMEPAIR_MASK_BYTES){// combine new value with the old one
@@ -17,7 +17,7 @@ void initSequencers (int sensor_port); ///Move to sensorcommon? currently it
voidinitGlobalPars(intsensor_port);/// resets all global parameters but debug mask (if ELPHEL_DEBUG)
intinitMultiPars(intsensor_port);/// initialize structures for individual per-sensor parameters. Now only works for sensor registers using G_MULTI_REGSM. Should be called aftre/during sensor detection
voidinitFramePars(intsensor_port);///initialize all parameters, set thisFrameNumber to frame8 (read from hardware, usually 0 after resetting i2c and cmd_seq)
voidresetFrameNumber(intsensor_port);/// reset this frame number (called from initFramePars(), also can be used to avoid frame number integer overflow)
voidresetFrameNumber(intsensor_port,u32aframe,inthreset);/// reset this frame number (called from initFramePars(), also can be used to avoid frame number integer overflow)
voidupdateFramePars(intsensor_port,intframe8,structinterframe_params_t*frame_pars);/// called from ISR - advance thisFrameNumber to match hardware frame8, copy parameters as needed.
/// frame8 usually is just next after thisFrameNumber
/// frame_pars - pointer to structure (between frames in the frame buffer) to save a pointer to past parameters
@@ -385,23 +404,23 @@ unsigned long * get_gamma_fpga (int color, ///< color channel 0..3
* @return Node index or 0 if none (unlocked) nodes are found
*/
intgamma_new_node(void){
inttmp_p;
if((gammas[0].non_scaled_length>GAMMA_THRESH)&&(gammas[gammas[0].oldest_non_scaled].newest_scaled==gammas[0].oldest_non_scaled)){// no scaled for the oldest hash
// sacrifice oldest hash
tmp_p=gammas[0].oldest_non_scaled;
remove_from_nonscaled(tmp_p);
}else{// use oldest scaled
tmp_p=gammas[0].oldest_all;
// skip locked if any (should be unlikely to get any locked)
if(tmp_p==0)return0;// none (unlocked) nodes are found
// remove from "all" chain (should work for tmp_p being oldest or not
remove_from_all(tmp_p);
// remove from "scaled chain"
remove_from_scaled(tmp_p);
}
gammas[tmp_p].valid=0;
returntmp_p;
inttmp_p;
if((gammas[0].non_scaled_length>GAMMA_THRESH)&&(gammas[gammas[0].oldest_non_scaled].newest_scaled==gammas[0].oldest_non_scaled)){// no scaled for the oldest hash
// sacrifice oldest hash
tmp_p=gammas[0].oldest_non_scaled;
remove_from_nonscaled(tmp_p);
}else{// use oldest scaled
tmp_p=gammas[0].oldest_all;
// skip locked if any (should be unlikely to get any locked)
set_gamma_table(0,GAMMA_SCLALE_1,NULL,0,0,0,0);// maybe not needed to put linear to cache - it can be calculated as soon FPGA will be tried to be programmed with
set_gamma_table(0,GAMMA_SCLALE_1,NULL,0,0,0,0);// maybe not needed to put linear to cache - it can be calculated as soon FPGA will be tried to be programmed with
MDF1(printk("copied %d bytes of sensor static parameters\r\n",sizeof(mt9p001)));
add_sensor_proc(onchange_detectsensor,&mt9x001_pgm_detectsensor);// detect sensor type, sets sensor structure (capabilities), function pointers NOTE: will be called directly, not through pointers
add_sensor_proc(onchange_initsensor,&mt9x001_pgm_initsensor);// resets sensor, reads sensor registers, schedules "secret" manufacturer's corrections to the registers (stops/re-enables hardware i2c)
add_sensor_proc(onchange_exposure,&mt9x001_pgm_exposure);// program exposure
add_sensor_proc(onchange_window,&mt9x001_pgm_window);// program sensor WOI and mirroring (flipping)
add_sensor_proc(onchange_window_safe,&mt9x001_pgm_window_safe);// program sensor WOI and mirroring (flipping) - now - only flipping? with lower latency
add_sensor_proc(onchange_limitfps,&mt9x001_pgm_limitfps);// check compressor will keep up, limit sensor FPS if needed
add_sensor_proc(onchange_gains,&mt9x001_pgm_gains);// program analog gains
add_sensor_proc(onchange_triggermode,&mt9x001_pgm_triggermode);// program sensor trigger mode
add_sensor_proc(onchange_sensorregs,&mt9x001_pgm_sensorregs);// write sensor registers (only changed from outside the driver as they may have different latencies)?
dev_dbg(g_dev_ptr,"{%d} copied %d bytes of sensor static parameters\n",sensor_port,sizeof(mt9p001));
add_sensor_proc(sensor_port,onchange_detectsensor,&mt9x001_pgm_detectsensor);// detect sensor type, sets sensor structure (capabilities), function pointers NOTE: will be called directly, not through pointers
add_sensor_proc(sensor_port,onchange_initsensor,&mt9x001_pgm_initsensor);// resets sensor, reads sensor registers, schedules "secret" manufacturer's corrections to the registers (stops/re-enables hardware i2c)
add_sensor_proc(sensor_port,onchange_exposure,&mt9x001_pgm_exposure);// program exposure
add_sensor_proc(sensor_port,onchange_window,&mt9x001_pgm_window);// program sensor WOI and mirroring (flipping)
add_sensor_proc(sensor_port,onchange_window_safe,&mt9x001_pgm_window_safe);// program sensor WOI and mirroring (flipping) - now - only flipping? with lower latency
add_sensor_proc(sensor_port,onchange_limitfps,&mt9x001_pgm_limitfps);// check compressor will keep up, limit sensor FPS if needed
add_sensor_proc(sensor_port,onchange_gains,&mt9x001_pgm_gains);// program analog gains
add_sensor_proc(sensor_port,onchange_triggermode,&mt9x001_pgm_triggermode);// program sensor trigger mode
add_sensor_proc(sensor_port,onchange_sensorregs,&mt9x001_pgm_sensorregs);// write sensor registers (only changed from outside the driver as they may have different latencies)?
// if video exposure is non-zero, P_VEXPOS is marked as modified or P_EXPOS is not modified - use video exposure (lines), else - absolute exposure (usec)
if((video_exposure>0)&&(FRAMEPAR_MODIFIED(P_VEXPOS)||!(FRAMEPAR_MODIFIED(P_EXPOS)||FRAMEPAR_MODIFIED(P_VIRT_WIDTH)))){// use number of lines
// send all parameters marked as "needed to be processed" to the sensor, clear those flags
// mask out all non sensor pars
...
...
@@ -1972,7 +1990,7 @@ int mt9x001_pgm_sensorregs (int sensor_port, ///< sensor port
// unsigned long bmask32= ((thispars->mod32) >> (P_SENSOR_REGS>>5)) & (P_SENSOR_NUMREGS-1) ; // wromg!, only valid for P_SENSOR_NUMREGS==256 (that is the case, actually)
@@ -2021,10 +2039,10 @@ int mt9x001_pgm_sensorregs (int sensor_port, ///< sensor port
bmask32=((thispars->mod32)>>(P_MULTI_REGS>>5))&((1<<((((MAX_SENSORS)*(P_MULTI_NUMREGS))>>5)+1))-1);// added one not to miss parameters with the last group of 32
}elseif((wt+wh-height1-vblank2)<(height2+vblank3+(sensor->minHeight*dv))){// Only first 2 sensors are needed - reduce second frame (10359, not the sensor)
height2=wh+wt-height1-vblank2;// only 10359, not the sensor
}else{// all 3 sensors needed, adjust height3 to make sure 10359 sends out exactly wh/dv lines (vblank* could be adjusted to compensate for Bayer when flipping)
printk("invalid 10359 bitstream version, found 0x%08lx, required >= 0x%08x\n",bitstream_version,I2C359_MINVERSION);
...
...
@@ -1023,8 +1032,8 @@ int multisensor_pgm_detectsensor (int sensor_port, ///< sensor p
GLOBALPARS(sensor_port,G_SENS_AVAIL)|=1<<(GLOBALPARS(sensor_port,G_SENS_AVAIL));// temporary to indicate sensor detection functions that they need to initialize multisensor registers
for(i=0;i<MAX_SENSORS;i++){
MDF24(printk("Probing sensor port %d, i2c bitdelays=0x%08x\n",i,i2c_delays(0)));
#ifdef NC353
dev_dbg(g_dev_ptr,"%s Probing sensor port %d, i2c bitdelays=0x%08x\n",__func__,i,i2c_delays(0));
rslt=multisensor_read_i2c(sensor_port,
MT9P001_I2C_ADDR+((i+1)*I2C359_INC),
P_MT9X001_CHIPVER,
...
...
@@ -1036,7 +1045,7 @@ int multisensor_pgm_detectsensor (int sensor_port, ///< sensor p
P_MT9X001_CHIPVER,
&sensor_id[i]);
#endif
MDF24(printk("Probing sensor port %d, i2c bitdelays=0x%08x, rslt=0x%x\n",i,i2c_delays(0),rslt));
// dev_dbg(g_dev_ptr,"%s Probing sensor port %d, i2c bitdelays=0x%08x, rslt=0x%x\n",__func__,i,i2c_delays(0),rslt);
Now overwrite sensor functions with it's own (originals (physical sensor ones) are already copied to the local structure
*/
// add_sensor_proc(onchange_multisens, &multisensor_pgm_multisens); // process 10359-specific parameters
add_sensor_proc(onchange_sensorregs,&multisensor_pgm_sensorregs);// write sensor 10359 registers (only changed from outside the driver)
add_sensor_proc(onchange_window,&multisensor_pgm_window);// program sensor WOI and mirroring (flipping)
add_sensor_proc(onchange_window_safe,&multisensor_pgm_window_safe);// program sensor WOI and mirroring (flipping) - now - only flipping? with lower latency
// add_sensor_proc(sensor_port,onchange_multisens, &multisensor_pgm_multisens); // process 10359-specific parameters
add_sensor_proc(sensor_port,onchange_sensorregs,&multisensor_pgm_sensorregs);// write sensor 10359 registers (only changed from outside the driver)
add_sensor_proc(sensor_port,onchange_window,&multisensor_pgm_window);// program sensor WOI and mirroring (flipping)
add_sensor_proc(sensor_port,onchange_window_safe,&multisensor_pgm_window_safe);// program sensor WOI and mirroring (flipping) - now - only flipping? with lower latency
// Initialize other 10359A parameters (move it to init/afterinit?)
...
...
@@ -1180,7 +1189,7 @@ int multisensor_pgm_multisens (int sensor_port, ///< sensor port n
if(!sensor_mask)sensor_mask=GLOBALPARS(sensor_port,G_SENS_AVAIL);// if none sensors were enabled - enable all what is available (same as with WOI size)
...
...
@@ -1201,8 +1210,8 @@ int multisensor_pgm_multisens (int sensor_port, ///< sensor port n
// TODO: recalculate sequence when MULTISENS_EN is chnaged (tried 5 - did not modify sequence, showed first frame only)
// Here - only recalculate SENSOR_HEIGHT, skipping disabled sensors. in multisensor_pgm_window() will need to skip disabled also
// No above is not really needed, sequence+enable can be handled by application software
if(multi_unitialized&&(!composite)&&(prev_composite||((new_sensor>=0)&&(old_sensor!=new_sensor)))){// now single-sensor mode, set P_WOI* from saved parameters
// add_sensor_proc(onchange_sensorregs, &mt9x001_pgm_sensorregs); // write sensor registers (only changed from outside the driver as they may have different latencies)?
// add_sensor_proc(sensor_port,onchange_sensorregs, &mt9x001_pgm_sensorregs); // write sensor registers (only changed from outside the driver as they may have different latencies)?
//#define SET_10359_REG(f,r,v)
// send all parameters marked as "needed to be processed" to the sensor, clear those flags
// mask out all non sensor pars
// It will be the first for the frame (before automatic sensor changes).
// Add testing for programmed sensor and move vbalues to later frames (not here but in the pgm_functions)
#define P_MAX_GPAR (NUM_GPAR - 1) ///< maximal # of global parameter - TODO: change name to NUM_GPAR and make it 2048
#define PARS_SAVE_FROM 128 ///< PARS_SAVE_NUM parameters starting from PARS_SAVE_FROM from "this" frame will be saved in circular buffer, PASTPARS_SAVE_ENTRIES entries
#define PARS_SAVE_COPY 16 ///< number of parameters copied from future (framepars) to the past (pastpars)
#define PARS_SAVE_COPY 18 ///< number of parameters copied from future (framepars) to the past (pastpars)
#define PARS_SAVE_NUM 32 ///< total size of previous parameter save page
#define PP_PROFILE_START 16 ///< index of the first profile timestamp in pastpars
#define PP_PROFILE_START PARS_SAVE_COPY ///< index of the first profile timestamp in pastpars
#define P_PROFILE (PARS_SAVE_FROM + PP_PROFILE_START) ///< index to access profiles as pastpars (i.e. from PHP ELPHEL_PROFILE1,PHP ELPHEL_PROFILE2)
#define FRAMEPAR_GLOBALS 0x01000 ///< start of global (not frame-related) parameters
...
...
@@ -758,6 +760,10 @@
//#define G_HIST_Y_FRAME (FRAMEPAR_GLOBALS + 57) // /< last frame for which Y histogram was calculated
//#define G_HIST_C_FRAME (FRAMEPAR_GLOBALS + 58) // /< last frame for which C histograms were calculated
#define G_SUBCHANNELS (FRAMEPAR_GLOBALS + 56) ///< subchannels used on this sensor port (bitmask)
#define G_COMPRESSOR_FRAME (FRAMEPAR_GLOBALS + 57) ///< last compressed frame number
//Gap 2 DWORDS
#define G_SKIP_DIFF_FRAME (FRAMEPAR_GLOBALS + 59) ///< number of frames with different size to tolerate before producing POLLHUP in poll(circbuf)
#define G_FTP_NEXT_TIME (FRAMEPAR_GLOBALS + 60) ///< time of the next FTP upload (seconds from epoch)
...
...
@@ -925,40 +931,40 @@ struct framepars_t {
* TODO: Try to make room for some new ones.
*/
enumonchange_functions_t{
onchange_recalcseq=0,///< recalculate sequences/latencies, according to P_SKIP, P_TRIG
onchange_detectsensor,///< detect sensor type, sets sensor structure (capabilities), function pointers
onchange_sensorphase,///< program sensor clock/phase (needs to know maximal clock frequency)
onchange_i2c,///< program i2c
onchange_sensorregs,///< write sensor registers (only changed from outside the driver as they may have different latencies)?
onchange_initsensor,///< resets sensor, reads sensor registers, schedules "secret" manufacturer's corrections to the registers (stops/re-enables hardware i2c)
onchange_afterinit,///< restore image size, decimation,... after sensor reset or set them according to sensor capabilities if none were specified
onchange_multisens,///< chnages related to multiplexed sensors
onchange_window,///< program sensor WOI and mirroring (flipping)
onchange_window_safe,///< program sensor WOI and mirroring (flipping) - lower latency, no bad frames
onchange_recalcseq=0,///< 0 recalculate sequences/latencies, according to P_SKIP, P_TRIG