Commit 196a40df authored by Andrey Filippov's avatar Andrey Filippov

adding video memor=y driver wih DT and sysfs interface to configure video memory

parent c2b627a5
......@@ -31,3 +31,4 @@ obj-$(CONFIG_ELPHEL393) += multi10359.o
obj-$(CONFIG_ELPHEL393) += imu_log393.o
obj-$(CONFIG_ELPHEL393) += cxi2c.o
obj-$(CONFIG_ELPHEL393) += x393_videomem.o
......@@ -40,7 +40,7 @@
#include <linux/interrupt.h>
#include <linux/platform_device.h>
#include <linux/of_device.h>
#include <asm/outercache.h>
#include <asm/outercache.h> // TODO: Implement cache operations for the logger !!!!
#include <asm/cacheflush.h>
#include <linux/module.h>
#include <linux/slab.h>
......@@ -304,8 +304,7 @@ static u32 bytePtrMask = 0;
static dma_addr_t logger_phys; ///< physical address of the DMA memory start
static int logger_fpga_configured = 0;
static const struct of_device_id elphel393_logger_of_match[];
/** @brief Global pointer to basic device structure. This pointer is used in debugfs output functions */
static struct device *g_dev_ptr;
static struct device *g_dev_ptr; ///< Global pointer to basic device structure. This pointer is used in debugfs output functions
wait_queue_head_t logger_wait_queue;
#endif
......@@ -914,15 +913,11 @@ static ssize_t imu_read(struct file * file, char * buf, size_t count, loff_t *of
}
}
/**
* @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 logger_irq_handler(int irq, void *dev_id)
/** Handle interrupts the logger. This handler is installed without SA_INTERRUPT
* flag meaning that interrupts are enabled during processing. Such behavior is recommended in LDD3. */
static irqreturn_t logger_irq_handler(int irq, ///< [in] interrupt number
void *dev_id) ///< [in] pointer to driver's private data structure
///< @return \e IRQ_HANDLED if interrupt was processed and \e IRQ_NONE otherwise
{
x393_mult_saxi_al_t mult_saxi_dwp = x393_mult_saxi_pointers(MULT_SAXI_CHN);
if (mult_saxi_dwp.addr32 < logger_offs32){
......@@ -1263,8 +1258,7 @@ static struct platform_driver elphel393_logger = {
},
};
//module_init(logger_init);
module_platform_driver(elphel393_logger);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Andrey Filippov <andrey@elphel.com>.");
MODULE_DESCRIPTION(IMU_MODULE_DESCRIPTION);
......@@ -191,25 +191,15 @@
#include <linux/fs.h>
#include <linux/string.h>
#include <linux/init.h>
//#include <linux/autoconf.h>
#include <linux/vmalloc.h>
//#include <asm/system.h>
#include <asm/byteorder.h> // endians
#include <asm/io.h>
#include <asm/irq.h>
#include <linux/delay.h>
//#include <asm/delay.h>
#include <asm/uaccess.h>
#include <elphel/c313a.h>
//#include <asm/elphel/exifa.h>
//#include "fpgactrl.h" // defines port_csp0_addr, port_csp4_addr
//#include "fpga_sdram.h" // use a single fpga_initSDRAM(void)
//#include "fpgaconfi2c.h" //to control clocks
//#include "cc3x3.h"
//#include "fpga_io.h"
//#include "x3x3.h" // hardware definitions
#include "framepars.h"
#include "sensor_common.h"
#include "multi10359.h"
......@@ -218,10 +208,8 @@
#include "quantization_tables.h"
#include "latency.h"
#include "pgm_functions.h"
//#include "cxdma.h" // is_dma_on()
#include "jpeghead.h" // to program FPGA Huffman tables
#include "legacy_defines.h" // temporarily
#include "legacy_defines.h" // temporarily
#include "sensor_i2c.h"
......
/***************************************************************************//**
* @file x393_fpga_functions.c
* @brief Reimplementation of Python methods to program FPGA parameters
* @copyright Copyright 2016 (C) Elphel, Inc.
* @par <b>License</b>
* 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 2 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/>.
*******************************************************************************/
#include "x393.h"
#include "x393_fpga_functions.h"
/** Setup memory controller for a sensor channel */
int setup_sensor_memory (int num_sensor, ///< sensor port number (0..3)
int frame_sa, ///< 22-bit frame start address ((3 CA LSBs==0. BA==0)
int frame_sa_inc, ///< 22-bit frame start address increment ((3 CA LSBs==0. BA==0)
int last_frame_num, ///< 16-bit number of the last frame in a buffer
int frame_full_width, ///< 13-bit Padded line length (8-row increment), in 8-bursts (16 bytes)
int window_width, ///< 13-bit - in 8*16=128 bit bursts
int window_height, ///< 16-bit window height (in scan lines)
int window_left, ///< 13-bit window left margin in 8-bursts (16 bytes)
int window_top, ///< 16-bit window top margin (in scan lines
x393cmd_t x393cmd, ///< how to apply commands - directly or through channel sequencer
int frame16) ///< Frame number the command should be applied to (if not immediate mode)
///< @return 0 -OK
//typedef enum {DIRECT,ABSOLUTE,RELATIVE} x393cmd_t;
{
x393_mcntrl_mode_scan_t mcntrl_mode = {.enable = 1, // [ 0] (1) enable requests from this channel ( 0 will let current to finish, but not raise want/need)
.chn_nreset = 0, // [ 1] (1) 0: immediately reset all the internal circuitry
.write_mem = 1, // [ 2] (0) 0 - read from memory, 1 - write to memory
.extra_pages = 0, // [ 4: 3] (0) 2-bit number of extra pages that need to stay (not to be overwritten) in the buffer
.keep_open = 0, // [ 5] (0) (NA in linescan) for 8 or less rows - do not close page between accesses (not used in scanline mode)
.byte32 = 0, // [ 6] (1) (NA in linescan) 32-byte columns (0 - 16-byte), not used in scanline mode
.reset_frame = 0, // [ 8] (0) reset frame number
.single = 0, // [ 9] (0) run single frame
.repetitive = 1, // [ 10] (1) run repetitive frames
.disable_need = 0, // [ 11] (0) disable 'need' generation, only 'want' (compressor channels)
.skip_too_late = 1}; // [ 12] (0) Skip over missed blocks to preserve frame structure (increment pointers)
x393_mcntrl_window_frame_sa_t window_frame_sa = {.d32=0};
x393_mcntrl_window_frame_sa_inc_t window_frame_sa_inc = {.d32=0};
x393_mcntrl_window_last_frame_num_t window_last_frame_num = {.d32=0};
x393_mcntrl_window_full_width_t window_full_width = {.d32=0};
x393_mcntrl_window_width_height_t window_width_height = {.d32=0};
x393_mcntrl_window_left_top_t window_left_top = {.d32=0};
window_frame_sa.frame_sa = frame_sa;
window_frame_sa_inc.frame_sa_inc = frame_sa_inc;
window_last_frame_num.last_frame_num = last_frame_num;
window_full_width.full_width = frame_full_width;
window_width_height.width = window_width;
window_width_height.height = window_height;
window_left_top.left = window_left;
window_left_top.top = window_top;
switch (x393cmd){
case RELATIVE:
seqr_x393_sens_mcntrl_scanline_startaddr (frame16, window_frame_sa, num_sensor); // Set frame start address
seqr_x393_sens_mcntrl_scanline_frame_size (frame16, window_frame_sa_inc, num_sensor); // Set frame size (address increment)
seqr_x393_sens_mcntrl_scanline_frame_last (frame16, window_last_frame_num, num_sensor); // Set last frame number (number of frames in buffer minus 1)
seqr_x393_sens_mcntrl_scanline_frame_full_width (frame16, window_full_width, num_sensor); // Set frame full(padded) width
seqr_x393_sens_mcntrl_scanline_window_wh (frame16, window_width_height, num_sensor); // Set frame window size
seqr_x393_sens_mcntrl_scanline_window_x0y0 (frame16, window_left_top, num_sensor); // Set frame position
seqr_x393_sens_mcntrl_scanline_mode (frame16, mcntrl_mode, num_sensor); // Set mode register (write last after other channel registers are set)
break;
case ABSOLUTE:
seqa_x393_sens_mcntrl_scanline_startaddr (frame16, window_frame_sa, num_sensor); // Set frame start address
seqa_x393_sens_mcntrl_scanline_frame_size (frame16, window_frame_sa_inc, num_sensor); // Set frame size (address increment)
seqa_x393_sens_mcntrl_scanline_frame_last (frame16, window_last_frame_num, num_sensor); // Set last frame number (number of frames in buffer minus 1)
seqa_x393_sens_mcntrl_scanline_frame_full_width (frame16, window_full_width, num_sensor); // Set frame full(padded) width
seqa_x393_sens_mcntrl_scanline_window_wh (frame16, window_width_height, num_sensor); // Set frame window size
seqa_x393_sens_mcntrl_scanline_window_x0y0 (frame16, window_left_top, num_sensor); // Set frame position
seqa_x393_sens_mcntrl_scanline_mode (frame16, mcntrl_mode, num_sensor); // Set mode register (write last after other channel registers are set)
break;
case DIRECT:
x393_sens_mcntrl_scanline_startaddr (window_frame_sa, num_sensor); // Set frame start address
x393_sens_mcntrl_scanline_frame_size (window_frame_sa_inc, num_sensor); // Set frame size (address increment)
x393_sens_mcntrl_scanline_frame_last (window_last_frame_num, num_sensor); // Set last frame number (number of frames in buffer minus 1)
x393_sens_mcntrl_scanline_frame_full_width (window_full_width, num_sensor); // Set frame full(padded) width
x393_sens_mcntrl_scanline_window_wh (window_width_height, num_sensor); // Set frame window size
x393_sens_mcntrl_scanline_window_x0y0 (window_left_top, num_sensor); // Set frame position
x393_sens_mcntrl_scanline_mode (mcntrl_mode, num_sensor); // Set mode register (write last after other channel registers are set)
break;
}
return 0;
}
/** Setup memory controller for a compressor channel */
int setup_compressor_memory (int num_sensor, ///< sensor port number (0..3)
int frame_sa, ///< 22-bit frame start address ((3 CA LSBs==0. BA==0)
int frame_sa_inc, ///< 22-bit frame start address increment ((3 CA LSBs==0. BA==0)
int last_frame_num, ///< 16-bit number of the last frame in a buffer
int frame_full_width, ///< 13-bit Padded line length (8-row increment), in 8-bursts (16 bytes)
int window_width, ///< 13-bit - in 8*16=128 bit bursts
int window_height, ///< 16-bit window height (in scan lines)
int window_left, ///< 13-bit window left margin in 8-bursts (16 bytes)
int window_top, ///< 16-bit window top margin (in scan lines
int byte32, ///< 1 - 32-byte columns (currently used), 0 - 16 byte columns
int tile_width, ///< tile width in pixels
int tile_vstep, ///< tile vertical step in pixel rows (JPEG18/jp4 = 16) // = 16
int tile_height, ///< tile height: 18 for color JPEG, 16 for JP4 flavors // = 18
int extra_pages, ///< extra pages needed (1) - number of previous pages to keep in a 4-page buffer
int disable_need, ///< disable "need" (yield to sensor channels - they can not wait)
x393cmd_t x393cmd, ///< how to apply commands - directly or through channel sequencer
int frame16) ///< Frame number the command should be applied to (if not immediate mode)
///< @return 0 - OK
{
x393_mcntrl_mode_scan_t mcntrl_mode = {.enable = 1, // [ 0] (1) enable requests from this channel ( 0 will let current to finish, but not raise want/need)
.chn_nreset = 0, // [ 1] (1) 0: immediately reset all the internal circuitry
.write_mem = 0, // [ 2] (0) 0 - read from memory, 1 - write to memory
.extra_pages = 1, // [ 4: 3] (0) 2-bit number of extra pages that need to stay (not to be overwritten) in the buffer
.keep_open = 0, // [ 5] (0) (NA in linescan) for 8 or less rows - do not close page between accesses (not used in scanline mode)
.byte32 = 1, // [ 6] (1) (NA in linescan) 32-byte columns (0 - 16-byte), not used in scanline mode
.reset_frame = 0, // [ 8] (0) reset frame number
.single = 0, // [ 9] (0) run single frame
.repetitive = 1, // [ 10] (1) run repetitive frames
.disable_need = 1, // [ 11] (0) disable 'need' generation, only 'want' (compressor channels)
.skip_too_late = 1};// [ 12] (0) Skip over missed blocks to preserve frame structure (increment pointers)
x393_mcntrl_window_frame_sa_t window_frame_sa = {.d32=0};
x393_mcntrl_window_frame_sa_inc_t window_frame_sa_inc = {.d32=0};
x393_mcntrl_window_last_frame_num_t window_last_frame_num = {.d32=0};
x393_mcntrl_window_full_width_t window_full_width = {.d32=0};
x393_mcntrl_window_width_height_t window_width_height = {.d32=0};
x393_mcntrl_window_left_top_t window_left_top = {.d32=0};
x393_mcntrl_window_tile_whs_t window_tile_whs = {.d32=0};
window_frame_sa.frame_sa = frame_sa;
window_frame_sa_inc.frame_sa_inc = frame_sa_inc;
window_last_frame_num.last_frame_num = last_frame_num;
window_full_width.full_width = frame_full_width;
window_width_height.width = window_width;
window_width_height.height = window_height;
window_left_top.left = window_left;
window_left_top.top = window_top;
window_tile_whs.tile_width = tile_width;
window_tile_whs.vert_step = tile_vstep;
window_tile_whs.tile_height = tile_height;
mcntrl_mode.disable_need = disable_need; // non-constant parameter
mcntrl_mode.extra_pages = extra_pages; // non-constant parameter
switch (x393cmd){
case RELATIVE:
seqr_x393_sens_mcntrl_tiled_startaddr (frame16, window_frame_sa, num_sensor); // Set frame start address
seqr_x393_sens_mcntrl_tiled_frame_size (frame16, window_frame_sa_inc, num_sensor); // Set frame size (address increment)
seqr_x393_sens_mcntrl_tiled_frame_last (frame16, window_last_frame_num, num_sensor); // Set last frame number (number of frames in buffer minus 1)
seqr_x393_sens_mcntrl_tiled_frame_full_width (frame16, window_full_width, num_sensor); // Set frame full(padded) width
seqr_x393_sens_mcntrl_tiled_window_wh (frame16, window_width_height, num_sensor); // Set frame window size
seqr_x393_sens_mcntrl_tiled_window_x0y0 (frame16, window_left_top, num_sensor); // Set frame position
seqr_x393_sens_mcntrl_tiled_tile_whs (frame16, window_tile_whs, num_sensor); // Set tile size/step (tiled mode only)
seqr_x393_sens_mcntrl_tiled_mode (frame16, mcntrl_mode, num_sensor); // Set mode register (write last after other channel registers are set)
break;
case ABSOLUTE:
seqa_x393_sens_mcntrl_tiled_startaddr (frame16, window_frame_sa, num_sensor); // Set frame start address
seqa_x393_sens_mcntrl_tiled_frame_size (frame16, window_frame_sa_inc, num_sensor); // Set frame size (address increment)
seqa_x393_sens_mcntrl_tiled_frame_last (frame16, window_last_frame_num, num_sensor); // Set last frame number (number of frames in buffer minus 1)
seqa_x393_sens_mcntrl_tiled_frame_full_width (frame16, window_full_width, num_sensor); // Set frame full(padded) width
seqa_x393_sens_mcntrl_tiled_window_wh (frame16, window_width_height, num_sensor); // Set frame window size
seqa_x393_sens_mcntrl_tiled_window_x0y0 (frame16, window_left_top, num_sensor); // Set frame position
seqa_x393_sens_mcntrl_tiled_tile_whs (frame16, window_tile_whs, num_sensor); // Set tile size/step (tiled mode only)
seqa_x393_sens_mcntrl_tiled_mode (frame16, mcntrl_mode, num_sensor); // Set mode register (write last after other channel registers are set)
break;
case DIRECT:
x393_sens_mcntrl_tiled_startaddr (window_frame_sa, num_sensor); // Set frame start address
x393_sens_mcntrl_tiled_frame_size (window_frame_sa_inc, num_sensor); // Set frame size (address increment)
x393_sens_mcntrl_tiled_frame_last (window_last_frame_num, num_sensor); // Set last frame number (number of frames in buffer minus 1)
x393_sens_mcntrl_tiled_frame_full_width (window_full_width, num_sensor); // Set frame full(padded) width
x393_sens_mcntrl_tiled_window_wh (window_width_height, num_sensor); // Set frame window size
x393_sens_mcntrl_tiled_window_x0y0 (window_left_top, num_sensor); // Set frame position
x393_sens_mcntrl_tiled_tile_whs (window_tile_whs, num_sensor); // Set tile size/step (tiled mode only)
x393_sens_mcntrl_tiled_mode (mcntrl_mode, num_sensor); // Set mode register (write last after other channel registers are set)
break;
}
return 0;
}
/*
*/
/***************************************************************************//**
* @file x393_fpga_functions.h
* @brief Reimplementation of Python methods to program FPGA parameters
* @copyright Copyright 2016 (C) Elphel, Inc.
* @par <b>License</b>
* 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 2 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/>.
*******************************************************************************/
//typedef enum {DIRECT,ABSOLUTE,RELATIVE} x393cmd_t;
#include "x393.h"
int setup_sensor_memory (int num_sensor, int frame_sa, int frame_sa_inc, int last_frame_num, int frame_full_width,
int window_width, int window_height, int window_left, int window_top, x393cmd_t x393cmd, int frame16);
int setup_compressor_memory (int num_sensor, int frame_sa, int frame_sa_inc, int last_frame_num, int frame_full_width,
int window_width, int window_height, int window_left, int window_top, int byte32, int tile_width, int tile_vstep,
int tile_height, int extra_pages, int disable_need, x393cmd_t x393cmd, int frame16);
/***************************************************************************//**
* @file x393_videomem.c
* @brief Driver for the external DDR3 memory of x393 (currently 0.5GB)
* @copyright Copyright 2016 (C) Elphel, Inc.
* @par <b>License</b>
* 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 2 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/>.
*******************************************************************************/
#include <linux/interrupt.h>
#include <linux/platform_device.h>
#include <linux/of_device.h>
#include <linux/module.h>
#include <asm/outercache.h> // TODO: Implement cache operations for the membridge !!!!
#include <asm/cacheflush.h>
#include <linux/errno.h>
#include <linux/fs.h>
#include "x393.h"
#include "x393_videomem.h"
#include <elphel/driver_numbers.h>
#define VIDEOMEM_MODULE_DESCRIPTION "Video buffer driver"
#define VIDEOMEM_DRIVER_NAME "video_mem"
static const struct of_device_id elphel393_videomem_of_match[];
static struct device *g_dev_ptr; ///< Global pointer to basic device structure. This pointer is used in debugfs output functions
wait_queue_head_t videomem_wait_queue;
static struct elphel_video_buf_t buffer_settings = { ///< some default settings, same as in DT
.frame_start = {0x00000000, 0x08000000, 0x10000000, 0x08000000}, /* Frame starts (in bytes) */
.frame_full_width = { 8192, 8192, 8192, 8192}, /* Frame full widths (in bytes). 1 memory page is 2048 bytes (128 bursts) */
.frame_height = { 8192, 8192, 8192, 8192}, /* Channel 3 maximal frame height in pixel lines */
.frames_in_buffer = { 2, 2, 2, 2} /* Number of frames in channel 3 buffer */
};
/* Programming mdemory channel access to video memory */
/** Setup memory controller for a sensor channel */
int setup_sensor_memory (int num_sensor, ///< sensor port number (0..3)
int window_width, ///< 13-bit - in 8*16=128 bit bursts
int window_height, ///< 16-bit window height (in scan lines)
int window_left, ///< 13-bit window left margin in 8-bursts (16 bytes)
int window_top, ///< 16-bit window top margin (in scan lines
x393cmd_t x393cmd, ///< how to apply commands - directly or through channel sequencer
int frame16) ///< Frame number the command should be applied to (if not immediate mode)
///< @return 0 -OK
//typedef enum {DIRECT,ABSOLUTE,RELATIVE} x393cmd_t;
{
int frame_sa = buffer_settings.frame_start[num_sensor] >> (4 + 3) ;
int frame_full_width = buffer_settings.frame_full_width[num_sensor] >> 4;
int frame_sa_inc = frame_full_width * (buffer_settings.frame_height[num_sensor] >>3);
int last_frame_num = buffer_settings.frames_in_buffer[num_sensor] - 1;
x393_mcntrl_mode_scan_t mcntrl_mode = {.enable = 1, // [ 0] (1) enable requests from this channel ( 0 will let current to finish, but not raise want/need)
.chn_nreset = 0, // [ 1] (1) 0: immediately reset all the internal circuitry
.write_mem = 1, // [ 2] (0) 0 - read from memory, 1 - write to memory
.extra_pages = 0, // [ 4: 3] (0) 2-bit number of extra pages that need to stay (not to be overwritten) in the buffer
.keep_open = 0, // [ 5] (0) (NA in linescan) for 8 or less rows - do not close page between accesses (not used in scanline mode)
.byte32 = 0, // [ 6] (1) (NA in linescan) 32-byte columns (0 - 16-byte), not used in scanline mode
.reset_frame = 0, // [ 8] (0) reset frame number
.single = 0, // [ 9] (0) run single frame
.repetitive = 1, // [ 10] (1) run repetitive frames
.disable_need = 0, // [ 11] (0) disable 'need' generation, only 'want' (compressor channels)
.skip_too_late = 1}; // [ 12] (0) Skip over missed blocks to preserve frame structure (increment pointers)
x393_mcntrl_window_frame_sa_t window_frame_sa = {.d32=0};
x393_mcntrl_window_frame_sa_inc_t window_frame_sa_inc = {.d32=0};
x393_mcntrl_window_last_frame_num_t window_last_frame_num = {.d32=0};
x393_mcntrl_window_full_width_t window_full_width = {.d32=0};
x393_mcntrl_window_width_height_t window_width_height = {.d32=0};
x393_mcntrl_window_left_top_t window_left_top = {.d32=0};
window_frame_sa.frame_sa = frame_sa;
window_frame_sa_inc.frame_sa_inc = frame_sa_inc;
window_last_frame_num.last_frame_num = last_frame_num;
window_full_width.full_width = frame_full_width;
window_width_height.width = window_width;
window_width_height.height = window_height;
window_left_top.left = window_left;
window_left_top.top = window_top;
switch (x393cmd){
case RELATIVE:
seqr_x393_sens_mcntrl_scanline_startaddr (frame16, window_frame_sa, num_sensor); // Set frame start address
seqr_x393_sens_mcntrl_scanline_frame_size (frame16, window_frame_sa_inc, num_sensor); // Set frame size (address increment)
seqr_x393_sens_mcntrl_scanline_frame_last (frame16, window_last_frame_num, num_sensor); // Set last frame number (number of frames in buffer minus 1)
seqr_x393_sens_mcntrl_scanline_frame_full_width (frame16, window_full_width, num_sensor); // Set frame full(padded) width
seqr_x393_sens_mcntrl_scanline_window_wh (frame16, window_width_height, num_sensor); // Set frame window size
seqr_x393_sens_mcntrl_scanline_window_x0y0 (frame16, window_left_top, num_sensor); // Set frame position
seqr_x393_sens_mcntrl_scanline_mode (frame16, mcntrl_mode, num_sensor); // Set mode register (write last after other channel registers are set)
break;
case ABSOLUTE:
seqa_x393_sens_mcntrl_scanline_startaddr (frame16, window_frame_sa, num_sensor); // Set frame start address
seqa_x393_sens_mcntrl_scanline_frame_size (frame16, window_frame_sa_inc, num_sensor); // Set frame size (address increment)
seqa_x393_sens_mcntrl_scanline_frame_last (frame16, window_last_frame_num, num_sensor); // Set last frame number (number of frames in buffer minus 1)
seqa_x393_sens_mcntrl_scanline_frame_full_width (frame16, window_full_width, num_sensor); // Set frame full(padded) width
seqa_x393_sens_mcntrl_scanline_window_wh (frame16, window_width_height, num_sensor); // Set frame window size
seqa_x393_sens_mcntrl_scanline_window_x0y0 (frame16, window_left_top, num_sensor); // Set frame position
seqa_x393_sens_mcntrl_scanline_mode (frame16, mcntrl_mode, num_sensor); // Set mode register (write last after other channel registers are set)
break;
case DIRECT:
x393_sens_mcntrl_scanline_startaddr (window_frame_sa, num_sensor); // Set frame start address
x393_sens_mcntrl_scanline_frame_size (window_frame_sa_inc, num_sensor); // Set frame size (address increment)
x393_sens_mcntrl_scanline_frame_last (window_last_frame_num, num_sensor); // Set last frame number (number of frames in buffer minus 1)
x393_sens_mcntrl_scanline_frame_full_width (window_full_width, num_sensor); // Set frame full(padded) width
x393_sens_mcntrl_scanline_window_wh (window_width_height, num_sensor); // Set frame window size
x393_sens_mcntrl_scanline_window_x0y0 (window_left_top, num_sensor); // Set frame position
x393_sens_mcntrl_scanline_mode (mcntrl_mode, num_sensor); // Set mode register (write last after other channel registers are set)
break;
}
return 0;
}
/** Setup memory controller for a compressor channel */
int setup_compressor_memory (int num_sensor, ///< sensor port number (0..3)
int window_width, ///< 13-bit - in 8*16=128 bit bursts
int window_height, ///< 16-bit window height (in scan lines)
int window_left, ///< 13-bit window left margin in 8-bursts (16 bytes)
int window_top, ///< 16-bit window top margin (in scan lines
int tile_width, ///< tile width in pixels
int tile_height, ///< tile height: 18 for color JPEG, 16 for JP4 flavors // = 18
int disable_need, ///< disable "need" (yield to sensor channels - they can not wait)
x393cmd_t x393cmd, ///< how to apply commands - directly or through channel sequencer
int frame16) ///< Frame number the command should be applied to (if not immediate mode)
///< @return 0 - OK
{
int frame_sa = buffer_settings.frame_start[num_sensor] >> (4 + 3) ;
int frame_full_width = buffer_settings.frame_full_width[num_sensor] >> 4;
int frame_sa_inc = frame_full_width * (buffer_settings.frame_height[num_sensor] >>3);
int last_frame_num = buffer_settings.frames_in_buffer[num_sensor] - 1;
int byte32 = 1; ///< 1 - 32-byte columns (currently used), 0 - 16 byte columns
int tile_vstep = 16; ///< tile vertical step in pixel rows (JPEG18/jp4 = 16) // = 16
int extra_pages = 1; ///< extra pages needed (1) - number of previous pages to keep in a 4-page buffer
x393_mcntrl_mode_scan_t mcntrl_mode = {.enable = 1, // [ 0] (1) enable requests from this channel ( 0 will let current to finish, but not raise want/need)
.chn_nreset = 0, // [ 1] (1) 0: immediately reset all the internal circuitry
.write_mem = 0, // [ 2] (0) 0 - read from memory, 1 - write to memory
.extra_pages = 1, // [ 4: 3] (0) 2-bit number of extra pages that need to stay (not to be overwritten) in the buffer
.keep_open = 0, // [ 5] (0) (NA in linescan) for 8 or less rows - do not close page between accesses (not used in scanline mode)
.byte32 = 1, // [ 6] (1) (NA in linescan) 32-byte columns (0 - 16-byte), not used in scanline mode
.reset_frame = 0, // [ 8] (0) reset frame number
.single = 0, // [ 9] (0) run single frame
.repetitive = 1, // [ 10] (1) run repetitive frames
.disable_need = 1, // [ 11] (0) disable 'need' generation, only 'want' (compressor channels)
.skip_too_late = 1};// [ 12] (0) Skip over missed blocks to preserve frame structure (increment pointers)
x393_mcntrl_window_frame_sa_t window_frame_sa = {.d32=0};
x393_mcntrl_window_frame_sa_inc_t window_frame_sa_inc = {.d32=0};
x393_mcntrl_window_last_frame_num_t window_last_frame_num = {.d32=0};
x393_mcntrl_window_full_width_t window_full_width = {.d32=0};
x393_mcntrl_window_width_height_t window_width_height = {.d32=0};
x393_mcntrl_window_left_top_t window_left_top = {.d32=0};
x393_mcntrl_window_tile_whs_t window_tile_whs = {.d32=0};
window_frame_sa.frame_sa = frame_sa;
window_frame_sa_inc.frame_sa_inc = frame_sa_inc;
window_last_frame_num.last_frame_num = last_frame_num;
window_full_width.full_width = frame_full_width;
window_width_height.width = window_width;
window_width_height.height = window_height;
window_left_top.left = window_left;
window_left_top.top = window_top;
window_tile_whs.tile_width = tile_width;
window_tile_whs.vert_step = tile_vstep;
window_tile_whs.tile_height = tile_height;
mcntrl_mode.disable_need = disable_need; // non-constant parameter
mcntrl_mode.extra_pages = extra_pages; // non-constant parameter
switch (x393cmd){
case RELATIVE:
seqr_x393_sens_mcntrl_tiled_startaddr (frame16, window_frame_sa, num_sensor); // Set frame start address
seqr_x393_sens_mcntrl_tiled_frame_size (frame16, window_frame_sa_inc, num_sensor); // Set frame size (address increment)
seqr_x393_sens_mcntrl_tiled_frame_last (frame16, window_last_frame_num, num_sensor); // Set last frame number (number of frames in buffer minus 1)
seqr_x393_sens_mcntrl_tiled_frame_full_width (frame16, window_full_width, num_sensor); // Set frame full(padded) width
seqr_x393_sens_mcntrl_tiled_window_wh (frame16, window_width_height, num_sensor); // Set frame window size
seqr_x393_sens_mcntrl_tiled_window_x0y0 (frame16, window_left_top, num_sensor); // Set frame position
seqr_x393_sens_mcntrl_tiled_tile_whs (frame16, window_tile_whs, num_sensor); // Set tile size/step (tiled mode only)
seqr_x393_sens_mcntrl_tiled_mode (frame16, mcntrl_mode, num_sensor); // Set mode register (write last after other channel registers are set)
break;
case ABSOLUTE:
seqa_x393_sens_mcntrl_tiled_startaddr (frame16, window_frame_sa, num_sensor); // Set frame start address
seqa_x393_sens_mcntrl_tiled_frame_size (frame16, window_frame_sa_inc, num_sensor); // Set frame size (address increment)
seqa_x393_sens_mcntrl_tiled_frame_last (frame16, window_last_frame_num, num_sensor); // Set last frame number (number of frames in buffer minus 1)
seqa_x393_sens_mcntrl_tiled_frame_full_width (frame16, window_full_width, num_sensor); // Set frame full(padded) width
seqa_x393_sens_mcntrl_tiled_window_wh (frame16, window_width_height, num_sensor); // Set frame window size
seqa_x393_sens_mcntrl_tiled_window_x0y0 (frame16, window_left_top, num_sensor); // Set frame position
seqa_x393_sens_mcntrl_tiled_tile_whs (frame16, window_tile_whs, num_sensor); // Set tile size/step (tiled mode only)
seqa_x393_sens_mcntrl_tiled_mode (frame16, mcntrl_mode, num_sensor); // Set mode register (write last after other channel registers are set)
break;
case DIRECT:
x393_sens_mcntrl_tiled_startaddr (window_frame_sa, num_sensor); // Set frame start address
x393_sens_mcntrl_tiled_frame_size (window_frame_sa_inc, num_sensor); // Set frame size (address increment)
x393_sens_mcntrl_tiled_frame_last (window_last_frame_num, num_sensor); // Set last frame number (number of frames in buffer minus 1)
x393_sens_mcntrl_tiled_frame_full_width (window_full_width, num_sensor); // Set frame full(padded) width
x393_sens_mcntrl_tiled_window_wh (window_width_height, num_sensor); // Set frame window size
x393_sens_mcntrl_tiled_window_x0y0 (window_left_top, num_sensor); // Set frame position
x393_sens_mcntrl_tiled_tile_whs (window_tile_whs, num_sensor); // Set tile size/step (tiled mode only)
x393_sens_mcntrl_tiled_mode (mcntrl_mode, num_sensor); // Set mode register (write last after other channel registers are set)
break;
}
return 0;
}
// TODO: Implement file operations using membridge for both raw memory access and per-channel image raw (including 16-bit)
static int videomem_open (struct inode *inode, struct file *filp) {return 0;}
static int videomem_release (struct inode *inode, struct file *filp) {return 0;}
static loff_t videomem_lseek (struct file * file, loff_t offset, int orig) {return 0;}
static ssize_t videomem_read (struct file * file, char * buf, size_t count, loff_t *off) {return 0;}
static ssize_t videomem_write (struct file * file, const char * buf, size_t count, loff_t *off) {return 0;}
static struct file_operations videomem_fops = {
owner: THIS_MODULE,
open: videomem_open,
release: videomem_release,
llseek: videomem_lseek,
read: videomem_read,
write: videomem_write
};
/** Handle interrupts from membridge (video memory <-> system memory transfers). This handler is installed without SA_INTERRUPT
* flag meaning that interrupts are enabled during processing. Such behavior is recommended in LDD3. */
static irqreturn_t videomem_irq_handler(int irq, ///< [in] irq interrupt number
void *dev_id) ///< [in] dev_id pointer to driver's private data structure
///< @return \e IRQ_HANDLED if interrupt was processed and \e IRQ_NONE otherwise
{
x393_membridge_ctrl_irq_t ctrl_interrupts= {.d32=0};
ctrl_interrupts.interrupt_cmd = X393_IRQ_RESET;
//TODO: Do what is needed here
x393_membridge_ctrl_irq(ctrl_interrupts); // reset interrupt
wake_up_interruptible(&videomem_wait_queue);
return IRQ_HANDLED;
}
// SysFS interface to read/modify video memory map
#define SYSFS_PERMISSIONS 0644 /* default permissions for sysfs files */
#define SYSFS_READONLY 0444
#define SYSFS_WRITEONLY 0222
/** Sysfs helper function - get channel number from the last character of the attribute name*/
static int get_channel_from_name(struct device_attribute *attr) ///< Linux kernel interface for exporting device attributes
///< @return channel number
{
int reg = 0;
sscanf(attr->attr.name + (strlen(attr->attr.name)-1), "%du", &reg);
return reg;
}
static ssize_t show_frame_start(struct device *dev, struct device_attribute *attr, char *buf)
{
return sprintf(buf,"0x%x\n", buffer_settings.frame_start[get_channel_from_name(attr)]);
}
static ssize_t show_full_width(struct device *dev, struct device_attribute *attr, char *buf)
{
return sprintf(buf,"0x%x\n", buffer_settings.frame_full_width[get_channel_from_name(attr)]);
}
static ssize_t show_frame_height(struct device *dev, struct device_attribute *attr, char *buf)
{
return sprintf(buf,"0x%x\n", buffer_settings.frame_height[get_channel_from_name(attr)]);
}
static ssize_t show_frames_in_buffer(struct device *dev, struct device_attribute *attr, char *buf)
{
return sprintf(buf,"0x%x\n", buffer_settings.frames_in_buffer[get_channel_from_name(attr)]);
}
static ssize_t store_frame_start(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{
size_t len;
sscanf(buf, "%i", &buffer_settings.frame_start[get_channel_from_name(attr)], &len);
return count;
}
static ssize_t store_full_width(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{
size_t len;
sscanf(buf, "%i", &buffer_settings.frame_full_width[get_channel_from_name(attr)], &len);
return count;
}
static ssize_t store_frame_height(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{
size_t len;
sscanf(buf, "%i", &buffer_settings.frame_height[get_channel_from_name(attr)], &len);
return count;
}
static ssize_t store_frames_in_buffer(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{
size_t len;
sscanf(buf, "%i", &buffer_settings.frames_in_buffer[get_channel_from_name(attr)], &len);
return count;
}
static DEVICE_ATTR(frame_start0, SYSFS_PERMISSIONS, show_frame_start, store_frame_start);
static DEVICE_ATTR(frame_start1, SYSFS_PERMISSIONS, show_frame_start, store_frame_start);
static DEVICE_ATTR(frame_start2, SYSFS_PERMISSIONS, show_frame_start, store_frame_start);
static DEVICE_ATTR(frame_start3, SYSFS_PERMISSIONS, show_frame_start, store_frame_start);
static DEVICE_ATTR(frame_full_width0, SYSFS_PERMISSIONS, show_full_width, store_full_width);
static DEVICE_ATTR(frame_full_width1, SYSFS_PERMISSIONS, show_full_width, store_full_width);
static DEVICE_ATTR(frame_full_width2, SYSFS_PERMISSIONS, show_full_width, store_full_width);
static DEVICE_ATTR(frame_full_width3, SYSFS_PERMISSIONS, show_full_width, store_full_width);
static DEVICE_ATTR(frame_height0, SYSFS_PERMISSIONS, show_frame_height, store_frame_height);
static DEVICE_ATTR(frame_height1, SYSFS_PERMISSIONS, show_frame_height, store_frame_height);
static DEVICE_ATTR(frame_height2, SYSFS_PERMISSIONS, show_frame_height, store_frame_height);
static DEVICE_ATTR(frame_height3, SYSFS_PERMISSIONS, show_frame_height, store_frame_height);
static DEVICE_ATTR(frames_in_buffer0, SYSFS_PERMISSIONS, show_frames_in_buffer, store_frames_in_buffer);
static DEVICE_ATTR(frames_in_buffer1, SYSFS_PERMISSIONS, show_frames_in_buffer, store_frames_in_buffer);
static DEVICE_ATTR(frames_in_buffer2, SYSFS_PERMISSIONS, show_frames_in_buffer, store_frames_in_buffer);
static DEVICE_ATTR(frames_in_buffer3, SYSFS_PERMISSIONS, show_frames_in_buffer, store_frames_in_buffer);
static struct attribute *root_dev_attrs[] = {
&dev_attr_frame_start0.attr,
&dev_attr_frame_start1.attr,
&dev_attr_frame_start2.attr,
&dev_attr_frame_start3.attr,
&dev_attr_frame_full_width0.attr,
&dev_attr_frame_full_width1.attr,
&dev_attr_frame_full_width2.attr,
&dev_attr_frame_full_width3.attr,
&dev_attr_frame_height0.attr,
&dev_attr_frame_height1.attr,
&dev_attr_frame_height2.attr,
&dev_attr_frame_height3.attr,
&dev_attr_frames_in_buffer0.attr,
&dev_attr_frames_in_buffer1.attr,
&dev_attr_frames_in_buffer2.attr,
&dev_attr_frames_in_buffer3.attr,
NULL
};
static const struct attribute_group dev_attr_root_group = {
.attrs = root_dev_attrs,
.name = NULL,
};
static int elphel393_videomem_sysfs_register(struct platform_device *pdev)
{
int retval=0;
struct device *dev = &pdev->dev;
if (&dev->kobj) {
if (((retval = sysfs_create_group(&dev->kobj, &dev_attr_root_group)))<0) return retval;
}
return retval;
}
static int videomem_probe(struct platform_device *pdev)
{
unsigned int irq;
int res;
struct device *dev = &pdev->dev;
const struct of_device_id *match;
const __be32 *bufsize_be;
struct device_node *node;
elphel393_videomem_sysfs_register(pdev);
/* sanity check */
match = of_match_device(elphel393_videomem_of_match, dev);
if (!match)
return -EINVAL;
node = of_find_node_by_name(NULL, "elphel393-videomem");
if (!node)
{
pr_err("Videomem ERROR: No device tree node found\n");
return -ENODEV;
}
buffer_settings.frame_start[0] = be32_to_cpup((__be32 *)of_get_property(node, "frame_start_chn0", NULL));
buffer_settings.frame_start[1] = be32_to_cpup((__be32 *)of_get_property(node, "frame_start_chn1", NULL));
buffer_settings.frame_start[2] = be32_to_cpup((__be32 *)of_get_property(node, "frame_start_chn2", NULL));
buffer_settings.frame_start[3] = be32_to_cpup((__be32 *)of_get_property(node, "frame_start_chn3", NULL));
buffer_settings.frame_full_width[0] = be32_to_cpup((__be32 *)of_get_property(node, "frame_full_width_chn0", NULL));
buffer_settings.frame_full_width[1] = be32_to_cpup((__be32 *)of_get_property(node, "frame_full_width_chn1", NULL));
buffer_settings.frame_full_width[2] = be32_to_cpup((__be32 *)of_get_property(node, "frame_full_width_chn2", NULL));
buffer_settings.frame_full_width[3] = be32_to_cpup((__be32 *)of_get_property(node, "frame_full_width_chn3", NULL));
buffer_settings.frame_height[0] = be32_to_cpup((__be32 *)of_get_property(node, "frame_height_chn0", NULL));
buffer_settings.frame_height[1] = be32_to_cpup((__be32 *)of_get_property(node, "frame_height_chn1", NULL));
buffer_settings.frame_height[2] = be32_to_cpup((__be32 *)of_get_property(node, "frame_height_chn2", NULL));
buffer_settings.frame_height[3] = be32_to_cpup((__be32 *)of_get_property(node, "frame_height_chn3", NULL));
buffer_settings.frames_in_buffer[0] = be32_to_cpup((__be32 *)of_get_property(node, "frames_in_buffer_chn0", NULL));
buffer_settings.frames_in_buffer[1] = be32_to_cpup((__be32 *)of_get_property(node, "frames_in_buffer_chn1", NULL));
buffer_settings.frames_in_buffer[2] = be32_to_cpup((__be32 *)of_get_property(node, "frames_in_buffer_chn2", NULL));
buffer_settings.frames_in_buffer[3] = be32_to_cpup((__be32 *)of_get_property(node, "frames_in_buffer_chn3", NULL));
// Add more parameters here?
// Add sysfs modification
dev_dbg(dev, "Registering character device with name "VIDEOMEM_DRIVER_NAME);
res = register_chrdev(LOGGER_MAJOR, VIDEOMEM_DRIVER_NAME, &videomem_fops);
if(res < 0) {
dev_err(dev, "\nlogger_init: couldn't get a major number %d.\n ",VIDEOMEM_MAJOR);
return res;
}
// Setup interrupt
irq = platform_get_irq_byname(pdev, "membridge_irq");
if (request_irq(irq,
videomem_irq_handler,
0, // no flags
"membridge_irq",
NULL)) {
dev_err(dev, "can not allocate interrupts for %s\n","membridge_irq");
return -EBUSY;
}
init_waitqueue_head(&videomem_wait_queue); // wait queue for logger
g_dev_ptr = dev; // for debugfs
return 0;
}
/** IMU/GPS logger driver remove function */
static int videomem_remove(struct platform_device *pdev) ///< [in] pointer to @e platform_device structure
///< @return always 0
{
unregister_chrdev(VIDEOMEM_MAJOR, VIDEOMEM_DRIVER_NAME);
return 0;
}
static const struct of_device_id elphel393_videomem_of_match[] = {
{ .compatible = "elphel,elphel393-videomem-1.00" },
{ /* end of list */ }
};
MODULE_DEVICE_TABLE(of, elphel393_videomem_of_match);
static struct platform_driver elphel393_videomem = {
.probe = videomem_probe,
.remove = videomem_remove,
.driver = {
.name = VIDEOMEM_DRIVER_NAME,
.of_match_table = elphel393_videomem_of_match,
},
};
module_platform_driver(elphel393_videomem);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Andrey Filippov <andrey@elphel.com>.");
MODULE_DESCRIPTION(VIDEOMEM_MODULE_DESCRIPTION);
/***************************************************************************//**
* @file x393_videomem.h
* @brief Driver for the external DDR3 memory of x393 (currently 0.5GB)
* @copyright Copyright 2016 (C) Elphel, Inc.
* @par <b>License</b>
* 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 2 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/>.
*******************************************************************************/
struct elphel_video_buf_t
{
int frame_start[4]; ///< Channel 0 frame start (in bytes)
int frame_full_width[4]; ///< Channel 0 frame full width (in bytes). 1 memory page is 2048 bytes (128 bursts)
int frame_height[4]; ///< Channel 0 maximal frame height in pixel lines
int frames_in_buffer[4]; ///< Number of frames in channel 0 buffer
};
......@@ -856,8 +856,10 @@
/// when the 4-bit counter is combined with the software variable to get the full 32-bit frame number.<br/>
/// Each parameter page includes 927 parameter registers, as well as 97 bit mask ones to speed up updates between frames.<br/>
/// So if no parameters are changed - nothing to be copied from page to page.
#define PARS_FRAMES 16
#define PARS_FRAMES_MASK (PARS_FRAMES-1) ///< Maximal frame number (15 for NC393)
#ifndef PARS_FRAMES
#define PARS_FRAMES 16
#define PARS_FRAMES_MASK (PARS_FRAMES-1) ///< Maximal frame number (15 for NC393)
#endif
/// Keeping the same size of past frames storage as in 353:<br/>
///#define PASTPARS_SAVE_ENTRIES (PARS_FRAMES << 8) // 2048<br/>
///#define PASTPARS_SAVE_ENTRIES_MASK ((PARS_FRAMES << 8)-1) // 0x7ff
......
......@@ -18,14 +18,15 @@
#define IMAGERAW_MAJOR 131
#define IMAGEACQ_MAJOR 140
#define LOGGER_MAJOR 141
#define VIDEOMEM_MAJOR 142 // implement raw access to memory and/or 16-bit image buffers over membridge interface
/// MINORS
#define LOGGER_MINOR 1
#define LOGGER_CTL_MINOR 2
#define IMAGERAW_MINOR_FRAME 1
#define IMAGERAW_MINOR_FPN 2
#define IMAGERAW_MINOR_UNLOCK 3
#define IMAGERAW_MINOR_FRAME 1
#define IMAGERAW_MINOR_FPN 2
#define IMAGERAW_MINOR_UNLOCK 3
#define CIRCBUF_MINOR 0x20
#define CIRCBUF_MINOR_CHN_0 0x20
......
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