Skip to content
GitLab
Menu
Projects
Groups
Snippets
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Sign in / Register
Toggle navigation
Menu
Open sidebar
adam.huang
Sunxi Tools
Commits
6d598a0e
Unverified
Commit
6d598a0e
authored
Nov 14, 2018
by
Chen-Yu Tsai
Committed by
GitHub
Nov 14, 2018
Browse files
Merge pull request #114 from apritzel/v1.5-rc1
v1.5-rc1
parents
5c197104
585cb1d4
Changes
12
Hide whitespace changes
Inline
Side-by-side
Makefile
View file @
6d598a0e
...
...
@@ -135,8 +135,9 @@ HOST_CFLAGS = $(DEFAULT_CFLAGS) $(CFLAGS)
PROGRESS
:=
progress.c progress.h
SOC_INFO
:=
soc_info.c soc_info.h
FEL_LIB
:=
fel_lib.c fel_lib.h
SPI_FLASH
:=
fel-spiflash.c fel-spiflash.h fel-remotefunc-spi-data-transfer.h
sunxi-fel
:
fel.c thunks/fel-to-spl-thunk.h $(PROGRESS) $(SOC_INFO) $(FEL_LIB)
sunxi-fel
:
fel.c thunks/fel-to-spl-thunk.h $(PROGRESS) $(SOC_INFO) $(FEL_LIB)
$(SPI_FLASH)
$(CC)
$(HOST_CFLAGS)
$(LIBUSB_CFLAGS)
$(ZLIB_CFLAGS)
$(LDFLAGS)
-o
$@
\
$(
filter
%.c,
$^
)
$(LIBS)
$(LIBUSB_LIBS)
$(ZLIB_LIBS)
...
...
fel-remotefunc-compiler.rb
0 → 100755
View file @
6d598a0e
#!/usr/bin/env ruby
#
# (C) Copyright 2016 Siarhei Siamashka <siarhei.siamashka@gmail.com>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
if
ARGV
.
size
<
2
printf
(
"Usage:
#{
$PROGRAM_NAME
}
[c_source_input] [marshalled_header_output]
\n\n
"
)
printf
(
"This script uses an ARM toolchain to compile native ARM code, and then
\n
"
)
printf
(
"automatically generates the necessary wrapper code for calling it from
\n
"
)
printf
(
"the sunxi-fel tool. Executing such compiled pieces of code natively on
\n
"
)
printf
(
"the device may be needed for the performance critical parts.
\n
"
)
printf
(
"
\n
Example input file:
\n\n
"
)
printf
(
" unsigned sum(unsigned a, unsigned b)
\n
"
)
printf
(
" {
\n
"
)
printf
(
" return a + b;
\n
"
)
printf
(
" }
\n
"
)
printf
(
"
\n
"
)
printf
(
"Using this example code inside of sunxi-fel:
\n
"
)
printf
(
"
\n
"
)
printf
(
" uint32_t a = 1, b = 2, c;
\n
"
)
printf
(
" aw_fel_remotefunc_prepare_sum(dev, a, b);
\n
"
)
printf
(
" aw_fel_remotefunc_execute(dev, &c);
\n
"
)
printf
(
" printf(
\"
%%d + %%d = %%d
\\
n
\"
, a, b, c);
\n\n
"
)
printf
(
"If the returned result is not needed (a void function), then the second
\n
"
)
printf
(
"argument to the 'aw_fel_remotefunc_execute' function can be NULL.
\n\n
"
)
exit
(
1
)
end
def
tool_exists
(
tool_name
)
`which
#{
tool_name
}
> /dev/null 2>&1`
return
$?
.
to_i
==
0
end
def
parse_stack_usage
(
filename
)
return
unless
File
.
exists?
(
filename
)
File
.
read
(
filename
).
strip
.
split
(
"
\n
"
).
map
do
|
l
|
if
l
=~
/\:([^\:\s]+)\s+(\d+)\s+(\S+)/
if
$3
!=
"static"
abort
sprintf
(
"Non-static stack usage for function '%s'
\n
"
,
$1
)
end
{
function_name:
$1
,
stack_usage:
$2
.
to_i
}
else
abort
sprintf
(
"Failed to parse stack usage information '%s'
\n
"
,
l
.
strip
)
end
end
end
toolchains
=
[
"arm-none-eabi-"
,
"arm-linux-gnueabihf-"
,
"arm-none-linux-gnueabi-"
,
"armv7a-hardfloat-linux-gnueabi-"
,
]
toolchain
=
toolchains
.
find
{
|
toolchain
|
tool_exists
(
"
#{
toolchain
}
gcc"
)
}
abort
"Can't find any usable ARM crosscompiler.
\n
"
unless
toolchain
# Compile the source file
system
(
"
#{
toolchain
}
gcc -c -O3 -marm -march=armv7-a -mfloat-abi=soft -fstack-usage -fpic -o
#{
ARGV
[
0
]
}
.o
#{
ARGV
[
0
]
}
"
)
exit
(
$?
.
to_i
)
if
$?
.
to_i
!=
0
# Read the stack usage information
stack_usage
=
parse_stack_usage
(
"
#{
ARGV
[
0
]
}
.su"
)
if
stack_usage
.
size
!=
1
abort
sprintf
(
"Expected only one function in the source file, but got %s.
\n
"
,
stack_usage
.
map
{
|
a
|
"'"
+
a
[
:function_name
]
+
"()'"
}.
join
(
", "
))
end
`
#{
toolchain
}
size -A
#{
ARGV
[
0
]
}
.o`
.
each_line
do
|
l
|
if
l
=~
/(\S+)\s+(\S+)/
if
(
$1
==
".data"
||
$1
==
".bss"
||
$1
==
".rodata"
)
&&
$2
.
to_i
>
0
abort
"Can't have non-empty '.data', '.bss' or '.rodata' section."
end
end
end
`
#{
toolchain
}
objdump -t
#{
ARGV
[
0
]
}
.o`
.
each_line
do
|
l
|
if
l
=~
/\*UND\*/
abort
"External references are not allowed: '
#{
l
.
strip
}
'.
\n
"
end
end
function_name
=
stack_usage
[
0
][
:function_name
]
# Read the source file and strip multiline C comments
sourcefile
=
File
.
read
(
ARGV
[
0
]).
gsub
(
/\/\*.*?\*\//m
,
""
)
# Try to find the function and its arguments
unless
sourcefile
=~
/
#{
function_name
}
\((.*?)\)/m
abort
sprintf
(
"Can't find the function '%s()' in the source file.
\n
"
,
function_name
)
end
# Extract the function argument names
function_args
=
$1
.
split
(
","
).
map
{
|
a
|
if
a
.
strip
=~
/([^\*\s]+)$/
then
$1
end
}
# Check if there is any return value
have_retval
=
!
(
sourcefile
=~
/void\s+
#{
function_name
}
/m
)
###############################################################################
# Generate output file
###############################################################################
out
=
File
.
open
(
ARGV
[
1
],
"w"
)
out
.
printf
(
"/* Automatically generated, do not edit! */
\n\n
"
)
out
.
printf
(
"static void
\n
"
)
funcdecl
=
sprintf
(
"aw_fel_remotefunc_prepare_
#{
function_name
}
(feldev_handle *dev,"
)
out
.
printf
(
"%s
\n
"
,
funcdecl
)
out
.
printf
(
"%s"
,
function_args
.
map
{
|
a
|
" "
*
funcdecl
.
index
(
"("
)
+
" uint32_t "
+
a
}.
join
(
",
\n
"
))
out
.
printf
(
")
\n
{
\n
"
)
out
.
printf
(
"
\t
static uint8_t arm_code[] = {
\n
"
)
`
#{
toolchain
}
objdump -d
#{
ARGV
[
0
]
}
.o`
.
each_line
{
|
l
|
next
unless
l
=~
/(\h+)\:\s+(\h+)\s+(\S+)\s+([^;]*)/
addr
=
$1
opcode
=
$2
p1
=
$3
p2
=
$4
.
strip
opcode
=
opcode
.
scan
(
/../
).
map
{
|
a
|
"0x"
+
a
}.
reverse
.
join
(
", "
)
out
.
printf
(
"
\t\t
%s, /* %4s: %-8s %-34s
\x2a
/
\n
"
,
opcode
,
addr
,
p1
,
p2
)
}
out
.
printf
(
"
\t
};
\n
"
)
out
.
printf
(
"
\t
uint32_t args[] = {
\n\t\t
"
)
out
.
printf
(
"%s
\n\t
};
\n
"
,
function_args
.
join
(
",
\n\t\t
"
))
out
.
printf
(
"
\t
aw_fel_remotefunc_prepare(dev, %d, arm_code, sizeof(arm_code), %d, args);
\n
"
,
stack_usage
[
0
][
:stack_usage
],
function_args
.
size
)
out
.
printf
(
"}
\n
"
)
fel-remotefunc-spi-data-transfer.c
0 → 100644
View file @
6d598a0e
/*
* Copyright © 2016 Siarhei Siamashka <siarhei.siamashka@gmail.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
typedef
unsigned
int
u32
;
typedef
unsigned
char
u8
;
#define readl(addr) (*((volatile u32 *)(addr)))
#define writel(v, addr) (*((volatile u32 *)(addr)) = (u32)(v))
#define readb(addr) (*((volatile u8 *)(addr)))
#define writeb(v, addr) (*((volatile u8 *)(addr)) = (u8)(v))
/*
* This is a basic full-duplex SPI data transfer function (we are sending a
* block of data and receiving the same amount of data back), doing the job
* without any help from DMA. And because we can be running in some rather
* adverse conditions (with default PMIC settings, low CPU clock speed and
* CPU caches disabled), it is necessary to use 32-bit accesses to read/write
* the FIFO buffers. As a result, Allwinner A13 with the default 408MHz CPU
* clock speed can successfully handle at least 12 MHz SPI clock speed.
*
* Supports both sun4i and sun6i variants of the SPI controller (they only
* need different hardware register addresses passed as arguments).
*/
static
void
inline
__attribute
((
always_inline
))
spi_data_transfer
(
void
*
buf
,
u32
bufsize
,
void
*
spi_ctl_reg
,
u32
spi_ctl_xch_bitmask
,
void
*
spi_fifo_reg
,
void
*
spi_tx_reg
,
void
*
spi_rx_reg
,
void
*
spi_bc_reg
,
void
*
spi_tc_reg
,
void
*
spi_bcc_reg
)
{
u32
cnt
;
u32
rxsize
=
bufsize
;
u32
txsize
=
bufsize
;
u8
*
rxbuf8
=
buf
;
u8
*
txbuf8
=
buf
;
u32
*
rxbuf
;
u32
*
txbuf
;
u32
cpsr
;
/* sun6i uses 3 registers, sun4i only needs 2 */
writel
(
bufsize
,
spi_bc_reg
);
writel
(
bufsize
,
spi_tc_reg
);
if
(
spi_bcc_reg
)
writel
(
bufsize
,
spi_bcc_reg
);
/* Fill the TX buffer with some initial data */
cnt
=
(
-
(
u32
)
txbuf8
&
3
)
+
60
;
if
(
cnt
>
txsize
)
cnt
=
txsize
;
while
(
cnt
--
>
0
)
{
writeb
(
*
txbuf8
++
,
spi_tx_reg
);
txsize
--
;
}
/* Temporarily disable IRQ & FIQ */
asm
volatile
(
"mrs %0, cpsr"
:
"=r"
(
cpsr
));
asm
volatile
(
"msr cpsr_c, %0"
::
"r"
(
cpsr
|
0xC0
));
/* Start the data transfer */
writel
(
readl
(
spi_ctl_reg
)
|
spi_ctl_xch_bitmask
,
spi_ctl_reg
);
/* Read the initial unaligned part of the data */
cnt
=
(
-
(
u32
)
rxbuf8
&
3
);
if
(
cnt
>
rxsize
)
cnt
=
rxsize
;
while
(
cnt
>
0
)
{
u32
fiforeg
=
readl
(
spi_fifo_reg
);
int
rxfifo
=
fiforeg
&
0x7F
;
if
(
rxfifo
>
0
)
{
*
rxbuf8
++
=
readb
(
spi_rx_reg
);
cnt
--
;
rxsize
--
;
}
}
/* Fast processing of the aligned part (read/write 32-bit at a time) */
rxbuf
=
(
u32
*
)
rxbuf8
;
txbuf
=
(
u32
*
)
txbuf8
;
while
(
rxsize
>=
4
)
{
u32
fiforeg
=
readl
(
spi_fifo_reg
);
int
rxfifo
=
fiforeg
&
0x7F
;
int
txfifo
=
(
fiforeg
>>
16
)
&
0x7F
;
if
(
rxfifo
>=
4
)
{
*
rxbuf
++
=
readl
(
spi_rx_reg
);
rxsize
-=
4
;
}
if
(
txfifo
<
60
&&
txsize
>=
4
)
{
writel
(
*
txbuf
++
,
spi_tx_reg
);
txsize
-=
4
;
}
}
/* Handle the trailing part pf the data */
rxbuf8
=
(
u8
*
)
rxbuf
;
txbuf8
=
(
u8
*
)
txbuf
;
while
(
rxsize
>=
1
)
{
u32
fiforeg
=
readl
(
spi_fifo_reg
);
int
rxfifo
=
fiforeg
&
0x7F
;
int
txfifo
=
(
fiforeg
>>
16
)
&
0x7F
;
if
(
rxfifo
>=
1
)
{
*
rxbuf8
++
=
readb
(
spi_rx_reg
);
rxsize
-=
1
;
}
if
(
txfifo
<
60
&&
txsize
>=
1
)
{
writeb
(
*
txbuf8
++
,
spi_tx_reg
);
txsize
-=
1
;
}
}
/* Restore CPSR */
asm
volatile
(
"msr cpsr_c, %0"
::
"r"
(
cpsr
));
}
void
spi_batch_data_transfer
(
u8
*
buf
,
void
*
spi_ctl_reg
,
u32
spi_ctl_xch_bitmask
,
void
*
spi_fifo_reg
,
void
*
spi_tx_reg
,
void
*
spi_rx_reg
,
void
*
spi_bc_reg
,
void
*
spi_tc_reg
,
void
*
spi_bcc_reg
)
{
u8
wait_for_completion_cmd
[
2
];
u8
*
backup_buf
;
u32
bufsize
;
while
(
1
)
{
u32
code
=
(
buf
[
0
]
<<
8
)
|
buf
[
1
];
/* End of data */
if
(
code
==
0
)
return
;
if
(
code
==
0xFFFF
)
{
/* Wait for completion, part 1 */
backup_buf
=
buf
;
buf
=
wait_for_completion_cmd
;
wait_for_completion_cmd
[
0
]
=
0x05
;
bufsize
=
2
;
}
else
{
/* Normal buffer */
buf
+=
2
;
bufsize
=
code
;
}
spi_data_transfer
(
buf
,
bufsize
,
spi_ctl_reg
,
spi_ctl_xch_bitmask
,
spi_fifo_reg
,
spi_tx_reg
,
spi_rx_reg
,
spi_bc_reg
,
spi_tc_reg
,
spi_bcc_reg
);
buf
+=
bufsize
;
if
(
code
==
0xFFFF
)
{
/* Wait for completion, part 2 */
buf
=
backup_buf
;
if
(
wait_for_completion_cmd
[
1
]
&
1
)
{
/* Still busy */
continue
;
}
/* Advance to the next code */
buf
=
backup_buf
+
2
;
}
}
}
fel-remotefunc-spi-data-transfer.h
0 → 100644
View file @
6d598a0e
/* Automatically generated, do not edit! */
static
void
aw_fel_remotefunc_prepare_spi_batch_data_transfer
(
feldev_handle
*
dev
,
uint32_t
buf
,
uint32_t
spi_ctl_reg
,
uint32_t
spi_ctl_xch_bitmask
,
uint32_t
spi_fifo_reg
,
uint32_t
spi_tx_reg
,
uint32_t
spi_rx_reg
,
uint32_t
spi_bc_reg
,
uint32_t
spi_tc_reg
,
uint32_t
spi_bcc_reg
)
{
static
uint8_t
arm_code
[]
=
{
0xf0
,
0x0f
,
0x2d
,
0xe9
,
/* 0: push {r4, r5, r6, r7, r8, r9, sl, fp} */
0x18
,
0xd0
,
0x4d
,
0xe2
,
/* 4: sub sp, sp, #24 */
0x38
,
0x50
,
0x9d
,
0xe5
,
/* 8: ldr r5, [sp, #56] */
0x3c
,
0x60
,
0x9d
,
0xe5
,
/* c: ldr r6, [sp, #60] */
0x06
,
0x00
,
0x8d
,
0xe9
,
/* 10: stmib sp, {r1, r2} */
0x00
,
0xa0
,
0xd0
,
0xe5
,
/* 14: ldrb sl, [r0] */
0x01
,
0x20
,
0xd0
,
0xe5
,
/* 18: ldrb r2, [r0, #1] */
0x0a
,
0xa4
,
0x92
,
0xe1
,
/* 1c: orrs sl, r2, sl, lsl #8 */
0x6a
,
0x00
,
0x00
,
0x0a
,
/* 20: beq 1d0 <spi_batch_data_transfer+0x1d0> */
0xff
,
0x2f
,
0x0f
,
0xe3
,
/* 24: movw r2, #65535 */
0x02
,
0x00
,
0x5a
,
0xe1
,
/* 28: cmp sl, r2 */
0x18
,
0x80
,
0x8d
,
0x02
,
/* 2c: addeq r8, sp, #24 */
0x02
,
0x80
,
0x80
,
0x12
,
/* 30: addne r8, r0, #2 */
0x05
,
0xb0
,
0xa0
,
0x03
,
/* 34: moveq fp, #5 */
0x48
,
0xc0
,
0x9d
,
0xe5
,
/* 38: ldr ip, [sp, #72] */
0x08
,
0xb0
,
0x68
,
0x05
,
/* 3c: strbeq fp, [r8, #-8]! */
0x00
,
0x10
,
0x68
,
0xe2
,
/* 40: rsb r1, r8, #0 */
0x40
,
0x20
,
0x9d
,
0xe5
,
/* 44: ldr r2, [sp, #64] */
0x03
,
0x10
,
0x01
,
0xe2
,
/* 48: and r1, r1, #3 */
0x44
,
0xb0
,
0x9d
,
0xe5
,
/* 4c: ldr fp, [sp, #68] */
0x0a
,
0x70
,
0xa0
,
0x11
,
/* 50: movne r7, sl */
0x0c
,
0x00
,
0x8d
,
0x05
,
/* 54: streq r0, [sp, #12] */
0x3c
,
0x00
,
0x81
,
0xe2
,
/* 58: add r0, r1, #60 */
0x02
,
0x70
,
0xa0
,
0x03
,
/* 5c: moveq r7, #2 */
0x00
,
0x00
,
0x5c
,
0xe3
,
/* 60: cmp ip, #0 */
0x00
,
0x70
,
0x82
,
0xe5
,
/* 64: str r7, [r2] */
0x08
,
0x20
,
0xa0
,
0xe1
,
/* 68: mov r2, r8 */
0x00
,
0x70
,
0x8b
,
0xe5
,
/* 6c: str r7, [fp] */
0x00
,
0x70
,
0x8c
,
0x15
,
/* 70: strne r7, [ip] */
0x07
,
0x00
,
0x50
,
0xe1
,
/* 74: cmp r0, r7 */
0x07
,
0x00
,
0xa0
,
0x21
,
/* 78: movcs r0, r7 */
0x00
,
0x40
,
0x88
,
0xe0
,
/* 7c: add r4, r8, r0 */
0x01
,
0xc0
,
0xd2
,
0xe4
,
/* 80: ldrb ip, [r2], #1 */
0x04
,
0x00
,
0x52
,
0xe1
,
/* 84: cmp r2, r4 */
0x00
,
0xc0
,
0xc5
,
0xe5
,
/* 88: strb ip, [r5] */
0xfb
,
0xff
,
0xff
,
0x1a
,
/* 8c: bne 80 <spi_batch_data_transfer+0x80> */
0x07
,
0x00
,
0x60
,
0xe0
,
/* 90: rsb r0, r0, r7 */
0x00
,
0x90
,
0x0f
,
0xe1
,
/* 94: mrs r9, CPSR */
0xc0
,
0xc0
,
0x89
,
0xe3
,
/* 98: orr ip, r9, #192 */
0x0c
,
0xf0
,
0x21
,
0xe1
,
/* 9c: msr CPSR_c, ip */
0x04
,
0xc0
,
0x9d
,
0xe5
,
/* a0: ldr ip, [sp, #4] */
0x07
,
0x00
,
0x51
,
0xe1
,
/* a4: cmp r1, r7 */
0x07
,
0x10
,
0xa0
,
0x21
,
/* a8: movcs r1, r7 */
0x08
,
0xb0
,
0x9d
,
0xe5
,
/* ac: ldr fp, [sp, #8] */
0x00
,
0x40
,
0x9c
,
0xe5
,
/* b0: ldr r4, [ip] */
0x01
,
0xc0
,
0x88
,
0xe0
,
/* b4: add ip, r8, r1 */
0x00
,
0xc0
,
0x8d
,
0xe5
,
/* b8: str ip, [sp] */
0x08
,
0xc0
,
0xa0
,
0xe1
,
/* bc: mov ip, r8 */
0x0b
,
0x40
,
0x84
,
0xe1
,
/* c0: orr r4, r4, fp */
0x04
,
0xb0
,
0x9d
,
0xe5
,
/* c4: ldr fp, [sp, #4] */
0x00
,
0x40
,
0x8b
,
0xe5
,
/* c8: str r4, [fp] */
0x00
,
0xb0
,
0x9d
,
0xe5
,
/* cc: ldr fp, [sp] */
0x0b
,
0x00
,
0x5c
,
0xe1
,
/* d0: cmp ip, fp */
0x06
,
0x00
,
0x00
,
0x0a
,
/* d4: beq f4 <spi_batch_data_transfer+0xf4> */
0x00
,
0x40
,
0x93
,
0xe5
,
/* d8: ldr r4, [r3] */
0x7f
,
0x00
,
0x14
,
0xe3
,
/* dc: tst r4, #127 */
0xfc
,
0xff
,
0xff
,
0x0a
,
/* e0: beq d8 <spi_batch_data_transfer+0xd8> */
0x00
,
0x40
,
0xd6
,
0xe5
,
/* e4: ldrb r4, [r6] */
0x01
,
0x40
,
0xcc
,
0xe4
,
/* e8: strb r4, [ip], #1 */
0x0b
,
0x00
,
0x5c
,
0xe1
,
/* ec: cmp ip, fp */
0xf8
,
0xff
,
0xff
,
0x1a
,
/* f0: bne d8 <spi_batch_data_transfer+0xd8> */
0x07
,
0x10
,
0x61
,
0xe0
,
/* f4: rsb r1, r1, r7 */
0x03
,
0x00
,
0x51
,
0xe3
,
/* f8: cmp r1, #3 */
0x12
,
0x00
,
0x00
,
0x9a
,
/* fc: bls 14c <spi_batch_data_transfer+0x14c> */
0x00
,
0x40
,
0x93
,
0xe5
,
/* 100: ldr r4, [r3] */
0x7f
,
0xb0
,
0x04
,
0xe2
,
/* 104: and fp, r4, #127 */
0x54
,
0x48
,
0xe6
,
0xe7
,
/* 108: ubfx r4, r4, #16, #7 */
0x03
,
0x00
,
0x5b
,
0xe3
,
/* 10c: cmp fp, #3 */
0x04
,
0x10
,
0x41
,
0xc2
,
/* 110: subgt r1, r1, #4 */
0x00
,
0xb0
,
0x96
,
0xc5
,
/* 114: ldrgt fp, [r6] */
0x04
,
0xb0
,
0x8c
,
0xc4
,
/* 118: strgt fp, [ip], #4 */
0x03
,
0x00
,
0x50
,
0xe3
,
/* 11c: cmp r0, #3 */
0x00
,
0xb0
,
0xa0
,
0x93
,
/* 120: movls fp, #0 */
0x01
,
0xb0
,
0xa0
,
0x83
,
/* 124: movhi fp, #1 */
0x3b
,
0x00
,
0x54
,
0xe3
,
/* 128: cmp r4, #59 */
0x00
,
0xb0
,
0xa0
,
0xc3
,
/* 12c: movgt fp, #0 */
0x00
,
0x00
,
0x5b
,
0xe3
,
/* 130: cmp fp, #0 */
0xef
,
0xff
,
0xff
,
0x0a
,
/* 134: beq f8 <spi_batch_data_transfer+0xf8> */
0x04
,
0x40
,
0x92
,
0xe4
,
/* 138: ldr r4, [r2], #4 */
0x03
,
0x00
,
0x51
,
0xe3
,
/* 13c: cmp r1, #3 */
0x04
,
0x00
,
0x40
,
0xe2
,
/* 140: sub r0, r0, #4 */
0x00
,
0x40
,
0x85
,
0xe5
,
/* 144: str r4, [r5] */
0xec
,
0xff
,
0xff
,
0x8a
,
/* 148: bhi 100 <spi_batch_data_transfer+0x100> */
0x00
,
0x00
,
0x51
,
0xe3
,
/* 14c: cmp r1, #0 */
0x10
,
0x00
,
0x00
,
0x0a
,
/* 150: beq 198 <spi_batch_data_transfer+0x198> */
0x00
,
0x40
,
0x93
,
0xe5
,
/* 154: ldr r4, [r3] */
0x7f
,
0x00
,
0x14
,
0xe3
,
/* 158: tst r4, #127 */
0x54
,
0x48
,
0xe6
,
0xe7
,
/* 15c: ubfx r4, r4, #16, #7 */
0x01
,
0x10
,
0x41
,
0x12
,
/* 160: subne r1, r1, #1 */
0x00
,
0xb0
,
0xd6
,
0x15
,
/* 164: ldrbne fp, [r6] */
0x01
,
0xb0
,
0xcc
,
0x14
,
/* 168: strbne fp, [ip], #1 */
0x00
,
0xb0
,
0x90
,
0xe2
,
/* 16c: adds fp, r0, #0 */
0x01
,
0xb0
,
0xa0
,
0x13
,
/* 170: movne fp, #1 */
0x3b
,
0x00
,
0x54
,
0xe3
,
/* 174: cmp r4, #59 */
0x00
,
0xb0
,
0xa0
,
0xc3
,
/* 178: movgt fp, #0 */
0x00
,
0x00
,
0x5b
,
0xe3
,
/* 17c: cmp fp, #0 */
0xf1
,
0xff
,
0xff
,
0x0a
,
/* 180: beq 14c <spi_batch_data_transfer+0x14c> */
0x01
,
0x40
,
0xd2
,
0xe4
,
/* 184: ldrb r4, [r2], #1 */
0x00
,
0x00
,
0x51
,
0xe3
,
/* 188: cmp r1, #0 */
0x01
,
0x00
,
0x40
,
0xe2
,
/* 18c: sub r0, r0, #1 */
0x00
,
0x40
,
0xc5
,
0xe5
,
/* 190: strb r4, [r5] */
0xee
,
0xff
,
0xff
,
0x1a
,
/* 194: bne 154 <spi_batch_data_transfer+0x154> */
0x09
,
0xf0
,
0x21
,
0xe1
,
/* 198: msr CPSR_c, r9 */
0xff
,
0xcf
,
0x0f
,
0xe3
,
/* 19c: movw ip, #65535 */
0x0c
,
0x00
,
0x5a
,
0xe1
,
/* 1a0: cmp sl, ip */
0x07
,
0x00
,
0x88
,
0x10
,
/* 1a4: addne r0, r8, r7 */
0x99
,
0xff
,
0xff
,
0x1a
,
/* 1a8: bne 14 <spi_batch_data_transfer+0x14> */
0x11
,
0x20
,
0xdd
,
0xe5
,
/* 1ac: ldrb r2, [sp, #17] */
0x01
,
0x00
,
0x12
,
0xe3
,
/* 1b0: tst r2, #1 */
0x08
,
0x00
,
0x00
,
0x1a
,
/* 1b4: bne 1dc <spi_batch_data_transfer+0x1dc> */
0x0c
,
0xb0
,
0x9d
,
0xe5
,
/* 1b8: ldr fp, [sp, #12] */
0x02
,
0x00
,
0x8b
,
0xe2
,
/* 1bc: add r0, fp, #2 */
0x00
,
0xa0
,
0xd0
,
0xe5
,
/* 1c0: ldrb sl, [r0] */
0x01
,
0x20
,
0xd0
,
0xe5
,
/* 1c4: ldrb r2, [r0, #1] */
0x0a
,
0xa4
,
0x92
,
0xe1
,
/* 1c8: orrs sl, r2, sl, lsl #8 */
0x94
,
0xff
,
0xff
,
0x1a
,
/* 1cc: bne 24 <spi_batch_data_transfer+0x24> */
0x18
,
0xd0
,
0x8d
,
0xe2
,
/* 1d0: add sp, sp, #24 */
0xf0
,
0x0f
,
0xbd
,
0xe8
,
/* 1d4: pop {r4, r5, r6, r7, r8, r9, sl, fp} */
0x1e
,
0xff
,
0x2f
,
0xe1
,
/* 1d8: bx lr */
0x0c
,
0x00
,
0x9d
,
0xe5
,
/* 1dc: ldr r0, [sp, #12] */
0x8b
,
0xff
,
0xff
,
0xea
,
/* 1e0: b 14 <spi_batch_data_transfer+0x14> */
};
uint32_t
args
[]
=
{
buf
,
spi_ctl_reg
,
spi_ctl_xch_bitmask
,
spi_fifo_reg
,
spi_tx_reg
,
spi_rx_reg
,
spi_bc_reg
,
spi_tc_reg
,
spi_bcc_reg
};
aw_fel_remotefunc_prepare
(
dev
,
56
,
arm_code
,
sizeof
(
arm_code
),
9
,
args
);
}
fel-spiflash.c
0 → 100644
View file @
6d598a0e
/*
* (C) Copyright 2016 Siarhei Siamashka <siarhei.siamashka@gmail.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "fel_lib.h"
#include "progress.h"
#include "fel-remotefunc-spi-data-transfer.h"
/*****************************************************************************/
typedef
struct
{
uint32_t
id
;
uint8_t
write_enable_cmd
;
uint8_t
large_erase_cmd
;
uint32_t
large_erase_size
;
uint8_t
small_erase_cmd
;
uint32_t
small_erase_size
;
uint8_t
program_cmd
;
uint32_t
program_size
;
char
*
text_description
;
}
spi_flash_info_t
;
spi_flash_info_t
spi_flash_info
[]
=
{
{
.
id
=
0xEF40
,
.
write_enable_cmd
=
0x6
,
.
large_erase_cmd
=
0xD8
,
.
large_erase_size
=
64
*
1024
,
.
small_erase_cmd
=
0x20
,
.
small_erase_size
=
4
*
1024
,
.
program_cmd
=
0x02
,
.
program_size
=
256
,
.
text_description
=
"Winbond W25Qxx"
},
{
.
id
=
0xC220
,
.
write_enable_cmd
=
0x6
,
.
large_erase_cmd
=
0xD8
,
.
large_erase_size
=
64
*
1024
,
.
small_erase_cmd
=
0x20
,
.
small_erase_size
=
4
*
1024
,
.
program_cmd
=
0x02
,
.
program_size
=
256
,
.
text_description
=
"Macronix MX25Lxxxx"
},
};
spi_flash_info_t
default_spi_flash_info
=
{
.
id
=
0x0000
,
.
write_enable_cmd
=
0x6
,
.
large_erase_cmd
=
0xD8
,
.
large_erase_size
=
64
*
1024
,
.
small_erase_cmd
=
0x20
,
.
small_erase_size
=
4
*
1024
,
.
program_cmd
=
0x02
,
.
program_size
=
256
,
.
text_description
=
"Unknown"
,
};
/*****************************************************************************/
uint32_t
fel_readl
(
feldev_handle
*
dev
,
uint32_t
addr
);
void
fel_writel
(
feldev_handle
*
dev
,
uint32_t
addr
,
uint32_t
val
);
#define readl(addr) fel_readl(dev, (addr))
#define writel(val, addr) fel_writel(dev, (addr), (val))
#define PA (0)
#define PB (1)
#define PC (2)
#define CCM_SPI0_CLK (0x01C20000 + 0xA0)
#define CCM_AHB_GATING0 (0x01C20000 + 0x60)
#define CCM_AHB_GATE_SPI0 (1 << 20)
#define SUN6I_BUS_SOFT_RST_REG0 (0x01C20000 + 0x2C0)
#define SUN6I_SPI0_RST (1 << 20)
#define SUNXI_GPC_SPI0 (3)
#define SUN50I_GPC_SPI0 (4)
#define SUN4I_CTL_ENABLE (1 << 0)
#define SUN4I_CTL_MASTER (1 << 1)
#define SUN4I_CTL_TF_RST (1 << 8)
#define SUN4I_CTL_RF_RST (1 << 9)
#define SUN4I_CTL_XCH (1 << 10)
#define SUN6I_TCR_XCH (1 << 31)
#define SUN4I_SPI0_CCTL (0x01C05000 + 0x1C)
#define SUN4I_SPI0_CTL (0x01C05000 + 0x08)
#define SUN4I_SPI0_RX (0x01C05000 + 0x00)
#define SUN4I_SPI0_TX (0x01C05000 + 0x04)
#define SUN4I_SPI0_FIFO_STA (0x01C05000 + 0x28)
#define SUN4I_SPI0_BC (0x01C05000 + 0x20)
#define SUN4I_SPI0_TC (0x01C05000 + 0x24)
#define SUN6I_SPI0_CCTL (0x01C68000 + 0x24)
#define SUN6I_SPI0_GCR (0x01C68000 + 0x04)
#define SUN6I_SPI0_TCR (0x01C68000 + 0x08)
#define SUN6I_SPI0_FIFO_STA (0x01C68000 + 0x1C)
#define SUN6I_SPI0_MBC (0x01C68000 + 0x30)
#define SUN6I_SPI0_MTC (0x01C68000 + 0x34)
#define SUN6I_SPI0_BCC (0x01C68000 + 0x38)
#define SUN6I_SPI0_TXD (0x01C68000 + 0x200)
#define SUN6I_SPI0_RXD (0x01C68000 + 0x300)
#define CCM_SPI0_CLK_DIV_BY_2 (0x1000)
#define CCM_SPI0_CLK_DIV_BY_4 (0x1001)
#define CCM_SPI0_CLK_DIV_BY_6 (0x1002)
/*
* Configure pin function on a GPIO port
*/
static
void
gpio_set_cfgpin
(
feldev_handle
*
dev
,
int
port_num
,
int
pin_num
,
int
val
)
{
uint32_t
port_base
=
0x01C20800
+
port_num
*
0x24
;
uint32_t
cfg_reg
=
port_base
+
4
*
(
pin_num
/
8
);
uint32_t
pin_idx
=
pin_num
%
8
;
uint32_t
x
=
readl
(
cfg_reg
);
x
&=
~
(
0x7
<<
(
pin_idx
*
4
));
x
|=
val
<<
(
pin_idx
*
4
);
writel
(
x
,
cfg_reg
);
}
static
bool
spi_is_sun6i
(
feldev_handle
*
dev
)
{
soc_info_t
*
soc_info
=
dev
->
soc_info
;
switch
(
soc_info
->
soc_id
)
{
case
0x1623
:
/* A10 */
case
0x1625
:
/* A13 */
case
0x1651
:
/* A20 */
return
false
;
default:
return
true
;
}
}
/*
* Init the SPI0 controller and setup pins muxing.
*/
static
bool
spi0_init
(
feldev_handle
*
dev
)
{
uint32_t
reg_val
;
soc_info_t
*
soc_info
=
dev
->
soc_info
;
if
(
!
soc_info
)
return
false
;
/* Setup SPI0 pins muxing */
switch
(
soc_info
->
soc_id
)
{
case
0x1625
:
/* Allwinner A13 */
case
0x1680
:
/* Allwinner H3 */
case
0x1718
:
/* Allwinner H5 */
gpio_set_cfgpin
(
dev
,
PC
,
0
,
SUNXI_GPC_SPI0
);
gpio_set_cfgpin
(
dev
,
PC
,
1
,
SUNXI_GPC_SPI0
);
gpio_set_cfgpin
(
dev
,
PC
,
2
,
SUNXI_GPC_SPI0
);
gpio_set_cfgpin
(
dev
,
PC
,
3
,
SUNXI_GPC_SPI0
);
break
;
case
0x1689
:
/* Allwinner A64 */
gpio_set_cfgpin
(
dev
,
PC
,
0
,
SUN50I_GPC_SPI0
);
gpio_set_cfgpin
(
dev
,
PC
,
1
,
SUN50I_GPC_SPI0
);
gpio_set_cfgpin
(
dev
,
PC
,
2
,
SUN50I_GPC_SPI0
);
gpio_set_cfgpin
(
dev
,
PC
,
3
,
SUN50I_GPC_SPI0
);
break
;
default:
/* Unknown/Unsupported SoC */
return
false
;
}
reg_val
=
readl
(
CCM_AHB_GATING0
);
reg_val
|=
CCM_AHB_GATE_SPI0
;
writel
(
reg_val
,
CCM_AHB_GATING0
);
/* 24MHz from OSC24M */
writel
((
1
<<
31
),
CCM_SPI0_CLK
);
/* divide by 4 */
writel
(
CCM_SPI0_CLK_DIV_BY_4
,
spi_is_sun6i
(
dev
)
?
SUN6I_SPI0_CCTL
:
SUN4I_SPI0_CCTL
);
if
(
spi_is_sun6i
(
dev
))
{
/* Deassert SPI0 reset */
reg_val
=
readl
(
SUN6I_BUS_SOFT_RST_REG0
);
reg_val
|=
SUN6I_SPI0_RST
;
writel
(
reg_val
,
SUN6I_BUS_SOFT_RST_REG0
);
/* Enable SPI in the master mode and do a soft reset */
reg_val
=
readl
(
SUN6I_SPI0_GCR
);
reg_val
|=
(
1
<<
31
)
|
3
;
writel
(
reg_val
,
SUN6I_SPI0_GCR
);
/* Wait for completion */
while
(
readl
(
SUN6I_SPI0_GCR
)
&
(
1
<<
31
))
{}
}
else
{
reg_val
=
readl
(
SUN4I_SPI0_CTL
);
reg_val
|=
SUN4I_CTL_MASTER
;
reg_val
|=
SUN4I_CTL_ENABLE
|
SUN4I_CTL_TF_RST
|
SUN4I_CTL_RF_RST
;
writel
(
reg_val
,
SUN4I_SPI0_CTL
);
}
return
true
;
}
/*
* Backup/restore the initial portion of the SRAM, which can be used as
* a temporary data buffer.
*/
static
void
*
backup_sram
(
feldev_handle
*
dev
)
{
soc_info_t
*
soc_info
=
dev
->
soc_info
;
size_t
bufsize
=
soc_info
->
scratch_addr
-
soc_info
->
spl_addr
;
void
*
buf
=
malloc
(
bufsize
);
aw_fel_read
(
dev
,
soc_info
->
spl_addr
,
buf
,
bufsize
);
return
buf
;
}
static
void
restore_sram
(
feldev_handle
*
dev
,
void
*
buf
)
{
soc_info_t
*
soc_info
=
dev
->
soc_info
;
size_t
bufsize
=
soc_info
->
scratch_addr
-
soc_info
->
spl_addr
;
aw_fel_write
(
dev
,
buf
,
soc_info
->
spl_addr
,
bufsize
);
free
(
buf
);
}
static
void
prepare_spi_batch_data_transfer
(
feldev_handle
*
dev
,
uint32_t
buf
)
{
if
(
spi_is_sun6i
(
dev
))
{
aw_fel_remotefunc_prepare_spi_batch_data_transfer
(
dev
,
buf
,
SUN6I_SPI0_TCR
,
SUN6I_TCR_XCH
,
SUN6I_SPI0_FIFO_STA
,
SUN6I_SPI0_TXD
,
SUN6I_SPI0_RXD
,
SUN6I_SPI0_MBC
,
SUN6I_SPI0_MTC
,
SUN6I_SPI0_BCC
);
}
else
{
aw_fel_remotefunc_prepare_spi_batch_data_transfer
(
dev
,
buf
,
SUN4I_SPI0_CTL
,
SUN4I_CTL_XCH
,
SUN4I_SPI0_FIFO_STA
,
SUN4I_SPI0_TX
,
SUN4I_SPI0_RX
,
SUN4I_SPI0_BC
,
SUN4I_SPI0_TC
,
0
);
}
}
/*
* Read data from the SPI flash. Use the first 4KiB of SRAM as the data buffer.
*/
void
aw_fel_spiflash_read
(
feldev_handle
*
dev
,
uint32_t
offset
,
void
*
buf
,
size_t
len
,
progress_cb_t
progress
)
{
soc_info_t
*
soc_info
=
dev
->
soc_info
;
void
*
backup
=
backup_sram
(
dev
);
uint8_t
*
buf8
=
(
uint8_t
*
)
buf
;
size_t
max_chunk_size
=
soc_info
->
scratch_addr
-
soc_info
->
spl_addr
;
if
(
max_chunk_size
>
0x1000
)
max_chunk_size
=
0x1000
;
uint8_t
*
cmdbuf
=
malloc
(
max_chunk_size
);
memset
(
cmdbuf
,
0
,
max_chunk_size
);
aw_fel_write
(
dev
,
cmdbuf
,
soc_info
->
spl_addr
,
max_chunk_size
);
if
(
!
spi0_init
(
dev
))
return
;
prepare_spi_batch_data_transfer
(
dev
,
soc_info
->
spl_addr
);
progress_start
(
progress
,
len
);
while
(
len
>
0
)
{
size_t
chunk_size
=
len
;
if
(
chunk_size
>
max_chunk_size
-
8
)
chunk_size
=
max_chunk_size
-
8
;
memset
(
cmdbuf
,
0
,
max_chunk_size
);
cmdbuf
[
0
]
=
(
chunk_size
+
4
)
>>
8
;
cmdbuf
[
1
]
=
(
chunk_size
+
4
);
cmdbuf
[
2
]
=
3
;
cmdbuf
[
3
]
=
offset
>>
16
;
cmdbuf
[
4
]
=
offset
>>
8
;
cmdbuf
[
5
]
=
offset
;
if
(
chunk_size
==
max_chunk_size
-
8
)
aw_fel_write
(
dev
,
cmdbuf
,
soc_info
->
spl_addr
,
6
);
else
aw_fel_write
(
dev
,
cmdbuf
,
soc_info
->
spl_addr
,
chunk_size
+
8
);
aw_fel_remotefunc_execute
(
dev
,
NULL
);
aw_fel_read
(
dev
,
soc_info
->
spl_addr
+
6
,
buf8
,
chunk_size
);
len
-=
chunk_size
;
offset
+=
chunk_size
;
buf8
+=
chunk_size
;
progress_update
(
chunk_size
);
}
free
(
cmdbuf
);
restore_sram
(
dev
,
backup
);
}
/*
* Write data to the SPI flash. Use the first 4KiB of SRAM as the data buffer.
*/
#define CMD_WRITE_ENABLE 0x06
void
aw_fel_spiflash_write_helper
(
feldev_handle
*
dev
,
uint32_t
offset
,
void
*
buf
,
size_t
len
,
size_t
erase_size
,
uint8_t
erase_cmd
,
size_t
program_size
,
uint8_t
program_cmd
)
{
soc_info_t
*
soc_info
=
dev
->
soc_info
;
uint8_t
*
buf8
=
(
uint8_t
*
)
buf
;
size_t
max_chunk_size
=
soc_info
->
scratch_addr
-
soc_info
->
spl_addr
;
size_t
cmd_idx
;
if
(
max_chunk_size
>
0x1000
)
max_chunk_size
=
0x1000
;
uint8_t
*
cmdbuf
=
malloc
(
max_chunk_size
);
cmd_idx
=
0
;
prepare_spi_batch_data_transfer
(
dev
,
soc_info
->
spl_addr
);
while
(
len
>
0
)
{
while
(
len
>
0
&&
max_chunk_size
-
cmd_idx
>
program_size
+
64
)
{
if
(
offset
%
erase_size
==
0
)
{
/* Emit write enable command */
cmdbuf
[
cmd_idx
++
]
=
0
;
cmdbuf
[
cmd_idx
++
]
=
1
;
cmdbuf
[
cmd_idx
++
]
=
CMD_WRITE_ENABLE
;
/* Emit erase command */
cmdbuf
[
cmd_idx
++
]
=
0
;
cmdbuf
[
cmd_idx
++
]
=
4
;
cmdbuf
[
cmd_idx
++
]
=
erase_cmd
;
cmdbuf
[
cmd_idx
++
]
=
offset
>>
16
;
cmdbuf
[
cmd_idx
++
]
=
offset
>>
8
;
cmdbuf
[
cmd_idx
++
]
=
offset
;
/* Emit wait for completion */
cmdbuf
[
cmd_idx
++
]
=
0xFF
;
cmdbuf
[
cmd_idx
++
]
=
0xFF
;
}
/* Emit write enable command */
cmdbuf
[
cmd_idx
++
]
=
0
;
cmdbuf
[
cmd_idx
++
]
=
1
;
cmdbuf
[
cmd_idx
++
]
=
CMD_WRITE_ENABLE
;
/* Emit page program command */
size_t
write_count
=
program_size
;
if
(
write_count
>
len
)
write_count
=
len
;
cmdbuf
[
cmd_idx
++
]
=
(
4
+
write_count
)
>>
8
;
cmdbuf
[
cmd_idx
++
]
=
4
+
write_count
;
cmdbuf
[
cmd_idx
++
]
=
program_cmd
;
cmdbuf
[
cmd_idx
++
]
=
offset
>>
16
;
cmdbuf
[
cmd_idx
++
]
=
offset
>>
8
;
cmdbuf
[
cmd_idx
++
]
=
offset
;
memcpy
(
cmdbuf
+
cmd_idx
,
buf8
,
write_count
);
cmd_idx
+=
write_count
;
buf8
+=
write_count
;
len
-=
write_count
;
offset
+=
write_count
;
/* Emit wait for completion */
cmdbuf
[
cmd_idx
++
]
=
0xFF
;
cmdbuf
[
cmd_idx
++
]
=
0xFF
;
}
/* Emit the end marker */
cmdbuf
[
cmd_idx
++
]
=
0
;
cmdbuf
[
cmd_idx
++
]
=
0
;
/* Flush */
aw_fel_write
(
dev
,
cmdbuf
,
soc_info
->
spl_addr
,
cmd_idx
);
aw_fel_remotefunc_execute
(
dev
,
NULL
);
cmd_idx
=
0
;
}
free
(
cmdbuf
);
}
void
aw_fel_spiflash_write
(
feldev_handle
*
dev
,
uint32_t
offset
,
void
*
buf
,
size_t
len
,
progress_cb_t
progress
)
{
void
*
backup
=
backup_sram
(
dev
);
uint8_t
*
buf8
=
(
uint8_t
*
)
buf
;
spi_flash_info_t
*
flash_info
=
&
default_spi_flash_info
;
/* FIXME */
if
((
offset
%
flash_info
->
small_erase_size
)
!=
0
)
{
fprintf
(
stderr
,
"aw_fel_spiflash_write: 'addr' must be %d bytes aligned
\n
"
,
flash_info
->
small_erase_size
);
exit
(
1
);
}
if
(
!
spi0_init
(
dev
))
return
;
progress_start
(
progress
,
len
);
while
(
len
>
0
)
{
size_t
write_count
;
if
((
offset
%
flash_info
->
large_erase_size
)
!=
0
||
len
<
flash_info
->
large_erase_size
)
{
write_count
=
flash_info
->
small_erase_size
;
if
(
write_count
>
len
)
write_count
=
len
;
aw_fel_spiflash_write_helper
(
dev
,
offset
,
buf8
,
write_count
,
flash_info
->
small_erase_size
,
flash_info
->
small_erase_cmd
,
flash_info
->
program_size
,
flash_info
->
program_cmd
);
}
else
{
write_count
=
flash_info
->
large_erase_size
;
if
(
write_count
>
len
)
write_count
=
len
;
aw_fel_spiflash_write_helper
(
dev
,
offset
,
buf8
,
write_count
,
flash_info
->
large_erase_size
,
flash_info
->
large_erase_cmd
,
flash_info
->
program_size
,
flash_info
->
program_cmd
);
}
len
-=
write_count
;
offset
+=
write_count
;
buf8
+=
write_count
;
progress_update
(
write_count
);
}
restore_sram
(
dev
,
backup
);
}
/*
* Use the read JEDEC ID (9Fh) command.
*/
void
aw_fel_spiflash_info
(
feldev_handle
*
dev
)
{
soc_info_t
*
soc_info
=
dev
->
soc_info
;
const
char
*
manufacturer
;
unsigned
char
buf
[]
=
{
0
,
4
,
0x9F
,
0
,
0
,
0
,
0x0
,
0x0
};
void
*
backup
=
backup_sram
(
dev
);
if
(
!
spi0_init
(
dev
))
return
;
aw_fel_write
(
dev
,
buf
,
soc_info
->
spl_addr
,
sizeof
(
buf
));
prepare_spi_batch_data_transfer
(
dev
,
soc_info
->
spl_addr
);
aw_fel_remotefunc_execute
(
dev
,
NULL
);
aw_fel_read
(
dev
,
soc_info
->
spl_addr
,
buf
,
sizeof
(
buf
));
restore_sram
(
dev
,
backup
);
/* Assume that the MISO pin is either pulled up or down */
if
(
buf
[
5
]
==
0x00
||
buf
[
5
]
==
0xFF
)
{
printf
(
"No SPI flash detected.
\n
"
);
return
;
}
switch
(
buf
[
3
])
{
case
0xEF
:
manufacturer
=
"Winbond"
;
break
;
case
0xC2
:
manufacturer
=
"Macronix"
;
break
;
default:
manufacturer
=
"Unknown"
;
break
;
}
printf
(
"Manufacturer: %s (%02Xh), model: %02Xh, size: %d bytes.
\n
"
,
manufacturer
,
buf
[
3
],
buf
[
4
],
(
1
<<
buf
[
5
]));
}
/*
* Show a help message about the available "spiflash-*" commands.
*/
void
aw_fel_spiflash_help
(
void
)
{
printf
(
" spiflash-info Retrieves basic information
\n
"
" spiflash-read addr length file Write SPI flash contents into file
\n
"
" spiflash-write addr file Store file contents into SPI flash
\n
"
);
}
fel-spiflash.h
0 → 100644
View file @
6d598a0e
/*
* (C) Copyright 2016 Siarhei Siamashka <siarhei.siamashka@gmail.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _SUNXI_TOOLS_FEL_SPIFLASH_H
#define _SUNXI_TOOLS_FEL_SPIFLASH_H
#include "fel_lib.h"
#include "progress.h"
void
aw_fel_spiflash_read
(
feldev_handle
*
dev
,
uint32_t
offset
,
void
*
buf
,
size_t
len
,
progress_cb_t
progress
);
void
aw_fel_spiflash_write
(
feldev_handle
*
dev
,
uint32_t
offset
,
void
*
buf
,
size_t
len
,
progress_cb_t
progress
);
void
aw_fel_spiflash_info
(
feldev_handle
*
dev
);
void
aw_fel_spiflash_help
(
void
);
void
aw_fel_spi0_init
(
feldev_handle
*
dev
);
#endif
fel.c
View file @
6d598a0e
...
...
@@ -18,6 +18,7 @@
#include "common.h"
#include "portable_endian.h"
#include "fel_lib.h"
#include "fel-spiflash.h"
#include <assert.h>
#include <ctype.h>
...
...
@@ -243,6 +244,111 @@ void aw_fel_fill(feldev_handle *dev, uint32_t offset, size_t size, unsigned char
}
}
/*
* Upload a function (implemented in native ARM code) to the device and
* prepare for executing it. Use a subset of 32-bit ARM AAPCS calling
* conventions: all arguments are integer 32-bit values, and an optional
* return value is a 32-bit integer too. The function code needs to be
* compiled in the ARM mode (Thumb2 is not supported), it also must be
* a position independent leaf function (have no calls to anything else)
* and have no references to any global variables.
*
* 'stack_size' - the required stack size for the function (can be
* calculated using the '-fstack-usage' GCC option)
* 'arm_code' - a pointer to the memory buffer with the function code
* 'arm_code_size' - the size of the function code
* 'num_args' - the number of 32-bit function arguments
* 'args' - an array with the function argument values
*
* Note: once uploaded, the function can be executed multiple times with
* exactly the same arguments. If some internal state needs to be
* updated between function calls, then it's best to pass a pointer
* to some state structure located elsewhere in SRAM as one of the
* function arguments.
*/
bool
aw_fel_remotefunc_prepare
(
feldev_handle
*
dev
,
size_t
stack_size
,
void
*
arm_code
,
size_t
arm_code_size
,
size_t
num_args
,
uint32_t
*
args
)
{
size_t
idx
,
i
;
size_t
tmp_buf_size
;
soc_info_t
*
soc_info
=
dev
->
soc_info
;
uint32_t
*
tmp_buf
;
uint32_t
new_sp
,
num_args_on_stack
=
(
num_args
<=
4
?
0
:
num_args
-
4
);
uint32_t
entry_code
[]
=
{
htole32
(
0xe58fe040
),
/* 0: str lr, [pc, #64] */
htole32
(
0xe58fd040
),
/* 4: str sp, [pc, #64] */
htole32
(
0xe59fd040
),
/* 8: ldr sp, [pc, #64] */
htole32
(
0xe28fc040
),
/* c: add ip, pc, #64 */
htole32
(
0xe1a0200d
),
/* 10: mov r2, sp */
htole32
(
0xe49c0004
),
/* 14: ldr r0, [ip], #4 */
htole32
(
0xe3500000
),
/* 18: cmp r0, #0 */
htole32
(
0x0a000003
),
/* 1c: beq 30 <entry+0x30> */
htole32
(
0xe49c1004
),
/* 20: ldr r1, [ip], #4 */
htole32
(
0xe4821004
),
/* 24: str r1, [r2], #4 */
htole32
(
0xe2500001
),
/* 28: subs r0, r0, #1 */
htole32
(
0x1afffffb
),
/* 2c: bne 20 <entry+0x20> */
htole32
(
0xe8bc000f
),
/* 30: ldm ip!, {r0, r1, r2, r3} */
htole32
(
0xe12fff3c
),
/* 34: blx ip */
htole32
(
0xe59fe008
),
/* 38: ldr lr, [pc, #8] */
htole32
(
0xe59fd008
),
/* 3c: ldr sp, [pc, #8] */
htole32
(
0xe58f0000
),
/* 40: str r0, [pc] */
htole32
(
0xe12fff1e
),
/* 44: bx lr */
htole32
(
0x00000000
),
/* 48: .word 0x00000000 */
htole32
(
0x00000000
),
/* 4c: .word 0x00000000 */
};
if
(
!
soc_info
)
return
false
;
/* Calculate the stack location */
new_sp
=
soc_info
->
scratch_addr
+
sizeof
(
entry_code
)
+
2
*
4
+
num_args_on_stack
*
4
+
4
*
4
+
arm_code_size
+
stack_size
;
new_sp
=
(
new_sp
+
7
)
&
~
7
;
tmp_buf_size
=
new_sp
-
soc_info
->
scratch_addr
;
tmp_buf
=
calloc
(
tmp_buf_size
,
1
);
memcpy
(
tmp_buf
,
entry_code
,
sizeof
(
entry_code
));
idx
=
sizeof
(
entry_code
)
/
4
;
tmp_buf
[
idx
++
]
=
htole32
(
new_sp
);
tmp_buf
[
idx
++
]
=
htole32
(
num_args_on_stack
);
for
(
i
=
num_args
-
num_args_on_stack
;
i
<
num_args
;
i
++
)
tmp_buf
[
idx
++
]
=
htole32
(
args
[
i
]);
for
(
i
=
0
;
i
<
4
;
i
++
)
tmp_buf
[
idx
++
]
=
(
i
<
num_args
?
htole32
(
args
[
i
])
:
0
);
memcpy
(
tmp_buf
+
idx
,
arm_code
,
arm_code_size
);
aw_fel_write
(
dev
,
tmp_buf
,
soc_info
->
scratch_addr
,
tmp_buf_size
);
free
(
tmp_buf
);
return
true
;
}
/*
* Execute the previously uploaded function. The 'result' pointer allows to
* retrieve the return value.
*/
bool
aw_fel_remotefunc_execute
(
feldev_handle
*
dev
,
uint32_t
*
result
)
{
soc_info_t
*
soc_info
=
dev
->
soc_info
;
if
(
!
soc_info
)
return
false
;
aw_fel_execute
(
dev
,
soc_info
->
scratch_addr
);
if
(
result
)
{
aw_fel_read
(
dev
,
soc_info
->
scratch_addr
+
0x48
,
result
,
sizeof
(
uint32_t
));
*
result
=
le32toh
(
*
result
);
}
return
true
;
}
static
uint32_t
fel_to_spl_thunk
[]
=
{
#include "thunks/fel-to-spl-thunk.h"
};
...
...
@@ -1072,6 +1178,8 @@ void usage(const char *cmd) {
" clear address length Clear memory
\n
"
" fill address length value Fill memory
\n
"
,
cmd
);
printf
(
"
\n
"
);
aw_fel_spiflash_help
();
exit
(
0
);
}
...
...
@@ -1242,6 +1350,23 @@ int main(int argc, char **argv)
if
(
!
uboot_autostart
)
printf
(
"Warning:
\"
uboot
\"
command failed to detect image! Can't execute U-Boot.
\n
"
);
skip
=
2
;
}
else
if
(
strcmp
(
argv
[
1
],
"spiflash-info"
)
==
0
)
{
aw_fel_spiflash_info
(
handle
);
}
else
if
(
strcmp
(
argv
[
1
],
"spiflash-read"
)
==
0
&&
argc
>
4
)
{
size_t
size
=
strtoul
(
argv
[
3
],
NULL
,
0
);
void
*
buf
=
malloc
(
size
);
aw_fel_spiflash_read
(
handle
,
strtoul
(
argv
[
2
],
NULL
,
0
),
buf
,
size
,
pflag_active
?
progress_bar
:
NULL
);
save_file
(
argv
[
4
],
buf
,
size
);
free
(
buf
);
skip
=
4
;
}
else
if
(
strcmp
(
argv
[
1
],
"spiflash-write"
)
==
0
&&
argc
>
3
)
{
size_t
size
;
void
*
buf
=
load_file
(
argv
[
3
],
&
size
);
aw_fel_spiflash_write
(
handle
,
strtoul
(
argv
[
2
],
NULL
,
0
),
buf
,
size
,
pflag_active
?
progress_bar
:
NULL
);
free
(
buf
);
skip
=
3
;
}
else
{
pr_fatal
(
"Invalid command %s
\n
"
,
argv
[
1
]);
}
...
...
fel_lib.h
View file @
6d598a0e
...
...
@@ -81,4 +81,12 @@ void fel_clrsetbits_le32(feldev_handle *dev,
bool
fel_get_sid_root_key
(
feldev_handle
*
dev
,
uint32_t
*
result
,
bool
force_workaround
);
bool
aw_fel_remotefunc_prepare
(
feldev_handle
*
dev
,
size_t
stack_size
,
void
*
arm_code
,
size_t
arm_code_size
,
size_t
num_args
,
uint32_t
*
args
);
bool
aw_fel_remotefunc_execute
(
feldev_handle
*
dev
,
uint32_t
*
result
);
#endif
/* _SUNXI_TOOLS_FEL_LIB_H */
fexc.c
View file @
6d598a0e
...
...
@@ -310,6 +310,7 @@ show_usage:
switch
(
argc
-
optind
)
{
case
2
:
filename
[
1
]
=
argv
[
optind
+
1
];
/* out */
/* fall-through */
case
1
:
if
(
strcmp
(
argv
[
optind
],
"-"
)
!=
0
)
filename
[
0
]
=
argv
[
optind
];
/* in */
...
...
pio.c
View file @
6d598a0e
...
...
@@ -165,7 +165,7 @@ static void print(const char *buf)
static
const
char
*
argv0
;
static
void
usage
(
int
rc
)
static
__attribute__
((
noreturn
))
void
usage
(
int
rc
)
{
fputs
(
"sunxi-pio "
VERSION
"
\n\n
"
,
stderr
);
fprintf
(
stderr
,
"usage: %s -m|-i input [-o output] pin..
\n
"
,
argv0
);
...
...
@@ -179,7 +179,7 @@ static void usage(int rc )
fprintf
(
stderr
,
" Pxx*count Oscillate GPIO output (mmap mode only)
\n
"
);
fprintf
(
stderr
,
" Pxx?pull Configure GPIO input
\n
"
);
fprintf
(
stderr
,
" clean Clean input pins
\n
"
);
fprintf
(
stderr
,
"
\n
mode 0-7, 0=input, 1=ouput, 2-7 I/O function
\n
"
);
fprintf
(
stderr
,
"
\n
mode 0-7, 0=input, 1=ou
t
put, 2-7 I/O function
\n
"
);
fprintf
(
stderr
,
" pull 0=none, 1=up, 2=down
\n
"
);
fprintf
(
stderr
,
" drive 0-3, I/O drive level
\n
"
);
...
...
@@ -427,4 +427,6 @@ int main(int argc, char **argv)
exit
(
1
);
}
}
return
0
;
}
soc_info.c
View file @
6d598a0e
...
...
@@ -94,6 +94,22 @@ sram_swap_buffers a80_sram_swap_buffers[] = {
{
.
size
=
0
}
/* End of the table */
};
/*
* H6 has 32KiB of SRAM A at 0x20000 and a large SRAM C at 0x28000. SRAM A
* and SRAM C reside in the address space back-to-back without any gaps, thus
* representing a singe large contiguous area. Everything is the same as on
* A10/A13/A20, but just shifted by 0x20000.
*/
sram_swap_buffers
h6_sram_swap_buffers
[]
=
{
/* 0x21C00-0x21FFF (IRQ stack) */
{
.
buf1
=
0x21C00
,
.
buf2
=
0x2A400
,
.
size
=
0x0400
},
/* 0x25C00-0x26FFF (Stack) */
{
.
buf1
=
0x25C00
,
.
buf2
=
0x2A800
,
.
size
=
0x1400
},
/* 0x27C00-0x27FFF (Something important) */
{
.
buf1
=
0x27C00
,
.
buf2
=
0x2BC00
,
.
size
=
0x0400
},
{
.
size
=
0
}
/* End of the table */
};
soc_info_t
soc_info_table
[]
=
{
{
.
soc_id
=
0x1623
,
/* Allwinner A10 */
...
...
@@ -207,6 +223,18 @@ soc_info_t soc_info_table[] = {
.
swap_buffers
=
a10_a13_a20_sram_swap_buffers
,
.
sid_base
=
0x01C1B000
,
.
sid_offset
=
0x200
,
},{
.
soc_id
=
0x1728
,
/* Allwinner H6 */
.
name
=
"H6"
,
.
spl_addr
=
0x20000
,
.
scratch_addr
=
0x21000
,
.
thunk_addr
=
0x2A200
,
.
thunk_size
=
0x200
,
.
swap_buffers
=
h6_sram_swap_buffers
,
.
sid_base
=
0x03006000
,
.
sid_offset
=
0x200
,
.
rvbar_reg
=
0x09010040
,
/* Check L.NOP in the OpenRISC reset vector */
.
needs_smc_workaround_if_zero_word_at_addr
=
0x100004
,
},{
.
swap_buffers
=
NULL
/* End of the table */
}
...
...
uart0-helloworld-sdboot.c
View file @
6d598a0e
...
...
@@ -61,6 +61,11 @@ typedef unsigned int u32;
#define AW_CCM_BASE 0x01c20000
#define AW_SRAMCTRL_BASE 0x01c00000
#define H6_UART0_BASE 0x05000000
#define H6_PIO_BASE 0x0300B000
#define H6_CCM_BASE 0x03001000
#define H6_SRAMCTRL_BASE 0x03000000
/*****************************************************************************
* GPIO code, borrowed from U-Boot *
*****************************************************************************/
...
...
@@ -140,6 +145,7 @@ enum sunxi_gpio_number {
#define SUN8I_H3_GPA_UART0 (2)
#define SUN8I_V3S_GPB_UART0 (3)
#define SUN50I_H5_GPA_UART0 (2)
#define SUN50I_H6_GPH_UART0 (2)
#define SUN50I_A64_GPB_UART0 (4)
#define SUNXI_GPF_UART0 (4)
...
...
@@ -148,6 +154,8 @@ enum sunxi_gpio_number {
#define SUNXI_GPIO_PULL_UP (1)
#define SUNXI_GPIO_PULL_DOWN (2)
static
u32
pio_base
;
int
sunxi_gpio_set_cfgpin
(
u32
pin
,
u32
val
)
{
u32
cfg
;
...
...
@@ -155,7 +163,7 @@ int sunxi_gpio_set_cfgpin(u32 pin, u32 val)
u32
index
=
GPIO_CFG_INDEX
(
pin
);
u32
offset
=
GPIO_CFG_OFFSET
(
pin
);
struct
sunxi_gpio
*
pio
=
&
((
struct
sunxi_gpio_reg
*
)
SUNXI_PIO_BASE
)
->
gpio_bank
[
bank
];
&
((
struct
sunxi_gpio_reg
*
)
pio_base
)
->
gpio_bank
[
bank
];
cfg
=
readl
(
&
pio
->
cfg
[
0
]
+
index
);
cfg
&=
~
(
0xf
<<
offset
);
cfg
|=
val
<<
offset
;
...
...
@@ -170,7 +178,7 @@ int sunxi_gpio_set_pull(u32 pin, u32 val)
u32
index
=
GPIO_PULL_INDEX
(
pin
);
u32
offset
=
GPIO_PULL_OFFSET
(
pin
);
struct
sunxi_gpio
*
pio
=
&
((
struct
sunxi_gpio_reg
*
)
SUNXI_PIO_BASE
)
->
gpio_bank
[
bank
];
&
((
struct
sunxi_gpio_reg
*
)
pio_base
)
->
gpio_bank
[
bank
];
cfg
=
readl
(
&
pio
->
pull
[
0
]
+
index
);
cfg
&=
~
(
0x3
<<
offset
);
cfg
|=
val
<<
offset
;
...
...
@@ -184,7 +192,7 @@ int sunxi_gpio_output(u32 pin, u32 val)
u32
bank
=
GPIO_BANK
(
pin
);
u32
num
=
GPIO_NUM
(
pin
);
struct
sunxi_gpio
*
pio
=
&
((
struct
sunxi_gpio_reg
*
)
SUNXI_PIO_BASE
)
->
gpio_bank
[
bank
];
&
((
struct
sunxi_gpio_reg
*
)
pio_base
)
->
gpio_bank
[
bank
];
dat
=
readl
(
&
pio
->
dat
);
if
(
val
)
dat
|=
1
<<
num
;
...
...
@@ -200,7 +208,7 @@ int sunxi_gpio_input(u32 pin)
u32
bank
=
GPIO_BANK
(
pin
);
u32
num
=
GPIO_NUM
(
pin
);
struct
sunxi_gpio
*
pio
=
&
((
struct
sunxi_gpio_reg
*
)
SUNXI_PIO_BASE
)
->
gpio_bank
[
bank
];
&
((
struct
sunxi_gpio_reg
*
)
pio_base
)
->
gpio_bank
[
bank
];
dat
=
readl
(
&
pio
->
dat
);
dat
>>=
num
;
return
(
dat
&
0x1
);
...
...
@@ -228,9 +236,13 @@ int gpio_direction_output(unsigned gpio, int value)
* *
* Allwinner A10s and A13 are using the same SoC type id, but they can be *
* differentiated using a certain part of the SID register. *
* *
* Allwinner H6 has its memory map totally reworked, but the SRAM controller *
* remains similar; the base of it is moved to 0x03000000. *
*****************************************************************************/
#define VER_REG (AW_SRAMCTRL_BASE + 0x24)
#define H6_VER_REG (H6_SRAMCTRL_BASE + 0x24)
#define SUN4I_SID_BASE 0x01C23800
#define SUN8I_SID_BASE 0x01C14000
...
...
@@ -266,8 +278,21 @@ void soc_detection_init(void)
if
(((
midr
>>
4
)
&
0xFFF
)
==
0xC0F
)
{
soc_id
=
0x1639
;
/* ARM Cortex-A15, so likely Allwinner A80 */
}
else
{
set_wbit
(
VER_REG
,
1
<<
15
);
soc_id
=
readl
(
VER_REG
)
>>
16
;
u32
reg
;
/*
* This register is GICD_IIDR on H6, but unmapped according to
* other known SoCs' user manuals.
*/
reg
=
readl
(
0x03021008
);
if
((
reg
&
0xfff
)
==
0x43b
)
/* Found GICv2 here, so it's a H6 */
reg
=
H6_VER_REG
;
else
reg
=
VER_REG
;
set_wbit
(
reg
,
1
<<
15
);
soc_id
=
readl
(
reg
)
>>
16
;
}
}
...
...
@@ -279,6 +304,7 @@ void soc_detection_init(void)
#define soc_is_a80() (soc_id == 0x1639)
#define soc_is_a64() (soc_id == 0x1689)
#define soc_is_h5() (soc_id == 0x1718)
#define soc_is_h6() (soc_id == 0x1728)
#define soc_is_r40() (soc_id == 0x1701)
#define soc_is_v3s() (soc_id == 0x1681)
...
...
@@ -334,7 +360,11 @@ int soc_is_h3(void)
#define APB2_GATE_UART_SHIFT (16)
#define APB2_RESET_UART_SHIFT (16)
void
clock_init_uart
(
void
)
#define H6_UART_GATE_RESET (H6_CCM_BASE + 0x90C)
#define H6_UART_GATE_SHIFT (0)
#define H6_UART_RESET_SHIFT (16)
void
clock_init_uart_legacy
(
void
)
{
/* Open the clock gate for UART0 */
set_wbit
(
APB2_GATE
,
1
<<
(
APB2_GATE_UART_SHIFT
+
CONFIG_CONS_INDEX
-
1
));
...
...
@@ -342,6 +372,22 @@ void clock_init_uart(void)
set_wbit
(
APB2_RESET
,
1
<<
(
APB2_RESET_UART_SHIFT
+
CONFIG_CONS_INDEX
-
1
));
}
void
clock_init_uart_h6
(
void
)
{
/* Open the clock gate for UART0 */
set_wbit
(
H6_UART_GATE_RESET
,
1
<<
(
H6_UART_GATE_SHIFT
+
CONFIG_CONS_INDEX
-
1
));
/* Deassert UART0 reset */
set_wbit
(
H6_UART_GATE_RESET
,
1
<<
(
H6_UART_RESET_SHIFT
+
CONFIG_CONS_INDEX
-
1
));
}
void
clock_init_uart
(
void
)
{
if
(
soc_is_h6
())
clock_init_uart_h6
();
else
clock_init_uart_legacy
();
}
/*****************************************************************************
* UART0 pins muxing is different for different SoC variants. *
* Allwinner A13 is a bit special, because there are no dedicated UART0 pins *
...
...
@@ -382,6 +428,10 @@ void gpio_init(void)
sunxi_gpio_set_cfgpin
(
SUNXI_GPA
(
4
),
SUN50I_H5_GPA_UART0
);
sunxi_gpio_set_cfgpin
(
SUNXI_GPA
(
5
),
SUN50I_H5_GPA_UART0
);
sunxi_gpio_set_pull
(
SUNXI_GPA
(
5
),
SUNXI_GPIO_PULL_UP
);
}
else
if
(
soc_is_h6
())
{
sunxi_gpio_set_cfgpin
(
SUNXI_GPH
(
0
),
SUN50I_H6_GPH_UART0
);
sunxi_gpio_set_cfgpin
(
SUNXI_GPH
(
1
),
SUN50I_H6_GPH_UART0
);
sunxi_gpio_set_pull
(
SUNXI_GPH
(
1
),
SUNXI_GPIO_PULL_UP
);
}
else
if
(
soc_is_v3s
())
{
sunxi_gpio_set_cfgpin
(
SUNXI_GPB
(
8
),
SUN8I_V3S_GPB_UART0
);
sunxi_gpio_set_cfgpin
(
SUNXI_GPB
(
9
),
SUN8I_V3S_GPB_UART0
);
...
...
@@ -394,19 +444,21 @@ void gpio_init(void)
/*****************************************************************************/
#define UART0_RBR (SUNXI_UART0_BASE + 0x0)
/* receive buffer register */
#define UART0_THR (SUNXI_UART0_BASE + 0x0)
/* transmit holding register */
#define UART0_DLL (SUNXI_UART0_BASE + 0x0)
/* divisor latch low register */
static
u32
uart0_base
;
#define UART0_RBR (uart0_base + 0x0)
/* receive buffer register */
#define UART0_THR (uart0_base + 0x0)
/* transmit holding register */
#define UART0_DLL (uart0_base + 0x0)
/* divisor latch low register */
#define UART0_DLH (
SUNXI_UART0_BASE
+ 0x4)
/* divisor latch high register */
#define UART0_IER (
SUNXI_UART0_BASE
+ 0x4)
/* interrupt enable reigster */
#define UART0_DLH (
uart0_base
+ 0x4)
/* divisor latch high register */
#define UART0_IER (
uart0_base
+ 0x4)
/* interrupt enable reigster */
#define UART0_IIR (
SUNXI_UART0_BASE
+ 0x8)
/* interrupt identity register */
#define UART0_FCR (
SUNXI_UART0_BASE
+ 0x8)
/* fifo control register */
#define UART0_IIR (
uart0_base
+ 0x8)
/* interrupt identity register */
#define UART0_FCR (
uart0_base
+ 0x8)
/* fifo control register */
#define UART0_LCR (
SUNXI_UART0_BASE
+ 0xc)
/* line control register */
#define UART0_LCR (
uart0_base
+ 0xc)
/* line control register */
#define UART0_LSR (
SUNXI_UART0_BASE
+ 0x14)
/* line status register */
#define UART0_LSR (
uart0_base
+ 0x14)
/* line status register */
#define BAUD_115200 (0xD)
/* 24 * 1000 * 1000 / 16 / 115200 = 13 */
#define NO_PARITY (0)
...
...
@@ -460,6 +512,8 @@ int get_boot_device(void)
u32
*
spl_signature
=
(
void
*
)
0x4
;
if
(
soc_is_a64
()
||
soc_is_a80
()
||
soc_is_h5
())
spl_signature
=
(
void
*
)
0x10004
;
if
(
soc_is_h6
())
spl_signature
=
(
void
*
)
0x20004
;
/* Check the eGON.BT0 magic in the SPL header */
if
(
spl_signature
[
0
]
!=
0x4E4F4765
||
spl_signature
[
1
]
!=
0x3054422E
)
...
...
@@ -474,9 +528,21 @@ int get_boot_device(void)
return
BOOT_DEVICE_UNK
;
}
void
bases_init
(
void
)
{
if
(
soc_is_h6
())
{
pio_base
=
H6_PIO_BASE
;
uart0_base
=
H6_UART0_BASE
;
}
else
{
pio_base
=
SUNXI_PIO_BASE
;
uart0_base
=
SUNXI_UART0_BASE
;
}
}
int
main
(
void
)
{
soc_detection_init
();
bases_init
();
gpio_init
();
uart0_init
();
...
...
@@ -499,6 +565,8 @@ int main(void)
uart0_puts
(
"Allwinner H3!
\n
"
);
else
if
(
soc_is_h5
())
uart0_puts
(
"Allwinner H5!
\n
"
);
else
if
(
soc_is_h6
())
uart0_puts
(
"Allwinner H6!
\n
"
);
else
if
(
soc_is_r40
())
uart0_puts
(
"Allwinner R40!
\n
"
);
else
if
(
soc_is_v3s
())
...
...
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