sensor_common.c 52.7 KB
Newer Older
Andrey Filippov's avatar
Andrey Filippov committed
1 2
/**
 * @file sensor_common.c
3 4 5 6 7 8 9 10
 * @brief This module handles sensor discovery, initialization and programming tasks
 * common for all sensors. Task that are implemented:
 * - system initialization (?)
 * - compressor write (and global read) pointers
 * - populating 32-byte interframe data
 * - interrupts handling
 * - tasklets
 * - device driver that includes waiting for the next frame regardless of compression
Andrey Filippov's avatar
Andrey Filippov committed
11
 * @copyright Copyright (C) 2016 Elphel, Inc.
12
 * @par <b>License</b>
13 14 15 16 17 18 19 20 21 22 23 24 25
 *  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
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
Mikhail Karpenko's avatar
Mikhail Karpenko committed
26 27 28 29 30 31 32

//copied from cxi2c.c - TODO:remove unneeded
#include <linux/sched.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/time.h>
33
#include <linux/platform_device.h>
34 35
#include <asm/outercache.h>
#include <asm/cacheflush.h>
36

37 38 39
#include <linux/spinlock.h>


40 41
#include <uapi/elphel/c313a.h>
#include <uapi/elphel/exifa.h>
42
//#include <uapi/elphel/x393_devices.h>
Mikhail Karpenko's avatar
Mikhail Karpenko committed
43 44 45

#include "framepars.h"
#include "sensor_common.h"
46
#include "pgm_functions.h"
Mikhail Karpenko's avatar
Mikhail Karpenko committed
47
#include "circbuf.h"
48
#include "exif393.h"
49 50
#include "histograms.h"
#include "gamma_tables.h"
Mikhail Karpenko's avatar
Mikhail Karpenko committed
51
#include "quantization_tables.h"
52
#include "x393_macro.h"
53
#include "x393.h"
54
//#include "x393_helpers.h"
Mikhail Karpenko's avatar
Mikhail Karpenko committed
55

56 57
#include <asm/delay.h> // just for usleep1000()

58
#include "x393_fpga_functions.h"
Andrey Filippov's avatar
Andrey Filippov committed
59 60 61
// NC393 debug macros
#include "debug393.h"

62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78
static DEFINE_SPINLOCK(framepars_irq_0); ///<
static DEFINE_SPINLOCK(framepars_irq_1); ///<
static DEFINE_SPINLOCK(framepars_irq_2); ///<
static DEFINE_SPINLOCK(framepars_irq_3); ///<
/** Define array of pointers to locks - hardware allows concurrent writes to different ports tables */
spinlock_t * frame_irq_locks[4] = {&framepars_irq_0, &framepars_irq_1, &framepars_irq_2, &framepars_irq_3};

static DEFINE_SPINLOCK(compressor_irq_0); ///<
static DEFINE_SPINLOCK(compressor_irq_1); ///<
static DEFINE_SPINLOCK(compressor_irq_2); ///<
static DEFINE_SPINLOCK(compressor_irq_3); ///<
/** Define array of pointers to locks - hardware allows concurrent writes to different ports tables */
spinlock_t * compressor_locks[4] = {&compressor_irq_0, &compressor_irq_1, &compressor_irq_2, &compressor_irq_3};




79 80
/* Driver name to display in log messages.*/
//#define IMAGEACQ_DRIVER_DESCRIPTION      "Elphel (R) Model 393 Image Acquisition device driver"
Andrey Filippov's avatar
Andrey Filippov committed
81 82

/** @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.*/
83
#define L2_INVAL_SIZE             (32 * 1024)
84

Andrey Filippov's avatar
Andrey Filippov committed
85 86 87
/** @brief Global pointer to basic device structure. This pointer is used in debugfs output functions */
static struct device *g_dev_ptr;

Andrey Filippov's avatar
Andrey Filippov committed
88
/** @brief Contains read and write pointers along with IRQ number for a single channel*/
89
struct jpeg_ptr_t {
90
    volatile u32 frame;          ///< Absolute frame number (last compressed)
Andrey Filippov's avatar
Andrey Filippov committed
91 92 93 94 95 96
	volatile int jpeg_wp;        ///< JPEG write pointer in 32 bit words
	volatile int jpeg_rp;        ///< JPEG read pointer in 32 bit words
	volatile int fpga_cntr_prev; ///< This field contains previous value of the FPGA transfer counter which is used to find out if it has changed. This pointer is in 32 bit words.
	unsigned int irq_num_comp;   ///< IRQ number associated with compressor
	unsigned int irq_num_sens;   ///< IRQ number associated with sensor
	unsigned int chn_num;        ///< Current channel number
97
	volatile unsigned int flags;
98
};
Mikhail Karpenko's avatar
Mikhail Karpenko committed
99

100 101 102 103 104 105 106 107 108 109 110 111
// just temporarily
 void i2c_run(void)      {}
 void i2c_stop_wait(void){}
 void udelay1000(int ms)
 {
     int i;
     for (i=0;i<ms;i++) udelay(1000);
 }




Andrey Filippov's avatar
Andrey Filippov committed
112
/** @brief Contains private data for the image acquisition driver */
113
struct image_acq_pd_t {
Andrey Filippov's avatar
Andrey Filippov committed
114 115
	int minor;								   ///< Driver minor number
	struct jpeg_ptr_t jpeg_ptr[SENSOR_PORTS];  ///< Array of read/write pointers
116
};
Andrey Filippov's avatar
Andrey Filippov committed
117 118


119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145
/* 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 image_acq_priv;

Andrey Filippov's avatar
Andrey Filippov committed
146 147 148 149 150 151
u32 get_compressor_frame(unsigned int chn) ///< Sensor port number (0..3)
                                           ///< @return absolute compressed frame number
{
    return image_acq_priv.jpeg_ptr[chn & 3].frame;
}

Andrey Filippov's avatar
Andrey Filippov committed
152 153 154 155 156 157 158
//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)

/** @brief  Works like a cache to time save on looking for tags in the directory (forced to recalculate if does not match)
 *  will have offset of the Exif_Image_DateTime data in meta page (Exif_Photo_SubSecTime should go immediately after in meta page)
 */
159
static struct meta_offsets_t { //
Andrey Filippov's avatar
Andrey Filippov committed
160
	int Image_DateTime;           ///< EXIF Date/Time offset
161
	                              ///< Has offset of the Exif_Image_DateTime data in meta page (Exif_Photo_SubSecTime should go immediately after in meta page)
Andrey Filippov's avatar
Andrey Filippov committed
162 163 164 165 166 167
	int Photo_DateTimeOriginal;   ///< EXIF Date/Time Original offset
	int Photo_ExposureTime;       ///< EXIF exposure offset
	int Image_ImageNumber;        ///< EXIF image number offset
	int Image_Orientation;        ///< EXIF image orientation offset
	int Photo_MakerNote;          ///< EXIF maker note (custom data for multi-frame composite images) offset
	int PageNumber;               ///< EXIF subchannel (0..3) number offset
168
} meta_offsets;
Mikhail Karpenko's avatar
Mikhail Karpenko committed
169

170 171 172 173 174 175 176 177 178 179 180 181
#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 */
182

183
/** Write pointer in circbuf, in bytes */
184
int camseq_get_jpeg_wp(unsigned int chn)
185
{
186
	return (chn < SENSOR_PORTS) ? image_acq_priv.jpeg_ptr[chn].jpeg_wp : 0;
187 188
}

189
int camseq_get_jpeg_rp(unsigned int chn)
190
{
191
	return (chn < SENSOR_PORTS) ? image_acq_priv.jpeg_ptr[chn].jpeg_rp : 0;
192 193
}

194
void camseq_set_jpeg_rp(unsigned int chn, int ptr) // ptr in bytes
195
{
196
	if (chn < SENSOR_PORTS) {
197
		image_acq_priv.jpeg_ptr[chn].jpeg_rp = ptr >> 2;
198

199
	    set_globalParam(chn, G_CIRCBUFRP, ptr);  // in bytes (same as in 353)
200 201 202 203
	    set_globalParam(chn, G_FREECIRCBUF,
	            (((get_globalParam(chn, G_CIRCBUFRP) <= get_globalParam(chn, G_CIRCBUFWP))?
	                    get_globalParam(chn, G_CIRCBUFSIZE):0)+ get_globalParam(chn, G_CIRCBUFRP))
	                    - get_globalParam(chn, G_CIRCBUFWP));
204 205
	}
}
206 207 208 209 210
/** Get latest compressed frame number */
int camSeqGetJPEG_frame(unsigned int chn)
{
    return (chn < SENSOR_PORTS) ? image_acq_priv.jpeg_ptr[chn].frame : 0;
}
211 212 213 214 215 216 217

