Commit 51d2d288 authored by Andrey Filippov's avatar Andrey Filippov
Browse files

merged with master

parents 1b1c1244 b4e02725
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -19,6 +19,8 @@ Run Eclipse from its location directory and provide additional heap memory to it
```
./eclipse -vmargs -Xmx4G
```
or just edit eclipse.ini (same directory as eclipse executable) and make sure -Xmx has at least 4G

 - File → Import... → General → Existing Project into Workspace
 - [Next] → Select root directory → Browse → specify project location (`poky/linux-elphel/`) → [OK] → [Finish]

+2 −0
Original line number Diff line number Diff line
@@ -14,6 +14,8 @@ obj-$(CONFIG_ELPHEL393) += clock10359.o
#fpgajtag-y := fpgajtag353.o x393.o 
#obj-$(CONFIG_ELPHEL393_EXTERNAL)  += fpgajtag.o

obj-$(CONFIG_ELPHEL393)           += exif393.o
obj-$(CONFIG_ELPHEL393)           += x393_helpers.o
obj-$(CONFIG_ELPHEL393)           += framepars.o
#obj-$(CONFIG_ELPHEL393)           += sensor_common.o x393.o
#obj-$(CONFIG_ELPHEL393)           += quantization_tables.o
+50 −0
Original line number Diff line number Diff line
@@ -37,6 +37,8 @@
#include <asm/outercache.h>
#include <asm/cacheflush.h>
#include <elphel/elphel393-mem.h>
#include "x393_helpers.h"

#define SYSFS_PERMISSIONS         0644 /* default permissions for sysfs files */
#define SYSFS_READONLY            0444
#define SYSFS_WRITEONLY           0222
@@ -311,6 +313,47 @@ static ssize_t sync_for_device_bidir(struct device *dev, struct device_attribute
    return count;
}

