[PATCH 0/3] Patches to include BeagleLogic support in the kernel

378 views
Skip to first unread message

Kumar Abhishek

unread,
Jun 22, 2014, 11:09:56 PM6/22/14
to beagl...@googlegroups.com
From: Kumar Abhishek <abhi...@theembeddedkitchen.net>

These patches add support for BeagleLogic in the kernel.
BeagleLogic is a logic analyzer realized on the BeagleBone Black using the
programmable real-time units. For more information, visit:
https://github.com/abhishek-kakkar/BeagleLogic/wiki/
http://elinux.org/BeagleBoard/GSoC/2014_Projects#Project:_BeagleLogic

CONFIG_PRU_RPROC_BEAGLELOGIC may be set to "m" or "y" accordingly to enable
BeagleLogic support in the built kernel. BeagleLogic may also be compiled as
an out-of tree module but is still included in the sources.

Please apply this after Matt Ranostay's patch to update pru_rproc.c for
supporting the PRU C Compiler version 2.0.0B [ref: http://git.io/uCfGKQ]

Download the matching PRU firmware beaglelogic-firmware.tar.gz for running
BeagleLogic from http://goo.gl/770FTZ and extract into /lib/firmware on your BBB

Kumar Abhishek (3):
Add DTS for BeagleLogic
Add BeagleLogic binding functions to pru_rproc
Add kernel module for BeagleLogic

drivers/remoteproc/Kconfig | 13 +
drivers/remoteproc/Makefile | 1 +
drivers/remoteproc/beaglelogic.c | 1189 ++++++++++++++++++++++++++++++++
drivers/remoteproc/beaglelogic.h | 62 ++
drivers/remoteproc/beaglelogic_glue.h | 43 ++
drivers/remoteproc/pru_rproc.c | 92 +++
firmware/Makefile | 1 +
firmware/capes/BB-BEAGLELOGIC-00A0.dts | 257 +++++++
8 files changed, 1658 insertions(+)
create mode 100644 drivers/remoteproc/beaglelogic.c
create mode 100644 drivers/remoteproc/beaglelogic.h
create mode 100644 drivers/remoteproc/beaglelogic_glue.h
create mode 100644 firmware/capes/BB-BEAGLELOGIC-00A0.dts

--
1.9.1

Kumar Abhishek

unread,
Jun 22, 2014, 11:09:57 PM6/22/14
to beagl...@googlegroups.com
From: Kumar Abhishek <abhi...@theembeddedkitchen.net>

Signed-off-by: Kumar Abhishek <abhi...@theembeddedkitchen.net>
---
firmware/Makefile | 1 +
firmware/capes/BB-BEAGLELOGIC-00A0.dts | 257 +++++++++++++++++++++++++++++++++
2 files changed, 258 insertions(+)
create mode 100644 firmware/capes/BB-BEAGLELOGIC-00A0.dts

diff --git a/firmware/Makefile b/firmware/Makefile
index 80e03ac..8c070c7 100644
--- a/firmware/Makefile
+++ b/firmware/Makefile
@@ -183,6 +183,7 @@ fw-shipped-$(CONFIG_CAPE_BEAGLEBONE) += \
bone_pwm_P9_31-00A0.dtbo \
bone_pwm_P9_42-00A0.dtbo \
BB-BONE-PWMT-00A0.dtbo \
+ BB-BEAGLELOGIC-00A0.dtbo \
BB-BONE-PRU-01-00A0.dtbo \
BB-BONE-PRU-02-00A0.dtbo \
BB-BONE-PRU-03-00A0.dtbo \
diff --git a/firmware/capes/BB-BEAGLELOGIC-00A0.dts b/firmware/capes/BB-BEAGLELOGIC-00A0.dts
new file mode 100644
index 0000000..089130b
--- /dev/null
+++ b/firmware/capes/BB-BEAGLELOGIC-00A0.dts
@@ -0,0 +1,257 @@
+/*
+ * This file is a part of the BeagleLogic Project
+ * Copyright (C) 2014 Kumar Abhishek
+ *
+ * Derived from the original works of Matt Ranostay and Pantelis Antoniou
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+/dts-v1/;
+/plugin/;
+
+/ {
+ compatible = "ti,beaglebone", "ti,beaglebone-black", "beaglelogic,beaglelogic";
+
+ /* Identification */
+ part-number = "bb-beaglelogic";
+ version = "00A0";
+
+ /* Resources for exclusive reservation */
+ exclusive-use =
+ // "P8.20", /* pru1: pr1_pru1_pru_r31_13 */
+ // "P8.21", /* pru1: pr1_pru1_pru_r31_12 */
+ "P8.27", /* pru1: pr1_pru1_pru_r31_8 */
+ "P8.28", /* pru1: pr1_pru1_pru_r31_10 */
+ "P8.29", /* pru1: pr1_pru1_pru_r31_9 */
+ "P8.30", /* pru1: pr1_pru1_pru_r31_11 */
+ "P8.39", /* pru1: pr1_pru1_pru_r31_6 */
+ "P8.40", /* pru1: pr1_pru1_pru_r31_7 */
+ "P8.41", /* pru1: pr1_pru1_pru_r31_4 */
+ "P8.42", /* pru1: pr1_pru1_pru_r31_5 */
+ "P8.43", /* pru1: pr1_pru1_pru_r31_2 */
+ "P8.44", /* pru1: pr1_pru1_pru_r31_3 */
+ "P8.45", /* pru1: pr1_pru1_pru_r31_0 */
+ "P8.46", /* pru1: pr1_pru1_pru_r31_1 */
+
+ /* The PRUs */
+ "pru0",
+ "pru1";
+
+ /* Pinmux Values */
+ fragment@0 {
+ target = <&am33xx_pinmux>;
+ __overlay__ {
+
+ pru_gpio_pins: pinmux_pru_gpio_pins {
+ pinctrl-single,pins = < >;
+ };
+
+ pru_pru_pins: pinmux_pru_pru_pins {
+ pinctrl-single,pins = <
+ // 0x084 0x2e /* gpmc_csn2.pr1_pru1_pru_r30_13, MODE6 | INPUT | PRU */
+ // 0x080 0x2e /* gpmc_csn1.pr1_pru1_pru_r30_12, MODE6 | INPUT | PRU */
+ 0x0ec 0x2e /* lcd_ac_bias_en.pr1_pru1_r31_11, MODE6 | INPUT | PRU */
+ 0x0e8 0x2e /* lcd_pclk.pr1_pru1_pru_r31_10, MODE6 | INPUT | PRU */
+ 0x0e0 0x2e /* lcd_vsync.pr1_pru1_pru_r31_8, MODE6 | INPUT | PRU */
+ 0x0e4 0x2e /* lcd_hsync.pr1_pru1_pru_r31_9, MODE6 | INPUT | PRU */
+ 0x0b8 0x2e /* lcd_data6.pr1_pru1_pru_r31_6, MODE6 | INPUT | PRU */
+ 0x0bc 0x2e /* lcd_data7.pr1_pru1_pru_r31_7, MODE6 | INPUT | PRU */
+ 0x0b0 0x2e /* lcd_data4.pr1_pru1_pru_r31_4, MODE6 | INPUT | PRU */
+ 0x0b4 0x2e /* lcd_data5.pr1_pru1_pru_r31_5, MODE6 | INPUT | PRU */
+ 0x0a8 0x2e /* lcd_data2.pr1_pru1_pru_r31_2, MODE6 | INPUT | PRU */
+ 0x0ac 0x2e /* lcd_data3.pr1_pru1_pru_r31_3, MODE6 | INPUT | PRU */
+ 0x0a0 0x2e /* lcd_data0.pr1_pru1_pru_r31_0, MODE6 | INPUT | PRU */
+ 0x0a4 0x2e /* lcd_data1.pr1_pru1_pru_r31_1, MODE6 | INPUT | PRU */
+ >;
+ };
+ };
+ };
+
+ /* PRU Configuration */
+ fragment@1 {
+ target = <&ocp>;
+
+ __overlay__ {
+
+ /* avoid stupid warning */
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ prurproc {
+ compatible = "ti,pru-rproc";
+
+ pinctrl-names = "default";
+ pinctrl-0 = <&pru_pru_pins>;
+
+ reg = <0x4a300000 0x080000>;
+
+ status = "okay";
+
+ ti,hwmods = "pruss";
+ ti,deassert-hard-reset = "pruss", "pruss";
+ interrupt-parent = <&intc>;
+
+ /* interrupts on the host */
+ interrupts = <20 21 22 23 24 25 26 27>;
+
+ /* events these interrupts map to (host interrupt) */
+ events = <2 3 4 5 6 7 8 9>;
+
+ /* PRU interrupt controller offset */
+ pintc = <0x20000>;
+
+ /* 12K Shared Data RAM global, size, local */
+ pdram = <0x10000 0x03000 0x10000>;
+
+ /*
+ * SYSEVENT ids
+ *
+ * - PRU/ARM communication
+ * PRU0_PRU1 17
+ * PRU1_PRU0 18
+ * PRU0_ARM 19
+ * PRU1_ARM 20
+ * ARM_PRU0 21
+ * ARM_PRU1 22
+ *
+ * Full SYSEVENT list
+ *
+ * parity_err_intr_pend 0
+ * pru0_r31_status_cnt16 1
+ * pru1_r31_status_cnt16 2
+ * uart_urxevt_intr_req 4
+ * uart_utxevt_intr_req 5
+ * uart_uint_intr_req 6
+ * iep_tim_cap_cmp_pend 7
+ * ecap_intr_req 15
+ * pru_mst_intr[0-15]_intr_req 16-31
+ * nirq 32 (UART1)
+ * mcasp_x_intr_pend 33 (MCASP1)
+ * mcasp_r_intr_pend 34 (MCASP1)
+ * ecap_intr_intr_pend 35 (ECAP1)
+ * ecap_intr_intr_pend 36 (ECAP2)
+ * epwm_intr_intr_pend 37 (eHRPWM2)
+ * dcan_uerr 38 (DCAN0)
+ * dcan_int1 39 (DCAN0)
+ * dcan_intr 40 (DCAN0)
+ * POINTRPEND 41 (I2C0)
+ * ecap_intr_intr_pend 42 (ECAP0)
+ * epwm_intr_intr_pend 43 (eHRPWM0)
+ * SINTERRUPTN 44 (McSPI0)
+ * eqep_intr_intr_pend 45 (eQEP0)
+ * epwm_intr_intr_pend 46 (eHRPWM1)
+ * c0_misc_pend 47 3PGSW (GEMAC)
+ * c0_tx_pend 48 3PGSW (GEMAC)
+ * c0_rx_pend 49 3PGSW (GEMAC)
+ * c0_rx_thresh_pend 50 3PGSW (GEMAC)
+ * nirq 51 (UART0)
+ * nirq 52 (UART2)
+ * gen_intr_pend 53 (ADC_TSC)
+ * mcasp_r_intr_pend 54 (McASP0)
+ * mcasp_x_intr_pend 55 (McASP1)
+ * pwm_trip_zone 56 (eHRPWM0/eHRPWM1/eHRP WM2)
+ * POINTRPEND1 57 (GPIO0)
+ * Emulation Suspend Signal 58 (Debugss)
+ * initiator_sinterrupt_q_n2 59 (Mbox0 - mail_u2_irq (mailbox interrupt for pru1))
+ * initiator_sinterrupt_q_n1 60 (Mbox0 - mail_u1_irq (mailbox interrupt for pru0))
+ * tptc_erint_pend_po 61 (TPTC0 (EDMA))
+ * tpcc_errint_pend_po 62 (TPCC (EDMA))
+ * tpcc_int_pend_po1 63 (TPCC (EDMA))
+ *
+ * HOST interrupt ids
+ *
+ * PRU0 0
+ * PRU1 1
+ * EVTOUT0-7 2-9
+ */
+
+ /* sysevent map to intc channel */
+ sysevent-to-channel-map =
+ <17 1>, /* PRU0_PRU1 -> CH1 */
+ <18 0>, /* PRU1_PRU0 -> CH0 */
+ <19 2>, /* PRU0_ARM -> CH2 */
+ <20 3>, /* PRU1_ARM -> CH3 */
+ <21 0>, /* ARM_PRU0 -> CH0 */
+ <22 1>, /* ARM_PRU1 -> CH1 */
+ <24 4>, /* VRING Host->PRU0 -> CH4 */
+ <25 5>, /* VRING PRU0->Host -> CH5 */
+ <26 6>, /* VRING Host->PRU1 -> CH6 */
+ <27 7>; /* VRING PRU1->Host -> CH7 */
+
+ /* channel to host interrupt map */
+ channel-to-host-interrupt-map =
+ <0 0>, /* CH0 -> PRU0 */
+ <1 1>, /* CH1 -> PRU1 */
+ <2 2>, /* CH2 -> EVTOUT0 */
+ <3 3>, /* CH3 -> EVTOUT1 */
+ <4 0>, /* CH4 -> PRU0 */
+ <5 6>, /* CH5 -> EVTOUT4 */
+ <6 1>, /* CH6 -> PRU1 */
+ <7 7>; /* CH7 -> EVTOUT5 */
+
+ /* indices are ARM=0, PRU0=1, PRU1=2 */
+ target-to-sysevent-map =
+ <0xffffffff 21 22>, /* ARM: DONTCARE, ARM_PRU0, ARM_PRU1 */
+ < 19 0xffffffff 17>, /* PRU0: PRU0_ARM, DONTCARE, PRU0_PRU1 */
+ < 20 18 0xffffffff>; /* PRU1: PRU1_ARM, PRU1_PRU0, DONTCARE */
+
+ /* both the PRUs have 200MHz frequency so period is 5ns */
+ clock-freq = <200000000>;
+
+ /* Enable BeagleLogic extensions to the rproc driver */
+ pru-beaglelogic-enabled;
+
+ /* Add default settings for the LA core */
+ pru-beaglelogic {
+ compatible = "beaglelogic,beaglelogic";
+ samplerate = <50000000>; /* 100MHz, 50MHz, 40MHz, 25MHz, 20MHz, 10MHz, 5MHz, 1MHz : (200 / int n) MHz */
+ sampleunit = <1>; /* Sample byte count: 1 or 2 bytes */
+ triggerflags = <0>; /* RFU for further firmware revisions */
+ };
+
+ /* PRU0 - psuedo-DMA controller */
+ pru0 {
+ pru-index = <0>;
+
+ /* offset, size, local */
+ iram = <0x34000 0x02000 0x00000>; /* code ram (8K) */
+
+ /* offset, size, local, other */
+ dram = <0x00000 0x02000 0x00000 0x10000>; /* data ram (8K) */
+
+ pctrl = <0x22000>;
+ pdbg = <0x22400>;
+
+ /* sysevents signaling ring activity (host, pru)*/
+ vring-sysev = <24 25>;
+
+ firmware-elf;
+ firmware = "beaglelogic-pru0";
+ };
+
+ /* PRU1 - data capture */
+ pru1 {
+ pru-index = <1>;
+
+ /* offset, size, local */
+ iram = <0x38000 0x02000 0x00000>; /* code ram (8K) */
+
+ /* offset, size, local, other */
+ dram = <0x02000 0x02000 0x00000 0x10000>; /* data ram (8K) */
+
+ pctrl = <0x24000>;
+ pdbg = <0x24400>;
+
+ /* sysevents signaling ring activity (host, pru)*/
+ vring-sysev = <26 27>;
+
+ firmware-elf;
+ firmware = "beaglelogic-pru1";
+ };
+ };
+ };
+ };
+};
--
1.9.1