/** Write pointer in circbuf, in DWORDs */
int camSeqGetJPEG_wp(unsigned int chn)
{
    return (chn < SENSOR_PORTS) ? image_acq_priv.jpeg_ptr[chn].jpeg_wp : 0;
}

218
int camSeqGetJPEG_rp(unsigned int chn) // return in DWORDs, not in bytes
219 220 221 222 223 224
{
    return (chn < SENSOR_PORTS) ? image_acq_priv.jpeg_ptr[chn].jpeg_rp : 0;
}

void camSeqSetJPEG_rp(unsigned int chn, ///< channel (0..3)
                      int ptr)          /// DWORD index in the buffer
225

226 227
{
    if (chn < SENSOR_PORTS) {
228 229
//        image_acq_priv.jpeg_ptr[chn].jpeg_rp = ptr << 2;
        image_acq_priv.jpeg_ptr[chn].jpeg_rp = ptr ;
230

231 232
//        set_globalParam(chn, G_CIRCBUFRP, ptr); // wrong! should be in bytes
        set_globalParam(chn, G_CIRCBUFRP, ptr << 2); // this is as in nc353
233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250
        set_globalParam(chn, G_FREECIRCBUF,
                (((get_globalParam(chn, G_CIRCBUFRP) <= get_globalParam(chn, G_CIRCBUFWP))?
                        get_globalParam(chn, G_CIRCBUFSIZE):0)+ get_globalParam(chn, G_CIRCBUFRP))
                        - get_globalParam(chn, G_CIRCBUFWP));
    }
}
#ifdef NC353
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

251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276
/** Return current frame number, if it was from the compressor interrupt
 * get the compressed frame number (updated when compression is over,
 * can happen even later than start of the next frame.
 * Otherwise use command sequencer (switching at frame sync (start of frame)
 * TODO: at each frame interrupt check how far is compressor behind,
 * take over if >=2 ? */
int getHardFrameNumber(int sensor_port,     ///< Sensor port number
		               int use_compressor)  ///< 1 - use compressor frame number, 0 - use sequencer frame number
		                                    ///< @return hardware frame number (4 bit currently, mod PARS_FRAMES )
{
	x393_cmprs_status_t cmprs_status;
	x393_cmdseqmux_status_t cmdseqmux_status;
	if (use_compressor) {
		cmprs_status = x393_cmprs_status(sensor_port);
		return cmprs_status.frame;
	} else {
		cmdseqmux_status = x393_cmdseqmux_status();
		switch(sensor_port){
		case 0:  return cmdseqmux_status.frame_num0;
		case 1:  return cmdseqmux_status.frame_num1;
		case 2:  return cmdseqmux_status.frame_num2;
		default: return cmdseqmux_status.frame_num3;
		}
	}

}
Mikhail Karpenko's avatar
Mikhail Karpenko committed
277 278 279

/*!
   End of compressor-related code - TODO: move to a separate file?
280
 */
Mikhail Karpenko's avatar
Mikhail Karpenko committed
281

282
static const struct of_device_id elphel393_sensor_of_match[];
283 284
static struct sensorproc_t as_sensorproc[SENSOR_PORTS]; // sensor parameters and functions to call
struct sensorproc_t * asensorproc = NULL;
285
//EXPORT_SYMBOL_GPL(sensorproc);
286
//wait_queue_head_t image_acq_wait_queue;  // queue for the sensor frame interrupts
Mikhail Karpenko's avatar
Mikhail Karpenko committed
287 288


Andrey Filippov's avatar
Andrey Filippov committed
289 290
void tasklet_cmdseq_function(unsigned long arg);
void tasklet_compressor_function(unsigned long arg);
Mikhail Karpenko's avatar
Mikhail Karpenko committed
291 292

/**
293 294
 * @brief Copy #sensorproc structure, needed for multisensor board to be able
 * to replace some of the functions
295
 * @param[in]   sensor_port sensor port number
296 297
 * @param[in]   copy   pointer to a copy structure
 * @return      pointer to a \b copy structure
Mikhail Karpenko's avatar
Mikhail Karpenko committed
298
 */
299
struct sensorproc_t * copy_sensorproc (int sensor_port, struct sensorproc_t * copy)
300 301
{
	/** copy sensor functions */
302
	memcpy(copy, &asensorproc[sensor_port], sizeof(struct sensorproc_t));
303
	return copy;
Mikhail Karpenko's avatar
Mikhail Karpenko committed
304 305
}

306
//#ifdef TEST_DISABLE_CODE
Mikhail Karpenko's avatar
Mikhail Karpenko committed
307 308


309
//
310 311 312 313 314 315 316
// initializes structures for the image acquisition parameter
// initializes hardware i2c controller and the command sequencer (leaves them stopped to ignore any frame syncs)
// sets some default acquisition parameters
// Maybe - set up DMA also?
// TODO: Take care while turning off reset on i2c and cmd_sequencer so there will be no sensor vsync lost
// (easier to do in FPGA)
// Done:
317 318 319
// #define CCAM_VSYNC_ON  port_csp0_addr[X313_WA_DCR1]=X353_DCR1(BLOCKVSYNC,0)
// #define CCAM_VSYNC_OFF port_csp0_addr[X313_WA_DCR1]=X353_DCR1(BLOCKVSYNC,1)
//
320
int init_acq_sensor(void); // Never used?
Mikhail Karpenko's avatar
Mikhail Karpenko committed
321

Andrey Filippov's avatar
Andrey Filippov committed
322 323 324 325 326 327 328 329 330 331 332 333
//DECLARE_TASKLET(tasklet_cmdseq, tasklet_cmdseq_function, 0); // 0 - no arguments for now
DECLARE_TASKLET(tasklet_cmdseq_0, tasklet_cmdseq_function, 0); // 0 - no arguments for now
DECLARE_TASKLET(tasklet_cmdseq_1, tasklet_cmdseq_function, 1); // 0 - no arguments for now
DECLARE_TASKLET(tasklet_cmdseq_2, tasklet_cmdseq_function, 2); // 0 - no arguments for now
DECLARE_TASKLET(tasklet_cmdseq_3, tasklet_cmdseq_function, 3); // 0 - no arguments for now
static struct tasklet_struct *tasklet_cmdseq[SENSOR_PORTS] = {&tasklet_cmdseq_0, &tasklet_cmdseq_1, &tasklet_cmdseq_2, &tasklet_cmdseq_3};

DECLARE_TASKLET(tasklet_compressor_0, tasklet_compressor_function, 0); // 0 - no arguments for now
DECLARE_TASKLET(tasklet_compressor_1, tasklet_compressor_function, 1); // 0 - no arguments for now
DECLARE_TASKLET(tasklet_compressor_2, tasklet_compressor_function, 2); // 0 - no arguments for now
DECLARE_TASKLET(tasklet_compressor_3, tasklet_compressor_function, 3); // 0 - no arguments for now
static struct tasklet_struct *tasklets_compressor[SENSOR_PORTS] = {&tasklet_compressor_0, &tasklet_compressor_1, &tasklet_compressor_2, &tasklet_compressor_3};
Mikhail Karpenko's avatar
Mikhail Karpenko committed
334 335 336


/**
337 338 339 340 341 342 343
 * @brief Reads FPGA data pointer from the channel given and updates its JPEG_wp
 *
 * This function gets current pointer inside frame buffer and compares it with the previous
 * value. It returns immediately if pointer has not advanced or updates \e jpeg_wr field in #jpeg_ptr_t for
 * current channel. It also tracks the situation when the pointer rolls over.
 * @param[in]   jptr   pointer to #jpeg_ptr_t structure for the channel which data is to be modified
 * @return 0 if compressor was off (no advance) or 1 if write pointer did actually advance
Mikhail Karpenko's avatar
Mikhail Karpenko committed
344
 */
