Loading README.md +2 −0 Original line number Diff line number Diff line Loading @@ -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] Loading src/drivers/elphel/Makefile +2 −0 Original line number Diff line number Diff line Loading @@ -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 Loading src/drivers/elphel/elphel393-mem.c +50 −0 Original line number Diff line number Diff line Loading @@ -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 Loading Loading @@ -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"); Loading @@ -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); Loading @@ -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, Loading @@ -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 }; Loading src/drivers/elphel/elphel393-pwr.c +202 −34 Original line number Diff line number Diff line Loading @@ -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>)*/ Loading @@ -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; Loading @@ -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; Loading Loading @@ -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 */ Loading @@ -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), Loading @@ -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); Loading @@ -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: Loading Loading @@ -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, Loading @@ -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 = { Loading Loading @@ -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 */ Loading Loading @@ -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"); Loading Loading @@ -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); Loading @@ -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); Loading @@ -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){ Loading @@ -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; } Loading src/drivers/elphel/framepars.c +22 −25 Original line number Diff line number Diff line Loading @@ -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 Loading Loading @@ -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) \ ({ \ Loading Loading @@ -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
README.md +2 −0 Original line number Diff line number Diff line Loading @@ -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] Loading
src/drivers/elphel/Makefile +2 −0 Original line number Diff line number Diff line Loading @@ -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 Loading
src/drivers/elphel/elphel393-mem.c +50 −0 Original line number Diff line number Diff line Loading @@ -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 Loading Loading @@ -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"); Loading @@ -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); Loading @@ -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, Loading @@ -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 }; Loading
src/drivers/elphel/elphel393-pwr.c +202 −34 Original line number Diff line number Diff line Loading @@ -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>)*/ Loading @@ -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; Loading @@ -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; Loading Loading @@ -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 */ Loading @@ -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), Loading @@ -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); Loading @@ -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: Loading Loading @@ -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, Loading @@ -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 = { Loading Loading @@ -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 */ Loading Loading @@ -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"); Loading Loading @@ -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); Loading @@ -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); Loading @@ -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){ Loading @@ -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; } Loading
src/drivers/elphel/framepars.c +22 −25 Original line number Diff line number Diff line Loading @@ -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 Loading Loading @@ -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) \ ({ \ Loading Loading @@ -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);