Kumar Abhishek

unread,
Jun 22, 2014, 11:10:00 PM6/22/14
to beagl...@googlegroups.com
From: Kumar Abhishek <abhi...@theembeddedkitchen.net>

BeagleLogic is implemented as a separate kernel module that
binds and unbinds itself from pru_rproc at runtime.

Signed-off-by: Kumar Abhishek <abhi...@theembeddedkitchen.net>
---
drivers/remoteproc/beaglelogic_glue.h | 43 ++++++++++++++++
drivers/remoteproc/pru_rproc.c | 92 +++++++++++++++++++++++++++++++++++
2 files changed, 135 insertions(+)
create mode 100644 drivers/remoteproc/beaglelogic_glue.h

diff --git a/drivers/remoteproc/beaglelogic_glue.h b/drivers/remoteproc/beaglelogic_glue.h
new file mode 100644
index 0000000..ede6370
--- /dev/null
+++ b/drivers/remoteproc/beaglelogic_glue.h
@@ -0,0 +1,43 @@
+/*
+ * Include file for the BeagleLogic kernel module [glue code for pru_rproc
+ *
+ * Copyright (C) 2014 Kumar Abhishek <abhi...@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_GLUE_H_
+#define BEAGLELOGIC_GLUE_H_
+
+/* IRQ requests handled by pru_rproc are rerouted to beaglelogic
+ * after a rename.
+ *
+ * Currently only two interrupts, buffer ready and cleanup after stop */
+#define BL_IRQ_BUFREADY 0
+#define BL_IRQ_CLEANUP 1
+
+struct beaglelogic_glue {
+ /* 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;
+};
+
+/* Bind and unbind requests */
+extern int pruproc_beaglelogic_request_bind(struct beaglelogic_glue *g);
+extern void pruproc_beaglelogic_request_unbind(void);
+
+#endif /* BEAGLELOGIC_KERNEL_H_ */
diff --git a/drivers/remoteproc/pru_rproc.c b/drivers/remoteproc/pru_rproc.c
index 7b7280d..ff8e541 100644
--- a/drivers/remoteproc/pru_rproc.c
+++ b/drivers/remoteproc/pru_rproc.c
@@ -34,6 +34,8 @@

#include "remoteproc_internal.h"

+#include "beaglelogic_glue.h"
+
/* PRU_EVTOUT0 is halt (system call) */

/* maximum PRUs */
@@ -189,8 +191,13 @@ struct pruproc {
int controller;
u32 dc_ids[DC_PWM_MAX];
} pwm;
+
+ struct beaglelogic_glue *beaglelogic;
};

