Skip to content
Projects
Groups
Snippets
Help
Loading...
Sign in
Toggle navigation
W
White Rabbit Switch - Software
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
86
Issues
86
List
Board
Labels
Milestones
Merge Requests
4
Merge Requests
4
CI / CD
CI / CD
Pipelines
Schedules
Wiki
Wiki
image/svg+xml
Discourse
Discourse
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Commits
Issue Boards
Open sidebar
Projects
White Rabbit Switch - Software
Commits
dc258a8e
Commit
dc258a8e
authored
Jan 18, 2012
by
Alessandro Rubini
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
tools: new, faster, load-fpga by Tom
parent
faee4998
Hide whitespace changes
Inline
Side-by-side
Showing
1 changed file
with
92 additions
and
54 deletions
+92
-54
load-fpga.c
tools/load-fpga.c
+92
-54
No files found.
tools/load-fpga.c
View file @
dc258a8e
/*
* Trivial gpio bit banger.
* Alessandro Rubini, 2011, for CERN.
* Turned into and spi user-space driver
* Tomasz Wlostowski, 2012, for CERN.
*
* Released to the public domain.
*/
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
...
...
@@ -15,24 +19,21 @@
#include <sys/mman.h>
#include <sys/time.h>
#include <linux/types.h>
#include <mach/at91_pio.h>
/* -I$LINUX/arch/arm/mach-at91/include/ */
/* -I$LINUX/arch/arm/mach-at91/include/ */
#include <mach/at91_pio.h>
#include <mach/at91_ssc.h>
#include <mach/at91_pmc.h>
#include <mach/at91sam9g45.h>
#ifndef ARRAY_SIZE
#define ARRAY_SIZE(a) (sizeof(a)/sizeof(a[0]))
#endif
unsigned
char
bstream
[
10
*
1000
*
1000
];
/* me lazy bastard */
void
*
pio
[
5
];
/* from mmap(/dev/mem) */
/* describe the g45 memory layout */
unsigned
char
*
piobase
=
(
void
*
)
0xfffff000
;
unsigned
char
*
bstream
;
int
offsets
[]
=
{
0x200
,
0x400
,
0x600
,
0x800
,
0xa00
};
void
*
pio
[
5
];
/* from mmap(/dev/mem) plus offsets above */
/* The address and size of the entire AT91 I/O reg space */
#define BASE_IOREGS 0xfff78000
#define SIZE_IOREGS 0x88000
enum
{
PIOA
=
0
,
...
...
@@ -42,8 +43,23 @@ enum {
PIOE
=
4
};
/* macro to access 32-bit registers */
#define __PIO(port, regname) (*(volatile __u32 *)(pio[port] + regname))
void
*
ioregs
;
#define AT91_PIOx(port) (AT91_PIOA + AT91_BASE_SYS + 0x200 * port)
/* macros to access 32-bit registers of various peripherals */
#define __PIO(port, regname) (*(volatile uint32_t *) \
(ioregs + AT91_PIOx(port) - BASE_IOREGS + regname))
#define __SSC(regname) (*(volatile uint32_t *) \
(ioregs + (AT91SAM9G45_BASE_SSC0 - BASE_IOREGS) + regname))
#define __PMC(regname) \
(*(volatile uint32_t *)(ioregs + (AT91_BASE_SYS - BASE_IOREGS) + regname))
/* Missing SSC reg fields */
#define AT91_SSC_CKO_DURING_XFER (2 << 2)
/* This sets a bit. To clear output se set ODR (output disable register) */
static
inline
void
pio_set
(
int
regname
,
int
port
,
int
bit
)
...
...
@@ -82,7 +98,7 @@ void ud(int usecs) /* horrible udelay thing without scheduling */
int
main
(
int
argc
,
char
**
argv
)
{
int
pagesize
,
bs_size
,
i
;
int
bs_size
,
i
;
int
fdmem
;
if
(
argc
!=
2
)
{
...
...
@@ -100,20 +116,30 @@ int main(int argc, char **argv)
strerror
(
errno
));
exit
(
1
);
}
bs_size
=
fread
(
bstream
,
1
,
sizeof
(
bstream
),
f
);
if
(
bs_size
<
0
)
{
fprintf
(
stderr
,
"%s: read(%s): %s
\n
"
,
argv
[
0
],
argv
[
1
],
strerror
(
errno
));
fseek
(
f
,
0
,
SEEK_END
);
bs_size
=
ftell
(
f
);
fseek
(
f
,
0
,
SEEK_SET
);
bstream
=
malloc
(
bs_size
);
if
(
bstream
==
NULL
)
{
fprintf
(
stderr
,
"malloc failed
\n
"
);
fclose
(
f
);
exit
(
1
);
}
if
(
bs_size
==
sizeof
(
bstream
))
{
fprintf
(
stderr
,
"%s: %s: too big
\n
"
,
argv
[
0
],
argv
[
1
]);
if
(
fread
(
bstream
,
1
,
bs_size
,
f
)
!=
bs_size
)
{
fprintf
(
stderr
,
"%s: read(%s): %s
\n
"
,
argv
[
0
],
argv
[
1
],
strerror
(
errno
));
exit
(
1
);
}
fclose
(
f
);
}
pagesize
=
getpagesize
();
/* can't fail */
/* /dev/mem for mmap of both gpio and spi1 */
if
((
fdmem
=
open
(
"/dev/mem"
,
O_RDWR
|
O_SYNC
))
<
0
)
{
...
...
@@ -122,33 +148,50 @@ int main(int argc, char **argv)
}
/* map a whole page (4kB, but we called getpagesize to know it) */
piobase
=
mmap
(
0
,
pagesize
,
PROT_READ
|
PROT_WRITE
,
MAP_SHARED
,
fdmem
,
(
int
)
piobase
&
(
~
(
pagesize
-
1
)));
if
(
piobase
==
MAP_FAILED
)
{
ioregs
=
mmap
(
0
,
SIZE_IOREGS
,
PROT_READ
|
PROT_WRITE
,
MAP_SHARED
,
fdmem
,
BASE_IOREGS
);
if
(
ioregs
==
MAP_FAILED
)
{
fprintf
(
stderr
,
"%s: mmap(/dev/mem): %s
\n
"
,
argv
[
0
],
strerror
(
errno
));
exit
(
1
);
}
/* ok, now move the pointers within the page, we won't munmap anyways */
for
(
i
=
0
;
i
<
ARRAY_SIZE
(
pio
);
i
++
)
{
pio
[
i
]
=
piobase
+
offsets
[
i
];
}
/*
* all of this stuff is working on gpio so enable pio, out or in
*/
/* clock and data are output, low by now */
pio_set
(
PIO_PER
,
TK0
);
pio_set
(
PIO_CODR
,
TK0
);
/* clock and data are output, connected to SSC, low by now */
pio_set
(
PIO_PDR
,
TK0
);
pio_set
(
PIO_ASR
,
TK0
);
pio_set
(
PIO_OER
,
TK0
);
pio_set
(
PIO_P
E
R
,
TD0
);
pio_set
(
PIO_
COD
R
,
TD0
);
pio_set
(
PIO_P
D
R
,
TD0
);
pio_set
(
PIO_
AS
R
,
TD0
);
pio_set
(
PIO_OER
,
TD0
);
/* enable SSC controller clock */
__PMC
(
AT91_PMC_PCER
)
=
1
<<
AT91SAM9G45_ID_SSC0
;
__SSC
(
AT91_SSC_CR
)
=
AT91_SSC_SWRST
;
__SSC
(
AT91_SSC_CR
)
=
0
;
/* Config clock rate = MCK / 3 */
__SSC
(
AT91_SSC_CMR
)
=
2
&
AT91_SSC_CMR_DIV
;
/* Clock source = divided master clock,
active only during data transfer, extra 2 cycles of delay
between subsequent bytes */
__SSC
(
AT91_SSC_TCMR
)
=
AT91_SSC_CKS_DIV
|
AT91_SSC_CKO_DURING_XFER
|
(
2
<<
16
);
/* 8 bits/xfer, MSB first */
__SSC
(
AT91_SSC_TFMR
)
=
(
7
&
AT91_SSC_DATALEN
)
|
AT91_SSC_MSBF
;
__SSC
(
AT91_SSC_CR
)
=
AT91_SSC_TXEN
;
/* fpga_reset is high */
pio_set
(
PIO_PER
,
FPGA_RESET
);
pio_set
(
PIO_SODR
,
FPGA_RESET
);
...
...
@@ -213,34 +256,29 @@ int main(int argc, char **argv)
if
(
pio_get
(
INITB
))
break
;
}
if
(
pio_get
(
INITB
))
{
fprintf
(
stderr
,
"%s: INIT_B is not going back high
\n
"
,
argv
[
0
]);
//exit(1);
}
ud
(
1000
);
/* wait for a short while before commencing the configuration - otherwise
the FPGA might not assert the DONE flag correctly */
/* Then write one byte at a time */
for
(
i
=
0
;
i
<
bs_size
;
i
++
)
{
int
byte
=
bstream
[
i
];
int
bit
;
if
(
!
(
i
&
1023
))
{
putchar
(
'.'
);
fflush
(
stdout
);
}
/* msb first */
for
(
bit
=
0x80
;
bit
>
0
;
bit
>>=
1
)
{
/* data on rising edge of clock, which starts low */
if
(
byte
&
bit
)
pio_set
(
PIO_SODR
,
TD0
);
else
pio_set
(
PIO_CODR
,
TD0
);
/* so, rising edge, after it's stable */
asm
volatile
(
"nop
\n
nop
\n
nop
\n
nop"
);
pio_set
(
PIO_SODR
,
TK0
);
pio_set
(
PIO_CODR
,
TK0
);
printf
(
"Booting FPGA: "
);
for
(
i
=
0
;
i
<
bs_size
;
i
++
)
{
if
(
!
(
i
&
32767
))
{
putchar
(
'.'
);
fflush
(
stdout
);
}
while
(
!
(
__SSC
(
AT91_SSC_SR
)
&
AT91_SSC_TXEMPTY
))
;
__SSC
(
AT91_SSC_THR
)
=
bstream
[
i
];
if
(
0
&&
/* don't do this check */
!
pio_get
(
DONE
))
{
fprintf
(
stderr
,
"%s: DONE is already high after "
"%i bytes (missing %i)
\n
"
,
argv
[
0
],
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment