From: Kumar Abhishek <abhis...@theembeddedkitchen.net>

Same as Revision 91b9d2b37292eb8cd5f862ad833687002677f95c
in github.com/abhishek-kakkar/BeagleLogic/

Signed-off-by: Kumar Abhishek <abhis...@theembeddedkitchen.net>
---
 drivers/remoteproc/Kconfig       |   13 +
 drivers/remoteproc/Makefile      |    1 +
 drivers/remoteproc/beaglelogic.c | 1189 ++++++++++++++++++++++++++++++++++++++
 drivers/remoteproc/beaglelogic.h |   62 ++
 4 files changed, 1265 insertions(+)
 create mode 100644 drivers/remoteproc/beaglelogic.c
 create mode 100644 drivers/remoteproc/beaglelogic.h

diff --git a/drivers/remoteproc/Kconfig b/drivers/remoteproc/Kconfig
index 13cb3ca..9f633d9 100644
--- a/drivers/remoteproc/Kconfig
+++ b/drivers/remoteproc/Kconfig
@@ -53,4 +53,17 @@ config PRU_RPROC
          This can be either built-in or a loadable module.
          If unsure say N.
 
+config PRU_RPROC_BEAGLELOGIC
+       tristate "BeagleLogic support over AM33xx PRU remoteproc support"
+       depends on EXPERIMENTAL
+       depends on HAS_DMA && SOC_AM33XX
+       select REMOTEPROC
+       select RPMSG
+       select PRU_RPROC
+       default n
+       help
+         Say y or m here to support BeagleLogic - a LA based on the AM33xx PRUs
+         This can be either built-in or a loadable module.
+         If unsure say N.
+
 endmenu
diff --git a/drivers/remoteproc/Makefile b/drivers/remoteproc/Makefile
index 9042660..347af77 100644
--- a/drivers/remoteproc/Makefile
+++ b/drivers/remoteproc/Makefile
@@ -10,3 +10,4 @@ remoteproc-y                          += 
remoteproc_elf_loader.o
 obj-$(CONFIG_OMAP_REMOTEPROC)          += omap_remoteproc.o
 obj-$(CONFIG_STE_MODEM_RPROC)          += ste_modem_rproc.o
 obj-$(CONFIG_PRU_RPROC)                        += pru_rproc.o
