Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
L
linux-elphel
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Commits
Open sidebar
Elphel
linux-elphel
Commits
196a40df
Commit
196a40df
authored
Aug 04, 2016
by
Andrey Filippov
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
adding video memor=y driver wih DT and sysfs interface to configure video memory
parent
c2b627a5
Changes
9
Show whitespace changes
Inline
Side-by-side
Showing
9 changed files
with
715 additions
and
32 deletions
+715
-32
Makefile
src/drivers/elphel/Makefile
+1
-0
imu_log393.c
src/drivers/elphel/imu_log393.c
+8
-14
pgm_functions.c
src/drivers/elphel/pgm_functions.c
+1
-13
x393_fpga_functions.c
src/drivers/elphel/x393_fpga_functions.c
+189
-0
x393_fpga_functions.h
src/drivers/elphel/x393_fpga_functions.h
+23
-0
x393_videomem.c
src/drivers/elphel/x393_videomem.c
+460
-0
x393_videomem.h
src/drivers/elphel/x393_videomem.h
+25
-0
c313a.h
src/include/elphel/c313a.h
+4
-2
driver_numbers.h
src/include/elphel/driver_numbers.h
+4
-3
No files found.
src/drivers/elphel/Makefile
View file @
196a40df
...
...
@@ -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
src/drivers/elphel/imu_log393.c
View file @
196a40df
...
...
@@ -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
);
src/drivers/elphel/pgm_functions.c
View file @
196a40df
...
...
@@ -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"
...
...
src/drivers/elphel/x393_fpga_functions.c
0 → 100644
View file @
196a40df
/***************************************************************************//**
* @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
;
}
/*
*/
src/drivers/elphel/x393_fpga_functions.h
0 → 100644
View file @
196a40df
/***************************************************************************//**
* @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
);
src/drivers/elphel/x393_videomem.c
0 → 100644
View file @
196a40df
/***************************************************************************//**
* @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
,
"
\n
logger_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
);
src/drivers/elphel/x393_videomem.h
0 → 100644
View file @
196a40df
/***************************************************************************//**
* @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
};
src/include/elphel/c313a.h
View file @
196a40df
...
...
@@ -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
...
...
src/include/elphel/driver_numbers.h
View file @
196a40df
...
...
@@ -18,6 +18,7 @@
#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
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment