On Wed, Jul 6, 2016 at 5:41 AM, Damien Miller <[email protected]> wrote: > That sounds like a reasonable compromise - it would let the admin load > code to the PRUs in rc.securelevel for later use, or set > kern.securelevel=0 in sysctl.conf if they wanted to do development > on a multi-user system.
OK -- I have tested and fixed the previous design. It is now working exactly as stated in the man page from my prior mail. Below patch is now in a review-ready state. On Wed, Jul 6, 2016 at 3:27 AM, Ian Sutton <[email protected]> wrote: > mainbus -> fdt is next. tipru(4) now attaches via flattened device tree. However, the dtb included in miniroot-am335x-60.fs is erroneously devoid of a PRU node. Here is a patch for the decompiled source file: http://ce.gl/am335x-boneblack.dts.patch And the resultant binary for convenience's sake: http://ce.gl/am335x-boneblack.dtb To replace it (on BBB, assuming root disk is sd0): # mount /dev/sd0i /mnt # curl http://ce.gl/am335x-boneblack.dtb > /mnt/am335x-boneblack.dtb # umount /mnt # reboot Ian Index: etc/etc.armv7/MAKEDEV =================================================================== RCS file: /cvs/src/etc/etc.armv7/MAKEDEV,v retrieving revision 1.19 diff -u -p -r1.19 MAKEDEV --- etc/etc.armv7/MAKEDEV 21 May 2016 22:15:09 -0000 1.19 +++ etc/etc.armv7/MAKEDEV 9 Jul 2016 07:06:54 -0000 @@ -4,7 +4,7 @@ # generated from: # # OpenBSD: etc.armv7/MAKEDEV.md,v 1.12 2016/05/21 21:30:22 kettenis Exp -# OpenBSD: MAKEDEV.common,v 1.88 2016/05/21 15:17:49 deraadt Exp +# OpenBSD: MAKEDEV.common,v 1.89 2016/05/26 16:29:51 deraadt Exp # OpenBSD: MAKEDEV.mi,v 1.82 2016/03/12 17:58:59 espie Exp # OpenBSD: MAKEDEV.sub,v 1.14 2005/02/07 06:14:18 david Exp # @@ -59,6 +59,7 @@ # usb* Bus control devices used by usbd for attach/detach # Special purpose devices: # apm Power management device +# tipru Programmable realtime unit # audio* Audio devices # bio ioctl tunnel pseudo-device # bktr* Video frame grabbers @@ -328,6 +329,10 @@ audio*) MKlist[${#MKlist[*]}]=";[ -e audioctl ] || ln -s audioctl$U audioctl" ;; +tipru*) + M tipru c 29 0 200 + ;; + apm*) M apm c 34 0 644 M apmctl c 34 8 644 @@ -469,14 +474,14 @@ local) ;; all) - R gpio0 gpio1 gpio2 gpio3 gpio4 gpio5 gpio6 gpio7 gpio8 vnd0 - R vnd1 vnd2 vnd3 sd0 sd1 sd2 sd3 sd4 sd5 sd6 sd7 sd8 sd9 cd0 - R cd1 rd0 tap0 tap1 tap2 tap3 tun0 tun1 tun2 tun3 bio pty0 - R diskmap vscsi0 ch0 bpf fuse pppx hotplug ptm local wscons - R pci0 pci1 pci2 pci3 uall rmidi0 rmidi1 rmidi2 rmidi3 rmidi4 - R rmidi5 rmidi6 rmidi7 tuner0 radio0 video0 video1 uk0 random - R tty00 tty01 tty02 tty03 tty04 tty05 tty06 tty07 tty08 tty09 - R tty0a tty0b apm pf wd0 wd1 wd2 wd3 std st0 st1 fd + R tipru0 gpio0 gpio1 gpio2 gpio3 gpio4 gpio5 gpio6 gpio7 + R gpio8 vnd0 vnd1 vnd2 vnd3 sd0 sd1 sd2 sd3 sd4 sd5 sd6 sd7 + R sd8 sd9 cd0 cd1 rd0 tap0 tap1 tap2 tap3 tun0 tun1 tun2 tun3 + R bio pty0 diskmap vscsi0 ch0 bpf fuse pppx hotplug ptm local + R wscons pci0 pci1 pci2 pci3 uall rmidi0 rmidi1 rmidi2 rmidi3 + R rmidi4 rmidi5 rmidi6 rmidi7 tuner0 radio0 video0 video1 uk0 + R random tty00 tty01 tty02 tty03 tty04 tty05 tty06 tty07 tty08 + R tty09 tty0a tty0b apm pf wd0 wd1 wd2 wd3 std st0 st1 fd ;; wd*|sd*) Index: etc/etc.armv7/MAKEDEV.md =================================================================== RCS file: /cvs/src/etc/etc.armv7/MAKEDEV.md,v retrieving revision 1.12 diff -u -p -r1.12 MAKEDEV.md --- etc/etc.armv7/MAKEDEV.md 21 May 2016 21:30:22 -0000 1.12 +++ etc/etc.armv7/MAKEDEV.md 9 Jul 2016 07:06:54 -0000 @@ -27,6 +27,8 @@ dnl ADVISED OF THE POSSIBILITY OF SUCH D dnl dnl __devitem(apm, apm, Power management device)dnl +__devitem(tipru, tipru, Programmable realtime unit)dnl +_mkdev(tipru, tipru*, {-M tipru c major_tipru_c 0 200-})dnl _TITLE(make) _DEV(all) _DEV(ramdisk) @@ -64,6 +66,7 @@ _DEV(ulpt, 66) _DEV(usb, 64) _TITLE(spec) _DEV(apm, 34) +_DEV(tipru, 29) _DEV(au, 36) _DEV(bio, 52) _DEV(bktr, 75) @@ -114,3 +117,4 @@ target(all, cd, 0, 1)dnl target(all, sd, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9)dnl target(all, vnd, 0, 1, 2, 3)dnl target(all, gpio, 0, 1, 2, 3, 4, 5, 6, 7, 8)dnl +target(all, tipru, 0)dnl Index: share/man/man4/man4.armv7/tipru.4 =================================================================== RCS file: share/man/man4/man4.armv7/tipru.4 diff -N share/man/man4/man4.armv7/tipru.4 --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ share/man/man4/man4.armv7/tipru.4 9 Jul 2016 07:07:02 -0000 @@ -0,0 +1,221 @@ +.\" Copyright (c) 2016 Ian Sutton <[email protected]> +.\" +.\" Permission to use, copy, modify, and distribute this software for any +.\" purpose with or without fee is hereby granted, provided that the above +.\" copyright notice and this permission notice appear in all copies. +.\" +.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +.\" +.Dd $Mdocdate: May 11 2016 $ +.Dt TIPRU 4 armv7 +.Os +.Sh NAME +.Nm tipru +.Nd Texas Instruments programmable realtime unit controller +.Sh SYNOPSIS +.Nm "tipru* at fdt?" +.Sh DESCRIPTION +The +.Nm +driver supports the Programmable Realtime Unit and Industrial Communication +Subsystem (PRU-ICSS) integrated in Texas Instruments' line of AM335x SoCs. The +PRU is a pair of 32-bit modified Harvard architecture processor cores which run +a simple RISC instruction set. The PRU forgoes any kind of heuristic caching +mechanisms (TLBs, L1/L2/etc caches) as well as instruction pipelining as to +allow for completely predictable and deterministic timing behavior. The PRU is +clocked at 200MHz and executes one instruction every cycle insofar as it +operates within its local data/instruction/shared memory spaces (See +.Sx CAVEATS +for additional details.) +.Pp +.Nm Ap +s primary interface is through its write-only character device file. Writes to +this file populate the PRU's data/instruction/shared memory and must occur at +predefined offsets. Further +.Xr ioctl 2 +calls control the PRU's execution. All +.Xr write 2 +operations and some +.Xr ioctl 2 +operations must occur when the system's +.Xr securelevel 7 +is equal to or lesser than zero, and only after +.Nm +has been explicitly enabled via +.Xr ioctl 2 +call listed in the following section. (See +.Sx SECURITY CONSIDERATIONS +for additional details.) +.Sh IOCTLS +The following +.Xr ioctl 2 +commands are supported, and allowed only when system +.Xr securelevel 7 +is lesser than or equal to zero: +.Bl -tag -width Ds -offset XXX +.It Dv PRUEN +Enables the +.Nm +driver itself. All the following +.Xr ioctl 2 +calls in this section, along with all +.Xr open 2 +and +.Xr write 2 +operations attempted on +.Nm Ap s +character device file will fail if they are attempted before a successful call +to this +.Xr ioctl 2 Ns . +.It Dv PRUIRQEN Fa "int *" +Not yet implemented. +.It Dv PRURESET +Halts all PRU cores, zeroes all data/instruction/shared memory, and resets +cores' program counters. +.El +.Pp +The following +.Xr ioctl 2 +commands are supported, and allowed only when system +.Xr securelevel 7 +is greater than zero: +.Bl -tag -width Ds -offset XXX +.It Dv PRUIRQBLOCK Fa "int *" +Not yet implemented. +.It Dv PRUKILL +Halts and resets PRU cores, and zeroes all data/instruction/shared memory +spaces. No further PRU activity occurs (or is even possible) after this +.Xr ioctl 2 +call is made until the system is rebooted. +.El +.Pp +The following +.Xr ioctl 2 +commands are supported, and allowed regardless of system +.Xr securelevel 7 Ns : +.Bl -tag -width Ds -offset XXX +.It Dv PRUCTL Fa "int *" +Start/halt PRU cores. Setting a core's *_SEL bit will change its execution state +to whatever the corresponding *_EN bit specifies. +.El +.Sh FILES +.Bl -tag -width XXXXXXXXXXXXXXX -compact +.It Pa /dev/tipru +Character device for accessing PRU instruction/data space and +controlling chip. +.El +.Sh ERRORS +.Bl -tag -width Er +.It Bq Er ENODEV +Character device was opened with mode other than +.Dv O_WRONLY +or a +.Xr read 2 +call was attempted. +.It Bq Er EBUSY +Another process already has an open file descriptor on the character device file. +.It Bq Er ENOTSUPP +Driver received an unsupported +.Xr ioctl 2 +call. +.It Bq Er ENOSYS +Driver received an unimplemented +.Xr ioctl 2 +call. +.It Bq Er EFAULT +.Xr write 2 +attempted at offset not corresponding to top of PRU's data/instruction/shared memory. +.It Bq Er EOVERFLOW +.Xr write 2 +attempted that would overflow targeted memory space. +.It Bq Er EPERM +.Xr write 2 Ns , +.Xr open 2 Ns , +or +.Xr ioctl 2 +call attempted by user other than root, or attempted when the system was in an +improper +.Xr securelevel 7 +for the attempted call. +.It Bq Er ECANCELED +Operation attempted after +.Nm +driver was disabled via +.Dv PRUKILL +.Xr ioctl 2 +call or attempted before a +.Dv PRUEN +.Xr ioctl 2 +call completed successfully. +.El +.Sh SEE ALSO +.Xr pructl 1 , +.Xr intro 4 , +.Xr securelevel 7 +.Sh HISTORY +The +.Nm +driver will hopefully soon appear in +.Ox 6.0 . +.Sh AUTHORS +.An -nosplit +The +.Nm +driver was written by +.An Ian Sutton Aq Mt [email protected] . +.Sh CAVEATS +While the PRU has its own data/instruction/shared memory, it is capable of +accessing all physical addresses on the system (even its own control registers). +Disabling the OCP ports (the mechanism through which the PRU accesses outside +memory) provides no extra security as the PRU itself can arbitrarily enable it +(See +.Sx BUGS +for additional details.) +.Pp +The PRU's runtime characteristics are only deterministic insofar as it accesses +memory within its own local address space. All timing guarantees are forfeit +once non-local memory is accessed. +.Sh BUGS +If the PRU attempts to access memory outside its own local address space, the +system will hang unless the OCP master ports are enabled via the SYSCFG +register. This is due to a silicon bug wholly irrectifiable by software (See +AM335x Technical Reference Manual for additional details.) +.Sh SECURITY CONSIDERATIONS +The PRU has comprehensive and unconditional access to all physical memory +present in the system. Accordingly, +.Nm +implements a number of additional safeguards to prevent exploitation, listed below: +.Bl -bullet -width left +.It +.Nm +will only grant file descriptors, honor +.Xr write 2 +attempts, and process +.Xr ioctl 2 +calls from real root (ruid 0) regardless of the device file's permission bits, +user login class, or current +.Xr securelevel 7 Ns . +.It +.Nm +comes disabled by default. Attempts to enable +.Nm Ns , +and following modification of the instruction/data/shared memory spaces, are only +allowed when the system's +.Xr securelevel 7 +is equal or lesser than zero. When the system's +.Xr securelevel 7 +is greater than zero the PRU cores may only be started or halted via the +.Dv PRUCTL +.Xr ioctl 2 +call, and the driver itself may be disabled via the +.Dv PRUKILL +.Xr ioctl 2 +call which effectively halts and prevents the PRU from performing any actions +until the system is rebooted. +.El Index: share/man/man8/man8.armv7/MAKEDEV.8 =================================================================== RCS file: /cvs/src/share/man/man8/man8.armv7/MAKEDEV.8,v retrieving revision 1.12 diff -u -p -r1.12 MAKEDEV.8 --- share/man/man8/man8.armv7/MAKEDEV.8 28 Apr 2016 18:17:31 -0000 1.12 +++ share/man/man8/man8.armv7/MAKEDEV.8 9 Jul 2016 07:07:03 -0000 @@ -1,10 +1,10 @@ -.\" $OpenBSD: MAKEDEV.8,v 1.12 2016/04/28 18:17:31 natano Exp $ +.\" $OpenBSD$ .\" .\" THIS FILE AUTOMATICALLY GENERATED. DO NOT EDIT. .\" generated from: .\" -.\" OpenBSD: etc.armv7/MAKEDEV.md,v 1.10 2016/04/25 20:38:10 tedu Exp -.\" OpenBSD: MAKEDEV.common,v 1.86 2016/04/25 20:39:42 tedu Exp +.\" OpenBSD: etc.armv7/MAKEDEV.md,v 1.12 2016/05/21 21:30:22 kettenis Exp +.\" OpenBSD: MAKEDEV.common,v 1.89 2016/05/26 16:29:51 deraadt Exp .\" OpenBSD: MAKEDEV.man,v 1.8 2016/03/12 17:59:27 espie Exp .\" OpenBSD: MAKEDEV.mansub,v 1.2 2004/02/20 19:13:01 miod Exp .\" @@ -23,7 +23,7 @@ .\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF .\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. .\" -.Dd $Mdocdate: April 28 2016 $ +.Dd $Mdocdate: March 12 2016 $ .Dt MAKEDEV 8 armv7 .Os .Sh NAME @@ -170,6 +170,9 @@ Bus control devices used by usbd for att .It Ar apm Power management device, see .Xr apm 4 . +.It Ar tipru +Programmable realtime unit, see +.Xr tipru 4 . .It Ar audio* Audio devices, see .Xr audio 4 . Index: sys/arch/arm/arm/conf.c =================================================================== RCS file: /cvs/src/sys/arch/arm/arm/conf.c,v retrieving revision 1.46 diff -u -p -r1.46 conf.c --- sys/arch/arm/arm/conf.c 23 May 2016 00:05:34 -0000 1.46 +++ sys/arch/arm/arm/conf.c 9 Jul 2016 07:07:03 -0000 @@ -145,6 +145,8 @@ cdev_decl(radio); #include <arm/conf.h> +cdev_decl(tipru); + /* Block devices */ struct bdevsw bdevsw[] = { @@ -301,7 +303,7 @@ struct cdevsw cdevsw[] = { cdev_disk_init(NCD,cd), /* 26: SCSI CD-ROM */ cdev_ch_init(NCH,ch), /* 27: SCSI autochanger */ cdev_uk_init(NUK,uk), /* 28: SCSI unknown */ - cdev_notdef(), /* 29: */ + cdev_disk_init(1, tipru), /* 29: Realtime processor */ cdev_notdef(), /* 30: */ cdev_notdef(), /* 31: */ cdev_notdef(), /* 32: */ Index: sys/arch/armv7/conf/GENERIC =================================================================== RCS file: /cvs/src/sys/arch/armv7/conf/GENERIC,v retrieving revision 1.27 diff -u -p -r1.27 GENERIC --- sys/arch/armv7/conf/GENERIC 28 Jun 2016 04:41:37 -0000 1.27 +++ sys/arch/armv7/conf/GENERIC 9 Jul 2016 07:07:03 -0000 @@ -76,6 +76,7 @@ cpsw* at fdt? com* at fdt? # onboard uarts ommmc* at fdt? # SD/MMC card controller sdmmc* at ommmc? # SD/MMC bus +tipru* at fdt? # PRU-ICSS ehci* at omap? # EHCI (shim) usb* at ehci? Index: sys/arch/armv7/conf/RAMDISK =================================================================== RCS file: /cvs/src/sys/arch/armv7/conf/RAMDISK,v retrieving revision 1.24 diff -u -p -r1.24 RAMDISK --- sys/arch/armv7/conf/RAMDISK 28 Jun 2016 04:41:37 -0000 1.24 +++ sys/arch/armv7/conf/RAMDISK 9 Jul 2016 07:07:03 -0000 @@ -75,6 +75,7 @@ cpsw* at fdt? com* at fdt? # onboard uarts ommmc* at fdt? # SD/MMC card controller sdmmc* at ommmc? # SD/MMC bus +tipru* at fdt? # Realtime processor ehci* at omap? # EHCI (shim) usb* at ehci? Index: sys/arch/armv7/omap/am335x.c =================================================================== RCS file: /cvs/src/sys/arch/armv7/omap/am335x.c,v retrieving revision 1.7 diff -u -p -r1.7 am335x.c --- sys/arch/armv7/omap/am335x.c 18 Mar 2014 07:34:17 -0000 1.7 +++ sys/arch/armv7/omap/am335x.c 9 Jul 2016 07:07:03 -0000 @@ -105,6 +105,17 @@ #define IIC1_IRQ 71 #define IIC2_IRQ 30 +#define PRU_SIZE 0x80000 +#define PRU_ADDR 0x4A300000 +#define PRU_IRQ0 20 +#define PRU_IRQ1 21 +#define PRU_IRQ2 22 +#define PRU_IRQ3 23 +#define PRU_IRQ4 24 +#define PRU_IRQ5 25 +#define PRU_IRQ6 26 +#define PRU_IRQ7 27 + struct armv7_dev am335x_devs[] = { /* @@ -166,6 +177,16 @@ struct armv7_dev am335x_devs[] = { { .name = "omdog", .unit = 0, .mem = { { WD_ADDR, WD_SIZE } } + }, + + /* + * PRU + */ + + { .name = "tipru", + .unit = 0, + .mem = { { PRU_ADDR, PRU_SIZE } }, + .irq = { PRU_IRQ0 } }, /* Index: sys/arch/armv7/omap/am335x_prcmreg.h =================================================================== RCS file: /cvs/src/sys/arch/armv7/omap/am335x_prcmreg.h,v retrieving revision 1.4 diff -u -p -r1.4 am335x_prcmreg.h --- sys/arch/armv7/omap/am335x_prcmreg.h 18 Mar 2014 07:34:17 -0000 1.4 +++ sys/arch/armv7/omap/am335x_prcmreg.h 9 Jul 2016 07:07:03 -0000 @@ -31,6 +31,7 @@ #define PRCM_AM335X_GPIO2_CLKCTRL 0x00b0 #define PRCM_AM335X_GPIO3_CLKCTRL 0x00b4 #define PRCM_AM335X_TPCC_CLKCTRL 0x00bc +#define PRCM_AM335X_PRU_ICSS_CLKCTRL 0x00e8 #define PRCM_AM335X_MMC1_CLKCTRL 0x00f4 #define PRCM_AM335X_MMC2_CLKCTRL 0x00f8 #define PRCM_AM335X_TPTC1_CLKCTRL 0x00fc Index: sys/arch/armv7/omap/files.omap =================================================================== RCS file: /cvs/src/sys/arch/armv7/omap/files.omap,v retrieving revision 1.13 diff -u -p -r1.13 files.omap --- sys/arch/armv7/omap/files.omap 26 Jun 2016 09:06:35 -0000 1.13 +++ sys/arch/armv7/omap/files.omap 9 Jul 2016 07:07:03 -0000 @@ -26,6 +26,10 @@ attach sitaracm at omap file arch/armv7/omap/am335x_cm_padconf.c sitaracm file arch/armv7/omap/sitara_cm.c sitaracm +device tipru +attach tipru at fdt +file arch/armv7/omap/tipru.c tipru + device omgpio: gpiobus attach omgpio at omap file arch/armv7/omap/omgpio.c omgpio Index: sys/arch/armv7/omap/prcm.c =================================================================== RCS file: /cvs/src/sys/arch/armv7/omap/prcm.c,v retrieving revision 1.9 diff -u -p -r1.9 prcm.c --- sys/arch/armv7/omap/prcm.c 8 May 2014 21:17:01 -0000 1.9 +++ sys/arch/armv7/omap/prcm.c 9 Jul 2016 07:07:03 -0000 @@ -325,6 +325,8 @@ prcm_am335x_clkctrl(int mod) return PRCM_AM335X_I2C1_CLKCTRL; case PRCM_I2C2: return PRCM_AM335X_I2C2_CLKCTRL; + case PRCM_PRU_ICSS: + return PRCM_AM335X_PRU_ICSS_CLKCTRL; default: panic("%s: module not found\n", __func__); } @@ -353,6 +355,11 @@ prcm_am335x_enablemodule(struct prcm_sof clkctrl &=~AM335X_CLKCTRL_MODULEMODE_MASK; clkctrl |= AM335X_CLKCTRL_MODULEMODE_ENABLE; bus_space_write_4(sc->sc_iot, sc->sc_prcm, reg, clkctrl); + + /* PRU has its own special reset register */ + if(reg == PRCM_AM335X_PRU_ICSS_CLKCTRL) { + bus_space_write_4(sc->sc_iot, sc->sc_prcm, PRCM_AM335X_PRM_PER, 0); + } /* wait until module is enabled */ while (bus_space_read_4(sc->sc_iot, sc->sc_prcm, reg) & 0x30000) Index: sys/arch/armv7/omap/prcmvar.h =================================================================== RCS file: /cvs/src/sys/arch/armv7/omap/prcmvar.h,v retrieving revision 1.5 diff -u -p -r1.5 prcmvar.h --- sys/arch/armv7/omap/prcmvar.h 18 Mar 2014 07:34:17 -0000 1.5 +++ sys/arch/armv7/omap/prcmvar.h 9 Jul 2016 07:07:03 -0000 @@ -51,6 +51,7 @@ enum PRCM_MODULES { PRCM_I2C0, PRCM_I2C1, PRCM_I2C2, + PRCM_PRU_ICSS, }; #define PRCM_REG_MAX 6 Index: sys/arch/armv7/omap/tipru.c =================================================================== RCS file: sys/arch/armv7/omap/tipru.c diff -N sys/arch/armv7/omap/tipru.c --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ sys/arch/armv7/omap/tipru.c 9 Jul 2016 07:07:03 -0000 @@ -0,0 +1,309 @@ +/* + * Copyright (c) 2016 Ian Sutton <[email protected]> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <sys/param.h> +#include <sys/device.h> +#include <sys/kernel.h> +#include <sys/kthread.h> +#include <sys/malloc.h> +#include <sys/systm.h> +#include <sys/conf.h> +#include <sys/ioctl.h> +#include <sys/sysctl.h> + +#include <machine/bus.h> +#include <machine/fdt.h> + +#include <dev/ofw/openfirm.h> + +#include <armv7/armv7/armv7var.h> +#include <armv7/omap/prcmvar.h> + +#include <sys/fcntl.h> +#include <sys/stat.h> + +#include "tipru.h" + +#define HREAD4(sc, reg) \ + (bus_space_read_4((sc)->sc_iot, (sc)->sc_ioh, (reg))) +#define HWRITE4(sc, reg, val) \ + bus_space_write_4((sc)->sc_iot, (sc)->sc_ioh, (reg), (val)) +#define HSET4(sc, reg, bits) \ + HWRITE4((sc), (reg), HREAD4((sc), (reg)) | (bits)) +#define HCLR4(sc, reg, bits) \ + HWRITE4((sc), (reg), HREAD4((sc), (reg)) & ~(bits)) + +#define DEVNAME(sc) (sc)->sc_dev.dv_xname +#define DEVUNIT(x) (minor(x) & 0x7f) + +struct tipru_softc { + struct device sc_dev; + bus_space_tag_t sc_iot; + bus_space_handle_t sc_ioh; +#define PRU_RUN 0x1 +#define PRU_OCP 0x2 +#define PRU_STEP 0x4 +#define PRU_SLEEP 0x8 + uint8_t sc_hwflags; +#define PRU_XCLUDE 0x1 +#define PRU_ENABLED 0x2 +#define PRU_KILLED 0x4 + uint8_t sc_swflags; +}; + +int tipru_match(struct device *, void *, void *); +void tipru_attach(struct device *, struct device *, void *); +void tipru_ctl(struct tipru_softc *, int); +/*int tipru_intr(void *); */ +void tipru_reset(struct tipru_softc *); + +struct cfattach tipru_ca = { + sizeof(struct tipru_softc), tipru_match, tipru_attach +}; + +struct cfdriver tipru_cd = { + NULL, "tipru", DV_DULL +}; + +int +tipru_match(struct device *parent, void *match, void *aux) +{ + struct fdt_attach_args *faa = aux; + + return OF_is_compatible(faa->fa_node, "ti,pruss-v2"); +} + +void +tipru_attach(struct device *parent, struct device *self, void *args) +{ + struct fdt_attach_args *aa = args; + struct tipru_softc *sc = (struct tipru_softc *) self; + uint32_t rev; + + sc->sc_iot = aa->fa_iot; + if (bus_space_map(sc->sc_iot, aa->fa_reg[0], + aa->fa_reg[1], 0, &sc->sc_ioh)) + panic("%s: bus_space_map failed!", __func__); + + prcm_enablemodule(PRCM_PRU_ICSS); + + rev = bus_space_read_4(sc->sc_iot, sc->sc_ioh, PRUx_CFG + PRUx_CFG_REVID); + printf(" revid 0x%08x\n", rev); + + HSET4(sc, PRUx_CFG + PRUx_CFG_SYSCFG, PRUx_CFG_SYSCFG_STANDBY_INIT); + while(HREAD4(sc, PRUx_CFG + PRUx_CFG_SYSCFG_SUB_MWAIT)); + + tipru_reset(sc); +} + +int +tipruopen(dev_t dev, int flag, int fmt, struct proc *p) +{ + struct tipru_softc *sc; + int unit; + + unit = DEVUNIT(dev); + if(unit >= tipru_cd.cd_ndevs) + return ENXIO; + sc = tipru_cd.cd_devs[unit]; + + if(p->p_ucred->cr_ruid || p->p_ucred->cr_uid) + return EPERM; + if(ISSET(sc->sc_swflags, PRU_KILLED)) + return ECANCELED; + if(ISSET(flag, O_WRONLY)) + return ENODEV; + if(ISSET(sc->sc_swflags, PRU_XCLUDE)) + return EBUSY; + + sc->sc_swflags |= PRU_XCLUDE; + return 0; +} + +int +tipruclose(dev_t dev, int flag, int fmt, struct proc *p) +{ + struct tipru_softc *sc; + int unit; + + unit = DEVUNIT(dev); + if(unit >= tipru_cd.cd_ndevs) + return ENXIO; + sc = tipru_cd.cd_devs[unit]; + + if(ISSET(sc->sc_swflags, PRU_KILLED)) + return ECANCELED; + + sc->sc_swflags &= (sc->sc_swflags & ~PRU_XCLUDE); + return 0; +} + +int +tipruioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p) +{ + struct tipru_softc *sc; + int unit; + + unit = DEVUNIT(dev); + if(unit >= tipru_cd.cd_ndevs) + return ENXIO; + sc = tipru_cd.cd_devs[unit]; + + if(p->p_ucred->cr_ruid || p->p_ucred->cr_uid) + return EPERM; + + if (ISSET(sc->sc_swflags, PRU_KILLED)) + return ECANCELED; + + if (cmd == PRUEN) { + if(securelevel > 0) + return ECANCELED; + + printf("%s: enabled\n", DEVNAME(sc)); + sc->sc_swflags |= PRU_ENABLED; + return 0; + } else if (!ISSET(sc->sc_swflags, PRU_ENABLED)) + return ECANCELED; + + switch(cmd) { + /* Begin seclevel 0 ioctls */ + case PRUIRQEN: + if(securelevel > 0) + return EPERM; + return ENOSYS; + break; + case PRURESET: /* XXX maybe we allow this in any securelevel */ + if(securelevel > 0) + return EPERM; + tipru_reset(sc); + break; + /* End prior, begin seclevel 1 ioctls */ + case PRUIRQBLOCK: + if(securelevel < 1) + return EPERM; + return ENOSYS; + break; + case PRUKILL: + if(securelevel < 1) + return EPERM; + tipru_reset(sc); + sc->sc_swflags |= PRU_KILLED; + sc->sc_swflags &= ~PRU_ENABLED; + /* End prior, begin seclevel-agnostic ioctls */ + case PRUCTL: + tipru_ctl(sc, (int)*data); + break; + default: + return EOPNOTSUPP; + } + + return 0; +} + +int +tipruread(dev_t dev, struct uio *uio, int flags) +{ + return ENODEV; +} + +int +tipruwrite(dev_t dev, struct uio *uio, int flags) +{ + struct tipru_softc *sc; + int unit, lim, i, j; + uint32_t *wbuf; + + unit = DEVUNIT(dev); + if(unit >= tipru_cd.cd_ndevs) + return ENXIO; + + sc = tipru_cd.cd_devs[unit]; + + if(uio->uio_procp->p_ucred->cr_ruid || uio->uio_procp->p_ucred->cr_uid + || securelevel > 0) + return EPERM; + + if(!ISSET(sc->sc_swflags, PRU_ENABLED) || ISSET(sc->sc_swflags, PRU_KILLED)) + return ECANCELED; + + switch(uio->uio_offset) { + case PRU0_DRAM: + case PRU1_DRAM: + case PRU0_IRAM: + case PRU1_IRAM: + /* FALLTHROUGH */ + lim = PRU_RAM_SIZE; + break; + case PRUx_SHRRAM: + lim = PRU_SHR_SIZE; + break; + default: + return EFAULT; + } + + for(i = 0; i < uio->uio_iovcnt; i++) { + if(uio->uio_iov[i].iov_len > lim) + return EOVERFLOW; + + for(j = 0; j < uio->uio_iov[i].iov_len / 4; j++) { + wbuf = uio->uio_iov[i].iov_base + 4 * j; + HWRITE4(sc, uio->uio_offset + j * 4, *wbuf); + } + } + + return 0; +} + +/* XXX clear intrs. here when irqs implemented. pending intrs. prevent hw halt */ +void +tipru_ctl(struct tipru_softc *sc, int target_runstate) +{ + if(target_runstate & PRUCTL_PRU0_SEL && target_runstate & PRUCTL_PRU0_EN) { + HSET4(sc, PRU0_CTRL, PRUx_CTRL_EN); + while(!ISSET(HREAD4(sc, PRU0_CTRL) , PRUx_CTRL_RUNSTATE)); + } else if(target_runstate & PRUCTL_PRU0_SEL) { + HCLR4(sc, PRU0_CTRL, PRUx_CTRL_EN); + while(ISSET(HREAD4(sc, PRU0_CTRL) , PRUx_CTRL_RUNSTATE)); + } + + if(target_runstate & PRUCTL_PRU1_SEL && target_runstate & PRUCTL_PRU1_EN) { + HSET4(sc, PRU1_CTRL, PRUx_CTRL_EN); + while(!ISSET(HREAD4(sc, PRU1_CTRL) , PRUx_CTRL_RUNSTATE)); + } else if(target_runstate & PRUCTL_PRU1_SEL) { + HCLR4(sc, PRU1_CTRL, PRUx_CTRL_EN); + while(ISSET(HREAD4(sc, PRU1_CTRL) , PRUx_CTRL_RUNSTATE)); + } +} + +void +tipru_reset(struct tipru_softc *sc) +{ + int i; + + tipru_ctl(sc, 0x0); + HCLR4(sc, PRU0_CTRL, PRUx_CTRL_PCTR_RST_VAL_MASK); + HCLR4(sc, PRU1_CTRL, PRUx_CTRL_PCTR_RST_VAL_MASK); + + for(i = 0; i < 2048; i++) { + HWRITE4(sc, PRU0_DRAM + i*4, 0x0); + HWRITE4(sc, PRU1_DRAM + i*4, 0x0); + HWRITE4(sc, PRU0_IRAM + i*4, 0x0); + HWRITE4(sc, PRU1_IRAM + i*4, 0x0); + } + + for(i = 0; i < 3072; i++) + HWRITE4(sc, PRUx_SHRRAM + i*4, 0x0); +} Index: sys/arch/armv7/omap/tipru.h =================================================================== RCS file: sys/arch/armv7/omap/tipru.h diff -N sys/arch/armv7/omap/tipru.h --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ sys/arch/armv7/omap/tipru.h 9 Jul 2016 07:07:03 -0000 @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2016 Ian Sutton <[email protected]> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + + +/* RAM segments, global context */ +#define PRU0_DRAM 0x00000 +#define PRU1_DRAM 0x02000 +#define PRUx_SHRRAM 0x10000 +#define PRU0_IRAM 0x34000 +#define PRU1_IRAM 0x38000 + +#define PRU_RAM_SIZE 0x02000 +#define PRU_SHR_SIZE 0x03000 + +/* register groups, global context */ +#define PRUx_INTC 0x20000 +#define PRU0_CTRL 0x22000 +#define PRU1_CTRL 0x24000 +#define PRU0_DBG 0x22400 +#define PRU1_DBG 0x24400 +#define PRUx_CFG 0x26000 +#define PRUx_UART 0x28000 +#define PRUx_IEP 0x2e000 +#define PRUx_ECAP 0x30000 + +/* control registers */ +#define PRUx_CTRL_PCTR_RST_VAL_SHAMT 16 +#define PRUx_CTRL_PCTR_RST_VAL_MASK (16 << PRUx_CTRL_PCTR_RST_VAL_SHAMT) +#define PRUx_CTRL_RUNSTATE (1 << 15) +#define PRUx_CTRL_SINGLE_STEP (1 << 8) +#define PRUx_CTRL_CTR_EN (1 << 3) +#define PRUx_CTRL_SLEEPING (1 << 2) +#define PRUx_CTRL_EN (1 << 1) +#define PRUx_CTRL_SOFT_RST_N (1 << 0) + +#define PRUx_CTRL_STS 0x04 +#define PRUx_CTRL_STS_PCTR_SHAMT 0 +#define PRUx_CTRL_SYS_PCTR_MASK (16 << PRUx_SYS_PCTR_SHAMT) + +#define PRUx_CTRL_WAKEUP_EN 0x08 +#define PRUx_CTRL_CYCLE_OFST 0x0C +#define PRUx_CTRL_STALL_OFST 0x10 + +/* intr. registers XXX */ + +/* configuration registers */ +#define PRUx_CFG_REVID 0x00 + +#define PRUx_CFG_SYSCFG 0x04 +#define PRUx_CFG_SYSCFG_SUB_MWAIT (1 << 5) +#define PRUx_CFG_SYSCFG_STANDBY_INIT (1 << 4) +#define PRUx_CFG_SYSCFG_STANDBY_MODE_SHAMT 2 +#define PRUx_CFG_SYSCFG_STANDBY_MODE_MASK (2 << PRUx_CFG_SYSCFG_STANDBY_MODE_SHAMT) +#define PRUx_CFG_SYSCFG_IDLE_MODE_SHAMT 0 +#define PRUx_CFG_SYSCFG_IDLE_MODE_MASK (2 << PRUx_CFG_SYSCFG_IDLE_MODE_SHAMT) + +#define PRUCTL_PRU0_SEL 0x1 +#define PRUCTL_PRU1_SEL 0x2 +#define PRUCTL_PRU0_EN 0x4 +#define PRUCTL_PRU1_EN 0x8 + +#define PRUCTL _IOW('P', 0, int) +#define PRUIRQEN _IOW('P', 1, int) +#define PRUIRQBLOCK _IOW('P', 2, int) +#define PRURESET _IO ('P', 3) +#define PRUEN _IO ('P', 4) +#define PRUKILL _IO ('P', 5)