static ssize_t flush_cpu_cache(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{
	const int buff_size = 0x1000000;
	const int buff_start_offset = 0x100000;
	unsigned int chn;
	int start_offset, end_offset;
	int num_items;
	dma_addr_t phys_addr_start, phys_addr_end;
	u32 start_time, end_time;

	num_items = sscanf(buf, "%u:%d:%d", &chn, &start_offset, &end_offset);
	start_time = get_rtc_usec();
	if (num_items == 3) {
		// invalidate L2 caches
		if (end_offset > start_offset) {
			// handle single buffer case
			phys_addr_start = _elphel_buf.paddr + buff_start_offset + chn * buff_size + start_offset;
			phys_addr_end = _elphel_buf.paddr + buff_start_offset + chn * buff_size + end_offset - 1;
			outer_inv_range(phys_addr_start, phys_addr_end);
		} else {
			// handle split buffer case when pointer rolls over the end
			// first, process the peace at the end of the buffer
			phys_addr_start = _elphel_buf.paddr + buff_start_offset + chn * buff_size + start_offset;
			phys_addr_end = _elphel_buf.paddr + buff_start_offset + ++chn * buff_size - 1;
			outer_inv_range(phys_addr_start, phys_addr_end);

			// second, process the peace at the start of the buffer
			phys_addr_start = _elphel_buf.paddr + buff_start_offset + chn * buff_size;
			phys_addr_end = _elphel_buf.paddr + buff_start_offset + chn * buff_size + end_offset - 1;
			outer_inv_range(phys_addr_start, phys_addr_end);
		}
	}
	end_time = get_rtc_usec();
	if (start_time == 0 && end_time == 0) {
		pr_info("Unable to get usec values\n");
	} else {
		pr_info("Cache invalidate time: %lu\n", end_time - start_time);
	}
	return count;
}

static ssize_t get_sync_for_device_h2d(struct device *dev, struct device_attribute *attr, char *buf)
{
	return sprintf(buf,"Write address/length pair into this file to hand this region of the host to device DMA buffer to device (after CPU writes).\n");
@@ -335,6 +378,11 @@ static ssize_t get_sync_for_cpu_bidir(struct device *dev, struct device_attribut
{
	return sprintf(buf,"Write address/length pair into this file to hand this region of the bidirectional DMA buffer to CPU (before CPU reads).\n");
}
static ssize_t get_flush_cpu_cache(struct device *dev, struct device_attribute *attr, char *buf)
{
	return sprintf(buf, "Write command and address into this file to flush CPU caches. Format 'chn:start_offset:end_offset' where "
			"'chn' is sensor channel, 'start_offset' and 'end_offset' are start and end data offsets in circbuf\n");
}

static DEVICE_ATTR(buffer_address,        SYSFS_PERMISSIONS & SYSFS_READONLY,     get_paddr,                 NULL);
static DEVICE_ATTR(buffer_pages,          SYSFS_PERMISSIONS & SYSFS_READONLY,     get_size,                  NULL);
@@ -351,6 +399,7 @@ static DEVICE_ATTR(sync_for_cpu_d2h, SYSFS_PERMISSIONS,
static DEVICE_ATTR(sync_for_device_d2h,   SYSFS_PERMISSIONS,                      get_sync_for_device_d2h,   sync_for_device_d2h);
static DEVICE_ATTR(sync_for_cpu_bidir,    SYSFS_PERMISSIONS,                      get_sync_for_cpu_bidir,    sync_for_cpu_bidir);
static DEVICE_ATTR(sync_for_device_bidir, SYSFS_PERMISSIONS,                      get_sync_for_device_bidir, sync_for_device_bidir);
static DEVICE_ATTR(flush_cpu_cache,       SYSFS_PERMISSIONS,                      get_flush_cpu_cache,       flush_cpu_cache);

static struct attribute *root_dev_attrs[] = {
		&dev_attr_buffer_address.attr,
@@ -368,6 +417,7 @@ static struct attribute *root_dev_attrs[] = {
		&dev_attr_sync_for_device_d2h.attr,
		&dev_attr_sync_for_cpu_bidir.attr,
		&dev_attr_sync_for_device_bidir.attr,
		&dev_attr_flush_cpu_cache.attr,
		NULL
};

+202 −34
Original line number Diff line number Diff line
@@ -38,9 +38,11 @@
#define SYSFS_READONLY            0444
#define SYSFS_WRITEONLY           0222


/* PCA6408As */
#define GPIO_CHIP1_ADDR    0x20
#define GPIO_CHIP2_ADDR    0x21
/* PCA9571 on 10389, high 4 pins are NC */
#define GPIO_10389_U4_ADDR 0x25
#define LTC3589_ADDR       0x34

/* TODO: set resistors in device tree to accommodate different revisions ( elphel393_pwr,vp15_r1 = <357000>)*/
@@ -61,6 +63,7 @@
#define REF_VAR_STEP_TENTH_MV  125
#define DEAFULT_TIMEOUT        300 /* number of retries testing pgood before giving up */

static DEFINE_MUTEX(gpio_10389_lock);

struct pwr_gpio_t {
	const char * label;
@@ -70,9 +73,9 @@ struct pwr_gpio_t {
};

struct elphel393_pwr_data_t {
	int chip_i2c_addr[3];
	int chip_i2c_addr[4];
	struct device * ltc3489_dev;
	struct pwr_gpio_t pwr_gpio [16];
	struct pwr_gpio_t pwr_gpio [24];
	int simulate; /* do not perform actual i2c writes */
	struct mutex lock;
	int pgoot_timeout;
@@ -203,7 +206,7 @@ static struct voltage_reg_t voltage_reg[]={
		},
}; 

static struct pwr_gpio_t pwr_gpio[16]={
static struct pwr_gpio_t pwr_gpio[24]={
/* 0x20: */
		{"PWR_MGB1",    0, 0, 0}, /* 1.8V margining magnitude (0 - 5%, 1 - 10%, float - 15%) */
		{"PWR_MG1",     1, 0, 0}, /* 1.8V margining enable 0 - negative margining, 1 - positive margining, float - no margining */
@@ -221,9 +224,20 @@ static struct pwr_gpio_t pwr_gpio[16]={
		{ NULL,        12, 0, 0}, /* Not connected */
		{ NULL,        13, 0, 0}, /* Not connected */
		{"MGTAVTTGOOD",14, 0, 0}, /*  (input) 1.2V linear regulator status (generated from 1.8V) */
		{"PGOOD18",    15, 0, 0} /*  (input). Combines other voltages, can be monitored when DIS_POR is activated */
		{"PGOOD18",    15, 0, 0}, /*  (input). Combines other voltages, can be monitored when DIS_POR is activated */
/* 0x25: */
		{ "FAN_CTL",   16, 1, 0}, /* Fan Control, 1 - on, 0 - off */
		{ "DAS_DSS",   17, 1, 0}, /* ? */
		{ "DEVSLP",    18, 1, 0}, /* ? */
		{ "EPGMA",     19, 1, 0}, /* ? */
		{ NULL,        20, 1, 0}, /* Not connected */
		{ NULL,        21, 1, 0}, /* Not connected */
		{ NULL,        22, 1, 0}, /* Not connected */
		{ NULL,        23, 1, 0}  /* Not connected */
};

static struct device * shutdown_dev;

static int make_group (struct device *dev, const char * name,
		ssize_t (*show)(struct device *dev, struct device_attribute *attr,
				char *buf),
@@ -250,7 +264,11 @@ static ssize_t pgood_show(struct device *dev, struct device_attribute *attr, cha
static ssize_t pbad_show(struct device *dev, struct device_attribute *attr, char *buf);
static ssize_t enable_por_show(struct device *dev, struct device_attribute *attr, char *buf);
static ssize_t enable_por_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count);
static ssize_t gpio_10389_get(struct device *dev, struct device_attribute *attr, char *buf);
static ssize_t gpio_10389_set(struct device *dev, struct device_attribute *attr, char *buf, size_t count);
static ssize_t gpio_poweroff(struct device *dev, struct device_attribute *attr, char *buf, size_t count);

static int gpio_shutdown(struct device *dev);
static int por_ctrl(struct device *dev, int disable_por);
static int get_and_disable_por(struct device *dev, int chn_bits, int * old_dis_por);
static int reenable_por(struct device *dev);
@@ -270,6 +288,7 @@ static int get_enable(struct device *dev, int chn);
static int set_enable(struct device *dev, int chn, int enable);
static int get_pgood(struct device *dev, int chn);

int gpio_10389_ctrl(struct device *dev, int value);

/*
 Voltages:
@@ -299,6 +318,22 @@ static DEVICE_ATTR(channels_dis,SYSFS_PERMISSIONS, channels_
static DEVICE_ATTR(power_good,   SYSFS_PERMISSIONS & SYSFS_READONLY,    pgood_show,          NULL);
static DEVICE_ATTR(power_bad,    SYSFS_PERMISSIONS & SYSFS_READONLY,    pbad_show,           NULL);
static DEVICE_ATTR(enable_por,   SYSFS_PERMISSIONS,                     enable_por_show,     enable_por_store);
/*
 * Performs power off whtough CHIP2 P0
 * examples:
 *  1. echo "anything" > power_off - immediate shutdown
 *  2. shutdown -hP now - civilized shutdown
 */
static DEVICE_ATTR(power_off,    SYSFS_PERMISSIONS                 ,    NULL,                gpio_poweroff);
/*
 * input is hex, set all outputs at once with a mask, 8xMSB - enable mask, 8xLSB - pin values.
 * examples:
 *  1. echo 0x101 > gpio_10389 - set P0 high, P1-P3 keep
 *  2. echo 0xf01 > gpio_10389 - set P0 high, P1-P3 - low
 *  3. echo 0x605 > gpio_10389 - P0 keep, P1 low, P2 high, P3 keep
 *  P7-P4 - NC, 0xX0X0 - not supported even on this driver level.
 */
static DEVICE_ATTR(gpio_10389,   SYSFS_PERMISSIONS,                     gpio_10389_get,      gpio_10389_set);

static struct attribute *root_dev_attrs[] = {
		&dev_attr_simulate.attr,
@@ -309,6 +344,8 @@ static struct attribute *root_dev_attrs[] = {
		&dev_attr_power_good.attr,
		&dev_attr_power_bad.attr,
		&dev_attr_enable_por.attr,
		&dev_attr_power_off.attr,
		&dev_attr_gpio_10389.attr,
	    NULL
};
static const struct attribute_group dev_attr_root_group = {
@@ -530,6 +567,7 @@ static ssize_t pgood_show(struct device *dev, struct device_attribute *attr, cha
{
	int chn, en_bits, pgood_bits=0;
	char * cp=buf;

	en_bits= get_enabled_mask(dev);
	if (en_bits<0) return en_bits;
	for (chn=0;chn<ARRAY_SIZE(voltage_reg);chn++) if (en_bits & (1 << chn)){ /* only deal with enabled channels */
@@ -573,6 +611,70 @@ static ssize_t enable_por_store(struct device *dev, struct device_attribute *att
	return count;
}

static ssize_t gpio_10389_set(struct device *dev, struct device_attribute *attr, char *buf, size_t count)
{
	int result;
	int value;
	sscanf(buf, "%i", &value);
	result = gpio_10389_ctrl(dev,value);
	if (result<0) return result;
	return count;
}

/* hardcoded to be [19:16] in pwr_gpio */
static ssize_t gpio_10389_get(struct device *dev, struct device_attribute *attr, char *buf)
{
	int i;
	unsigned int res=0;
	struct elphel393_pwr_data_t *clientdata=platform_get_drvdata(to_platform_device(dev));
	// just 4 of them
	for (i=16;i<20;i++){
		if (pwr_gpio[i].label){
			res += ((clientdata->pwr_gpio[i].out_val)?1:0)<<(i-16);
		}
	}
	return sprintf(buf,"%02x\n",res);
}

static ssize_t gpio_poweroff(struct device *dev, struct device_attribute *attr, char *buf, size_t count)
{
	int rc=gpio_shutdown(dev);
	if (rc<0) return rc;
	return count;
}

int gpio_shutdown(struct device *dev)
{
	int gpio_shutdown_index=get_gpio_index_by_name("NSHUTDOWN");
	if (gpio_shutdown_index<0) return gpio_shutdown_index;
	return gpio_conf_by_index(dev, gpio_shutdown_index, 1,  0);
}

//TODO: test mutex_lock/unlock works
int gpio_10389_ctrl(struct device *dev, int value){
	int i, res;
	int val = 0;

	mutex_lock(&gpio_10389_lock);
	for(i=16;i<20;i++){
		if ((value>>(i-8))&0x1){
			val = (value>>(i-16))&0x1;
			//res = gpio_conf_by_index(dev, i, 1, ~val);
			//if (res<0) return res;
			res = gpio_conf_by_index(dev, i, 1, val);
			if (res<0) return res;
		}
	}
	mutex_unlock(&gpio_10389_lock);
	return 0;
}

int gpio_10389_control(int value){
	gpio_10389_ctrl(shutdown_dev,value);
	return 0;
}
EXPORT_SYMBOL_GPL(gpio_10389_control);

int por_ctrl(struct device *dev, int disable_por)
{
	int gpio_disable_por_index=get_gpio_index_by_name("DIS_POR");
@@ -1094,23 +1196,35 @@ static int i2c_addr_gpiochip_match(struct gpio_chip *chip, void *data)
	return i2c_verify_client(chip->dev) && (client->addr==addr[0]);
}

static void shutdown(void){
	gpio_shutdown(shutdown_dev);
}

static int elphel393_pwr_probe(struct platform_device *pdev)
{
	struct gpio_chip *chip;
//	struct device * ltc3489_dev;
	int i,rc;
	int base[2];

	struct device *tmp_dev;
	struct i2c_client *tmp_i2c_client;
	int base[3],dir[3],out_val[3];

	struct i2c_client *ltc3589_client;
	struct elphel393_pwr_data_t *clientdata = NULL;

	struct gpio_desc *desc;

	shutdown_dev = &pdev->dev;

	dev_info(&pdev->dev,"Probing elphel393-pwr\n");
	clientdata = devm_kzalloc(&pdev->dev, sizeof(*clientdata), GFP_KERNEL);
	clientdata->pgoot_timeout=DEAFULT_TIMEOUT;
	clientdata->pinstrapped_oven=PINSTRAPPED_OVEN;

	clientdata->chip_i2c_addr[0]=0x20;
	clientdata->chip_i2c_addr[1]=0x21;
	clientdata->chip_i2c_addr[2]=0x34;
	clientdata->chip_i2c_addr[0]=GPIO_CHIP1_ADDR;
	clientdata->chip_i2c_addr[1]=GPIO_CHIP2_ADDR;
	clientdata->chip_i2c_addr[2]=GPIO_10389_U4_ADDR;
	clientdata->chip_i2c_addr[3]=LTC3589_ADDR;
	platform_set_drvdata(pdev, clientdata);

	elphel393_pwr_sysfs_register(pdev);
@@ -1119,16 +1233,54 @@ static int elphel393_pwr_probe(struct platform_device *pdev)
	mutex_init(&clientdata->lock);
	
	/* locate GPIO chips by i2c address */
    for (i=0;i<2;i++){
    for (i=0;i<3;i++){
    	chip = gpiochip_find(&clientdata->chip_i2c_addr[i], i2c_addr_gpiochip_match);
    	if (chip!=NULL) {
    		base[i]=chip->base;
    		dev_dbg(&pdev->dev,"Found gpio_chip with i2c_addr=0x%02x, label=%s, base=0x%x\n",clientdata->chip_i2c_addr[i],chip->label,base[i]);

			tmp_dev=find_device_by_i2c_addr(clientdata->chip_i2c_addr[i]);
			tmp_i2c_client = to_i2c_client(tmp_dev);

			//chip0 and chip1 have registers, chip2 - no regs, only outputs
    		if (i<2){
    			//need to invert direction register value
    			dir[i]=i2c_smbus_read_byte_data(tmp_i2c_client, 0x3)^0xff;
    			out_val[i]=i2c_smbus_read_byte_data(tmp_i2c_client, 0x1)&0xff;
    			//dir[i]=0x0;
    			//out_val[i]=0x0;
    			pr_debug("chip %d: dir=%d val=%d\n",i,dir[i],out_val[i]);
    		}else{
    			dir[i]=0xff;
    			out_val[i]=i2c_smbus_read_byte(tmp_i2c_client)&0xff;
    			out_val[i]=0x0;
    		}
    	}else{
    		base[i]=NULL;
    	}
    }

    if (base[2]==NULL){
    	device_remove_file(&pdev->dev, &dev_attr_gpio_10389);
    }
    for (i=0;i<ARRAY_SIZE(pwr_gpio);i++) if (pwr_gpio[i].label){

    for (i=0;i<ARRAY_SIZE(pwr_gpio);i++){
    	if (base[i>>3]!=NULL) if (pwr_gpio[i].label){
    		clientdata->pwr_gpio[i].label=pwr_gpio[i].label;
    	    clientdata->pwr_gpio[i].pin=base[i>>3]+(i & 7);
    	clientdata->pwr_gpio[i].dir=0; /* input */
    	clientdata->pwr_gpio[i].out_val=0; 

    	    pr_debug("setting gpio %d struct to dir=%d val=%d\n",i,(dir[i>>3]>>(i&7))&0x1,(out_val[i>>3]>>(i&7))&0x1);
    	    clientdata->pwr_gpio[i].dir = (dir[i>>3]>>(i&7))&0x1;
    	    clientdata->pwr_gpio[i].out_val = (out_val[i>>3]>>(i&7))&0x1;

    	    //if (i<16) clientdata->pwr_gpio[i].dir=0; /* input */
    	    //else      clientdata->pwr_gpio[i].dir=1; /* output */

    	    //if (i<16) clientdata->pwr_gpio[i].out_val=0;
    	    //else      clientdata->pwr_gpio[i].out_val=1;

    	    //clientdata->pwr_gpio[i].out_val=0;

    	    rc=gpio_request(clientdata->pwr_gpio[i].pin, clientdata->pwr_gpio[i].label);
    	    if (rc<0){
    	    	dev_err(&pdev->dev," Failed to get GPIO[%d] with label %s\n",clientdata->pwr_gpio[i].pin,clientdata->pwr_gpio[i].label);
@@ -1137,6 +1289,8 @@ static int elphel393_pwr_probe(struct platform_device *pdev)
    	    	dev_dbg(&pdev->dev,"Confirmed request GPIO[%d] with label %s\n",clientdata->pwr_gpio[i].pin,clientdata->pwr_gpio[i].label);
    	    }
    	}
    }

    /* find ltc3589 */
    clientdata->ltc3489_dev=find_device_by_i2c_addr(LTC3589_ADDR);
    if (!clientdata->ltc3489_dev){
@@ -1149,6 +1303,20 @@ static int elphel393_pwr_probe(struct platform_device *pdev)
	dev_dbg(&pdev->dev,"LTC3589 status= 0x%02x\n",ltc3589_read_field(ltc3589_client, LTC3589_AWE_PGSTAT));
	elphel393_pwr_init_of(pdev);
	
	/*
	 * 1. pm_power_off - arch/arm/kernel/process.c - called in the end of halt if power off requested
	 * 2. To perform a proper system shutdown with power off ("shutdown -hP now") this function is set here.
	 */
	pm_power_off = shutdown;

	/*
	if (base[2]!=NULL){
		//turn off PCA9571
		gpio_10389_ctrl(&pdev->dev, 0xf0f);
		gpio_10389_ctrl(&pdev->dev, 0xf00);
	}
	*/

	return 0;
}	

+22 −25
Original line number Diff line number Diff line
@@ -19,7 +19,7 @@
 */

//copied from cxi2c.c - TODO:remove unneeded
#undef JTAG_BRANCH


#include <linux/types.h>        /// div for 64
#include <asm/div64.h>          /// div for 64
@@ -147,9 +147,7 @@ wait_queue_head_t aframepars_wait_queue[SENSOR_PORTS];/// used to wait for

/* Remove after compilation OK */
struct sensorproc_t * sensorproc = NULL;
#ifdef JTAG_BRANCH
void camera_interrupts (int on) {}
#endif
//void camera_interrupts (int on) {}
#if 0
#define wait_event_interruptible(wq, condition)				\
({									\
@@ -1342,25 +1340,24 @@ int framepars_remove(struct platform_device *pdev)

	return 0;
}
#ifdef JTAG_BRANCH
static const struct of_device_id elphel393_framepars_of_match[] = {
	{ .compatible = "elphel,elphel393-framepars-1.00" },
	{ /* end of list */ }
};
MODULE_DEVICE_TABLE(of, elphel393_framepars_of_match);

static struct platform_driver elphel393_framepars = {
	.probe			= framepars_init,
	.remove			= framepars_remove,
	.driver			= {
		.name		= FRAMEPARS_DRIVER_NAME,
		.of_match_table = elphel393_framepars_of_match,
	},
};

module_platform_driver(elphel393_framepars);

MODULE_LICENSE("GPL");
MODULE_AUTHOR("Andrey Filippov <andrey@elphel.com>.");
MODULE_DESCRIPTION(X3X3_FRAMEPARS_DRIVER_NAME);
#endif
 No newline at end of file
//static const struct of_device_id elphel393_framepars_of_match[] = {
//	{ .compatible = "elphel,elphel393-framepars-1.00" },
//	{ /* end of list */ }
//};
//MODULE_DEVICE_TABLE(of, elphel393_framepars_of_match);
//
//static struct platform_driver elphel393_framepars = {
//	.probe			= framepars_init,
//	.remove			= framepars_remove,
//	.driver			= {
//		.name		= FRAMEPARS_DRIVER_NAME,
//		.of_match_table = elphel393_framepars_of_match,
//	},
//};
//
//module_platform_driver(elphel393_framepars);
//
//MODULE_LICENSE("GPL");
//MODULE_AUTHOR("Andrey Filippov <andrey@elphel.com>.");
//MODULE_DESCRIPTION(X3X3_FRAMEPARS_DRIVER_NAME);
Loading