+/* For the BeagleLogic bindings */
+static struct pruproc *pp_bl;
+
/* global memory map (for am33xx) (almost the same as local) */
#define PRU_DATA_RAM0 0x00000
#define PRU_DATA_RAM1 0x02000
@@ -1794,6 +1801,11 @@ static irqreturn_t pru_handler(int irq, void *data)

handled = 0;

+ /* Handle BeagleLogic interrupts (same as vrings)
+ * This takes precedence when BeagleLogic is enabled and bound */
+ if (pst->vring == 1 && pp->beaglelogic)
+ return pp->beaglelogic->serve_irq(pru_idx, pp->beaglelogic);
+
/* we either handle a vring or not */
if (!pst->vring) {
ret = pru_handle_syscall(ppc);
@@ -2346,6 +2358,83 @@ static int pruproc_create_devices(struct pruproc *pp)
return ret;
}

+/* BeagleLogic plugin code section */
+
+/* Downcall wrapper */
+static int beaglelogic_pru_downcall(int pru_no, u32 nr, u32 arg0, u32 arg1,
+ u32 arg2, u32 arg3, u32 arg4)
+{
+ return pru_downcall_idx(pp_bl, pru_no, nr, arg0,
+ arg1, arg2, arg3, arg4);
+}
+
+/* Request VA to remapped PRU memory area */
+static void * __iomem beaglelogic_pru_d_da_to_va(int idx, u32 daddr)
+{
+ return pru_d_da_to_va(pp_bl->pru_to_pruc[idx], daddr, NULL);
+}
+
+/* Post-configuration, resume the PRU [reserved for a future FWrev] */
+static int beaglelogic_pru_start(int idx)
+{
+ /* u32 addr; */
+
+ /* TODO Attempt to start halted PRU, skip over HALT */
+ /*
+ if (pru_is_halted(pp_bl->pru_to_pruc[idx], &addr)) {
+ return -1;
+ }
+ pru_resume(pp_bl->pru_to_pruc[idx], addr + 4);
+ */
+ return 0;
+}
+
+/* Signal the PRU Firmware to abort after the next buffer */
+static void beaglelogic_pru_request_stop(void)
+{
+ /* ARM -> PRU1 interrupt */
+ u32 sysint = pp_bl->target_to_sysev[TARGET_ARM_TO_PRU_IDX(1)];
+
+ /* Raise interrupt */
+ if (sysint < 32)
+ pintc_write_reg(pp_bl, PINTC_SRSR0, 1 << sysint);
+ else
+ pintc_write_reg(pp_bl, PINTC_SRSR1, 1 << (sysint - 32));
+}
+
+/* The BeagleLogic module requests attach to the remoteproc module here */
+int pruproc_beaglelogic_request_bind(struct beaglelogic_glue *g)
+{
+ if (pp_bl == NULL)
+ return -1;
+
+ /* Export the fp's to BeagleLogic functions located in this module */
+ g->downcall_idx = beaglelogic_pru_downcall;
+ g->d_da_to_va = beaglelogic_pru_d_da_to_va;
+ g->pru_request_stop = beaglelogic_pru_request_stop;
+ g->pru_start = beaglelogic_pru_start;
+
+ g->coreclockfreq = pp_bl->clock_freq;
+
+ pp_bl->beaglelogic = g;
+
+ return 0;
+}
+EXPORT_SYMBOL(pruproc_beaglelogic_request_bind);
+
+void pruproc_beaglelogic_request_unbind(void)
+{
+ /* Invalidate our handle to the module exported functions */
+ pp_bl->beaglelogic = NULL;
+}
+EXPORT_SYMBOL(pruproc_beaglelogic_request_unbind);
+
+static void pruproc_beaglelogic_init_bindings(struct pruproc *pp)
+{
+ pp_bl = pp;
+}
+/* End BeagleLogic Section */
+
static int pruproc_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
@@ -2787,6 +2876,9 @@ static int pruproc_probe(struct platform_device *pdev)
/* creating devices */
pruproc_create_devices(pp);