+obj-$(CONFIG_PRU_RPROC_BEAGLELOGIC)    += beaglelogic.o
diff --git a/drivers/remoteproc/beaglelogic.c b/drivers/remoteproc/beaglelogic.c
new file mode 100644
index 0000000..11da9f9
--- /dev/null
+++ b/drivers/remoteproc/beaglelogic.c
@@ -0,0 +1,1189 @@
+/*
+ * Kernel module for BeagleLogic - a logic analyzer for the BeagleBone [Black]
+ * Designed to be used in conjunction with a modified pru_rproc driver
+ *
+ * Copyright (C) 2014 Kumar Abhishek <abhis...@theembeddedkitchen.net>
+ *
+ * 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.
+ */
+
+#include <asm/atomic.h>
+#include <asm/uaccess.h>
+
+#include <linux/module.h>
+#include <linux/err.h>
+#include <linux/kernel.h> 
+#include <linux/init.h>
+#include <linux/wait.h>
+
+#include <linux/platform_device.h>
+#include <linux/miscdevice.h>
+
+#include <linux/io.h>
+#include <linux/irqreturn.h>
+#include <linux/slab.h>
+#include <linux/genalloc.h>
+#include <linux/mm.h>
+#include <linux/dma-mapping.h>
+
+#include <linux/kobject.h>
+#include <linux/string.h>
+
+#include <linux/of.h>
+#include <linux/of_platform.h>
+#include <linux/of_address.h>
+#include <linux/of_device.h>
+
+#include <linux/sysfs.h>
+#include <linux/fs.h>
+
+#include "beaglelogic.h"
+#include "beaglelogic_glue.h"
+
+/* Buffer states */
+enum bufstates {
+       STATE_BL_BUF_ALLOC,
+       STATE_BL_BUF_MAPPED,
+       STATE_BL_BUF_UNMAPPED,
+       STATE_BL_BUF_DROPPED
+};
+
+/* PRU Downcall API */
+#define BL_DC_GET_VERSION      0   /* Firmware */
+#define BL_DC_GET_MAX_SG       1   /* Get the Max number of SG entries */
+#define BL_DC_GET_CXT_PTR      2   /* Get the context pointer */
+#define BL_DC_SM_RATE          3   /* Get/set rate = (200 / n) MHz, n = 2... */
+#define BL_DC_SM_TRIGGER       4   /* RFU */
+#define BL_DC_SM_ARM           7   /* Arm the LA (start sampling) */
+
+/* PRU-side sample buffer descriptor */
+typedef struct prusamplebuf {
+       u32 dma_start_addr;
+       u32 dma_end_addr;
+} buflist;
+
+/* Shared structure containing PRU attributes */
+typedef struct capture_context {
+       /* Firmware context structure magic bytes */
+#define BL_FW_MAGIC    0xBEA61E10
+       u32 magic;
+       u32 errorCode;
+
+       u32 interrupt1count;
+
+       buflist list_head; /* This is really an array on the PRU side */
+} ccontext;
+
+/* Forward declration */
+static const struct file_operations pru_beaglelogic_fops;
+
+/* Buffers are arranged as an array but are
+ * also circularly linked to simplify reads */
+typedef struct databuf logic_buffer;
+typedef struct databuf {
+       void *buf;
+       dma_addr_t phys_addr;
+       size_t size;
+
+       unsigned short state;
+       unsigned short index;
+
+       logic_buffer *next;
+} logic_buffer;
+
+struct beaglelogicdev {
+       /* Misc device descriptor */
+       struct miscdevice miscdev;
+
+       /* Imported functions */
+       int (*downcall_idx)(int, u32, u32, u32, u32, u32, u32);
+       void __iomem *(*d_da_to_va)(int, u32);
+       int (*pru_start)(int);
+       void (*pru_request_stop)(void);
+
+       /* Exported functions */
+       int (*serve_irq)(int, void *);
+
+       /* Core clock frequency: Required for configuring sample rates */
+       u32 coreclockfreq;
+
+       /* Private data */
+       struct device *p_dev; /* Parent platform device */
+
+       /* Locks */
+       struct mutex mutex;
+
+       /* Buffer management */
+       logic_buffer *buffers;
+       logic_buffer *lastbufready;
+       logic_buffer *bufbeingread;
+       u32 bufcount;
+       wait_queue_head_t wait;
+
+       /* ISR Bookkeeping */
+       u32 previntcount;       /* Previous interrupt count read from PRU */
+
+       /* Firmware capabilities */
+       ccontext *cxt_pru;
+
+       /* Device capabilities */
+       u32 bufunitsize;        /* Size of 1 Allocation unit */
+       u32 maxbufcount;        /* Max buffer count supported by the PRU FW */
+       u32 samplerate;         /* Sample rate = 100 / n MHz, n = 2+ (int) */
+       u32 triggerflags;       /* bit 0 : 1shot/!continuous */
+       u32 sampleunit;         /* 0:8bits, 1:16bits */
+
+       /* State */
+       u32 state;
+       u32 lasterror;
+};
+
+typedef struct bufreader {
+       struct beaglelogicdev *bldev;
+       logic_buffer *buf;
+
+       u32 pos;
+       u32 remaining;
+} logic_buffer_reader;
+
+#define to_beaglelogicdev(dev) container_of((dev), \
+               struct beaglelogicdev, miscdev)
+
+#define DRV_NAME       "beaglelogic"
+#define DRV_VERSION    "1.0"
+
+/* Begin Buffer Management section */
+static int bufunitsize = 4 * 1024 * 1024;
+module_param(bufunitsize, int, S_IRUGO);
+MODULE_PARM_DESC(bufunitsize, " Size of each buffer unit [default 4 MB]");
+
+/* Allocate DMA buffers for the PRU
+ * This method acquires & releases the device mutex */
+static int beaglelogic_memalloc(struct device *dev, u32 bufsize)
+{
+       struct beaglelogicdev *bldev = dev_get_drvdata(dev);
+       int i, cnt;
+       void *buf;
+
+       /* Check if BL is in use */
+       if (!mutex_trylock(&bldev->mutex))
+               return -EBUSY;
+
+       /* Compute no. of buffers to allocate, round up
+        * We need at least two buffers for ping-pong action */
+       cnt = max(DIV_ROUND_UP(bufsize, bldev->bufunitsize), (u32)2);
+
+       /* Too large? */
+       if (cnt > bldev->maxbufcount) {
+               dev_err(dev, "Not enough memory\n");
+               return -ENOMEM;
+       }
+
+       bldev->bufcount = cnt;
+
+       /* Allocate buffer list */
+       bldev->buffers = devm_kzalloc(dev, sizeof(logic_buffer) * (cnt),
+                       GFP_KERNEL);
+       if (!bldev->buffers)
+               goto failnomem;
+
+       /* Allocate DMA buffers */
+       for (i = 0; i < cnt; i++) {
+               buf = kmalloc(bldev->bufunitsize, GFP_KERNEL);
+               if (!buf)
+                       goto failrelease;
+
+               /* Fill with 0xFF */
+               memset(buf, 0xFF, bldev->bufunitsize);
+
+               /* Set the buffers */
+               bldev->buffers[i].buf = buf;
+               bldev->buffers[i].phys_addr = virt_to_phys(buf);
+               bldev->buffers[i].size = bldev->bufunitsize;
+               bldev->buffers[i].index = i;
+
+               /* Circularly link the buffers */
+               bldev->buffers[i].next = &bldev->buffers[(i + 1) % cnt];
+       }
+
+       /* Write log and unlock */
+       dev_info(dev, "Successfully allocated %d bytes of memory.\n",
+                       cnt * bldev->bufunitsize);
+
+       mutex_unlock(&bldev->mutex);
+
+       /* Done */
+       return 0;
+failrelease:
+       for (i = 0; i < cnt; i++) {
+               if (bldev->buffers[i].buf)
+                       kfree(bldev->buffers[i].buf);
+       }
+       devm_kfree(dev, bldev->buffers);
+       dev_err(dev, "Sample buffer allocation:");
+failnomem:
+       dev_err(dev, "Not enough memory\n");
+       mutex_unlock(&bldev->mutex);
+       return -ENOMEM;
+}
+
+/* Frees the DMA buffers and the bufferlist */
+static void beaglelogic_memfree(struct device *dev)
+{
+       struct beaglelogicdev *bldev = dev_get_drvdata(dev);
+       int i;
+
+       mutex_lock(&bldev->mutex);
+       for (i = 0; i < bldev->bufcount; i++)
+               kfree(bldev->buffers[i].buf);
+
+       if (bldev->buffers)
+               devm_kfree(dev, bldev->buffers);
+       mutex_unlock(&bldev->mutex);
+}
+
+/* No argument checking for the map/unmap functions */
+static int beaglelogic_map_buffer(struct device *dev, logic_buffer *buf)
+{
+       dma_addr_t dma_addr;
+
+       /* If already mapped, do nothing */
+       if (buf->state == STATE_BL_BUF_MAPPED)
+               return 0;
+
+       dma_addr = dma_map_single(dev, buf->buf, buf->size, DMA_FROM_DEVICE);
+       if (dma_mapping_error(dev, dma_addr))
+               goto fail;
+       else {
+               buf->phys_addr = dma_addr;
+               buf->state = STATE_BL_BUF_MAPPED;
+       }
+
+       return 0;
+fail:
+       dev_err(dev, "DMA Mapping error. \n");
+       return -1;
+}
+
+static void beaglelogic_unmap_buffer(struct device *dev, logic_buffer *buf)
+{
+       dma_unmap_single(dev, buf->phys_addr, buf->size, DMA_FROM_DEVICE);
+       buf->state = STATE_BL_BUF_UNMAPPED;
+}
+
+/* Fill the sample buffer with a pattern of increasing 32-bit ints
+ * This can be studied to watch out for dropped bytes/buffers */
+static void beaglelogic_fill_buffer_testpattern(struct device *dev)
+{
+       struct beaglelogicdev *bldev = dev_get_drvdata(dev);
+       int i, j;
+       u32 cnt = 0, *addr;
+
+       mutex_lock(&bldev->mutex);
+       for (i = 0; i < bldev->bufcount; i++) {
+               addr = bldev->buffers[i].buf;
+
+               for (j = 0; j < bldev->buffers[i].size / sizeof(cnt); j++)
+                       *addr++ = cnt++;
+       }
+       mutex_unlock(&bldev->mutex);
+}
+
+/* Map all the buffers. This is done just before beginning a sample operation
+ * NOTE: PRUs are halted at this time */
+static int beaglelogic_map_and_submit_all_buffers(struct device *dev)
+{
+       struct beaglelogicdev *bldev = dev_get_drvdata(dev);
+       buflist *pru_buflist = &bldev->cxt_pru->list_head;
+       int i, j;
+       dma_addr_t addr;
+
+       if (!pru_buflist)
+               return -1;
+
+       for (i = 0; i < bldev->bufcount;i++) {
+               if (beaglelogic_map_buffer(dev, &bldev->buffers[i]))
+                       goto fail;
+       }
+
+       /* Write buffer table to the PRU memory, and null terminate */
+       for (i = 0; i < bldev->bufcount; i++) {
+               addr = bldev->buffers[i].phys_addr;
+               pru_buflist[i].dma_start_addr = addr;
+               pru_buflist[i].dma_end_addr = addr + bldev->buffers[i].size;
+       }
+       pru_buflist[i].dma_start_addr = 0;
+       pru_buflist[i].dma_end_addr = 0;
+
+       /* Update state to ready */
+       if (i)
+               bldev->state = STATE_BL_ARMED;
+
+       return 0;
+fail:
+       /* Unmap the buffers */
+       for (j = 0; j < i; j++)
+               beaglelogic_unmap_buffer(dev, &bldev->buffers[i]);
+
+       dev_err(dev, "DMA Mapping failed at i=%d\n", i);
+
+       bldev->state = STATE_BL_ERROR;
+       return 1;
+}
+
+/* End Buffer Management section */
+
+/* Begin Device Attributes Configuration Section
+ * All set operations lock and unlock the device mutex */
+
+u32 beaglelogic_get_samplerate(struct device *dev)
+{
+       struct beaglelogicdev *bldev = dev_get_drvdata(dev);
+       return bldev->samplerate;
+}
+
+int beaglelogic_set_samplerate(struct device *dev, u32 samplerate)
+{
+       struct beaglelogicdev *bldev = dev_get_drvdata(dev);
+       if (samplerate > bldev->coreclockfreq / 2 || samplerate < 100000)
+               return -EINVAL;
+
+       if (mutex_trylock(&bldev->mutex)) {
+               /* Get sample rate nearest to divisor */
+               bldev->samplerate = (bldev->coreclockfreq / 2) /
+                               ((bldev->coreclockfreq / 2)/ samplerate);
+               mutex_unlock(&bldev->mutex);
+               return 0;
+       }
+       return -EBUSY;
+}
+
+u32 beaglelogic_get_sampleunit(struct device *dev)
+{
+       struct beaglelogicdev *bldev = dev_get_drvdata(dev);
+       return bldev->sampleunit;
+}
+
+int beaglelogic_set_sampleunit(struct device *dev, u32 sampleunit)
+{
+       struct beaglelogicdev *bldev = dev_get_drvdata(dev);
+       if (sampleunit > 2)
+               return -EINVAL;
+
+       if (mutex_trylock(&bldev->mutex)) {
+               bldev->sampleunit = sampleunit;
+               mutex_unlock(&bldev->mutex);
+
+               return 0;
+       }
+       return -EBUSY;
+}
+
+u32 beaglelogic_get_triggerflags(struct device *dev)
+{
+       struct beaglelogicdev *bldev = dev_get_drvdata(dev);
+       return bldev->triggerflags;
+}
+
+int beaglelogic_set_triggerflags(struct device *dev, u32 triggerflags)
+{
+       struct beaglelogicdev *bldev = dev_get_drvdata(dev);
+       if (triggerflags > 1)
+               return -EINVAL;
+
+       if (mutex_trylock(&bldev->mutex)) {
+               bldev->triggerflags = triggerflags;
+               mutex_unlock(&bldev->mutex);
+
+               return 0;
+       }
+       return -EBUSY;
+}
+
+/* End Device Attributes Configuration Section */
+
+/* This is [to be] called from a threaded IRQ handler */
+int beaglelogic_serve_irq(int irqno, void *data)
+{
+       struct beaglelogicdev *bldev = data;
+       struct device *dev = bldev->miscdev.this_device;
+       u32 state = bldev->state;
+
+       dev_dbg(dev, "Beaglelogic IRQ #%d\n", irqno);
+       if (irqno == BL_IRQ_BUFREADY) {
+               /* Manage the buffers */
+               beaglelogic_unmap_buffer(dev,
+                       bldev->lastbufready = bldev->bufbeingread);
+
+               /* Avoid a false buffer overrun warning on the last run */
+               if (bldev->triggerflags != BL_TRIGGERFLAGS_ONESHOT ||
+                       bldev->bufbeingread->next->index != 0) {
+                       beaglelogic_map_buffer(dev,
+                               bldev->bufbeingread = 
bldev->bufbeingread->next);
+               }
+               wake_up_interruptible(&bldev->wait);
+       } else if (irqno == BL_IRQ_CLEANUP) {
+               /* This interrupt occurs twice:
+                *  1. After a successful configuration of PRU capture
+                *  2. After the last buffer transferred  */
+               state = bldev->state;
+               if (state <= STATE_BL_ARMED) {
+                       dev_dbg(dev, "config written, BeagleLogic ready\n");
+                       return IRQ_HANDLED;
+               }
+               else if (state != STATE_BL_REQUEST_STOP &&
+                               state != STATE_BL_RUNNING) {
+                       dev_err(dev, "Unexpected stop request \n");
+                       bldev->state = STATE_BL_ERROR;
+                       return IRQ_HANDLED;
+               }
+               bldev->state = STATE_BL_INITIALIZED;
+               wake_up_interruptible(&bldev->wait);
+       }
+
+       return IRQ_HANDLED;
+}
+
+/* Write configuration into the PRU [via downcall] (assume mutex is held) */
+int beaglelogic_write_configuration(struct device *dev)
+{
+       struct beaglelogicdev *bldev = dev_get_drvdata(dev);
+       int i;
+
+       /* Do a downcall and hand over the settings */
+       i = bldev->downcall_idx(0, BL_DC_SM_TRIGGER,
+                       (bldev->coreclockfreq / 2) / bldev->samplerate,
+                       bldev->sampleunit, bldev->triggerflags, 0, 0);
+
+       dev_dbg(dev, "PRU Config written, err code = %d\n", i);
+       return 0;
+}
+
+/* Begin the sampling operation [This takes the mutex] */
+int beaglelogic_start(struct device *dev)
+{
+       struct beaglelogicdev *bldev = dev_get_drvdata(dev);
+
+       /* This mutex will be locked for the entire duration BeagleLogic runs */
+       mutex_lock(&bldev->mutex);
+       if (beaglelogic_write_configuration(dev)) {
+               mutex_unlock(&bldev->mutex);
+               return -1;
+       }
+       bldev->bufbeingread = &bldev->buffers[0];
+       bldev->pru_start(0);
+       bldev->downcall_idx(0, BL_DC_SM_ARM, 0, 0, 0, 0, 0);
+
+       /* All set now. Start the PRUs and wait for IRQs */
+       bldev->state = STATE_BL_RUNNING;
+       bldev->lasterror = 0;
+
+       dev_info(dev, "capture started with sample rate=%d Hz, sampleunit=%d, "\
+                       "triggerflags=%d",
+                       bldev->samplerate,
+                       bldev->sampleunit,
+                       bldev->triggerflags);
+       return 0;
+}
+
+/* Request stop. Stop will effect only after the last buffer is written out */
+void beaglelogic_stop(struct device *dev)
+{
+       struct beaglelogicdev *bldev = dev_get_drvdata(dev);
+
+       if (mutex_is_locked(&bldev->mutex)) {
+               bldev->pru_request_stop();
+               bldev->state = STATE_BL_REQUEST_STOP;
+
+               /* Wait for the PRU to signal completion */
+               wait_event_interruptible_timeout(bldev->wait,
+                               bldev->state == STATE_BL_INITIALIZED, HZ / 100);
+
+               /* Release */
+               mutex_unlock(&bldev->mutex);
+
+               dev_info(dev, "capture session ended\n");
+       }
+}
+
+/* fops */
+static int beaglelogic_f_open(struct inode *inode, struct file *filp)
+{
+       logic_buffer_reader *reader;
+       struct beaglelogicdev *bldev = to_beaglelogicdev(filp->private_data);
+       struct device *dev = bldev->miscdev.this_device;
+
+       if (bldev->bufcount == 0)
+               return -ENOMEM;
+
+       reader = devm_kzalloc(dev, sizeof(*reader), GFP_KERNEL);
+       reader->bldev = bldev;
+       reader->buf = NULL;
+       reader->pos = 0;
+       reader->remaining = 0;
+
+       filp->private_data = reader;
+
+       /* Map and submit all the buffers */
+       if (beaglelogic_map_and_submit_all_buffers(dev))
+               return -ENOMEM;
+
+       return 0;
+}
+
+/* Read the sample (ring) buffer. TODO Implement Nonblock */
+ssize_t beaglelogic_f_read (struct file *filp, char __user *buf,
+                          size_t sz, loff_t *offset)
+{
+       int count;
+       logic_buffer_reader *reader = filp->private_data;
+       struct beaglelogicdev *bldev = reader->bldev;
+       struct device *dev = bldev->miscdev.this_device;
+
+       if (bldev->state == STATE_BL_ERROR)
+               return -EIO;
+
+       if (reader->remaining > 0)
+               goto perform_copy;
+
+       if (reader->buf) {
+               if (bldev->state == STATE_BL_INITIALIZED &&
+                               bldev->lastbufready == reader->buf)
+                       return 0;
+
+               reader->buf = reader->buf->next;
+       }
+       else {
+               /* (re)trigger */
+               if (beaglelogic_start(dev))
+                       return -ENOEXEC;
+
+               reader->buf = &bldev->buffers[0];
+       }
+       reader->pos = 0;
+       reader->remaining = reader->buf->size;
+
+       dev_dbg(dev, "waiting for IRQ\n");
+       wait_event_interruptible(bldev->wait,
+                       reader->buf->state == STATE_BL_BUF_UNMAPPED);
+       dev_dbg(dev, "got IRQ\n");
+perform_copy:
+       count = min(reader->remaining, sz);
+
+       /* Detect buffer drop */
+       if (reader->buf->state == STATE_BL_BUF_MAPPED) {
+               dev_warn(dev, "buffer dropped at index %d \n",
+                               reader->buf->index);
+               reader->buf->state = STATE_BL_BUF_DROPPED;
+               bldev->lasterror = 0x10000 | reader->buf->index;
+       }
+
+       if (copy_to_user(buf, reader->buf->buf + reader->pos, count))
+               return -EFAULT;
+
+       reader->pos += count;
+       reader->remaining -= count;
+
+       return count;
+}
+
+/* Map the PRU buffers to user space [cache coherency managed by driver] */
+int beaglelogic_f_mmap(struct file *filp, struct vm_area_struct *vma)
+{
+       int i, ret;
+       logic_buffer_reader *reader = filp->private_data;
+       struct beaglelogicdev *bldev = reader->bldev;
+
+       unsigned long addr = vma->vm_start;
+
+       if (vma->vm_end - vma->vm_start > bldev->bufunitsize * bldev->bufcount)
+               return -EINVAL;
+
+       for (i = 0; i < bldev->bufcount; i++) {
+               ret = remap_pfn_range(vma, addr,
+                               (bldev->buffers[i].phys_addr) >> PAGE_SHIFT,
+                               bldev->buffers[i].size,
+                               vma->vm_page_prot);
+
+               if (ret)
+                       return -EINVAL;
+
+               addr += bldev->buffers[i].size;
+       }
+       return 0;
+}
+
+/* Configuration through ioctl */
+static long beaglelogic_f_ioctl(struct file *filp, unsigned int cmd,
+                 unsigned long arg)
+{
+       logic_buffer_reader *reader = filp->private_data;
+       struct beaglelogicdev *bldev = reader->bldev;
+       struct device *dev = bldev->miscdev.this_device;
+
+       u32 val;
+
+       dev_info(dev, "BeagleLogic: IOCTL called cmd = %08X, "\
+                       "arg = %08lX\n", cmd, arg);
+
+       switch (cmd) {
+               case IOCTL_BL_GET_VERSION:
+                       return 0;
+
+               case IOCTL_BL_GET_SAMPLE_RATE:
+                       if (copy_to_user((void * __user)arg,
+                                       &bldev->samplerate,
+                                       sizeof(bldev->samplerate)))
+                               return -EFAULT;
+                       return 0;
+
+               case IOCTL_BL_SET_SAMPLE_RATE:
+                       if (beaglelogic_set_samplerate(dev, (u32)arg))
+                               return -EFAULT;
+                       return 0;
+
+               case IOCTL_BL_GET_SAMPLE_UNIT:
+                       if (copy_to_user((void * __user)arg,
+                                       &bldev->sampleunit,
+                                       sizeof(bldev->sampleunit)))
+                               return -EFAULT;
+                       return 0;
+
+               case IOCTL_BL_SET_SAMPLE_UNIT:
+                       if (beaglelogic_set_sampleunit(dev, (u32)arg))
+                               return -EFAULT;
+                       return 0;
+
+               case IOCTL_BL_GET_TRIGGER_FLAGS:
+                       if (copy_to_user((void * __user)arg,
+                                       &bldev->triggerflags,
+                                       sizeof(bldev->triggerflags)))
+                               return -EFAULT;
+                       return 0;
+
+               case IOCTL_BL_SET_TRIGGER_FLAGS:
+                       if (beaglelogic_set_triggerflags(dev, (u32)arg))
+                               return -EFAULT;
+                       return 0;
+
+               case IOCTL_BL_GET_CUR_INDEX:
+                       if (copy_to_user((void * __user)arg,
+                                       &bldev->bufbeingread->index,
+                                       sizeof(bldev->bufbeingread->index)))
+                               return -EFAULT;
+                       return 0;
+
+               case IOCTL_BL_CACHE_INVALIDATE:
+                       for (val = 0; val < bldev->bufcount; val++) {
+                               beaglelogic_unmap_buffer(dev,
+                                               &bldev->buffers[val]);
+                       }
+                       return 0;
+
+               case IOCTL_BL_GET_BUFFER_SIZE:
+                       val = bldev->bufunitsize * bldev->bufcount;
+                       if (copy_to_user((void * __user)arg,
+                                       &val,
+                                       sizeof(val)))
+                               return -EFAULT;
+                       return 0;
+
+               case IOCTL_BL_SET_BUFFER_SIZE:
+                       beaglelogic_memfree(dev);
+                       val = beaglelogic_memalloc(dev, arg);
+                       if (!val)
+                               return 
beaglelogic_map_and_submit_all_buffers(dev);
+                       return 0;
+
+               case IOCTL_BL_GET_BUFUNIT_SIZE:
+                       if (copy_to_user((void * __user)arg,
+                                       &bldev->bufunitsize,
+                                       sizeof(bldev->bufunitsize)))
+                               return -EFAULT;
+                       return 0;
+
+               case IOCTL_BL_FILL_TEST_PATTERN:
+                       beaglelogic_fill_buffer_testpattern(dev);
+                       return 0;
+
+               case IOCTL_BL_START:
+                       beaglelogic_start(dev);
+                       return 0;
+
+               case IOCTL_BL_STOP:
+                       beaglelogic_stop(dev);
+                       return 0;
+
+       }
+       return -ENOTTY;
+}
+
+/* llseek to offset zero resets the LA */
+static loff_t beaglelogic_f_llseek(struct file *filp, loff_t offset, int 
whence)
+{
+       logic_buffer_reader *reader = filp->private_data;
+       struct device *dev = reader->bldev->miscdev.this_device;
+       if (whence == SEEK_SET && offset == 0) {
+               /* The next read triggers the LA */
+               reader->buf = NULL;
+               reader->pos = 0;
+               reader->remaining = 0;
+
+               /* Stop and map the first buffer */
+               beaglelogic_stop(dev);
+               beaglelogic_map_buffer(dev, &reader->bldev->buffers[0]);
+       }
+       return -EINVAL;
+}
+
+/* Device file close handler */
+static int beaglelogic_f_release(struct inode *inode, struct file *filp)
+{
+       logic_buffer_reader *reader = filp->private_data;
+       struct beaglelogicdev *bldev = reader->bldev;
+       struct device *dev = bldev->miscdev.this_device;
+
+       /* Stop & Release */
+       beaglelogic_stop(dev);
+       devm_kfree(dev, reader);
+
+       return 0;
+}
+
+/* File operations struct */
+static const struct file_operations pru_beaglelogic_fops = {
+       .owner = THIS_MODULE,
+       .open = beaglelogic_f_open,
+       .unlocked_ioctl = beaglelogic_f_ioctl,
+       .read = beaglelogic_f_read,
+       .llseek = beaglelogic_f_llseek,
+       .mmap = beaglelogic_f_mmap,
+       .release = beaglelogic_f_release,
+};
+/* fops */
+
+/* begin sysfs attrs */
+static ssize_t bl_memalloc_show(struct device *dev,
+        struct device_attribute *attr, char *buf)
+{
+       struct beaglelogicdev *bldev = dev_get_drvdata(dev);
+
+       return scnprintf(buf, PAGE_SIZE, "%d\n",
+                       bldev->bufcount * bldev->bufunitsize);
+}
+
+static ssize_t bl_memalloc_store(struct device *dev,
+        struct device_attribute *attr, const char *buf, size_t count)
+{
+       struct beaglelogicdev *bldev = dev_get_drvdata(dev);
+       u32 val;
+       int ret;
+
+       if (kstrtouint(buf, 10, &val))
+               return -EINVAL;
+
+       /* Check value of memory to reserve */
+       if (val > bldev->maxbufcount * bldev->bufunitsize)
+               return -EINVAL;
+
+       /* Free buffers and reallocate */
+       beaglelogic_memfree(dev);
+       ret = beaglelogic_memalloc(dev, val);
+
+       if (!ret && val)
+               beaglelogic_map_and_submit_all_buffers(dev);
+
+       return count;
+}
+
+static ssize_t bl_samplerate_show(struct device *dev,
+               struct device_attribute *attr, char *buf)
+{
+       return scnprintf(buf, PAGE_SIZE, "%d\n",
+                       beaglelogic_get_samplerate(dev));
+}
+
+static ssize_t bl_samplerate_store(struct device *dev,
+               struct device_attribute *attr, const char *buf, size_t count)
+{
+       u32 val;
+
+       if (kstrtouint(buf, 10, &val))
+               return -EINVAL;
+
+       /* Check value of sample rate - 100 kHz to 100MHz */
+       if (beaglelogic_set_samplerate(dev, val))
+               return -EINVAL;
+
+       return count;
+}
+
+static ssize_t bl_sampleunit_show(struct device *dev,
+               struct device_attribute *attr, char *buf)
+{
+       u32 ret = beaglelogic_get_sampleunit(dev);
+       int cnt = scnprintf(buf, PAGE_SIZE, "%d:", ret);
+
+       switch (ret)
+       {
+               case 0:
+                       cnt += scnprintf(buf, PAGE_SIZE, "8bits,norle\n");
+                       break;
+
+               case 1:
+                       cnt += scnprintf(buf, PAGE_SIZE, "16bit,norle\n");
+                       break;
+       }
+       return cnt;
+}
+
+static ssize_t bl_sampleunit_store(struct device *dev,
+               struct device_attribute *attr, const char *buf, size_t count)
+{
+       int err;
+       u32 val;
+
+       if (kstrtouint(buf, 10, &val))
+               return -EINVAL;
+
+       /* Check value of sample unit - only 0 or 1 currently */
+       if ((err = beaglelogic_set_sampleunit(dev, val)))
+               return err;
+
+       return count;
+}
+
+static ssize_t bl_triggerflags_show(struct device *dev,
+               struct device_attribute *attr, char *buf)
+{
+       switch (beaglelogic_get_triggerflags(dev)) {
+               case BL_TRIGGERFLAGS_ONESHOT:
+                       return scnprintf(buf, PAGE_SIZE, "0:oneshot\n");
+
+               case BL_TRIGGERFLAGS_CONTINUOUS:
+                       return scnprintf(buf, PAGE_SIZE, "1:continuous\n");
+       }
+       return 0;
+}
+
+static ssize_t bl_triggerflags_store(struct device *dev,
+               struct device_attribute *attr, const char *buf, size_t count)
+{
+       u32 val;
+       int err;
+
+       if (kstrtouint(buf, 10, &val))
+               return -EINVAL;
+
+       if ((err = beaglelogic_set_triggerflags(dev, val)))
+               return err;
+
+       return count;
+}
+
+static ssize_t bl_state_show(struct device *dev,
+               struct device_attribute *attr, char *buf)
+{
+       struct beaglelogicdev *bldev = dev_get_drvdata(dev);
+       u32 state = bldev->state;
+       logic_buffer *buffer = bldev->bufbeingread;
+
+       if (state == STATE_BL_RUNNING) {
+               /* State blocks and returns last buffer read */
+               wait_event_interruptible(bldev->wait,
+                               buffer->state == STATE_BL_BUF_UNMAPPED);
+               return scnprintf(buf, PAGE_SIZE, "%d\n", buffer->index);
+       }
+
+       /* Identify non-buffer debug states with a -ve value */
+       return scnprintf(buf, PAGE_SIZE, "-%d\n", -bldev->state);
+}
+
+static ssize_t bl_state_store(struct device *dev,
+               struct device_attribute *attr, const char *buf, size_t count)
+{
+       u32 val;
+
+       if (kstrtouint(buf, 10, &val))
+               return -EINVAL;
+
+       /* State going to 1 starts the sampling operation, 0 aborts*/
+       if (val > 1)
+               return -EINVAL;
+
+       if (val == 1)
+               beaglelogic_start(dev);
+       else
+               beaglelogic_stop(dev);
+
+       return count;
+}
+
+static ssize_t bl_buffers_show(struct device *dev,
+               struct device_attribute *attr, char *buf)
+{
+       struct beaglelogicdev *bldev = dev_get_drvdata(dev);
+       int i, c, cnt;
+
+       for (i = 0, c = 0, cnt = 0; i < bldev->bufcount; i++) {
+               c = scnprintf(buf, PAGE_SIZE, "%08x,%u\n",
+                               (u32)bldev->buffers[i].phys_addr,
+                               bldev->buffers[i].size);
+               cnt += c;
+               buf += c;
+       }
+
+       return cnt;
+}
+
+static ssize_t bl_lasterror_show(struct device *dev,
+               struct device_attribute *attr, char *buf)
+{
+       struct beaglelogicdev *bldev = dev_get_drvdata(dev);
+
+       wait_event_interruptible(bldev->wait,
+                       bldev->state != STATE_BL_RUNNING);
+
+
+       return scnprintf(buf, PAGE_SIZE, "%d\n", bldev->lasterror);
+}
+
+static ssize_t bl_testpattern_store(struct device *dev,
+               struct device_attribute *attr, const char *buf, size_t count)
+{
+       u32 val;
+
+       if (kstrtouint(buf, 10, &val))
+               return -EINVAL;
+
+       /* Only if we get the magic number, trigger the test pattern */
+       if (val == 12345678)
+               beaglelogic_fill_buffer_testpattern(dev);
+
+       return count;
+}
+
+static DEVICE_ATTR(memalloc, S_IWUSR | S_IRUGO,
+               bl_memalloc_show, bl_memalloc_store);
+
+static DEVICE_ATTR(samplerate, S_IWUSR | S_IRUGO,
+               bl_samplerate_show, bl_samplerate_store);
+
+static DEVICE_ATTR(sampleunit, S_IWUSR | S_IRUGO,
+               bl_sampleunit_show, bl_sampleunit_store);
+
+static DEVICE_ATTR(triggerflags, S_IWUSR | S_IRUGO,
+               bl_triggerflags_show, bl_triggerflags_store);
+
+static DEVICE_ATTR(state, S_IWUSR | S_IRUGO,
+               bl_state_show, bl_state_store);
+
+static DEVICE_ATTR(buffers, S_IRUGO,
+               bl_buffers_show, NULL);
+
+static DEVICE_ATTR(lasterror, S_IRUGO,
+               bl_lasterror_show, NULL);
+
+static DEVICE_ATTR(filltestpattern, S_IWUSR,
+               NULL, bl_testpattern_store);
+
+static struct attribute *beaglelogic_attributes[] = {
+       &dev_attr_memalloc.attr,
+       &dev_attr_samplerate.attr,
+       &dev_attr_sampleunit.attr,
+       &dev_attr_triggerflags.attr,
+       &dev_attr_state.attr,
+       &dev_attr_buffers.attr,
+       &dev_attr_lasterror.attr,
+       &dev_attr_filltestpattern.attr,
+       NULL
+};
+
+static struct attribute_group beaglelogic_attr_group = {
+       .attrs = beaglelogic_attributes
+};
+/* end sysfs attrs */
+
+static int beaglelogic_probe(struct platform_device *pdev)
+{
+       struct device_node *node = pdev->dev.of_node;
+       int err, ret;
+       struct beaglelogicdev *bldev;
+       struct device *dev;
+       u32 val;
+
+       printk("BeagleLogic loaded and initializing\n");
+
+       /* Allocate memory for our private structure */
+       bldev = kzalloc(sizeof(*bldev), GFP_KERNEL);
+       if (!bldev)
+               goto fail;
+
+       bldev->miscdev.fops = &pru_beaglelogic_fops;
+       bldev->miscdev.minor = MISC_DYNAMIC_MINOR;
+       bldev->miscdev.mode = S_IRUGO;
+       bldev->miscdev.name = "beaglelogic";
+
+       /* Export the IRQ handler */
+       bldev->serve_irq = beaglelogic_serve_irq;
+
+       /* Link the platform device data to our private structure */
+       bldev->p_dev = &pdev->dev;
+       dev_set_drvdata(bldev->p_dev, bldev);
+
+       /* Bind to the pru_rproc module */
+       err = pruproc_beaglelogic_request_bind((void *)bldev);
+       if (err)
+               goto fail;
+
+       /* Once done, register our misc device and link our private data */
+       err = misc_register(&bldev->miscdev);
+       if (err)
+               goto fail;
+       dev = bldev->miscdev.this_device;
+       dev_set_drvdata(dev, bldev);
+
+       /* Set up locks */
+       mutex_init(&bldev->mutex);
+       init_waitqueue_head(&bldev->wait);
+
+       /* Power on in disabled state */
+       bldev->state = STATE_BL_DISABLED;
+
+       /* Get firmware properties */
+       ret = bldev->downcall_idx(0, BL_DC_GET_VERSION, 0, 0, 0, 0, 0);
+       if (ret != 0) {
+               dev_info(dev, "BeagleLogic PRU Firmware version: %d.%d\n",
+                               ret >> 8, ret & 0xFF);
+       } else {
+               dev_err(dev, "Firmware error!\n");
+               goto faildereg;
+       }
+
+       ret = bldev->downcall_idx(0, BL_DC_GET_MAX_SG, 0, 0, 0, 0, 0);
+       if (ret > 0 && ret < 256) { /* Let's be reasonable here */
+               dev_info(dev, "Device supports max %d vector transfers\n", ret);
+               bldev->maxbufcount = ret;
+       } else {
+               dev_err(dev, "Firmware error!\n");
+               goto faildereg;
+       }
+
+       ret = bldev->downcall_idx(0, BL_DC_GET_CXT_PTR, 0, 0, 0, 0, 0);
+       bldev->cxt_pru = bldev->d_da_to_va(0, ret);
+
+       if (!bldev->cxt_pru) {
+               dev_err(dev, "BeagleLogic: Unable to access PRU SRAM.\n");
+               goto faildereg;
+       }
+
+       /* To be removed in the next iteration */
+       if (bldev->cxt_pru->magic == BL_FW_MAGIC)
+               dev_info(dev, "Valid PRU capture context structure "\
+                               "found at offset %04X\n", ret);
+       else {
+               dev_err(dev, "Firmware error!\n");
+               goto faildereg;
+       }
+
+
+       /* Apply default configuration first */
+       bldev->samplerate = 100 * 1000 * 1000;
+       bldev->sampleunit = 1;
+       bldev->bufunitsize = 4 * 1024 * 1024;
+       bldev->triggerflags = 0;
+
+       /* Override defaults with the device tree */
+       if (!of_property_read_u32(node, "samplerate", &val))
+               if (beaglelogic_set_samplerate(dev, val))
+                       dev_warn(dev, "Invalid default samplerate\n");
+
+       if (!of_property_read_u32(node, "sampleunit", &val))
+               if (beaglelogic_set_sampleunit(dev, val))
+                       dev_warn(dev, "Invalid default sampleunit\n");
+
+       if (!of_property_read_u32(node, "triggerflags", &val))
+               if (beaglelogic_set_triggerflags(dev, val))
+                       dev_warn(dev, "Invalid default triggerflags\n");
+
+       if (bufunitsize < 2 * 1024 * 1024)
+               dev_warn(dev, "WARNING:Buffer unit sizes less than "\
+                               "2 MB are not recommended. Using 4 MB");
+       else
+               bldev->bufunitsize = bufunitsize;
+
+       /* We got configuration from PRUs, now mark device init'd */
+       bldev->state = STATE_BL_INITIALIZED;
+
+       /* Display our init'ed state */
+       dev_info(dev, "Default sample rate=%d Hz, sampleunit=%d, "\
+                       "triggerflags=%d. Buffer in units of %d bytes each",
+                       bldev->samplerate,
+                       bldev->sampleunit,
+                       bldev->triggerflags,
+                       bldev->bufunitsize);
+
+       /* Once done, create device files */
+       err = sysfs_create_group(&dev->kobj, &beaglelogic_attr_group);
+       if (err) {
+               dev_err(dev, "Registration failed.\n");
+               goto faildereg;
+       }
+
+       return 0;
+faildereg:
+       misc_deregister(&bldev->miscdev);
+       kfree(bldev);
+fail:
+       return -1;
+}
+
+static int beaglelogic_remove(struct platform_device *pdev)
+{
+       struct beaglelogicdev *bldev = platform_get_drvdata(pdev);
+       struct device *dev = bldev->miscdev.this_device;
+
+       /* Unregister ourselves from the pru_rproc module */
+       pruproc_beaglelogic_request_unbind();
+
+       /* Free all buffers */
+       beaglelogic_memfree(dev);
+
+       /* Remove the sysfs attributes */
+       sysfs_remove_group(&dev->kobj, &beaglelogic_attr_group);
+
+       /* Deregister the misc device */
+       misc_deregister(&bldev->miscdev);
+
+       /* Free up memory */
+       kfree(bldev);
+
+       /* Print a log message to announce unloading */
+       printk("BeagleLogic unloaded\n");
+       return 0;
+}
+
+static const struct of_device_id beaglelogic_dt_ids[] = {
+       { .compatible = "beaglelogic,beaglelogic", .data = NULL, },
+       { /* sentinel */ },
+};
+
+static struct platform_driver beaglelogic_driver = {
+       .driver = {
+               .name = DRV_NAME,
+               .owner = THIS_MODULE,
+               .of_match_table = beaglelogic_dt_ids,
+       },
+       .probe = beaglelogic_probe,
+       .remove = beaglelogic_remove,
+};
+
+module_platform_driver(beaglelogic_driver);
+
+MODULE_AUTHOR("Kumar Abhishek <abhis...@theembeddedkitchen.net>");
+MODULE_DESCRIPTION("Kernel Driver for BeagleLogic");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(DRV_VERSION);
diff --git a/drivers/remoteproc/beaglelogic.h b/drivers/remoteproc/beaglelogic.h
new file mode 100644
index 0000000..3b7313a
--- /dev/null
+++ b/drivers/remoteproc/beaglelogic.h
@@ -0,0 +1,62 @@
+/*
+ * Userspace/Kernelspace common API for BeagleLogic
+ * ioctl commands and enumeration of states
+ *
+ * Copyright (C) 2014 Kumar Abhishek <abhis...@theembeddedkitchen.net>
+ *
+ * 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.
+ */
+
+#ifndef BEAGLELOGIC_H_
+#define BEAGLELOGIC_H_
+
+enum beaglelogic_states {
+       STATE_BL_DISABLED,      /* Powered off (at module start) */
+       STATE_BL_INITIALIZED,   /* Powered on */
+       STATE_BL_MEMALLOCD,     /* Buffers allocated */
+       STATE_BL_ARMED,         /* All Buffers DMA-mapped and configuration 
done */
+       STATE_BL_RUNNING,       /* Data being captured */
+       STATE_BL_REQUEST_STOP,  /* Stop requested */
+       STATE_BL_ERROR          /* Buffer overrun */
+};
+
+enum beaglelogic_triggerflags {
+       BL_TRIGGERFLAGS_ONESHOT = 0,
+       BL_TRIGGERFLAGS_CONTINUOUS
+};
+
+enum beaglelogic_sampleunit {
+       BL_SAMPLEUNIT_16_BITS = 0,
+       BL_SAMPLEUNIT_8_BITS
+};
+
+/* ioctl calls that can be issued on /dev/beaglelogic */
+
+#define IOCTL_BL_GET_VERSION        _IOR('k', 0x20, u32)
+
+#define IOCTL_BL_GET_SAMPLE_RATE    _IOR('k', 0x21, u32)
+#define IOCTL_BL_SET_SAMPLE_RATE    _IOW('k', 0x21, u32)
+
+#define IOCTL_BL_GET_SAMPLE_UNIT    _IOR('k', 0x22, u32)
+#define IOCTL_BL_SET_SAMPLE_UNIT    _IOW('k', 0x22, u32)
+
+#define IOCTL_BL_GET_TRIGGER_FLAGS  _IOR('k', 0x23, u32)
+#define IOCTL_BL_SET_TRIGGER_FLAGS  _IOW('k', 0x23, u32)
+
+#define IOCTL_BL_GET_CUR_INDEX      _IOR('k', 0x24, u32)
+#define IOCTL_BL_CACHE_INVALIDATE    _IO('k', 0x25)
+
+#define IOCTL_BL_GET_BUFFER_SIZE    _IOR('k', 0x26, u32)
+#define IOCTL_BL_SET_BUFFER_SIZE    _IOW('k', 0x26, u32)
+
+#define IOCTL_BL_GET_BUFUNIT_SIZE   _IOR('k', 0x27, u32)
+
+#define IOCTL_BL_FILL_TEST_PATTERN   _IO('k', 0x28)
+
+#define IOCTL_BL_START               _IO('k', 0x29)
+#define IOCTL_BL_STOP                _IO('k', 0x2A)
+
+#endif /* BEAGLELOGIC_H_ */
-- 
1.9.1

-- 
For more options, visit http://beagleboard.org/discuss
--- 
You received this message because you are subscribed to the Google Groups 
"BeagleBoard" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to beagleboard+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Reply via email to