Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
E
ezynq
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Wiki
Wiki
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Commits
Issue Boards
Open sidebar
Elphel
ezynq
Commits
a7aad2bb
Commit
a7aad2bb
authored
Sep 19, 2013
by
Andrey Filippov
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Generating lowlevel.c for u-boot
parent
b833a922
Changes
1
Hide whitespace changes
Inline
Side-by-side
Showing
1 changed file
with
216 additions
and
0 deletions
+216
-0
ezynq_uboot.py
ezynq_uboot.py
+216
-0
No files found.
ezynq_uboot.py
0 → 100644
View file @
a7aad2bb
#!/usr/bin/env python
# Copyright (C) 2013, Elphel.inc.
# Generation of the C source file for u-boot lowlevel init
# 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 3 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/>.
__author__
=
"Andrey Filippov"
__copyright__
=
"Copyright 2013, Elphel, Inc."
__license__
=
"GPL"
__version__
=
"3.0+"
__maintainer__
=
"Andrey Filippov"
__email__
=
"andrey@elphel.com"
__status__
=
"Development"
#import ezynq_clk
class
EzynqUBoot
:
license
=
"""/*
* This file is automatically generated by the Free Software program using open information from the
* components datasheets, reference manuals and user data.
* No license is required to distribute this file. User may select his/her own license to replace
* this header text.
*/
"""
# remove unneeded
include_section
=
"""
#include <common.h>
#include <asm/io.h>
#include <asm/arch/sys_proto.h>
#include <asm/arch/hardware.h>
"""
def
__init__
(
self
,
verbosity
):
self
.
cfile
=
self
.
license
+
self
.
include_section
self
.
verbosity
=
verbosity
self
.
sections
=
[
'license'
,
'include'
]
def
get_c_file
(
self
):
return
self
.
cfile
def
_add_reg_writes
(
self
,
reg_sets
):
for
addr
,
data
,
_
,
module_name
,
register_name
,
r_def
in
reg_sets
:
try
:
comments
=
r_def
[
'COMMENTS'
]
except
:
comments
=
''
self
.
cfile
+=
'
\t
writel(0x
%08
x, 0x
%08
x); /*
%
s.
%
s
%
s */
\n
'
%
(
data
,
addr
,
module_name
,
register_name
,
comments
)
def
registers_setup
(
self
,
reg_sets
,
clk
,
num_rbl_regs
):
#clk is an instance of ezynq_clk.EzynqClk
self
.
sections
.
append
(
'registers_setup'
)
self
.
cfile
+=
"""
/*
Setup registers after control is passed from the ROM boot loader to the user code.
%
i registers are already set up using RBL register initialization feature
*/
inline void register_setup(void)
{
"""
%
num_rbl_regs
self
.
_add_reg_writes
(
reg_sets
)
self
.
cfile
+=
'}
\n\n
'
def
pll_setup
(
self
,
reg_sets
,
clk
):
#clk is an instance of ezynq_clk.EzynqClk
pll_status_comment
=
clk
.
clk_register_set
.
get_register_comments
(
'pll_status'
)
pll_arm
=
clk
.
clk_register_set
.
get_bitfield_address_mask_comments
(
'pll_status'
,
'arm_pll_lock'
)
pll_ddr
=
clk
.
clk_register_set
.
get_bitfield_address_mask_comments
(
'pll_status'
,
'ddr_pll_lock'
)
pll_io
=
clk
.
clk_register_set
.
get_bitfield_address_mask_comments
(
'pll_status'
,
'io_pll_lock'
)
address
=
pll_arm
[
0
]
mask
=
0
pll_used
=
clk
.
get_plls_used
()
for
pll
,
pll_tuple
in
zip
([
'ARM'
,
'DDR'
,
'IO'
],[
pll_arm
,
pll_ddr
,
pll_io
]):
if
pll
in
pll_used
:
mask
|=
pll_tuple
[
1
]
if
mask
==
0
:
print
'No PLLs are used, skipping generating pll_setup()'
return
self
.
sections
.
append
(
'pll_setup'
)
self
.
cfile
+=
'''/* Wait for PLLs locked:
%
s */
inline void pll_setup(void)
{
\t
/* Wait for all PLLs locked */
\t
while ((readl (0x
%
x) & 0x
%
x) != 0x
%
x); /* slcr.pll_status
%
s */
\t
/* release PLL bypass on each PLL */
'''
%
(
str
(
pll_used
),
address
,
mask
,
mask
,
pll_status_comment
)
self
.
_add_reg_writes
(
reg_sets
)
self
.
cfile
+=
'}
\n\n
'
def
dci_calibration
(
self
,
reg_sets
,
ddr
):
#ddr is an instance of ezynq_ddr.EzynqDDR
if
len
(
reg_sets
)
==
0
:
print
'No DCI calibration register data is provided, skipping generating dci_calibration()'
return
dci_status_comment
=
ddr
.
ddriob_register_set
.
get_register_comments
(
'ddriob_dci_status'
)
address
,
mask
,
_
=
ddr
.
ddriob_register_set
.
get_bitfield_address_mask_comments
(
'ddriob_dci_status'
,
'done'
)
self
.
cfile
+=
'''/* Calibrate DDR DCI, wait for completion */
inline void dci_calibration(void)
{
\t
/* Toggle active-low DCI reset, initialize DCI calibration */
'''
self
.
_add_reg_writes
(
reg_sets
)
self
.
cfile
+=
'''
\t
/* Wait DCI calibration is DONE */
\t
while ((readl (0x
%
x) & 0x
%
x) != 0x
%
x); /* slcr.ddriob_dci_status
%
s */
'''
%
(
address
,
mask
,
mask
,
dci_status_comment
)
self
.
cfile
+=
'}
\n\n
'
self
.
sections
.
append
(
'dci_calibration'
)
def
ddr_start
(
self
,
reg_sets
,
ddr
):
#ddr is an instance of ezynq_ddr.EzynqDDR
if
len
(
reg_sets
)
==
0
:
print
'No DDR start data is provided, skipping generating ddr_start()'
return
ddrc_status_comment
=
ddr
.
ddrc_register_set
.
get_register_comments
(
'mode_sts_reg'
)
address
,
mask
,
_
=
ddr
.
ddrc_register_set
.
get_bitfield_address_mask_comments
(
'mode_sts_reg'
,
'ddrc_reg_operating_mode'
)
self
.
cfile
+=
'''/* Start DDRC, wait for initialization complete */
inline void ddr_start(void)
{
\t
/* Release DDRC active-low reset */
'''
self
.
_add_reg_writes
(
reg_sets
)
self
.
cfile
+=
'''
\t
/* DDRC operation mode is INITIALIZED */
\t
while ((readl (0x
%
x) & 0x
%
x) == 0); /* ddrc.mode_sts_reg
%
s */
'''
%
(
address
,
mask
,
ddrc_status_comment
)
self
.
cfile
+=
'}
\n\n
'
self
.
sections
.
append
(
'ddr_start'
)
def
make_lowlevel_init
(
self
):
self
.
cfile
+=
'''/* Initialize clocks, DDR memory, copy OCM to DDR */
void lowlevel_init(void)
{
/*
Unlock SLCR and write PLL and clocks registers as the code is now running in the OCM and no
peripherals are needed
*/
\t
register_setup();
/*
Wait PLLs locked and turn off bypass - all clocks should have specified values now
*/
\t
pll_setup();
/*
Calibrate DDR DCI impedance and wait for completion
*/
\t
dci_calibration();
/*
Remove soft reset from DDR controller - that starts initialization. Wait for completion
*/
\t
ddr_start();
/*
Copy 3 pages of OCM from 0x00000.0x2ffff to DDR 0x4000000.0x402ffff
*/
\t
int * s= (int *) 0;
\t
int * d= (int *) 0x4000000;
\t
while (s< ((int *)0x30000)) *d++=*s++;
/*
Now jump to the same instruction in the DDR copy of the currently executed code in OCM
Be careful not to call functions or access data stored in the 3 lower OCM pages.
writel() is OK as it is just a macro, not a function call
*/
\t
asm("add pc, pc, #0x4000000" );
/*
Remap DDR to zero, FILTERSTART
*/
\t
writel(0, &scu_base->filter_start);
/*
Device config APB, unlock the PCAP
*/
\t
writel(0x757BDF0D, &devcfg_base->unlock);
\t
writel(0xFFFFFFFF, &devcfg_base->rom_shadow);
/*
Now as the code is executed outside of the OCM it is possible to remap the 3 lower
OCM pages to high memory.
OCM_CFG, Mask out the ROM, map ram into upper addresses
*/
\t
writel(0x1F, &slcr_base->ocm_cfg);
/*
Copy program memory that we are currently executing to low DRAM (0x0.0x2ffff)
Not possible to call library memcpy() as it will try to access not-yet copied code
*/
\t
s= (int *) 0x4000000;
\t
d= (int *) 0;
\t
while (d < ((int *) 0x30000)) *d++=*s++;
/*
Continue with the original low-level init, Now we have 2 copies of the code again,
currently executing somewhere above 0x4000000. But as soon as we will return
from the call (execute 'bx lr') we'll get back to the low memory.
*/
\t
/* FPGA_RST_CTRL, clear resets on AXI fabric ports */
\t
writel(0x0, &slcr_base->fpga_rst_ctrl);
\t
/* TZ_DDR_RAM, Set DDR trust zone non-secure */
\t
writel(0xFFFFFFFF, &slcr_base->trust_zone);
\t
/* Set urgent bits with register */
\t
writel(0x0, &slcr_base->ddr_urgent_sel);
\t
/* Urgent write, ports S2/S3 */
\t
writel(0xC, &slcr_base->ddr_urgent);
\t
zynq_slcr_lock();
/*
This code was called from low OCM, so return should just get back correctly
*/
}
'''
def
output_c_file
(
self
,
cname
):
if
not
cname
:
return
print
'Writing generated u-boot lowlevel() function to '
,
cname
c_out_file
=
open
(
cname
,
'w'
)
c_out_file
.
write
(
self
.
cfile
)
c_out_file
.
close
()
\ No newline at end of file
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