Compare commits

...

127 Commits

Author SHA1 Message Date
Chris Johns
b7f1fa2f89 libmisc/shell/edit: Return if no memory in move_gap
Closes #4565
2023-01-30 14:11:59 +11:00
Chris Johns
45f60cfbcf libmisc/shell/edit: Fix closing the editor
Closes #4564
2023-01-30 13:59:11 +11:00
Chris Johns
2243fd6d6b libmisc/shell/chmod: Fix multiple file arguments to the command
Closes #4558
2023-01-30 13:37:42 +11:00
Kinsey Moore
05461aa475 cpukit/fdt: Free index before container
Ensure that the index is released before the structure containing it is
freed and NULLed.

Updates #4460
2022-10-03 13:24:28 -05:00
Kinsey Moore
cab00c7035 cpukit/fdt: Check correct allocation
The second allocation check was mistakenly rechecking the first
allocation. It now checks the correct allocation and ensures that names
is not NULL.

Updates #4462
2022-10-03 13:24:28 -05:00
Chris Johns
c5b794227b cpukit/include: Fix including in C++
Closes #4709
2022-08-27 10:36:27 +10:00
Sebastian Huber
b9de5b3bd6 score: Fix unlimited objects support
Commit 21275b58a5 ("score: Static
Objects_Information initialization") introduced an off-by-one error in the
maintenance of inactive objects.

Close #4676.
2022-07-18 09:36:34 +02:00
Sebastian Huber
fc7584d719 score: Fix _Objects_Active_count()
With unlimited objects the object maximum may be larger than the sum of active
and inactive objects.

Update #4676.
2022-07-18 09:36:09 +02:00
Sebastian Huber
8d54187a19 Synchronize all file descriptors in sync()
Synchronize all file descriptors and not just the ones associated with a FILE
object.

Close #4655.
2022-05-17 15:27:50 +02:00
Sebastian Huber
5d73509a34 posix: Fix use of clock for relative times
Close #4429.
2022-05-04 15:57:37 +02:00
Sebastian Huber
be5d2bc03d heap: Fix heap statistics with protection enabled
Close #4643.
2022-05-04 15:57:37 +02:00
Christian Mauderer
fc89cc7680 imfs: Fix index underrun when extending empty file
Currently the following sequence causes a endless loop when extending an
IMFS file:

- Create a file with zero length and close it.
- Make sure nearly no allocatable memory is left.
- Open the file and write enough data into it that more than the
  remaining memory will be used.

In that case when extending the IMFS file, the file currently need zero
blocks. If allocating enough new blocks fails, the already allocated new
blocks will be freed again.

The comparison of block>=old_blocks that has been used prior to this
patch compared two unsigned numbers. If old_blocks was zero, the
comparison of these two numbers always evaluated to true.

This patch frees the last block in a separate step to avoid this
problem.

Fixes #4638
2022-04-07 10:39:50 +02:00
Christian Mauderer
fc21b923ba bsp/atsam: Improve UART / USART tx performance
Put the next character into the send buffer if the buffer is empty and
not when the last character has been sent out to the line. This improves
the performance slightly.

Before that patch, the receive path was faster than the transmit path.
Therefore a simple echo could drop characters on a busy connection.
With this patch sending and receiving has about the same performance so
that no characters are lost.

Fixes #4611
2022-02-15 14:45:42 +01:00
Christian Mauderer
f7a204e3d7 bsp/atsam/i2c: Add error return and fix edge cases
The driver didn't return with an error on (for example) a NACK on the
bus. This adds the expected error return. Due to the new case that a
transfer can be interrupted on an error, there were some new edge cases.
This patch therefore also fixes these edge cases by removing the
transfer_state that more or less duplicated the interrupt states.

Fixes #4591
2022-02-10 09:03:19 +01:00
Christian Mauderer
f71c620f7e bsp/atsam/i2c: Simplify driver
Do some clean ups. Remove superfluous variables. Eliminate some overly
complex logic (information about transfer and remaining bytes has been
tracked redundantly in multiple variables).

This patch doesn't change the behavior of the driver.

Update #4591
2022-02-10 09:02:56 +01:00
Christian Mauderer
9942ff80c4 termios: Pass number of sent chars to l_start
At the moment the line discipline start function (l_start) has no
possibility to get feedback about the number of characters that have
been sent. This patch passes that information via an additional
parameter.

The change might trigger a warning on existing code because of a pointer
mismatch but it shouldn't break it. An existing function with the old
API will just ignore the additional parameter.

Update #4494
2022-02-10 09:02:03 +01:00
Christian Mauderer
779847a5ef bsp/atsam: Optionally use DMA for UART Rx
If the system is busy with other interrupts and the UART is set to a
fast baud rate, it's possible to loose UART interrupts and therefore
characters. This allows to optionally enable a DMA for the UARTs so that
a number of lost interrupts can be tolerated.

The number of DMAs on this chip is limited and not not all applications
need that feature. Therefore the DMA is disabled by default.

Close #4577
2022-01-18 08:50:06 +01:00
Christian Mauderer
d9c0dd3c32 bsp/atsam: Merge USART and UART driver
If no extended features of the USART are used and if the comparison
feature of the UART is not used, the two modules are compatible. The
drivers were nearly identical except for some names of the defines.

This patch merges the two drivers into one.

Update #4577
2022-01-18 08:50:04 +01:00
Christian Mauderer
ff3f3490df untar: Make behavior similar to GNU or BSD tar
RTEMS untar implementation had problems with overwriting or integrating
archives into existing directory structures. This patch adapts the
behavior to mimic that of a GNU tar or BSD tar and extends the tar01
test to check for the behavior. That is:

* If a directory structure exists, the files from the archive will be
  integrated. Existing files are overwritten.

* If a file exists and the archive contains a directory with the same
  name, the file is removed and a directory is created. In the above
  example: if l1/l2 is a file it will be overwritten with a new
  directory.

* If a directory exists and the archive contains a file with the same
  name, the directory will be replaced if it is empty. If it contains
  files, the result is an error.

* An archive also can contain only a file without the parent
  directories. If in that case one of the parent directories exists as a
  file extracting the archive results in an error. In the example: if
  l1/l2 is a file and the archive doesn't contain the directories but
  only the file l1/l2/x.txt that would be an error.

* In case of an error, it is possible that the archive has been
  partially extracted.

Closes #4552
2021-12-09 08:26:34 +01:00
Sebastian Huber
18bbfc729e score: Fix atomic stores for C++
Close #4567.
2021-12-07 12:31:12 +01:00
Sebastian Huber
5382f617ff score: Add _Timecounter_Set_NTP_update_second()
Allow the installation of an NTP update second handler which may be used by an
NTP service.

Update #4549.
2021-11-16 10:13:03 +01:00
Sebastian Huber
780b468845 score: Optimize timehand updates for non-SMP
In uniprocessor configurations, the timehand updates are done with
interrupts disabled.  So, it is impossible to observe a generation
number of zero.
2021-11-16 09:48:22 +01:00
Sebastian Huber
1c378f1a98 score: Port large time delta support to RTEMS 2021-11-16 09:48:22 +01:00
Sebastian Huber
68a3658d44 score: Initialize timehand generation to UINT_MAX
This leads to a timehand generation overflow right at the system start
and helps to get code coverage in test programs.
2021-11-16 09:48:22 +01:00
Mark Johnston
1640657022 timecounter: Load the currently selected tc once in tc_windup()
Reported by:	Sebastian Huber <sebastian.huber@embedded-brains.de>
Reviewed by:	kib
MFC after:	1 week
Sponsored by:	The FreeBSD Foundation
Differential Revision:	https://reviews.freebsd.org/D32729
2021-11-16 09:48:22 +01:00
Sebastian Huber
4f130929b8 kern_tc.c: Scaling/large delta recalculation
This change is a slight performance optimization for systems with a slow
64-bit division.

The th->th_scale and th->th_large_delta values only depend on the
timecounter frequency and the th->th_adjustment. The timecounter
frequency of a timehand only changes when a new timecounter is activated
for the timehand. The th->th_adjustment is only changed by the NTP
second update. The NTP second update is not done for every call of
tc_windup().

Move the code block to recalculate the scaling factor and
the large delta of a timehand to the new helper function
recalculate_scaling_factor_and_large_delta().

Call recalculate_scaling_factor_and_large_delta() when a new timecounter
is activated and a NTP second update occurred.

MFC after:	1 week
2021-11-16 09:48:22 +01:00
Mark Johnston
e27dc9d6ac timecounter: Lock the timecounter list
Timecounter registration is dynamic, i.e., there is no requirement that
timecounters must be registered during single-threaded boot.  Loadable
drivers may in principle register timecounters (which can be switched to
automatically).  Timecounters cannot be unregistered, though this could
be implemented.

Registered timecounters belong to a global linked list.  Add a mutex to
synchronize insertions and the traversals done by (mpsafe) sysctl
handlers.  No functional change intended.

Reviewed by:	imp, kib
MFC after:	2 weeks
Sponsored by:	The FreeBSD Foundation
Differential Revision:	https://reviews.freebsd.org/D32511
2021-11-16 09:48:22 +01:00
Mark Johnston
f03147f172 timecounter: Let kern.timecounter.stepwarnings be set as a tunable
MFC after:	1 week
2021-11-16 09:48:22 +01:00
Ed Maste
fc06357840 Remove "All Rights Reserved" from
FreeBSD Foundation sys/ copyrights

These ones were unambiguous cases where the Foundation was the only
listed copyright holder (in the associated license block).

Sponsored by:	The FreeBSD Foundation
2021-11-16 09:48:22 +01:00
Warner Losh
1ca98b274b kern: clarify boot time
In FreeBSD, the current time is computed from uptime + boottime. Uptime
is a continuous, smooth function that's monotonically increasing. To
effect changes to the current time, boottime is adjusted.  boottime is
mutable and shouldn't be cached against future need. Document the
current implementation, with the caveat that we may stop stepping
boottime on resume in the future and will step uptime instead (noted in
the commit message, but not in the code).

Sponsored by:		Netflix
Reviewed by:		phk, rpokala
Differential Revision:	https://reviews.freebsd.org/D30116
2021-11-16 09:48:22 +01:00
Konstantin Belousov
2cf37001fc Make kern.timecounter.hardware tunable
Noted and reviewed by:	kevans
MFC after:	1 week
Sponsored by:	The FreeBSD Foundation
Differential revision:	https://reviews.freebsd.org/D29122
2021-11-16 09:48:22 +01:00
Konstantin Belousov
c3fc52ec06 Add ddb 'show timecounter' command.
MFC after:	1 week
Sponsored by:	The FreeBSD Foundation
2021-11-16 09:48:22 +01:00
Robert Watson
512e0b59af Changes that improve DTrace FBT reliability
on freebsd/arm64:

- Implement a dtrace_getnanouptime(), matching the existing
  dtrace_getnanotime(), to avoid DTrace calling out to a potentially
  instrumentable function.

  (These should probably both be under KDTRACE_HOOKS.  Also, it's not clear
  to me that they are correct implementations for the DTrace thread time
  functions they are used in .. fixes for another commit.)

- Don't allow FBT to instrument functions involved in EL1 exception handling
  that are involved in FBT trap processing: handle_el1h_sync() and
  do_el1h_sync().

- Don't allow FBT to instrument DDB and KDB functions, as that makes it
  rather harder to debug FBT problems.

Prior to these changes, use of FBT on FreeBSD/arm64 rapidly led to kernel
panics due to recursion in DTrace.

Reliable FBT on FreeBSD/arm64 is reliant on another change from @andrew to
have the aarch64 instrumentor more carefully check that instructions it
replaces are against the stack pointer, which can otherwise lead to memory
corruption.  That change remains under review.

MFC after:	2 weeks
Reviewed by:	andrew, kp, markj (earlier version), jrtc27 (earlier version)
Differential revision:	https://reviews.freebsd.org/D27766
2021-11-16 09:48:22 +01:00
Konstantin Belousov
62c428f241 Remove double-calls to tc_get_timecount()
to warm timecounters.

It seems that second call does not add any useful state change for all
implemented timecounters.

Discussed with:	bde
Sponsored by:	The FreeBSD Foundation
MFC after:	3 weeks
2021-11-16 09:48:22 +01:00
Pawel Biernacki
eb909371c7 Mark more nodes as CTLFLAG_MPSAFE
or CTLFLAG_NEEDGIANT (17 of many)

r357614 added CTLFLAG_NEEDGIANT to make it easier to find nodes that are
still not MPSAFE (or already are but aren’t properly marked).
Use it in preparation for a general review of all nodes.

This is non-functional change that adds annotations to SYSCTL_NODE and
SYSCTL_PROC nodes using one of the soon-to-be-required flags.

Mark all obvious cases as MPSAFE.  All entries that haven't been marked
as MPSAFE before are by default marked as NEEDGIANT

Approved by:	kib (mentor, blanket)
Commented by:	kib, gallatin, melifaro
Differential Revision:	https://reviews.freebsd.org/D23718
2021-11-16 09:48:22 +01:00
Konstantin Belousov
166a80c3d8 Consolidate read code for timecounters
and fix possible overflow in bintime()/binuptime().

The algorithm to read the consistent snapshot of current timehand is
repeated in each accessor, including the details proper rollup
detection and synchronization with the writer.  In fact there are only
two different kind of readers: one for bintime()/binuptime() which has
to do the in-place calculation, and another kind which fetches some
member from struct timehand.

Extract the logic into type-checked macros, GETTHBINTIME() for bintime
calculation, and GETTHMEMBER() for safe read of a structure' member.
This way, the synchronization is only written in bintime_off() and
getthmember().

In bintime_off(), use overflow-safe calculation of th_scale *
delta(timecounter).  In tc_windup, pre-calculate the min delta value
which overflows and require slow algorithm, into the new timehands
th_large_delta member.

This part with overflow fix was written by Bruce Evans.

Reported by:	Mark Millard <marklmi@yahoo.com> (the overflow issue)
Tested by:	pho
Discussed with:	emaste
Sponsored by:	The FreeBSD Foundation (kib)
MFC after:	3 weeks
2021-11-16 09:48:22 +01:00
Mateusz Guzik
265c2e620b Remove duplicated empty lines from kern/*.c
No functional changes.
2021-11-16 09:48:22 +01:00
Konstantin Belousov
bc9c0e00cc Initialize timehands linkage much earlier.
Reported and tested by:	trasz
Sponsored by:	The FreeBSD Foundation
MFC after:	1 week
2021-11-16 09:48:22 +01:00
Konstantin Belousov
402dafa495 Make timehands count selectable at boottime.
Tested by:	O'Connor, Daniel <darius@dons.net.au>
Sponsored by:	The FreeBSD Foundation
MFC after:	1 week
Differential revision:	https://reviews.freebsd.org/D21563

This patch was modified by Sebastian Huber
<sebastian.huber@embedded-brains.de> to adjust it for RTEMS.  See
comment in the patch.
2021-11-16 09:48:22 +01:00
Olivier Houchard
a9ce44bf8f Instead of using an incomplete list of platforms
that uses 64bits time_t in 32bits mode, special case amd64, as i386 is
the only arch that still uses 32bits time_t.
2021-11-16 09:48:22 +01:00
Andrew Turner
975ecc1702 Create a new macro for static DPCPU data.
On arm64 (and possible other architectures) we are unable to use static
DPCPU data in kernel modules. This is because the compiler will generate
PC-relative accesses, however the runtime-linker expects to be able to
relocate these.

In preparation to fix this create two macros depending on if the data is
global or static.

Reviewed by:	bz, emaste, markj
Sponsored by:	ABT Systems Ltd
Differential Revision:	https://reviews.freebsd.org/D16140
2021-11-16 09:48:22 +01:00
Mateusz Guzik
f43beb03c2 tc: bcopy -> memcpy 2021-11-16 09:48:22 +01:00
Brooks Davis
c54b13b072 Move most of the contents of opt_compat.h
to opt_global.h.

opt_compat.h is mentioned in nearly 180 files. In-progress network
driver compabibility improvements may add over 100 more so this is
closer to "just about everywhere" than "only some files" per the
guidance in sys/conf/options.

Keep COMPAT_LINUX32 in opt_compat.h as it is confined to a subset of
sys/compat/linux/*.c.  A fake _COMPAT_LINUX option ensure opt_compat.h
is created on all architectures.

Move COMPAT_LINUXKPI to opt_dontuse.h as it is only used to control the
set of compiled files.

Reviewed by:	kib, cem, jhb, jtl
Sponsored by:	DARPA, AFRL
Differential Revision:	https://reviews.freebsd.org/D14941
2021-11-16 09:48:22 +01:00
Sebastian Huber
f77b692e5c score: Remove FreeBSD identifier 2021-11-16 09:48:22 +01:00
Konstantin Belousov
7d3712fb26 Use atomic_load(9) to read ppsinfo sequence numbers.
In this case volatile qualifiers enusre that a compiler does not
optimize the accesses out.

Reviewed by:	alc, jhb
Sponsored by:	The FreeBSD Foundation
MFC after:	1 week
Differential revision:	https://reviews.freebsd.org/D13534
2021-11-16 09:48:22 +01:00
Pedro F. Giffuni
73b77be719 SPDX: use the Beerware identifier. 2021-11-16 09:48:22 +01:00
Sebastian Huber
d5649e25f3 kern_tc.c: Remove unused code
This fix relates to a Coverity issue (PW.DECLARED_BUT_NOT_REFERENCED).
2021-11-16 09:48:22 +01:00
Joel Sherrill
c8a1060988 Add support for IDLE Thread stack allocator
Add a stack allocator hook specifically for allocation of IDLE thread stacks.
This allows the user to decide if IDLE thread stacks are statically allocated
or handled by the same custom allocator mechanism as other thread stacks.

Closes #4520.
2021-10-07 10:31:38 -05:00
Chris Johns
99698fb5a2 powerpc/motorola_powerpc: Map LibBSD bus space to the PCI base address
Closes #4516
2021-09-22 10:58:14 +10:00
Chris Johns
cfef84a007 powerpc/io: Make [out/in] le and be calls conditional
- These calls clash with the Linux IO header in LibBSD. Making these
  conditional here means BSPs build and the imported Linux header is
  untouched.

Updates #4245
2021-09-22 10:58:14 +10:00
Ryan Long
e9712e7890 pxcdevctl: Adjust for standard (5 branch)
psxdevctl is supposed to return the value in errno. Before, it was
returning -1 and setting errno. Changed the tests to reflect these
changes. Added code from RRADE's posix_devctl.c.

Closes #4505
2021-09-20 13:48:14 -05:00
Sebastian Huber
ff94ddcd84 rtems: Initialize count of postponed jobs
The rtems_rate_monotonic_get_status() directive returns an arbitrary
number for the count of postponed jobs if it is called for a newly
created period object.  Set the count of postponed jobs to zero during
object creation.

Close #4512.
2021-09-09 15:17:50 +02:00
Gedare Bloom
e5a1b15848 m68k/uC5282: linkcmds KEEP and SORT sections
Fixes a problem with bad epilog code in _fini and to keep sections
necessary with the -ffunction/data-sections.

Closes #4465.
2021-07-01 12:53:50 -06:00
Jan Sommer
4925ab4f52 bsps/i386: Update calibration of TSC to be more accurate
Closes #4456
2021-06-21 10:13:37 +02:00
Sebastian Huber
8d4382ba34 bsps/irq: Change license to BSD-2-Clause
Change license to BSD-2-Clause according to file history and
re-licensing agreement.

Update #3053.
2021-06-21 10:12:26 +02:00
Christian Mauderer
50a835393a cpukit: Add description of release version numbers
The release version in the git sources doesn't change. Add a note why
that is the case.
2021-05-28 08:24:05 +02:00
Sebastian Huber
06427c8df4 rtems: Check entry point in rtems_task_start()
Close #4409.
2021-05-14 09:22:17 +02:00
Sebastian Huber
d697769d46 bsps/arm: ARMV7_CP15_START_WORKSPACE_ENTRY_INDEX
Change the ARMV7_CP15_START_WORKSPACE_ENTRY_INDEX value to be in line
with the workspace entry in ARMV7_CP15_START_DEFAULT_SECTIONS.

Close #4394.
2021-04-29 13:39:36 +02:00
Moyano, Gabriel
bc806d41a5 grlib/genirq: Taking into account that it could be more than one ISR enabled/disabled
Closes #4385
2021-04-16 08:49:54 +02:00
Christian Mauderer
a274b6fdcb shell: Add i2c and spi commands
This adds some commands that are usefull for debugging simple serial
interfaces.

Even if they are a complete re-implementation, the i2c* commands use a
simmilar call like the Linux i2c tools.

Closes #4371
2021-03-31 10:43:48 +02:00
Jan Sommer
ec2660548e bsps/xilinx_zynq: Add Xilinx AXI SPI driver to build
Closes #4370
2021-03-31 10:22:42 +02:00
Jan Sommer
ce2b276803 bsps/xilinx_zynq: Add SPI driver for xilinx-axi-spi
Updates #4370
2021-03-31 10:15:49 +02:00
Jan Sommer
14e74e4312 bsps/xilinx_zynq: Add cadence SPI driver to build system
Closes #4369
2021-03-31 10:02:00 +02:00
Jan Sommer
c86d513664 bsps/xilinx_zynq: Add SPI driver for cadence-spi
Updates #4369
2021-03-31 10:00:12 +02:00
G S Niteesh Babu
08f807e64a rtems-fdt/rtems-fdt.c: Fix bug in loop termination
The while loop, loops infinitely in case of raw FDT data.
The loop condition (size) is not modified during iterations.

Fixes #4350
2021-03-21 12:39:14 +01:00
Sebastian Huber
3a66586c9e rtems: Allow RTEMS_PRIORITY for MrsP semaphores
In order to improve the compatibility of RTEMS 5.2 with future version
of RTEMS which fixed #4346 allow MrsP semaphores to be created with
RTEMS_PRIORITY.

Close #4347.
2021-03-16 15:00:08 +01:00
Jan Sommer
645dbc5fcc bsps/shared: Allow setting baud rate for zynq uart
Closes #4236
2021-03-09 09:28:43 +01:00
Kinsey Moore
2f323700b9 zynq-uart: Fix set_attributes implementation
The zynq-uart set_attributes implementation was configured to always
return false which causes spconsole01 to fail. This restores the
disabled implementation which sets the baud rate registers
appropriately and allows spconsole01 to pass. This also expands the
set_attributes functionality to allow setting of the stop bits,
character width, and parity.

Updates #4236
2021-03-09 09:28:43 +01:00
Daniel Hellstrom
2497a46a76 sparc,leon: avoid triggering LEON3FT errata TN-0009
Update #4154.
2021-03-07 16:08:27 +01:00
Daniel Hellstrom
3074eb0f37 sparc,leon: avoid triggering TN-0009 bad sequence
Update #4154.
2021-03-07 16:08:26 +01:00
Daniel Hellstrom
291267113b grlib,grspw_pkt: correct link state enum numbering
Not used by the driver itself, but shuold be correct if used by
application.

Update #4316.
2021-03-07 16:08:26 +01:00
Martin Aberg
8cfaa0eb76 leon, l2cache: prevent unused diagnostic access
Update #4315.
2021-03-07 16:08:26 +01:00
Martin Aberg
b0eb952427 leon, ahbstat: register definitions for AHBSTAT version 1
Update #4314.
2021-03-07 16:08:26 +01:00
Martin Aberg
1161e1fb92 leon, grspw_router: added router_port_link_div()
Allows user to set SpaceWire run clock divisor for an individual port.

Update #4313.
2021-03-07 16:08:26 +01:00
Daniel Hellstrom
d9d96f0608 sparc: fix bad register alignment for 64 bit store
Update #4311.
2021-03-07 16:08:25 +01:00
Daniel Hellstrom
cb8379dc09 leon: restart and load timer counter at initialization
Without this smp05 and smpthreadlife01 tests may fail
depending on how the boot loader initialized the GPTIMER.
Before the time counter stopped counting when reaching
zero, but tests could work since it could take 2^32 us
before stopping.

The timer driver will potentially overwrite this, but it
happens later due to the initialization order having
RTEMS_SYSINIT_CPU_COUNTER very early.

Update #4312.
2021-03-07 16:08:25 +01:00
Daniel Hellstrom
81e4a15b18 leon,ckinit: avoid assuming 1MHz timer pre-scaler clock
Update #4310.
2021-03-07 16:08:25 +01:00
Daniel Hellstrom
0ed294b6cc leon3: avoid dependency on apbuart/timer driver
Moves drvmgr_drivers[] from amba.c to a separate file in order
to avoid the dependecy on APBUART/GPTIMER drivers. This has
an effect when user configured not to use timer or uart
in their project.

Update #4309.
2021-03-07 16:08:25 +01:00
Daniel Hellstrom
c13205f691 leon,greth: added support for variable sized descriptor table sizes
The descriptor table size is equal to its alignment and set when
configuring the HW IP through VHDL generics. This SW patch simply
probes the HW how large the RX/TX descriptor tables are and adjusts
accordingly.

The number of descriptors actual used are controlled by other
settings (rxDescs and txDescs) controlled by the user.

Update #4308.
2021-03-07 16:08:25 +01:00
Daniel Hellstrom
23cc5a6090 leon,grcan: split out GRCAN non-FD specific support in separate file
Update #4307.
2021-03-07 16:08:24 +01:00
Daniel Hellstrom
e180f281ab leon,grcanfd: split out GRCANFD specific support in separate file
Update #4307.
2021-03-07 16:08:24 +01:00
Daniel Hellstrom
c41e7bae9c leon,grcan: added support for GRCANFD
The new GRCAN_FD IP supports CAN FD standard and is mostly backwards
compatible with GRCAN SW interface. The GRCAN driver have been extended
to support the GRCANFD IP using the same driver.

Additional functions have been added that uses a new CAN FD frame
format and read/write/baud-rate functions that supports both GRCANFD
and GRCAN. To keep the SW API fully backwards compatible with GRCAN,
the old functions remain.

Update #4307.
2021-03-07 16:08:24 +01:00
Daniel Hellstrom
e1062fae3c grlib: added 64-bit read no-cache function
Update #4307.
2021-03-07 16:08:24 +01:00
Daniel Hellstrom
7db032cf02 leon,occan: use common CAN baud-rate calculation routine
Update #4306.
2021-03-07 16:08:24 +01:00
Daniel Hellstrom
78b45cc561 leon,grcan: use common CAN baud-rate calculation routine
Update #4306.
2021-03-07 16:08:23 +01:00
Daniel Hellstrom
da7cb87b4d leon,can: introduce common CAN baud-rate calculation function
Reimplemented the baud-rate algorithm from scratch to cope with
GRCAN, GRCANFD and OC_CAN devices.

Update #4306.
2021-03-07 16:08:23 +01:00
Daniel Hellstrom
0ab993b04a grlib,ambapp: added new IP core IDs
Update #4305.
2021-03-07 16:08:23 +01:00
Daniel Hellstrom
84fb340ac4 leon,grspw: fix for SET_PACKET_SIZE
When the DMA table has been allocated dynamically, the IOCTL_SET_PACKETSIZE
will trigger an issue where pDev->rx and pDev->tx are not updated with
the new DMA tables base address. Instead the old pointers are used.

There is no point in reallocting the DMA tables because there is no
configuration option to it. Therefore the DMA tables allocation is
moved to a separate function never called from SET_PACKETSIZE.

Update #4304.
2021-03-07 16:08:23 +01:00
Arvid Bjorkengren
8004ffb649 leon,gr1553b: Only align allocated memory. Verify alignment of memory.
Update #4303.
2021-03-07 16:08:23 +01:00
Arvid Bjorkengren
14fcf38891 leon,gr1553b: set codec version
This is enables the updated codec for GR740 and is backwards compatible
with all other versions of the IP.

Updates #4275.
2021-03-07 16:08:22 +01:00
Arvid Bjorkengren
1223f5e402 leon,gr1553rt: Fixed spinlock unlock
Update #4274.
2021-03-07 16:08:22 +01:00
Arvid Bjorkengren
a97a4732f7 leon,gr1553rt: Fixed memory leak
Update #4274.
2021-03-07 16:08:22 +01:00
Daniel Cederman
980cdb82a7 sparc: Remove sequences that the B2BST scan script warns about
Update #4154.
2021-03-07 16:08:22 +01:00
Vijay Kumar Banerjee
f4d00aa538 powerpc/beatnik/net: Remove unused files
Close #4293
2021-03-03 19:45:00 -07:00
Chris Johns
d1bab986ca powerpc/motorola_power: Place any common data in the .bss section
- It seems the compiler how defaults to -fcommon and this means
  some uninitialised data is ignored.

Closes #4266
2021-02-27 10:59:25 +11:00
Chris Johns
3824960f24 powerpc/motorola_power: Link all text sections into the executable image
- The change to building all code with code and data sections means
  we have a section per function. Make sure all functions are
  placed in the text section.

Closes #4266
2021-02-24 17:04:36 +11:00
Chris Johns
2f56b7375a Update motorola_power to irq-generic interrupt management
- Add support to the BSP to enable irq-generic management

- Update the powerpc shared irq code to support irq-generic. This
  is an opt in option for existing powerpc bsps. This change
  should be simpler now

- Fix a number of issues in ISA IRQ controller handling by porting
  fixes from the i386 (PC) BSP

Closes #4247
Closes #4248
2021-02-16 15:24:33 +11:00
Chris Johns
388bd8054c bsp/motorola_powerp: Print RTEMS_VERSION from the bootloader
Close #4234
2021-02-10 17:35:30 +11:00
Chris Johns
6d9843e189 powerpc/shared: ISA bus bridge fails to enable the openpic irq
- The call to enable the openpic irq for the ISA bridge fails
  because the IRQ used is offset by the ISA bus signals and
  the openpic call expects an IRQ relative to its signals.

- Add the MVME 2600/2700 to the list of boards with an ISA bridge.

Closes #4233
2021-02-08 09:43:48 +11:00
Sebastian Huber
ef1ac8afff score: Add barrier thread queue operations
This fixes a missing decrement of the number of waiting threads during a
barrier wait timeout.

Close #4232.
2021-02-06 21:06:10 +01:00
Sebastian Huber
cc2a237129 score: Make FIFO thread queue ops public
Update #4232.
2021-02-06 21:06:05 +01:00
Sebastian Huber
5861e42567 score: Constify Thread_queue_First_operation
Update #4232.
2021-02-06 21:05:58 +01:00
Sebastian Huber
5ae7ec9477 Fix RTEMS_LINKER_ROSET_ITEM_ORDERED_DECLARE()
Add "extern" similar to RTEMS_LINKER_RWSET_ITEM_ORDERED_DECLARE().

Close #4224.
2021-01-25 06:46:09 +01:00
Christian Mauderer
0d44334ca1 bsp/imx: Fix system counter init for imx6
For i.MX7 U-Boot initializes the system counter. On i.MX6 Barebox is
often used which doesn't initialize the counter. With this patch, we try
to auto-detect whether the counter is initialized or not and do the
initialization ourself if necessary.

Closes #4220
2021-01-21 10:29:15 +01:00
Sebastian Huber
2a8f755107 bsps/arm: Fix MMU configuration
Update #4185.
2020-12-15 11:26:43 +01:00
Jan Sommer
21ed8d11c5 bsps/arm: Fix MMU small pages support
- For small tables only round to the next 4kiB instead of 1MiB

Close #4185.
2020-12-11 06:55:18 +01:00
Sebastian Huber
dedc3e1d49 rtems: Improve rtems_interrupt_server_create()
Also start interrupt server tasks on processors which do not have a
scheduler.  Applications may dynamically manage processors using
rtems_scheduler_remove_processor() and rtems_scheduler_add_processor().

Close #4190.
2020-11-25 08:32:24 +01:00
Sebastian Huber
1dbdf94e67 bsps: Fix rtems_interrupt_server_delete()
The ISR lock must be destroyed to prevent memory corruption if RTEMS_PROFILING
and RTEMS_SMP is enabled.

Close #4189.
2020-11-25 08:25:02 +01:00
Christian Mauderer
0af682cf5d bsp/atsam: Fix XDMAD status
In "bsp/atsam: Simplify XDMAD_Handler()" (5f813694f6) the interrupt
callback has been made unconditional. That allowed to avoid some special
deadlock situations in error cases. But it removed part of the XDMAD
status handling.

This patch adds the ability to update the XDMAD status from the
callback if that is necessary for the driver.

Fixes #4172
2020-11-12 08:31:41 +01:00
Jan Sommer
f84c4a5b81 confdefs: Add extern C guards to libpci.h
Closes #4169
2020-10-30 13:21:46 +11:00
Chris Johns
7021c01464 libfs/rfs: Check search bit map end on last bit
- Do not write past the last location of the search bit map
  whe nit is being created.

Closes #4149
2020-10-17 10:55:30 +11:00
Sebastian Huber
e71e271ce1 bsps/arm: Add workaround for Errata 794072
Add a workaround for Cortex-A9 Errata 845369: A short loop including a DMB
instruction might cause a denial of service on another which executes a CP15
broadcast operation.

Close #4114.
2020-10-16 06:41:32 +02:00
Sebastian Huber
3d7da43562 bsps/arm: Workaround for Errata 845369
Add a workaround for Cortex-A9 Errata 845369: Under Very Rare Timing
Circumstances Transition into Streaming Mode Might Create Data Corruption.

Update #4114.
2020-10-16 06:41:27 +02:00
Gedare Bloom
40f23ceae6 i386/score: fix assembly mnemonic
This is a backport for assembler error observed in 6. Although the
assembler error does not appear in 5, the backport was requested.

Closes #4083.
2020-10-02 10:38:49 -06:00
Ryan Long
fdbe9b7599 rtems-bsps: add ability to print architecture/bsp list
Closes #4099.
2020-09-29 07:59:31 -05:00
Frank Kühndel
18549295be Fixing bug in line editing of the shell with CTRL-U.
This patch fixes a tiny bug in the command line editing of the RTEMS shell.
Typing CTRL-U in the shell should remove all characters left of the cursor.
After pressing CTRL-U, the current implementation does wrongly place the cursor
at the end of the line instead at its beginning.

To reproduce the bug, start the shell and type 'abc123' (no <RETURN>):

> ~/src/rtems $ qemu-system-arm -net none -nographic -M realview-pbx-a9 \
  -m 256M -kernel build/arm/realview_pbx_a9_qemu/testsuites/libtests/dl10.exe
> *** BEGIN OF TEST libdl (RTL) 10 ***
> *** TEST VERSION: 6.0.0.d9bdf166644f612dd628fe4951c12c6f8e94ba5f
> *** TEST STATE: USER_INPUT
> *** TEST BUILD: RTEMS_DEBUG RTEMS_NETWORKING RTEMS_POSIX_API RTEMS_SMP
> *** TEST TOOLS: 10.2.1 20200904 \
  (RTEMS 6, RSB 31f936a7b74d60bda609a9960c6e1a705ba54974, Newlib a0d7982)
> RTL (libdl) commands: dl, rtl
>
> RTEMS Shell on /dev/foobar. Use 'help' to list commands.
> SHLL [/] # abc123

Then move the cursor onto the '1' by hitting three times the <ARROW-LEFT> key.
Next type <CTRL>-U:

> SHLL [/] # 123

Note that the cursor is at the end of the line (after '3') instead of correctly
at the beginning (on the '1'), now.

Continuing typing 'echo ' incorrectly results in the output:

> SHLL [/] # 123echo 123

The patch changes this behavior so that the cursor in the second last step will
be on the '1' and typing 'echo ' will then correctly reflected as:

> SHLL [/] # echo 123

Close #4096.
2020-09-28 14:20:35 +02:00
Jan Sommer
b11745148d bsps/pc386: Add missing license header
Closes #4902.
2020-09-23 08:24:05 -05:00
Jan Sommer
61ccb9c05d bsp/xilinx-zynq: Flush TX-Buffer before initializing uart
Closes #4055
Closes #4056
2020-08-22 17:30:12 +10:00
Sebastian Huber
7661402bc2 confdefs: Fix cyclic dependency
Close #4060.
2020-08-21 20:02:35 +02:00
Chris Johns
5284e812e2 powerpc/io: The eieio() function clashes with FreeBSD. Change.
Closes #4021
2020-08-12 13:02:14 +10:00
Kinsey Moore
e95c00a79e posix: Only check shm_unlink obj_err if necessary
In the nominal case checked by spsysinit01, obj_err is unmodified if
_POSIX_Shm_Get_by_name returns non-NULL. In the case of shm_unlink, this means
an uninitialized value is passed into the switch and it appears tests using it
were passing by virtue of the stack having the right value on it in most cases.
This now checks obj_err only if _POSIX_Shm_Get_by_name returns NULL.

Close #4016
2020-08-11 07:48:19 -05:00
Chris Johns
95036a4591 shell: Only clear std handles when the shell task exits
Clearing the std file handles when the main loop exited crashes
telnetd as it reuses its session threads.

Closes #3859
2020-08-08 18:07:32 +10:00
Sebastian Huber
534f9dbe13 arm/atsam: Make interrupt server configurable
The external UART over SPI device SC16IS752 uses the interrupt server
for interrupt processing. The interrupt server is also heavily used by
libbsd. The interrupt processing for the SC16IS752 is time critical and
doesn't work if network traffic is processed at the same priority.
With #4033 custom interrupt servers are available. Change
atsam_sc16is752_spi_create() to support user-defined interrupt servers.
Introduced atsam_sc16is752_spi_config to cut down the argument count of
this function.

Close #4038.
2020-08-05 06:59:10 +02:00
Christian Mauderer
4a2ac5ef8d dosfs: Fix memory leak on failed mounts.
Currently if mount fails, a converter isn't destroyed. We have to take
care of two cases:

1. The user doesn't provide a converter.

In this case mounting a dosfs creates a default converter. This patch
makes sure that the converter is destroyed again if mount failes for
this case.

2. The user provides a converter.

In this case it's not sure that the dosfs specific routines are reached
because mount can fail before that. Therefore the user has to destroy
the converter himself again. This patch adds a documentation for that
and implements it in the media server.

Closes #4041.
2020-08-04 08:26:58 +02:00
Sebastian Huber
5eb0773159 rtems: Add rtems_interrupt_server_create()
Add rtems_interrupt_server_destroy().

Before this patch, the only way to create interrupt servers was
rtems_interrupt_server_initialize(). This function creates the default
interrupt server and in SMP configurations additional interrupt servers
for the additional processors. The interrupt server is heavily used by
libbsd. This includes the epoch based reclamation which performs time
consuming resource and memory deallocation work. This does not work well
with time critical services, for example an UART over SPI or I2C. One
approach to address this problem is to allow the application to create
custom interrupt servers with the right priority and task properties.
The interrupt server API accounted for this, however, it was not
implemented before this patch.

Close #4033.
2020-08-03 08:43:45 +02:00
Jan Sommer
849d741832 i386: Fix possible race condition on first context restore
Make sure that the esp is restored before the eflags register.

When the init task is initially restored, system interrupts are activated when the
eflags register is loaded.
If the esp register still points to an address in the interrupt stack
area (from early system initlization) the ISR might overwrite its own
stack.

Closes #4030
2020-07-29 11:39:35 +02:00
Jan Sommer
a1f9265c03 bsps/pc386: Fix IPI for non-consecutive APICIDs
- properly use the cpu <-> apic maps for IPIs

Closes #4028.
2020-07-16 08:08:09 -05:00
177 changed files with 7162 additions and 2706 deletions

View File

@@ -16,6 +16,7 @@
#include <bsp/irq.h>
#include <bsp/fatal.h>
#include <rtems/console.h>
#include <rtems/seterr.h>
#include <rtems/termiostypes.h>
@@ -23,230 +24,12 @@
#include <unistd.h>
#define UART_RX_DMA_BUF_SIZE 32l
typedef struct {
rtems_termios_device_context base;
Usart *regs;
rtems_vector_number irq;
uint32_t id;
bool console;
#ifdef ATSAM_CONSOLE_USE_INTERRUPTS
bool transmitting;
#endif
} atsam_usart_context;
static atsam_usart_context atsam_usart_instances[] = {
{
.regs = USART0,
.irq = USART0_IRQn,
.id = ID_USART0
}
#ifdef USART1
, {
.regs = USART1,
.irq = USART1_IRQn,
.id = ID_USART1
}
#endif
#ifdef USART2
, {
.regs = USART2,
.irq = USART2_IRQn,
.id = ID_USART2
}
#endif
};
#ifdef ATSAM_CONSOLE_USE_INTERRUPTS
static void atsam_usart_interrupt(void *arg)
{
rtems_termios_tty *tty = arg;
atsam_usart_context *ctx = rtems_termios_get_device_context(tty);
Usart *regs = ctx->regs;
uint32_t csr = regs->US_CSR;
while ((csr & US_CSR_RXRDY) != 0) {
char c = (char) regs->US_RHR;
rtems_termios_enqueue_raw_characters(tty, &c, 1);
csr = regs->US_CSR;
}
if (ctx->transmitting && (csr & US_CSR_TXEMPTY) != 0) {
rtems_termios_dequeue_characters(tty, 1);
}
}
#endif
static bool atsam_usart_set_attributes(
rtems_termios_device_context *base,
const struct termios *term
)
{
atsam_usart_context *ctx = (atsam_usart_context *) base;
Usart *regs = ctx->regs;
rtems_termios_baud_t baud;
uint32_t mr;
baud = rtems_termios_baud_to_number(term->c_ospeed);
regs->US_BRGR = (BOARD_MCK / baud) / 16;
if ((term->c_cflag & CREAD) != 0) {
regs->US_CR = US_CR_RXEN | US_CR_TXEN;
} else {
regs->US_CR = US_CR_TXEN;
}
mr = US_MR_USART_MODE_NORMAL | US_MR_USCLKS_MCK;
switch (term->c_cflag & CSIZE) {
case CS5:
mr |= US_MR_CHRL_5_BIT;
break;
case CS6:
mr |= US_MR_CHRL_6_BIT;
break;
case CS7:
mr |= US_MR_CHRL_7_BIT;
break;
default:
mr |= US_MR_CHRL_8_BIT;
break;
}
if ((term->c_cflag & PARENB) != 0) {
if ((term->c_cflag & PARODD) != 0) {
mr |= US_MR_PAR_ODD;
} else {
mr |= US_MR_PAR_EVEN;
}
} else {
mr |= US_MR_PAR_NO;
}
if ((term->c_cflag & CSTOPB) != 0) {
mr |= US_MR_NBSTOP_2_BIT;
} else {
mr |= US_MR_NBSTOP_1_BIT;
}
regs->US_MR = mr;
return true;
}
static bool atsam_usart_first_open(
rtems_termios_tty *tty,
rtems_termios_device_context *base,
struct termios *term,
rtems_libio_open_close_args_t *args
)
{
atsam_usart_context *ctx = (atsam_usart_context *) base;
Usart *regs = ctx->regs;
#ifdef ATSAM_CONSOLE_USE_INTERRUPTS
rtems_status_code sc;
#endif
regs->US_CR = US_CR_RSTRX | US_CR_RSTTX | US_CR_RSTSTA;
regs->US_IDR = 0xffffffff;
PMC_EnablePeripheral(ctx->id);
rtems_termios_set_initial_baud(tty, ATSAM_CONSOLE_BAUD);
atsam_usart_set_attributes(base, term);
#ifdef ATSAM_CONSOLE_USE_INTERRUPTS
regs->US_IER = US_IDR_RXRDY;
sc = rtems_interrupt_handler_install(
ctx->irq,
"USART",
RTEMS_INTERRUPT_SHARED,
atsam_usart_interrupt,
tty
);
if (sc != RTEMS_SUCCESSFUL) {
return false;
}
#endif
return true;
}
static void atsam_usart_last_close(
rtems_termios_tty *tty,
rtems_termios_device_context *base,
rtems_libio_open_close_args_t *args
)
{
atsam_usart_context *ctx = (atsam_usart_context *) base;
#ifdef ATSAM_CONSOLE_USE_INTERRUPTS
rtems_interrupt_handler_remove(ctx->irq, atsam_usart_interrupt, tty);
#endif
if (!ctx->console) {
PMC_DisablePeripheral(ctx->id);
}
}
static void atsam_usart_write(
rtems_termios_device_context *base,
const char *buf,
size_t len
)
{
atsam_usart_context *ctx = (atsam_usart_context *) base;
Usart *regs = ctx->regs;
#ifdef ATSAM_CONSOLE_USE_INTERRUPTS
if (len > 0) {
ctx->transmitting = true;
regs->US_THR = buf[0];
regs->US_IER = US_IDR_TXEMPTY;
} else {
ctx->transmitting = false;
regs->US_IDR = US_IDR_TXEMPTY;
}
#else
size_t i;
for (i = 0; i < len; ++i) {
while ((regs->US_CSR & US_CSR_TXEMPTY) == 0) {
/* Wait */
}
regs->US_THR = buf[i];
}
#endif
}
#ifndef ATSAM_CONSOLE_USE_INTERRUPTS
static int atsam_usart_read(rtems_termios_device_context *base)
{
atsam_usart_context *ctx = (atsam_usart_context *) base;
Usart *regs = ctx->regs;
if ((regs->US_CSR & US_CSR_RXRDY) != 0) {
return (char) regs->US_RHR;
} else {
return -1;
}
}
#endif
static const rtems_termios_device_handler atsam_usart_handler = {
.first_open = atsam_usart_first_open,
.last_close = atsam_usart_last_close,
.write = atsam_usart_write,
.set_attributes = atsam_usart_set_attributes,
#ifdef ATSAM_CONSOLE_USE_INTERRUPTS
.mode = TERMIOS_IRQ_DRIVEN
#else
.poll_read = atsam_usart_read,
.mode = TERMIOS_POLLED
#endif
};
char buf[UART_RX_DMA_BUF_SIZE];
LinkedListDescriporView3 desc;
} atsam_uart_rx_dma;
typedef struct {
rtems_termios_device_context base;
@@ -254,43 +37,79 @@ typedef struct {
rtems_vector_number irq;
uint32_t id;
bool console;
bool is_usart;
#ifdef ATSAM_CONSOLE_USE_INTERRUPTS
bool transmitting;
bool rx_dma_enabled;
uint32_t rx_dma_channel;
atsam_uart_rx_dma *rx_dma;
char *volatile*rx_dma_da;
char *rx_next_read_pos;
#endif
} atsam_uart_context;
static atsam_uart_context atsam_usart_instances[] = {
{
.regs = (Uart *)USART0,
.irq = USART0_IRQn,
.id = ID_USART0,
.is_usart = true,
}
#ifdef USART1
, {
.regs = (Uart *)USART1,
.irq = USART1_IRQn,
.id = ID_USART1,
.is_usart = true,
}
#endif
#ifdef USART2
, {
.regs = (Uart *)USART2,
.irq = USART2_IRQn,
.id = ID_USART2,
.is_usart = true,
}
#endif
};
static atsam_uart_context atsam_uart_instances[] = {
{
.regs = UART0,
.irq = UART0_IRQn,
.id = ID_UART0
.id = ID_UART0,
.is_usart = false,
}
#ifdef UART1
, {
.regs = UART1,
.irq = UART1_IRQn,
.id = ID_UART1
.id = ID_UART1,
.is_usart = false,
}
#endif
#ifdef UART2
, {
.regs = UART2,
.irq = UART2_IRQn,
.id = ID_UART2
.id = ID_UART2,
.is_usart = false,
}
#endif
#ifdef UART3
, {
.regs = UART3,
.irq = UART3_IRQn,
.id = ID_UART3
.id = ID_UART3,
.is_usart = false,
}
#endif
#ifdef UART4
, {
.regs = UART4,
.irq = UART4_IRQn,
.id = ID_UART4
.id = ID_UART4,
.is_usart = false,
}
#endif
};
@@ -303,16 +122,32 @@ static void atsam_uart_interrupt(void *arg)
Uart *regs = ctx->regs;
uint32_t sr = regs->UART_SR;
while ((sr & UART_SR_RXRDY) != 0) {
char c = (char) regs->UART_RHR;
if (!ctx->rx_dma_enabled) {
while ((sr & UART_SR_RXRDY) != 0) {
char c = (char) regs->UART_RHR;
rtems_termios_enqueue_raw_characters(tty, &c, 1);
rtems_termios_enqueue_raw_characters(tty, &c, 1);
sr = regs->UART_SR;
sr = regs->UART_SR;
}
} else {
while (*ctx->rx_dma_da != ctx->rx_next_read_pos) {
char c;
c = *ctx->rx_next_read_pos;
++ctx->rx_next_read_pos;
if (ctx->rx_next_read_pos >= &ctx->rx_dma->buf[UART_RX_DMA_BUF_SIZE]) {
ctx->rx_next_read_pos = &ctx->rx_dma->buf[0];
}
rtems_termios_enqueue_raw_characters(tty, &c, 1);
}
}
if (ctx->transmitting && (sr & UART_SR_TXEMPTY) != 0) {
while (ctx->transmitting && (sr & UART_SR_TXRDY) != 0) {
rtems_termios_dequeue_characters(tty, 1);
sr = regs->UART_SR;
}
}
#endif
@@ -336,10 +171,31 @@ static bool atsam_uart_set_attributes(
regs->UART_CR = UART_CR_TXEN;
}
mr = UART_MR_FILTER_DISABLED | UART_MR_BRSRCCK_PERIPH_CLK;
if (ctx->is_usart) {
mr = US_MR_USART_MODE_NORMAL | US_MR_USCLKS_MCK;
} else {
mr = UART_MR_FILTER_DISABLED | UART_MR_BRSRCCK_PERIPH_CLK;
}
if ((term->c_cflag & CSIZE) != CS8) {
return false;
if (ctx->is_usart) {
switch (term->c_cflag & CSIZE) {
case CS5:
mr |= US_MR_CHRL_5_BIT;
break;
case CS6:
mr |= US_MR_CHRL_6_BIT;
break;
case CS7:
mr |= US_MR_CHRL_7_BIT;
break;
default:
mr |= US_MR_CHRL_8_BIT;
break;
}
} else {
if ((term->c_cflag & CSIZE) != CS8) {
return false;
}
}
if ((term->c_cflag & PARENB) != 0) {
@@ -352,8 +208,16 @@ static bool atsam_uart_set_attributes(
mr |= UART_MR_PAR_NO;
}
if ((term->c_cflag & CSTOPB) != 0) {
return false;
if (ctx->is_usart) {
if ((term->c_cflag & CSTOPB) != 0) {
mr |= US_MR_NBSTOP_2_BIT;
} else {
mr |= US_MR_NBSTOP_1_BIT;
}
} else {
if ((term->c_cflag & CSTOPB) != 0) {
return false;
}
}
regs->UART_MR = mr;
@@ -361,6 +225,118 @@ static bool atsam_uart_set_attributes(
return true;
}
static void atsam_uart_disable_rx_dma(atsam_uart_context *ctx)
{
if (ctx->rx_dma) {
rtems_cache_coherent_free(ctx->rx_dma);
ctx->rx_dma = NULL;
}
if (ctx->rx_dma_channel != XDMAD_ALLOC_FAILED) {
XDMAD_FreeChannel(&XDMAD_Instance, ctx->rx_dma_channel);
}
ctx->rx_dma_enabled = false;
}
static rtems_status_code atsam_uart_enable_rx_dma(atsam_uart_context *ctx)
{
eXdmadRC rc;
int channel_id;
if (ctx->rx_dma_enabled) {
return RTEMS_SUCCESSFUL;
}
/*
* Make sure everything is in a clean default state so that the cleanup works
* in an error case.
*/
ctx->rx_dma = NULL;
ctx->rx_dma_channel = XDMAD_ALLOC_FAILED;
ctx->rx_dma = rtems_cache_coherent_allocate(sizeof(*ctx->rx_dma), 0, 0);
if (ctx->rx_dma == NULL) {
atsam_uart_disable_rx_dma(ctx);
return RTEMS_NO_MEMORY;
}
ctx->rx_next_read_pos = &ctx->rx_dma->buf[0];
ctx->rx_dma_channel = XDMAD_AllocateChannel(
&XDMAD_Instance,
XDMAD_TRANSFER_MEMORY,
ctx->id
);
if (ctx->rx_dma_channel == XDMAD_ALLOC_FAILED) {
atsam_uart_disable_rx_dma(ctx);
return RTEMS_IO_ERROR;
}
rc = XDMAD_PrepareChannel(&XDMAD_Instance, ctx->rx_dma_channel);
if (rc != XDMAD_OK) {
atsam_uart_disable_rx_dma(ctx);
return RTEMS_IO_ERROR;
}
channel_id = ctx->rx_dma_channel & 0xff;
ctx->rx_dma_da =
(char *volatile*) &XDMAD_Instance.pXdmacs->XDMAC_CHID[channel_id].XDMAC_CDA;
ctx->rx_dma->desc.mbr_nda = (uint32_t)&ctx->rx_dma->desc;
ctx->rx_dma->desc.mbr_ubc =
1 |
XDMA_UBC_NVIEW_NDV3 |
XDMA_UBC_NDE_FETCH_EN |
XDMA_UBC_NDEN_UPDATED |
XDMA_UBC_NSEN_UPDATED;
ctx->rx_dma->desc.mbr_sa = (uint32_t) &ctx->regs->UART_RHR;
ctx->rx_dma->desc.mbr_da = (uint32_t) &ctx->rx_dma->buf[0];
ctx->rx_dma->desc.mbr_cfg =
XDMAC_CC_TYPE_PER_TRAN |
XDMAC_CC_MBSIZE_SINGLE |
XDMAC_CC_DSYNC_PER2MEM |
XDMAC_CC_SWREQ_HWR_CONNECTED |
XDMAC_CC_MEMSET_NORMAL_MODE |
XDMAC_CC_CSIZE_CHK_1 |
XDMAC_CC_DWIDTH_BYTE |
XDMAC_CC_SIF_AHB_IF1 |
XDMAC_CC_DIF_AHB_IF1 |
XDMAC_CC_SAM_FIXED_AM |
XDMAC_CC_DAM_UBS_AM |
XDMAC_CC_PERID(XDMAIF_Get_ChannelNumber(ctx->id, XDMAD_TRANSFER_RX));
ctx->rx_dma->desc.mbr_bc = UART_RX_DMA_BUF_SIZE - 1;
ctx->rx_dma->desc.mbr_ds = 0;
ctx->rx_dma->desc.mbr_sus = 0;
ctx->rx_dma->desc.mbr_dus = 0;
rc = XDMAD_ConfigureTransfer(
&XDMAD_Instance,
ctx->rx_dma_channel,
NULL,
XDMAC_CNDC_NDE_DSCR_FETCH_EN |
XDMAC_CNDC_NDVIEW_NDV3 |
XDMAC_CNDC_NDDUP_DST_PARAMS_UPDATED |
XDMAC_CNDC_NDSUP_SRC_PARAMS_UPDATED,
(uint32_t)&ctx->rx_dma->desc,
0);
if (rc != XDMAD_OK) {
atsam_uart_disable_rx_dma(ctx);
return RTEMS_IO_ERROR;
}
rc = XDMAD_StartTransfer(&XDMAD_Instance, ctx->rx_dma_channel);
if (rc != XDMAD_OK) {
atsam_uart_disable_rx_dma(ctx);
return RTEMS_IO_ERROR;
}
ctx->rx_dma_enabled = true;
return RTEMS_SUCCESSFUL;
}
static bool atsam_uart_first_open(
rtems_termios_tty *tty,
rtems_termios_device_context *base,
@@ -386,7 +362,7 @@ static bool atsam_uart_first_open(
regs->UART_IER = UART_IDR_RXRDY;
sc = rtems_interrupt_handler_install(
ctx->irq,
"UART",
ctx->is_usart ? "USART" : "UART",
RTEMS_INTERRUPT_SHARED,
atsam_uart_interrupt,
tty
@@ -411,6 +387,10 @@ static void atsam_uart_last_close(
rtems_interrupt_handler_remove(ctx->irq, atsam_uart_interrupt, tty);
#endif
if (ctx->rx_dma_enabled) {
atsam_uart_disable_rx_dma(ctx);
}
if (!ctx->console) {
PMC_DisablePeripheral(ctx->id);
}
@@ -429,16 +409,16 @@ static void atsam_uart_write(
if (len > 0) {
ctx->transmitting = true;
regs->UART_THR = buf[0];
regs->UART_IER = UART_IDR_TXEMPTY;
regs->UART_IER = UART_IDR_TXRDY;
} else {
ctx->transmitting = false;
regs->UART_IDR = UART_IDR_TXEMPTY;
regs->UART_IDR = UART_IDR_TXRDY;
}
#else
size_t i;
for (i = 0; i < len; ++i) {
while ((regs->UART_SR & UART_SR_TXEMPTY) == 0) {
while ((regs->UART_SR & UART_SR_TXRDY) == 0) {
/* Wait */
}
@@ -461,13 +441,41 @@ static int atsam_uart_read(rtems_termios_device_context *base)
}
#endif
#ifdef ATSAM_CONSOLE_USE_INTERRUPTS
static int atsam_uart_ioctl(
rtems_termios_device_context *base,
ioctl_command_t request,
void *buffer
)
{
atsam_uart_context *ctx = (atsam_uart_context *) base;
rtems_status_code sc;
switch (request) {
case ATSAM_UART_ENABLE_RX_DMA:
sc = atsam_uart_enable_rx_dma(ctx);
if (sc != RTEMS_SUCCESSFUL) {
rtems_set_errno_and_return_minus_one(EIO);
} else {
ctx->rx_dma_enabled = true;
}
break;
default:
rtems_set_errno_and_return_minus_one(EINVAL);
}
return 0;
}
#endif
static const rtems_termios_device_handler atsam_uart_handler = {
.first_open = atsam_uart_first_open,
.last_close = atsam_uart_last_close,
.write = atsam_uart_write,
.set_attributes = atsam_uart_set_attributes,
#ifdef ATSAM_CONSOLE_USE_INTERRUPTS
.mode = TERMIOS_IRQ_DRIVEN
.mode = TERMIOS_IRQ_DRIVEN,
.ioctl = atsam_uart_ioctl,
#else
.poll_read = atsam_uart_read,
.mode = TERMIOS_POLLED
@@ -490,7 +498,7 @@ rtems_status_code console_initialize(
usart[sizeof(usart) - 2] = (char) ('0' + i);
rtems_termios_device_install(
&usart[0],
&atsam_usart_handler,
&atsam_uart_handler,
NULL,
&atsam_usart_instances[i].base
);

View File

@@ -132,9 +132,66 @@ static uint32_t XDMAD_AllocateXdmacChannel(sXdmad *pXdmad,
return XDMAD_ALLOC_FAILED;
}
/*
* Update the internal xdmad state. Returns true if further processing in the
* callback is recommended.
*
* In an earlier version of the API this has been done by the interrupt handler
* directly. But in some cases the application might want to process some of the
* other interrupts too. Therefore the user callback should now decide itself
* whether this is necessary or not.
*/
bool XDMAD_UpdateStatusFromCallback(sXdmad *pXdmad,
uint32_t Channel,
uint32_t status)
{
Xdmac *pXdmac;
uint32_t xdmaGlobalChStatus;
bool bExec;
bExec = false;
pXdmac = pXdmad->pXdmacs;
xdmaGlobalChStatus = XDMAC_GetGlobalChStatus(pXdmac);
if ((xdmaGlobalChStatus & (XDMAC_GS_ST0 << Channel)) == 0) {
uint32_t xdmaChannelIntMask;
sXdmadChannel *pCh;
pCh = &pXdmad->XdmaChannels[Channel];
xdmaChannelIntMask = XDMAC_GetChannelItMask(pXdmac, Channel);
status &= xdmaChannelIntMask;
if (status & XDMAC_CIS_BIS) {
if ((xdmaChannelIntMask & XDMAC_CIM_LIM) == 0) {
pCh->state = XDMAD_STATE_DONE;
bExec = true;
}
}
if (status & XDMAC_CIS_LIS) {
pCh->state = XDMAD_STATE_DONE;
bExec = true;
}
if (status & XDMAC_CIS_DIS) {
pCh->state = XDMAD_STATE_DONE;
bExec = true;
}
} else {
/* Block end interrupt for LLI dma mode */
if (XDMAC_GetChannelIsr(pXdmac, Channel) & XDMAC_CIS_BIS) {
bExec = true;
}
}
return bExec;
}
void XDMAD_DoNothingCallback(uint32_t Channel, void *pArg, uint32_t status)
{
/* Do nothing */
/* Do nothing except status update */
XDMAD_UpdateStatusFromCallback((sXdmad *)pArg, Channel, status);
}
/*----------------------------------------------------------------------------
@@ -157,6 +214,7 @@ static void XDMAD_SysInitialize(void)
for (j = 0; j < pXdmad->numChannels; j ++) {
pXdmad->XdmaChannels[j].fCallback = XDMAD_DoNothingCallback;
pXdmad->XdmaChannels[j].pArg = (void *)pXdmad;
}
sc = rtems_interrupt_handler_install(

View File

@@ -33,72 +33,65 @@
static void
atsam_i2c_disable_interrupts(Twihs *regs)
{
regs->TWIHS_IDR = 0xFFFFFFFF;
TWI_DisableIt(regs, 0xFFFFFFFF);
}
static void
atsam_i2c_set_transfer_status(transfer_desc *trans_desc, transfer_state state)
/*
* Return true if the message is done right after this. That is the case if all
* bytes are received but no stop is requested.
*/
static bool
atsam_i2c_continue_read(Twihs *regs, atsam_i2c_bus *bus)
{
trans_desc->trans_state = state;
}
bool done = false;
static void
atsam_i2c_continue_read(Twihs *regs, transfer_desc *trans_desc)
{
trans_desc->data[trans_desc->already_transferred] = TWI_ReadByte(regs);
trans_desc->already_transferred++;
*bus->current_msg_byte = TWI_ReadByte(regs);
++bus->current_msg_byte;
--bus->current_msg_todo;
/* check for transfer finish */
if (trans_desc->already_transferred == trans_desc->data_size) {
if (trans_desc->stop_request){
if (bus->current_msg_todo == 0) {
if (bus->stop_request){
TWI_DisableIt(regs, TWIHS_IDR_RXRDY);
TWI_EnableIt(regs, TWIHS_IER_TXCOMP);
atsam_i2c_set_transfer_status(trans_desc, TX_RX_STOP_SENT);
} else {
atsam_i2c_set_transfer_status(trans_desc, RX_CONT_MESSAGE_NEEDED);
done = true;
}
}
/* Last byte? */
else if ((trans_desc->already_transferred == (trans_desc->data_size - 1))
&& (trans_desc->stop_request)){
else if (bus->current_msg_todo == 1 && bus->stop_request) {
TWI_Stop(regs);
}
return done;
}
/*
* Return true if the message is done right after this. That is the case if all
* bytes are sent but no stop is requested.
*/
static bool
atsam_i2c_is_state(transfer_desc *trans_desc, transfer_state state)
atsam_i2c_continue_write(Twihs *regs, atsam_i2c_bus *bus)
{
return (trans_desc->trans_state == state);
}
bool done = false;
static void
atsam_i2c_continue_write(Twihs *regs, transfer_desc *trans_desc)
{
/* Transfer finished ? */
if (trans_desc->already_transferred == trans_desc->data_size) {
if (bus->current_msg_todo == 0) {
TWI_DisableIt(regs, TWIHS_IDR_TXRDY);
if (trans_desc->stop_request){
if (bus->stop_request){
TWI_EnableIt(regs, TWIHS_IER_TXCOMP);
TWI_SendSTOPCondition(regs);
atsam_i2c_set_transfer_status(trans_desc, TX_RX_STOP_SENT);
} else {
atsam_i2c_set_transfer_status(trans_desc, TX_CONT_MESSAGE_NEEDED);
done = true;
}
}
/* Bytes remaining */
else {
TWI_WriteByte(regs,
trans_desc->data[trans_desc->already_transferred]);
trans_desc->already_transferred++;
TWI_WriteByte(regs, *bus->current_msg_byte);
++bus->current_msg_byte;
--bus->current_msg_todo;
}
}
static void
atsam_i2c_finish_write_transfer(Twihs *regs, transfer_desc *trans_desc)
{
TWI_ReadByte(regs);
TWI_DisableIt(regs, TWIHS_IDR_TXCOMP);
trans_desc->status = 0;
return done;
}
static void
@@ -115,19 +108,6 @@ atsam_i2c_next_packet(atsam_i2c_bus *bus)
bus->current_msg_byte = msg->buf;
}
static void
atsam_i2c_set_td(atsam_i2c_bus *bus, uint32_t already_transferred,
bool stop_needed)
{
transfer_desc *trans_desc = &bus->trans_desc;
trans_desc->status = ASYNC_STATUS_PENDING;
trans_desc->data = bus->current_msg_byte;
trans_desc->data_size = bus->current_msg_todo;
trans_desc->already_transferred = already_transferred;
trans_desc->stop_request = stop_needed;
}
static bool
atsam_i2c_set_address_size(const i2c_msg *msg)
{
@@ -186,6 +166,8 @@ atsam_i2c_setup_write_transfer(atsam_i2c_bus *bus, Twihs *regs, bool ctrl,
{
atsam_i2c_set_address_regs(regs, slave_addr, ctrl, false);
TWI_WriteByte(regs, *bus->current_msg_byte);
++bus->current_msg_byte;
--bus->current_msg_todo;
TWI_EnableIt(regs, TWIHS_IER_TXRDY);
}
@@ -197,8 +179,8 @@ atsam_i2c_setup_transfer(atsam_i2c_bus *bus, Twihs *regs)
uint32_t msg_todo = bus->msg_todo;
uint16_t slave_addr;
bool ten_bit_addr = false;
uint32_t already_transferred;
bool stop_needed = true;
bool read;
ten_bit_addr = atsam_i2c_set_address_size(msgs);
@@ -206,22 +188,17 @@ atsam_i2c_setup_transfer(atsam_i2c_bus *bus, Twihs *regs)
stop_needed = false;
}
bus->read = (msgs->flags & I2C_M_RD) != 0;
read = (msgs->flags & I2C_M_RD) != 0;
slave_addr = msgs->addr;
already_transferred = (bus->read == true) ? 0 : 1;
atsam_i2c_set_td(bus, already_transferred, stop_needed);
bus->stop_request = stop_needed;
transfer_desc *trans_desc = &bus->trans_desc;
if (bus->read){
if (read){
if (bus->current_msg_todo == 1){
send_stop = true;
}
atsam_i2c_set_transfer_status(trans_desc, RX_SEND_DATA);
atsam_i2c_setup_read_transfer(regs, ten_bit_addr,
slave_addr, send_stop);
} else {
atsam_i2c_set_transfer_status(trans_desc, TX_SEND_DATA);
atsam_i2c_setup_write_transfer(bus, regs, ten_bit_addr,
slave_addr);
}
@@ -233,40 +210,28 @@ atsam_i2c_interrupt(void *arg)
atsam_i2c_bus *bus = arg;
uint32_t irqstatus;
bool done = false;
transfer_desc *trans_desc;
Twihs *regs = bus->regs;
/* read interrupts */
irqstatus = regs->TWIHS_SR;
irqstatus = TWI_GetMaskedStatus(regs);
if((irqstatus & (TWIHS_SR_ARBLST | TWIHS_SR_NACK)) != 0) {
if((irqstatus & ATSAMV_I2C_IRQ_ERROR) != 0) {
done = true;
}
trans_desc = &bus->trans_desc;
if (((irqstatus & TWIHS_SR_RXRDY) != 0) &&
(atsam_i2c_is_state(trans_desc, RX_SEND_DATA))){
/* carry on read transfer */
atsam_i2c_continue_read(regs, trans_desc);
} else if (((irqstatus & TWIHS_SR_TXCOMP) != 0) &&
(atsam_i2c_is_state(trans_desc, TX_RX_STOP_SENT))){
atsam_i2c_finish_write_transfer(regs, trans_desc);
} else if ((irqstatus & TWIHS_SR_RXRDY) != 0) {
done = atsam_i2c_continue_read(regs, bus);
} else if ((irqstatus & TWIHS_SR_TXCOMP) != 0) {
TWI_DisableIt(regs, TWIHS_IDR_TXCOMP);
done = true;
} else if (((irqstatus & TWIHS_SR_TXRDY) != 0) &&
(atsam_i2c_is_state(trans_desc, TX_SEND_DATA))){
atsam_i2c_continue_write(regs, trans_desc);
if (trans_desc->trans_state == TX_CONT_MESSAGE_NEEDED){
done = true;
}
} else if ((irqstatus & TWIHS_SR_TXRDY) != 0) {
done = atsam_i2c_continue_write(regs, bus);
}
if(done){
uint32_t err = irqstatus & ATSAMV_I2C_IRQ_ERROR;
bus->err = irqstatus & ATSAMV_I2C_IRQ_ERROR;
atsam_i2c_next_packet(bus);
if (bus->msg_todo == 0 || err != 0) {
if (bus->msg_todo == 0 || bus->err != 0) {
atsam_i2c_disable_interrupts(regs);
rtems_binary_semaphore_post(&bus->sem);
} else {
@@ -291,27 +256,38 @@ atsam_i2c_transfer(i2c_bus *base, i2c_msg *msgs, uint32_t msg_count)
if ((msgs[i].flags & I2C_M_RECV_LEN) != 0) {
return -EINVAL;
}
if (msgs[i].len == 0) {
/* Hardware doesn't support zero length messages */
return -EINVAL;
}
}
bus->msgs = &msgs[0];
bus->msg_todo = msg_count;
bus->current_msg_todo = msgs[0].len;
bus->current_msg_byte = msgs[0].buf;
bus->err = 0;
regs = bus->regs;
atsam_i2c_setup_transfer(bus, regs);
/* Start with a clean start. Enable error interrupts. */
TWI_ConfigureMaster(bus->regs, bus->output_clock, BOARD_MCK);
TWI_EnableIt(regs, ATSAMV_I2C_IRQ_ERROR);
regs->TWIHS_IER = ATSAMV_I2C_IRQ_ERROR;
atsam_i2c_setup_transfer(bus, regs);
eno = rtems_binary_semaphore_wait_timed_ticks(
&bus->sem,
bus->base.timeout
);
if (eno != 0) {
if (eno != 0 || bus->err != 0) {
TWI_ConfigureMaster(bus->regs, bus->output_clock, BOARD_MCK);
rtems_binary_semaphore_try_wait(&bus->sem);
return -ETIMEDOUT;
if (bus->err != 0) {
return -EIO;
} else {
return -ETIMEDOUT;
}
}
return 0;

View File

@@ -33,6 +33,7 @@
#include <bspopts.h>
#include <bsp/default-initial-extension.h>
#include <sys/ioccom.h>
#include <rtems.h>
@@ -109,6 +110,18 @@ void atsam_rtc_get_time(rtems_time_of_day *tod);
void bsp_restart( const void *const addr );
/*
* This ioctl enables the receive DMA for an UART. The DMA can be usefull if you
* loose characters in high interrupt load situations.
*
* Disabling the DMA again is only possible by closing all file descriptors of
* that UART.
*
* Note that every UART needs one DMA channel and the system has only a limited
* amount of DMAs. So only use it if you need it.
*/
#define ATSAM_UART_ENABLE_RX_DMA _IO('d', 0)
#ifdef __cplusplus
}
#endif /* __cplusplus */

View File

@@ -28,35 +28,23 @@ extern "C" {
#define TWI_AMOUNT_PINS 2
typedef enum {
TX_SEND_DATA,
TX_SEND_STOP,
TX_CONT_MESSAGE_NEEDED,
RX_SEND_DATA,
RX_SEND_STOP,
RX_CONT_MESSAGE_NEEDED,
TX_RX_STOP_SENT
}transfer_state;
typedef struct {
uint8_t status;
uint8_t *data;
bool stop_request;
uint32_t data_size;
uint32_t already_transferred;
transfer_state trans_state;
} transfer_desc;
typedef struct {
i2c_bus base;
i2c_msg *msgs;
Twihs *regs;
transfer_desc trans_desc;
/* First message and number of messages that have to be processed. */
i2c_msg *msgs;
uint32_t msg_todo;
/* Information about the current transfer. */
bool stop_request;
uint32_t current_msg_todo;
uint8_t *current_msg_byte;
/* Error information that can be returned to the task */
uint32_t err;
uint32_t output_clock;
bool read;
rtems_binary_semaphore sem;
rtems_vector_number irq;
} atsam_i2c_bus;

View File

@@ -24,44 +24,85 @@
extern "C" {
#endif /* __cplusplus */
/**
* @brief The SC16IS752 device context.
*
* All members are private to the device driver.
*/
typedef struct {
sc16is752_spi_context base;
Pin irq_pin;
rtems_interrupt_server_entry irqs_entry; /* Internal. Don't touch. */
rtems_interrupt_server_action irqs_action; /* Internal. Don't touch. */
rtems_interrupt_server_entry irqs_entry;
rtems_interrupt_server_action irqs_action;
uint32_t irqs_index;
} atsam_sc16is752_spi_context;
/**
* @brief The SC16IS752 device configuration.
*
* @see atsam_sc16is752_spi_create().
*/
typedef struct {
/**
* @brief The device file path for the new device.
*/
const char *device_path;
/**
* @brief The SC16IS752 mode.
*/
sc16is752_mode mode;
/**
* @brief The input frequency in Hertz of the SC16IS752 chip. See XTAL1 and
* XTAL2 pins.
*/
uint32_t input_frequency;
/**
* @brief The SPI bus device path.
*/
const char *spi_path;
/**
* @brief The SPI chip select (starts with 0, the SPI driver uses
* SPI_ChipSelect(1 << spi_chip_select)).
*/
uint8_t spi_chip_select;
/**
* @brief The SPI bus speed in Hertz.
*/
uint32_t spi_speed_hz;
/**
* @brief The interrupt pin, e.g. { PIO_PD28, PIOD, ID_PIOD, PIO_INPUT,
* PIO_IT_LOW_LEVEL }.
*/
const Pin irq_pin;
/**
* @brief The index to identify the interrupt server used for interrupt
* processing.
*/
uint32_t server_index;
} atsam_sc16is752_spi_config;
/**
* @brief Creates an SPI connected SC16IS752 device.
*
* This devices uses the interrupt server, see
* rtems_interrupt_server_initialize().
* This devices uses the interrupt server, see rtems_interrupt_server_create().
*
* The device claims the interrupt of the PIO block.
*
* @param[in] ctx The device context. May have an arbitrary content.
* @param[in] device_path The device file path for the new device.
* @param[in] mode The SC16IS752 mode.
* @param[in] input_frequency The input frequency in Hertz of the SC16IS752
* chip. See XTAL1 and XTAL2 pins.
* @param[in] spi_path The SPI bus device path.
* @param[in] spi_chip_select The SPI chip select (starts with 0, the SPI
* driver uses SPI_ChipSelect(1 << spi_chip_select)).
* @param[in] spi_speed_hz The SPI bus speed in Hertz.
* @param[in] irq_pin The interrupt pin, e.g. { PIO_PD28, PIOD, ID_PIOD,
* PIO_INPUT, PIO_IT_LOW_LEVEL }.
* @param[out] ctx is the device context. It may have an arbitrary content.
* @param config is the device configuration.
*
* @return See sc16is752_spi_create().
*/
int atsam_sc16is752_spi_create(
atsam_sc16is752_spi_context *ctx,
const char *device_path,
sc16is752_mode mode,
uint32_t input_frequency,
const char *spi_path,
uint8_t spi_chip_select,
uint32_t spi_speed_hz,
const Pin *irq_pin
atsam_sc16is752_spi_context *ctx,
const atsam_sc16is752_spi_config *config
);
#ifdef __cplusplus

View File

@@ -241,6 +241,10 @@ extern eXdmadRC XDMAD_StartTransfer(sXdmad *pXdmad, uint32_t dwChannel);
extern void XDMAD_DoNothingCallback(uint32_t Channel, void *pArg, uint32_t status);
extern bool XDMAD_UpdateStatusFromCallback(sXdmad *pXdmad,
uint32_t Channel,
uint32_t status);
extern eXdmadRC XDMAD_SetCallback(sXdmad *pXdmad,
uint32_t dwChannel,
XdmadTransferCallback fCallback,

View File

@@ -41,7 +41,7 @@ static bool atsam_sc16is752_install_interrupt(sc16is752_context *base)
rtems_status_code sc;
uint8_t rv;
sc = rtems_interrupt_server_entry_initialize(RTEMS_INTERRUPT_SERVER_DEFAULT,
sc = rtems_interrupt_server_entry_initialize(ctx->irqs_index,
&ctx->irqs_entry);
rtems_interrupt_server_action_prepend(&ctx->irqs_entry,
&ctx->irqs_action, atsam_sc16i752_irqs_handler, ctx);
@@ -64,24 +64,19 @@ static void atsam_sc16is752_remove_interrupt(sc16is752_context *base)
}
int atsam_sc16is752_spi_create(
atsam_sc16is752_spi_context *ctx,
const char *device_path,
sc16is752_mode mode,
uint32_t input_frequency,
const char *spi_path,
uint8_t spi_chip_select,
uint32_t spi_speed_hz,
const Pin *irq_pin
atsam_sc16is752_spi_context *ctx,
const atsam_sc16is752_spi_config *config
)
{
ctx->base.base.mode = mode;
ctx->base.base.input_frequency = input_frequency;
ctx->base.base.mode = config->mode;
ctx->base.base.input_frequency = config->input_frequency;
ctx->base.base.install_irq = atsam_sc16is752_install_interrupt;
ctx->base.base.remove_irq = atsam_sc16is752_remove_interrupt;
ctx->base.spi_path = spi_path;
ctx->base.cs = spi_chip_select;
ctx->base.speed_hz = spi_speed_hz;
ctx->irq_pin = *irq_pin;
ctx->base.spi_path = config->spi_path;
ctx->base.cs = config->spi_chip_select;
ctx->base.speed_hz = config->spi_speed_hz;
ctx->irq_pin = config->irq_pin;
ctx->irqs_index = config->server_index;
return sc16is752_spi_create(&ctx->base, device_path);
return sc16is752_spi_create(&ctx->base, config->device_path);
}

View File

@@ -39,6 +39,10 @@ include_bsp_HEADERS += ../../../../../bsps/arm/include/bsp/lpc-timer.h
include_bsp_HEADERS += ../../../../../bsps/arm/include/bsp/start.h
include_bsp_HEADERS += ../../../../../bsps/arm/include/bsp/zynq-uart-regs.h
include_bsp_HEADERS += ../../../../../bsps/arm/include/bsp/zynq-uart.h
include_bsp_HEADERS += ../../../../../bsps/arm/include/bsp/cadence-spi-regs.h
include_bsp_HEADERS += ../../../../../bsps/arm/include/bsp/cadence-spi.h
include_bsp_HEADERS += ../../../../../bsps/arm/include/bsp/xilinx-axi-spi-regs.h
include_bsp_HEADERS += ../../../../../bsps/arm/include/bsp/xilinx-axi-spi.h
include_libcpudir = $(includedir)/libcpu
include_libcpu_HEADERS =

View File

@@ -18,6 +18,7 @@
#include <bsp/fdt.h>
#include <bsp/irq-generic.h>
#include <bsp/linker-symbols.h>
#include <libcpu/arm-cp15.h>
#include <libfdt.h>
@@ -58,6 +59,60 @@ uint32_t bsp_fdt_map_intr(const uint32_t *intr, size_t icells)
return intr[1] + MAGIC_IRQ_OFFSET;
}
static bool imx_is_imx6(const void *fdt)
{
/*
* At the moment: Check for some compatible strings that should be there
* somewhere in every fdt.
*
* FIXME: It would be nice if some CPU-ID could be used instead. But I didn't
* find one.
*/
int node;
node = fdt_node_offset_by_compatible(fdt, -1, "fsl,imx6ul");
if (node >= 0) {
return true;
}
node = fdt_node_offset_by_compatible(fdt, -1, "fsl,imx6ull");
if (node >= 0) {
return true;
}
return false;
}
#define SYSCNT_CNTCR (0x0)
#define SYSCNT_CNTCR_ENABLE (1 << 0)
#define SYSCNT_CNTCR_HDBG (1 << 1)
#define SYSCNT_CNTCR_FCREQ(n) (1 << (8 + (n)))
#define SYSCNT_CNTFID(n) (0x20 + 4 * (n))
static uint32_t imx_syscnt_enable_and_return_frequency(const void *fdt)
{
uint32_t freq;
volatile void *syscnt_base;
/* That's not in the usual FDTs. Sorry for falling back to a magic value. */
if (imx_is_imx6(fdt)) {
syscnt_base = (void *)0x021dc000;
} else {
syscnt_base = (void *)0x306c0000;
}
freq = *(uint32_t *)(syscnt_base + SYSCNT_CNTFID(0));
arm_cp15_set_counter_frequency(freq);
*(uint32_t *)(syscnt_base + SYSCNT_CNTCR) =
SYSCNT_CNTCR_ENABLE |
SYSCNT_CNTCR_HDBG |
SYSCNT_CNTCR_FCREQ(0);
return freq;
}
void arm_generic_timer_get_config(
uint32_t *frequency,
uint32_t *irq
@@ -75,7 +130,11 @@ void arm_generic_timer_get_config(
if (val != NULL && len >= 4) {
*frequency = fdt32_to_cpu(val[0]);
} else {
bsp_fatal(IMX_FATAL_GENERIC_TIMER_FREQUENCY);
/*
* Normally clock-frequency would be provided by the boot loader. If it
* didn't add one, we have to initialize the system counter ourself.
*/
*frequency = imx_syscnt_enable_and_return_frequency(fdt);
}
/* FIXME: Figure out how Linux gets a proper IRQ number */

View File

@@ -123,6 +123,35 @@ arm_a9mpcore_start_enable_smp_in_auxiliary_control(void)
actlr |= ARM_CORTEX_A9_ACTL_SMP | ARM_CORTEX_A9_ACTL_FW;
arm_cp15_set_auxiliary_control(actlr);
}
BSP_START_TEXT_SECTION static inline void
arm_a9mpcore_start_errata_794072_handler(void)
{
uint32_t diag;
/*
* Workaround for Errata 794072: A short loop including a DMB instruction
* might cause a denial of service on another which executes a CP15 broadcast
* operation.
*/
diag = arm_cp15_get_diagnostic_control();
diag |= 1U << 4;
arm_cp15_set_diagnostic_control(diag);
}
BSP_START_TEXT_SECTION static inline void
arm_a9mpcore_start_errata_845369_handler(void)
{
uint32_t diag;
/*
* Workaround for Errata 845369: Under Very Rare Timing Circumstances
* Transition into Streaming Mode Might Create Data Corruption.
*/
diag = arm_cp15_get_diagnostic_control();
diag |= 1U << 22;
arm_cp15_set_diagnostic_control(diag);
}
#endif
BSP_START_TEXT_SECTION static inline void arm_a9mpcore_start_hook_0(void)
@@ -138,6 +167,8 @@ BSP_START_TEXT_SECTION static inline void arm_a9mpcore_start_hook_0(void)
}
#ifdef RTEMS_SMP
arm_a9mpcore_start_errata_794072_handler();
arm_a9mpcore_start_errata_845369_handler();
arm_a9mpcore_start_enable_smp_in_auxiliary_control();
#endif

View File

@@ -73,6 +73,10 @@ typedef struct {
.begin = (uint32_t) bsp_section_bss_begin, \
.end = (uint32_t) bsp_section_bss_end, \
.flags = ARMV7_MMU_DATA_READ_WRITE_CACHED \
}, { \
.begin = (uint32_t) bsp_section_rtemsstack_begin, \
.end = (uint32_t) bsp_section_rtemsstack_end, \
.flags = ARMV7_MMU_DATA_READ_WRITE_CACHED \
}, { \
.begin = (uint32_t) bsp_section_work_begin, \
.end = (uint32_t) bsp_section_work_end, \
@@ -95,7 +99,7 @@ typedef struct {
.flags = ARMV7_MMU_DATA_READ_WRITE_CACHED \
}
#define ARMV7_CP15_START_WORKSPACE_ENTRY_INDEX 8
#define ARMV7_CP15_START_WORKSPACE_ENTRY_INDEX 9
BSP_START_DATA_SECTION extern const arm_cp15_start_section_config
arm_cp15_start_mmu_config_table[];
@@ -119,7 +123,7 @@ arm_cp15_start_set_translation_table_entries(
pt = &ttb[ARM_MMU_TRANSLATION_TABLE_ENTRY_COUNT];
i = ARM_MMU_SMALL_PAGE_GET_INDEX(config->begin);
iend = ARM_MMU_SMALL_PAGE_GET_INDEX(ARM_MMU_SECT_MVA_ALIGN_UP(config->end));
iend = ARM_MMU_SMALL_PAGE_GET_INDEX(ARM_MMU_SMALL_PAGE_MVA_ALIGN_UP(config->end));
index_mask = (1U << (32 - ARM_MMU_SMALL_PAGE_BASE_SHIFT)) - 1U;
flags = ARM_MMU_SECT_FLAGS_TO_SMALL_PAGE(config->flags);

View File

@@ -0,0 +1,84 @@
/* SPDX-License-Identifier: BSD-2-Clause */
/*
* Copyright (C) 2021 Jan Sommer, German Aerospace Center (DLR)
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef LIBBSP_ARM_XILINX_ZYNQ_CADENCE_SPI_REGS_H
#define LIBBSP_ARM_XILINX_ZYNQ_CADENCE_SPI_REGS_H
#include <bsp/utility.h>
typedef struct {
uint32_t config;
#define CADENCE_SPI_CONFIG_MODEFAIL_EN BSP_BIT32(17)
#define CADENCE_SPI_CONFIG_MANSTRT BSP_BIT32(16)
#define CADENCE_SPI_CONFIG_MANSTRT_EN BSP_BIT32(15)
#define CADENCE_SPI_CONFIG_MANUAL_CS BSP_BIT32(14)
#define CADENCE_SPI_CONFIG_CS(val) BSP_FLD32(val, 10, 13)
#define CADENCE_SPI_CONFIG_CS_GET(reg) BSP_FLD32GET(reg, 10, 13)
#define CADENCE_SPI_CONFIG_CS_SET(reg, val) BSP_FLD32SET(reg, val, 10, 13)
#define CADENCE_SPI_CONFIG_PERI_SEL BSP_BIT32(9)
#define CADENCE_SPI_CONFIG_REF_CLK BSP_BIT32(8)
#define CADENCE_SPI_CONFIG_BAUD_DIV(val) BSP_FLD32(val, 3, 5)
#define CADENCE_SPI_CONFIG_BAUD_DIV_GET(reg) BSP_FLD32GET(reg, 3, 5)
#define CADENCE_SPI_CONFIG_BAUD_DIV_SET(reg, val) BSP_FLD32SET(reg, val, 3, 5)
#define CADENCE_SPI_CONFIG_CLK_PH BSP_BIT32(2)
#define CADENCE_SPI_CONFIG_CLK_POL BSP_BIT32(1)
#define CADENCE_SPI_CONFIG_MSTREN BSP_BIT32(0)
uint32_t irqstatus;
uint32_t irqenable;
uint32_t irqdisable;
uint32_t irqmask;
#define CADENCE_SPI_IXR_TXUF BSP_BIT32(6)
#define CADENCE_SPI_IXR_RXFULL BSP_BIT32(5)
#define CADENCE_SPI_IXR_RXNEMPTY BSP_BIT32(4)
#define CADENCE_SPI_IXR_TXFULL BSP_BIT32(3)
#define CADENCE_SPI_IXR_TXOW BSP_BIT32(2)
#define CADENCE_SPI_IXR_MODF BSP_BIT32(1)
#define CADENCE_SPI_IXR_RXOVR BSP_BIT32(0)
uint32_t spienable;
#define CADENCE_SPI_EN BSP_BIT32(0)
uint32_t delay;
#define CADENCE_SPI_DELAY_DNSS(val) BSP_FLD32(val, 24, 31)
#define CADENCE_SPI_DELAY_DNSS_GET(reg) BSP_FLD32GET(reg, 24, 31)
#define CADENCE_SPI_DELAY_DNSS_SET(reg, val) BSP_FLD32SET(reg, val, 24, 31)
#define CADENCE_SPI_DELAY_DBTWN(val) BSP_FLD32(val, 16, 23)
#define CADENCE_SPI_DELAY_DBTWN_GET(reg) BSP_FLD32GET(reg, 16, 23)
#define CADENCE_SPI_DELAY_DBTWN_SET(reg, val) BSP_FLD32SET(reg, val, 16, 23)
#define CADENCE_SPI_DELAY_DAFTER(val) BSP_FLD32(val, 8, 15)
#define CADENCE_SPI_DELAY_DAFTER_GET(reg) BSP_FLD32GET(reg, 8, 15)
#define CADENCE_SPI_DELAY_DAFTER_SET(reg, val) BSP_FLD32SET(reg, val, 8, 15)
#define CADENCE_SPI_DELAY_DINT(val) BSP_FLD32(val, 0, 7)
#define CADENCE_SPI_DELAY_DINT_GET(reg) BSP_FLD32GET(reg, 0, 7)
#define CADENCE_SPI_DELAY_DINT_SET(reg, val) BSP_FLD32SET(reg, val, 0, 7)
uint32_t txdata;
uint32_t rxdata;
uint32_t slave_idle_count;
uint32_t txthreshold;
uint32_t rxthreshold;
uint32_t moduleid;
} cadence_spi;
#endif /* LIBBSP_ARM_XILINX_ZYNQ_CADENCE_SPI_REGS_H */

View File

@@ -0,0 +1,63 @@
/* SPDX-License-Identifier: BSD-2-Clause */
/*
* Copyright (C) 2021 Jan Sommer, German Aerospace Center (DLR)
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef LIBBSP_ARM_XILINX_ZYNQ_CADENCE_SPI_H
#define LIBBSP_ARM_XILINX_ZYNQ_CADENCE_SPI_H
#include <rtems.h>
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
/**
* Register the cadence-spi device with rtems
*
* @param bus_path path of the new device (e.g. /dev/spi0)
* @register_base Address of the first (i.e. config) register
* @input_clock Configured frequency of the input clock
*
* @return RTEMS_SUCCESSFUL on success, negative number on failure
*
* Note: The spi frequencies the cadence spi device can achieve
* are the @p input_clock divided by a power of 2 between
* 4 and 256.
* The driver tries to find a divider which yields a spi
* frequency equal to or lower than the desired bus frequency.
*/
int spi_bus_register_cadence(
const char *bus_path,
uintptr_t register_base,
uint32_t input_clock,
rtems_vector_number irq
);
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif /* LIBBSP_ARM_XILINX_ZYNQ_CADENCE_SPI_H */

View File

@@ -90,6 +90,10 @@ LINKER_SYMBOL(bsp_section_bss_begin)
LINKER_SYMBOL(bsp_section_bss_end)
LINKER_SYMBOL(bsp_section_bss_size)
LINKER_SYMBOL(bsp_section_rtemsstack_begin)
LINKER_SYMBOL(bsp_section_rtemsstack_end)
LINKER_SYMBOL(bsp_section_rtemsstack_size)
LINKER_SYMBOL(bsp_section_work_begin)
LINKER_SYMBOL(bsp_section_work_end)
LINKER_SYMBOL(bsp_section_work_size)

View File

@@ -0,0 +1,88 @@
/* SPDX-License-Identifier: BSD-2-Clause */
/*
* Copyright (C) 2021 Jan Sommer, German Aerospace Center (DLR)
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef LIBBSP_ARM_XILINX_AXI_SPI_REGS_H
#define LIBBSP_ARM_XILINX_AXI_SPI_REGS_H
#include <bsp/utility.h>
typedef struct {
uint32_t reserved1[7];
uint32_t globalirq;
#define XILINX_AXI_SPI_GLOBAL_IRQ_ENABLE BSP_BIT32(31)
uint32_t irqstatus;
uint32_t reserved2;
uint32_t irqenable;
#define XILINX_AXI_SPI_IRQ_CMD_ERR BSP_BIT32(13)
#define XILINX_AXI_SPI_IRQ_LOOP_ERR BSP_BIT32(12)
#define XILINX_AXI_SPI_IRQ_MSB_ERR BSP_BIT32(11)
#define XILINX_AXI_SPI_IRQ_SLV_ERR BSP_BIT32(10)
#define XILINX_AXI_SPI_IRQ_CPOL_CPHA_ERR BSP_BIT32(9)
#define XILINX_AXI_SPI_IRQ_RXNEMPTY BSP_BIT32(8)
#define XILINX_AXI_SPI_IRQ_CS_MODE BSP_BIT32(7)
#define XILINX_AXI_SPI_IRQ_TXHALF BSP_BIT32(6)
#define XILINX_AXI_SPI_IRQ_RXOVR BSP_BIT32(5)
#define XILINX_AXI_SPI_IRQ_RXFULL BSP_BIT32(4)
#define XILINX_AXI_SPI_IRQ_TXUF BSP_BIT32(3)
#define XILINX_AXI_SPI_IRQ_TXEMPTY BSP_BIT32(2)
#define XILINX_AXI_SPI_IRQ_SLV_MODF BSP_BIT32(1)
#define XILINX_AXI_SPI_IRQ_MODF BSP_BIT32(0)
uint32_t reserved3[5];
uint32_t reset;
#define XILINX_AXI_SPI_RESET 0x0000000a
uint32_t reserved4[7];
uint32_t control;
#define XILINX_AXI_SPI_CONTROL_LSBFIRST BSP_BIT32(9)
#define XILINX_AXI_SPI_CONTROL_MST_TRANS_INHIBIT BSP_BIT32(8)
#define XILINX_AXI_SPI_CONTROL_MANUAL_CS BSP_BIT32(7)
#define XILINX_AXI_SPI_CONTROL_RX_FIFO_RESET BSP_BIT32(6)
#define XILINX_AXI_SPI_CONTROL_TX_FIFO_RESET BSP_BIT32(5)
#define XILINX_AXI_SPI_CONTROL_CPHA BSP_BIT32(4)
#define XILINX_AXI_SPI_CONTROL_CPOL BSP_BIT32(3)
#define XILINX_AXI_SPI_CONTROL_MSTREN BSP_BIT32(2)
#define XILINX_AXI_SPI_CONTROL_SPIEN BSP_BIT32(1)
#define XILINX_AXI_SPI_CONTROL_LOOP BSP_BIT32(0)
uint32_t status;
#define XILINX_AXI_SPI_STATUS_CMD_ERR BSP_BIT32(10)
#define XILINX_AXI_SPI_STATUS_LOOP_ERR BSP_BIT32(9)
#define XILINX_AXI_SPI_STATUS_MSB_ERR BSP_BIT32(8)
#define XILINX_AXI_SPI_STATUS_SLV_ERR BSP_BIT32(7)
#define XILINX_AXI_SPI_STATUS_CPOL_CPHA_ERR BSP_BIT32(6)
#define XILINX_AXI_SPI_STATUS_SLV_MODE BSP_BIT32(5)
#define XILINX_AXI_SPI_STATUS_MODF BSP_BIT32(4)
#define XILINX_AXI_SPI_STATUS_TXFULL BSP_BIT32(3)
#define XILINX_AXI_SPI_STATUS_TXEMPTY BSP_BIT32(2)
#define XILINX_AXI_SPI_STATUS_RXFULL BSP_BIT32(1)
#define XILINX_AXI_SPI_STATUS_RXEMPTY BSP_BIT32(0)
uint32_t txdata;
uint32_t rxdata;
uint32_t cs;
uint32_t tx_fifo_len;
uint32_t rx_fifo_len;
} xilinx_axi_spi;
#endif /* LIBBSP_ARM_XILINX_AXI_SPI_REGS_H */

View File

@@ -0,0 +1,67 @@
/* SPDX-License-Identifier: BSD-2-Clause */
/*
* Copyright (C) 2021 Jan Sommer, German Aerospace Center (DLR)
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef LIBBSP_ARM_XILINX_AXI_SPI_H
#define LIBBSP_ARM_XILINX_AXI_SPI_H
#include <rtems.h>
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
/**
* Register Xilinx AXI SPI device
*
* Note:
* The Xilinx Quad SPI device is very versatile and
* supports many options. This driver assumes the
* following setup:
* - Standard SPI mode and AXI Lite interface
* - FIFO available (driver might also work without FIFOs)
*
* @param bus_path path for the new device node (e.g. "/dev/spi0")
* @param register_base base address of the device
* @param fifo_size Configured fifo size. Either 0, 16 or 256
* @param num_cs Number of configured CS lines (0-32)
*
* @return 0 on success. Negative number otherwise.
*
*/
int spi_bus_register_xilinx_axi(
const char *bus_path,
uintptr_t register_base,
uint32_t fifo_size,
uint32_t num_cs,
rtems_vector_number irq
);
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif /* LIBBSP_ARM_XILINX_AXI_SPI_H */

View File

@@ -71,6 +71,13 @@ void zynq_uart_write_polled(
*/
void zynq_uart_reset_tx_flush(zynq_uart_context *ctx);
int zynq_cal_baud_rate(
uint32_t baudrate,
uint32_t* brgr,
uint32_t* bauddiv,
uint32_t modereg
);
#ifdef __cplusplus
}
#endif /* __cplusplus */

View File

@@ -40,7 +40,7 @@ uint32_t zynq_uart_input_clock(void)
return ZYNQ_CLOCK_UART;
}
static int zynq_cal_baud_rate(uint32_t baudrate,
int zynq_cal_baud_rate(uint32_t baudrate,
uint32_t* brgr,
uint32_t* bauddiv,
uint32_t modereg)
@@ -122,6 +122,8 @@ void zynq_uart_initialize(rtems_termios_device_context *base)
uint32_t brgr = 0x3e;
uint32_t bauddiv = 0x6;
zynq_uart_reset_tx_flush(ctx);
zynq_cal_baud_rate(ZYNQ_UART_DEFAULT_BAUD, &brgr, &bauddiv, regs->mode);
regs->control &= ~(ZYNQ_UART_CONTROL_RXEN | ZYNQ_UART_CONTROL_TXEN);

View File

@@ -142,25 +142,82 @@ static bool zynq_uart_set_attributes(
const struct termios *term
)
{
#if 0
volatile zynq_uart *regs = zynq_uart_get_regs(minor);
zynq_uart_context *ctx = (zynq_uart_context *) context;
volatile zynq_uart *regs = ctx->regs;
int32_t baud;
uint32_t brgr = 0;
uint32_t bauddiv = 0;
uint32_t mode = 0;
int rc;
rc = zynq_cal_baud_rate(115200, &brgr, &bauddiv, regs->mode);
if (rc != 0)
return rc;
/*
* Determine the baud rate
*/
baud = rtems_termios_baud_to_number(term->c_ospeed);
if (baud > 0) {
rc = zynq_cal_baud_rate(baud, &brgr, &bauddiv, regs->mode);
if (rc != 0)
return rc;
}
/*
* Configure the mode register
*/
mode |= ZYNQ_UART_MODE_CHMODE(ZYNQ_UART_MODE_CHMODE_NORMAL);
/*
* Parity
*/
mode |= ZYNQ_UART_MODE_PAR(ZYNQ_UART_MODE_PAR_NONE);
if (term->c_cflag & PARENB) {
if (!(term->c_cflag & PARODD)) {
mode |= ZYNQ_UART_MODE_PAR(ZYNQ_UART_MODE_PAR_ODD);
} else {
mode |= ZYNQ_UART_MODE_PAR(ZYNQ_UART_MODE_PAR_EVEN);
}
}
/*
* Character Size
*/
switch (term->c_cflag & CSIZE)
{
case CS5:
return false;
case CS6:
mode |= ZYNQ_UART_MODE_CHRL(ZYNQ_UART_MODE_CHRL_6);
break;
case CS7:
mode |= ZYNQ_UART_MODE_CHRL(ZYNQ_UART_MODE_CHRL_7);
break;
case CS8:
default:
mode |= ZYNQ_UART_MODE_CHRL(ZYNQ_UART_MODE_CHRL_8);
break;
}
/*
* Stop Bits
*/
if (term->c_cflag & CSTOPB) {
/* 2 stop bits */
mode |= ZYNQ_UART_MODE_NBSTOP(ZYNQ_UART_MODE_NBSTOP_STOP_2);
} else {
/* 1 stop bit */
mode |= ZYNQ_UART_MODE_NBSTOP(ZYNQ_UART_MODE_NBSTOP_STOP_1);
}
regs->control &= ~(ZYNQ_UART_CONTROL_RXEN | ZYNQ_UART_CONTROL_TXEN);
regs->baud_rate_gen = ZYNQ_UART_BAUD_RATE_GEN_CD(brgr);
regs->baud_rate_div = ZYNQ_UART_BAUD_RATE_DIV_BDIV(bauddiv);
regs->mode = mode;
/* Ignore baud rate of B0. There are no modem control lines to de-assert */
if (baud > 0) {
regs->baud_rate_gen = ZYNQ_UART_BAUD_RATE_GEN_CD(brgr);
regs->baud_rate_div = ZYNQ_UART_BAUD_RATE_DIV_BDIV(bauddiv);
}
regs->control |= ZYNQ_UART_CONTROL_RXEN | ZYNQ_UART_CONTROL_TXEN;
return true;
#else
return false;
#endif
}
const rtems_termios_device_handler zynq_uart_handler = {

View File

@@ -0,0 +1,444 @@
/* SPDX-License-Identifier: BSD-2-Clause */
/*
* Copyright (C) 2021 Jan Sommer, German Aerospace Center (DLR)
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include <bsp.h>
#include <rtems/irq-extension.h>
#include <sys/param.h> /* MAX() */
#include <dev/spi/spi.h>
#include <bsp/cadence-spi.h>
#include <bsp/cadence-spi-regs.h>
#define CADENCE_SPI_FIFO_SIZE 128
#define CADENCE_SPI_MAX_CHIPSELECTS 3
#define CADENCE_SPI_CS_NONE 0xF
typedef struct cadence_spi_bus cadence_spi_bus;
struct cadence_spi_bus {
spi_bus base;
volatile cadence_spi *regs;
uint32_t clk_in;
uint16_t clk_per_usecs;
uint32_t msg_todo;
const spi_ioc_transfer *msg;
uint32_t todo;
uint32_t in_transfer;
uint8_t *rx_buf;
const uint8_t *tx_buf;
rtems_id task_id;
rtems_vector_number irq;
};
static void cadence_spi_disable_interrupts(volatile cadence_spi *regs)
{
regs->irqdisable = 0xffff;
}
static void cadence_spi_clear_irq_status(volatile cadence_spi *regs)
{
regs->irqstatus = regs->irqstatus;
}
static bool cadence_spi_rx_fifo_not_empty(volatile cadence_spi *regs)
{
return (regs->irqstatus & CADENCE_SPI_IXR_RXNEMPTY) != 0;
}
static void cadence_spi_reset(cadence_spi_bus *bus)
{
volatile cadence_spi *regs = bus->regs;
uint32_t val;
cadence_spi_disable_interrupts(regs);
regs->spienable = 0;
val = regs->config;
val &= ~(CADENCE_SPI_CONFIG_MODEFAIL_EN
| CADENCE_SPI_CONFIG_MANSTRT_EN
| CADENCE_SPI_CONFIG_MANUAL_CS
| CADENCE_SPI_CONFIG_PERI_SEL
| CADENCE_SPI_CONFIG_REF_CLK);
val |= CADENCE_SPI_CONFIG_CS(CADENCE_SPI_CS_NONE)
| CADENCE_SPI_CONFIG_MSTREN
| CADENCE_SPI_CONFIG_MANSTRT;
regs->config = val;
/* Initialize here, will be set for every transfer */
regs->txthreshold = 1;
/* Set to 1, so we can check when the rx buffer is empty */
regs->rxthreshold = 1;
while (cadence_spi_rx_fifo_not_empty(regs)) {
regs->rxdata;
}
cadence_spi_clear_irq_status(regs);
}
static void cadence_spi_done(cadence_spi_bus *bus)
{
volatile cadence_spi *regs = bus->regs;
regs->spienable = 0;
cadence_spi_disable_interrupts(regs);
cadence_spi_clear_irq_status(regs);
rtems_event_transient_send(bus->task_id);
}
static void cadence_spi_push(cadence_spi_bus *bus, volatile cadence_spi *regs)
{
while (bus->todo > 0 && bus->in_transfer < CADENCE_SPI_FIFO_SIZE) {
uint8_t val = 0;
if (bus->tx_buf != NULL) {
val = *bus->tx_buf;
++bus->tx_buf;
}
--bus->todo;
regs->txdata = val;
++bus->in_transfer;
}
}
static void
cadence_spi_set_chipsel(cadence_spi_bus *bus, uint32_t cs)
{
volatile cadence_spi *regs = bus->regs;
uint32_t cs_bit = CADENCE_SPI_CS_NONE;
uint32_t config = regs->config;
if (cs != SPI_NO_CS && cs < CADENCE_SPI_MAX_CHIPSELECTS) {
cs_bit >>= (CADENCE_SPI_MAX_CHIPSELECTS - cs + 1);
}
config = CADENCE_SPI_CONFIG_CS_SET(config, cs_bit);
bus->base.cs = cs;
regs->config = config;
}
static uint32_t
cadence_spi_baud_divider(cadence_spi_bus *bus,
uint32_t speed_hz)
{
uint32_t div;
uint32_t clk_in;
clk_in = bus->clk_in;
div = clk_in / speed_hz;
div = fls((int) div);
if (clk_in > (speed_hz << div)) {
++div;
}
/* The baud divider needs to be at least 4, i.e. 2^2 */
div = MAX(2, div);
/* 0b111 is the maximum possible divider value */
div = MIN(7, div-1);
return div;
}
static void cadence_spi_config(
cadence_spi_bus *bus,
volatile cadence_spi *regs,
uint32_t speed_hz,
uint32_t mode,
uint16_t delay_usecs,
uint8_t cs
)
{
spi_bus *base = &bus->base;
uint32_t config = regs->config;
uint32_t delay;
regs->spienable = 0;
if ((mode & SPI_CPHA) != 0) {
config |= CADENCE_SPI_CONFIG_CLK_PH;
} else {
config &= ~CADENCE_SPI_CONFIG_CLK_PH;
}
if ((mode & SPI_CPOL) != 0) {
config |= CADENCE_SPI_CONFIG_CLK_POL;
} else {
config &= ~CADENCE_SPI_CONFIG_CLK_POL;
}
config = CADENCE_SPI_CONFIG_BAUD_DIV_SET(config,
cadence_spi_baud_divider(bus, speed_hz));
regs->config = config;
cadence_spi_set_chipsel(bus, cs);
delay = regs->delay;
delay = CADENCE_SPI_DELAY_DBTWN_SET(delay, delay_usecs * bus->clk_per_usecs);
regs->delay = delay;
base->speed_hz = speed_hz;
base->mode = mode;
base->cs = cs;
}
static void
cadence_spi_next_msg(cadence_spi_bus *bus, volatile cadence_spi *regs)
{
if (bus->msg_todo > 0) {
const spi_ioc_transfer *msg;
spi_bus *base = &bus->base;
msg = bus->msg;
if (
msg->speed_hz != base->speed_hz
|| msg->mode != base->mode
|| msg->cs != base->cs
) {
cadence_spi_config(
bus,
regs,
msg->speed_hz,
msg->mode,
msg->delay_usecs,
msg->cs
);
}
if ((msg->mode & SPI_NO_CS) != 0) {
cadence_spi_set_chipsel(bus, CADENCE_SPI_CS_NONE);
}
bus->todo = msg->len;
bus->rx_buf = msg->rx_buf;
bus->tx_buf = msg->tx_buf;
cadence_spi_push(bus, regs);
cadence_spi_disable_interrupts(regs);
if (bus->todo < CADENCE_SPI_FIFO_SIZE) {
/* if the msg fits into the FIFO for empty TX buffer */
regs->txthreshold = 1;
} else {
/* if the msg does not fit refill tx_buf when the threshold is hit */
regs->txthreshold = CADENCE_SPI_FIFO_SIZE / 2;
}
regs->irqenable = CADENCE_SPI_IXR_TXOW;
regs->spienable = 1;
} else {
cadence_spi_done(bus);
}
}
static void cadence_spi_interrupt(void *arg)
{
cadence_spi_bus *bus;
volatile cadence_spi *regs;
bus = arg;
regs = bus->regs;
/* The RXNEMPTY flag is sometimes not cleared fast
* enough between 2 reads which could lead to
* reading an extra byte erroneously. Therefore,
* also check the in_transfer counter
*/
while (cadence_spi_rx_fifo_not_empty(regs)
&& bus->in_transfer > 0) {
uint32_t val = regs->rxdata;
if (bus->rx_buf != NULL) {
*bus->rx_buf = (uint8_t)val;
++bus->rx_buf;
}
--bus->in_transfer;
}
if (bus->todo > 0) {
cadence_spi_push(bus, regs);
} else if (bus->in_transfer > 0) {
/* Wait until all bytes have been transfered */
regs->txthreshold = 1;
} else {
--bus->msg_todo;
++bus->msg;
cadence_spi_next_msg(bus, regs);
}
}
static int cadence_spi_check_messages(
cadence_spi_bus *bus,
const spi_ioc_transfer *msg,
uint32_t size)
{
while(size > 0) {
if (msg->bits_per_word != 8) {
return -EINVAL;
}
if ((msg->mode &
~(SPI_CPHA | SPI_CPOL | SPI_NO_CS)) != 0) {
return -EINVAL;
}
if ((msg->mode & SPI_NO_CS) == 0 &&
(msg->cs > CADENCE_SPI_MAX_CHIPSELECTS)) {
return -EINVAL;
}
++msg;
--size;
}
return 0;
}
static int cadence_spi_transfer(
spi_bus *base,
const spi_ioc_transfer *msgs,
uint32_t n
)
{
cadence_spi_bus *bus;
int rv;
bus = (cadence_spi_bus *) base;
rv = cadence_spi_check_messages(bus, msgs, n);
if (rv == 0) {
bus->msg_todo = n;
bus->msg = &msgs[0];
bus->task_id = rtems_task_self();
cadence_spi_next_msg(bus, bus->regs);
rtems_event_transient_receive(RTEMS_WAIT, RTEMS_NO_TIMEOUT);
cadence_spi_set_chipsel(bus, CADENCE_SPI_CS_NONE);
}
return rv;
}
static void cadence_spi_destroy(spi_bus *base)
{
cadence_spi_bus *bus;
bus = (cadence_spi_bus *) base;
rtems_interrupt_handler_remove(bus->irq, cadence_spi_interrupt, bus);
spi_bus_destroy_and_free(&bus->base);
}
static int cadence_spi_setup(spi_bus *base)
{
cadence_spi_bus *bus;
uint32_t mode = base->mode;
bus = (cadence_spi_bus *) base;
/* Baud rate divider is at least 4 and at most 256 */
if (
base->speed_hz > base->max_speed_hz
|| base->speed_hz < (bus->clk_in / 256)
|| bus->base.bits_per_word > 8
) {
return -EINVAL;
}
/* SPI_CS_HIGH and SPI_LOOP not supported */
if ((mode & SPI_CS_HIGH) || (mode & SPI_LOOP)) {
return -EINVAL;
}
cadence_spi_config(
bus,
bus->regs,
base->speed_hz,
base->mode,
base->delay_usecs,
base->cs
);
return 0;
}
int spi_bus_register_cadence(const char *bus_path,
uintptr_t register_base,
uint32_t input_clock,
rtems_vector_number irq)
{
cadence_spi_bus *bus;
spi_bus *base;
int sc;
bus = (cadence_spi_bus *) spi_bus_alloc_and_init(sizeof(*bus));
if (bus == NULL){
return -1;
}
base = &bus->base;
bus->regs = (volatile cadence_spi *) register_base;
bus->clk_in = input_clock;
bus->clk_per_usecs = input_clock / 1000000;
bus->irq = irq;
/* The minimum clock divider is 4 */
base->max_speed_hz = (input_clock + 3) / 4;
base->delay_usecs = 0;
base->speed_hz = base->max_speed_hz;
base->cs = SPI_NO_CS;
cadence_spi_reset(bus);
cadence_spi_config(
bus,
bus->regs,
base->speed_hz,
base->mode,
base->delay_usecs,
base->cs
);
sc = rtems_interrupt_handler_install(
bus->irq,
"CASPI",
RTEMS_INTERRUPT_UNIQUE,
cadence_spi_interrupt,
bus
);
if (sc != RTEMS_SUCCESSFUL) {
(*bus->base.destroy)(&bus->base);
rtems_set_errno_and_return_minus_one(EAGAIN);
}
bus->base.transfer = cadence_spi_transfer;
bus->base.destroy = cadence_spi_destroy;
bus->base.setup = cadence_spi_setup;
return spi_bus_register(&bus->base, bus_path);
}

View File

@@ -0,0 +1,402 @@
/* SPDX-License-Identifier: BSD-2-Clause */
/*
* Copyright (C) 2021 Jan Sommer, German Aerospace Center (DLR)
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include <bsp.h>
#include <rtems/irq-extension.h>
#include <sys/param.h> /* MAX() */
#include <dev/spi/spi.h>
#include <bsp/xilinx-axi-spi.h>
#include <bsp/xilinx-axi-spi-regs.h>
#define XILINX_AXI_SPI_CS_NONE 0xFF
typedef struct xilinx_axi_spi_bus xilinx_axi_spi_bus;
struct xilinx_axi_spi_bus {
spi_bus base;
volatile xilinx_axi_spi *regs;
uint32_t fifo_size;
uint32_t num_cs;
uint32_t msg_todo;
const spi_ioc_transfer *msg;
uint32_t todo;
uint32_t in_transfer;
uint8_t *rx_buf;
const uint8_t *tx_buf;
rtems_id task_id;
rtems_vector_number irq;
};
static void xilinx_axi_spi_disable_interrupts(volatile xilinx_axi_spi *regs)
{
regs->globalirq = 0;
regs->irqenable = 0;
}
static bool xilinx_axi_spi_rx_fifo_not_empty(volatile xilinx_axi_spi *regs)
{
return (regs->status & XILINX_AXI_SPI_STATUS_RXEMPTY) == 0;
}
static void xilinx_axi_spi_reset(xilinx_axi_spi_bus *bus)
{
volatile xilinx_axi_spi *regs = bus->regs;
uint32_t control;
/* Initiate soft reset for initial state */
regs->reset = XILINX_AXI_SPI_RESET;
/* Configure as master */
control = regs->control;
control |= XILINX_AXI_SPI_CONTROL_MSTREN;
regs->control = control;
}
static void xilinx_axi_spi_done(xilinx_axi_spi_bus *bus)
{
volatile xilinx_axi_spi *regs = bus->regs;
uint32_t control = regs->control;
control &= ~XILINX_AXI_SPI_CONTROL_SPIEN;
regs->control = control;
xilinx_axi_spi_disable_interrupts(regs);
rtems_event_transient_send(bus->task_id);
}
static void xilinx_axi_spi_push(xilinx_axi_spi_bus *bus, volatile xilinx_axi_spi *regs)
{
while (bus->todo > 0 && bus->in_transfer < bus->fifo_size) {
uint8_t val = 0;
if (bus->tx_buf != NULL) {
val = *bus->tx_buf;
++bus->tx_buf;
}
--bus->todo;
regs->txdata = val;
++bus->in_transfer;
}
}
static void
xilinx_axi_spi_set_chipsel(xilinx_axi_spi_bus *bus, uint32_t cs)
{
volatile xilinx_axi_spi *regs = bus->regs;
uint32_t cs_bit = XILINX_AXI_SPI_CS_NONE;
if (cs != SPI_NO_CS && cs < bus->num_cs) {
cs_bit &= ~(1<<cs);
}
bus->base.cs = cs;
regs->cs = cs_bit;
}
static void xilinx_axi_spi_config(
xilinx_axi_spi_bus *bus,
volatile xilinx_axi_spi *regs,
uint32_t mode,
uint8_t cs
)
{
spi_bus *base = &bus->base;
uint32_t control = regs->control;
control &= ~XILINX_AXI_SPI_CONTROL_SPIEN;
regs->control = control;
if ((mode & SPI_CPHA) != 0) {
control |= XILINX_AXI_SPI_CONTROL_CPHA;
} else {
control &= ~XILINX_AXI_SPI_CONTROL_CPHA;
}
if ((mode & SPI_CPOL) != 0) {
control |= XILINX_AXI_SPI_CONTROL_CPOL;
} else {
control &= ~XILINX_AXI_SPI_CONTROL_CPOL;
}
if ((mode & SPI_LOOP) != 0) {
control |= XILINX_AXI_SPI_CONTROL_LOOP;
} else {
control &= ~XILINX_AXI_SPI_CONTROL_LOOP;
}
regs->control = control;
xilinx_axi_spi_set_chipsel(bus, cs);
base->mode = mode;
base->cs = cs;
}
static void
xilinx_axi_spi_next_msg(xilinx_axi_spi_bus *bus, volatile xilinx_axi_spi *regs)
{
uint32_t control = regs->control;
control |= XILINX_AXI_SPI_CONTROL_MST_TRANS_INHIBIT
| XILINX_AXI_SPI_CONTROL_RX_FIFO_RESET
| XILINX_AXI_SPI_CONTROL_TX_FIFO_RESET;
regs->control = control;
if (bus->msg_todo > 0) {
const spi_ioc_transfer *msg;
spi_bus *base = &bus->base;
msg = bus->msg;
if (
msg->mode != base->mode
|| msg->cs != base->cs
) {
xilinx_axi_spi_config(
bus,
regs,
msg->mode,
msg->cs
);
}
if ((msg->mode & SPI_NO_CS) != 0) {
xilinx_axi_spi_set_chipsel(bus, XILINX_AXI_SPI_CS_NONE);
}
bus->todo = msg->len;
bus->rx_buf = msg->rx_buf;
bus->tx_buf = msg->tx_buf;
xilinx_axi_spi_push(bus, regs);
xilinx_axi_spi_disable_interrupts(regs);
if (
bus->todo < bus->fifo_size
|| bus->fifo_size == 1) {
/* if the msg fits into the FIFO, wait for empty TX buffer */
regs->irqenable = XILINX_AXI_SPI_IRQ_TXEMPTY;
} else {
/* if the msg does not fit, refill tx_buf when the tx FIFO is half empty */
regs->irqenable = XILINX_AXI_SPI_IRQ_TXHALF;
}
regs->globalirq = XILINX_AXI_SPI_GLOBAL_IRQ_ENABLE;
control = regs->control;
control |= XILINX_AXI_SPI_CONTROL_SPIEN;
control &= ~XILINX_AXI_SPI_CONTROL_MST_TRANS_INHIBIT;
regs->control = control;
} else {
xilinx_axi_spi_done(bus);
}
}
static void xilinx_axi_spi_interrupt(void *arg)
{
xilinx_axi_spi_bus *bus;
volatile xilinx_axi_spi *regs;
bus = arg;
regs = bus->regs;
/* Clear interrupt flag. It's safe, since only one IRQ active at a time */
regs->irqstatus = regs->irqenable;
while (xilinx_axi_spi_rx_fifo_not_empty(regs)) {
uint32_t val = regs->rxdata;
if (bus->rx_buf != NULL) {
*bus->rx_buf = (uint8_t)val;
++bus->rx_buf;
}
--bus->in_transfer;
}
if (bus->todo > 0) {
xilinx_axi_spi_push(bus, regs);
} else if (bus->in_transfer > 0) {
/* Wait until all bytes have been transfered */
regs->irqenable = XILINX_AXI_SPI_IRQ_TXEMPTY;
} else {
--bus->msg_todo;
++bus->msg;
xilinx_axi_spi_next_msg(bus, regs);
}
}
static int xilinx_axi_spi_check_messages(
xilinx_axi_spi_bus *bus,
const spi_ioc_transfer *msg,
uint32_t size)
{
while(size > 0) {
if (msg->bits_per_word != 8) {
return -EINVAL;
}
if ((msg->mode &
~(SPI_CPHA | SPI_CPOL | SPI_NO_CS)) != 0) {
return -EINVAL;
}
if ((msg->mode & SPI_NO_CS) == 0 &&
(msg->cs > bus->num_cs)) {
return -EINVAL;
}
++msg;
--size;
}
return 0;
}
static int xilinx_axi_spi_transfer(
spi_bus *base,
const spi_ioc_transfer *msgs,
uint32_t n
)
{
xilinx_axi_spi_bus *bus;
int rv;
bus = (xilinx_axi_spi_bus *) base;
rv = xilinx_axi_spi_check_messages(bus, msgs, n);
if (rv == 0) {
bus->msg_todo = n;
bus->msg = &msgs[0];
bus->task_id = rtems_task_self();
xilinx_axi_spi_next_msg(bus, bus->regs);
rtems_event_transient_receive(RTEMS_WAIT, RTEMS_NO_TIMEOUT);
xilinx_axi_spi_set_chipsel(bus, XILINX_AXI_SPI_CS_NONE);
}
return rv;
}
static void xilinx_axi_spi_destroy(spi_bus *base)
{
xilinx_axi_spi_bus *bus;
bus = (xilinx_axi_spi_bus *) base;
rtems_interrupt_handler_remove(bus->irq, xilinx_axi_spi_interrupt, bus);
spi_bus_destroy_and_free(&bus->base);
}
static int xilinx_axi_spi_setup(spi_bus *base)
{
xilinx_axi_spi_bus *bus;
uint32_t mode = base->mode;
bus = (xilinx_axi_spi_bus *) base;
if (bus->base.bits_per_word > 8) {
return -EINVAL;
}
/* SPI_CS_HIGH not supported */
if (mode & SPI_CS_HIGH) {
return -EINVAL;
}
xilinx_axi_spi_config(
bus,
bus->regs,
base->mode,
base->cs
);
return 0;
}
int spi_bus_register_xilinx_axi(
const char *bus_path,
uintptr_t register_base,
uint32_t fifo_size,
uint32_t num_cs,
rtems_vector_number irq)
{
xilinx_axi_spi_bus *bus;
spi_bus *base;
int sc;
if (fifo_size != 0 && fifo_size != 16 && fifo_size != 256) {
return -1;
}
if (num_cs > 32) {
return -1;
}
bus = (xilinx_axi_spi_bus *) spi_bus_alloc_and_init(sizeof(*bus));
if (bus == NULL){
return -1;
}
base = &bus->base;
bus->regs = (volatile xilinx_axi_spi *) register_base;
bus->irq = irq;
bus->num_cs = num_cs;
/* For operation without FIFO set fifo_size to 1
* so that comparison operators work
*/
if (fifo_size == 0) {
bus->fifo_size = 1;
} else {
bus->fifo_size = fifo_size;
}
base->cs = SPI_NO_CS;
xilinx_axi_spi_reset(bus);
xilinx_axi_spi_config(
bus,
bus->regs,
base->mode,
base->cs
);
sc = rtems_interrupt_handler_install(
bus->irq,
"XSPI",
RTEMS_INTERRUPT_UNIQUE,
xilinx_axi_spi_interrupt,
bus
);
if (sc != RTEMS_SUCCESSFUL) {
(*bus->base.destroy)(&bus->base);
rtems_set_errno_and_return_minus_one(EAGAIN);
}
bus->base.transfer = xilinx_axi_spi_transfer;
bus->base.destroy = xilinx_axi_spi_destroy;
bus->base.setup = xilinx_axi_spi_setup;
return spi_bus_register(&bus->base, bus_path);
}

View File

@@ -34,6 +34,7 @@ include_grlib_HEADERS += ../../bsps/include/grlib/apbuart_termios.h
include_grlib_HEADERS += ../../bsps/include/grlib/b1553brm.h
include_grlib_HEADERS += ../../bsps/include/grlib/b1553rt.h
include_grlib_HEADERS += ../../bsps/include/grlib/bspcommon.h
include_grlib_HEADERS += ../../bsps/include/grlib/canbtrs.h
include_grlib_HEADERS += ../../bsps/include/grlib/canmux.h
include_grlib_HEADERS += ../../bsps/include/grlib/cons.h
include_grlib_HEADERS += ../../bsps/include/grlib/debug_defs.h

View File

@@ -104,48 +104,60 @@ static uint32_t pc386_get_timecount_i8254(struct timecounter *tc)
/*
* Calibrate CPU cycles per tick. Interrupts should be disabled.
* Will also set the PIT, so call this before registering the
* periodic timer for rtems tick generation
*/
static void calibrate_tsc(void)
{
uint64_t begin_time;
uint8_t then_lsb, then_msb, now_lsb, now_msb;
uint32_t i;
uint8_t lsb, msb;
uint32_t max_timer_value;
uint32_t last_tick, cur_tick;
int32_t diff, remaining;
/*
* We just reset the timer, so we know we're at the beginning of a tick.
*/
/*
* Count cycles. Watching the timer introduces a several microsecond
* uncertaintity, so let it cook for a while and divide by the number of
* ticks actually executed.
*/
/* Set the timer to free running mode */
outport_byte(TIMER_MODE, TIMER_SEL0 | TIMER_16BIT | TIMER_INTTC);
/* Reset the 16 timer reload value, first LSB, then MSB */
outport_byte(TIMER_CNTR0, 0);
outport_byte(TIMER_CNTR0, 0);
/* We use the full 16 bit */
max_timer_value = 0xffff;
/* Calibrate for 1s, i.e. TIMER_TICK PIT ticks */
remaining = TIMER_TICK;
begin_time = rdtsc();
for (i = rtems_clock_get_ticks_per_second() * pc386_isrs_per_tick;
i != 0; --i ) {
/* We know we've just completed a tick when timer goes from low to high */
then_lsb = then_msb = 0xff;
do {
READ_8254(now_lsb, now_msb);
if ((then_msb < now_msb) ||
((then_msb == now_msb) && (then_lsb < now_lsb)))
break;
then_lsb = now_lsb;
then_msb = now_msb;
} while (1);
READ_8254(lsb, msb);
last_tick = (msb << 8) | lsb;
while(remaining > 0) {
READ_8254(lsb, msb);
cur_tick = (msb << 8) | lsb;
/* PIT counts down, so subtract cur from last */
diff = last_tick - cur_tick;
last_tick = cur_tick;
if (diff < 0) {
diff += max_timer_value;
}
remaining -= diff;
}
pc586_tsc_frequency = rdtsc() - begin_time;
#if 0
printk( "CPU clock at %u MHz\n", (uint32_t)(pc586_tsc_frequency / 1000000));
printk( "CPU clock at %u Hz\n", (uint32_t)(pc586_tsc_frequency ));
#endif
}
static void clockOn(void)
{
/*
* First calibrate the TSC. Do this every time we
* turn the clock on in case the CPU clock speed has changed.
*/
if ( x86_has_tsc() ) {
calibrate_tsc();
}
rtems_interrupt_lock_context lock_context;
pc386_isrs_per_tick = 1;
pc386_microseconds_per_isr = rtems_configuration_get_microseconds_per_tick();
@@ -171,13 +183,6 @@ static void clockOn(void)
rtems_interrupt_lock_release(&rtems_i386_i8254_access_lock, &lock_context);
bsp_interrupt_vector_enable( BSP_PERIODIC_TIMER );
/*
* Now calibrate cycles per tick. Do this every time we
* turn the clock on in case the CPU clock speed has changed.
*/
if ( x86_has_tsc() )
calibrate_tsc();
}
bool Clock_isr_enabled = false;

View File

@@ -1,3 +1,29 @@
/* SPDX-License-Identifier: BSD-2-Clause */
/*
* Copyright (C) 2020 Jan Sommer, Deutsches Zentrum für Luft- und Raumfahrt e. V. (DLR)
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include <rtems/score/smpimpl.h>

View File

@@ -226,9 +226,11 @@ get_checksum(unsigned start, int length)
int
send_ipi(unsigned int dst, unsigned int v)
{
int to, send_status;
int to, send_status, apicid;
IMPS_LAPIC_WRITE(LAPIC_ICR+0x10, (dst << 24));
apicid = imps_cpu_apic_map[dst];
IMPS_LAPIC_WRITE(LAPIC_ICR+0x10, (apicid << 24));
IMPS_LAPIC_WRITE(LAPIC_ICR, v);
/* Wait for send to finish */
@@ -251,9 +253,11 @@ static int
boot_cpu(imps_processor *proc)
{
int apicid = proc->apic_id, success = 1;
int cpuid;
unsigned bootaddr;
unsigned bios_reset_vector = PHYS_TO_VIRTUAL(BIOS_RESET_VECTOR);
cpuid = imps_apic_cpu_map[apicid];
/*
* Copy boot code for secondary CPUs here. Find it in between
* "patch_code_start" and "patch_code_end" symbols. The other CPUs
@@ -276,7 +280,7 @@ boot_cpu(imps_processor *proc)
/* Pass start function, stack region and gdtdescr to AP
* see startAP.S for location */
reset[1] = (uint32_t)secondary_cpu_initialize;
reset[2] = (uint32_t)_Per_CPU_Get_by_index(apicid)->interrupt_stack_high;
reset[2] = (uint32_t)_Per_CPU_Get_by_index(cpuid)->interrupt_stack_high;
memcpy(
(char*) &reset[3],
&gdtdesc,
@@ -295,13 +299,13 @@ boot_cpu(imps_processor *proc)
/* assert INIT IPI */
send_ipi(
apicid,
cpuid,
LAPIC_ICR_TM_LEVEL | LAPIC_ICR_LEVELASSERT | LAPIC_ICR_DM_INIT
);
UDELAY(10000);
/* de-assert INIT IPI */
send_ipi(apicid, LAPIC_ICR_TM_LEVEL | LAPIC_ICR_DM_INIT);
send_ipi(cpuid, LAPIC_ICR_TM_LEVEL | LAPIC_ICR_DM_INIT);
UDELAY(10000);
@@ -312,7 +316,7 @@ boot_cpu(imps_processor *proc)
if (proc->apic_ver >= APIC_VER_NEW) {
int i;
for (i = 1; i <= 2; i++) {
send_ipi(apicid, LAPIC_ICR_DM_SIPI | ((bootaddr >> 12) & 0xFF));
send_ipi(cpuid, LAPIC_ICR_DM_SIPI | ((bootaddr >> 12) & 0xFF));
UDELAY(1000);
}
}

View File

@@ -1,3 +1,5 @@
/* SPDX-License-Identifier: BSD-2-Clause */
/**
* @file
*
@@ -5,9 +7,7 @@
*/
/*
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (C) 2019 embedded brains GmbH
* Copyright (C) 2019 embedded brains GmbH (http://www.embedded-brains.de)
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions

View File

@@ -1,27 +1,43 @@
/* SPDX-License-Identifier: BSD-2-Clause */
/**
* @file
*
* @ingroup bsp_interrupt
*
* @brief Generic BSP interrupt support API.
* @brief This header file provides interfaces of the generic interrupt
* controller support.
*/
/*
* Based on concepts of Pavel Pisa, Till Straumann and Eric Valette.
* Copyright (C) 2016 Chris Johns <chrisj@rtems.org>
*
* Copyright (c) 2008, 2017 embedded brains GmbH.
* Copyright (C) 2008, 2017 embedded brains GmbH (http://www.embedded-brains.de)
*
* embedded brains GmbH
* Dornierstr. 4
* 82178 Puchheim
* Germany
* <rtems@embedded-brains.de>
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* Copyright (c) 2016 Chris Johns <chrisj@rtems.org>
*
* The license and distribution terms for this file may be
* found in the file LICENSE in this distribution or at
* http://www.rtems.org/license/LICENSE.
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
/*
* The API is based on concepts of Pavel Pisa, Till Straumann and Eric Valette.
*/
#ifndef LIBBSP_SHARED_IRQ_GENERIC_H

View File

@@ -1,22 +1,37 @@
/* SPDX-License-Identifier: BSD-2-Clause */
/**
* @file
*
* @ingroup bsp_interrupt
*
* @brief Generic BSP interrupt information API.
* @brief This header file provides interfaces of the generic interrupt
* controller support for the RTEMS Shell.
*/
/*
* Copyright (c) 2008, 2009
* embedded brains GmbH
* Obere Lagerstr. 30
* D-82178 Puchheim
* Germany
* <rtems@embedded-brains.de>
* Copyright (C) 2008, 2009 embedded brains GmbH (http://www.embedded-brains.de)
*
* The license and distribution terms for this file may be
* found in the file LICENSE in this distribution or at
* http://www.rtems.org/license/LICENSE.
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef LIBBSP_SHARED_IRQ_INFO_H

View File

@@ -21,6 +21,8 @@ extern "C" {
struct ahbstat_regs {
volatile uint32_t status;
volatile uint32_t failing;
volatile uint32_t status2;
volatile uint32_t failing2;
};
/* AHB fail interrupt callback to user. This function is declared weak so that

View File

@@ -226,6 +226,25 @@
#define GAISLER_SPIMASTER 0x0a6
#define GAISLER_SPISLAVE 0x0a7
#define GAISLER_GRSRIO 0x0a8
#define GAISLER_AHBLM2AHB 0x0a9
#define GAISLER_AHBS2NOC 0x0aa
#define GAISLER_TCAU 0x0ab
#define GAISLER_GRTMDYNVCID 0x0ac
#define GAISLER_RNOCIRQPROP 0x0ad
#define GAISLER_FTADDR 0x0ae
#define GAISLER_ATG 0x0b0
#define GAISLER_DFITRACE 0x0b1
#define GAISLER_SELFTEST 0x0b2
#define GAISLER_DFIERRINJ 0x0b3
#define GAISLER_DFICHECK 0x0b4
#define GAISLER_GRCANFD 0x0b5
#define GAISLER_NIM 0x0b6
#define GAISLER_BANDGAP 0x1f0
#define GAISLER_MPROT 0x1f1
#define GAISLER_ADC 0x1f2
#define GAISLER_BO 0x1f3
#define GAISLER_DAC 0x1f4
#define GAISLER_PLL 0x1f6
#define GAISLER_PIPEWRAPPER 0xffa
#define GAISLER_L2TIME 0xffd /* internal device: leon2 timer */

View File

@@ -0,0 +1,94 @@
/* SPDX-License-Identifier: BSD-2-Clause */
/**
* @file
* @ingroup can
* @brief Common CAN baud-rate routines for OCCAN/GRCAN/GRCANFD controllers
*/
/*
* Copyright (C) 2019, 2020 Cobham Gaisler AB
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef __GRLIB_CANBTRS_H__
#define __GRLIB_CANBTRS_H__
/**
* @defgroup can CAN
*
* @ingroup RTEMSBSPsSharedGRLIB
*
* @brief CAN routines shared between OCCAN, GRCAN and GRCANFD controllers
*
* @{
*/
#ifdef __cplusplus
extern "C" {
#endif
/* CAN Baud-rate parameters, range of valid parameter values */
struct grlib_canbtrs_ranges {
unsigned int max_scaler;
char has_bpr;
unsigned char divfactor;
unsigned char min_tseg1;
unsigned char max_tseg1;
unsigned char min_tseg2;
unsigned char max_tseg2;
};
struct grlib_canbtrs_timing {
unsigned char scaler;
unsigned char ps1;
unsigned char ps2;
unsigned char rsj;
unsigned char bpr;
};
/* @brief Calculate CAN baud-rate generation parameters from requested baud-rate
*
* @param baud The CAN baud rate requested
* @param core_hz Input clock [Hz] to CAN core
* @param sampl_pt CAN sample point in %, 80 means 80%
* @param br CAN Baud-rate parameters limitations
* @param[out] timing result is placed here
*
* @retval 0 Baud-rate parameters sucessfully calculated
* @retval negative Failure to generate parameters with less than 5% error
* margin from requested baud-rate
*/
int grlib_canbtrs_calc_timing(
unsigned int baud,
unsigned int core_hz,
unsigned int sampl_pt,
struct grlib_canbtrs_ranges *br,
struct grlib_canbtrs_timing *timing
);
#ifdef __cplusplus
}
#endif
#endif

View File

@@ -1,6 +1,7 @@
/**
* @file
* @ingroup can
* @brief Driver API for the GRLIB GRCAN and GRCANFD controllers
*/
/*
@@ -25,6 +26,8 @@
* @{
*/
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
@@ -37,7 +40,13 @@ struct grcan_regs {
volatile unsigned int smask; /* 0x18 */
volatile unsigned int scode; /* 0x1C */
volatile unsigned int dummy1[56]; /* 0x20-0xFC */
volatile unsigned int dummy1[8]; /* 0x20-0x3C */
volatile unsigned int nbtr; /* 0x40 */
volatile unsigned int fdbtr; /* 0x44 */
volatile unsigned int tdelay; /* 0x48 */
volatile unsigned int dummy1b[45]; /* 0x4C-0xFC */
volatile unsigned int pimsr; /* 0x100 */
volatile unsigned int pimr; /* 0x104 */
@@ -82,10 +91,18 @@ struct grcan_timing {
unsigned char scaler;
unsigned char ps1;
unsigned char ps2;
unsigned int rsj;
unsigned char rsj;
unsigned char bpr;
};
struct grcanfd_timing {
unsigned char scaler;
unsigned char ps1;
unsigned char ps2;
unsigned char sjw;
unsigned char resv_zero;
};
struct grcan_selection {
int selection;
int enable0;
@@ -97,16 +114,34 @@ struct grcan_filter {
unsigned long long code;
};
#define GRCAN_FDOPT_NOM 0
#define GRCAN_FDOPT_FDBTR 0x01
#define GRCAN_FDOPT_FDFRM 0x02
#define GRCAN_FDMASK (GRCAN_FDOPT_FDBTR | GRCAN_FDOPT_FDFRM)
/* CAN MESSAGE */
typedef struct {
char extended; /* 1= Extended Frame (29-bit id), 0= STD Frame (11-bit id) */
char rtr; /* RTR - Remote Transmission Request */
char unused; /* unused */
char unused; /* Must be 0 to select classic CAN frame */
unsigned char len;
unsigned char data[8];
unsigned int id;
} CANMsg;
/* CAN-FD MESSAGE */
typedef struct {
uint8_t extended; /* 1= Extended Frame (29-bit id), 0= STD Frame (11-bit id) */
uint8_t rtr; /* RTR - Remote Transmission Request */
uint8_t fdopts; /* Bit1: 1=Switch bit rate. bit2: 1=FD frame. */
uint8_t len; /* 0-8, 12, 16, 20, 24, 32, 48 or 64 bytes */
uint32_t id;
union {
uint64_t dwords[8]; /* up to 64 bytes if FD=1 and len>8 */
uint8_t bytes[64]; /* up to 64 bytes if FD=1 and len>8 */
} data;
} CANFDMsg;
enum {
GRCAN_RET_OK = 0,
GRCAN_RET_INVARG = -1,
@@ -166,6 +201,26 @@ enum grcan_state {
#define GRCAN_RXCTRL_ENABLE 1
#define GRCAN_RXCTRL_ONGOING 1
#define GRCANFD_NBTR_SCALER 0x00ff0000
#define GRCANFD_NBTR_PS1 0x0000fc00
#define GRCANFD_NBTR_PS2 0x000003e0
#define GRCANFD_NBTR_SJW 0x0000001f
#define GRCANFD_NBTR_SCALER_BIT 16
#define GRCANFD_NBTR_PS1_BIT 10
#define GRCANFD_NBTR_PS2_BIT 5
#define GRCANFD_NBTR_SJW_BIT 0
#define GRCANFD_FDBTR_SCALER 0x00ff0000
#define GRCANFD_FDBTR_PS1 0x00003c00
#define GRCANFD_FDBTR_PS2 0x000001e0
#define GRCANFD_FDBTR_SJW 0x0000000f
#define GRCANFD_FDBTR_SCALER_BIT 16
#define GRCANFD_FDBTR_PS1_BIT 10
#define GRCANFD_FDBTR_PS2_BIT 5
#define GRCANFD_FDBTR_SJW_BIT 0
/* Relative offset of IRQ sources to AMBA Plug&Play */
#define GRCAN_IRQ_IRQ 0
#define GRCAN_IRQ_TXSYNC 1
@@ -229,6 +284,15 @@ extern void *grcan_open_by_name(char *name, int *dev_no);
*/
extern int grcan_close(void *d);
/*
* Returns if CAN hardware device is CANFD capable.
*
* dev_no: Device handle
* return: 0=Not FD capable, 1=FD capable.
* function returns NULL if device can not be opened.
*/
extern int grcan_canfd_capable(void *d);
/*
* Receive CAN messages
*
@@ -254,6 +318,31 @@ extern int grcan_read(
size_t count
);
/*
* Receive CAN messages (only GRCANFD)
*
* Multiple CAN messages can be received in one call.
*
* d: Device handle
* msg: Pointer to receive messages
* count: Number of CAN messages to receive
*
* return:
* >=0: Number of CAN messages received. This can be
* less than the count parameter.
* GRCAN_RET_INVARG: count parameter less than one or NULL msg.
* GRCAN_RET_NOTSTARTED: Device not in started mode
* GRCAN_RET_TIMEOUT: Timeout in non-blocking mode
* GRCAN_RET_BUSOFF: A read was interrupted by a bus-off error.
* Device has left started mode.
* GRCAN_RET_AHBERR: Similar to BUSOFF, but was caused by AHB Error.
*/
extern int grcanfd_read(
void *d,
CANFDMsg *msg,
size_t count
);
/*
* Transmit CAN messages
*
@@ -279,6 +368,31 @@ extern int grcan_write(
size_t count
);
/*
* Transmit CAN-FD complient messages (only GRCANFD)
*
* Multiple CAN messages can be transmit in one call.
*
* d: Device handle
* msg: Pointer to messages to transmit
* count: Number of CAN messages to transmit
*
* return:
* >=0: Number of CAN messages transmitted. This can be
* less than the count parameter.
* GRCAN_RET_INVARG: count parameter less than one.
* GRCAN_RET_NOTSTARTED: Device not in started mode
* GRCAN_RET_TIMEOUT: Timeout in non-blocking mode
* GRCAN_RET_BUSOFF: A write was interrupted by a Bus-off error.
* Device has left started mode
* GRCAN_RET_AHBERR: Similar to BUSOFF, but was caused by AHB Error.
*/
extern int grcanfd_write(
void *d,
CANFDMsg *msg,
size_t ucount
);
/*
* Returns current GRCAN software state
*
@@ -320,6 +434,16 @@ extern int grcan_set_speed(void *d, unsigned int hz);
/* Set baudrate by specifying the timing registers manually */
extern int grcan_set_btrs(void *d, const struct grcan_timing *timing);
/* Set the Nominal and FD baudrate by using driver's baud rate timing
* calculation routines
*/
extern int grcanfd_set_speed(void *d, unsigned int nomhz, unsigned int fdhz);
/* Set Nominal and FD baudrate by specifying the timing registers manually*/
extern int grcanfd_set_btrs(
void *d,
const struct grcanfd_timing *nominal,
const struct grcanfd_timing *fd);
/* Functions can be called whenever */
/* Enable/disable Blocking on reception (until at least one message has been received) */
int grcan_set_rxblock(void* d, int block);

View File

@@ -100,6 +100,7 @@ typedef struct _greth_regs {
#define GRETH_STATUS_TXIRQ 0x00000008 /* Transmit Error IRQ */
#define GRETH_STATUS_RXAHBERR 0x00000010 /* Receiver AHB Error */
#define GRETH_STATUS_TXAHBERR 0x00000020 /* Transmitter AHB Error */
#define GRETH_STATUS_NRD 0x0f000000 /* Number of descriptors */
/* MDIO Control */
#define GRETH_MDIO_WRITE 0x00000001 /* MDIO Write */

View File

@@ -122,6 +122,16 @@ RTEMS_INLINE_ROUTINE unsigned int grlib_read_uncached32(unsigned int address)
return tmp;
}
RTEMS_INLINE_ROUTINE uint64_t grlib_read_uncached64(uint64_t *address)
{
uint64_t tmp;
__asm__ (" ldda [%1]1, %0 "
: "=r"(tmp)
: "r"(address)
);
return tmp;
}
#define GRLIB_DMA_IS_CACHE_COHERENT CPU_SPARC_HAS_SNOOPING
#else

View File

@@ -150,8 +150,8 @@ typedef enum {
SPW_LS_ERRRST = 0,
SPW_LS_ERRWAIT = 1,
SPW_LS_READY = 2,
SPW_LS_CONNECTING = 3,
SPW_LS_STARTED = 4,
SPW_LS_STARTED = 3,
SPW_LS_CONNECTING = 4,
SPW_LS_RUN = 5
} spw_link_state_t;

View File

@@ -343,6 +343,7 @@ extern int router_port_enable(void *d, int port);
extern int router_port_disable(void *d, int port);
extern int router_port_link_stop(void *d, int port);
extern int router_port_link_start(void *d, int port);
extern int router_port_link_div(void *d, int port, int rundiv);
extern int router_port_link_receive_spill(void *d, int port);
extern int router_port_link_transmit_reset(void *d, int port);

View File

@@ -1,7 +1,7 @@
/**
* @file
* @ingroup can
* @brief Gaisler wrapper to OpenCores CAN - driver interface
* @brief Driver API for GRLIB wrapper to OpenCores CAN
*/
/*

View File

@@ -91,13 +91,13 @@ SECTIONS
* crtn.o are in.
*/
PROVIDE (_init = .);
*crti.o(.init)
*(.init)
*crtn.o(.init)
KEEP (*crti.o(.init))
KEEP (*(.init))
KEEP (*crtn.o(.init))
PROVIDE (_fini = .);
*crti.o(.fini)
*(.fini)
*crtn.o(.fini)
KEEP (*crti.o(.fini))
KEEP (*(.fini))
KEEP (*crtn.o(.fini))
/*
* Special FreeBSD sysctl sections.
@@ -122,18 +122,22 @@ SECTIONS
* crtend.o. The same comments apply to it.
*/
. = ALIGN (16);
*crtbegin.o(.ctors)
*(.ctors)
*crtend.o(.ctors)
*crtbegin.o(.dtors)
*(.dtors)
*crtend.o(.dtors)
KEEP (*crtbegin.o(.ctors))
KEEP (*crtbegin?.o(.ctors))
KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .ctors))
KEEP (*(SORT(.ctors.*)))
KEEP (*(.ctors))
KEEP (*crtbegin.o(.dtors))
KEEP (*crtbegin?.o(.dtors))
KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .dtors))
KEEP (*(SORT(.dtors.*)))
KEEP (*(.dtors))
/*
* Exception frame info
*/
. = ALIGN (16);
*(.eh_frame)
KEEP (*(.eh_frame))
/*
* Read-only data
@@ -141,7 +145,7 @@ SECTIONS
. = ALIGN (16);
_rodata_start = . ;
*(.rodata*)
KEEP (*(SORT(.rtemsroset.*)))
KEEP (*(SORT(.rtemsroset.*)))
*(.gnu.linkonce.r*)
. = ALIGN (16);
@@ -179,7 +183,7 @@ SECTIONS
KEEP (*(SORT(.rtemsrwset.*)))
*(.gnu.linkonce.d*)
*(.gcc_except_table*)
*(.jcr)
KEEP (*(.jcr))
. = ALIGN (16);
PROVIDE (_edata = .);
PROVIDE (_copy_end = .);

View File

@@ -1,145 +0,0 @@
#include <rtems.h>
#include <bsp.h>
#include <bsp/if_mve_pub.h>
#include <stdlib.h>
#include <stdio.h>
/* Demo for the mv64360 ethernet quirk:
*
* $$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$
* $$ buffer segments < 8 bytes must be aligned $$
* $$ to 8 bytes but larger segments are not $$
* $$ sensitive to alignment. $$
* $$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$
*
* How to use:
*
* Init MVE driver on (unused) unit 2:
*
* mve = mvtst_init(2)
*
* data = { 1,2,3,4,5,6,7,8,9,0xa,0xb, ... }
*
* Alloc 2-element mbuf chain (1st holds an
* ethernet header which is > 8bytes so we can't
* test this with only 1 mbuf. The 2nd mbuf holds
* a small fragment of data).
*
* mb = mvtst_getbuf(mve)
*
* Copy data into aligned area inside 2nd mbuf,
* (so that you can see if the chip starts using
* the aligned area rather than the unaligned
* buffer pointer). Point mbuf's data pointer
* at 'off'set from the aligned area:
*
* mvtst_putbuf(mb, data, len, offset)
*
* Send chain off:
*
* BSP_mve_send_buf(mve, mb, 0, 0)
*
* Watch raw data:
*
* tcpdump -XX -vv -s0 ether host <my-ether-addr>
*
* E.g, if offset = 1, len = 2 then we would like
* to see
*
* GOOD:
* < 14 header bytes > 0x02, 0x03
* but if the chip starts DMA at aligned address
* we see instead
* BAD:
* < 14 header bytes > 0x01, 0x02
*/
static inline void *rmalloc(size_t l) { return malloc(l); }
static inline void rfree(void *p) { return free(p); }
#define _KERNEL
#include <sys/param.h>
#include <sys/mbuf.h>
static void
cleanup_buf(void *u_b, void *closure, int error)
{
rtems_bsdnet_semaphore_obtain();
m_freem((struct mbuf*)u_b);
rtems_bsdnet_semaphore_release();
}
struct mbuf *mvtst_getbuf(struct mveth_private *mp)
{
struct mbuf *m,*n;
if ( !mp ) {
printf("need driver ptr arg\n");
return 0;
}
rtems_bsdnet_semaphore_obtain();
MGETHDR(m, M_DONTWAIT, MT_DATA);
MGET(n, M_DONTWAIT, MT_DATA);
m->m_next = n;
rtems_bsdnet_semaphore_release();
/* Ethernet header */
memset( mtod(m, unsigned char*), 0xff, 6);
BSP_mve_read_eaddr(mp, mtod(m, unsigned char*) + 6);
/* Arbitrary; setting to IP but we don't bother
* to setup a real IP header. We just watch the
* raw packet contents...
*/
mtod(m, unsigned char*)[12] = 0x08;
mtod(m, unsigned char*)[13] = 0x00;
m->m_pkthdr.len = m->m_len = 14;
n->m_len = 0;
return m;
}
int
mvtst_putbuf(struct mbuf *m, void *data, int len, int off)
{
int i;
if ( m ) {
m->m_pkthdr.len += len;
if ( ( m= m->m_next ) ) {
m->m_len = len;
memcpy(mtod(m, void*), data, 32);
m->m_data += off;
printf("m.dat: 0x%08x, m.data: 0x%08x\n", m->m_dat, m->m_data);
for ( i=0; i< 16; i++ ) {
printf(" %02x,",mtod(m, unsigned char*)[i]);
}
printf("\n");
}
}
return 0;
}
static void *alloc_rxbuf(int *p_size, unsigned long *paddr)
{
return *(void**)paddr = rmalloc((*p_size = 1800));
}
static void consume_buf(void *buf, void *closure, int len)
{
rfree(buf);
}
void *
mvtst_init(int unit)
{
struct mveth_private *mp;
mp = BSP_mve_setup(
unit, 0,
cleanup_buf, 0,
alloc_rxbuf,
consume_buf, 0,
10, 10,
0);
if ( mp )
BSP_mve_init_hw(mp, 0, 0);
return mp;
}

View File

@@ -1,324 +0,0 @@
#ifndef KERNEL
#define KERNEL
#endif
#include <rtems.h>
#include <rtems/rtems_bsdnet_internal.h>
#include <bsp.h>
#include <sys/param.h>
#include <sys/mbuf.h>
#include "mv64340_eth_ll.h"
#include <string.h>
#include <assert.h>
#include <netinet/in.h>
#include <stdio.h>
#define RX_SPACING 1
#define TX_SPACING 1
#define RX_RING_SIZE (MV64340_RX_QUEUE_SIZE*RX_SPACING)
#define TX_RING_SIZE (MV64340_TX_QUEUE_SIZE*TX_SPACING)
struct eth_rx_desc rx_ring[RX_RING_SIZE] __attribute__((aligned(32)));
struct eth_rx_desc rx_ring[RX_RING_SIZE] = {{0},};
struct eth_tx_desc tx_ring[TX_RING_SIZE] __attribute__((aligned(32)));
struct eth_tx_desc tx_ring[TX_RING_SIZE] = {{0},};
/* packet buffers */
char rx_buf[MV64340_RX_QUEUE_SIZE][2048] __attribute__((aligned(8)));
char rx_buf[MV64340_RX_QUEUE_SIZE][2048];
char tx_buf[MV64340_RX_QUEUE_SIZE][2048] __attribute__((aligned(8)));
char tx_buf[MV64340_RX_QUEUE_SIZE][2048];
char BcHeader[22] = {
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* dst */
0x00, 0x01, 0xaf, 0x13, 0xb5, 0x3e, /* src */
00, 00, /* len */
0xAA, /* dsap */
0xAA, /* ssap */
0x03, /* ctrl */
0x08, 0x00, 0x56, /* snap_org [stanford] */
0x80, 0x5b, /* snap_type (stanford kernel) */
};
struct mv64340_private mveth = {
port_num: 0,
port_mac_addr: {0x00,0x01,0xAF,0x13,0xB5,0x3C},
/* port_config .. tx_resource_err are set by port_init */
0
};
struct pkt_info p0,p1;
static inline void rx_stopq(int port)
{
MV_WRITE(MV64340_ETH_RECEIVE_QUEUE_COMMAND_REG(port), 0x0000ff00);
}
static inline void tx_stopq(int port)
{
MV_WRITE(MV64340_ETH_TRANSMIT_QUEUE_COMMAND_REG(port), 0x0000ff00);
}
#define MV64360_ENET2MEM_SNOOP_NONE 0x0000
#define MV64360_ENET2MEM_SNOOP_WT 0x1000
#define MV64360_ENET2MEM_SNOOP_WB 0x2000
#if 0
int
mveth_init(struct mv64340_private *mp)
{
int i;
mp->p_rx_desc_area = rx_ring;
mp->p_tx_desc_area = tx_ring;
rx_stopq(mp->port_num);
tx_stopq(mp->port_num);
/* MotLoad has cache snooping disabled on the ENET2MEM windows.
* Some comments in (linux) indicate that there are errata
* which cause problems which is a real bummer.
* We try it anyways...
*/
{
unsigned long disbl, bar;
disbl = MV_READ(MV64340_ETH_BASE_ADDR_ENABLE_REG);
/* disable all 6 windows */
MV_WRITE(MV64340_ETH_BASE_ADDR_ENABLE_REG, 0x3f);
/* set WB snooping */
for ( i=0; i<6*8; i+=8 ) {
if ( (bar = MV_READ(MV64340_ETH_BAR_0 + i)) && MV_READ(MV64340_ETH_SIZE_REG_0 + i) ) {
MV_WRITE(MV64340_ETH_BAR_0 + i, bar | MV64360_ENET2MEM_SNOOP_WB);
/* read back to flush fifo [linux comment] */
(void)MV_READ(MV64340_ETH_BAR_0 + i);
}
}
/* restore/re-enable */
MV_WRITE(MV64340_ETH_BASE_ADDR_ENABLE_REG, disbl);
}
eth_port_init(mp);
sleep(1);
mveth_init_tx_desc_ring(mp);
mveth_init_rx_desc_ring(mp);
#if 0
for ( i = 0; i<MV64340_RX_QUEUE_SIZE; i++ ) {
p0.byte_cnt = sizeof(rx_buf[0]);
p0.buf_ptr = (dma_addr_t)rx_buf[i];
p0.return_info = (void*)i;
/* other fields are not used by ll driver */
assert ( ETH_OK == eth_rx_return_buff(mp,&p0) );
}
memset(&p0, 0, sizeof(p0));
#endif
return eth_port_start(mp);
}
#endif
void
mveth_stop(struct mv64340_private *mp)
{
extern void mveth_stop_hw();
rtems_bsdnet_semaphore_obtain();
mveth_stop_hw(mp);
rtems_bsdnet_semaphore_release();
}
extern int mveth_send_mbuf();
extern int mveth_swipe_tx();
int
mveth_tx(struct mv64340_private *mp, char *data, int len, int nbufs)
{
int rval = -1,l;
char *p;
struct mbuf *m;
char *emsg = 0;
rtems_bsdnet_semaphore_obtain();
MGETHDR(m, M_WAIT, MT_DATA);
if ( !m ) {
emsg="Unable to allocate header\n";
goto bail;
}
MCLGET(m, M_WAIT);
if ( !(m->m_flags & M_EXT) ) {
m_freem(m);
emsg="Unable to allocate cluster\n";
goto bail;
}
p = mtod(m, char *);
l = 0;
switch (nbufs) {
case 3:
default:
emsg="nbufs arg must be 1..3\n";
goto bail;
case 1:
l += sizeof(BcHeader);
memcpy(p, &BcHeader, sizeof(BcHeader));
p += sizeof(BcHeader);
case 2:
memcpy(p,data,len);
l += len;
m->m_len = m->m_pkthdr.len = l;
if ( 2 == nbufs ) {
M_PREPEND(m, sizeof (BcHeader), M_WAIT);
if (!m) {
emsg = "Unable to prepend\n";
goto bail;
}
p = mtod(m, char*);
memcpy(p,&BcHeader,sizeof(BcHeader));
l += sizeof(BcHeader);
}
break;
}
*(short*)(mtod(m, char*) + 12) = htons(l-14);
rval = mveth_send_mbuf(mp,m);
bail:
rtems_bsdnet_semaphore_release();
if (emsg)
printf(emsg);
#if 0
/*
* Add local net header. If no space in first mbuf,
* allocate another.
*/
M_PREPEND(m, sizeof (struct ether_header), M_DONTWAIT);
if (m == 0)
senderr(ENOBUFS);
eh = mtod(m, struct ether_header *);
(void)memcpy(&eh->ether_type, &type,
sizeof(eh->ether_type));
(void)memcpy(eh->ether_dhost, edst, sizeof (edst));
(void)memcpy(eh->ether_shost, ac->ac_enaddr,
sizeof(eh->ether_shost));
#endif
return rval;
}
int
mveth_protected(int (*p)(struct mv64340_private*), struct mv64340_private *mp)
{
int rval;
rtems_bsdnet_semaphore_obtain();
rval = p(mp);
rtems_bsdnet_semaphore_release();
return rval;
}
int
mveth_rx(struct mv64340_private *mp)
{
extern int mveth_swipe_rx();
return mveth_protected(mveth_swipe_rx,mp);
}
int
mveth_reclaim(struct mv64340_private *mp)
{
extern int mveth_swipe_tx();
return mveth_protected(mveth_swipe_tx,mp);
}
int preth(FILE *f, char *p)
{
int i;
for (i=0; i<4; i++)
fprintf(f,"%02X:",p[i]);
fprintf(f,"%02X",p[i]);
return 6;
}
char *errcode2str(st)
{
char *rval;
switch(st) {
case ETH_OK:
rval = "OK";
break;
case ETH_ERROR:
rval = "Fundamental error.";
break;
case ETH_RETRY:
rval = "Could not process request. Try later.";
break;
case ETH_END_OF_JOB:
rval = "Ring has nothing to process.";
break;
case ETH_QUEUE_FULL:
rval = "Ring resource error.";
break;
case ETH_QUEUE_LAST_RESOURCE:
rval = "Ring resources about to exhaust.";
break;
default:
rval = "UNKNOWN"; break;
}
return rval;
}
#if 0
int
mveth_rx(struct mv64340_private *mp)
{
int st;
struct pkt_info p;
if ( ETH_OK != (st=eth_port_receive(mp, &p)) ) {
fprintf(stderr,"receive: %s\n", errcode2str(st));
return -1;
}
printf("%i bytes received from ", p.byte_cnt);
preth(stdout,(char*)p.buf_ptr+6);
printf(" (desc. stat: 0x%08x)\n", p.cmd_sts);
p.byte_cnt = sizeof(rx_buf[0]);
p.buf_ptr -= RX_BUF_OFFSET;
if ( ETH_OK != (st=eth_rx_return_buff(mp,&p) ) ) {
fprintf(stderr,"returning buffer: %s\n", errcode2str(st));
return -1;
}
return 0;
}
#endif
int
dring()
{
int i;
if (1) {
struct eth_rx_desc *pr;
printf("RX:\n");
for (i=0, pr=rx_ring; i<RX_RING_SIZE; i+=RX_SPACING, pr+=RX_SPACING) {
dcbi(pr);
printf("cnt: 0x%04x, size: 0x%04x, stat: 0x%08x, next: 0x%08x, buf: 0x%08x\n",
pr->byte_cnt, pr->buf_size, pr->cmd_sts, pr->next_desc_ptr, pr->buf_ptr);
}
}
if (1) {
struct eth_tx_desc *pt;
printf("TX:\n");
for (i=0, pt=tx_ring; i<TX_RING_SIZE; i+=TX_SPACING, pt+=TX_SPACING) {
dcbi(pt);
printf("cnt: 0x%04x, stat: 0x%08x, next: 0x%08x, buf: 0x%08x\n",
pt->byte_cnt, pt->cmd_sts, pt->next_desc_ptr, pt->buf_ptr);
}
}
return 0;
}

View File

@@ -1,34 +0,0 @@
#include <rtems.h>
#include <porting/rtemscompat.h>
/* CEXP module initialization/finalization */
/* Copyright: Till Straumann <strauman@slac.stanford.edu>, 2005;
* License: see LICENSE file.
*/
void
_cexpModuleInitialize(void *unused)
{
extern void NET_EMBEMB(rtems_,NETDRIVER_PREFIX,_bringup)(char *);
METHODSPTR = &METHODS;
/*
#ifdef DEBUG
NET_EMBEMB(rtems_,NETDRIVER_PREFIX,_bringup)("192.168.2.13/255.255.255.0");
#endif
*/
}
int
_cexpModuleFinalize(void *unused)
{
#ifdef DEBUG
extern int NET_EMBEMB(rtems_,NETDRIVER_PREFIX,_bringdown)();
if (NET_EMBEMB(rtems_,NETDRIVER_PREFIX,_bringdown)())
return -1;
METHODSPTR = 0;
return 0;
#else
return -1;
#endif
}

View File

@@ -50,6 +50,11 @@ extern int BSP_disable_irq_at_pic(const rtems_irq_number irqLine);
*/
extern int BSP_setup_the_pic(rtems_irq_global_settings* config);
/*
* Set up for the irq-generic.h interface.
*/
int BSP_rtems_irq_generic_set(rtems_irq_global_settings* config);
/* IRQ dispatcher to be defined by the PIC driver; note that it MUST
* implement shared interrupts.
* Note also that the exception frame passed to this handler is not very

View File

@@ -50,7 +50,7 @@
* Acts as a barrier to ensure all previous I/O accesses have
* completed before any further ones are issued.
*/
static inline void eieio(void)
static inline void io_eieio(void)
{
__asm__ __volatile__ ("eieio");
}
@@ -59,9 +59,9 @@ static inline void eieio(void)
/* Enforce in-order execution of data I/O.
* No distinction between read/write on PPC; use eieio for all three.
*/
#define iobarrier_rw() eieio()
#define iobarrier_r() eieio()
#define iobarrier_w() eieio()
#define iobarrier_rw() io_eieio()
#define iobarrier_r() io_eieio()
#define iobarrier_w() io_eieio()
/*
* 8, 16 and 32 bit, big and little endian I/O operations, with barrier.
@@ -107,6 +107,7 @@ static inline void out_be16(volatile uint16_t *addr, uint16_t val)
__asm__ __volatile__("sth%U0%X0 %1,%0; eieio" : "=m" (*addr) : "r" (val));
}
#ifndef in_le32
static inline uint32_t in_le32(const volatile uint32_t *addr)
{
uint32_t ret;
@@ -115,7 +116,9 @@ static inline uint32_t in_le32(const volatile uint32_t *addr)
"r" (addr), "m" (*addr));
return ret;
}
#endif
#ifndef in_be32
static inline uint32_t in_be32(const volatile uint32_t *addr)
{
uint32_t ret;
@@ -123,17 +126,22 @@ static inline uint32_t in_be32(const volatile uint32_t *addr)
__asm__ __volatile__("lwz%U1%X1 %0,%1; eieio" : "=r" (ret) : "m" (*addr));
return ret;
}
#endif
#ifndef out_le32
static inline void out_le32(volatile uint32_t *addr, uint32_t val)
{
__asm__ __volatile__("stwbrx %1,0,%2; eieio" : "=m" (*addr) :
"r" (val), "r" (addr));
}
#endif
#ifndef out_be32
static inline void out_be32(volatile uint32_t *addr, uint32_t val)
{
__asm__ __volatile__("stw%U0%X0 %1,%0; eieio" : "=m" (*addr) : "r" (val));
}
#endif
#endif /* ASM */
#endif /* _LIBCPU_IO_H */

View File

@@ -23,6 +23,8 @@
#include <rtems/bspIo.h>
#include <bsp.h>
#include <rtems.h>
/* to align the pointer to the (next) page boundary */
#define PAGE_ALIGN(addr) (((addr) + PAGE_MASK) & ~PAGE_MASK)
@@ -401,7 +403,7 @@ setup_hw(void)
}
#endif
printk("\nRTEMS 4.x/PPC load: ");
printk("\nRTEMS " RTEMS_VERSION "/PPC load: ");
timer = 0;
cp = bd->cmd_line+strlen(bd->cmd_line);
while (timer++ < 5*1000) {

View File

@@ -38,7 +38,9 @@ SECTIONS
BYTE(0x75); BYTE(0x78); /* Partition name */
. = 0x400;
*(.text)
*(.text*)
*(.sdata2)
*(.sdata2*)
*(.rodata)
*(.rodata*)
}
@@ -71,13 +73,17 @@ SECTIONS
*(.data)
*(.data*)
*(.sdata)
*(.sdata*)
. = ALIGN(4);
_data_end = .;
}
.bss :
{
*(.sbss)
*(.sbss*)
*(.bss)
*(.bss*)
*(COMMON)
. = ALIGN(4);
_bss_end = .;
}
@@ -95,7 +101,7 @@ SECTIONS
/DISCARD/ :
{
*(.comment)
*(.comment*)
*(.debug*)
}
}

View File

@@ -31,11 +31,11 @@
#include <rtems.h>
#include <libcpu/io.h>
#include <bsp/vectors.h>
#ifdef qemu
#include <rtems/bspcmdline.h>
#endif
#ifdef __cplusplus
extern "C" {
#endif
@@ -115,6 +115,36 @@ extern "C" {
#endif
#endif
/*
* The BSP has PCI devices. Enable support in LibBSD.
*/
#define BSP_HAS_PC_PCI
/*
* Remap the PCI address space for LibBSD
*/
#define RTEMS_BSP_PCI_IO_REGION_BASE 0
#define RTEMS_BSP_PCI_MEM_REGION_BASE PCI_DRAM_OFFSET
/*
* Remap the PCI address space for LibBSD
*/
#define RTEMS_BSP_ADDR_PTR(_type) uint ## _type ## _t __volatile*
#define RTEMS_BSP_ADDR_CPTR(_type) const RTEMS_BSP_ADDR_PTR(_type)
#define RTEMS_BSP_ADDRESS_READ(_addr, _type) \
*((RTEMS_BSP_ADDR_CPTR(_type)) (((RTEMS_BSP_ADDR_CPTR(8)) _addr) + PCI_DRAM_OFFSET))
#define RTEMS_BSP_ADDRESS_WRITE(_addr, _val, _type) \
*((RTEMS_BSP_ADDR_PTR(_type)) (((RTEMS_BSP_ADDR_PTR(8)) _addr) + PCI_DRAM_OFFSET)) = (_val)
#define RTEMS_BSP_READ_1(_addr) RTEMS_BSP_ADDRESS_READ(_addr, 8)
#define RTEMS_BSP_READ_2(_addr) RTEMS_BSP_ADDRESS_READ(_addr, 16)
#define RTEMS_BSP_READ_4(_addr) RTEMS_BSP_ADDRESS_READ(_addr, 32)
#define RTEMS_BSP_READ_8(_addr) RTEMS_BSP_ADDRESS_READ(_addr, 64)
#define RTEMS_BSP_WRITE_1(_addr, _val) RTEMS_BSP_ADDRESS_WRITE(_addr, _val, 8)
#define RTEMS_BSP_WRITE_2(_addr, _val) RTEMS_BSP_ADDRESS_WRITE(_addr, _val, 16)
#define RTEMS_BSP_WRITE_4(_addr, _val) RTEMS_BSP_ADDRESS_WRITE(_addr, _val, 32)
#define RTEMS_BSP_WRITE_8(_addr, _val) RTEMS_BSP_ADDRESS_WRITE(_addr, _val, 64)
/*
* Base address definitions for several devices

View File

@@ -19,9 +19,17 @@
#ifndef BSP_POWERPC_IRQ_H
#define BSP_POWERPC_IRQ_H
#ifndef BSP_SHARED_HANDLER_SUPPORT
#define BSP_SHARED_HANDLER_SUPPORT 1
#endif
#include <rtems/irq.h>
#include <bsp/irq-default.h>
/*
* Switch to using the generic support. Remove this when all BSPs have
* been converted.
*/
#define BSP_POWERPC_IRQ_GENERIC_SUPPORT 1
/*
* 8259 edge/level control definitions at VIA
@@ -107,6 +115,8 @@ extern "C" {
#define BSP_IRQ_NUMBER (BSP_MISC_IRQ_MAX_OFFSET + 1)
#define BSP_LOWEST_OFFSET (BSP_ISA_IRQ_LOWEST_OFFSET)
#define BSP_MAX_OFFSET (BSP_MISC_IRQ_MAX_OFFSET)
#define BSP_INTERRUPT_VECTOR_MIN (BSP_LOWEST_OFFSET)
#define BSP_INTERRUPT_VECTOR_MAX (BSP_MAX_OFFSET)
/*
* Some ISA IRQ symbolic name definition
*/
@@ -191,6 +201,9 @@ int BSP_irq_ack_at_i8259s (const rtems_irq_number irqLine);
*/
int BSP_irq_enabled_at_i8259s (const rtems_irq_number irqLine);
unsigned short BSP_irq_suspend_i8259s(unsigned short mask);
void BSP_irq_resume_i8259s(unsigned short in_progress_save);
extern void BSP_rtems_irq_mng_init(unsigned cpuId);
extern void BSP_i8259s_init(void);

View File

@@ -27,6 +27,7 @@
#include <bsp/pci.h>
#include <bsp/openpic.h>
#include <bsp/irq.h>
#include <bsp/irq-generic.h>
#include <libcpu/bat.h>
#include <libcpu/pte121.h>
#include <libcpu/cpuIdent.h>
@@ -334,10 +335,8 @@ static void bsp_early( void )
*/
bsp_clicks_per_usec = BSP_bus_frequency/(BSP_time_base_divisor * 1000);
/*
* Initalize RTEMS IRQ system
*/
BSP_rtems_irq_mng_init(0);
/* Initialize interrupt support */
bsp_interrupt_initialize();
/* Activate the page table mappings only after
* initializing interrupts because the irq_mng_init()

View File

@@ -12,6 +12,19 @@
#include <bsp.h>
#include <bsp/irq.h>
#define PIC_EOSI 0x60 ///< End of Specific Interrupt (EOSI)
#define PIC_EOI 0x20 ///< Generic End of Interrupt (EOI)
/* Operation control word type 3. Bit 3 (0x08) must be set. Even address. */
#define PIC_OCW3_RIS 0x01 /* 1 = read IS, 0 = read IR */
#define PIC_OCW3_RR 0x02 /* register read */
#define PIC_OCW3_P 0x04 /* poll mode command */
/* 0x08 must be 1 to select OCW3 vs OCW2 */
#define PIC_OCW3_SEL 0x08 /* must be 1 */
/* 0x10 must be 0 to select OCW3 vs ICW1 */
#define PIC_OCW3_SMM 0x20 /* special mode mask */
#define PIC_OCW3_ESMM 0x40 /* enable SMM */
/*-------------------------------------------------------------------------+
| Cache for 1st and 2nd PIC IRQ line's status (enabled or disabled) register.
+--------------------------------------------------------------------------*/
@@ -19,91 +32,137 @@
* lower byte is interrupt mask on the master PIC.
* while upper bits are interrupt on the slave PIC.
*/
volatile rtems_i8259_masks i8259s_cache = 0xfffb;
static rtems_i8259_masks i8259s_imr_cache = 0xFFFB;
static rtems_i8259_masks i8259s_in_progress = 0;
static inline
void BSP_i8259s_irq_update_master_imr( void )
{
rtems_i8259_masks mask = i8259s_in_progress | i8259s_imr_cache;
outport_byte( PIC_MASTER_IMR_IO_PORT, mask & 0xff );
}
static inline
void BSP_i8259s_irq_update_slave_imr( void )
{
rtems_i8259_masks mask = i8259s_in_progress | i8259s_imr_cache;
outport_byte( PIC_SLAVE_IMR_IO_PORT, ( mask >> 8 ) & 0xff );
}
/*
* Is the IRQ valid?
*/
static inline bool BSP_i8259s_irq_valid(const rtems_irq_number irqLine)
{
return ((int)irqLine >= BSP_ISA_IRQ_LOWEST_OFFSET) &&
((int)irqLine <= BSP_ISA_IRQ_MAX_OFFSET);
}
/*
* Read the IRR register. The default.
*/
static inline uint8_t BSP_i8259s_irq_int_request_reg(uint32_t ioport)
{
uint8_t isr;
inport_byte(ioport, isr);
return isr;
}
/*
* Read the ISR register. Keep the default of the IRR.
*/
static inline uint8_t BSP_i8259s_irq_in_service_reg(uint32_t ioport)
{
uint8_t isr;
outport_byte(ioport, PIC_OCW3_SEL | PIC_OCW3_RR | PIC_OCW3_RIS);
inport_byte(ioport, isr);
outport_byte(ioport, PIC_OCW3_SEL | PIC_OCW3_RR);
return isr;
}
/*-------------------------------------------------------------------------+
| Function: BSP_irq_disable_at_i8259s
| Description: Mask IRQ line in appropriate PIC chip.
| Global Variables: i8259s_cache
| Global Variables: i8259s_imr_cache, i8259s_in_progress
| Arguments: vector_offset - number of IRQ line to mask.
| Returns: original state or -1 on error.
| Returns: 0 is OK.
+--------------------------------------------------------------------------*/
int BSP_irq_disable_at_i8259s (const rtems_irq_number irqLine)
int BSP_irq_disable_at_i8259s(const rtems_irq_number irqLine)
{
unsigned short mask;
rtems_interrupt_level level;
int rval;
if ( ((int)irqLine < BSP_ISA_IRQ_LOWEST_OFFSET) ||
((int)irqLine > BSP_ISA_IRQ_MAX_OFFSET)
)
if (!BSP_i8259s_irq_valid(irqLine))
return -1;
rtems_interrupt_disable(level);
mask = 1 << irqLine;
rval = i8259s_cache & mask ? 0 : 1;
i8259s_cache |= mask;
i8259s_imr_cache |= mask;
if (irqLine < 8)
{
outport_byte(PIC_MASTER_IMR_IO_PORT, i8259s_cache & 0xff);
BSP_i8259s_irq_update_master_imr();
}
else
{
outport_byte(PIC_SLAVE_IMR_IO_PORT, ((i8259s_cache & 0xff00) >> 8));
BSP_i8259s_irq_update_slave_imr();
}
rtems_interrupt_enable(level);
return rval;
return 0;
}
/*-------------------------------------------------------------------------+
| Function: BSP_irq_enable_at_i8259s
| Description: Unmask IRQ line in appropriate PIC chip.
| Global Variables: i8259s_cache
| Global Variables: i8259s_imr_cache, i8259s_in_progress
| Arguments: irqLine - number of IRQ line to mask.
| Returns: Nothing.
+--------------------------------------------------------------------------*/
int BSP_irq_enable_at_i8259s (const rtems_irq_number irqLine)
int BSP_irq_enable_at_i8259s(const rtems_irq_number irqLine)
{
unsigned short mask;
rtems_interrupt_level level;
unsigned short mask;
uint8_t isr;
uint8_t irr;
if ( ((int)irqLine < BSP_ISA_IRQ_LOWEST_OFFSET) ||
((int)irqLine > BSP_ISA_IRQ_MAX_OFFSET )
)
if (!BSP_i8259s_irq_valid(irqLine))
return 1;
rtems_interrupt_disable(level);
mask = ~(1 << irqLine);
i8259s_cache &= mask;
mask = 1 << irqLine;
i8259s_imr_cache &= ~mask;
if (irqLine < 8)
{
outport_byte(PIC_MASTER_IMR_IO_PORT, i8259s_cache & 0xff);
isr = BSP_i8259s_irq_in_service_reg(PIC_MASTER_COMMAND_IO_PORT);
irr = BSP_i8259s_irq_int_request_reg(PIC_MASTER_COMMAND_IO_PORT);
BSP_i8259s_irq_update_master_imr();
}
else
{
outport_byte(PIC_SLAVE_IMR_IO_PORT, ((i8259s_cache & 0xff00) >> 8));
isr = BSP_i8259s_irq_in_service_reg(PIC_SLAVE_COMMAND_IO_PORT);
irr = BSP_i8259s_irq_int_request_reg(PIC_SLAVE_COMMAND_IO_PORT);
BSP_i8259s_irq_update_slave_imr();
}
rtems_interrupt_enable(level);
return 0;
} /* mask_irq */
int BSP_irq_enabled_at_i8259s (const rtems_irq_number irqLine)
int BSP_irq_enabled_at_i8259s(const rtems_irq_number irqLine)
{
unsigned short mask;
if ( ((int)irqLine < BSP_ISA_IRQ_LOWEST_OFFSET) ||
((int)irqLine > BSP_ISA_IRQ_MAX_OFFSET)
)
if (!BSP_i8259s_irq_valid(irqLine))
return 1;
mask = (1 << irqLine);
return (~(i8259s_cache & mask));
return (~(i8259s_imr_cache & mask));
}
/*-------------------------------------------------------------------------+
@@ -113,24 +172,47 @@ int BSP_irq_enabled_at_i8259s (const rtems_irq_number irqLine)
| Arguments: irqLine - number of IRQ line to acknowledge.
| Returns: Nothing.
+--------------------------------------------------------------------------*/
int BSP_irq_ack_at_i8259s (const rtems_irq_number irqLine)
int BSP_irq_ack_at_i8259s(const rtems_irq_number irqLine)
{
uint8_t slave_isr = 0;
if (irqLine >= 8) {
outport_byte(PIC_MASTER_COMMAND_IO_PORT, SLAVE_PIC_EOSI);
outport_byte(PIC_SLAVE_COMMAND_IO_PORT, (PIC_EOSI | (irqLine - 8)));
}
else {
outport_byte(PIC_MASTER_COMMAND_IO_PORT, (PIC_EOSI | irqLine));
outport_byte(PIC_SLAVE_COMMAND_IO_PORT, PIC_EOI);
slave_isr = BSP_i8259s_irq_in_service_reg(PIC_SLAVE_COMMAND_IO_PORT);
}
/*
* Only issue the EOI to the master if there are no more interrupts in
* service for the slave. i8259a data sheet page 18, The Special Fully Nested
* Mode, b.
*/
if (slave_isr == 0)
outport_byte(PIC_MASTER_COMMAND_IO_PORT, PIC_EOI);
return 0;
} /* ackIRQ */
unsigned short BSP_irq_suspend_i8259s(unsigned short mask)
{
unsigned short in_progress_save = i8259s_in_progress;
i8259s_in_progress |= mask;
BSP_i8259s_irq_update_master_imr();
BSP_i8259s_irq_update_slave_imr();
return in_progress_save;
}
void BSP_irq_resume_i8259s(unsigned short in_progress_save)
{
i8259s_in_progress = in_progress_save;
BSP_i8259s_irq_update_master_imr();
BSP_i8259s_irq_update_slave_imr();
}
void BSP_i8259s_init(void)
{
/*
* init master 8259 interrupt controller
* Always mask at least current interrupt to prevent re-entrance
*/
outport_byte(PIC_MASTER_COMMAND_IO_PORT, 0x11); /* Start init sequence */
outport_byte(PIC_MASTER_IMR_IO_PORT, 0x00);/* Vector base = 0 */

View File

@@ -280,6 +280,7 @@ void BSP_rtems_irq_mng_init(unsigned cpuId)
int known_cpi_isa_bridge = 0;
#endif
int i;
int r;
/*
* First initialize the Interrupt management hardware
@@ -310,7 +311,7 @@ void BSP_rtems_irq_mng_init(unsigned cpuId)
#endif
known_cpi_isa_bridge = 1;
}
if ( currentBoard == MVME_2300 ) {
if ( currentBoard == MVME_2300 || currentBoard == MVME_2600_2700_W_MVME761 ) {
/* nothing to do for W83C553 bridge */
known_cpi_isa_bridge = 1;
}
@@ -351,7 +352,19 @@ void BSP_rtems_irq_mng_init(unsigned cpuId)
initial_config.irqBase = BSP_LOWEST_OFFSET;
initial_config.irqPrioTbl = irqPrioTable;
if (!BSP_rtems_irq_mngt_set(&initial_config)) {
#ifdef BSP_POWERPC_IRQ_GENERIC_SUPPORT
#ifdef TRACE_IRQ_INIT
printk("RTEMS IRQ management: irq-generic\n");
#endif
r = BSP_rtems_irq_generic_set(&initial_config);
#else
#ifdef TRACE_IRQ_INIT
printk("RTEMS IRQ management: legacy\n");
#endif
r = BSP_rtems_irq_mngt_set(&initial_config);
#endif
if (!r) {
/*
* put something here that will show the failure...
*/

View File

@@ -15,6 +15,7 @@
#include <bsp.h>
#include <bsp/irq.h>
#include <bsp/irq_supp.h>
#include <bsp/irq-generic.h>
#ifndef BSP_HAS_NO_VME
#include <bsp/VMEConfig.h>
#endif
@@ -214,7 +215,7 @@ int BSP_setup_the_pic(rtems_irq_global_settings* config)
/*
* Must enable PCI/ISA bridge IRQ
*/
openpic_enable_irq (BSP_PCI_ISA_BRIDGE_IRQ);
openpic_enable_irq (BSP_PCI_ISA_BRIDGE_IRQ - BSP_PCI_IRQ_LOWEST_OFFSET);
#endif
#endif
@@ -234,15 +235,15 @@ int C_dispatch_irq_handler (BSP_Exception_frame *frame, unsigned int excNum)
#if BSP_ISA_IRQ_NUMBER > 0
register unsigned isaIntr; /* boolean */
register unsigned oldMask = 0; /* old isa pic masks */
register unsigned newMask; /* new isa pic masks */
#endif
if (excNum == ASM_DEC_VECTOR) {
bsp_irq_dispatch_list(rtems_hdl_tbl, BSP_DECREMENTER, default_rtems_entry.hdl);
#ifdef BSP_POWERPC_IRQ_GENERIC_SUPPORT
bsp_interrupt_handler_dispatch(BSP_DECREMENTER);
#else
bsp_irq_dispatch_list(rtems_hdl_tbl, BSP_DECREMENTER, default_rtems_entry.hdl);
#endif
return 0;
}
#if BSP_PCI_IRQ_NUMBER > 0
@@ -274,7 +275,7 @@ int C_dispatch_irq_handler (BSP_Exception_frame *frame, unsigned int excNum)
#if BSP_ISA_IRQ_NUMBER > 0
#ifdef BSP_PCI_ISA_BRIDGE_IRQ
#if 0 == BSP_PCI_IRQ_NUMBER
#if 0 == BSP_PCI_IRQ_NUMBER
#error "Configuration Error -- BSP w/o PCI IRQs MUST NOT define BSP_PCI_ISA_BRIDGE_IRQ"
#endif
isaIntr = (irq == BSP_PCI_ISA_BRIDGE_IRQ);
@@ -289,11 +290,7 @@ int C_dispatch_irq_handler (BSP_Exception_frame *frame, unsigned int excNum)
/*
* store current PIC mask
*/
oldMask = i8259s_cache;
newMask = oldMask | irq_mask_or_tbl [irq];
i8259s_cache = newMask;
outport_byte(PIC_MASTER_IMR_IO_PORT, i8259s_cache & 0xff);
outport_byte(PIC_SLAVE_IMR_IO_PORT, ((i8259s_cache & 0xff00) >> 8));
oldMask = BSP_irq_suspend_i8259s(irq_mask_or_tbl [irq]);
BSP_irq_ack_at_i8259s (irq);
#if BSP_PCI_IRQ_NUMBER > 0
if ( OpenPIC )
@@ -303,13 +300,15 @@ int C_dispatch_irq_handler (BSP_Exception_frame *frame, unsigned int excNum)
#endif
/* dispatch handlers */
#ifdef BSP_POWERPC_IRQ_GENERIC_SUPPORT
bsp_interrupt_handler_dispatch(irq);
#else
bsp_irq_dispatch_list(rtems_hdl_tbl, irq, default_rtems_entry.hdl);
#endif
#if BSP_ISA_IRQ_NUMBER > 0
if (isaIntr) {
i8259s_cache = oldMask;
outport_byte(PIC_MASTER_IMR_IO_PORT, i8259s_cache & 0xff);
outport_byte(PIC_SLAVE_IMR_IO_PORT, ((i8259s_cache & 0xff00) >> 8));
BSP_irq_resume_i8259s(oldMask);
}
else
#endif

View File

@@ -0,0 +1,117 @@
/* SPDX-License-Identifier: BSD-2-Clause */
/**
* @file
*
* @ingroup RTEMSBSPsPowerPC
*
* @brief Generic Interrupt suppoer
*/
/*
* Copyright (C) 2021 Chris Johns. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include <stdlib.h>
#include <rtems.h>
#include <stdlib.h>
#include <rtems/bspIo.h> /* for printk */
#include <libcpu/spr.h>
#include <bsp/irq_supp.h>
#include <bsp/irq-generic.h>
#include <bsp/vectors.h>
SPR_RW(BOOKE_TSR)
SPR_RW(PPC405_TSR)
/* legacy mode for bookE DEC exception;
* to avoid the double layer of function calls
* (dec_handler_bookE -> C_dispatch_irq_handler -> user handler)
* it is preferrable for the user to hook the DEC
* exception directly.
* However, the legacy mode works with less modifications
* of user code.
*/
static int C_dispatch_dec_handler_bookE (BSP_Exception_frame *frame, unsigned int excNum)
{
/* clear interrupt; we must do this
* before C_dispatch_irq_handler()
* re-enables MSR_EE.
* Note that PPC405 uses a different SPR# for TSR
*/
if (ppc_cpu_is_bookE()==PPC_BOOKE_405)
_write_PPC405_TSR( BOOKE_TSR_DIS );
else
_write_BOOKE_TSR( BOOKE_TSR_DIS );
return C_dispatch_irq_handler(frame, ASM_DEC_VECTOR);
}
/*
* RTEMS Global Interrupt Handler Management Routines
*/
int BSP_rtems_irq_generic_set(rtems_irq_global_settings* config)
{
int r;
r = BSP_setup_the_pic(config);
if (!r)
return r;
ppc_exc_set_handler(ASM_EXT_VECTOR, C_dispatch_irq_handler);
if ( ppc_cpu_is_bookE() ) {
/* bookE decrementer interrupt needs to be cleared BEFORE
* dispatching the user ISR (because the user ISR is called
* with EE enabled)
* We do this so that existing DEC handlers can be used
* with minor modifications.
*/
ppc_exc_set_handler(ASM_BOOKE_DEC_VECTOR, C_dispatch_dec_handler_bookE);
} else {
ppc_exc_set_handler(ASM_DEC_VECTOR, C_dispatch_irq_handler);
}
return 1;
}
void bsp_interrupt_vector_enable(rtems_vector_number vector)
{
bsp_interrupt_assert(bsp_interrupt_is_valid_vector(vector));
BSP_enable_irq_at_pic(vector);
}
void bsp_interrupt_vector_disable(rtems_vector_number vector)
{
bsp_interrupt_assert(bsp_interrupt_is_valid_vector(vector));
BSP_disable_irq_at_pic(vector);
}
rtems_status_code bsp_interrupt_facility_initialize(void)
{
/*
* Initialize RTEMS IRQ system
*/
BSP_rtems_irq_mng_init(0);
return RTEMS_SUCCESSFUL;
}

View File

@@ -20,8 +20,11 @@ librtemsbsp_a_SOURCES += ../../../../../../bsps/shared/grlib/ascs/grascs.c
librtemsbsp_a_SOURCES += ../../../../../../bsps/shared/grlib/btimer/gptimer.c
librtemsbsp_a_SOURCES += ../../../../../../bsps/shared/grlib/btimer/tlib.c
librtemsbsp_a_SOURCES += ../../../../../../bsps/shared/grlib/btimer/tlib_ckinit.c
librtemsbsp_a_SOURCES += ../../../../../../bsps/shared/grlib/can/canbtrs.c
librtemsbsp_a_SOURCES += ../../../../../../bsps/shared/grlib/can/canmux.c
librtemsbsp_a_SOURCES += ../../../../../../bsps/shared/grlib/can/grcan.c
librtemsbsp_a_SOURCES += ../../../../../../bsps/shared/grlib/can/grcanfd.c
librtemsbsp_a_SOURCES += ../../../../../../bsps/shared/grlib/can/grcanstd.c
librtemsbsp_a_SOURCES += ../../../../../../bsps/shared/grlib/can/occan.c
librtemsbsp_a_SOURCES += ../../../../../../bsps/shared/grlib/can/satcan.c
librtemsbsp_a_SOURCES += ../../../../../../bsps/shared/grlib/drvmgr/ambapp_bus.c

View File

@@ -206,6 +206,10 @@ static int gr1553_init2(struct drvmgr_dev *dev)
GR1553B_WRITE_REG(&regs->rt_cfg, 0x15530000);
/* Stop BM logging (just in case) */
GR1553B_WRITE_REG(&regs->bm_ctrl, 0);
/* Set codec version. This is only supported by some devices, i.e. GR740.
* It will not have any effect on devices that does not support this bit.
*/
GR1553B_WRITE_REG(&regs->hwcfg, 1<<12);
return DRVMGR_OK;
}

View File

@@ -63,7 +63,7 @@ struct gr1553bc_priv {
*/
#define NEXT_MINOR_MARKER 0x01
/* To separate ASYNC list from SYNC list we mark them differently, but with
/* To separate ASYNC list from SYNC list we mark them differently, but with
* LSB always set. This can be used to get the list the descriptor is a part
* of.
*/
@@ -71,7 +71,7 @@ struct gr1553bc_priv {
struct gr1553bc_list_cfg gr1553bc_def_cfg =
{
.rt_timeout =
.rt_timeout =
{
20, 20, 20, 20,
20, 20, 20, 20,
@@ -80,7 +80,7 @@ struct gr1553bc_list_cfg gr1553bc_def_cfg =
20, 20, 20, 20,
20, 20, 20, 20,
20, 20, 20, 20,
20, 20, 20
20, 20, 20
},
.bc_timeout = 30,
.tropt_irq_on_err = 0,
@@ -132,7 +132,7 @@ int gr1553bc_list_config
/* RT Time Tolerances */
for (i=0; i<31; i++) {
/* 0=14us, 1=18us ... 0xf=74us
/* 0=14us, 1=18us ... 0xf=74us
* round upwards: 15us will be 18us
*/
timeout = ((cfg->rt_timeout[i] + 1) - 14) / 4;
@@ -167,7 +167,7 @@ void gr1553bc_list_link_major(
if ( major ) {
major->next = next;
if ( next ) {
major->minors[major->cfg->minor_cnt-1]->next =
major->minors[major->cfg->minor_cnt-1]->next =
next->minors[0];
} else {
major->minors[major->cfg->minor_cnt-1]->next = NULL;
@@ -195,7 +195,7 @@ int gr1553bc_list_set_major(
prev = list->majors[list->major_cnt-1];
}
/* Link to next Major if not the last one and if there is
/* Link to next Major if not the last one and if there is
* a next major
*/
if ( no == list->major_cnt-1 ) {
@@ -262,7 +262,7 @@ int gr1553bc_list_table_size(struct gr1553bc_list *list)
minor_cnt = major->cfg->minor_cnt;
for (j=0; j<minor_cnt; j++) {
/* 128-bit Alignment required by HW */
size += (GR1553BC_BD_ALIGN -
size += (GR1553BC_BD_ALIGN -
(size & (GR1553BC_BD_ALIGN-1))) &
~(GR1553BC_BD_ALIGN-1);
@@ -284,6 +284,7 @@ int gr1553bc_list_table_alloc
int i, j, minor_cnt, size;
unsigned int table;
struct gr1553bc_priv *bcpriv = list->bc;
int retval = 0;
/* Free previous allocated descriptor table */
gr1553bc_list_table_free(list);
@@ -298,8 +299,8 @@ int gr1553bc_list_table_alloc
/* Address given in Hardware accessible address, we
* convert it into CPU-accessible address.
*/
list->table_hw = (unsigned int)bdtab_custom & ~0x1;
list->_table = bdtab_custom;
list->_table = (void*)((unsigned int)bdtab_custom & ~0x1);
list->table_hw = (unsigned int)list->_table;
drvmgr_translate_check(
*bcpriv->pdev,
DMAMEM_TO_CPU,
@@ -310,16 +311,19 @@ int gr1553bc_list_table_alloc
if (bdtab_custom == NULL) {
/* Allocate descriptors */
list->_table = grlib_malloc(size + (GR1553BC_BD_ALIGN-1));
if ( list->_table == NULL )
return -1;
if ( list->_table == NULL ) {
retval = -1;
goto err;
}
/* 128-bit Alignment required by HW */
list->table_cpu =
(((unsigned int)list->_table + (GR1553BC_BD_ALIGN-1)) &
~(GR1553BC_BD_ALIGN-1));
} else {
/* Custom address, given in CPU-accessible address */
list->_table = bdtab_custom;
list->table_cpu = (unsigned int)list->_table;
}
/* 128-bit Alignment required by HW */
list->table_cpu =
(((unsigned int)list->_table + (GR1553BC_BD_ALIGN-1)) &
~(GR1553BC_BD_ALIGN-1));
/* We got CPU accessible descriptor table address, now we
* translate that into an address that the Hardware can
@@ -338,6 +342,12 @@ int gr1553bc_list_table_alloc
}
}
/* Verify alignment */
if (list->table_hw & (GR1553BC_BD_ALIGN-1)) {
retval = -2;
goto err;
}
/* Write End-Of-List all over the descriptor table here,
* For debugging/safety?
*/
@@ -359,8 +369,16 @@ int gr1553bc_list_table_alloc
table += gr1553bc_minor_table_size(major->minors[j]);
}
}
return 0;
err:
if (retval) {
if (list->_table_custom == NULL && list->_table) {
free(list->_table);
}
list->table_hw = 0;
list->table_cpu = 0;
list->_table = NULL;
}
return retval;
}
void gr1553bc_list_table_free(struct gr1553bc_list *list)
@@ -399,7 +417,7 @@ int gr1553bc_list_table_build(struct gr1553bc_list *list)
bds = minor->bds;
/* BD[0..SLOTCNT-1] = message slots
* BD[SLOTCNT+0] = END
* BD[SLOTCNT+0] = END
* BD[SLOTCNT+1] = JUMP
*
* or if no optional time slot handling:
@@ -485,7 +503,7 @@ void gr1553bc_bd_init(
((word0 & GR1553BC_BD_TYPE) == 0) ) {
/* Don't touch timeslot previously allocated */
word0 &= ~GR1553BC_TR_TIME;
word0 |= GR1553BC_READ_MEM(&raw->words[0]) &
word0 |= GR1553BC_READ_MEM(&raw->words[0]) &
GR1553BC_TR_TIME;
}
GR1553BC_WRITE_MEM(&raw->words[0], word0);
@@ -523,7 +541,7 @@ int gr1553bc_major_alloc_skel
maj->cfg = cfg;
maj->next = NULL;
/* Create links between minor frames, and from minor frames
/* Create links between minor frames, and from minor frames
* to configuration structure.
*/
minor = (struct gr1553bc_minor *)&maj->minors[cfg->minor_cnt];
@@ -697,7 +715,7 @@ int gr1553bc_slot_alloc2(
set0 = (set0 & ~GR1553BC_TR_TIME) | timefree;
GR1553BC_WRITE_MEM(&trbd->settings[0], set0);
/* Note: at the moment the minor frame can be executed faster
* than expected, we hurry up writing requested
* than expected, we hurry up writing requested
* descriptor.
*/
}
@@ -886,7 +904,7 @@ int gr1553bc_slot_irq_prepare
union gr1553bc_bd *bd;
int slot_no, to_mid;
/* Build unconditional IRQ descriptor. The padding is used
/* Build unconditional IRQ descriptor. The padding is used
* for identifying the MINOR frame and function and custom data.
*
* The IRQ is disabled at first, a unconditional jump to next
@@ -1115,7 +1133,7 @@ int gr1553bc_slot_update
*stat = GR1553BC_READ_MEM(&bd->tr.status);
if ( status ) {
/* Clear status fields user selects, then
* or bit31 if user wants that. The bit31
* or bit31 if user wants that. The bit31
* may be used to indicate if the BC has
* performed the access.
*/
@@ -1192,7 +1210,7 @@ int gr1553bc_mid_from_bd(
found_mid:
/* Get MID of JUMP descriptor */
bdmid = word2 >> 8;
/* Subtract distance from JUMP descriptor to find MID
/* Subtract distance from JUMP descriptor to find MID
* of requested BD.
*/
slot_no = GR1553BC_SLOTID_FROM_ID(bdmid);
@@ -1445,7 +1463,7 @@ void gr1553bc_device_init(struct gr1553bc_priv *priv)
/* Stop BC if not already stopped */
GR1553BC_WRITE_REG(&priv->regs->bc_ctrl, GR1553BC_KEY | 0x0204);
/* Since RT can not be used at the same time as BC, we stop
/* Since RT can not be used at the same time as BC, we stop
* RT rx, it should already be stopped...
*/
GR1553BC_WRITE_REG(&priv->regs->rt_cfg, GR1553RT_KEY);
@@ -1463,7 +1481,7 @@ void gr1553bc_device_init(struct gr1553bc_priv *priv)
priv->alist = NULL;
priv->irq_log_base = (uint32_t *)
(((uint32_t)priv->irq_log_p + (GR1553BC_IRQLOG_SIZE-1)) &
(((uint32_t)priv->irq_log_p + (GR1553BC_IRQLOG_SIZE-1)) &
~(GR1553BC_IRQLOG_SIZE-1));
/* Translate into a hardware accessible address */
drvmgr_translate_check(
@@ -1487,7 +1505,7 @@ void gr1553bc_device_uninit(struct gr1553bc_priv *priv)
/* Stop BC if not already stopped */
GR1553BC_WRITE_REG(&priv->regs->bc_ctrl, GR1553BC_KEY | 0x0204);
/* Since RT can not be used at the same time as BC, we stop
/* Since RT can not be used at the same time as BC, we stop
* RT rx, it should already be stopped...
*/
GR1553BC_WRITE_REG(&priv->regs->rt_cfg, GR1553RT_KEY);
@@ -1518,7 +1536,7 @@ void gr1553bc_isr(void *arg)
/* Clear handled IRQs */
GR1553BC_WRITE_REG(&priv->regs->irq, irq);
/* DMA error. This IRQ does not affect the IRQ log.
/* DMA error. This IRQ does not affect the IRQ log.
* We let standard IRQ handle handle it.
*/
if ( irq & GR1553B_IRQEN_BCDE ) {
@@ -1563,7 +1581,7 @@ void gr1553bc_isr(void *arg)
bd = NULL;
}
/* Handle Descriptor that cased IRQ
/* Handle Descriptor that cased IRQ
*
* If someone have inserted an IRQ descriptor and tied
* that to a custom function we call that function, otherwise

View File

@@ -89,7 +89,7 @@ static void gr1553bm_hw_start(struct gr1553bm_priv *priv)
/* Start logging */
priv->regs->bm_ctrl =
(priv->cfg.filt_error_options &
(priv->cfg.filt_error_options &
(GR1553B_BM_CTRL_MANL|GR1553B_BM_CTRL_UDWL|GR1553B_BM_CTRL_IMCL))
| GR1553B_BM_CTRL_BMEN;
@@ -178,6 +178,7 @@ void gr1553bm_close(void *bm)
/* Configure the BM driver */
int gr1553bm_config(void *bm, struct gr1553bm_config *cfg)
{
int retval = 0;
struct gr1553bm_priv *priv = bm;
if ( priv->started )
@@ -193,12 +194,11 @@ int gr1553bm_config(void *bm, struct gr1553bm_config *cfg)
}
priv->buffer_size = cfg->buffer_size & ~0x7; /* on 8 byte bounadry */
if ((unsigned int)cfg->buffer_custom & 1) {
/* Custom Address Given in Remote address. We need
* to convert it intoTranslate into Hardware a
* hardware accessible address
/* Custom address given in remote address. We need
* to convert it into a hardware accessible address
*/
priv->buffer_base_hw = (unsigned int)cfg->buffer_custom & ~1;
priv->buffer = cfg->buffer_custom;
priv->buffer = (void*)((unsigned int)cfg->buffer_custom & ~1);
priv->buffer_base_hw = (unsigned int)priv->buffer;
drvmgr_translate_check(
*priv->pdev,
DMAMEM_TO_CPU,
@@ -209,17 +209,19 @@ int gr1553bm_config(void *bm, struct gr1553bm_config *cfg)
if (cfg->buffer_custom == NULL) {
/* Allocate new buffer dynamically */
priv->buffer = grlib_malloc(priv->buffer_size + 8);
if (priv->buffer == NULL)
return -1;
if (priv->buffer == NULL) {
retval = -1;
goto err;
}
/* Align to 8 bytes */
priv->buffer_base = ((unsigned int)priv->buffer + (8-1)) & ~(8-1);
} else {
/* Address given in CPU accessible address, no
* translation required.
*/
priv->buffer = cfg->buffer_custom;
priv->buffer_base = (unsigned int)priv->buffer;
}
/* Align to 16 bytes */
priv->buffer_base = ((unsigned int)priv->buffer + (8-1)) &
~(8-1);
/* Translate address of buffer base into address that Hardware must
* use to access the buffer.
*/
@@ -229,13 +231,28 @@ int gr1553bm_config(void *bm, struct gr1553bm_config *cfg)
(void *)priv->buffer_base,
(void **)&priv->buffer_base_hw,
priv->buffer_size);
}
/* Verify alignment */
if (priv->buffer_base_hw & (8-1)) {
retval = -2;
goto err;
}
/* Copy valid config */
priv->cfg = *cfg;
return 0;
err:
if (retval) {
if (cfg->buffer_custom == NULL && priv->buffer) {
free(priv->buffer);
}
priv->buffer_base_hw = (unsigned int)NULL;
priv->buffer_base = (unsigned int)NULL;
priv->buffer = NULL;
}
return retval;
}
/* Start logging */
@@ -249,7 +266,7 @@ int gr1553bm_start(void *bm)
return -2;
/* Start at Time = 0 */
priv->regs->bm_ttag =
priv->regs->bm_ttag =
priv->cfg.time_resolution << GR1553B_BM_TTAG_RES_BIT;
/* Configure Filters */
@@ -282,7 +299,7 @@ void gr1553bm_stop(void *bm)
/* Stop Hardware */
gr1553bm_hw_stop(priv);
/* At this point the hardware must be stopped and IRQ
/* At this point the hardware must be stopped and IRQ
* sources unmasked.
*/
@@ -331,7 +348,7 @@ resample:
hwtime2 = priv->regs->bm_ttag & GR1553B_BM_TTAG_VAL;
if ( hwtime > hwtime2 ) {
/* priv->time and hwtime may be out of sync if
* IRQ updated priv->time just after bm_ttag was read
* IRQ updated priv->time just after bm_ttag was read
* here, we resample if we detect inconsistancy.
*/
goto resample;

View File

@@ -147,7 +147,6 @@ static int gr1553rt_list_reg(struct gr1553rt_list *list)
return -1;
}
#if 0 /* unused for now */
/* Unregister List from device */
static void gr1553rt_list_unreg(struct gr1553rt_list *list)
{
@@ -156,16 +155,15 @@ static void gr1553rt_list_unreg(struct gr1553rt_list *list)
priv->lists[list->listid] = NULL;
list->listid = -1;
}
#endif
static int gr1553rt_bdid(void *rt, struct gr1553rt_sw_bd *bd)
{
struct gr1553rt_priv *priv = rt;
unsigned short index;
/* Get Index of Software BD */
index = ((unsigned int)bd - (unsigned int)&priv->swbds[0]) /
index = ((unsigned int)bd - (unsigned int)&priv->swbds[0]) /
sizeof(struct gr1553rt_sw_bd);
return index;
@@ -197,10 +195,9 @@ static int gr1553rt_bd_alloc(void *rt, struct gr1553rt_sw_bd **bd, int cnt)
}
*bd = &priv->swbds[priv->swbd_free];
curr = &priv->swbds[priv->swbd_free];
for (i=0; i<cnt; i++) {
if ( i == 0) {
curr = &priv->swbds[priv->swbd_free];
} else {
if ( i != 0) {
curr = &priv->swbds[curr->this_next];
}
if ( curr->this_next == 0xffff ) {
@@ -240,7 +237,7 @@ int gr1553rt_list_init
{
struct gr1553rt_priv *priv = rt;
size_t size;
int i;
int i, malloc_used;
struct gr1553rt_sw_bd *swbd;
unsigned short index;
struct gr1553rt_list *list;
@@ -251,6 +248,7 @@ int gr1553rt_list_init
* If the IN/OUT plist argument points to NULL a list
* dynamically allocated here.
*/
malloc_used = 0;
list = *plist;
if ( list == NULL ) {
/* Dynamically allocate LIST */
@@ -258,20 +256,27 @@ int gr1553rt_list_init
(cfg->bd_cnt * sizeof(list->bds[0]));
list = grlib_malloc(size);
if ( list == NULL )
return -1;
return -1; /* Out of Memory */
*plist = list;
malloc_used = 1;
}
list->rt = rt;
list->subadr = -1;
list->listid = gr1553rt_list_reg(list);
if ( list->listid == -1 )
if ( list->listid == -1 ) {
if (malloc_used)
free(list);
return -2; /* Too many lists */
}
list->cfg = cfg;
list->bd_cnt = cfg->bd_cnt;
/* Allocate all BDs needed by list */
if ( gr1553rt_bd_alloc(rt, &swbd, list->bd_cnt) ) {
gr1553rt_list_unreg(list);
if (malloc_used)
free(list);
return -3; /* Too few descriptors */
}
@@ -352,7 +357,7 @@ int gr1553rt_bd_init(
bd->next = nextbd;
SPIN_UNLOCK_IRQ(&priv->devlock, irqflags);
return 0;
return 0;
}
int gr1553rt_bd_update(
@@ -410,7 +415,7 @@ int gr1553rt_bd_update(
}
*dptr = (uint16_t *)tmp;
}
SPIN_LOCK_IRQ(&priv->devlock, irqflags);
SPIN_UNLOCK_IRQ(&priv->devlock, irqflags);
return 0;
}
@@ -727,7 +732,7 @@ void gr1553rt_hw_stop(struct gr1553rt_priv *priv)
GR1553RT_WRITE_REG(&priv->regs->rt_cfg, GR1553RT_KEY);
/* Stop BC if not already stopped: BC can not be used simultaneously
* as the RT anyway
* as the RT anyway
*/
GR1553RT_WRITE_REG(&priv->regs->bc_ctrl, GR1553BC_KEY | 0x0204);
@@ -766,17 +771,17 @@ void gr1553rt_sw_free(struct gr1553rt_priv *priv)
}
}
/* Free dynamically allocated buffers, if any */
static int gr1553rt_sw_alloc(struct gr1553rt_priv *priv)
{
int size;
int retval = 0;
/* Allocate Event log */
if ((unsigned int)priv->cfg.evlog_buffer & 1) {
/* Translate Address from HARDWARE (REMOTE) to CPU-LOCAL */
priv->evlog_hw_base = (unsigned int *)
priv->evlog_buffer = (void *)
((unsigned int)priv->cfg.evlog_buffer & ~0x1);
priv->evlog_buffer = priv->cfg.evlog_buffer;
priv->evlog_hw_base = (unsigned int*)priv->evlog_buffer;
drvmgr_translate_check(
*priv->pdev,
DMAMEM_TO_CPU,
@@ -788,16 +793,19 @@ static int gr1553rt_sw_alloc(struct gr1553rt_priv *priv)
if (priv->cfg.evlog_buffer == NULL) {
priv->evlog_buffer = grlib_malloc(
priv->cfg.evlog_size * 2);
if (priv->evlog_buffer == NULL)
return -1;
if (priv->evlog_buffer == NULL) {
retval = -1;
goto err;
}
/* Align to SIZE bytes boundary */
priv->evlog_cpu_base = (unsigned int *)
(((unsigned int)priv->evlog_buffer +
(priv->cfg.evlog_size-1)) & ~(priv->cfg.evlog_size-1));
} else {
/* Addess already CPU-LOCAL */
priv->evlog_buffer = priv->cfg.evlog_buffer;
priv->evlog_cpu_base = (unsigned int *)priv->evlog_buffer;
}
/* Align to SIZE bytes boundary */
priv->evlog_cpu_base = (unsigned int *)
(((unsigned int)priv->evlog_buffer +
(priv->cfg.evlog_size-1)) & ~(priv->cfg.evlog_size-1));
drvmgr_translate_check(
*priv->pdev,
@@ -807,6 +815,11 @@ static int gr1553rt_sw_alloc(struct gr1553rt_priv *priv)
priv->cfg.evlog_size
);
}
/* Verify alignment */
if ((unsigned int)priv->evlog_hw_base & (priv->cfg.evlog_size-1)) {
retval = -2;
goto err;
}
priv->evlog_cpu_end = priv->evlog_cpu_base +
priv->cfg.evlog_size/sizeof(unsigned int *);
@@ -815,9 +828,9 @@ static int gr1553rt_sw_alloc(struct gr1553rt_priv *priv)
size = priv->bds_cnt * sizeof(struct gr1553rt_bd);
if ((unsigned int)priv->cfg.bd_buffer & 1) {
/* Translate Address from HARDWARE (REMOTE) to CPU-LOCAL */
priv->bds_hw = (struct gr1553rt_bd *)
priv->bd_buffer = (void *)
((unsigned int)priv->cfg.bd_buffer & ~0x1);
priv->bd_buffer = priv->cfg.bd_buffer;
priv->bds_hw = (struct gr1553rt_bd *)priv->bd_buffer;
drvmgr_translate_check(
*priv->pdev,
DMAMEM_TO_CPU,
@@ -828,15 +841,18 @@ static int gr1553rt_sw_alloc(struct gr1553rt_priv *priv)
} else {
if ( priv->cfg.bd_buffer == NULL ) {
priv->bd_buffer = grlib_malloc(size + 0xf);
if (priv->bd_buffer == NULL)
return -1;
if (priv->bd_buffer == NULL) {
retval = -1;
goto err;
}
/* Align to 16 bytes boundary */
priv->bds_cpu = (struct gr1553rt_bd *)
(((unsigned int)priv->bd_buffer + 0xf) & ~0xf);
} else {
/* Addess already CPU-LOCAL */
priv->bd_buffer = priv->cfg.bd_buffer;
priv->bds_cpu = (struct gr1553rt_bd *)priv->bd_buffer;
}
/* Align to 16 bytes boundary */
priv->bds_cpu = (struct gr1553rt_bd *)
(((unsigned int)priv->bd_buffer + 0xf) & ~0xf);
/* Translate from CPU address to hardware address */
drvmgr_translate_check(
@@ -847,21 +863,28 @@ static int gr1553rt_sw_alloc(struct gr1553rt_priv *priv)
size
);
}
/* Verify alignment */
if ((unsigned int)priv->bds_hw & (0xf)) {
retval = -2;
goto err;
}
#if (RTBD_MAX == 0)
/* Allocate software description of */
priv->swbds = grlib_malloc(priv->cfg.bd_count * sizeof(*priv->swbds));
if ( priv->swbds == NULL ) {
return -1;
retval = -1;
goto err;
}
#endif
/* Allocate Sub address table */
if ((unsigned int)priv->cfg.satab_buffer & 1) {
/* Translate Address from HARDWARE (REMOTE) to CPU-LOCAL */
priv->sas_hw = (struct gr1553rt_sa *)
priv->satab_buffer = (void *)
((unsigned int)priv->cfg.satab_buffer & ~0x1);
priv->satab_buffer = priv->cfg.satab_buffer;
priv->sas_hw = (struct gr1553rt_sa *)priv->satab_buffer;
drvmgr_translate_check(
*priv->pdev,
DMAMEM_TO_CPU,
@@ -871,16 +894,18 @@ static int gr1553rt_sw_alloc(struct gr1553rt_priv *priv)
} else {
if (priv->cfg.satab_buffer == NULL) {
priv->satab_buffer = grlib_malloc((16 * 32) * 2);
if (priv->satab_buffer == NULL)
return -1;
if (priv->satab_buffer == NULL) {
retval = -1;
goto err;
}
/* Align to 512 bytes boundary */
priv->sas_cpu = (struct gr1553rt_sa *)
(((unsigned int)priv->satab_buffer + 0x1ff) & ~0x1ff);
} else {
/* Addess already CPU-LOCAL */
priv->satab_buffer = priv->cfg.satab_buffer;
priv->sas_cpu = (struct gr1553rt_sa *)priv->satab_buffer;
}
/* Align to 512 bytes boundary */
priv->sas_cpu = (struct gr1553rt_sa *)
(((unsigned int)priv->satab_buffer + 0x1ff) &
~0x1ff);
/* Translate Address from CPU-LOCAL to HARDWARE (REMOTE) */
drvmgr_translate_check(
@@ -890,8 +915,17 @@ static int gr1553rt_sw_alloc(struct gr1553rt_priv *priv)
(void **)&priv->sas_hw,
16 * 32);
}
/* Verify alignment */
if ((unsigned int)priv->sas_hw & (0x1ff)) {
retval = -2;
goto err;
}
return 0;
err:
if (retval) {
gr1553rt_sw_free(priv);
}
return retval;
}
void gr1553rt_sw_init(struct gr1553rt_priv *priv)
@@ -937,7 +971,7 @@ void gr1553rt_sw_init(struct gr1553rt_priv *priv)
int gr1553rt_config(void *rt, struct gr1553rt_cfg *cfg)
{
struct gr1553rt_priv *priv = rt;
int retval = 0;
if ( priv->started )
return -1;
@@ -949,9 +983,9 @@ int gr1553rt_config(void *rt, struct gr1553rt_cfg *cfg)
if ( cfg->rtaddress > 30 )
return -1;
if ( (cfg->evlog_size & (cfg->evlog_size-1)) != 0)
return -1; /* SIZE: Not aligned to a power of 2 */
return -2; /* SIZE: Not aligned to a power of 2 */
if ( ((unsigned int)priv->cfg.evlog_buffer & (cfg->evlog_size-1)) != 0 )
return -1; /* Buffer: Not aligned to size */
return -2; /* Buffer: Not aligned to size */
#if (RTBD_MAX > 0)
if ( cfg->bd_count > RTBD_MAX )
return -1;
@@ -962,8 +996,9 @@ int gr1553rt_config(void *rt, struct gr1553rt_cfg *cfg)
/*** Adapt to new config ***/
if ( gr1553rt_sw_alloc(priv) != 0 )
return -1;
if ( (retval=gr1553rt_sw_alloc(priv)) != 0 ) {
return retval;
}
gr1553rt_sw_init(priv);

View File

@@ -46,12 +46,20 @@ int (*ahbstat_error)(
uint32_t failing_address
) __attribute__((weak)) = NULL;
#define AHBSTAT_STS_ME_BIT 13
#define AHBSTAT_STS_FW_BIT 12
#define AHBSTAT_STS_CF_BIT 11
#define AHBSTAT_STS_AF_BIT 10
#define AHBSTAT_STS_CE_BIT 9
#define AHBSTAT_STS_NE_BIT 8
#define AHBSTAT_STS_HW_BIT 7
#define AHBSTAT_STS_HM_BIT 3
#define AHBSTAT_STS_HS_BIT 0
#define AHBSTAT_STS_ME (1 << AHBSTAT_STS_ME_BIT)
#define AHBSTAT_STS_FW (1 << AHBSTAT_STS_FW_BIT)
#define AHBSTAT_STS_CF (1 << AHBSTAT_STS_CF_BIT)
#define AHBSTAT_STS_AF (1 << AHBSTAT_STS_AF_BIT)
#define AHBSTAT_STS_CE (1 << AHBSTAT_STS_CE_BIT)
#define AHBSTAT_STS_NE (1 << AHBSTAT_STS_NE_BIT)
#define AHBSTAT_STS_HW (1 << AHBSTAT_STS_HW_BIT)

View File

@@ -199,7 +199,26 @@ static ambapp_device_name GAISLER_devices[] =
{GAISLER_TCCOP, "TCCOP"},
{GAISLER_SPIMASTER, "SPIMASTER"},
{GAISLER_SPISLAVE, "SPISLAVE"},
{GAISLER_GRSRIO, "GRSRIO"},
{GAISLER_GRSRIO, "GRSRIO"},
{GAISLER_AHBLM2AHB, "AHBLM2AHB"},
{GAISLER_AHBS2NOC, "AHBS2NOC"},
{GAISLER_TCAU, "TCAU"},
{GAISLER_GRTMDYNVCID, "GRTMDYNVCID"},
{GAISLER_RNOCIRQPROP, "RNOCIRQPROP"},
{GAISLER_FTADDR, "FTADDR"},
{GAISLER_ATG, "ATG"},
{GAISLER_DFITRACE, "DFITRACE"},
{GAISLER_SELFTEST, "SELFTEST"},
{GAISLER_DFIERRINJ, "DFIERRINJ"},
{GAISLER_DFICHECK, "DFICHECK"},
{GAISLER_GRCANFD, "GRCANFD"},
{GAISLER_NIM, "NIM"},
{GAISLER_BANDGAP, "BANDGAP"},
{GAISLER_MPROT, "MPROT"},
{GAISLER_ADC, "ADC"},
{GAISLER_BO, "BO"},
{GAISLER_DAC, "DAC"},
{GAISLER_PLL, "PLL"},
{0, NULL}
};

View File

@@ -209,15 +209,14 @@ static uint32_t simple_tlib_tc_get_timecount(struct timecounter *tc)
static rtems_device_driver simple_initialize_counter(void)
{
uint64_t frequency;
unsigned int tick_hz;
unsigned int tick_hz, frequency;
frequency = 1000000;
tlib_get_freq(priv.tlib_tick, &frequency, NULL);
tick_hz = rtems_configuration_get_microseconds_per_tick();
rtems_timecounter_simple_install(
&priv.tc_simple,
frequency,
(uint64_t)frequency,
tick_hz,
simple_tlib_tc_get_timecount
);

View File

@@ -0,0 +1,144 @@
/* SPDX-License-Identifier: BSD-2-Clause */
/**
* @file
*
* @ingroup can
*
* @brief Common CAN baud-rate routines for OCCAN/GRCAN/GRCANFD controllers
*
* Implements common routines for calculating CAN baud-rate parameters from
* a user provided baud-rate speed.
*/
/*
* Copyright (C) 2019, 2020 Cobham Gailer AB
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include <grlib/canbtrs.h>
/*#define GRLIB_CANBTRS_DEBUG*/
/* Calculate CAN baud-rate generation parameters from requested baud-rate */
int grlib_canbtrs_calc_timing(
unsigned int baud,
unsigned int core_hz,
unsigned int sampl_pt,
struct grlib_canbtrs_ranges *br,
struct grlib_canbtrs_timing *timing
)
{
int best_error = 2000000000, best_tseg=0, best_scaler=0;
int tseg=0, tseg1=0, tseg2=0, sc, tmp, error;
/* Default to 80% sample point */
if ((sampl_pt < 50) || (sampl_pt > 99))
sampl_pt = 80;
/* step though all TSEG1+TSEG2 values possible */
for (tseg = (br->min_tseg1 + br->min_tseg2);
tseg <= (br->max_tseg1 + br->max_tseg2);
tseg++) {
/* calculate scaler */
tmp = ((br->divfactor + tseg) * baud);
sc = (core_hz * 2)/ tmp - core_hz / tmp;
if (sc <= 0 || sc > br->max_scaler)
continue;
if (br->has_bpr &&
(((sc > 256 * 1) && (sc <= 256 * 2) && (sc & 0x1)) ||
((sc > 256 * 2) && (sc <= 256 * 4) && (sc & 0x3)) ||
((sc > 256 * 4) && (sc <= 256 * 8) && (sc & 0x7))))
continue;
error = baud - core_hz / (sc * (br->divfactor + tseg));
#ifdef GRLIB_CANBTRS_DEBUG
printf(" baud=%d, tseg=%d, sc=%d, error=%d\n",
baud, tseg, sc, error);
#endif
if (error < 0)
error = -error;
/* tseg is increasing, so we accept higher tseg with the same
* baudrate to get better sampling point.
*/
if (error <= best_error) {
best_error = error;
best_tseg = tseg;
best_scaler = sc;
#ifdef GRLIB_CANBTRS_DEBUG
printf(" ! best baud=%d\n",
core_hz/(sc * (br->divfactor + tseg)));
#endif
}
}
/* return an error if 5% off baud-rate */
if (best_error && (baud / best_error <= 5)) {
return -2;
} else if (!timing) {
return 0; /* nothing to store result in, but a valid bitrate can be calculated */
}
tseg2 = (best_tseg + br->divfactor) -
((sampl_pt * (best_tseg + br->divfactor)) / 100);
if (tseg2 < br->min_tseg2) {
tseg2 = br->min_tseg2;
} else if (tseg2 > br->max_tseg2) {
tseg2 = br->max_tseg2;
}
tseg1 = best_tseg - tseg2;
if (tseg1 > br->max_tseg1) {
tseg1 = br->max_tseg1;
tseg2 = best_tseg - tseg1;
} else if (tseg1 < br->min_tseg1) {
tseg1 = br->min_tseg1;
tseg2 = best_tseg - tseg1;
}
/* Get scaler and BPR from pseudo SCALER clock */
if (best_scaler <= 256) {
timing->scaler = best_scaler - 1;
timing->bpr = 0;
} else if (best_scaler <= 256 * 2) {
timing->scaler = ((best_scaler + 1) >> 1) - 1;
timing->bpr = 1;
} else if (best_scaler <= 256 * 4) {
timing->scaler = ((best_scaler + 1) >> 2) - 1;
timing->bpr = 2;
} else {
timing->scaler = ((best_scaler + 1) >> 3) - 1;
timing->bpr = 3;
}
timing->ps1 = tseg1;
timing->ps2 = tseg2;
timing->rsj = 1;
#ifdef GRLIB_CANBTRS_DEBUG
printf(" ! result: sc=%d,bpr=%d,ps1=%d,ps2=%d\n", timing->scaler, timing->bpr, timing->ps1, timing->ps2);
#endif
return 0;
}

View File

@@ -1,7 +1,7 @@
/*
* GRCAN driver
*
* COPYRIGHT (c) 2007.
* COPYRIGHT (c) 2007-2019.
* Cobham Gaisler AB.
*
* The license and distribution terms for this file may be
@@ -18,18 +18,17 @@
#include <rtems/bspIo.h>
#include <grlib/grcan.h>
#include <grlib/canbtrs.h>
#include <drvmgr/drvmgr.h>
#include <grlib/ambapp_bus.h>
#include <grlib/ambapp.h>
#include <grlib/grlib_impl.h>
#include "grcan_internal.h"
/* Maximum number of GRCAN devices supported by driver */
#define GRCAN_COUNT_MAX 8
#define WRAP_AROUND_TX_MSGS 1
#define WRAP_AROUND_RX_MSGS 2
#define GRCAN_MSG_SIZE sizeof(struct grcan_msg)
#define BLOCK_SIZE (16*4)
/* grcan needs to have it buffers aligned to 1k boundaries */
@@ -57,15 +56,6 @@
#define IRQ_MASK(irqno)
#endif
#ifndef GRCAN_DEFAULT_BAUD
/* default to 500kbits/s */
#define GRCAN_DEFAULT_BAUD 500000
#endif
#ifndef GRCAN_SAMPLING_POINT
#define GRCAN_SAMPLING_POINT 80
#endif
/* Uncomment for debug output */
/****************** DEBUG Definitions ********************/
#define DBG_TX 2
@@ -88,70 +78,10 @@ int state2err[4] = {
/* STATE_AHBERR */ GRCAN_RET_AHBERR
};
struct grcan_msg {
unsigned int head[2];
unsigned char data[8];
};
struct grcan_config {
struct grcan_timing timing;
struct grcan_selection selection;
int abort;
int silent;
};
struct grcan_priv {
struct drvmgr_dev *dev; /* Driver manager device */
char devName[32]; /* Device Name */
unsigned int baseaddr, ram_base;
struct grcan_regs *regs;
int irq;
int minor;
int open;
int started;
unsigned int channel;
int flushing;
unsigned int corefreq_hz;
/* Circular DMA buffers */
void *_rx, *_rx_hw;
void *_tx, *_tx_hw;
void *txbuf_adr;
void *rxbuf_adr;
struct grcan_msg *rx;
struct grcan_msg *tx;
unsigned int rxbuf_size; /* requested RX buf size in bytes */
unsigned int txbuf_size; /* requested TX buf size in bytes */
int txblock, rxblock;
int txcomplete, rxcomplete;
struct grcan_filter sfilter;
struct grcan_filter afilter;
int config_changed; /* 0=no changes, 1=changes ==> a Core reset is needed */
struct grcan_config config;
struct grcan_stats stats;
rtems_id rx_sem, tx_sem, txempty_sem, dev_sem;
SPIN_DECLARE(devlock);
};
static void __inline__ grcan_hw_reset(struct grcan_regs *regs);
static int grcan_hw_read_try(
struct grcan_priv *pDev,
struct grcan_regs *regs,
CANMsg *buffer,
int max);
static int grcan_hw_write_try(
struct grcan_priv *pDev,
struct grcan_regs *regs,
CANMsg *buffer,
int count);
static void grcan_hw_config(
struct grcan_regs *regs,
struct grcan_priv *pDev,
struct grcan_config *conf);
static void grcan_hw_accept(
@@ -164,22 +94,41 @@ static void grcan_hw_sync(
static void grcan_interrupt(void *arg);
#ifdef GRCAN_REG_BYPASS_CACHE
#define READ_REG(address) grlib_read_uncached32((unsigned int)(address))
#else
#define READ_REG(address) (*(volatile unsigned int *)(address))
#endif
#ifdef GRCAN_DMA_BYPASS_CACHE
#define READ_DMA_WORD(address) grlib_read_uncached32((unsigned int)(address))
#define READ_DMA_BYTE(address) grlib_read_uncached8((unsigned int)(address))
#else
#define READ_DMA_WORD(address) (*(volatile unsigned int *)(address))
#define READ_DMA_BYTE(address) (*(volatile unsigned char *)(address))
#endif
#define NELEM(a) ((int) (sizeof (a) / sizeof (a[0])))
/* GRCAN nominal boundaries for baud-rate paramters */
struct grlib_canbtrs_ranges grcan_btrs_ranges = {
.max_scaler = 256*8, /* scaler is multiplied by BPR in steps 1,2,4,8 */
.has_bpr = 1,
.divfactor = 2,
.min_tseg1 = 1,
.max_tseg1 = 15,
.min_tseg2 = 2,
.max_tseg2 = 8,
};
/* GRCANFD nominal boundaries */
struct grlib_canbtrs_ranges grcanfd_nom_btrs_ranges = {
.max_scaler = 256,
.has_bpr = 0,
.divfactor = 1,
.min_tseg1 = 2,
.max_tseg1 = 63,
.min_tseg2 = 2,
.max_tseg2 = 16,
};
/* GRCANFD flexible baud-rate boundaries */
struct grlib_canbtrs_ranges grcanfd_fd_btrs_ranges = {
.max_scaler = 256,
.has_bpr = 0,
.divfactor = 1,
.min_tseg1 = 1,
.max_tseg1 = 15,
.min_tseg2 = 2,
.max_tseg2 = 8,
};
static int grcan_count = 0;
static struct grcan_priv *priv_tab[GRCAN_COUNT_MAX];
@@ -202,6 +151,7 @@ struct amba_dev_id grcan_ids[] =
{
{VENDOR_GAISLER, GAISLER_GRCAN},
{VENDOR_GAISLER, GAISLER_GRHCAN},
{VENDOR_GAISLER, GAISLER_GRCANFD},
{0, 0} /* Mark end of table */
};
@@ -294,6 +244,8 @@ int grcan_device_init(struct grcan_priv *pDev)
pDev->irq = pnpinfo->irq;
pDev->regs = (struct grcan_regs *)pnpinfo->apb_slv->start;
pDev->minor = pDev->dev->minor_drv;
if (ambadev->id.device == GAISLER_GRCANFD)
pDev->fd_capable = 1;
/* Get frequency in Hz */
if ( drvmgr_freq_get(pDev->dev, DEV_APB_SLV, &pDev->corefreq_hz) ) {
@@ -373,7 +325,7 @@ static rtems_device_driver grcan_hw_start(struct grcan_priv *pDev)
* and Setup timing
*/
if (pDev->config_changed) {
grcan_hw_config(pDev->regs, &pDev->config);
grcan_hw_config(pDev, &pDev->config);
pDev->config_changed = 0;
}
@@ -456,9 +408,10 @@ static void grcan_sw_stop(struct grcan_priv *pDev)
rtems_semaphore_release(pDev->txempty_sem);
}
static void grcan_hw_config(struct grcan_regs *regs, struct grcan_config *conf)
static void grcan_hw_config(struct grcan_priv *pDev, struct grcan_config *conf)
{
unsigned int config = 0;
struct grcan_regs *regs = pDev->regs;
/* Reset HurriCANe Core */
regs->ctrl = 0;
@@ -479,13 +432,29 @@ static void grcan_hw_config(struct grcan_regs *regs, struct grcan_config *conf)
config |= GRCAN_CFG_ENABLE1;
/* Timing */
config |= (conf->timing.bpr << GRCAN_CFG_BPR_BIT) & GRCAN_CFG_BPR;
config |= (conf->timing.rsj << GRCAN_CFG_RSJ_BIT) & GRCAN_CFG_RSJ;
config |= (conf->timing.ps1 << GRCAN_CFG_PS1_BIT) & GRCAN_CFG_PS1;
config |= (conf->timing.ps2 << GRCAN_CFG_PS2_BIT) & GRCAN_CFG_PS2;
config |=
(conf->timing.scaler << GRCAN_CFG_SCALER_BIT) & GRCAN_CFG_SCALER;
if (!pDev->fd_capable) {
config |= (conf->timing.bpr << GRCAN_CFG_BPR_BIT) &
GRCAN_CFG_BPR;
config |= (conf->timing.rsj << GRCAN_CFG_RSJ_BIT) &
GRCAN_CFG_RSJ;
config |= (conf->timing.ps1 << GRCAN_CFG_PS1_BIT) &
GRCAN_CFG_PS1;
config |= (conf->timing.ps2 << GRCAN_CFG_PS2_BIT) &
GRCAN_CFG_PS2;
config |= (conf->timing.scaler << GRCAN_CFG_SCALER_BIT) &
GRCAN_CFG_SCALER;
} else {
regs->nbtr =
(conf->timing.scaler << GRCANFD_NBTR_SCALER_BIT) |
(conf->timing.ps1 << GRCANFD_NBTR_PS1_BIT) |
(conf->timing.ps2 << GRCANFD_NBTR_PS2_BIT) |
(conf->timing.rsj << GRCANFD_NBTR_SJW_BIT);
regs->fdbtr =
(conf->timing_fd.scaler << GRCANFD_FDBTR_SCALER_BIT) |
(conf->timing_fd.ps1 << GRCANFD_FDBTR_PS1_BIT) |
(conf->timing_fd.ps2 << GRCANFD_FDBTR_PS2_BIT) |
(conf->timing_fd.sjw << GRCANFD_FDBTR_SJW_BIT);
}
/* Write configuration */
regs->conf = config;
@@ -520,338 +489,7 @@ static void grcan_hw_sync(struct grcan_regs *regs, struct grcan_filter *sfilter)
regs->smask = sfilter->mask;
}
static unsigned int grcan_hw_rxavail(
unsigned int rp,
unsigned int wp, unsigned int size
)
{
if (rp == wp) {
/* read pointer and write pointer is equal only
* when RX buffer is empty.
*/
return 0;
}
if (wp > rp) {
return (wp - rp) / GRCAN_MSG_SIZE;
} else {
return (size - (rp - wp)) / GRCAN_MSG_SIZE;
}
}
static unsigned int grcan_hw_txspace(
unsigned int rp,
unsigned int wp,
unsigned int size
)
{
unsigned int left;
if (rp == wp) {
/* read pointer and write pointer is equal only
* when TX buffer is empty.
*/
return size / GRCAN_MSG_SIZE - WRAP_AROUND_TX_MSGS;
}
/* size - 4 - abs(read-write) */
if (wp > rp) {
left = size - (wp - rp);
} else {
left = rp - wp;
}
return left / GRCAN_MSG_SIZE - WRAP_AROUND_TX_MSGS;
}
#define MIN_TSEG1 1
#define MIN_TSEG2 2
#define MAX_TSEG1 14
#define MAX_TSEG2 8
static int grcan_calc_timing(
unsigned int baud, /* The requested BAUD to calculate timing for */
unsigned int core_hz, /* Frequency in Hz of GRCAN Core */
unsigned int sampl_pt,
struct grcan_timing *timing /* result is placed here */
)
{
int best_error = 1000000000;
int error;
int best_tseg = 0, best_brp = 0, brp = 0;
int tseg = 0, tseg1 = 0, tseg2 = 0;
int sjw = 1;
/* Default to 90% */
if ((sampl_pt < 50) || (sampl_pt > 99)) {
sampl_pt = GRCAN_SAMPLING_POINT;
}
if ((baud < 5000) || (baud > 1000000)) {
/* invalid speed mode */
return -1;
}
/* find best match, return -2 if no good reg
* combination is available for this frequency
*/
/* some heuristic specials */
if (baud > ((1000000 + 500000) / 2))
sampl_pt = 75;
if (baud < ((12500 + 10000) / 2))
sampl_pt = 75;
/* tseg even = round down, odd = round up */
for (
tseg = (MIN_TSEG1 + MIN_TSEG2 + 2) * 2;
tseg <= (MAX_TSEG2 + MAX_TSEG1 + 2) * 2 + 1;
tseg++
) {
brp = core_hz / ((1 + tseg / 2) * baud) + tseg % 2;
if (
(brp <= 0) ||
((brp > 256 * 1) && (brp <= 256 * 2) && (brp & 0x1)) ||
((brp > 256 * 2) && (brp <= 256 * 4) && (brp & 0x3)) ||
((brp > 256 * 4) && (brp <= 256 * 8) && (brp & 0x7)) ||
(brp > 256 * 8)
)
continue;
error = baud - core_hz / (brp * (1 + tseg / 2));
if (error < 0) {
error = -error;
}
if (error <= best_error) {
best_error = error;
best_tseg = tseg / 2;
best_brp = brp - 1;
}
}
if (best_error && (baud / best_error < 10)) {
return -2;
} else if (!timing)
return 0; /* nothing to store result in, but a valid bitrate can be calculated */
tseg2 = best_tseg - (sampl_pt * (best_tseg + 1)) / 100;
if (tseg2 < MIN_TSEG2) {
tseg2 = MIN_TSEG2;
}
if (tseg2 > MAX_TSEG2) {
tseg2 = MAX_TSEG2;
}
tseg1 = best_tseg - tseg2 - 2;
if (tseg1 > MAX_TSEG1) {
tseg1 = MAX_TSEG1;
tseg2 = best_tseg - tseg1 - 2;
}
/* Get scaler and BRP from pseudo BRP */
if (best_brp <= 256) {
timing->scaler = best_brp;
timing->bpr = 0;
} else if (best_brp <= 256 * 2) {
timing->scaler = ((best_brp + 1) >> 1) - 1;
timing->bpr = 1;
} else if (best_brp <= 256 * 4) {
timing->scaler = ((best_brp + 1) >> 2) - 1;
timing->bpr = 2;
} else {
timing->scaler = ((best_brp + 1) >> 3) - 1;
timing->bpr = 3;
}
timing->ps1 = tseg1 + 1;
timing->ps2 = tseg2;
timing->rsj = sjw;
return 0;
}
static int grcan_hw_read_try(
struct grcan_priv *pDev,
struct grcan_regs *regs,
CANMsg * buffer,
int max
)
{
int i, j;
CANMsg *dest;
struct grcan_msg *source, tmp;
unsigned int wp, rp, size, rxmax, addr;
int trunk_msg_cnt;
FUNCDBG();
wp = READ_REG(&regs->rx0wr);
rp = READ_REG(&regs->rx0rd);
/*
* Due to hardware wrap around simplification write pointer will
* never reach the read pointer, at least a gap of 8 bytes.
* The only time they are equal is when the read pointer has
* reached the write pointer (empty buffer)
*
*/
if (wp != rp) {
/* Not empty, we have received chars...
* Read as much as possible from DMA buffer
*/
size = READ_REG(&regs->rx0size);
/* Get number of bytes available in RX buffer */
trunk_msg_cnt = grcan_hw_rxavail(rp, wp, size);
/* truncate size if user space buffer hasn't room for
* all received chars.
*/
if (trunk_msg_cnt > max)
trunk_msg_cnt = max;
/* Read until i is 0 */
i = trunk_msg_cnt;
addr = (unsigned int)pDev->rx;
source = (struct grcan_msg *)(addr + rp);
dest = buffer;
rxmax = addr + (size - GRCAN_MSG_SIZE);
/* Read as many can messages as possible */
while (i > 0) {
/* Read CAN message from DMA buffer */
tmp.head[0] = READ_DMA_WORD(&source->head[0]);
tmp.head[1] = READ_DMA_WORD(&source->head[1]);
if (tmp.head[1] & 0x4) {
DBGC(DBG_RX, "overrun\n");
}
if (tmp.head[1] & 0x2) {
DBGC(DBG_RX, "bus-off mode\n");
}
if (tmp.head[1] & 0x1) {
DBGC(DBG_RX, "error-passive mode\n");
}
/* Convert one grcan CAN message to one "software" CAN message */
dest->extended = tmp.head[0] >> 31;
dest->rtr = (tmp.head[0] >> 30) & 0x1;
if (dest->extended) {
dest->id = tmp.head[0] & 0x3fffffff;
} else {
dest->id = (tmp.head[0] >> 18) & 0xfff;
}
dest->len = tmp.head[1] >> 28;
for (j = 0; j < dest->len; j++)
dest->data[j] = READ_DMA_BYTE(&source->data[j]);
/* wrap around if neccessary */
source =
((unsigned int)source >= rxmax) ?
(struct grcan_msg *)addr : source + 1;
dest++; /* straight user buffer */
i--;
}
{
/* A bus off interrupt may have occured after checking pDev->started */
SPIN_IRQFLAGS(oldLevel);
SPIN_LOCK_IRQ(&pDev->devlock, oldLevel);
if (pDev->started == STATE_STARTED) {
regs->rx0rd = (unsigned int) source - addr;
regs->rx0ctrl = GRCAN_RXCTRL_ENABLE;
} else {
DBGC(DBG_STATE, "cancelled due to a BUS OFF error\n");
trunk_msg_cnt = state2err[pDev->started];
}
SPIN_UNLOCK_IRQ(&pDev->devlock, oldLevel);
}
return trunk_msg_cnt;
}
return 0;
}
static int grcan_hw_write_try(
struct grcan_priv *pDev,
struct grcan_regs *regs,
CANMsg * buffer,
int count
)
{
unsigned int rp, wp, size, txmax, addr;
int ret;
struct grcan_msg *dest;
CANMsg *source;
int space_left;
unsigned int tmp;
int i;
DBGC(DBG_TX, "\n");
/*FUNCDBG(); */
rp = READ_REG(&regs->tx0rd);
wp = READ_REG(&regs->tx0wr);
size = READ_REG(&regs->tx0size);
space_left = grcan_hw_txspace(rp, wp, size);
/* is circular fifo full? */
if (space_left < 1)
return 0;
/* Truncate size */
if (space_left > count)
space_left = count;
ret = space_left;
addr = (unsigned int)pDev->tx;
dest = (struct grcan_msg *)(addr + wp);
source = (CANMsg *) buffer;
txmax = addr + (size - GRCAN_MSG_SIZE);
while (space_left > 0) {
/* Convert and write CAN message to DMA buffer */
if (source->extended) {
tmp = (1 << 31) | (source->id & 0x3fffffff);
} else {
tmp = (source->id & 0xfff) << 18;
}
if (source->rtr)
tmp |= (1 << 30);
dest->head[0] = tmp;
dest->head[1] = source->len << 28;
for (i = 0; i < source->len; i++)
dest->data[i] = source->data[i];
source++; /* straight user buffer */
dest =
((unsigned int)dest >= txmax) ?
(struct grcan_msg *)addr : dest + 1;
space_left--;
}
{
/* A bus off interrupt may have occured after checking pDev->started */
SPIN_IRQFLAGS(oldLevel);
SPIN_LOCK_IRQ(&pDev->devlock, oldLevel);
if (pDev->started == STATE_STARTED) {
regs->tx0wr = (unsigned int) dest - addr;
regs->tx0ctrl = GRCAN_TXCTRL_ENABLE;
} else {
DBGC(DBG_STATE, "cancelled due to a BUS OFF error\n");
ret = state2err[pDev->started];
}
SPIN_UNLOCK_IRQ(&pDev->devlock, oldLevel);
}
return ret;
}
static int grcan_wait_rxdata(struct grcan_priv *pDev, int min)
int grcan_wait_rxdata(struct grcan_priv *pDev, int min)
{
unsigned int wp, rp, size, irq;
unsigned int irq_trunk, dataavail;
@@ -934,7 +572,7 @@ static int grcan_wait_rxdata(struct grcan_priv *pDev, int min)
* min must be at least WRAP_AROUND_TX_MSGS less than max buffer capacity
* (pDev->txbuf_size/GRCAN_MSG_SIZE) for this algo to work.
*/
static int grcan_wait_txspace(struct grcan_priv *pDev, int min)
int grcan_wait_txspace(struct grcan_priv *pDev, int min)
{
int wait, state;
unsigned int irq, rp, wp, size, space_left;
@@ -1007,7 +645,7 @@ static int grcan_wait_txspace(struct grcan_priv *pDev, int min)
return state2err[pDev->started];
}
/* At this point the TxIRQ has been masked, we ned not to mask it */
/* At this point the TxIRQ has been masked, we need not to mask it */
return 0;
}
@@ -1211,6 +849,7 @@ void *grcan_open(int dev_no)
struct grcan_priv *pDev;
void *ret;
union drvmgr_key_value *value;
struct grlib_canbtrs_ranges *br;
FUNCDBG();
@@ -1282,7 +921,13 @@ void *grcan_open(int dev_no)
pDev->sfilter.code = 0x00000000;
/* Calculate default timing register values */
grcan_calc_timing(GRCAN_DEFAULT_BAUD,pDev->corefreq_hz,GRCAN_SAMPLING_POINT,&pDev->config.timing);
if (pDev->fd_capable)
br = &grcanfd_nom_btrs_ranges;
else
br = &grcan_btrs_ranges;
grlib_canbtrs_calc_timing(
GRCAN_DEFAULT_BAUD, pDev->corefreq_hz, GRCAN_SAMPLING_POINT,
br, (struct grlib_canbtrs_timing *)&pDev->config.timing);
if ( grcan_alloc_buffers(pDev,1,1) ) {
ret = NULL;
@@ -1316,174 +961,11 @@ int grcan_close(void *d)
return 0;
}
int grcan_read(void *d, CANMsg *msg, size_t ucount)
int grcan_canfd_capable(void *d)
{
struct grcan_priv *pDev = d;
CANMsg *dest;
unsigned int count, left;
int nread;
int req_cnt;
FUNCDBG();
dest = msg;
req_cnt = ucount;
if ( (!dest) || (req_cnt<1) )
return GRCAN_RET_INVARG;
if (pDev->started != STATE_STARTED) {
return GRCAN_RET_NOTSTARTED;
}
DBGC(DBG_RX, "grcan_read [%p]: buf: %p len: %u\n", d, msg, (unsigned int) ucount);
nread = grcan_hw_read_try(pDev,pDev->regs,dest,req_cnt);
if (nread < 0) {
return nread;
}
count = nread;
if ( !( pDev->rxblock && pDev->rxcomplete && (count!=req_cnt) ) ){
if ( count > 0 ) {
/* Successfully received messages (at least one) */
return count;
}
/* nothing read, shall we block? */
if ( !pDev->rxblock ) {
/* non-blocking mode */
return GRCAN_RET_TIMEOUT;
}
}
while (count == 0 || (pDev->rxcomplete && (count!=req_cnt))) {
if (!pDev->rxcomplete) {
left = 1; /* return as soon as there is one message available */
} else {
left = req_cnt - count; /* return as soon as all data are available */
/* never wait for more than the half the maximum size of the receive buffer
* Why? We need some time to copy buffer before to catch up with hw,
* otherwise we would have to copy everything when the data has been
* received.
*/
if (left > ((pDev->rxbuf_size/GRCAN_MSG_SIZE) / 2)){
left = (pDev->rxbuf_size/GRCAN_MSG_SIZE) / 2;
}
}
nread = grcan_wait_rxdata(pDev, left);
if (nread) {
/* The wait has been aborted, probably due to
* the device driver has been closed by another
* thread or a bus-off. Return error code.
*/
return nread;
}
/* Try read bytes from circular buffer */
nread = grcan_hw_read_try(
pDev,
pDev->regs,
dest+count,
req_cnt-count);
if (nread < 0) {
/* The read was aborted by bus-off. */
return nread;
}
count += nread;
}
/* no need to unmask IRQ as IRQ Handler do that for us. */
return count;
}
int grcan_write(void *d, CANMsg *msg, size_t ucount)
{
struct grcan_priv *pDev = d;
CANMsg *source;
unsigned int count, left;
int nwritten;
int req_cnt;
DBGC(DBG_TX,"\n");
if ((pDev->started != STATE_STARTED) || pDev->config.silent || pDev->flushing)
return GRCAN_RET_NOTSTARTED;
req_cnt = ucount;
source = (CANMsg *) msg;
/* check proper length and buffer pointer */
if (( req_cnt < 1) || (source == NULL) ){
return GRCAN_RET_INVARG;
}
nwritten = grcan_hw_write_try(pDev,pDev->regs,source,req_cnt);
if (nwritten < 0) {
return nwritten;
}
count = nwritten;
if ( !(pDev->txblock && pDev->txcomplete && (count!=req_cnt)) ) {
if ( count > 0 ) {
/* Successfully transmitted chars (at least one char) */
return count;
}
/* nothing written, shall we block? */
if ( !pDev->txblock ) {
/* non-blocking mode */
return GRCAN_RET_TIMEOUT;
}
}
/* if in txcomplete mode we need to transmit all chars */
while((count == 0) || (pDev->txcomplete && (count!=req_cnt)) ){
/*** block until room to fit all or as much of transmit buffer as possible
* IRQ comes. Set up a valid IRQ point so that an IRQ is received
* when we can put a chunk of data into transmit fifo
*/
if ( !pDev->txcomplete ){
left = 1; /* wait for anything to fit buffer */
}else{
left = req_cnt - count; /* wait for all data to fit in buffer */
/* never wait for more than the half the maximum size of the transmit
* buffer
* Why? We need some time to fill buffer before hw catches up.
*/
if ( left > ((pDev->txbuf_size/GRCAN_MSG_SIZE)/2) ){
left = (pDev->txbuf_size/GRCAN_MSG_SIZE)/2;
}
}
nwritten = grcan_wait_txspace(pDev,left);
/* Wait until more room in transmit buffer */
if ( nwritten ) {
/* The wait has been aborted, probably due to
* the device driver has been closed by another
* thread. To avoid deadlock we return directly
* with error status.
*/
return nwritten;
}
/* Try read bytes from circular buffer */
nwritten = grcan_hw_write_try(
pDev,
pDev->regs,
source+count,
req_cnt-count);
if (nwritten < 0) {
/* Write was aborted by bus-off. */
return nwritten;
}
count += nwritten;
}
/* no need to unmask IRQ as IRQ Handler do that for us. */
return count;
return pDev->fd_capable;
}
int grcan_start(void *d)
@@ -1712,51 +1194,6 @@ int grcan_clr_stats(void *d)
return 0;
}
int grcan_set_speed(void *d, unsigned int speed)
{
struct grcan_priv *pDev = d;
struct grcan_timing timing;
int ret;
FUNCDBG();
/* cannot change speed during run mode */
if (pDev->started == STATE_STARTED)
return -1;
/* get speed rate from argument */
ret = grcan_calc_timing(speed, pDev->corefreq_hz, GRCAN_SAMPLING_POINT, &timing);
if ( ret )
return -2;
/* save timing/speed */
pDev->config.timing = timing;
pDev->config_changed = 1;
return 0;
}
int grcan_set_btrs(void *d, const struct grcan_timing *timing)
{
struct grcan_priv *pDev = d;
FUNCDBG();
/* Set BTR registers manually
* Read GRCAN/HurriCANe Manual.
*/
if (pDev->started == STATE_STARTED)
return -1;
if ( !timing )
return -2;
pDev->config.timing = *timing;
pDev->config_changed = 1;
return 0;
}
int grcan_set_afilter(void *d, const struct grcan_filter *filter)
{
struct grcan_priv *pDev = d;

View File

@@ -0,0 +1,140 @@
/*
* GRCAN driver
*
* COPYRIGHT (c) 2007-2019.
* Cobham Gaisler AB.
*
* The license and distribution terms for this file may be
* found in the file LICENSE in this distribution or at
* http://www.rtems.org/license/LICENSE.
*/
#ifndef GRCAN_DEFAULT_BAUD
/* default to 500kbits/s */
#define GRCAN_DEFAULT_BAUD 500000
#endif
#ifndef GRCAN_SAMPLING_POINT
#define GRCAN_SAMPLING_POINT 80
#endif
#define WRAP_AROUND_TX_MSGS 1
#define WRAP_AROUND_RX_MSGS 2
#define GRCAN_MSG_SIZE sizeof(struct grcan_msg)
struct grcan_msg {
unsigned int head[2];
unsigned char data[8];
};
struct grcan_config {
struct grcan_timing timing;
struct grcanfd_timing timing_fd;
struct grcan_selection selection;
int abort;
int silent;
};
struct grcan_priv {
struct drvmgr_dev *dev; /* Driver manager device */
char devName[32]; /* Device Name */
unsigned int baseaddr, ram_base;
struct grcan_regs *regs;
int irq;
int minor;
int open;
int started;
unsigned int channel;
int flushing;
unsigned int corefreq_hz;
int fd_capable;
/* Circular DMA buffers */
void *_rx, *_rx_hw;
void *_tx, *_tx_hw;
void *txbuf_adr;
void *rxbuf_adr;
struct grcan_msg *rx;
struct grcan_msg *tx;
unsigned int rxbuf_size; /* requested RX buf size in bytes */
unsigned int txbuf_size; /* requested TX buf size in bytes */
int txblock, rxblock;
int txcomplete, rxcomplete;
struct grcan_filter sfilter;
struct grcan_filter afilter;
int config_changed; /* 0=no changes, 1=changes ==> a Core reset is needed */
struct grcan_config config;
struct grcan_stats stats;
rtems_id rx_sem, tx_sem, txempty_sem, dev_sem;
SPIN_DECLARE(devlock);
};
#ifdef GRCAN_REG_BYPASS_CACHE
#define READ_REG(address) grlib_read_uncached32((unsigned int)(address))
#else
#define READ_REG(address) (*(volatile unsigned int *)(address))
#endif
#ifdef GRCAN_DMA_BYPASS_CACHE
#define READ_DMA_DOUBLE(address) grlib_read_uncached64((uint64_t *)(address))
#define READ_DMA_WORD(address) grlib_read_uncached32((unsigned int)(address))
#define READ_DMA_BYTE(address) grlib_read_uncached8((unsigned int)(address))
#else
#define READ_DMA_DOUBLE(address) (*(volatile uint64_t *)(address))
#define READ_DMA_WORD(address) (*(volatile unsigned int *)(address))
#define READ_DMA_BYTE(address) (*(volatile unsigned char *)(address))
#endif
extern int state2err[4];
extern struct grlib_canbtrs_ranges grcan_btrs_ranges;
extern struct grlib_canbtrs_ranges grcanfd_nom_btrs_ranges;
extern struct grlib_canbtrs_ranges grcanfd_fd_btrs_ranges;
int grcan_wait_rxdata(struct grcan_priv *pDev, int min);
int grcan_wait_txspace(struct grcan_priv *pDev, int min);
static inline unsigned int grcan_hw_rxavail(
unsigned int rp,
unsigned int wp,
unsigned int size)
{
if (rp == wp) {
/* read pointer and write pointer is equal only
* when RX buffer is empty.
*/
return 0;
}
if (wp > rp) {
return (wp - rp) / GRCAN_MSG_SIZE;
} else {
return (size - (rp - wp)) / GRCAN_MSG_SIZE;
}
}
static inline unsigned int grcan_hw_txspace(
unsigned int rp,
unsigned int wp,
unsigned int size)
{
unsigned int left;
if (rp == wp) {
/* read pointer and write pointer is equal only
* when TX buffer is empty.
*/
return size / GRCAN_MSG_SIZE - WRAP_AROUND_TX_MSGS;
}
/* size - 4 - abs(read-write) */
if (wp > rp) {
left = size - (wp - rp);
} else {
left = rp - wp;
}
return left / GRCAN_MSG_SIZE - WRAP_AROUND_TX_MSGS;
}

View File

@@ -0,0 +1,535 @@
/*
* FD extenstions to the GRCAN driver
*
* COPYRIGHT (c) 2007-2019.
* Cobham Gaisler AB.
*
* The license and distribution terms for this file may be
* found in the file LICENSE in this distribution or at
* http://www.rtems.org/license/LICENSE.
*/
#include <bsp.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <assert.h>
#include <ctype.h>
#include <rtems/bspIo.h>
#include <grlib/grcan.h>
#include <grlib/canbtrs.h>
#include <drvmgr/drvmgr.h>
#include <grlib/ambapp_bus.h>
#include <grlib/ambapp.h>
#include <grlib/grlib_impl.h>
#include "grcan_internal.h"
/* Uncomment for debug output */
/****************** DEBUG Definitions ********************/
#define DBG_TX 2
#define DBG_RX 4
#define DBG_STATE 8
#define DEBUG_FLAGS (DBG_STATE | DBG_RX | DBG_TX )
/*
#define DEBUG
#define DEBUGFUNCS
*/
#include <grlib/debug_defs.h>
/*********************************************************/
struct grcanfd_bd0 {
uint32_t head[2];
uint64_t data0; /* variable size, from 1 to 8 dwords */
};
struct grcanfd_bd1 {
unsigned long long data[2];
};
static uint8_t dlc2len[16] = {
0, 1, 2, 3,
4, 5, 6, 7,
8, 12, 16, 20,
24, 32, 48, 64
};
static uint8_t len2fddlc[14] = {
/* 12,13 */ 0x9,
/* 16,17 */ 0xA,
/* 20,21 */ 0xB,
/* 24,25 */ 0xC,
/* 28,29 */ -1,
/* 32,33 */ 0xD,
/* 36,37 */ -1,
/* 40,41 */ -1,
/* 44,45 */ -1,
/* 48,49 */ 0xE,
/* 52,53 */ -1,
/* 56,57 */ -1,
/* 60,61 */ -1,
/* 64,65 */ 0xF,
};
/* Convert length in bytes to descriptor length field */
static inline uint8_t grcan_len2dlc(int len)
{
if (len <= 8)
return len;
if (len > 64)
return -1;
if (len & 0x3)
return -1;
return len2fddlc[(len - 12) >> 2];
}
static inline int grcan_numbds(int len)
{
return 1 + ((len + 7) >> 4);
}
static int grcan_hw_read_try_fd(
struct grcan_priv *pDev,
struct grcan_regs *regs,
CANFDMsg * buffer,
int max)
{
int j;
CANFDMsg *dest;
struct grcanfd_bd0 *source, tmp, *rxmax;
unsigned int wp, rp, size, addr;
int bds_hw_avail, bds_tot, bds, ret, dlc;
uint64_t *dp;
SPIN_IRQFLAGS(oldLevel);
FUNCDBG();
wp = READ_REG(&regs->rx0wr);
rp = READ_REG(&regs->rx0rd);
/*
* Due to hardware wrap around simplification write pointer will
* never reach the read pointer, at least a gap of 8 bytes.
* The only time they are equal is when the read pointer has
* reached the write pointer (empty buffer)
*
*/
if (wp != rp) {
/* Not empty, we have received chars...
* Read as much as possible from DMA buffer
*/
size = READ_REG(&regs->rx0size);
/* Get number of bytes available in RX buffer */
bds_hw_avail = grcan_hw_rxavail(rp, wp, size);
addr = (unsigned int)pDev->rx;
source = (struct grcanfd_bd0 *)(addr + rp);
dest = buffer;
rxmax = (struct grcanfd_bd0 *)(addr + size);
ret = bds_tot = 0;
/* Read as many can messages as possible */
while ((ret < max) && (bds_tot < bds_hw_avail)) {
/* Read CAN message from DMA buffer */
*(uint64_t *)&tmp = READ_DMA_DOUBLE(source);
if (tmp.head[1] & 0x4) {
DBGC(DBG_RX, "overrun\n");
}
if (tmp.head[1] & 0x2) {
DBGC(DBG_RX, "bus-off mode\n");
}
if (tmp.head[1] & 0x1) {
DBGC(DBG_RX, "error-passive mode\n");
}
/* Convert one grcan CAN message to one "software" CAN message */
dest->extended = tmp.head[0] >> 31;
dest->rtr = (tmp.head[0] >> 30) & 0x1;
if (dest->extended) {
dest->id = tmp.head[0] & 0x3fffffff;
} else {
dest->id = (tmp.head[0] >> 18) & 0xfff;
}
dest->fdopts = (tmp.head[1] >> 25) & GRCAN_FDMASK;
dlc = tmp.head[1] >> 28;
if (dest->fdopts & GRCAN_FDOPT_FDFRM) {
dest->len = dlc2len[dlc];
} else {
dest->len = dlc;
if (dlc > 8)
dest->len = 8;
}
dp = (uint64_t *)&source->data0;
for (j = 0; j < ((dest->len + 7) / 8); j++) {
dest->data.dwords[j] = READ_DMA_DOUBLE(dp);
if (++dp >= (uint64_t *)rxmax)
dp = (uint64_t *)addr; /* wrap around */
}
/* wrap around if neccessary */
bds = grcan_numbds(dest->len);
source += bds;
if (source >= rxmax) {
source = (struct grcanfd_bd0 *)
((void *)source - size);
}
dest++; /* straight user buffer */
ret++;
bds_tot += bds;
}
/* A bus off interrupt may have occured after checking pDev->started */
SPIN_LOCK_IRQ(&pDev->devlock, oldLevel);
if (pDev->started == STATE_STARTED) {
regs->rx0rd = (unsigned int) source - addr;
regs->rx0ctrl = GRCAN_RXCTRL_ENABLE;
} else {
DBGC(DBG_STATE, "cancelled due to a BUS OFF error\n");
ret = state2err[pDev->started];
}
SPIN_UNLOCK_IRQ(&pDev->devlock, oldLevel);
return ret;
}
return 0;
}
int grcanfd_read(void *d, CANFDMsg *msg, size_t ucount)
{
struct grcan_priv *pDev = d;
CANFDMsg *dest;
unsigned int count, left;
int nread;
int req_cnt;
FUNCDBG();
dest = msg;
req_cnt = ucount;
if ( (!dest) || (req_cnt<1) )
return GRCAN_RET_INVARG;
if (pDev->started != STATE_STARTED) {
return GRCAN_RET_NOTSTARTED;
}
DBGC(DBG_RX, "grcan_read [%p]: buf: %p len: %u\n", d, msg, (unsigned int) ucount);
nread = grcan_hw_read_try_fd(pDev,pDev->regs,dest,req_cnt);
if (nread < 0) {
return nread;
}
count = nread;
if ( !( pDev->rxblock && pDev->rxcomplete && (count!=req_cnt) ) ){
if ( count > 0 ) {
/* Successfully received messages (at least one) */
return count;
}
/* nothing read, shall we block? */
if ( !pDev->rxblock ) {
/* non-blocking mode */
return GRCAN_RET_TIMEOUT;
}
}
while (count == 0 || (pDev->rxcomplete && (count!=req_cnt))) {
if (!pDev->rxcomplete) {
left = 1; /* return as soon as there is one message available */
} else {
left = req_cnt - count; /* return as soon as all data are available */
/* never wait for more than the half the maximum size of the receive buffer
* Why? We need some time to copy buffer before to catch up with hw,
* otherwise we would have to copy everything when the data has been
* received.
*/
if (left > ((pDev->rxbuf_size/GRCAN_MSG_SIZE) / 2)){
left = (pDev->rxbuf_size/GRCAN_MSG_SIZE) / 2;
}
}
nread = grcan_wait_rxdata(pDev, left);
if (nread) {
/* The wait has been aborted, probably due to
* the device driver has been closed by another
* thread or a bus-off. Return error code.
*/
return nread;
}
/* Try read bytes from circular buffer */
nread = grcan_hw_read_try_fd(
pDev,
pDev->regs,
dest+count,
req_cnt-count);
if (nread < 0) {
/* The read was aborted by bus-off. */
return nread;
}
count += nread;
}
/* no need to unmask IRQ as IRQ Handler do that for us. */
return count;
}
static int grcan_hw_write_try_fd(
struct grcan_priv *pDev,
struct grcan_regs *regs,
CANFDMsg *buffer,
int count)
{
unsigned int rp, wp, size, addr;
int ret;
struct grcanfd_bd0 *dest, *txmax;
CANFDMsg *source = (CANFDMsg *) buffer;
int space_left;
unsigned int tmp;
int i, bds;
uint64_t *dp;
uint8_t dlc;
SPIN_IRQFLAGS(oldLevel);
DBGC(DBG_TX, "\n");
rp = READ_REG(&regs->tx0rd);
wp = READ_REG(&regs->tx0wr);
size = READ_REG(&regs->tx0size);
space_left = grcan_hw_txspace(rp, wp, size);
addr = (unsigned int)pDev->tx;
dest = (struct grcanfd_bd0 *)(addr + wp);
txmax = (struct grcanfd_bd0 *)(addr + size);
ret = 0;
while (source < &buffer[count]) {
/* Get the number of descriptors to wait for */
if (source->fdopts & GRCAN_FDOPT_FDFRM)
bds = grcan_numbds(source->len); /* next msg's buffers */
else
bds = 1;
if (space_left < bds)
break;
/* Convert and write CAN message to DMA buffer */
dlc = grcan_len2dlc(source->len);
if (dlc < 0) {
/* Bad user input. Report the number of written messages
* or an error when non sent.
*/
if (ret <= 0)
return GRCAN_RET_INVARG;
break;
}
dest->head[1] = (dlc << 28) |
((source->fdopts & GRCAN_FDMASK) << 25);
dp = &dest->data0;
for (i = 0; i < ((source->len + 7) / 8); i++) {
*dp++ = source->data.dwords[i];
if (dp >= (uint64_t *)txmax)
dp = (uint64_t *)addr; /* wrap around */
}
if (source->extended) {
tmp = (1 << 31) | (source->id & 0x3fffffff);
} else {
tmp = (source->id & 0xfff) << 18;
}
if (source->rtr)
tmp |= (1 << 30);
dest->head[0] = tmp;
source++; /* straight user buffer */
dest += bds;
if (dest >= txmax)
dest = (struct grcanfd_bd0 *)((void *)dest - size);
space_left -= bds;
ret++;
}
/* A bus off interrupt may have occured after checking pDev->started */
SPIN_LOCK_IRQ(&pDev->devlock, oldLevel);
if (pDev->started == STATE_STARTED) {
regs->tx0wr = (unsigned int) dest - addr;
regs->tx0ctrl = GRCAN_TXCTRL_ENABLE;
} else {
DBGC(DBG_STATE, "cancelled due to a BUS OFF error\n");
ret = state2err[pDev->started];
}
SPIN_UNLOCK_IRQ(&pDev->devlock, oldLevel);
return ret;
}
int grcanfd_write(
void *d,
CANFDMsg *msg,
size_t ucount)
{
struct grcan_priv *pDev = d;
CANFDMsg *source, *curr;
unsigned int count, left;
int nwritten;
int req_cnt;
DBGC(DBG_TX,"\n");
if ((pDev->started != STATE_STARTED) || pDev->config.silent || pDev->flushing)
return GRCAN_RET_NOTSTARTED;
req_cnt = ucount;
curr = source = (CANFDMsg *) msg;
/* check proper length and buffer pointer */
if (( req_cnt < 1) || (source == NULL) ){
return GRCAN_RET_INVARG;
}
nwritten = grcan_hw_write_try_fd(pDev,pDev->regs,source,req_cnt);
if (nwritten < 0) {
return nwritten;
}
count = nwritten;
if ( !(pDev->txblock && pDev->txcomplete && (count!=req_cnt)) ) {
if ( count > 0 ) {
/* Successfully transmitted chars (at least one char) */
return count;
}
/* nothing written, shall we block? */
if ( !pDev->txblock ) {
/* non-blocking mode */
return GRCAN_RET_TIMEOUT;
}
}
/* if in txcomplete mode we need to transmit all chars */
while((count == 0) || (pDev->txcomplete && (count!=req_cnt)) ){
/*** block until room to fit all or as much of transmit buffer
* as possible before IRQ comes. Set up a valid IRQ point so
* that an IRQ is triggered when we can put a chunk of data
* into transmit fifo.
*/
/* Get the number of descriptors to wait for */
curr = &source[count];
if (curr->fdopts & GRCAN_FDOPT_FDFRM)
left = grcan_numbds(curr->len); /* next msg's buffers */
else
left = 1;
if (pDev->txcomplete) {
/* Wait for all messages to fit into descriptor table.
* Assume all following msgs are single descriptors.
*/
left += req_cnt - count - 1;
if (left > ((pDev->txbuf_size/GRCAN_MSG_SIZE)/2)) {
left = (pDev->txbuf_size/GRCAN_MSG_SIZE)/2;
}
}
nwritten = grcan_wait_txspace(pDev,left);
/* Wait until more room in transmit buffer */
if ( nwritten ) {
/* The wait has been aborted, probably due to
* the device driver has been closed by another
* thread. To avoid deadlock we return directly
* with error status.
*/
return nwritten;
}
/* Try read bytes from circular buffer */
nwritten = grcan_hw_write_try_fd(
pDev,
pDev->regs,
source+count,
req_cnt-count);
if (nwritten < 0) {
/* Write was aborted by bus-off. */
return nwritten;
}
count += nwritten;
}
/* no need to unmask IRQ as IRQ Handler do that for us. */
return count;
}
int grcanfd_set_speed(void *d, unsigned int nom_hz, unsigned int fd_hz)
{
struct grcan_priv *pDev = d;
struct grlib_canbtrs_timing nom, fd;
int ret;
FUNCDBG();
/* cannot change speed during run mode */
if ((pDev->started == STATE_STARTED) || !pDev->fd_capable)
return -1;
/* get speed rate from argument */
ret = grlib_canbtrs_calc_timing(
nom_hz, pDev->corefreq_hz, GRCAN_SAMPLING_POINT,
&grcanfd_nom_btrs_ranges, &nom);
if ( ret )
return -2;
ret = grlib_canbtrs_calc_timing(
fd_hz, pDev->corefreq_hz, GRCAN_SAMPLING_POINT,
&grcanfd_fd_btrs_ranges, &fd);
if ( ret )
return -2;
/* save timing/speed */
pDev->config.timing = *(struct grcan_timing *)&nom;
pDev->config.timing_fd.scaler = fd.scaler;
pDev->config.timing_fd.ps1 = fd.ps1;
pDev->config.timing_fd.ps2 = fd.ps2;
pDev->config.timing_fd.sjw = fd.rsj;
pDev->config.timing_fd.resv_zero = 0;
pDev->config_changed = 1;
return 0;
}
int grcanfd_set_btrs(
void *d,
const struct grcanfd_timing *nominal,
const struct grcanfd_timing *fd)
{
struct grcan_priv *pDev = d;
FUNCDBG();
/* Set BTR registers manually
* Read GRCAN/HurriCANe Manual.
*/
if ((pDev->started == STATE_STARTED) || !pDev->fd_capable)
return -1;
if (!nominal)
return -2;
pDev->config.timing.scaler = nominal->scaler;
pDev->config.timing.ps1 = nominal->ps1;
pDev->config.timing.ps2 = nominal->ps2;
pDev->config.timing.rsj = nominal->sjw;
pDev->config.timing.bpr = 0;
if (fd) {
pDev->config.timing_fd = *fd;
} else {
memset(&pDev->config.timing_fd, 0,
sizeof(struct grcanfd_timing));
}
pDev->config_changed = 1;
return 0;
}

View File

@@ -0,0 +1,435 @@
/*
* non-FD specific function for GRCAN driver
*
* COPYRIGHT (c) 2007-2019.
* Cobham Gaisler AB.
*
* The license and distribution terms for this file may be
* found in the file LICENSE in this distribution or at
* http://www.rtems.org/license/LICENSE.
*/
#include <bsp.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <assert.h>
#include <ctype.h>
#include <rtems/bspIo.h>
#include <grlib/grcan.h>
#include <grlib/canbtrs.h>
#include <drvmgr/drvmgr.h>
#include <grlib/ambapp_bus.h>
#include <grlib/ambapp.h>
#include <grlib/grlib_impl.h>
#include "grcan_internal.h"
/* Uncomment for debug output */
/****************** DEBUG Definitions ********************/
#define DBG_TX 2
#define DBG_RX 4
#define DBG_STATE 8
#define DEBUG_FLAGS (DBG_STATE | DBG_RX | DBG_TX )
/*
#define DEBUG
#define DEBUGFUNCS
*/
#include <grlib/debug_defs.h>
static int grcan_hw_read_try(
struct grcan_priv *pDev,
struct grcan_regs *regs,
CANMsg * buffer,
int max
)
{
int i, j;
CANMsg *dest;
struct grcan_msg *source, tmp;
unsigned int wp, rp, size, rxmax, addr;
int trunk_msg_cnt;
FUNCDBG();
wp = READ_REG(&regs->rx0wr);
rp = READ_REG(&regs->rx0rd);
/*
* Due to hardware wrap around simplification write pointer will
* never reach the read pointer, at least a gap of 8 bytes.
* The only time they are equal is when the read pointer has
* reached the write pointer (empty buffer)
*
*/
if (wp != rp) {
/* Not empty, we have received chars...
* Read as much as possible from DMA buffer
*/
size = READ_REG(&regs->rx0size);
/* Get number of bytes available in RX buffer */
trunk_msg_cnt = grcan_hw_rxavail(rp, wp, size);
/* truncate size if user space buffer hasn't room for
* all received chars.
*/
if (trunk_msg_cnt > max)
trunk_msg_cnt = max;
/* Read until i is 0 */
i = trunk_msg_cnt;
addr = (unsigned int)pDev->rx;
source = (struct grcan_msg *)(addr + rp);
dest = buffer;
rxmax = addr + (size - GRCAN_MSG_SIZE);
/* Read as many can messages as possible */
while (i > 0) {
/* Read CAN message from DMA buffer */
tmp.head[0] = READ_DMA_WORD(&source->head[0]);
tmp.head[1] = READ_DMA_WORD(&source->head[1]);
if (tmp.head[1] & 0x4) {
DBGC(DBG_RX, "overrun\n");
}
if (tmp.head[1] & 0x2) {
DBGC(DBG_RX, "bus-off mode\n");
}
if (tmp.head[1] & 0x1) {
DBGC(DBG_RX, "error-passive mode\n");
}
/* Convert one grcan CAN message to one "software" CAN message */
dest->extended = tmp.head[0] >> 31;
dest->rtr = (tmp.head[0] >> 30) & 0x1;
if (dest->extended) {
dest->id = tmp.head[0] & 0x3fffffff;
} else {
dest->id = (tmp.head[0] >> 18) & 0xfff;
}
dest->len = tmp.head[1] >> 28;
for (j = 0; j < dest->len; j++)
dest->data[j] = READ_DMA_BYTE(&source->data[j]);
/* wrap around if neccessary */
source =
((unsigned int)source >= rxmax) ?
(struct grcan_msg *)addr : source + 1;
dest++; /* straight user buffer */
i--;
}
{
/* A bus off interrupt may have occured after checking pDev->started */
SPIN_IRQFLAGS(oldLevel);
SPIN_LOCK_IRQ(&pDev->devlock, oldLevel);
if (pDev->started == STATE_STARTED) {
regs->rx0rd = (unsigned int) source - addr;
regs->rx0ctrl = GRCAN_RXCTRL_ENABLE;
} else {
DBGC(DBG_STATE, "cancelled due to a BUS OFF error\n");
trunk_msg_cnt = state2err[pDev->started];
}
SPIN_UNLOCK_IRQ(&pDev->devlock, oldLevel);
}
return trunk_msg_cnt;
}
return 0;
}
static int grcan_hw_write_try(
struct grcan_priv *pDev,
struct grcan_regs *regs,
CANMsg * buffer,
int count
)
{
unsigned int rp, wp, size, txmax, addr;
int ret;
struct grcan_msg *dest;
CANMsg *source;
int space_left;
unsigned int tmp;
int i;
DBGC(DBG_TX, "\n");
/*FUNCDBG(); */
rp = READ_REG(&regs->tx0rd);
wp = READ_REG(&regs->tx0wr);
size = READ_REG(&regs->tx0size);
space_left = grcan_hw_txspace(rp, wp, size);
/* is circular fifo full? */
if (space_left < 1)
return 0;
/* Truncate size */
if (space_left > count)
space_left = count;
ret = space_left;
addr = (unsigned int)pDev->tx;
dest = (struct grcan_msg *)(addr + wp);
source = (CANMsg *) buffer;
txmax = addr + (size - GRCAN_MSG_SIZE);
while (space_left > 0) {
/* Convert and write CAN message to DMA buffer */
if (source->extended) {
tmp = (1 << 31) | (source->id & 0x3fffffff);
} else {
tmp = (source->id & 0xfff) << 18;
}
if (source->rtr)
tmp |= (1 << 30);
dest->head[0] = tmp;
dest->head[1] = source->len << 28;
for (i = 0; i < source->len; i++)
dest->data[i] = source->data[i];
source++; /* straight user buffer */
dest =
((unsigned int)dest >= txmax) ?
(struct grcan_msg *)addr : dest + 1;
space_left--;
}
{
/* A bus off interrupt may have occured after checking pDev->started */
SPIN_IRQFLAGS(oldLevel);
SPIN_LOCK_IRQ(&pDev->devlock, oldLevel);
if (pDev->started == STATE_STARTED) {
regs->tx0wr = (unsigned int) dest - addr;
regs->tx0ctrl = GRCAN_TXCTRL_ENABLE;
} else {
DBGC(DBG_STATE, "cancelled due to a BUS OFF error\n");
ret = state2err[pDev->started];
}
SPIN_UNLOCK_IRQ(&pDev->devlock, oldLevel);
}
return ret;
}
int grcan_read(void *d, CANMsg *msg, size_t ucount)
{
struct grcan_priv *pDev = d;
CANMsg *dest;
unsigned int count, left;
int nread;
int req_cnt;
FUNCDBG();
dest = msg;
req_cnt = ucount;
if ( (!dest) || (req_cnt<1) )
return GRCAN_RET_INVARG;
if (pDev->started != STATE_STARTED) {
return GRCAN_RET_NOTSTARTED;
}
DBGC(DBG_RX, "grcan_read [%p]: buf: %p len: %u\n", d, msg, (unsigned int) ucount);
nread = grcan_hw_read_try(pDev,pDev->regs,dest,req_cnt);
if (nread < 0) {
return nread;
}
count = nread;
if ( !( pDev->rxblock && pDev->rxcomplete && (count!=req_cnt) ) ){
if ( count > 0 ) {
/* Successfully received messages (at least one) */
return count;
}
/* nothing read, shall we block? */
if ( !pDev->rxblock ) {
/* non-blocking mode */
return GRCAN_RET_TIMEOUT;
}
}
while (count == 0 || (pDev->rxcomplete && (count!=req_cnt))) {
if (!pDev->rxcomplete) {
left = 1; /* return as soon as there is one message available */
} else {
left = req_cnt - count; /* return as soon as all data are available */
/* never wait for more than the half the maximum size of the receive buffer
* Why? We need some time to copy buffer before to catch up with hw,
* otherwise we would have to copy everything when the data has been
* received.
*/
if (left > ((pDev->rxbuf_size/GRCAN_MSG_SIZE) / 2)){
left = (pDev->rxbuf_size/GRCAN_MSG_SIZE) / 2;
}
}
nread = grcan_wait_rxdata(pDev, left);
if (nread) {
/* The wait has been aborted, probably due to
* the device driver has been closed by another
* thread or a bus-off. Return error code.
*/
return nread;
}
/* Try read bytes from circular buffer */
nread = grcan_hw_read_try(
pDev,
pDev->regs,
dest+count,
req_cnt-count);
if (nread < 0) {
/* The read was aborted by bus-off. */
return nread;
}
count += nread;
}
/* no need to unmask IRQ as IRQ Handler do that for us. */
return count;
}
int grcan_write(void *d, CANMsg *msg, size_t ucount)
{
struct grcan_priv *pDev = d;
CANMsg *source;
unsigned int count, left;
int nwritten;
int req_cnt;
DBGC(DBG_TX,"\n");
if ((pDev->started != STATE_STARTED) || pDev->config.silent || pDev->flushing)
return GRCAN_RET_NOTSTARTED;
req_cnt = ucount;
source = (CANMsg *) msg;
/* check proper length and buffer pointer */
if (( req_cnt < 1) || (source == NULL) ){
return GRCAN_RET_INVARG;
}
nwritten = grcan_hw_write_try(pDev,pDev->regs,source,req_cnt);
if (nwritten < 0) {
return nwritten;
}
count = nwritten;
if ( !(pDev->txblock && pDev->txcomplete && (count!=req_cnt)) ) {
if ( count > 0 ) {
/* Successfully transmitted chars (at least one char) */
return count;
}
/* nothing written, shall we block? */
if ( !pDev->txblock ) {
/* non-blocking mode */
return GRCAN_RET_TIMEOUT;
}
}
/* if in txcomplete mode we need to transmit all chars */
while((count == 0) || (pDev->txcomplete && (count!=req_cnt)) ){
/*** block until room to fit all or as much of transmit buffer as possible
* IRQ comes. Set up a valid IRQ point so that an IRQ is received
* when we can put a chunk of data into transmit fifo
*/
if ( !pDev->txcomplete ){
left = 1; /* wait for anything to fit buffer */
}else{
left = req_cnt - count; /* wait for all data to fit in buffer */
/* never wait for more than the half the maximum size of the transmit
* buffer
* Why? We need some time to fill buffer before hw catches up.
*/
if ( left > ((pDev->txbuf_size/GRCAN_MSG_SIZE)/2) ){
left = (pDev->txbuf_size/GRCAN_MSG_SIZE)/2;
}
}
nwritten = grcan_wait_txspace(pDev,left);
/* Wait until more room in transmit buffer */
if ( nwritten ) {
/* The wait has been aborted, probably due to
* the device driver has been closed by another
* thread. To avoid deadlock we return directly
* with error status.
*/
return nwritten;
}
/* Try read bytes from circular buffer */
nwritten = grcan_hw_write_try(
pDev,
pDev->regs,
source+count,
req_cnt-count);
if (nwritten < 0) {
/* Write was aborted by bus-off. */
return nwritten;
}
count += nwritten;
}
/* no need to unmask IRQ as IRQ Handler do that for us. */
return count;
}
int grcan_set_speed(void *d, unsigned int speed)
{
struct grcan_priv *pDev = d;
struct grcan_timing timing;
int ret;
FUNCDBG();
/* cannot change speed during run mode */
if ((pDev->started == STATE_STARTED) || pDev->fd_capable)
return -1;
/* get speed rate from argument */
ret = grlib_canbtrs_calc_timing(
speed, pDev->corefreq_hz, GRCAN_SAMPLING_POINT,
&grcan_btrs_ranges, (struct grlib_canbtrs_timing *)&timing);
if (ret)
return -2;
/* save timing/speed */
pDev->config.timing = timing;
pDev->config_changed = 1;
return 0;
}
int grcan_set_btrs(void *d, const struct grcan_timing *timing)
{
struct grcan_priv *pDev = d;
FUNCDBG();
/* Set BTR registers manually
* Read GRCAN/HurriCANe Manual.
*/
if ((pDev->started == STATE_STARTED) || pDev->fd_capable)
return -1;
if ( !timing )
return -2;
pDev->config.timing = *timing;
pDev->config_changed = 1;
return 0;
}

View File

@@ -19,6 +19,7 @@
#include <drvmgr/drvmgr.h>
#include <grlib/ambapp_bus.h>
#include <grlib/occan.h>
#include <grlib/canbtrs.h>
#include <grlib/grlib_impl.h>
@@ -185,19 +186,20 @@ typedef struct {
#define pelican_regs pelican32_regs
#endif
/* Default sampling point in % */
#define OCCAN_SAMPLING_POINT 90
#define MAX_TSEG2 7
#define MAX_TSEG1 15
/* OCCAN baud-rate paramter boundaries */
struct grlib_canbtrs_ranges occan_btrs_ranges = {
.max_scaler = 64,
.has_bpr = 0,
.divfactor = 1,
.min_tseg1 = 1,
.max_tseg1 = 16,
.min_tseg2 = 1,
.max_tseg2 = 8,
};
#if 0
typedef struct {
unsigned char brp;
unsigned char sjw;
unsigned char tseg1;
unsigned char tseg2;
unsigned char sam;
} occan_speed_regs;
#endif
typedef struct {
unsigned char btr0;
unsigned char btr1;
@@ -251,7 +253,9 @@ static CANMsg *occan_fifo_claim_get(occan_fifo *fifo);
static void occan_fifo_clr(occan_fifo *fifo);
/**** Hardware related Interface ****/
static int occan_calc_speedregs(unsigned int clock_hz, unsigned int rate, occan_speed_regs *result);
static void convert_timing_to_btrs(
struct grlib_canbtrs_timing *t,
occan_speed_regs *btrs);
static int occan_set_speedregs(occan_priv *priv, occan_speed_regs *timing);
static void pelican_init(occan_priv *priv);
static void pelican_open(occan_priv *priv);
@@ -765,6 +769,7 @@ static void pelican_init(occan_priv *priv){
static void pelican_open(occan_priv *priv){
int ret;
struct grlib_canbtrs_timing timing;
/* Set defaults */
priv->speed = OCCAN_SPEED_250K;
@@ -783,13 +788,19 @@ static void pelican_open(occan_priv *priv){
*/
WRITE_REG(priv, &priv->regs->clkdiv, (1<<PELICAN_CDR_MODE_BITS) | (DEFAULT_CLKDIV & PELICAN_CDR_DIV));
ret = occan_calc_speedregs(priv->sys_freq_hz,priv->speed,&priv->timing);
if ( ret ){
ret = grlib_canbtrs_calc_timing(
priv->speed, priv->sys_freq_hz,
OCCAN_SAMPLING_POINT, &occan_btrs_ranges,
(struct grlib_canbtrs_timing *)&timing);
if ( ret ) {
/* failed to set speed for this system freq, try with 50K instead */
priv->speed = OCCAN_SPEED_50K;
occan_calc_speedregs(priv->sys_freq_hz, priv->speed,
&priv->timing);
grlib_canbtrs_calc_timing(
priv->speed, priv->sys_freq_hz,
OCCAN_SAMPLING_POINT, &occan_btrs_ranges,
(struct grlib_canbtrs_timing *)&timing);
}
convert_timing_to_btrs(&timing, &priv->timing);
/* disable all interrupts */
WRITE_REG(priv, &priv->regs->inten, 0);
@@ -983,97 +994,13 @@ static void pelican_set_accept(occan_priv *priv, unsigned char *acode, unsigned
WRITE_REG(priv, amask3, amask[3]);
}
/* This function calculates BTR0 and BTR1 values for a given bitrate.
*
* Set communication parameters.
* \param clock_hz OC_CAN Core frequency in Hz.
* \param rate Requested baud rate in bits/second.
* \param result Pointer to where resulting BTRs will be stored.
* \return zero if successful to calculate a baud rate.
*/
static int occan_calc_speedregs(unsigned int clock_hz, unsigned int rate, occan_speed_regs *result)
static void convert_timing_to_btrs(
struct grlib_canbtrs_timing *t,
occan_speed_regs *btrs)
{
int best_error = 1000000000;
int error;
int best_tseg=0, best_brp=0, brp=0;
int tseg=0, tseg1=0, tseg2=0;
int sjw = 0;
int clock = clock_hz / 2;
int sampl_pt = 90;
if ( (rate<5000) || (rate>1000000) ){
/* invalid speed mode */
return -1;
}
/* find best match, return -2 if no good reg
* combination is available for this frequency */
/* some heuristic specials */
if (rate > ((1000000 + 500000) / 2))
sampl_pt = 75;
if (rate < ((12500 + 10000) / 2))
sampl_pt = 75;
if (rate < ((100000 + 125000) / 2))
sjw = 1;
/* tseg even = round down, odd = round up */
for (tseg = (0 + 0 + 2) * 2;
tseg <= (MAX_TSEG2 + MAX_TSEG1 + 2) * 2 + 1;
tseg++)
{
brp = clock / ((1 + tseg / 2) * rate) + tseg % 2;
if ((brp == 0) || (brp > 64))
continue;
error = rate - clock / (brp * (1 + tseg / 2));
if (error < 0)
{
error = -error;
}
if (error <= best_error)
{
best_error = error;
best_tseg = tseg/2;
best_brp = brp-1;
}
}
if (best_error && (rate / best_error < 10))
{
printk("OCCAN: bitrate %d is not possible with %d Hz clock\n\r",rate, clock);
return -2;
}else if ( !result )
return 0; /* nothing to store result in, but a valid bitrate can be calculated */
tseg2 = best_tseg - (sampl_pt * (best_tseg + 1)) / 100;
if (tseg2 < 0)
{
tseg2 = 0;
}
if (tseg2 > MAX_TSEG2)
{
tseg2 = MAX_TSEG2;
}
tseg1 = best_tseg - tseg2 - 2;
if (tseg1 > MAX_TSEG1)
{
tseg1 = MAX_TSEG1;
tseg2 = best_tseg - tseg1 - 2;
}
result->btr0 = (sjw<<OCCAN_BUSTIM_SJW_BIT) | (best_brp&OCCAN_BUSTIM_BRP);
result->btr1 = (0<<7) | (tseg2<<OCCAN_BUSTIM_TSEG2_BIT) | tseg1;
return 0;
btrs->btr0 = (t->rsj << OCCAN_BUSTIM_SJW_BIT) |
(t->scaler & OCCAN_BUSTIM_BRP);
btrs->btr1 = (0<<7) | (t->ps2 << OCCAN_BUSTIM_TSEG2_BIT) | t->ps1;
}
static int occan_set_speedregs(occan_priv *priv, occan_speed_regs *timing)
@@ -1441,7 +1368,7 @@ static rtems_device_driver occan_write(rtems_device_major_number major, rtems_de
static rtems_device_driver occan_ioctl(rtems_device_major_number major, rtems_device_minor_number minor, void *arg)
{
int ret;
occan_speed_regs timing;
struct grlib_canbtrs_timing timing;
occan_priv *can;
struct drvmgr_dev *dev;
unsigned int speed;
@@ -1467,7 +1394,11 @@ static rtems_device_driver occan_ioctl(rtems_device_major_number major, rtems_de
/* get speed rate from argument */
speed = (unsigned int)ioarg->buffer;
ret = occan_calc_speedregs(can->sys_freq_hz,speed,&timing);
/* Calculate default timing register values */
ret = grlib_canbtrs_calc_timing(
speed, can->sys_freq_hz,
OCCAN_SAMPLING_POINT, &occan_btrs_ranges,
(struct grlib_canbtrs_timing *)&timing);
if ( ret )
return RTEMS_INVALID_NAME; /* EINVAL */
@@ -1476,7 +1407,7 @@ static rtems_device_driver occan_ioctl(rtems_device_major_number major, rtems_de
/* save timing/speed */
can->speed = speed;
can->timing = timing;
convert_timing_to_btrs(&timing, &can->timing);
break;
case OCCAN_IOC_SET_BTRS:

View File

@@ -188,8 +188,8 @@ static int genirq_set_active(
return 1;
}
e = isrentry;
} else {
enabled += isrentry->enabled;
} else if ( isrentry->enabled ) {
enabled = 1;
}
isrentry = isrentry->next;
}

View File

@@ -894,9 +894,9 @@ int l2cache_diag_tag( int way, int index, struct l2cache_tag * tag)
return L2CACHE_ERR_EINVAL;
}
unsigned int val = l2cache_reg_diagtag(way,index);
if (tag){
unsigned int val = l2cache_reg_diagtag(way,index);
tag->tag = l2cache_get_tag(val);
tag->valid = l2cache_tag_valid(val);
tag->dirty = l2cache_tag_dirty(val);

View File

@@ -186,6 +186,7 @@ struct greth_softc
unsigned int advmodes; /* advertise ethernet speed modes. 0 = all modes. */
struct timespec auto_neg_time;
int mc_available;
int num_descs;
/*
* Statistics
@@ -422,7 +423,7 @@ greth_initialize_hardware (struct greth_softc *sc)
int tmp2;
struct timespec tstart, tnow;
greth_regs *regs;
unsigned int advmodes, speed;
unsigned int advmodes, speed, tabsize;
regs = sc->regs;
@@ -616,8 +617,9 @@ auto_neg_done:
/* Initialize rx/tx descriptor table pointers. Due to alignment we
* always allocate maximum table size.
*/
sc->txdesc = (greth_rxtxdesc *) almalloc(0x800, 0x400);
sc->rxdesc = (greth_rxtxdesc *) &sc->txdesc[128];
tabsize = sc->num_descs * 8;
sc->txdesc = (greth_rxtxdesc *) almalloc(tabsize * 2, tabsize);
sc->rxdesc = (greth_rxtxdesc *) (tabsize + (void *)sc->txdesc);
sc->tx_ptr = 0;
sc->tx_dptr = 0;
sc->tx_cnt = 0;
@@ -631,8 +633,8 @@ auto_neg_done:
CPUMEM_TO_DMA,
(void *)sc->txdesc,
(void **)&sc->txdesc_remote,
0x800);
sc->rxdesc_remote = sc->txdesc_remote + 0x400;
tabsize * 2);
sc->rxdesc_remote = sc->txdesc_remote + tabsize;
regs->txdesc = (int) sc->txdesc_remote;
regs->rxdesc = (int) sc->rxdesc_remote;
@@ -1555,6 +1557,7 @@ int greth_device_init(struct greth_softc *sc)
struct ambapp_core *pnpinfo;
union drvmgr_key_value *value;
unsigned int speed;
int i, nrd;
/* Get device information from AMBA PnP information */
ambadev = (struct amba_dev_info *)sc->dev->businfo;
@@ -1608,12 +1611,17 @@ int greth_device_init(struct greth_softc *sc)
sc->rxbufs = 32;
sc->phyaddr = -1;
/* Probe the number of descriptors available the */
nrd = (sc->regs->status & GRETH_STATUS_NRD) >> 24;
for (sc->num_descs = 128, i = 0; i < nrd; i++)
sc->num_descs = sc->num_descs * 2;
value = drvmgr_dev_key_get(sc->dev, "txDescs", DRVMGR_KT_INT);
if ( value && (value->i <= 128) )
if ( value && (value->i <= sc->num_descs) )
sc->txbufs = value->i;
value = drvmgr_dev_key_get(sc->dev, "rxDescs", DRVMGR_KT_INT);
if ( value && (value->i <= 128) )
if ( value && (value->i <= sc->num_descs) )
sc->rxbufs = value->i;
value = drvmgr_dev_key_get(sc->dev, "phyAdr", DRVMGR_KT_INT);

View File

@@ -261,6 +261,7 @@ static void check_rx_errors(GRSPW_DEV *pDev, int ctrl);
static void grspw_rxnext(GRSPW_DEV *pDev);
static void grspw_interrupt(void *arg);
static int grspw_buffer_alloc(GRSPW_DEV *pDev);
static int grspw_dmatables_alloc(GRSPW_DEV *pDev);
static rtems_device_driver grspw_initialize(
rtems_device_major_number major,
@@ -553,6 +554,8 @@ int grspw_device_init(GRSPW_DEV *pDev)
if (grspw_buffer_alloc(pDev))
return RTEMS_NO_MEMORY;
if (grspw_dmatables_alloc(pDev))
return RTEMS_NO_MEMORY;
/* Create semaphores */
rtems_semaphore_create(
@@ -678,7 +681,11 @@ static int grspw_buffer_alloc(GRSPW_DEV *pDev)
(void **)&pDev->ptr_txhbuf0_remote,
pDev->txhbufsize * pDev->txbufcnt);
}
return 0;
}
static int grspw_dmatables_alloc(GRSPW_DEV *pDev)
{
/* DMA DESCRIPTOR TABLES */
if (pDev->bd_dma_area & 1) {
/* Address given in remote address */

View File

@@ -1431,6 +1431,11 @@ int router_port_link_start(void *d, int port)
return router_port_ctrl_rmw(d, port, NULL, PCTRL_LD | PCTRL_LS, PCTRL_LS);
}
int router_port_link_div(void *d, int port, int rundiv)
{
return router_port_ctrl_rmw(d, port, NULL, PCTRL_RD, (rundiv << PCTRL_RD_BIT) & PCTRL_RD);
}
int router_port_link_receive_spill(void *d, int port)
{
struct router_priv *priv = d;

View File

@@ -1,15 +1,37 @@
/* SPDX-License-Identifier: BSD-2-Clause */
/**
* @file
*
* @ingroup bsp_interrupt
*
* @brief This source file contains the default implementation of
* bsp_interrupt_handler_default().
*/
/*
* Copyright (c) 2008-2012 embedded brains GmbH. All rights reserved.
* Copyright (C) 2008, 2012 embedded brains GmbH (http://www.embedded-brains.de)
*
* embedded brains GmbH
* Obere Lagerstr. 30
* 82178 Puchheim
* Germany
* <rtems@embedded-brains.de>
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* The license and distribution terms for this file may be
* found in the file LICENSE in this distribution or at
* http://www.rtems.org/license/LICENSE.
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include <inttypes.h>

View File

@@ -1,13 +1,17 @@
/* SPDX-License-Identifier: BSD-2-Clause */
/**
* @file
*
* @ingroup RTEMSBSPsShared
* @ingroup bsp_interrupt
*
* @brief This source file contains the default implementation of
* bsp_interrupt_vector_enable(), bsp_interrupt_vector_disable(), and
* bsp_interrupt_facility_initialize().
*/
/*
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (C) 2019 embedded brains GmbH
* Copyright (C) 2019 embedded brains GmbH (http://www.embedded-brains.de)
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions

View File

@@ -1,25 +1,37 @@
/* SPDX-License-Identifier: BSD-2-Clause */
/**
* @file
*
* @ingroup bsp_interrupt
*
* @brief Generic BSP interrupt support implementation.
* @brief This source file contains the generic interrupt controller support
* implementation.
*/
/*
* Based on concepts of Pavel Pisa, Till Straumann and Eric Valette.
* Copyright (C) 2008, 2018 embedded brains GmbH (http://www.embedded-brains.de)
*
* Copyright (c) 2008, 2018 embedded brains GmbH.
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* embedded brains GmbH
* Dornierstr. 4
* 82178 Puchheim
* Germany
* <rtems@embedded-brains.de>
*
* The license and distribution terms for this file may be
* found in the file LICENSE in this distribution or at
* http://www.rtems.org/license/LICENSE.
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include <bsp/irq-generic.h>

View File

@@ -1,22 +1,37 @@
/* SPDX-License-Identifier: BSD-2-Clause */
/**
* @file
*
* @ingroup bsp_interrupt
*
* @brief Generic BSP interrupt information implementation.
* @brief This source file contains the implementation of
* bsp_interrupt_report() and bsp_interrupt_report_with_plugin().
*/
/*
* Copyright (c) 2008, 2009, 2010
* embedded brains GmbH
* Obere Lagerstr. 30
* D-82178 Puchheim
* Germany
* <rtems@embedded-brains.de>
* Copyright (C) 2008, 2010 embedded brains GmbH (http://www.embedded-brains.de)
*
* The license and distribution terms for this file may be
* found in the file LICENSE in this distribution or at
* http://www.rtems.org/license/LICENSE.
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include <inttypes.h>

View File

@@ -1,22 +1,37 @@
/* SPDX-License-Identifier: BSD-2-Clause */
/**
* @file
*
* @ingroup bsp_interrupt
*
* @brief Generic BSP interrupt support legacy implementation.
* @brief This source file contains the legacy interrupt controller support
* implementation.
*/
/*
* Copyright (c) 2008, 2009
* embedded brains GmbH
* Obere Lagerstr. 30
* D-82178 Puchheim
* Germany
* <rtems@embedded-brains.de>
* Copyright (C) 2008, 2009 embedded brains GmbH (http://www.embedded-brains.de)
*
* The license and distribution terms for this file may be
* found in the file LICENSE in this distribution or at
* http://www.rtems.org/license/LICENSE.
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include <string.h>

View File

@@ -1,25 +1,37 @@
/* SPDX-License-Identifier: BSD-2-Clause */
/**
* @file
*
* @ingroup bsp_interrupt
*
* @brief BSP interrupt support lock implementation.
* @brief This source file contains the implementation of
* bsp_interrupt_lock() and bsp_interrupt_unlock().
*/
/*
* Based on concepts of Pavel Pisa, Till Straumann and Eric Valette.
* Copyright (C) 2008, 2018 embedded brains GmbH (http://www.embedded-brains.de)
*
* Copyright (c) 2008, 2018 embedded brains GmbH.
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* embedded brains GmbH
* Dornierstr. 4
* 82178 Puchheim
* Germany
* <rtems@embedded-brains.de>
*
* The license and distribution terms for this file may be
* found in the file LICENSE in this distribution or at
* http://www.rtems.org/license/LICENSE.
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include <bsp/irq-generic.h>

View File

@@ -1,26 +1,40 @@
/* SPDX-License-Identifier: BSD-2-Clause */
/**
* @file
*
* @ingroup bsp_interrupt
*
* @brief Generic BSP interrupt server implementation.
* @brief This source file contains the interrupt server implementation.
*/
/*
* Copyright (c) 2009, 2019 embedded brains GmbH. All rights reserved.
* Copyright (C) 2009, 2020 embedded brains GmbH (http://www.embedded-brains.de)
*
* embedded brains GmbH
* Dornierstr. 4
* 82178 Puchheim
* Germany
* <rtems@embedded-brains.de>
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* The license and distribution terms for this file may be
* found in the file LICENSE in this distribution or at
* http://www.rtems.org/license/LICENSE.
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include <stdlib.h>
#include <string.h>
#include <rtems.h>
#include <rtems/chain.h>
@@ -30,54 +44,43 @@
#define BSP_INTERRUPT_SERVER_MANAGEMENT_VECTOR (BSP_INTERRUPT_VECTOR_MAX + 1)
typedef struct {
RTEMS_INTERRUPT_LOCK_MEMBER(lock);
rtems_chain_control entries;
rtems_id server;
unsigned errors;
} bsp_interrupt_server_context;
static rtems_interrupt_server_control bsp_interrupt_server_default;
#if defined(RTEMS_SMP)
static bsp_interrupt_server_context *bsp_interrupt_server_instances;
#else
static bsp_interrupt_server_context bsp_interrupt_server_instance;
#endif
static rtems_chain_control bsp_interrupt_server_chain =
RTEMS_CHAIN_INITIALIZER_EMPTY(bsp_interrupt_server_chain);
static bsp_interrupt_server_context *bsp_interrupt_server_get_context(
static rtems_interrupt_server_control *bsp_interrupt_server_get_context(
uint32_t server_index,
rtems_status_code *sc
)
{
#if defined(RTEMS_SMP)
if (bsp_interrupt_server_instances == NULL) {
*sc = RTEMS_INCORRECT_STATE;
return NULL;
}
#else
if (bsp_interrupt_server_instance.server == RTEMS_ID_NONE) {
*sc = RTEMS_INCORRECT_STATE;
return NULL;
}
#endif
rtems_chain_node *node;
if (server_index >= rtems_scheduler_get_processor_maximum()) {
*sc = RTEMS_INVALID_ID;
return NULL;
bsp_interrupt_lock();
node = rtems_chain_first(&bsp_interrupt_server_chain);
while (node != rtems_chain_tail(&bsp_interrupt_server_chain)) {
rtems_interrupt_server_control *s;
s = RTEMS_CONTAINER_OF(node, rtems_interrupt_server_control, node);
if (s->index == server_index) {
bsp_interrupt_unlock();
return s;
}
node = rtems_chain_next(node);
}
*sc = RTEMS_SUCCESSFUL;
#if defined(RTEMS_SMP)
return &bsp_interrupt_server_instances[server_index];
#else
return &bsp_interrupt_server_instance;
#endif
bsp_interrupt_unlock();
*sc = RTEMS_INVALID_ID;
return NULL;
}
static void bsp_interrupt_server_trigger(void *arg)
{
rtems_interrupt_lock_context lock_context;
rtems_interrupt_server_entry *e = arg;
bsp_interrupt_server_context *s = e->server;
rtems_interrupt_server_control *s = e->server;
if (bsp_interrupt_is_valid_vector(e->vector)) {
bsp_interrupt_vector_disable(e->vector);
@@ -137,7 +140,7 @@ static rtems_interrupt_server_entry *bsp_interrupt_server_query_entry(
}
typedef struct {
bsp_interrupt_server_context *server;
rtems_interrupt_server_control *server;
rtems_vector_number vector;
rtems_option options;
rtems_interrupt_handler handler;
@@ -281,7 +284,7 @@ static void bsp_interrupt_server_remove_helper(void *arg)
}
static rtems_status_code bsp_interrupt_server_call_helper(
bsp_interrupt_server_context *s,
rtems_interrupt_server_control *s,
rtems_vector_number vector,
rtems_option options,
rtems_interrupt_handler handler,
@@ -314,7 +317,7 @@ static rtems_status_code bsp_interrupt_server_call_helper(
}
static rtems_interrupt_server_entry *bsp_interrupt_server_get_entry(
bsp_interrupt_server_context *s
rtems_interrupt_server_control *s
)
{
rtems_interrupt_lock_context lock_context;
@@ -337,7 +340,7 @@ static rtems_interrupt_server_entry *bsp_interrupt_server_get_entry(
static void bsp_interrupt_server_task(rtems_task_argument arg)
{
bsp_interrupt_server_context *s = (bsp_interrupt_server_context *) arg;
rtems_interrupt_server_control *s = (rtems_interrupt_server_control *) arg;
while (true) {
rtems_event_set events;
@@ -377,7 +380,7 @@ rtems_status_code rtems_interrupt_server_handler_install(
)
{
rtems_status_code sc;
bsp_interrupt_server_context *s;
rtems_interrupt_server_control *s;
s = bsp_interrupt_server_get_context(server_index, &sc);
if (s == NULL) {
@@ -402,7 +405,7 @@ rtems_status_code rtems_interrupt_server_handler_remove(
)
{
rtems_status_code sc;
bsp_interrupt_server_context *s;
rtems_interrupt_server_control *s;
s = bsp_interrupt_server_get_context(server_index, &sc);
if (s == NULL) {
@@ -464,7 +467,7 @@ rtems_status_code rtems_interrupt_server_handler_iterate(
{
rtems_status_code sc;
bsp_interrupt_server_handler_iterate_helper_data hihd;
bsp_interrupt_server_context *s;
rtems_interrupt_server_control *s;
s = bsp_interrupt_server_get_context(server_index, &sc);
if (s == NULL) {
@@ -487,6 +490,90 @@ rtems_status_code rtems_interrupt_server_handler_iterate(
);
}
/*
* The default server is statically allocated. Just clear the structure so
* that it can be re-initialized.
*/
static void bsp_interrupt_server_destroy_default(
rtems_interrupt_server_control *s
)
{
memset(s, 0, sizeof(*s));
}
#if defined(RTEMS_SMP)
static void bsp_interrupt_server_destroy_secondary(
rtems_interrupt_server_control *s
)
{
free(s);
}
#endif
static rtems_status_code bsp_interrupt_server_create(
rtems_interrupt_server_control *s,
rtems_task_priority priority,
size_t stack_size,
rtems_mode modes,
rtems_attribute attributes,
uint32_t cpu_index
)
{
rtems_status_code sc;
#if defined(RTEMS_SMP)
rtems_id scheduler;
cpu_set_t cpu;
#endif
sc = rtems_task_create(
rtems_build_name('I', 'R', 'Q', 'S'),
priority,
stack_size,
modes,
attributes,
&s->server
);
if (sc != RTEMS_SUCCESSFUL) {
(*s->destroy)(s);
return sc;
}
rtems_interrupt_lock_initialize(&s->lock, "Interrupt Server");
rtems_chain_initialize_empty(&s->entries);
#if defined(RTEMS_SMP)
sc = rtems_scheduler_ident_by_processor(cpu_index, &scheduler);
/*
* If a scheduler exists for the processor, then move it to this scheduler
* and try to set the affinity to the processor, otherwise keep the scheduler
* of the executing thread.
*/
if (sc == RTEMS_SUCCESSFUL) {
sc = rtems_task_set_scheduler(s->server, scheduler, priority);
_Assert(sc == RTEMS_SUCCESSFUL);
/* Set the task to processor affinity on a best-effort basis */
CPU_ZERO(&cpu);
CPU_SET(cpu_index, &cpu);
(void) rtems_task_set_affinity(s->server, sizeof(cpu), &cpu);
}
#else
(void) cpu_index;
#endif
rtems_chain_append_unprotected(&bsp_interrupt_server_chain, &s->node);
sc = rtems_task_start(
s->server,
bsp_interrupt_server_task,
(rtems_task_argument) s
);
_Assert(sc == RTEMS_SUCCESSFUL);
return sc;
}
rtems_status_code rtems_interrupt_server_initialize(
rtems_task_priority priority,
size_t stack_size,
@@ -495,95 +582,166 @@ rtems_status_code rtems_interrupt_server_initialize(
uint32_t *server_count
)
{
rtems_status_code sc;
rtems_interrupt_server_control *s;
uint32_t cpu_index;
#if defined(RTEMS_SMP)
uint32_t cpu_count;
uint32_t dummy;
bsp_interrupt_server_context *instances;
#endif
if (server_count == NULL) {
server_count = &dummy;
cpu_index = 0;
s = &bsp_interrupt_server_default;
bsp_interrupt_lock();
if (s->server != 0) {
sc = RTEMS_INCORRECT_STATE;
goto done;
}
s->destroy = bsp_interrupt_server_destroy_default;
sc = bsp_interrupt_server_create(
s,
priority,
stack_size,
modes,
attributes,
cpu_index
);
if (sc != RTEMS_SUCCESSFUL) {
goto done;
}
cpu_index = 1;
#if defined(RTEMS_SMP)
cpu_count = rtems_scheduler_get_processor_maximum();
#if defined(RTEMS_SMP)
instances = calloc(cpu_count, sizeof(*instances));
if (instances == NULL) {
return RTEMS_NO_MEMORY;
}
#else
instances = &bsp_interrupt_server_instance;
#endif
while (cpu_index < cpu_count) {
s = calloc(1, sizeof(*s));
for (cpu_index = 0; cpu_index < cpu_count; ++cpu_index) {
bsp_interrupt_server_context *s = &instances[cpu_index];
rtems_status_code sc;
#if defined(RTEMS_SMP)
rtems_id scheduler;
cpu_set_t cpu;
#endif
if (s == NULL) {
sc = RTEMS_NO_MEMORY;
goto done;
}
rtems_interrupt_lock_initialize(&s->lock, "Interrupt Server");
rtems_chain_initialize_empty(&s->entries);
sc = rtems_task_create(
rtems_build_name('I', 'R', 'Q', 'S'),
s->destroy = bsp_interrupt_server_destroy_secondary;
s->index = cpu_index;
sc = bsp_interrupt_server_create(
s,
priority,
stack_size,
modes,
attributes,
&s->server
cpu_index
);
if (sc != RTEMS_SUCCESSFUL) {
*server_count = cpu_index;
#if defined(RTEMS_SMP)
if (cpu_index > 0) {
bsp_interrupt_server_instances = instances;
return RTEMS_SUCCESSFUL;
}
free(instances);
#endif
return RTEMS_TOO_MANY;
goto done;
}
#if defined(RTEMS_SMP)
sc = rtems_scheduler_ident_by_processor(cpu_index, &scheduler);
if (sc != RTEMS_SUCCESSFUL) {
/* Do not start an interrupt server on a processor without a scheduler */
continue;
}
sc = rtems_task_set_scheduler(s->server, scheduler, priority);
_Assert(sc == RTEMS_SUCCESSFUL);
/* Set the task to processor affinity on a best-effort basis */
CPU_ZERO(&cpu);
CPU_SET(cpu_index, &cpu);
(void) rtems_task_set_affinity(s->server, sizeof(cpu), &cpu);
++cpu_index;
}
#endif
sc = rtems_task_start(
s->server,
bsp_interrupt_server_task,
(rtems_task_argument) s
);
_Assert(sc == RTEMS_SUCCESSFUL);
done:
bsp_interrupt_unlock();
if (server_count != NULL) {
*server_count = cpu_index;
}
#if defined(RTEMS_SMP)
bsp_interrupt_server_instances = instances;
#endif
*server_count = cpu_index;
return sc;
}
rtems_status_code rtems_interrupt_server_create(
rtems_interrupt_server_control *s,
const rtems_interrupt_server_config *config,
uint32_t *server_index
)
{
rtems_status_code sc;
sc = rtems_task_create(
config->name,
config->priority,
config->storage_size,
config->modes,
config->attributes,
&s->server
);
if (sc != RTEMS_SUCCESSFUL) {
return sc;
}
rtems_interrupt_lock_initialize(&s->lock, "Interrupt Server");
rtems_chain_initialize_empty(&s->entries);
s->destroy = config->destroy;
s->index = rtems_object_id_get_index(s->server)
+ rtems_scheduler_get_processor_maximum();
*server_index = s->index;
bsp_interrupt_lock();
rtems_chain_initialize_node(&s->node);
rtems_chain_append_unprotected(&bsp_interrupt_server_chain, &s->node);
bsp_interrupt_unlock();
sc = rtems_task_start(
s->server,
bsp_interrupt_server_task,
(rtems_task_argument) s
);
_Assert(sc == RTEMS_SUCCESSFUL);
return sc;
}
static void bsp_interrupt_server_destroy_helper(void *arg)
{
bsp_interrupt_server_helper_data *hd = arg;
rtems_interrupt_server_control *s = hd->server;
rtems_status_code sc;
bsp_interrupt_lock();
rtems_chain_extract_unprotected(&s->node);
bsp_interrupt_unlock();
rtems_interrupt_lock_destroy(&s->lock);
if (s->destroy != NULL) {
(*s->destroy)(s);
}
sc = rtems_event_transient_send(hd->task);
_Assert(sc == RTEMS_SUCCESSFUL);
(void) sc;
rtems_task_exit();
}
rtems_status_code rtems_interrupt_server_delete(uint32_t server_index)
{
rtems_status_code sc;
rtems_interrupt_server_control *s;
s = bsp_interrupt_server_get_context(server_index, &sc);
if (s == NULL) {
return sc;
}
bsp_interrupt_server_call_helper(
s,
BSP_INTERRUPT_SERVER_MANAGEMENT_VECTOR,
0,
NULL,
NULL,
bsp_interrupt_server_destroy_helper
);
return RTEMS_SUCCESSFUL;
}
static void bsp_interrupt_server_entry_initialize(
rtems_interrupt_server_entry *entry,
bsp_interrupt_server_context *s
rtems_interrupt_server_control *s
)
{
rtems_chain_set_off_chain(&entry->node);
@@ -611,7 +769,7 @@ rtems_status_code rtems_interrupt_server_entry_initialize(
)
{
rtems_status_code sc;
bsp_interrupt_server_context *s;
rtems_interrupt_server_control *s;
s = bsp_interrupt_server_get_context(server_index, &sc);
if (s == NULL) {
@@ -645,7 +803,7 @@ rtems_status_code rtems_interrupt_server_entry_move(
)
{
rtems_status_code sc;
bsp_interrupt_server_context *s;
rtems_interrupt_server_control *s;
s = bsp_interrupt_server_get_context(destination_server_index, &sc);
if (s == NULL) {
@@ -667,7 +825,7 @@ void rtems_interrupt_server_entry_destroy(
rtems_interrupt_server_entry *entry
)
{
bsp_interrupt_server_context *s;
rtems_interrupt_server_control *s;
rtems_interrupt_lock_context lock_context;
s = entry->server;
@@ -698,7 +856,7 @@ rtems_status_code rtems_interrupt_server_request_initialize(
)
{
rtems_status_code sc;
bsp_interrupt_server_context *s;
rtems_interrupt_server_control *s;
s = bsp_interrupt_server_get_context(server_index, &sc);
if (s == NULL) {
@@ -727,8 +885,8 @@ static void bsp_interrupt_server_handler_move_helper(void *arg)
e = bsp_interrupt_server_query_entry(hd->vector, &trigger_options);
if (e != NULL) {
rtems_interrupt_lock_context lock_context;
bsp_interrupt_server_context *src = e->server;
bsp_interrupt_server_context *dst = hihd->arg;
rtems_interrupt_server_control *src = e->server;
rtems_interrupt_server_control *dst = hihd->arg;
bool pending;
/* The source server is only used in SMP configurations for the lock */
@@ -763,8 +921,8 @@ rtems_status_code rtems_interrupt_server_move(
)
{
rtems_status_code sc;
bsp_interrupt_server_context *src;
bsp_interrupt_server_context *dst;
rtems_interrupt_server_control *src;
rtems_interrupt_server_control *dst;
bsp_interrupt_server_handler_iterate_helper_data hihd;
src = bsp_interrupt_server_get_context(source_server_index, &sc);
@@ -810,7 +968,7 @@ static void bsp_interrupt_server_entry_suspend_helper(void *arg)
rtems_status_code rtems_interrupt_server_suspend(uint32_t server_index)
{
rtems_status_code sc;
bsp_interrupt_server_context *s;
rtems_interrupt_server_control *s;
s = bsp_interrupt_server_get_context(server_index, &sc);
if (s == NULL) {
@@ -831,7 +989,7 @@ rtems_status_code rtems_interrupt_server_suspend(uint32_t server_index)
rtems_status_code rtems_interrupt_server_resume(uint32_t server_index)
{
rtems_status_code sc;
bsp_interrupt_server_context *s;
rtems_interrupt_server_control *s;
s = bsp_interrupt_server_get_context(server_index, &sc);
if (s == NULL) {
@@ -858,7 +1016,7 @@ rtems_status_code rtems_interrupt_server_set_affinity(
)
{
rtems_status_code sc;
bsp_interrupt_server_context *s;
rtems_interrupt_server_control *s;
rtems_id scheduler;
s = bsp_interrupt_server_get_context(server_index, &sc);

View File

@@ -1,22 +1,37 @@
/* SPDX-License-Identifier: BSD-2-Clause */
/**
* @file
*
* @ingroup bsp_interrupt
*
* @brief Generic BSP interrupt shell implementation.
* @brief This source file contains the definition of
* ::bsp_interrupt_shell_command.
*/
/*
* Copyright (c) 2009
* embedded brains GmbH
* Obere Lagerstr. 30
* D-82178 Puchheim
* Germany
* <rtems@embedded-brains.de>
* Copyright (C) 2009 embedded brains GmbH (http://www.embedded-brains.de)
*
* The license and distribution terms for this file may be
* found in the file LICENSE in this distribution or at
* http://www.rtems.org/license/LICENSE.
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include <stdio.h>

View File

@@ -34,18 +34,6 @@ struct ambapp_bus ambapp_plb;
#include <drvmgr/drvmgr.h>
#include <grlib/ambapp_bus_grlib.h>
extern void gptimer_register_drv (void);
extern void apbuart_cons_register_drv(void);
/* All drivers included by BSP, this is overridden by the user by including
* the drvmgr_confdefs.h. By default the Timer and UART driver are included.
*/
drvmgr_drv_reg_func drvmgr_drivers[] __attribute__((weak)) =
{
gptimer_register_drv,
apbuart_cons_register_drv,
NULL /* End array with NULL */
};
/* Driver resources configuration for AMBA root bus. It is declared weak
* so that the user may override it, if the defualt settings are not
* enough.

View File

@@ -60,7 +60,10 @@ static void leon3_counter_initialize(void)
counter->counter_register = &gpt->timer[LEON3_COUNTER_GPTIMER_INDEX].value;
/* Enable timer just in case no clock driver is configured */
gpt->timer[LEON3_COUNTER_GPTIMER_INDEX].ctrl |= GPTIMER_TIMER_CTRL_EN;
gpt->timer[LEON3_COUNTER_GPTIMER_INDEX].reload = 0xffffffff;
gpt->timer[LEON3_COUNTER_GPTIMER_INDEX].ctrl |= GPTIMER_TIMER_CTRL_EN |
GPTIMER_TIMER_CTRL_RS |
GPTIMER_TIMER_CTRL_LD;
leon3_counter_frequency = ambapp_freq_get(&ambapp_plb, LEON3_Timer_Adev) /
(gpt->scaler_reload + 1);

View File

@@ -0,0 +1,28 @@
/*
* Default BSP drivers when Driver Manager enabled
*
* COPYRIGHT (c) 2019.
* Cobham Gaisler
*
* The license and distribution terms for this file may be
* found in the file LICENSE in this distribution or at
* http://www.rtems.org/license/LICENSE.
*/
#include <bsp.h>
#ifdef RTEMS_DRVMGR_STARTUP
#include <drvmgr/drvmgr.h>
extern void gptimer_register_drv (void);
extern void apbuart_cons_register_drv(void);
/* All drivers included by BSP, this is overridden by the user by including
* the drvmgr_confdefs.h. By default the Timer and UART driver are included.
*/
drvmgr_drv_reg_func drvmgr_drivers[] __attribute__((weak)) =
{
gptimer_register_drv,
apbuart_cons_register_drv,
NULL /* End array with NULL */
};
#endif

View File

@@ -71,6 +71,10 @@ librtemsbsp_a_SOURCES += ../../../../../../bsps/arm/shared/clock/clock-a9mpcore.
# I2C
librtemsbsp_a_SOURCES += ../../../../../../bsps/arm/xilinx-zynq/i2c/cadence-i2c.c
# SPI
librtemsbsp_a_SOURCES += ../../../../../../bsps/arm/shared/spi/cadence-spi.c
librtemsbsp_a_SOURCES += ../../../../../../bsps/arm/shared/spi/xilinx-axi-spi.c
# Cache
librtemsbsp_a_SOURCES += ../../../../../../bsps/arm/shared/cache/cache-l2c-310.c

View File

@@ -66,6 +66,10 @@ librtemsbsp_a_SOURCES += ../../../../../../bsps/arm/shared/serial/zynq-uart-poll
# Clock
librtemsbsp_a_SOURCES += ../../../../../../bsps/arm/shared/clock/clock-generic-timer.c
# SPI
librtemsbsp_a_SOURCES += ../../../../../../bsps/arm/shared/spi/cadence-spi.c
librtemsbsp_a_SOURCES += ../../../../../../bsps/arm/shared/spi/xilinx-axi-spi.c
# Cache
librtemsbsp_a_SOURCES += ../../../../../../bsps/arm/shared/cache/cache-cp15.c

View File

@@ -92,9 +92,10 @@ librtemsbsp_a_SOURCES += ../../../../../../bsps/powerpc/shared/btimer/btimer-ppc
librtemsbsp_a_SOURCES += ../../../../../../bsps/powerpc/shared/mmu/bat.c
librtemsbsp_a_SOURCES += ../../../../../../bsps/powerpc/shared/mmu/mmuAsm.S
librtemsbsp_a_SOURCES += ../../../../../../bsps/powerpc/shared/mmu/pte121.c
librtemsbsp_a_SOURCES += ../../../../../../bsps/powerpc/shared/irq/ppc-irq-legacy.c
librtemsbsp_a_SOURCES += ../../../../../../bsps/powerpc/shared/irq/ppc-irq-generic.c
librtemsbsp_a_SOURCES += ../../../../../../bsps/shared/irq/irq-default-handler.c
include $(srcdir)/../../../../../../bsps/shared/irq-default-sources.am
include $(srcdir)/../../../../../../bsps/shared/irq-sources.am
include $(srcdir)/../../../../../../bsps/shared/shared-sources.am
include $(top_srcdir)/../../../../automake/subdirs.am
include $(srcdir)/../../../../../../bsps/powerpc/shared/shared-sources.am

View File

@@ -38,6 +38,7 @@ librtemsbsp_a_SOURCES += ../../../../../../bsps/shared/start/bspreset-empty.c
librtemsbsp_a_SOURCES += ../../../../../../bsps/sparc/leon3/start/cpucounter.c
librtemsbsp_a_SOURCES += ../../../../../../bsps/sparc/shared/start/bsp_fatal_exit.c
librtemsbsp_a_SOURCES += ../../../../../../bsps/sparc/leon3/start/bsp_fatal_halt.c
librtemsbsp_a_SOURCES += ../../../../../../bsps/sparc/leon3/start/drvmgr_def_drivers.c
# gnatsupp
librtemsbsp_a_SOURCES += ../../../../../../bsps/sparc/leon3/gnatsupp/gnatsupp.c

View File

@@ -930,6 +930,7 @@ librtemscpu_a_SOURCES += score/src/schedulercbssetparameters.c
librtemscpu_a_SOURCES += score/src/schedulercbsreleasejob.c
librtemscpu_a_SOURCES += score/src/schedulercbsunblock.c
librtemscpu_a_SOURCES += score/src/stackallocator.c
librtemscpu_a_SOURCES += score/src/stackallocatorforidle.c
librtemscpu_a_SOURCES += score/src/pheapallocate.c
librtemscpu_a_SOURCES += score/src/pheapextend.c
librtemscpu_a_SOURCES += score/src/pheapfree.c
@@ -1483,6 +1484,10 @@ librtemscpu_a_SOURCES += libmisc/shell/login_prompt.c
librtemscpu_a_SOURCES += libmisc/shell/login_check.c
librtemscpu_a_SOURCES += libmisc/shell/fdisk.c
librtemscpu_a_SOURCES += libmisc/shell/main_rtc.c
librtemscpu_a_SOURCES += libmisc/shell/main_spi.c
librtemscpu_a_SOURCES += libmisc/shell/main_i2cdetect.c
librtemscpu_a_SOURCES += libmisc/shell/main_i2cset.c
librtemscpu_a_SOURCES += libmisc/shell/main_i2cget.c
librtemscpu_a_SOURCES += libmisc/shell/dd-args.c
librtemscpu_a_SOURCES += libmisc/shell/main_dd.c
librtemscpu_a_SOURCES += libmisc/shell/dd-conv.c

View File

@@ -416,6 +416,7 @@ include_rtems_score_HEADERS += include/rtems/score/threadimpl.h
include_rtems_score_HEADERS += include/rtems/score/threadmp.h
include_rtems_score_HEADERS += include/rtems/score/threadq.h
include_rtems_score_HEADERS += include/rtems/score/threadqimpl.h
include_rtems_score_HEADERS += include/rtems/score/threadqops.h
include_rtems_score_HEADERS += include/rtems/score/timecounter.h
include_rtems_score_HEADERS += include/rtems/score/timecounterimpl.h
include_rtems_score_HEADERS += include/rtems/score/timespec.h

View File

@@ -13,6 +13,10 @@
#include <stdint.h>
#include <rtems/rtl/rtl-obj-fwd.h>
#ifdef __cplusplus
extern "C" {
#endif
enum sections
{
rap_text = 0,
@@ -76,4 +80,8 @@ int _rtld_linkmap_add (rtems_rtl_obj* obj);
* Remove link map from the list.
*/
void _rtld_linkmap_delete (rtems_rtl_obj* obj);
#ifdef __cplusplus
}
#endif
#endif /* _LINK_ELF_H_ */

View File

@@ -17,6 +17,10 @@
#include <rtems/score/rbtree.h>
#ifdef __cplusplus
extern "C" {
#endif
#define rb_node RBTree_Node
#define rb_left Node.rbe_left
@@ -96,7 +100,7 @@ static inline struct rb_node *rb_last( struct rb_root *root )
static inline void rb_replace_node(
struct rb_node *victim,
struct rb_node *replacement,
struct rb_node *replacement,
struct rb_root *root
)
{
@@ -138,4 +142,8 @@ static inline struct rb_node *rb_parent( struct rb_node *node )
node = next \
)
#ifdef __cplusplus
}
#endif
#endif /* _LINUX_RBTREE_H */

View File

@@ -838,7 +838,7 @@ rtems_capture_task_flags (rtems_tcb* tcb)
static inline rtems_capture_control*
rtems_capture_task_control (rtems_tcb* tcb)
{
return tcb->Capture.control;
return (rtems_capture_control*) tcb->Capture.control;
}
/**
@@ -853,7 +853,7 @@ rtems_capture_task_control (rtems_tcb* tcb)
static inline uint32_t
rtems_capture_task_control_flags (rtems_tcb* tcb)
{
rtems_capture_control* control = tcb->Capture.control;
rtems_capture_control* control = rtems_capture_task_control (tcb);
if (!control)
return 0;
return control->flags;

View File

@@ -21,6 +21,10 @@
#error "Do not include this file directly, use <rtems/confdefs.h> instead"
#endif
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
/*
* Select PCI Configuration Library
*/
@@ -67,4 +71,8 @@
#endif
#endif
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif /* _RTEMS_CONFDEFS_LIBPCI_H */

View File

@@ -6,9 +6,6 @@
* @ingroup RTEMSApplicationConfiguration
*
* @brief Evaluate MPCI Configuration Options
*
* This header file defines _CONFIGURE_MPCI_RECEIVE_SERVER_COUNT for use by
* other configuration header files.
*/
/*
@@ -49,6 +46,8 @@
#ifdef CONFIGURE_MP_APPLICATION
#include <rtems/confdefs/threads.h>
#ifndef CONFIGURE_EXTRA_MPCI_RECEIVE_SERVER_STACK
#define CONFIGURE_EXTRA_MPCI_RECEIVE_SERVER_STACK 0
#endif
@@ -83,8 +82,6 @@
#error "CONFIGURE_MP_NODE_NUMBER must be less than or equal to CONFIGURE_MP_MAXIMUM_NODES"
#endif
#define _CONFIGURE_MPCI_RECEIVE_SERVER_COUNT 1
#ifdef __cplusplus
extern "C" {
#endif
@@ -126,10 +123,6 @@ RTEMS_SECTION( ".rtemsstack.mpci" );
}
#endif
#else /* CONFIGURE_MP_APPLICATION */
#define _CONFIGURE_MPCI_RECEIVE_SERVER_COUNT 0
#endif /* CONFIGURE_MP_APPLICATION */
#else /* RTEMS_MULTIPROCESSING */
@@ -138,8 +131,6 @@ RTEMS_SECTION( ".rtemsstack.mpci" );
#error "CONFIGURE_MP_APPLICATION must not be defined if multiprocessing is disabled"
#endif
#define _CONFIGURE_MPCI_RECEIVE_SERVER_COUNT 0
#endif /* RTEMS_MULTIPROCESSING */
#endif /* CONFIGURE_INIT */

View File

@@ -133,11 +133,19 @@ RTEMS_DEFINE_GLOBAL_SYMBOL(
const size_t _Thread_Idle_stack_size = CONFIGURE_IDLE_TASK_STACK_SIZE;
char _Thread_Idle_stacks[
_CONFIGURE_MAXIMUM_PROCESSORS
* ( CONFIGURE_IDLE_TASK_STACK_SIZE + CPU_IDLE_TASK_IS_FP * CONTEXT_FP_SIZE )
] RTEMS_ALIGNED( CPU_INTERRUPT_STACK_ALIGNMENT )
RTEMS_SECTION( ".rtemsstack.idle" );
/*
* If the user provides a custom idle stack allocator, then we do not need
* memory reserved for the stacks but the symbol is still referenced in
* threadcreateidle.c. The code path just never uses it. Make it minimal
* size to proceed.
*/
#ifndef CONFIGURE_TASK_STACK_ALLOCATOR_FOR_IDLE
char _Thread_Idle_stacks[
_CONFIGURE_MAXIMUM_PROCESSORS
* ( CONFIGURE_IDLE_TASK_STACK_SIZE + CPU_IDLE_TASK_IS_FP * CONTEXT_FP_SIZE )
] RTEMS_ALIGNED( CPU_INTERRUPT_STACK_ALIGNMENT )
RTEMS_SECTION( ".rtemsstack.idle" );
#endif
#if defined(CONFIGURE_IDLE_TASK_INITIALIZES_APPLICATION) && \
!defined(CONFIGURE_IDLE_TASK_BODY)

View File

@@ -44,7 +44,6 @@
#include <rtems/confdefs/bdbuf.h>
#include <rtems/confdefs/extensions.h>
#include <rtems/confdefs/mpci.h>
#include <rtems/confdefs/percpu.h>
#include <rtems/confdefs/scheduler.h>
#include <rtems/confdefs/unlimited.h>
@@ -197,6 +196,12 @@ const size_t _Thread_Initial_thread_count =
rtems_resource_maximum_per_allocation( _CONFIGURE_TASKS ) +
rtems_resource_maximum_per_allocation( CONFIGURE_MAXIMUM_POSIX_THREADS );
#if defined(RTEMS_MULTIPROCESSING) && defined(CONFIGURE_MP_APPLICATION)
#define _CONFIGURE_MPCI_RECEIVE_SERVER_COUNT 1
#else
#define _CONFIGURE_MPCI_RECEIVE_SERVER_COUNT 0
#endif
THREAD_INFORMATION_DEFINE(
_Thread,
OBJECTS_INTERNAL_API,

View File

@@ -132,12 +132,14 @@ const uintptr_t _Stack_Space_size = _CONFIGURE_STACK_SPACE_SIZE;
#if defined(CONFIGURE_TASK_STACK_ALLOCATOR) \
&& defined(CONFIGURE_TASK_STACK_DEALLOCATOR)
/* Custom allocator may or may not use the work space. */
#ifdef CONFIGURE_TASK_STACK_ALLOCATOR_AVOIDS_WORK_SPACE
const bool _Stack_Allocator_avoids_workspace = true;
#else
const bool _Stack_Allocator_avoids_workspace = false;
#endif
/* Custom allocator may or may not need initialization. */
#ifdef CONFIGURE_TASK_STACK_ALLOCATOR_INIT
const Stack_Allocator_initialize _Stack_Allocator_initialize =
CONFIGURE_TASK_STACK_ALLOCATOR_INIT;
@@ -145,16 +147,30 @@ const uintptr_t _Stack_Space_size = _CONFIGURE_STACK_SPACE_SIZE;
const Stack_Allocator_initialize _Stack_Allocator_initialize = NULL;
#endif
/* Custom allocator must include allocate and free */
const Stack_Allocator_allocate _Stack_Allocator_allocate =
CONFIGURE_TASK_STACK_ALLOCATOR;
const Stack_Allocator_free _Stack_Allocator_free =
CONFIGURE_TASK_STACK_DEALLOCATOR;
/*
* Must provide both a custom stack allocator and deallocator
*/
#elif defined(CONFIGURE_TASK_STACK_ALLOCATOR) \
|| defined(CONFIGURE_TASK_STACK_DEALLOCATOR)
#error "CONFIGURE_TASK_STACK_ALLOCATOR and CONFIGURE_TASK_STACK_DEALLOCATOR must be both defined or both undefined"
#endif
/*
* Custom IDLE thread stacks allocator. If this is provided, it is assumed
* that the allocator is providing its own memory for these stacks.
*/
#ifdef CONFIGURE_TASK_STACK_ALLOCATOR_FOR_IDLE
const Stack_Allocator_allocate_for_idle _Stack_Allocator_allocate_for_idle =
CONFIGURE_TASK_STACK_ALLOCATOR_FOR_IDLE;
#endif
#ifdef CONFIGURE_DIRTY_MEMORY
RTEMS_SYSINIT_ITEM(
_Memory_Dirty_free_areas,

View File

@@ -129,6 +129,9 @@ uint32_t rtems_configuration_get_maximum_extensions( void );
#define rtems_configuration_get_stack_free_hook() \
(_Stack_Allocator_free)
#define rtems_configuration_get_stack_allocate_for_idle_hook() \
(_Stack_Allocator_allocate_for_idle)
/**
* This macro assists in accessing the field which indicates whether
* RTEMS is responsible for zeroing the Executive Workspace.

View File

@@ -214,6 +214,9 @@ typedef struct {
/**
* @brief Converter implementation for new file system instance.
*
* Note: If you pass a converter to mount, you have to destroy it yourself if
* mount failed. In a good case it is destroyed at unmount.
*
* Before converters have been added to the RTEMS implementation of the FAT
* file system, the implementation was:
* - Short names were saved in code page format (as is still the case).
@@ -270,6 +273,10 @@ typedef struct {
* RTEMS_FILESYSTEM_READ_WRITE,
* &mount_opts
* );
*
* if (rv != 0) {
* (*mount_opts.converter->handler->destroy)(mount_opts.converter);
* }
* } else {
* rv = -1;
* errno = ENOMEM;

View File

@@ -9,13 +9,7 @@
/*
* Based on concepts of Pavel Pisa, Till Straumann and Eric Valette.
*
* Copyright (C) 2008, 2019 embedded brains GmbH
*
* embedded brains GmbH
* Dornierstr. 4
* 82178 Puchheim
* Germany
* <rtems@embedded-brains.de>
* Copyright (C) 2008, 2020 embedded brains GmbH (http://www.embedded-brains.de)
*
* The license and distribution terms for this file may be
* found in the file LICENSE in this distribution or at
@@ -259,6 +253,76 @@ typedef struct rtems_interrupt_server_action {
*/
#define RTEMS_INTERRUPT_SERVER_DEFAULT 0
/**
* @brief An interrupt server control.
*
* This structure must be treated as an opaque data type. Members must not be
* accessed directly.
*
* @see rtems_interrupt_server_create()
*/
typedef struct rtems_interrupt_server_control {
RTEMS_INTERRUPT_LOCK_MEMBER( lock )
rtems_chain_control entries;
rtems_id server;
unsigned long errors;
uint32_t index;
rtems_chain_node node;
void ( *destroy )( struct rtems_interrupt_server_control * );
} rtems_interrupt_server_control;
/**
* @brief An interrupt server configuration.
*
* @see rtems_interrupt_server_create()
*/
typedef struct {
/**
* @brief The task name of the interrupt server.
*/
rtems_name name;
/**
* @brief The initial task priority of the interrupt server.
*/
rtems_task_priority priority;
/**
* @brief The task storage area of the interrupt server.
*
* It shall be NULL for interrupt servers created by
* rtems_interrupt_server_create().
*/
void *storage_area;
/**
* @brief The task storage size of the interrupt server.
*
* For interrupt servers created by rtems_interrupt_server_create() this is
* the task stack size.
*/
size_t storage_size;
/**
* @brief The initial task modes of the interrupt server.
*/
rtems_mode modes;
/**
* @brief The task attributes of the interrupt server.
*/
rtems_attribute attributes;
/**
* @brief An optional handler to destroy the interrupt server control handed
* over to rtems_interrupt_server_create().
*
* This handler is called in the context of the interrupt server to be
* deleted, see also rtems_interrupt_server_delete().
*/
void ( *destroy )( rtems_interrupt_server_control * );
} rtems_interrupt_server_config;
/**
* @brief An interrupt server entry.
*
@@ -309,16 +373,19 @@ typedef struct {
*
* The server count pointer @a server_count may be @a NULL.
*
* The task name of interrupt servers created by this function is
* rtems_build_name( 'I', 'R', 'Q', 'S' ).
*
* This function may block.
*
* @see rtems_task_create().
* @retval RTEMS_SUCCESSFUL The operation was successful.
*
* @retval RTEMS_SUCCESSFUL Successful operation.
* @retval RTEMS_INCORRECT_STATE The interrupt servers are not initialized.
* @retval RTEMS_NO_MEMORY Not enough memory.
* @retval RTEMS_TOO_MANY No free task available to create at least one server task.
* @retval RTEMS_UNSATISFIED Task stack size too large.
* @retval RTEMS_INVALID_PRIORITY Invalid task priority.
* @retval RTEMS_INCORRECT_STATE The interrupt servers were already initialized.
*
* @return The function uses rtems_task_create(). If this operation is not
* successful, then its status code is returned.
*
* @see rtems_interrupt_server_create() and rtems_interrupt_server_delete().
*/
rtems_status_code rtems_interrupt_server_initialize(
rtems_task_priority priority,
@@ -328,6 +395,54 @@ rtems_status_code rtems_interrupt_server_initialize(
uint32_t *server_count
);
/**
* @brief Creates an interrupt server.
*
* This function may block.
*
* @param[out] control is the interrupt server control. The ownership of this
* structure is transferred from the caller of this function to the interrupt
* server management.
*
* @param config is the interrupt server configuration.
*
* @param[out] server_index is the pointer to a server index variable. The
* index of the built interrupt server will be stored in the referenced
* variable if the operation was successful.
*
* @retval RTEMS_SUCCESSFUL The operation was successful.
*
* @return The function uses rtems_task_create(). If this operation is not
* successful, then its status code is returned.
*
* @see rtems_interrupt_server_initialize() and
* rtems_interrupt_server_delete().
*/
rtems_status_code rtems_interrupt_server_create(
rtems_interrupt_server_control *control,
const rtems_interrupt_server_config *config,
uint32_t *server_index
);
/**
* @brief Destroys the interrupt server.
*
* This function may block.
*
* The interrupt server deletes itself, so after the return of the function the
* interrupt server may be still in the termination process depending on the
* task priorities of the system.
*
* @param server_index is the index of the interrupt server to destroy. Use
* ::RTEMS_INTERRUPT_SERVER_DEFAULT to specify the default server.
*
* @retval RTEMS_SUCCESSFUL The operation was successful.
* @retval RTEMS_INVALID_ID The interrupt server index was invalid.
*
* @see rtems_interrupt_server_create()
*/
rtems_status_code rtems_interrupt_server_delete( uint32_t server_index );
/**
* @brief Installs the interrupt handler routine @a handler for the interrupt
* vector with number @a vector on the server @a server.

Some files were not shown because too many files have changed in this diff Show More