345 346
static inline int updateIRQJPEG_wp(struct jpeg_ptr_t *jptr)
{
347 348 349
	phys_addr_t phys_addr;
	void *virt_addr;
	//	int prev_dword;
350
	int xferred;                                           // number of 32-byte chunks transferred since compressor was reset
Andrey Filippov's avatar
Andrey Filippov committed
351
//	x393_cmdseqmux_status_t cmdseqmux_status;
352
	x393_afimux_status_t stat = x393_afimux0_status(jptr->chn_num);
Andrey Filippov's avatar
Andrey Filippov committed
353 354
	int frame16;
	u32 aframe = GLOBALPARS(jptr->chn_num,G_THIS_FRAME); // thisFrameNumber(jptr->chn_num); // current absolute frame number
355 356

	xferred = stat.offset256 - (jptr->fpga_cntr_prev >> 3);
357
	if (xferred == 0)
358
		return 0;                                          // no advance (compressor was off?)
359

360
	jptr->flags |= SENS_FLAG_IRQ;
361 362 363
	jptr->fpga_cntr_prev = jptr->jpeg_wp;
	jptr->jpeg_wp = (stat.offset256 << 3);

Andrey Filippov's avatar
Andrey Filippov committed
364 365 366
// Find absolute frame number just compressed WRONG, should use comressor frame number
//	cmdseqmux_status = x393_cmdseqmux_status(); // CMDSEQMUX status data (frame numbers and interrupts
	frame16 = getHardFrameNumber(jptr->chn_num, 1); // Use compressor
367

Andrey Filippov's avatar
Andrey Filippov committed
368
	if (frame16 > (aframe & PARS_FRAMES_MASK))
369
	    aframe -= 16;
Andrey Filippov's avatar
Andrey Filippov committed
370 371
	jptr->frame = (aframe & ~PARS_FRAMES_MASK) | frame16; // This is absolute compressed frame number, may lag behind current one

372 373 374 375 376 377 378 379 380 381 382 383 384 385
	/* 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];
	}

	// 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);
386 387

	return 1;
Mikhail Karpenko's avatar
Mikhail Karpenko committed
388
}
389

Mikhail Karpenko's avatar
Mikhail Karpenko committed
390
/**
Andrey Filippov's avatar
Andrey Filippov committed
391
 * Calculate/update CIRCBUF parameters available after compressor interrupt
Mikhail Karpenko's avatar
Mikhail Karpenko committed
392
 */
393
inline void update_irq_circbuf(struct jpeg_ptr_t *jptr) {
Andrey Filippov's avatar
Andrey Filippov committed
394
	/*set_globalParam (G_CIRCBUFWP, JPEG_wp<<2);set_globalParam (G_FREECIRCBUF, (((get_globalParam (G_CIRCBUFRP) <= get_globalParam (G_CIRCBUFWP))? get_globalParam (G_CIRCBUFSIZE):0)+
395 396
                                     get_globalParam (G_CIRCBUFRP)) -    get_globalParam (G_CIRCBUFWP));*/
	/* the concept of global parameters will be changed, use one channel only for testing */
397 398 399
//	set_globalParam(jptr->chn_num, G_CIRCBUFWP, jptr->jpeg_wp);

    set_globalParam(jptr->chn_num, G_CIRCBUFWP, jptr->jpeg_wp << 2); // jptr->jpeg_wp in 32-bit words, G_CIRCBUFWP - in bytes
Andrey Filippov's avatar
Andrey Filippov committed
400 401
	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)+
402
			get_globalParam (jptr->chn_num, G_CIRCBUFRP)) -    get_globalParam (jptr->chn_num, G_CIRCBUFWP));
Mikhail Karpenko's avatar
Mikhail Karpenko committed
403 404 405 406 407
}
/**
 * @brief Calculate/update focus parameters available after compressor interrupt
 * NOTE: currently global (latest), not per-frame
 */
408 409
inline void updateIRQFocus(struct jpeg_ptr_t *jptr)
{
410 411
	//set_globalParam     (G_GFOCUS_VALUE, X313_HIGHFREQ);
	//set_imageParamsThis (P_FOCUS_VALUE, X313_HIGHFREQ);
412
	u32 high_freq = x393_cmprs_hifreq(jptr->chn_num);
413 414
	set_globalParam     (jptr->chn_num, G_GFOCUS_VALUE, high_freq);
	set_imageParamsThis (jptr->chn_num, P_FOCUS_VALUE, high_freq);
Mikhail Karpenko's avatar
Mikhail Karpenko committed
415 416 417 418 419 420
}

/**
 * @brief Locate area between frames in the circular buffer
 * @return pointer to interframe parameters structure
 */
421 422 423 424
inline struct interframe_params_t* updateIRQ_interframe(struct jpeg_ptr_t *jptr)
{
	dma_addr_t phys_addr;
	void *virt_addr;
425
	int chn = jptr->chn_num;
426
	struct interframe_params_t *interframe = NULL;
427
	int len_offset = X393_BUFFSUB_CHN(DW2BYTE(jptr->jpeg_wp), CHUNK_SIZE + 4, chn);
428
	int jpeg_len = circbuf_priv_ptr[jptr->chn_num].buf_ptr[BYTE2DW(len_offset)] & FRAME_LENGTH_MASK;
429
	int jpeg_start = X393_BUFFSUB_CHN(DW2BYTE(jptr->jpeg_wp) - CHUNK_SIZE - INSERTED_BYTES(jpeg_len) - CCAM_MMAP_META, jpeg_len,chn);
430
	// frame_params_offset points to interframe_params_t area before current frame (this parameters belong to the frame below in memory, not the previous)
431 432
	int frame_params_offset = BYTE2DW(X393_BUFFSUB_CHN(jpeg_start, CHUNK_SIZE, chn));
	int prev_len32_off = X393_BUFFSUB_CHN(jpeg_start, CHUNK_SIZE + 4,chn);
433 434 435 436
	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
437
		prev_len32_off = X393_BUFFSUB_CHN(prev_len32_off, 0x20,chn);
438 439
		prev_len32 = circbuf_priv_ptr[jptr->chn_num].buf_ptr[BYTE2DW(prev_len32_off)];
		if ((prev_len32 & MARKER_FF) == MARKER_FF) {
440
			frame_params_offset = BYTE2DW(X393_BUFFADD_CHN(prev_len32_off, 4, jptr->chn_num));
441 442
		}
	}
443 444

	interframe = (struct interframe_params_t *) &circbuf_priv_ptr[jptr->chn_num].buf_ptr[frame_params_offset];
445 446
	interframe->frame_length = jpeg_len;
	interframe->signffff = 0xffff;
447

448
	set_globalParam(jptr->chn_num, G_FRAME_SIZE, jpeg_len);
Mikhail Karpenko's avatar
Mikhail Karpenko committed
449

450 451 452 453 454 455 456
	// 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;
Mikhail Karpenko's avatar
Mikhail Karpenko committed
457
}
Andrey Filippov's avatar
Andrey Filippov committed
458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482
#ifdef NC353
inline struct interframe_params_t* updateIRQ_interframe353(struct jpeg_ptr_t *jptr) {
   int circbuf_size=get_globalParam (G_CIRCBUFSIZE)>>2;
   int alen = jptr->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

   return interframe;
}
#endif




Mikhail Karpenko's avatar
Mikhail Karpenko committed
483

Andrey Filippov's avatar
Andrey Filippov committed
484 485 486 487 488
/** Fill exif data with the current frame data, save pointer to Exif page in the interframe area
 *
 * TODO NC393: Allow lag between current frame and compressor frame, use only previous parameters (among those copied)
 *
 *
Mikhail Karpenko's avatar
Mikhail Karpenko committed
489
 */
Andrey Filippov's avatar
Andrey Filippov committed
490 491 492
inline void updateIRQ_Exif(struct jpeg_ptr_t *jptr,                ///< pointer to jpeg_ptr_t structure with read/write image pointers
                           struct interframe_params_t* interframe) ///< pointer to interframe parameters structure
{
493 494
	unsigned char short_buff[2];
	unsigned int sensor_port = jptr->chn_num;
495 496 497 498 499 500 501
	int  index_time = jptr->jpeg_wp - 11;
    char time_buff[27];
    char * exif_meta_time_string;
    int global_flips, extra_flips;
    unsigned char orientations[]="1638274545273816";
    unsigned char orientation_short[2];
    int maker_offset;
Andrey Filippov's avatar
Andrey Filippov committed
502
    u32 frame =  jptr->frame;
503
//    int frame_index = frame & PASTPARS_SAVE_ENTRIES_MASK;
504
    // NC393: current parameters are valid at compressor done interrupt (after frame sync interrupts latest valid is new frame number - 2
505
    if (index_time<0) index_time+=get_globalParam (sensor_port, G_CIRCBUFSIZE)>>2;
506
	//   struct exif_datetime_t
507
	// calculates datetime([20] and subsec[7], returns  pointer to char[27]
508
	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]);
509
	// may be split in datetime/subsec - now it will not notice missing subsec field in template
510 511
	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
512
    putlong_meta_irq(sensor_port, get_imageParamsFrame(sensor_port, P_EXPOS, frame), &meta_offsets.Photo_ExposureTime,  Exif_Photo_ExposureTime);
Andrey Filippov's avatar
Andrey Filippov committed
513
	putlong_meta_irq(sensor_port, frame, &meta_offsets.Image_ImageNumber,   Exif_Image_ImageNumber);
514
	//Exif_Photo_MakerNote
515
	global_flips=(get_imageParamsFrame(sensor_port, P_FLIPH, frame) & 1) | ((get_imageParamsFrame(sensor_port, P_FLIPV, frame)<<1)  & 2);
516
	extra_flips=0;