+ /* init the BeagleLogic binding section */
+ pruproc_beaglelogic_init_bindings(pp);
+
(void)pru_d_read_u32;
(void)pru_i_write_u32;
(void)pru_d_write_u32;
--
1.9.1

Kumar Abhishek

unread,
Jun 22, 2014, 11:10:02 PM6/22/14
to beagl...@googlegroups.com
From: Kumar Abhishek <abhi...@theembeddedkitchen.net>

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

Signed-off-by: Kumar Abhishek <abhi...@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 <abhi...@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 <abhi...@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 <abhi...@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

Robert Nelson

unread,
Jun 24, 2014, 12:46:31 PM6/24/14
to Beagle Board
On Sun, Jun 22, 2014 at 10:09 PM, Kumar Abhishek
<kumar.abhi...@gmail.com> wrote:
> From: Kumar Abhishek <abhi...@theembeddedkitchen.net>
>
> These patches add support for BeagleLogic in the kernel.
> BeagleLogic is a logic analyzer realized on the BeagleBone Black using the
> programmable real-time units. For more information, visit:
> https://github.com/abhishek-kakkar/BeagleLogic/wiki/
> http://elinux.org/BeagleBoard/GSoC/2014_Projects#Project:_BeagleLogic
>
> CONFIG_PRU_RPROC_BEAGLELOGIC may be set to "m" or "y" accordingly to enable
> BeagleLogic support in the built kernel. BeagleLogic may also be compiled as
> an out-of tree module but is still included in the sources.
>
> Please apply this after Matt Ranostay's patch to update pru_rproc.c for
> supporting the PRU C Compiler version 2.0.0B [ref: http://git.io/uCfGKQ]
>
> Download the matching PRU firmware beaglelogic-firmware.tar.gz for running
> BeagleLogic from http://goo.gl/770FTZ and extract into /lib/firmware on your BBB

Hi Kumar,

Ran into one small issue when merging this as-is into the BeagleBone tree:

In file included from drivers/remoteproc/pru_rproc.c:37:0:
drivers/remoteproc/beaglelogic_glue.h:24:20: error: field ‘miscdev’
has incomplete type
scripts/Makefile.build:307: recipe for target
'drivers/remoteproc/pru_rproc.o' failed
make[2]: *** [drivers/remoteproc/pru_rproc.o] Error 1
scripts/Makefile.build:454: recipe for target 'drivers/remoteproc' failed
make[1]: *** [drivers/remoteproc] Error 2
make[1]: *** Waiting for unfinished jobs....

https://github.com/RobertCNelson/bb-kernel/commit/956c41426010a1a110b91dab7b39f31d45741643

Regards,

--
Robert Nelson
http://www.rcn-ee.com/

Kumar Abhishek

unread,
Jun 24, 2014, 1:36:38 PM6/24/14
to beagl...@googlegroups.com
Yep, I came to realize of this after I had already sent the patch on the list. The fix is to just add #include <linux/miscdevice.h> into the pru_rproc.c file at line 70 [This was not required for the file in Koen's tree as it had some code from the lighting the example].

Let me send you a patch shortly

Regards

Kumar Abhishek
Undergraduate Student
Department of Electronics and Electrical Communications Engineering
Indian Institute of Technology, Kharagpur


--
For more options, visit http://beagleboard.org/discuss
---
You received this message because you are subscribed to a topic in the Google Groups "BeagleBoard" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/beagleboard/ui8-no8J6HY/unsubscribe.
To unsubscribe from this group and all its topics, send an email to beagleboard...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Kumar Abhishek

unread,
Jun 24, 2014, 2:02:29 PM6/24/14
to beagl...@googlegroups.com
From: Kumar Abhishek <abhi...@theembeddedkitchen.net>

Signed-off-by: Kumar Abhishek <abhi...@theembeddedkitchen.net>
---
drivers/remoteproc/pru_rproc.c | 1 +
1 file changed, 1 insertion(+)

diff --git a/drivers/remoteproc/pru_rproc.c b/drivers/remoteproc/pru_rproc.c
index ff8e541..402f2ef 100644
--- a/drivers/remoteproc/pru_rproc.c
+++ b/drivers/remoteproc/pru_rproc.c
@@ -34,6 +34,7 @@

#include "remoteproc_internal.h"

+#include <linux/miscdevice.h>
#include "beaglelogic_glue.h"

/* PRU_EVTOUT0 is halt (system call) */
--
1.9.1

Robert Nelson

unread,
Jun 24, 2014, 2:43:39 PM6/24/14
to Beagle Board

Kumar Abhishek

unread,
Jun 24, 2014, 3:56:39 PM6/24/14
to beagl...@googlegroups.com
Hi,

I would recommend setting CONFIG_PRU_RPROC_BEAGLELOGIC to "m" so that it could help in debugging.

Also, could you please include the firmware files beaglelogic-pru0 and beaglelogic-pru1 into your tree from this link: http://goo.gl/770FTZ
Otherwise probing the driver will fail (and being compiled in there would be no way to retrigger the probe)

Regards

Kumar Abhishek
Undergraduate Student
Department of Electronics and Electrical Communications Engineering
Indian Institute of Technology, Kharagpur


Robert Nelson

unread,
Jun 24, 2014, 4:26:40 PM6/24/14
to Beagle Board
On Tue, Jun 24, 2014 at 2:56 PM, Kumar Abhishek
<kumar.abhi...@gmail.com> wrote:
> Hi,
>
> I would recommend setting CONFIG_PRU_RPROC_BEAGLELOGIC to "m" so that it
> could help in debugging.

Sure, not a problem.

https://github.com/RobertCNelson/bb-kernel/commit/5a78b87629d205e14d08b4f91f1703cfc7297198

> Also, could you please include the firmware files beaglelogic-pru0 and
> beaglelogic-pru1 into your tree from this link: http://goo.gl/770FTZ
> Otherwise probing the driver will fail (and being compiled in there would be
> no way to retrigger the probe)


After:

https://github.com/RobertCNelson/boot-scripts/commit/e601c22335d0936f32d6a4b70ed3cf9ef7000044

They will be located here:

/opt/scripts/device/bone/capes/BB-BEAGLELOGIC/

I'll move then to /lib/firmware in the default debian image, but
current debian users will just have to:

sudo cp -v /opt/scripts/device/bone/capes/BB-BEAGLELOGIC/* /lib/firmware

Kumar Abhishek

unread,
Jul 4, 2014, 9:32:08 PM7/4/14
to beagl...@googlegroups.com
From: Kumar Abhishek <abhi...@theembeddedkitchen.net>

Signed-off-by: Kumar Abhishek <abhi...@theembeddedkitchen.net>
---
drivers/remoteproc/beaglelogic.c | 134 ++++++++++++++++++++++++++++++---------
1 file changed, 103 insertions(+), 31 deletions(-)

diff --git a/drivers/remoteproc/beaglelogic.c b/drivers/remoteproc/beaglelogic.c
index 11da9f9..391f9be 100644
--- a/drivers/remoteproc/beaglelogic.c
+++ b/drivers/remoteproc/beaglelogic.c
@@ -18,6 +18,7 @@
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/wait.h>
+#include <linux/poll.h>

#include <linux/platform_device.h>
#include <linux/miscdevice.h>
@@ -130,8 +131,8 @@ struct beaglelogicdev {
ccontext *cxt_pru;

/* Device capabilities */
- u32 bufunitsize; /* Size of 1 Allocation unit */
u32 maxbufcount; /* Max buffer count supported by the PRU FW */
+ u32 bufunitsize; /* Size of 1 Allocation unit */
u32 samplerate; /* Sample rate = 100 / n MHz, n = 2+ (int) */
u32 triggerflags; /* bit 0 : 1shot/!continuous */
u32 sampleunit; /* 0:8bits, 1:16bits */
@@ -153,7 +154,7 @@ typedef struct bufreader {
struct beaglelogicdev, miscdev)

#define DRV_NAME "beaglelogic"
-#define DRV_VERSION "1.0"
+#define DRV_VERSION "1.1"

/* Begin Buffer Management section */
static int bufunitsize = 4 * 1024 * 1024;
@@ -348,7 +349,7 @@ u32 beaglelogic_get_samplerate(struct device *dev)
int beaglelogic_set_samplerate(struct device *dev, u32 samplerate)
{
struct beaglelogicdev *bldev = dev_get_drvdata(dev);
- if (samplerate > bldev->coreclockfreq / 2 || samplerate < 100000)
+ if (samplerate > bldev->coreclockfreq / 2 || samplerate < 1)
return -EINVAL;

if (mutex_trylock(&bldev->mutex)) {
@@ -527,14 +528,17 @@ static int beaglelogic_f_open(struct inode *inode, struct file *filp)

filp->private_data = reader;

- /* Map and submit all the buffers */
- if (beaglelogic_map_and_submit_all_buffers(dev))
+ /* The buffers will be mapped/resubmitted at the time of allocation
+ * Here, we just map the first buffer */
+ if (!bldev->buffers)
return -ENOMEM;

+ beaglelogic_map_buffer(dev, &bldev->buffers[0]);
+
return 0;
}

-/* Read the sample (ring) buffer. TODO Implement Nonblock */
+/* Read the sample (ring) buffer. */
ssize_t beaglelogic_f_read (struct file *filp, char __user *buf,
size_t sz, loff_t *offset)
{
@@ -546,47 +550,56 @@ ssize_t beaglelogic_f_read (struct file *filp, char __user *buf,
if (bldev->state == STATE_BL_ERROR)
return -EIO;

- if (reader->remaining > 0)
+ if (reader->pos > 0)
goto perform_copy;

- if (reader->buf) {
- if (bldev->state == STATE_BL_INITIALIZED &&
- bldev->lastbufready == reader->buf)
- return 0;
+ if (reader->buf == NULL) {
+ /* First time init */
+ reader->buf = &reader->bldev->buffers[0];
+ reader->remaining = reader->buf->size;

- reader->buf = reader->buf->next;
- }
- else {
- /* (re)trigger */
- if (beaglelogic_start(dev))
- return -ENOEXEC;
-
- reader->buf = &bldev->buffers[0];
+ if (bldev->state != STATE_BL_RUNNING) {
+ /* Start the capture */
+ if (beaglelogic_start(dev))
+ return -ENOEXEC;
+ }
+ } else {
+ /* EOF Condition, back to buffer 0 and stopped */
+ if (reader->buf == bldev->buffers &&
+ bldev->state == STATE_BL_INITIALIZED)
+ return 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");
+ if (filp->f_flags & O_NONBLOCK) {
+ if (reader->buf->state != STATE_BL_BUF_UNMAPPED)
+ return -EAGAIN;
+ } else
+ wait_event_interruptible(bldev->wait,
+ reader->buf->state == STATE_BL_BUF_UNMAPPED);
perform_copy:
count = min(reader->remaining, sz);

+ if (copy_to_user(buf, reader->buf->buf + reader->pos, count))
+ return -EFAULT;
+
/* Detect buffer drop */
if (reader->buf->state == STATE_BL_BUF_MAPPED) {
- dev_warn(dev, "buffer dropped at index %d \n",
+ dev_warn(dev, "buffer may be 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;

+ if (reader->remaining == 0) {
+ /* Change the buffer */
+ reader->buf = reader->buf->next;
+ reader->pos = 0;
+ reader->remaining = reader->buf->size;
+ }
+
return count;
}

@@ -626,7 +639,7 @@ static long beaglelogic_f_ioctl(struct file *filp, unsigned int cmd,

u32 val;

- dev_info(dev, "BeagleLogic: IOCTL called cmd = %08X, "\
+ dev_dbg(dev, "BeagleLogic: IOCTL called cmd = %08X, "\
"arg = %08lX\n", cmd, arg);

switch (cmd) {
@@ -710,6 +723,11 @@ static long beaglelogic_f_ioctl(struct file *filp, unsigned int cmd,
return 0;

case IOCTL_BL_START:
+ /* Reset and reconfigure the reader object and then start */
+ reader->buf = &bldev->buffers[0];
+ reader->pos = 0;
+ reader->remaining = reader->buf->size;
+
beaglelogic_start(dev);
return 0;

@@ -725,7 +743,36 @@ static long beaglelogic_f_ioctl(struct file *filp, unsigned int cmd,
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;
+ struct beaglelogicdev *bldev = reader->bldev;
+ struct device *dev = bldev->miscdev.this_device;
+
+ loff_t i = offset;
+ u32 j;
+
+ if (whence == SEEK_CUR) {
+ while (i > 0) {
+ if (reader->buf->state == STATE_BL_BUF_MAPPED) {
+ dev_warn(dev, "buffer may be dropped at index %d \n",
+ reader->buf->index);
+ reader->buf->state = STATE_BL_BUF_DROPPED;
+ bldev->lasterror = 0x10000 | reader->buf->index;
+ }
+
+ j = min((u32)i, reader->remaining);
+ reader->pos += j;
+
+ if ((reader->remaining -= j) == 0) {
+ /* Change the buffer */
+ reader->buf = reader->buf->next;
+ reader->pos = 0;
+ reader->remaining = reader->buf->size;
+ }
+
+ i -= j;
+ }
+ return offset;
+ }
+
if (whence == SEEK_SET && offset == 0) {
/* The next read triggers the LA */
reader->buf = NULL;
@@ -735,10 +782,34 @@ static loff_t beaglelogic_f_llseek(struct file *filp, loff_t offset, int whence)
/* Stop and map the first buffer */
beaglelogic_stop(dev);
beaglelogic_map_buffer(dev, &reader->bldev->buffers[0]);
+
+ return 0;
}
+
return -EINVAL;
}

+/* Poll the file descriptor */
+unsigned int beaglelogic_f_poll(struct file *filp,
+ struct poll_table_struct *tbl)
+{
+ logic_buffer_reader *reader = filp->private_data;
+ struct beaglelogicdev *bldev = reader->bldev;
+ logic_buffer *buf;
+
+ /* Raise an error if polled without starting the LA first */
+ if (reader->buf == NULL && bldev->state != STATE_BL_RUNNING)
+ return -ENOEXEC;
+
+ buf = reader->buf;
+ if (buf->state == STATE_BL_BUF_UNMAPPED)
+ return (POLLIN | POLLRDNORM);
+
+ poll_wait(filp, &bldev->wait, tbl);
+
+ return 0;
+}
+
/* Device file close handler */
static int beaglelogic_f_release(struct inode *inode, struct file *filp)
{
@@ -761,6 +832,7 @@ static const struct file_operations pru_beaglelogic_fops = {
.read = beaglelogic_f_read,
.llseek = beaglelogic_f_llseek,
.mmap = beaglelogic_f_mmap,
+ .poll = beaglelogic_f_poll,
.release = beaglelogic_f_release,
};
/* fops */
--
1.9.1

Robert Nelson

unread,
Jul 5, 2014, 10:07:52 AM7/5/14
to Beagle Board
On Fri, Jul 4, 2014 at 8:31 PM, Kumar Abhishek
<kumar.abhi...@gmail.com> wrote:
> From: Kumar Abhishek <abhi...@theembeddedkitchen.net>
>
> Signed-off-by: Kumar Abhishek <abhi...@theembeddedkitchen.net>
> ---
> drivers/remoteproc/beaglelogic.c | 134 ++++++++++++++++++++++++++++++---------
> 1 file changed, 103 insertions(+), 31 deletions(-)

Thanks! Queue'd up:
https://github.com/RobertCNelson/bb-kernel/commit/3cafc80fbc3f18d200d1b3f5ca9397c411074fd2

I'm just waiting back for a phy testing confirmation, so i'll one more
patch before i push this out with bone60.

bla...@gmail.com

unread,
Jun 1, 2015, 9:31:33 AM6/1/15
to beagl...@googlegroups.com
On Tuesday, June 24, 2014 at 1:26:40 PM UTC-7, RobertCNelson wrote:
I'll move then to /lib/firmware in the default debian image, but
current debian users will just have to:

sudo cp -v /opt/scripts/device/bone/capes/BB-BEAGLELOGIC/* /lib/firmware

As of bone70 these files are not in /lib/firmware. Should I open a bug somewhere to suggest this?
Reply all
Reply to author
Forward
0 new messages