517 518
	if (get_imageParamsFrame(sensor_port, P_MULTI_MODE,frame)!=0) {
		extra_flips=get_imageParamsFrame(sensor_port, P_MULTI_MODE_FLIPS,frame);
519 520 521 522
		global_flips=extra_flips & 3;
	}

	orientation_short[0]=0;
523
	orientation_short[1]=0xf & orientations[(get_imageParamsFrame(sensor_port, P_PORTRAIT, frame)&3) | (global_flips<<2)];
524 525 526 527 528 529 530 531 532
	write_meta_irq(sensor_port, orientation_short, &meta_offsets.Image_Orientation,   Exif_Image_Orientation, 2);

	// 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
533
	maker_offset=putlong_meta_irq(sensor_port, get_imageParamsFrame(sensor_port, P_GAINR,frame),   &meta_offsets.Photo_MakerNote, Exif_Photo_MakerNote);
534
	if (maker_offset>0) {
535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550
#if 0 // just debugging
        putlong_meta_raw_irq(sensor_port, frame,                                            maker_offset+ 4);
        putlong_meta_raw_irq(sensor_port, get_imageParamsFrame(sensor_port, P_EXPOS, frame), maker_offset+ 8);
        putlong_meta_raw_irq(sensor_port, ccam_dma_buf_ptr[sensor_port][index_time],        maker_offset+12);
        putlong_meta_raw_irq(sensor_port, ccam_dma_buf_ptr[sensor_port][index_time+1],      maker_offset+16);
#else
		putlong_meta_raw_irq(sensor_port, get_imageParamsFrame(sensor_port, P_GAING,frame),   maker_offset+4);
		putlong_meta_raw_irq(sensor_port, get_imageParamsFrame(sensor_port, P_GAINGB,frame),  maker_offset+8);
		putlong_meta_raw_irq(sensor_port, get_imageParamsFrame(sensor_port, P_GAINB,frame),   maker_offset+12);
		putlong_meta_raw_irq(sensor_port, get_imageParamsFrame(sensor_port, P_GTAB_R,frame),  maker_offset+16);
#endif
		putlong_meta_raw_irq(sensor_port, get_imageParamsFrame(sensor_port, P_GTAB_G,frame),  maker_offset+20);
		putlong_meta_raw_irq(sensor_port, get_imageParamsFrame(sensor_port, P_GTAB_GB,frame), maker_offset+24);
		putlong_meta_raw_irq(sensor_port, get_imageParamsFrame(sensor_port, P_GTAB_B,frame),  maker_offset+28);
		putlong_meta_raw_irq(sensor_port, get_imageParamsFrame(sensor_port, P_WOI_LEFT,frame) | (get_imageParamsFrame(sensor_port, P_WOI_WIDTH,frame)<<16),  maker_offset+32); //No Past
		putlong_meta_raw_irq(sensor_port, get_imageParamsFrame(sensor_port, P_WOI_TOP,frame) | (get_imageParamsFrame(sensor_port, P_WOI_HEIGHT,frame)<<16),  maker_offset+36); //No Past
551
		putlong_meta_raw_irq(sensor_port,   global_flips |
552 553 554 555 556 557
				((get_imageParamsFrame(sensor_port, P_BAYER, frame)<<2)     & 0xc) |
				((get_imageParamsFrame(sensor_port, P_COLOR, frame)<<4)     & 0xF0) |
				((get_imageParamsFrame(sensor_port, P_DCM_HOR, frame)<<8)   & 0xF00) |
				((get_imageParamsFrame(sensor_port, P_DCM_VERT, frame)<<12) & 0xF000) |
				((get_imageParamsFrame(sensor_port, P_BIN_HOR, frame)<<16)  & 0xF0000) |
				((get_imageParamsFrame(sensor_port, P_BIN_VERT, frame)<<20) & 0xF00000) |
558
				(extra_flips <<24) ,  maker_offset+40);
559 560
		putlong_meta_raw_irq(sensor_port, get_imageParamsFrame(sensor_port, P_MULTI_HEIGHT_BLANK1,frame),   maker_offset+44);
		putlong_meta_raw_irq(sensor_port, get_imageParamsFrame(sensor_port, P_MULTI_HEIGHT_BLANK2,frame),   maker_offset+48);
561
		//     putlong_meta_raw_irq(0x1234567,  maker_offset+52); // just testing
562 563 564 565 566
		putlong_meta_raw_irq(sensor_port, get_imageParamsFrame(sensor_port, P_QUALITY, frame) |
		        ((get_imageParamsFrame(sensor_port, P_PORTRAIT, frame)&1)<<7) |
		        ( get_imageParamsFrame(sensor_port, P_CORING_INDEX, frame)<<16),  maker_offset+52);
		putlong_meta_raw_irq(sensor_port, get_imageParamsFrame(sensor_port, G_TEMPERATURE01, frame),  maker_offset+56); // data should be provided by a running daemon
		putlong_meta_raw_irq(sensor_port, get_imageParamsFrame(sensor_port, G_TEMPERATURE23, frame),  maker_offset+60);
567 568 569 570
		//get_globalParam(G_TASKLET_CTL)
		// left 1 long spare (+44)
	}
	interframe->meta_index=store_meta(sensor_port);
Mikhail Karpenko's avatar
Mikhail Karpenko committed
571 572 573 574 575 576 577 578 579 580
}


/**
 * @brief hardware IRQ service
 * most urgent tasks
 * @param irq 
 * @param dev_id 
 * @return 
 */
581
/*static irqreturn_t elphel_FPGA_interrupt(int irq, void *dev_id) {
Mikhail Karpenko's avatar
Mikhail Karpenko committed
582 583 584 585 586
   unsigned long irq_state;

   irq_state = X313_IRQSTATE; //!making dummy read - see c353.h
   DIS_INTERRUPTS;
   PROFILE_NEXT(0);
587
// read hardware write pointer (will only advance if compression was on)
Mikhail Karpenko's avatar
Mikhail Karpenko committed
588 589 590 591
///find out if compressor was running and update pointers, exif, ...?
   if (updateIRQJPEG_wp()) { ///also fills P_FRAME ahead
      updateIRQCircbuf();
      updateIRQFocus(); ///NOTE: currently global (latest), not per-frame
592 593
      struct interframe_params_t* interframe= updateIRQ_interframe(); // fills jpeg_len, signffff
// should we use memcpy as before here?
Mikhail Karpenko's avatar
Mikhail Karpenko committed
594 595 596 597
//      interframe->frame_length=jpeg_len;
//      interframe->signffff=0xffff;
      updateIRQ_Exif(interframe);
      updateFramePars(X3X3_I2C_FRAME, interframe);
598
      wake_up_interruptible(&circbuf_wait_queue); // only when frame is acquired
Mikhail Karpenko's avatar
Mikhail Karpenko committed
599 600 601 602
   } else {
      updateFramePars(X3X3_I2C_FRAME, NULL); 
   }
   PROFILE_NOW(1);
603
   wake_up_interruptible(&framepars_wait_queue); // all interrupts, not just frames acquired
Andrey Filippov's avatar
Andrey Filippov committed
604
   tasklet_schedule(&tasklet_cmdseq); // trigger software interrupt
Mikhail Karpenko's avatar
Mikhail Karpenko committed
605 606 607 608

   EN_INTERRUPT(SMART);

   return IRQ_HANDLED;
609 610
}*/

611 612 613 614 615 616 617 618 619 620
/**
 * @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.
 * @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
 * @return \e IRQ_HANDLED if interrupt was processed and \e IRQ_NONE otherwise
 */
static irqreturn_t frame_sync_irq_handler(int irq, void *dev_id)
{
621
	struct jpeg_ptr_t *jptr = dev_id;
Andrey Filippov's avatar
Andrey Filippov committed
622 623 624
    x393_cmdframeseq_mode_t cmdframeseq_mode = {.d32 = 0};
    unsigned long flags;
    int frame16;
625 626
    u32 aframe;
    cmdframeseq_mode.interrupt_cmd = IRQ_CLEAR;
627 628
//    local_irq_save(flags);
    spin_lock_irqsave(frame_irq_locks[jptr->chn_num],flags);
629
    aframe = GLOBALPARS(jptr->chn_num, G_THIS_FRAME); // thisFrameNumber(jptr->chn_num); // current absolute frame number
Andrey Filippov's avatar
Andrey Filippov committed
630 631 632
    frame16 = getHardFrameNumber(jptr->chn_num, 0); // Use sensor frame number
    updateFramePars     (jptr->chn_num,
                         frame16);
633
	wake_up_interruptible(&aframepars_wait_queue[jptr->chn_num]);
Andrey Filippov's avatar
Andrey Filippov committed
634 635
	//	tasklet_schedule(&tasklet_cmdseq);
	tasklet_schedule(tasklet_cmdseq[jptr->chn_num]);
Andrey Filippov's avatar
Andrey Filippov committed
636
	x393_cmdframeseq_ctrl(cmdframeseq_mode, jptr->chn_num);
637 638
//    local_irq_restore(flags);
    spin_unlock_irqrestore(frame_irq_locks[jptr->chn_num],flags);
639 640 641 642 643 644 645 646
	return IRQ_HANDLED;
}

/**
 * @brief Handle interrupts from JPEG compressor channels. This handler is installed without SA_INTERRUPT
 * 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
647
 * the channel which raised interrupt
648 649 650 651
 * @return \e IRQ_HANDLED if interrupt was processed and \e IRQ_NONE otherwise
 */
static irqreturn_t compressor_irq_handler(int irq, void *dev_id)
{
652 653
	struct jpeg_ptr_t *jptr = dev_id;
	struct interframe_params_t *interframe = NULL;
654
	x393_cmprs_interrupts_t irq_ctrl;
655
//	int frame16;
Andrey Filippov's avatar
Andrey Filippov committed
656
	unsigned long flags;
657

658 659 660 661
//	local_irq_save(flags);
    spin_lock_irqsave(compressor_locks[jptr->chn_num],flags);


Andrey Filippov's avatar
Andrey Filippov committed
662 663 664 665 666 667 668 669
	if (updateIRQJPEG_wp(jptr)) {                // Updates write pointer, invalidates cache, calculates absolute frame number (compressed)
		update_irq_circbuf(jptr);                // Update global parameters (accessible over mmap): G_CIRCBUFWP, G_FREECIRCBUF (depends on user-set G_CIRCBUFRP)
		updateIRQFocus(jptr);                    // Reads FPGA and updates both G_GFOCUS_VALUE and P_FOCUS_VALUE
		interframe = updateIRQ_interframe(jptr); // updates SOME data in the 32-byte gaps between the images:
		                                         // Calculates frame size, adds 0xffff signature to detect buffer overrun
		                                         // invalidates cache

		updateIRQ_Exif(jptr, interframe);        // Updates Exif data for compressed frame (separate ring buffer), extending interframe data
670
		                                         // interframe use: just adds meta_index
Andrey Filippov's avatar
Andrey Filippov committed
671

672
//	    frame16 = getHardFrameNumber(jptr->chn_num, 1); // Use compressor frame number
Andrey Filippov's avatar
Andrey Filippov committed
673
	    // Updarte G_COMPRESSOR_FRAME (from jptr->frame, set other interframe data from past parameters (subset of all parameters preserved after the frame)
Andrey Filippov's avatar
Andrey Filippov committed
674
	    updateInterFrame(jptr->chn_num, // Sensor port number (0..3)
Andrey Filippov's avatar
Andrey Filippov committed
675
	                     jptr->frame,   // absolute compressed frame number, updated in updateIRQJPEG_wp
Andrey Filippov's avatar
Andrey Filippov committed
676 677
	                                    // interrupt should be processed after frame sync interrupt
	                     interframe);   // pointer to the area in circbuf to save parameters
678
	                                    // copies some data from old (but not pastpars) to interframe
Andrey Filippov's avatar
Andrey Filippov committed
679 680
	    tasklet_schedule(tasklets_compressor[jptr->chn_num]);
//		wake_up_interruptible(&circbuf_wait_queue); // should be done in tasklet (after cache invalidation)
681 682
	}
	//wake_up_interruptible(&framepars_wait_queue);
Andrey Filippov's avatar
Andrey Filippov committed
683 684
	//	tasklet_schedule(&tasklet_cmdseq);
//	tasklet_schedule(tasklets_compressor[jptr->chn_num]);
685
	irq_ctrl.interrupt_cmd = IRQ_CLEAR;
686
	x393_cmprs_interrupts(irq_ctrl, jptr->chn_num);
687 688 689
//	local_irq_restore(flags);
    spin_unlock_irqrestore(compressor_locks[jptr->chn_num],flags);

690 691 692
	return IRQ_HANDLED;
}

Mikhail Karpenko's avatar
Mikhail Karpenko committed
693 694 695 696 697 698 699
/**
 * @brief Tasklet - software interrupt
 * lower priority tasks
 * try to implement some balancing - if job is not finished - reduce FPS for it (alternate jobs)?
 * @param arg not used
 */

Andrey Filippov's avatar
Andrey Filippov committed
700 701 702 703
void tasklet_compressor_function(unsigned long arg)
{
    dma_addr_t phys_addr_start, phys_addr_end;
    void *virt_addr_start;
704
//    int sensor_port = image_acq_priv.jpeg_ptr[arg].chn_num; // == arg & 3
Andrey Filippov's avatar
Andrey Filippov committed
705 706
    const struct jpeg_ptr_t *jptr = &image_acq_priv.jpeg_ptr[arg];
    unsigned int sz;
707
    u32 ccam_dma_size = circbuf_priv_ptr[jptr->chn_num].buf_size;
Andrey Filippov's avatar
Andrey Filippov committed
708 709 710 711
    /* 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;
712
    if (sz < ccam_dma_size) {
Andrey Filippov's avatar
Andrey Filippov committed
713 714 715 716
        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 {
717
        phys_addr_end = phys_addr_start + (ccam_dma_size - DW2BYTE(jptr->fpga_cntr_prev) - 1);
Andrey Filippov's avatar
Andrey Filippov committed
718
        outer_inv_range(phys_addr_start, phys_addr_end);
719
        __cpuc_flush_dcache_area(virt_addr_start, ccam_dma_size - DW2BYTE(jptr->fpga_cntr_prev));
Andrey Filippov's avatar
Andrey Filippov committed
720 721

        phys_addr_start = circbuf_priv_ptr[jptr->chn_num].phys_addr;
722
        phys_addr_end = phys_addr_start + (sz - ccam_dma_size - 1);
Andrey Filippov's avatar
Andrey Filippov committed
723 724
        virt_addr_start = circbuf_priv_ptr[jptr->chn_num].buf_ptr;
        outer_inv_range(phys_addr_start, phys_addr_end);
725
        __cpuc_flush_dcache_area(virt_addr_start, sz - ccam_dma_size);
Andrey Filippov's avatar
Andrey Filippov committed
726 727 728 729
    }
    wake_up_interruptible(&circbuf_wait_queue); // should be done in here (after cache invalidation), not in ISR
}

Mikhail Karpenko's avatar
Mikhail Karpenko committed
730 731 732 733 734 735
/*!TODO:

implement 2 modes of controlling when to calculate histograms:
1 - add mask to 3 frame number LSB (i.e. - 0/10000000/10001000/10101010/11111111) - 3 contol bits - en/dis and mode
2 - requested in advance (i.e. by autoexposure when writing new exposure or white balance - when writing balance

736
mode 1 will provide easy way to display histograms (no need to repeatedly request them),
Mikhail Karpenko's avatar
Mikhail Karpenko committed
737 738
mode 2 - useful for autoexposure

739
Modify waiting (LSEEK_*) for histograms so they will only unfreeze if the histogram is available (skipping multiple frames))
Mikhail Karpenko's avatar
Mikhail Karpenko committed
740 741 742
For displaying histograms - try use latest available - not waiting fro a particular frame.


743
 */
Mikhail Karpenko's avatar
Mikhail Karpenko committed
744

745 746
// 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
Mikhail Karpenko's avatar
Mikhail Karpenko committed
747
//#define HISTOGRAMS_WAKEUP_ALWAYS 0
Andrey Filippov's avatar
Andrey Filippov committed
748
void tasklet_cmdseq_function(unsigned long arg)
749 750
{
    int hist_en;
Andrey Filippov's avatar
Andrey Filippov committed
751
    int sensor_port = image_acq_priv.jpeg_ptr[arg].chn_num; // == arg & 3
752 753
    int tasklet_disable=get_globalParam(sensor_port, G_TASKLET_CTL);
    unsigned long thisFrameNumber=getThisFrameNumber(sensor_port);
754
#ifdef ISR_HISTOGRAMS
755 756 757 758
    unsigned long prevFrameNumber=thisFrameNumber-1;
    unsigned long * hash32p=&(aframepars[sensor_port][(thisFrameNumber-1) & PARS_FRAMES_MASK].pars[P_GTAB_R]); // same gamma for all sub-channels
    unsigned long * framep= &(aframepars[sensor_port][(thisFrameNumber-1) & PARS_FRAMES_MASK].pars[P_FRAME]);
    int subchn,hist_indx;
759
#endif
760 761 762


    // Time is out?
Andrey Filippov's avatar
Andrey Filippov committed
763 764 765 766
    if ((getThisFrameNumber(sensor_port) ^ getHardFrameNumber(sensor_port, 0))  & PARS_FRAMES_MASK) {
        dev_dbg(g_dev_ptr, "%s : port= %d, === already next frame (1)\n", __func__, sensor_port);
        return; // already next frame
    }
767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789
    // 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(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(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(sensor_port, P_HISTRQ) & (1<<HISTRQ_BIT_Y));
        break;
    case TASKLET_HIST_RQONLY:  // calculate only when specifically requested
        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;
    }
790 791

    // Actually in NC393 nothing has to be done with histograms at interrupts - do all the processing when histograms are requested
792 793
    //#ifdef TEST_DISABLE_CODE
    if (hist_en) {
794
#ifdef ISR_HISTOGRAMS
Andrey Filippov's avatar
Andrey Filippov committed
795
        histograms_check_init(); // check if histograms are initialized and initialize if not (structures and hardware)
796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812
        // after updateFramePars gammaHash are from framepars[this-1]
        for (subchn=0;subchn<MAX_SENSORS;subchn++) if (((hist_indx=get_hist_index(sensor_port,subchn)))>=0){
            if (PER_CHANNEL393) {
                set_histograms (sensor_port,
                        subchn,
                        prevFrameNumber,
                        (1 << COLOR_Y_NUMBER),
                        hash32p+hist_indx*16*sizeof (u32),
                        framep+hist_indx*32*sizeof (u32)); // 0x2 Green1
            } else {
                set_histograms (sensor_port, subchn, prevFrameNumber, (1 << COLOR_Y_NUMBER), hash32p, framep); // 0x2 Green1
            }
            GLOBALPARS(sensor_port, G_HIST_Y_FRAME + subchn) = prevFrameNumber;           // histogram corresponds to previous frame
        }
        PROFILE_NOW(3);
        // Time is out?
        // Old 353		if ((getThisFrameNumber(sensor_port) ^ X3X3_I2C_FRAME)  & PARS_FRAMES_MASK) return; // already next frame
Andrey Filippov's avatar
Andrey Filippov committed
813 814 815 816 817

        if ((getThisFrameNumber(sensor_port) ^ getHardFrameNumber(sensor_port, 0))  & PARS_FRAMES_MASK) {
            dev_dbg(g_dev_ptr, "%s : port= %d, === already next frame (1)\n", __func__, sensor_port);
            return; // already next frame
        }
818
#endif // ifdef ISR_HISTOGRAMS
Mikhail Karpenko's avatar
Mikhail Karpenko committed
819
#if HISTOGRAMS_WAKEUP_ALWAYS
820
    }
821
    wake_up_interruptible(&ahist_y_wait_queue[sensor_port]);    // wait queue for the G1 histogram (used as Y)
Mikhail Karpenko's avatar
Mikhail Karpenko committed
822
#else
823
    wake_up_interruptible(&ahist_y_wait_queue[sensor_port]);    // wait queue for the G1 histogram (used as Y)
824
    }
Mikhail Karpenko's avatar
Mikhail Karpenko committed
825
#endif
826 827
    // Process parameters
    if ((tasklet_disable & (1 << TASKLET_CTL_PGM))   == 0) {
Andrey Filippov's avatar
Andrey Filippov committed
828 829
        processPars (sensor_port, &asensorproc[sensor_port], getThisFrameNumber(sensor_port), get_globalParam(sensor_port, G_MAXAHEAD)); // program parameters
        PROFILE_NOW(3); // was 5 in NC353
830 831
    }
    // Time is out?
Andrey Filippov's avatar
Andrey Filippov committed
832 833 834 835
    if ((getThisFrameNumber(sensor_port) ^ getHardFrameNumber(sensor_port, 0))  & PARS_FRAMES_MASK) {
        dev_dbg(g_dev_ptr, "%s : port= %d, === already next frame (1)\n", __func__, sensor_port);
        return; // already next frame
    }
836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857
    // Are C histograms needed?
    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(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(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(sensor_port, P_HISTRQ) & (1<<HISTRQ_BIT_C));
        break;
    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)
        hist_en=1;
    }
    if (hist_en) {
858
#ifdef ISR_HISTOGRAMS
Andrey Filippov's avatar
Andrey Filippov committed
859
        histograms_check_init(); // check if histograms are initialized and initialize if not (structures and hardware)
860 861 862 863 864 865 866 867 868 869 870 871 872 873 874
        // after updateFramePars gammaHash are from framepars[this-1]
        // after updateFramePars gammaHash are from framepars[this-1]
        for (subchn=0;subchn<MAX_SENSORS;subchn++) if (((hist_indx=get_hist_index(sensor_port,subchn)))>=0){
            if (PER_CHANNEL393) {
                set_histograms (sensor_port,
                        subchn,
                        prevFrameNumber,
                        0xf, // all colors
                        hash32p+hist_indx*16*sizeof (u32),
                        framep+hist_indx*32*sizeof (u32)); // 0x2 Green1
            } else {
                set_histograms (sensor_port, subchn, prevFrameNumber, 0xf, hash32p, framep); // 0x2 Green1
            }
            GLOBALPARS(sensor_port, G_HIST_C_FRAME + subchn) = prevFrameNumber;           // histogram corresponds to previous frame
        }
Andrey Filippov's avatar
Andrey Filippov committed
875
        PROFILE_NOW(4); // was 5 in NC353
876
        // Time is out?
Andrey Filippov's avatar
Andrey Filippov committed
877 878 879 880
        if ((getThisFrameNumber(sensor_port) ^ getHardFrameNumber(sensor_port, 0))  & PARS_FRAMES_MASK) {
            dev_dbg(g_dev_ptr, "%s : port= %d, === already next frame (1)\n", __func__, sensor_port);
            return; // already next frame
        }
881
#endif // ifdef ISR_HISTOGRAMS
Mikhail Karpenko's avatar
Mikhail Karpenko committed
882
#if HISTOGRAMS_WAKEUP_ALWAYS
883
    }
884
    wake_up_interruptible(&ahist_c_wait_queue[sensor_port]);     // wait queue for all the other (R,G2,B) histograms (color)
Mikhail Karpenko's avatar
Mikhail Karpenko committed
885
#else
886
        wake_up_interruptible(&ahist_c_wait_queue[sensor_port]);   // wait queue for all the other (R,G2,B) histograms (color)
887
    }
Mikhail Karpenko's avatar
Mikhail Karpenko committed
888 889 890
#endif
}

891
//#endif /* TEST_DISABLE_CODE */
Mikhail Karpenko's avatar
Mikhail Karpenko committed
892

893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919
int init_compressor_dma(int chn_mask, int reset)
{ int res;
    int status_mode = 3;
    int report_mode = 0;
    int port_afi = 0;
    dma_addr_t cmprs_sa[4];
    u32 cmprs_len[4];
    int chn;
    struct  circbuf_priv_t * cirbuf_data;
    for (chn = 0; chn <4; chn++) if (chn_mask & (1 << chn)){
        cirbuf_data = get_circbuf(chn);
        cmprs_sa[chn] =  cirbuf_data->phys_addr;
        cmprs_len[chn] = cirbuf_data->buf_size;
    }

    res = compressor_dma_setup (port_afi,
                                chn_mask,
                                reset,
                                status_mode,
                                report_mode,
                                cmprs_sa[0], cmprs_len[0],
                                cmprs_sa[1], cmprs_len[1],
                                cmprs_sa[2], cmprs_len[2],
                                cmprs_sa[3], cmprs_len[3]);
    return res;
}

Mikhail Karpenko's avatar
Mikhail Karpenko committed
920 921 922
/**
 * @brief resets compressor and buffer pointers
 */
923 924 925 926
void reset_compressor(unsigned int chn)
{
	unsigned long flags;

927 928
//	local_irq_save(flags);
    spin_lock_irqsave(frame_irq_locks[chn],flags);
Mikhail Karpenko's avatar
Mikhail Karpenko committed
929
#ifdef TEST_DISABLE_CODE
930
	port_csp0_addr[X313_WA_COMP_CMD]= COMPCMD_RESET; // bypasses command sequencer
931 932
	if (framepars) set_imageParamsR_all( P_COMPRESSOR_RUN, COMPRESSOR_RUN_STOP );
	else printk ("framepars is not initialized\n");
933
	// TODO: There still is a possibility, that there are compressor commands in the hardware que. Should we stop the hardware sequencer here (and restart it later)?
Mikhail Karpenko's avatar
Mikhail Karpenko committed
934
#endif /* TEST_DISABLE_CODE */
935 936 937 938 939
	image_acq_priv.jpeg_ptr[chn].jpeg_wp = 0;
	image_acq_priv.jpeg_ptr[chn].jpeg_rp = 0;
	image_acq_priv.jpeg_ptr[chn].fpga_cntr_prev = 0;
	image_acq_priv.jpeg_ptr[chn].flags = 0;
	//update_irq_circbuf(jptr);
940 941 942
//	local_irq_restore(flags);
    spin_unlock_irqrestore(frame_irq_locks[chn],flags);

Mikhail Karpenko's avatar
Mikhail Karpenko committed
943 944
}

Andrey Filippov's avatar
Andrey Filippov committed
945 946 947 948
/** Camera compressor interrupts on/off */
void compressor_interrupts (int on,   ///< 0 -interrupt disable, 1 - interrupt enable
                            int chn)  ///< compressor channel (0..3)
{
Andrey Filippov's avatar
Andrey Filippov committed
949
//	int i;
Andrey Filippov's avatar
Andrey Filippov committed
950
	x393_cmprs_interrupts_t irq_ctrl =         {.d32=0};
951

Andrey Filippov's avatar
Andrey Filippov committed
952
	//MDF2(printk ("compressor_interrupts(%d)\n",on));
Andrey Filippov's avatar
Andrey Filippov committed
953
	dev_dbg(g_dev_ptr, "Set compressor interrupts for channel %d: %d\n",chn, on);
Mikhail Karpenko's avatar
Mikhail Karpenko committed
954
#ifdef TEST_DISABLE_CODE
955 956 957 958 959
	if (on) {
		EN_INTERRUPT(SMART);
	}  else {
		DIS_INTERRUPTS;
	}
960
	// clear smart interrupt circuitry in any case
961
	port_csp0_addr[X313_WA_SMART_IRQ]=0x8000;
Mikhail Karpenko's avatar
Mikhail Karpenko committed
962

963 964 965 966
	reg_intr_vect_rw_mask intr_mask;
	intr_mask = REG_RD(intr_vect, regi_irq, rw_mask);
	intr_mask.ext = on ? 1 : 0;
	REG_WR(intr_vect, regi_irq, rw_mask, intr_mask);
Mikhail Karpenko's avatar
Mikhail Karpenko committed
967
#endif /* TEST_DISABLE_CODE */
968

Andrey Filippov's avatar
Andrey Filippov committed
969 970 971 972 973 974 975 976 977
	//
	irq_ctrl.interrupt_cmd =         on ? IRQ_ENABLE : IRQ_DISABLE;
	x393_cmprs_interrupts(irq_ctrl, chn);
}

/** Camera sensor (frame sequencer) compressor interrupts on/off */
void sensor_interrupts (int on,   ///< 0 -interrupt disable, 1 - interrupt enable
                        int chn)  ///< compressor channel (0..3)
{
Andrey Filippov's avatar
Andrey Filippov committed
978
//    int i;
Andrey Filippov's avatar
Andrey Filippov committed
979 980 981
    x393_cmdframeseq_mode_t cmdframeseq_mode = {.d32=0};

    //MDF2(printk ("compressor_interrupts(%d)\n",on));
Andrey Filippov's avatar
Andrey Filippov committed
982
    dev_dbg(g_dev_ptr, "set sensor interrupts status: %d\n", on);
Andrey Filippov's avatar
Andrey Filippov committed
983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002
#ifdef TEST_DISABLE_CODE
    if (on) {
        EN_INTERRUPT(SMART);
    }  else {
        DIS_INTERRUPTS;
    }
    // clear smart interrupt circuitry in any case
    port_csp0_addr[X313_WA_SMART_IRQ]=0x8000;

    reg_intr_vect_rw_mask intr_mask;
    intr_mask = REG_RD(intr_vect, regi_irq, rw_mask);
    intr_mask.ext = on ? 1 : 0;
    REG_WR(intr_vect, regi_irq, rw_mask, intr_mask);
#endif /* TEST_DISABLE_CODE */

    //
    cmdframeseq_mode.interrupt_cmd = on ? IRQ_ENABLE : IRQ_DISABLE;
    x393_cmdframeseq_ctrl(cmdframeseq_mode, chn);
}

1003 1004 1005 1006 1007
/** Recover from waiting trigger - internal FPGA or external by re-writing current period to the register in immediate mode
 * If the period was 0 (stopped), use 1 (single) */
void trigger_restart(void)
{
    u32 period = get_x393_camsync_trig_period();
1008
    if (!(period & ~31)) period = 1; // if 0 or bit length setup
1009 1010

    period = 1; // make it always single/not changing any P_*
1011 1012 1013 1014 1015 1016
    set_x393_camsync_trig_period(period);
    dev_dbg(g_dev_ptr, "Reset trigger period in immediate mode = %d (0x%x)\n", (int) period, (int) period);
}



Andrey Filippov's avatar
Andrey Filippov committed
1017 1018 1019 1020 1021 1022
int sequencer_stop_run_reset(int chn,  ///< Sensor port
                             int cmd)  ///< Command: SEQ_CMD_STOP=0 - stop, SEQ_CMD_RUN=1 - run, SEQ_CMD_RESET=2 - reset
                                       ///< @return always 0
{
    x393_cmdframeseq_mode_t cmdframeseq_mode = {.d32 = 0};
    x393_status_ctrl_t status_ctrl = {.d32=0};
Andrey Filippov's avatar
Andrey Filippov committed
1023
    MDP(DBGB_SCRST,chn,"cmd = %d\n",cmd)
Andrey Filippov's avatar
Andrey Filippov committed
1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040
    switch (cmd){
    case SEQ_CMD_STOP:
        cmdframeseq_mode.run_cmd = 2;
        break;
    case SEQ_CMD_RUN:
        cmdframeseq_mode.run_cmd = 3;
        status_ctrl.mode = 3; // autoupdate, is anyway set to it when reading i2c
        break;
    case SEQ_CMD_RESET:
        cmdframeseq_mode.reset =   1;
    }
    if (cmdframeseq_mode.d32)
        x393_cmdframeseq_ctrl (cmdframeseq_mode, chn);
    if (cmd == SEQ_CMD_RESET)
        udelay(1);
    if (status_ctrl.mode)
        set_x393_cmdseqmux_status_ctrl(status_ctrl);
Andrey Filippov's avatar
Andrey Filippov committed
1041 1042 1043
    // debug
    udelay(1);
    MDP(DBGB_SCRST,chn,"status_ctrl.d32 = 0x%x\n",status_ctrl.d32)
Andrey Filippov's avatar
Andrey Filippov committed
1044
    return 0;
Mikhail Karpenko's avatar
Mikhail Karpenko committed
1045 1046
}

1047 1048 1049 1050 1051
/**
 * @brief sensor_common driver probing function
 * @param[in]   pdev   pointer to \b platform_device structure
 * @return      0 on success or negative error code otherwise
 */
1052 1053
//static int image_acq_init(struct platform_device *pdev)
int image_acq_init(struct platform_device *pdev)
1054 1055
{
	int i;
1056
//	int res;
1057 1058
	unsigned int irq;
	struct device *dev = &pdev->dev;
1059
//	const struct of_device_id *match;
1060 1061 1062 1063
	const char *frame_sync_irq_names[4] = {"frame_sync_irq_0", "frame_sync_irq_1",
			"frame_sync_irq_2", "frame_sync_irq_3"};
	const char *compressor_irq_names[4] = {"compr_irq_0", "compr_irq_1",
			"compr_irq_2", "compr_irq_3"};
1064 1065

	/* sanity check */
1066
	/*match = of_match_device(elphel393_sensor_of_match, dev);
1067
	if (!match)
1068
		return -EINVAL;*/
1069

Andrey Filippov's avatar
Andrey Filippov committed
1070 1071
//	asensorproc= &as_sensorproc[0];
    asensorproc= as_sensorproc;
1072
	//MDD1(printk("sensorproc=0x%x\n",(int) sensorproc));
Andrey Filippov's avatar
Andrey Filippov committed
1073
//	dev_dbg(dev, "sensorproc addresses: 0x%x\n", (int) sensorproc);
1074

1075
	for (i = 0; i < SENSOR_PORTS; i++) {
Andrey Filippov's avatar
Andrey Filippov committed
1076
	    dev_dbg(dev, "sensorproc addresses: 0x%x\n", (int) &asensorproc[i]);
1077 1078 1079 1080 1081 1082
		irq = platform_get_irq_byname(pdev, frame_sync_irq_names[i]);
		if (request_irq(irq,
				frame_sync_irq_handler,
				0, // no flags
				frame_sync_irq_names[i],
				&image_acq_priv.jpeg_ptr[i])) {
1083
			dev_err(dev, "can not allocate Elphel FPGA interrupts\n");
1084 1085
			return -EBUSY;
		}
1086
		image_acq_priv.jpeg_ptr[i].irq_num_sens = irq;
Andrey Filippov's avatar
Andrey Filippov committed
1087 1088 1089
        dev_info(dev, "Elphel FPGA interrupts set: %s\n",frame_sync_irq_names[i]);

        irq = platform_get_irq_byname(pdev, compressor_irq_names[i]);
1090 1091 1092 1093 1094
		if (request_irq(irq,
				compressor_irq_handler,
				0, // no flags
				compressor_irq_names[i],
				&image_acq_priv.jpeg_ptr[i])) {
1095
			dev_err(dev, "can not allocate Elphel FPGA interrupts\n");
1096 1097 1098
			return -EBUSY;
		}
		image_acq_priv.jpeg_ptr[i].irq_num_comp = irq;
1099
		image_acq_priv.jpeg_ptr[i].chn_num = i;
Andrey Filippov's avatar
Andrey Filippov committed
1100 1101
        dev_info(dev, "Elphel FPGA interrupts set: %s\n",compressor_irq_names[i]);

1102
	}
Mikhail Karpenko's avatar
Mikhail Karpenko committed
1103

1104 1105 1106 1107 1108 1109
	if (init_mmio_ptr() < 0) {
		dev_err(dev, "unable to remap FPGA registers to memory region\n");
		return -EINVAL;
	}


Mikhail Karpenko's avatar
Mikhail Karpenko committed
1110 1111
#ifdef TEST_DISABLE_CODE

1112 1113 1114 1115 1116 1117 1118 1119
	if(request_irq(EXT_INTR_VECT,
			elphel_FPGA_interrupt,
			SA_INTERRUPT, // SA_SHIRQ | SA_INTERRUPT if it is a shared one.
			"Elphel FPGA interrupts",
			NULL)) {
		printk(KERN_ERR "Can't allocate Elphel FPGA interrupts");
		return -EBUSY;
	}
Mikhail Karpenko's avatar
Mikhail Karpenko committed
1120 1121 1122

#endif

1123
	dev_info(dev, "Elphel FPGA interrupts initialized\n");
1124
	dev_dbg(dev, "reset all compressors\n");
1125
	for (i = 0; i < SENSOR_PORTS; i++) {
1126
		reset_compressor(i);
Andrey Filippov's avatar
Andrey Filippov committed
1127 1128
	    dev_info(dev, "init_pgm_proc (%d)\n",i);
	    init_pgm_proc (i);   // setup pointers to functions (not sensor-specific)
1129
	}
1130
	//reset_compressor(); // reset compressor and buffer pointers
1131
	//MDD1(printk("x313_dma_init()\n"));
1132
	//x313_dma_init();    // initialize ETRAX FS DMA
Andrey Filippov's avatar
Andrey Filippov committed
1133 1134 1135 1136 1137
	dev_info(dev, "reset_qtables(0) (policy = COMMON_CACHE)\n");
	set_cache_policy(COMMON_CACHE);
    reset_qtables(0); // force initialization at next access (with COMMON_CACHE chyannel is ignored, with PER_CHN_CACHE - do for each chennel)
	pgm_functions_set_device(dev);
	g_dev_ptr = dev;
1138
	return 0;
Mikhail Karpenko's avatar
Mikhail Karpenko committed
1139 1140
}

1141
int image_acq_stop(struct platform_device *pdev)
1142 1143
{
	return 0;
Mikhail Karpenko's avatar
Mikhail Karpenko committed
1144
}
1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156
//#define I2C359_INC                    2   ///< slave address increment between sensors in 10359A board (broadcast, 1,2,3)
/** Register i2c pages equal to slave address,
 * Use to convert 353 code  */
int legacy_i2c(int ports) ///< bitmask of the sensor ports to use
                          ///< @return 0 (may add errors)
{
    int sensor_port, subchn;
    x393_i2c_device_t *class_10359, *class_sensor, dev_sensor;
    class_10359 = xi2c_dev_get(name_10359);
    BUG_ON(!class_10359);
    class_sensor= xi2c_dev_get(name_sensor);
    BUG_ON(!class_sensor);
Andrey Filippov's avatar
Andrey Filippov committed
1157
    memcpy(&dev_sensor, class_sensor, sizeof(x393_i2c_device_t));
Andrey Filippov's avatar
Andrey Filippov committed
1158 1159 1160
    dev_dbg(g_dev_ptr, "Initializing sensor i2c for legacy commands, ports bit-mask= 0x%x\n",ports);
    for (sensor_port=0; sensor_port< SENSOR_PORTS; sensor_port++) if (ports & (1 << sensor_port)) {
        i2c_page_alloc_init(sensor_port); // reset all pages allocation
1161
        i2c_page_register(sensor_port, class_10359->slave7);
1162 1163
        dev_dbg(g_dev_ptr, "Reset previously allocated pages for port= %d\n",sensor_port);
        dev_dbg(g_dev_ptr, "Setting 10359 page for port %d, slave= 0x%x\n",sensor_port,class_10359->slave7);
1164 1165 1166
        set_xi2c_wrc(class_10359, sensor_port, class_10359->slave7, 0);
        for (subchn = 0; subchn <4; subchn++){ // subchn == 0 - broadcast
            dev_sensor.slave7 = class_sensor->slave7 + I2C359_INC * subchn;
1167
            dev_dbg(g_dev_ptr, "Setting sensor page for port %d, slave= 0x%x\n",sensor_port,dev_sensor.slave7);
1168 1169 1170 1171
            i2c_page_register(sensor_port, dev_sensor.slave7);
            set_xi2c_wrc(&dev_sensor, sensor_port, dev_sensor.slave7, 0);
        }
        // Now register one page for reading 10359 and the sensor using sensor speed data
Andrey Filippov's avatar
Andrey Filippov committed
1172
        memcpy(&dev_sensor, class_sensor, sizeof(x393_i2c_device_t)); // dev_sensor));
1173
        dev_dbg(g_dev_ptr, "Registering page to read senors 16-bit on port %d, page= 0x%x\n",sensor_port,LEGACY_READ_PAGE2);
Andrey Filippov's avatar
Andrey Filippov committed
1174
        i2c_page_register(sensor_port, LEGACY_READ_PAGE2);
1175
        set_xi2c_rdc(&dev_sensor, sensor_port, LEGACY_READ_PAGE2);
1176
        dev_dbg(g_dev_ptr, "Registering page to read 32-bit data for 10359 on port %d, page= 0x%x\n",sensor_port,LEGACY_READ_PAGE4);
Andrey Filippov's avatar
Andrey Filippov committed
1177
        i2c_page_register(sensor_port, LEGACY_READ_PAGE4);
1178 1179
        dev_sensor.data_bytes=4; // for reading 10359 in 32-bit mode
        set_xi2c_rdc(&dev_sensor, sensor_port, LEGACY_READ_PAGE4);
Andrey Filippov's avatar
Andrey Filippov committed
1180
        dev_dbg(g_dev_ptr, "Initialized sensor i2c for legacy commands, sensor_port= 0x%x\n",sensor_port);
1181 1182
    }
    return 0;
Andrey Filippov's avatar
Andrey Filippov committed
1183 1184 1185 1186 1187 1188 1189 1190
/*
 /home/eyesis/git/elphel393/poky/build/tmp/work-shared/elphel393/kernel-source/drivers/elphel/sensor_common.c: In function 'legacy_i2c':
/home/eyesis/git/elphel393/poky/build/tmp/work-shared/elphel393/kernel-source/drivers/elphel/sensor_common.c:1060:45:
  warning: argument to 'sizeof' in 'memcpy' call is the same pointer type 'x393_i2c_device_t * {aka struct <anonymous> *}'
    as the destination; expected 'x393_i2c_device_t {aka struct <anonymous>}' or an explicit length [-Wsizeof-pointer-memaccess]
     memcpy(&dev_sensor, class_sensor, sizeof(class_sensor));
invalid type argument of unary '*' (have 'x393_i2c_device_t {aka struct <anonymous>}')
 */
1191
}
1192 1193 1194 1195 1196 1197
//static const struct of_device_id elphel393_sensor_of_match[] = {
//		{ .compatible = "elphel,elphel393-sensor-1.00" },
//		{ /* end of list */ }
//};
//MODULE_DEVICE_TABLE(of, elphel393_sensor_of_match);

1198

1199
/*static struct platform_driver elphel393_sensor_common = {
1200 1201 1202 1203 1204 1205
		.probe          = image_acq_init,
		.remove         = image_acq_stop,
		.driver = {
				.name = IMAGEACQ_DRIVER_NAME,
				.of_match_table = elphel393_sensor_of_match,
		}
1206
};*/
1207

1208
//module_platform_driver(elphel393_sensor_common);
Mikhail Karpenko's avatar
Mikhail Karpenko committed
1209

1210 1211
//MODULE_LICENSE("GPL");
//MODULE_AUTHOR("Andrey Filippov <andrey@elphel.com>.");
1212
//MODULE_DESCRIPTION(IMAGEACQ_DRIVER_DESCRIPTION);