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
Arm Trusted Firmware
Commits
ba0248b5
Unverified
Commit
ba0248b5
authored
Jul 19, 2018
by
danh-arm
Committed by
GitHub
Jul 19, 2018
Browse files
Merge pull request #1450 from MISL-EBU-System-SW/marvell-support-v6
Marvell support for Armada 8K SoC family
parents
992a3536
23e0fe52
Changes
116
Hide whitespace changes
Inline
Side-by-side
plat/marvell/a8k/a70x0_amc/board/dram_port.c
0 → 100644
View file @
ba0248b5
/*
* Copyright (C) 2018 Marvell International Ltd.
*
* SPDX-License-Identifier: BSD-3-Clause
* https://spdx.org/licenses
*/
#include <arch_helpers.h>
#include <debug.h>
#include <mv_ddr_if.h>
#include <plat_marvell.h>
/*
* This function may modify the default DRAM parameters
* based on information received from SPD or bootloader
* configuration located on non volatile storage
*/
void
plat_marvell_dram_update_topology
(
void
)
{
}
/*
* This struct provides the DRAM training code with
* the appropriate board DRAM configuration
*/
static
struct
mv_ddr_topology_map
board_topology_map
=
{
/* FIXME: MISL board 2CS 8Gb x8 devices of micron - 2133P */
DEBUG_LEVEL_ERROR
,
0x1
,
/* active interfaces */
/* cs_mask, mirror, dqs_swap, ck_swap X subphys */
{
{
{
{
0x3
,
0x2
,
0
,
0
},
{
0x3
,
0x2
,
0
,
0
},
{
0x3
,
0x2
,
0
,
0
},
{
0x3
,
0x2
,
0
,
0
},
{
0x3
,
0x2
,
0
,
0
},
{
0x3
,
0x2
,
0
,
0
},
{
0x3
,
0x2
,
0
,
0
},
{
0x3
,
0x2
,
0
,
0
},
{
0x3
,
0x2
,
0
,
0
}
},
SPEED_BIN_DDR_2400T
,
/* speed_bin */
MV_DDR_DEV_WIDTH_8BIT
,
/* sdram device width */
MV_DDR_DIE_CAP_8GBIT
,
/* die capacity */
MV_DDR_FREQ_SAR
,
/* frequency */
0
,
0
,
/* cas_l, cas_wl */
MV_DDR_TEMP_LOW
}
},
/* temperature */
MV_DDR_32BIT_ECC_PUP8_BUS_MASK
,
/* subphys mask */
MV_DDR_CFG_DEFAULT
,
/* ddr configuration data source */
{
{
0
}
},
/* raw spd data */
{
0
},
/* timing parameters */
{
/* electrical configuration */
{
/* memory electrical configuration */
MV_DDR_RTT_NOM_PARK_RZQ_DISABLE
,
/* rtt_nom */
{
MV_DDR_RTT_NOM_PARK_RZQ_DIV4
,
/* rtt_park 1cs */
MV_DDR_RTT_NOM_PARK_RZQ_DIV1
/* rtt_park 2cs */
},
{
MV_DDR_RTT_WR_DYN_ODT_OFF
,
/* rtt_wr 1cs */
MV_DDR_RTT_WR_RZQ_DIV2
/* rtt_wr 2cs */
},
MV_DDR_DIC_RZQ_DIV7
/* dic */
},
{
/* phy electrical configuration */
MV_DDR_OHM_30
,
/* data_drv_p */
MV_DDR_OHM_30
,
/* data_drv_n */
MV_DDR_OHM_30
,
/* ctrl_drv_p */
MV_DDR_OHM_30
,
/* ctrl_drv_n */
{
MV_DDR_OHM_60
,
/* odt_p 1cs */
MV_DDR_OHM_120
/* odt_p 2cs */
},
{
MV_DDR_OHM_60
,
/* odt_n 1cs */
MV_DDR_OHM_120
/* odt_n 2cs */
},
},
{
/* mac electrical configuration */
MV_DDR_ODT_CFG_NORMAL
,
/* odtcfg_pattern */
MV_DDR_ODT_CFG_ALWAYS_ON
,
/* odtcfg_write */
MV_DDR_ODT_CFG_NORMAL
,
/* odtcfg_read */
},
}
};
struct
mv_ddr_topology_map
*
mv_ddr_topology_map_get
(
void
)
{
/* Return the board topology as defined in the board code */
return
&
board_topology_map
;
}
plat/marvell/a8k/a70x0_amc/board/marvell_plat_config.c
0 → 100644
View file @
ba0248b5
/*
* Copyright (C) 2018 Marvell International Ltd.
*
* SPDX-License-Identifier: BSD-3-Clause
* https://spdx.org/licenses
*/
#include <a8k_common.h>
/*
* If bootrom is currently at BLE there's no need to include the memory
* maps structure at this point
*/
#include <mvebu_def.h>
#ifndef IMAGE_BLE
/*****************************************************************************
* AMB Configuration
*****************************************************************************
*/
struct
addr_map_win
*
amb_memory_map
;
int
marvell_get_amb_memory_map
(
struct
addr_map_win
**
win
,
uint32_t
*
size
,
uintptr_t
base
)
{
*
win
=
amb_memory_map
;
if
(
*
win
==
NULL
)
*
size
=
0
;
else
*
size
=
ARRAY_SIZE
(
amb_memory_map
);
return
0
;
}
#endif
/*****************************************************************************
* IO WIN Configuration
*****************************************************************************
*/
struct
addr_map_win
io_win_memory_map
[]
=
{
#ifndef IMAGE_BLE
/* MCI 0 indirect window */
{
MVEBU_MCI_REG_BASE_REMAP
(
0
),
0x100000
,
MCI_0_TID
},
/* MCI 1 indirect window */
{
MVEBU_MCI_REG_BASE_REMAP
(
1
),
0x100000
,
MCI_1_TID
},
#endif
};
uint32_t
marvell_get_io_win_gcr_target
(
int
ap_index
)
{
return
PIDI_TID
;
}
int
marvell_get_io_win_memory_map
(
int
ap_index
,
struct
addr_map_win
**
win
,
uint32_t
*
size
)
{
*
win
=
io_win_memory_map
;
if
(
*
win
==
NULL
)
*
size
=
0
;
else
*
size
=
ARRAY_SIZE
(
io_win_memory_map
);
return
0
;
}
#ifndef IMAGE_BLE
/*****************************************************************************
* IOB Configuration
*****************************************************************************
*/
struct
addr_map_win
iob_memory_map
[]
=
{
/* PEX0_X4 window */
{
0x00000000f6000000
,
0x6000000
,
PEX0_TID
},
{
0x00000000c0000000
,
0x30000000
,
PEX0_TID
},
{
0x0000000800000000
,
0x200000000
,
PEX0_TID
},
};
int
marvell_get_iob_memory_map
(
struct
addr_map_win
**
win
,
uint32_t
*
size
,
uintptr_t
base
)
{
*
win
=
iob_memory_map
;
*
size
=
ARRAY_SIZE
(
iob_memory_map
);
return
0
;
}
#endif
/*****************************************************************************
* CCU Configuration
*****************************************************************************
*/
struct
addr_map_win
ccu_memory_map
[]
=
{
#ifdef IMAGE_BLE
{
0x00000000f2000000
,
0x4000000
,
IO_0_TID
},
/* IO window */
#else
{
0x00000000f2000000
,
0xe000000
,
IO_0_TID
},
{
0x00000000c0000000
,
0x30000000
,
IO_0_TID
},
/* IO window */
{
0x0000000800000000
,
0x200000000
,
IO_0_TID
},
/* IO window */
#endif
};
uint32_t
marvell_get_ccu_gcr_target
(
int
ap
)
{
return
DRAM_0_TID
;
}
int
marvell_get_ccu_memory_map
(
int
ap_index
,
struct
addr_map_win
**
win
,
uint32_t
*
size
)
{
*
win
=
ccu_memory_map
;
*
size
=
ARRAY_SIZE
(
ccu_memory_map
);
return
0
;
}
#ifdef IMAGE_BLE
struct
pci_hw_cfg
*
plat_get_pcie_hw_data
(
void
)
{
return
NULL
;
}
/*****************************************************************************
* SKIP IMAGE Configuration
*****************************************************************************
*/
#if PLAT_RECOVERY_IMAGE_ENABLE
struct
skip_image
skip_im
=
{
.
detection_method
=
GPIO
,
.
info
.
gpio
.
num
=
33
,
.
info
.
gpio
.
button_state
=
HIGH
,
.
info
.
test
.
cp_ap
=
CP
,
.
info
.
test
.
cp_index
=
0
,
};
void
*
plat_marvell_get_skip_image_data
(
void
)
{
/* Return the skip_image configurations */
return
&
skip_im
;
}
#endif
#endif
plat/marvell/a8k/a70x0_amc/mvebu_def.h
0 → 100644
View file @
ba0248b5
/*
* Copyright (C) 2018 Marvell International Ltd.
*
* SPDX-License-Identifier: BSD-3-Clause
* https://spdx.org/licenses
*/
#ifndef __MVEBU_DEF_H__
#define __MVEBU_DEF_H__
#include <a8k_plat_def.h>
#define CP_COUNT 1
/* A70x0 has single CP0 */
/***********************************************************************
* Required platform porting definitions common to all
* Management Compute SubSystems (MSS)
***********************************************************************
*/
/*
* Load address of SCP_BL2
* SCP_BL2 is loaded to the same place as BL31.
* Once SCP_BL2 is transferred to the SCP,
* it is discarded and BL31 is loaded over the top.
*/
#ifdef SCP_IMAGE
#define SCP_BL2_BASE BL31_BASE
#endif
#endif
/* __MVEBU_DEF_H__ */
plat/marvell/a8k/a70x0_amc/platform.mk
0 → 100644
View file @
ba0248b5
#
# Copyright (C) 2018 Marvell International Ltd.
#
# SPDX-License-Identifier: BSD-3-Clause
# https://spdx.org/licenses
#
PCI_EP_SUPPORT
:=
0
DOIMAGE_SEC
:=
tools/doimage/secure/sec_img_7K.cfg
MARVELL_MOCHI_DRV
:=
drivers/marvell/mochi/apn806_setup.c
include
plat/marvell/a8k/common/a8k_common.mk
include
plat/marvell/common/marvell_common.mk
plat/marvell/a8k/a80x0/board/dram_port.c
0 → 100644
View file @
ba0248b5
/*
* Copyright (C) 2018 Marvell International Ltd.
*
* SPDX-License-Identifier: BSD-3-Clause
* https://spdx.org/licenses
*/
#include <arch_helpers.h>
#include <a8k_i2c.h>
#include <debug.h>
#include <mmio.h>
#include <mv_ddr_if.h>
#include <mvebu_def.h>
#include <plat_marvell.h>
#define MVEBU_AP_MPP_CTRL0_7_REG MVEBU_AP_MPP_REGS(0)
#define MVEBU_AP_MPP_CTRL4_OFFS 16
#define MVEBU_AP_MPP_CTRL5_OFFS 20
#define MVEBU_AP_MPP_CTRL4_I2C0_SDA_ENA 0x3
#define MVEBU_AP_MPP_CTRL5_I2C0_SCK_ENA 0x3
#define MVEBU_CP_MPP_CTRL37_OFFS 20
#define MVEBU_CP_MPP_CTRL38_OFFS 24
#define MVEBU_CP_MPP_CTRL37_I2C0_SCK_ENA 0x2
#define MVEBU_CP_MPP_CTRL38_I2C0_SDA_ENA 0x2
#define MVEBU_MPP_CTRL_MASK 0xf
/*
* This struct provides the DRAM training code with
* the appropriate board DRAM configuration
*/
static
struct
mv_ddr_topology_map
board_topology_map
=
{
/* MISL board with 1CS 8Gb x4 devices of Micron 2400T */
DEBUG_LEVEL_ERROR
,
0x1
,
/* active interfaces */
/* cs_mask, mirror, dqs_swap, ck_swap X subphys */
{
{
{
{
0x1
,
0x0
,
0
,
0
},
/* FIXME: change the cs mask for all 64 bit */
{
0x1
,
0x0
,
0
,
0
},
{
0x1
,
0x0
,
0
,
0
},
{
0x1
,
0x0
,
0
,
0
},
{
0x1
,
0x0
,
0
,
0
},
{
0x1
,
0x0
,
0
,
0
},
{
0x1
,
0x0
,
0
,
0
},
{
0x1
,
0x0
,
0
,
0
},
{
0x1
,
0x0
,
0
,
0
}
},
/* TODO: double check if the speed bin is 2400T */
SPEED_BIN_DDR_2400T
,
/* speed_bin */
MV_DDR_DEV_WIDTH_8BIT
,
/* sdram device width */
MV_DDR_DIE_CAP_8GBIT
,
/* die capacity */
MV_DDR_FREQ_SAR
,
/* frequency */
0
,
0
,
/* cas_l, cas_wl */
MV_DDR_TEMP_LOW
}
},
/* temperature */
MV_DDR_64BIT_ECC_PUP8_BUS_MASK
,
/* subphys mask */
MV_DDR_CFG_SPD
,
/* ddr configuration data source */
{
{
0
}
},
/* raw spd data */
{
0
},
/* timing parameters */
{
/* electrical configuration */
{
/* memory electrical configuration */
MV_DDR_RTT_NOM_PARK_RZQ_DISABLE
,
/* rtt_nom */
{
MV_DDR_RTT_NOM_PARK_RZQ_DIV4
,
/* rtt_park 1cs */
MV_DDR_RTT_NOM_PARK_RZQ_DIV1
/* rtt_park 2cs */
},
{
MV_DDR_RTT_WR_DYN_ODT_OFF
,
/* rtt_wr 1cs */
MV_DDR_RTT_WR_RZQ_DIV2
/* rtt_wr 2cs */
},
MV_DDR_DIC_RZQ_DIV7
/* dic */
},
{
/* phy electrical configuration */
MV_DDR_OHM_30
,
/* data_drv_p */
MV_DDR_OHM_30
,
/* data_drv_n */
MV_DDR_OHM_30
,
/* ctrl_drv_p */
MV_DDR_OHM_30
,
/* ctrl_drv_n */
{
MV_DDR_OHM_60
,
/* odt_p 1cs */
MV_DDR_OHM_120
/* odt_p 2cs */
},
{
MV_DDR_OHM_60
,
/* odt_n 1cs */
MV_DDR_OHM_120
/* odt_n 2cs */
},
},
{
/* mac electrical configuration */
MV_DDR_ODT_CFG_NORMAL
,
/* odtcfg_pattern */
MV_DDR_ODT_CFG_ALWAYS_ON
,
/* odtcfg_write */
MV_DDR_ODT_CFG_NORMAL
,
/* odtcfg_read */
},
}
};
struct
mv_ddr_topology_map
*
mv_ddr_topology_map_get
(
void
)
{
/* Return the board topology as defined in the board code */
return
&
board_topology_map
;
}
static
void
mpp_config
(
void
)
{
uintptr_t
reg
;
uint32_t
val
;
reg
=
MVEBU_CP_MPP_REGS
(
0
,
4
);
/* configure CP0 MPP 37 and 38 to i2c */
val
=
mmio_read_32
(
reg
);
val
&=
~
((
MVEBU_MPP_CTRL_MASK
<<
MVEBU_CP_MPP_CTRL37_OFFS
)
|
(
MVEBU_MPP_CTRL_MASK
<<
MVEBU_CP_MPP_CTRL38_OFFS
));
val
|=
(
MVEBU_CP_MPP_CTRL37_I2C0_SCK_ENA
<<
MVEBU_CP_MPP_CTRL37_OFFS
)
|
(
MVEBU_CP_MPP_CTRL38_I2C0_SDA_ENA
<<
MVEBU_CP_MPP_CTRL38_OFFS
);
mmio_write_32
(
reg
,
val
);
}
/*
* This function may modify the default DRAM parameters
* based on information received from SPD or bootloader
* configuration located on non volatile storage
*/
void
plat_marvell_dram_update_topology
(
void
)
{
struct
mv_ddr_topology_map
*
tm
=
mv_ddr_topology_map_get
();
INFO
(
"Gathering DRAM information
\n
"
);
if
(
tm
->
cfg_src
==
MV_DDR_CFG_SPD
)
{
/* configure MPPs to enable i2c */
mpp_config
();
/* initialize i2c */
i2c_init
((
void
*
)
MVEBU_CP0_I2C_BASE
);
/* select SPD memory page 0 to access DRAM configuration */
i2c_write
(
I2C_SPD_P0_ADDR
,
0x0
,
1
,
tm
->
spd_data
.
all_bytes
,
1
);
/* read data from spd */
i2c_read
(
I2C_SPD_ADDR
,
0x0
,
1
,
tm
->
spd_data
.
all_bytes
,
sizeof
(
tm
->
spd_data
.
all_bytes
));
}
}
plat/marvell/a8k/a80x0/board/marvell_plat_config.c
0 → 100644
View file @
ba0248b5
/*
* Copyright (C) 2018 Marvell International Ltd.
*
* SPDX-License-Identifier: BSD-3-Clause
* https://spdx.org/licenses
*/
#include <a8k_common.h>
/*
* If bootrom is currently at BLE there's no need to include the memory
* maps structure at this point
*/
#include <mvebu_def.h>
#ifndef IMAGE_BLE
/*****************************************************************************
* AMB Configuration
*****************************************************************************
*/
struct
addr_map_win
amb_memory_map
[]
=
{
/* CP1 SPI1 CS0 Direct Mode access */
{
0xf900
,
0x1000000
,
AMB_SPI1_CS0_ID
},
};
int
marvell_get_amb_memory_map
(
struct
addr_map_win
**
win
,
uint32_t
*
size
,
uintptr_t
base
)
{
*
win
=
amb_memory_map
;
if
(
*
win
==
NULL
)
*
size
=
0
;
else
*
size
=
ARRAY_SIZE
(
amb_memory_map
);
return
0
;
}
#endif
/*****************************************************************************
* IO WIN Configuration
*****************************************************************************
*/
struct
addr_map_win
io_win_memory_map
[]
=
{
/* CP1 (MCI0) internal regs */
{
0x00000000f4000000
,
0x2000000
,
MCI_0_TID
},
#ifndef IMAGE_BLE
/* PCIe0 and SPI1_CS0 (RUNIT) on CP1*/
{
0x00000000f9000000
,
0x2000000
,
MCI_0_TID
},
/* PCIe1 on CP1*/
{
0x00000000fb000000
,
0x1000000
,
MCI_0_TID
},
/* PCIe2 on CP1*/
{
0x00000000fc000000
,
0x1000000
,
MCI_0_TID
},
/* MCI 0 indirect window */
{
MVEBU_MCI_REG_BASE_REMAP
(
0
),
0x100000
,
MCI_0_TID
},
/* MCI 1 indirect window */
{
MVEBU_MCI_REG_BASE_REMAP
(
1
),
0x100000
,
MCI_1_TID
},
#endif
};
uint32_t
marvell_get_io_win_gcr_target
(
int
ap_index
)
{
return
PIDI_TID
;
}
int
marvell_get_io_win_memory_map
(
int
ap_index
,
struct
addr_map_win
**
win
,
uint32_t
*
size
)
{
*
win
=
io_win_memory_map
;
if
(
*
win
==
NULL
)
*
size
=
0
;
else
*
size
=
ARRAY_SIZE
(
io_win_memory_map
);
return
0
;
}
#ifndef IMAGE_BLE
/*****************************************************************************
* IOB Configuration
*****************************************************************************
*/
struct
addr_map_win
iob_memory_map_cp0
[]
=
{
/* CP0 */
/* PEX1_X1 window */
{
0x00000000f7000000
,
0x1000000
,
PEX1_TID
},
/* PEX2_X1 window */
{
0x00000000f8000000
,
0x1000000
,
PEX2_TID
},
/* PEX0_X4 window */
{
0x00000000f6000000
,
0x1000000
,
PEX0_TID
}
};
struct
addr_map_win
iob_memory_map_cp1
[]
=
{
/* CP1 */
/* SPI1_CS0 (RUNIT) window */
{
0x00000000f9000000
,
0x1000000
,
RUNIT_TID
},
/* PEX1_X1 window */
{
0x00000000fb000000
,
0x1000000
,
PEX1_TID
},
/* PEX2_X1 window */
{
0x00000000fc000000
,
0x1000000
,
PEX2_TID
},
/* PEX0_X4 window */
{
0x00000000fa000000
,
0x1000000
,
PEX0_TID
}
};
int
marvell_get_iob_memory_map
(
struct
addr_map_win
**
win
,
uint32_t
*
size
,
uintptr_t
base
)
{
switch
(
base
)
{
case
MVEBU_CP_REGS_BASE
(
0
):
*
win
=
iob_memory_map_cp0
;
*
size
=
ARRAY_SIZE
(
iob_memory_map_cp0
);
return
0
;
case
MVEBU_CP_REGS_BASE
(
1
):
*
win
=
iob_memory_map_cp1
;
*
size
=
ARRAY_SIZE
(
iob_memory_map_cp1
);
return
0
;
default:
*
size
=
0
;
*
win
=
0
;
return
1
;
}
}
#endif
/*****************************************************************************
* CCU Configuration
*****************************************************************************
*/
struct
addr_map_win
ccu_memory_map
[]
=
{
#ifdef IMAGE_BLE
{
0x00000000f2000000
,
0x4000000
,
IO_0_TID
},
/* IO window */
#else
{
0x00000000f2000000
,
0xe000000
,
IO_0_TID
},
/* IO window */
#endif
};
uint32_t
marvell_get_ccu_gcr_target
(
int
ap
)
{
return
DRAM_0_TID
;
}
int
marvell_get_ccu_memory_map
(
int
ap
,
struct
addr_map_win
**
win
,
uint32_t
*
size
)
{
*
win
=
ccu_memory_map
;
*
size
=
ARRAY_SIZE
(
ccu_memory_map
);
return
0
;
}
#ifndef IMAGE_BLE
/*****************************************************************************
* SoC PM configuration
*****************************************************************************
*/
/* CP GPIO should be used and the GPIOs should be within same GPIO register */
struct
power_off_method
pm_cfg
=
{
.
type
=
PMIC_GPIO
,
.
cfg
.
gpio
.
pin_count
=
1
,
.
cfg
.
gpio
.
info
=
{{
0
,
35
}
},
.
cfg
.
gpio
.
step_count
=
7
,
.
cfg
.
gpio
.
seq
=
{
1
,
0
,
1
,
0
,
1
,
0
,
1
},
.
cfg
.
gpio
.
delay_ms
=
10
,
};
void
*
plat_marvell_get_pm_cfg
(
void
)
{
/* Return the PM configurations */
return
&
pm_cfg
;
}
/* In reference to #ifndef IMAGE_BLE, this part is used for BLE only. */
#else
/*****************************************************************************
* SKIP IMAGE Configuration
*****************************************************************************
*/
#if PLAT_RECOVERY_IMAGE_ENABLE
struct
skip_image
skip_im
=
{
.
detection_method
=
GPIO
,
.
info
.
gpio
.
num
=
33
,
.
info
.
gpio
.
button_state
=
HIGH
,
.
info
.
test
.
cp_ap
=
CP
,
.
info
.
test
.
cp_index
=
0
,
};
void
*
plat_marvell_get_skip_image_data
(
void
)
{
/* Return the skip_image configurations */
return
&
skip_im
;
}
#endif
#endif
plat/marvell/a8k/a80x0/mvebu_def.h
0 → 100644
View file @
ba0248b5
/*
* Copyright (C) 2018 Marvell International Ltd.
*
* SPDX-License-Identifier: BSD-3-Clause
* https://spdx.org/licenses
*/
#ifndef __MVEBU_DEF_H__
#define __MVEBU_DEF_H__
#include <a8k_plat_def.h>
#define CP_COUNT 2
/* A80x0 has both CP0 & CP1 */
#define I2C_SPD_ADDR 0x53
/* Access SPD data */
#define I2C_SPD_P0_ADDR 0x36
/* Select SPD data page 0 */
#endif
/* __MVEBU_DEF_H__ */
plat/marvell/a8k/a80x0/platform.mk
0 → 100644
View file @
ba0248b5
#
# Copyright (C) 2018 Marvell International Ltd.
#
# SPDX-License-Identifier: BSD-3-Clause
# https://spdx.org/licenses
#
PCI_EP_SUPPORT
:=
0
DOIMAGE_SEC
:=
tools/doimage/secure/sec_img_8K.cfg
MARVELL_MOCHI_DRV
:=
drivers/marvell/mochi/apn806_setup.c
include
plat/marvell/a8k/common/a8k_common.mk
include
plat/marvell/common/marvell_common.mk
plat/marvell/a8k/a80x0_mcbin/board/dram_port.c
0 → 100644
View file @
ba0248b5
/*
* Copyright (C) 2018 Marvell International Ltd.
*
* SPDX-License-Identifier: BSD-3-Clause
* https://spdx.org/licenses
*/
#include <arch_helpers.h>
#include <a8k_i2c.h>
#include <debug.h>
#include <mmio.h>
#include <mv_ddr_if.h>
#include <mvebu_def.h>
#include <plat_marvell.h>
#define MVEBU_CP_MPP_CTRL37_OFFS 20
#define MVEBU_CP_MPP_CTRL38_OFFS 24
#define MVEBU_CP_MPP_CTRL37_I2C0_SCK_ENA 0x2
#define MVEBU_CP_MPP_CTRL38_I2C0_SDA_ENA 0x2
#define MVEBU_MPP_CTRL_MASK 0xf
/*
* This struct provides the DRAM training code with
* the appropriate board DRAM configuration
*/
static
struct
mv_ddr_topology_map
board_topology_map
=
{
/* Board with 1CS 8Gb x4 devices of Micron 2400T */
DEBUG_LEVEL_ERROR
,
0x1
,
/* active interfaces */
/* cs_mask, mirror, dqs_swap, ck_swap X subphys */
{
{
{
{
0x1
,
0x0
,
0
,
0
},
/* FIXME: change the cs mask for all 64 bit */
{
0x1
,
0x0
,
0
,
0
},
{
0x1
,
0x0
,
0
,
0
},
{
0x1
,
0x0
,
0
,
0
},
{
0x1
,
0x0
,
0
,
0
},
{
0x1
,
0x0
,
0
,
0
},
{
0x1
,
0x0
,
0
,
0
},
{
0x1
,
0x0
,
0
,
0
},
{
0x1
,
0x0
,
0
,
0
}
},
/* TODO: double check if the speed bin is 2400T */
SPEED_BIN_DDR_2400T
,
/* speed_bin */
MV_DDR_DEV_WIDTH_8BIT
,
/* sdram device width */
MV_DDR_DIE_CAP_8GBIT
,
/* die capacity */
MV_DDR_FREQ_SAR
,
/* frequency */
0
,
0
,
/* cas_l, cas_wl */
MV_DDR_TEMP_LOW
}
},
/* temperature */
MV_DDR_64BIT_BUS_MASK
,
/* subphys mask */
MV_DDR_CFG_SPD
,
/* ddr configuration data source */
{
{
0
}
},
/* raw spd data */
{
0
},
/* timing parameters */
{
/* electrical configuration */
{
/* memory electrical configuration */
MV_DDR_RTT_NOM_PARK_RZQ_DISABLE
,
/* rtt_nom */
{
MV_DDR_RTT_NOM_PARK_RZQ_DIV4
,
/* rtt_park 1cs */
MV_DDR_RTT_NOM_PARK_RZQ_DIV1
/* rtt_park 2cs */
},
{
MV_DDR_RTT_WR_DYN_ODT_OFF
,
/* rtt_wr 1cs */
MV_DDR_RTT_WR_RZQ_DIV2
/* rtt_wr 2cs */
},
MV_DDR_DIC_RZQ_DIV7
/* dic */
},
{
/* phy electrical configuration */
MV_DDR_OHM_30
,
/* data_drv_p */
MV_DDR_OHM_30
,
/* data_drv_n */
MV_DDR_OHM_30
,
/* ctrl_drv_p */
MV_DDR_OHM_30
,
/* ctrl_drv_n */
{
MV_DDR_OHM_60
,
/* odt_p 1cs */
MV_DDR_OHM_120
/* odt_p 2cs */
},
{
MV_DDR_OHM_60
,
/* odt_n 1cs */
MV_DDR_OHM_120
/* odt_n 2cs */
},
},
{
/* mac electrical configuration */
MV_DDR_ODT_CFG_NORMAL
,
/* odtcfg_pattern */
MV_DDR_ODT_CFG_ALWAYS_ON
,
/* odtcfg_write */
MV_DDR_ODT_CFG_NORMAL
,
/* odtcfg_read */
},
}
};
struct
mv_ddr_topology_map
*
mv_ddr_topology_map_get
(
void
)
{
/* Return the board topology as defined in the board code */
return
&
board_topology_map
;
}
static
void
mpp_config
(
void
)
{
uint32_t
val
;
uintptr_t
reg
=
MVEBU_CP_MPP_REGS
(
0
,
4
);
/* configure CP0 MPP 37 and 38 to i2c */
val
=
mmio_read_32
(
reg
);
val
&=
~
((
MVEBU_MPP_CTRL_MASK
<<
MVEBU_CP_MPP_CTRL37_OFFS
)
|
(
MVEBU_MPP_CTRL_MASK
<<
MVEBU_CP_MPP_CTRL38_OFFS
));
val
|=
(
MVEBU_CP_MPP_CTRL37_I2C0_SCK_ENA
<<
MVEBU_CP_MPP_CTRL37_OFFS
)
|
(
MVEBU_CP_MPP_CTRL38_I2C0_SDA_ENA
<<
MVEBU_CP_MPP_CTRL38_OFFS
);
mmio_write_32
(
reg
,
val
);
}
/*
* This function may modify the default DRAM parameters
* based on information received from SPD or bootloader
* configuration located on non volatile storage
*/
void
plat_marvell_dram_update_topology
(
void
)
{
struct
mv_ddr_topology_map
*
tm
=
mv_ddr_topology_map_get
();
INFO
(
"Gathering DRAM information
\n
"
);
if
(
tm
->
cfg_src
==
MV_DDR_CFG_SPD
)
{
/* configure MPPs to enable i2c */
mpp_config
();
/* initialize the i2c */
i2c_init
((
void
*
)
MVEBU_CP0_I2C_BASE
);
/* select SPD memory page 0 to access DRAM configuration */
i2c_write
(
I2C_SPD_P0_ADDR
,
0x0
,
1
,
tm
->
spd_data
.
all_bytes
,
1
);
/* read data from spd */
i2c_read
(
I2C_SPD_ADDR
,
0x0
,
1
,
tm
->
spd_data
.
all_bytes
,
sizeof
(
tm
->
spd_data
.
all_bytes
));
}
}
plat/marvell/a8k/a80x0_mcbin/board/marvell_plat_config.c
0 → 100644
View file @
ba0248b5
/*
* Copyright (C) 2018 Marvell International Ltd.
*
* SPDX-License-Identifier: BSD-3-Clause
* https://spdx.org/licenses
*/
#include <a8k_common.h>
#include <delay_timer.h>
#include <mmio.h>
/*
* If bootrom is currently at BLE there's no need to include the memory
* maps structure at this point
*/
#include <mvebu_def.h>
#ifndef IMAGE_BLE
/*****************************************************************************
* GPIO Configuration
*****************************************************************************
*/
#define MPP_CONTROL_REGISTER 0xf2440018
#define MPP_CONTROL_MPP_SEL_52_MASK 0xf0000
#define GPIO_DATA_OUT1_REGISTER 0xf2440140
#define GPIO_DATA_OUT_EN_CTRL1_REGISTER 0xf2440144
#define GPIO52_MASK 0x100000
/* Reset PCIe via GPIO number 52 */
int
marvell_gpio_config
(
void
)
{
uint32_t
reg
;
reg
=
mmio_read_32
(
MPP_CONTROL_REGISTER
);
reg
|=
MPP_CONTROL_MPP_SEL_52_MASK
;
mmio_write_32
(
MPP_CONTROL_REGISTER
,
reg
);
reg
=
mmio_read_32
(
GPIO_DATA_OUT1_REGISTER
);
reg
|=
GPIO52_MASK
;
mmio_write_32
(
GPIO_DATA_OUT1_REGISTER
,
reg
);
reg
=
mmio_read_32
(
GPIO_DATA_OUT_EN_CTRL1_REGISTER
);
reg
&=
~
GPIO52_MASK
;
mmio_write_32
(
GPIO_DATA_OUT_EN_CTRL1_REGISTER
,
reg
);
udelay
(
100
);
return
0
;
}
/*****************************************************************************
* AMB Configuration
*****************************************************************************
*/
struct
addr_map_win
amb_memory_map
[]
=
{
/* CP1 SPI1 CS0 Direct Mode access */
{
0xf900
,
0x1000000
,
AMB_SPI1_CS0_ID
},
};
int
marvell_get_amb_memory_map
(
struct
addr_map_win
**
win
,
uint32_t
*
size
,
uintptr_t
base
)
{
*
win
=
amb_memory_map
;
if
(
*
win
==
NULL
)
*
size
=
0
;
else
*
size
=
ARRAY_SIZE
(
amb_memory_map
);
return
0
;
}
#endif
/*****************************************************************************
* IO WIN Configuration
*****************************************************************************
*/
struct
addr_map_win
io_win_memory_map
[]
=
{
/* CP1 (MCI0) internal regs */
{
0x00000000f4000000
,
0x2000000
,
MCI_0_TID
},
#ifndef IMAGE_BLE
/* PCIe0 and SPI1_CS0 (RUNIT) on CP1*/
{
0x00000000f9000000
,
0x2000000
,
MCI_0_TID
},
/* PCIe1 on CP1*/
{
0x00000000fb000000
,
0x1000000
,
MCI_0_TID
},
/* PCIe2 on CP1*/
{
0x00000000fc000000
,
0x1000000
,
MCI_0_TID
},
/* MCI 0 indirect window */
{
MVEBU_MCI_REG_BASE_REMAP
(
0
),
0x100000
,
MCI_0_TID
},
/* MCI 1 indirect window */
{
MVEBU_MCI_REG_BASE_REMAP
(
1
),
0x100000
,
MCI_1_TID
},
#endif
};
uint32_t
marvell_get_io_win_gcr_target
(
int
ap_index
)
{
return
PIDI_TID
;
}
int
marvell_get_io_win_memory_map
(
int
ap_index
,
struct
addr_map_win
**
win
,
uint32_t
*
size
)
{
*
win
=
io_win_memory_map
;
if
(
*
win
==
NULL
)
*
size
=
0
;
else
*
size
=
ARRAY_SIZE
(
io_win_memory_map
);
return
0
;
}
#ifndef IMAGE_BLE
/*****************************************************************************
* IOB Configuration
*****************************************************************************
*/
struct
addr_map_win
iob_memory_map_cp0
[]
=
{
/* CP0 */
/* PEX1_X1 window */
{
0x00000000f7000000
,
0x1000000
,
PEX1_TID
},
/* PEX2_X1 window */
{
0x00000000f8000000
,
0x1000000
,
PEX2_TID
},
/* PEX0_X4 window */
{
0x00000000f6000000
,
0x1000000
,
PEX0_TID
},
{
0x00000000c0000000
,
0x30000000
,
PEX0_TID
},
{
0x0000000800000000
,
0x100000000
,
PEX0_TID
},
};
struct
addr_map_win
iob_memory_map_cp1
[]
=
{
/* CP1 */
/* SPI1_CS0 (RUNIT) window */
{
0x00000000f9000000
,
0x1000000
,
RUNIT_TID
},
/* PEX1_X1 window */
{
0x00000000fb000000
,
0x1000000
,
PEX1_TID
},
/* PEX2_X1 window */
{
0x00000000fc000000
,
0x1000000
,
PEX2_TID
},
/* PEX0_X4 window */
{
0x00000000fa000000
,
0x1000000
,
PEX0_TID
}
};
int
marvell_get_iob_memory_map
(
struct
addr_map_win
**
win
,
uint32_t
*
size
,
uintptr_t
base
)
{
switch
(
base
)
{
case
MVEBU_CP_REGS_BASE
(
0
):
*
win
=
iob_memory_map_cp0
;
*
size
=
ARRAY_SIZE
(
iob_memory_map_cp0
);
return
0
;
case
MVEBU_CP_REGS_BASE
(
1
):
*
win
=
iob_memory_map_cp1
;
*
size
=
ARRAY_SIZE
(
iob_memory_map_cp1
);
return
0
;
default:
*
size
=
0
;
*
win
=
0
;
return
1
;
}
}
#endif
/*****************************************************************************
* CCU Configuration
*****************************************************************************
*/
struct
addr_map_win
ccu_memory_map
[]
=
{
#ifdef IMAGE_BLE
{
0x00000000f2000000
,
0x4000000
,
IO_0_TID
},
/* IO window */
#else
{
0x00000000f2000000
,
0xe000000
,
IO_0_TID
},
/* IO window */
{
0x00000000c0000000
,
0x30000000
,
IO_0_TID
},
/* IO window */
{
0x0000000800000000
,
0x100000000
,
IO_0_TID
},
/* IO window */
#endif
};
uint32_t
marvell_get_ccu_gcr_target
(
int
ap
)
{
return
DRAM_0_TID
;
}
int
marvell_get_ccu_memory_map
(
int
ap_index
,
struct
addr_map_win
**
win
,
uint32_t
*
size
)
{
*
win
=
ccu_memory_map
;
*
size
=
ARRAY_SIZE
(
ccu_memory_map
);
return
0
;
}
/* In reference to #ifndef IMAGE_BLE, this part is used for BLE only. */
/*****************************************************************************
* SKIP IMAGE Configuration
*****************************************************************************
*/
void
*
plat_marvell_get_skip_image_data
(
void
)
{
/* No recovery button on A8k-MCBIN board */
return
NULL
;
}
plat/marvell/a8k/a80x0_mcbin/mvebu_def.h
0 → 100644
View file @
ba0248b5
/*
* Copyright (C) 2018 Marvell International Ltd.
*
* SPDX-License-Identifier: BSD-3-Clause
* https://spdx.org/licenses
*/
#ifndef __MVEBU_DEF_H__
#define __MVEBU_DEF_H__
#include <a8k_plat_def.h>
#define CP_COUNT 2
/* A80x0 has both CP0 & CP1 */
#define I2C_SPD_ADDR 0x53
/* Access SPD data */
#define I2C_SPD_P0_ADDR 0x36
/* Select SPD data page 0 */
#endif
/* __MVEBU_DEF_H__ */
plat/marvell/a8k/a80x0_mcbin/platform.mk
0 → 100644
View file @
ba0248b5
#
# Copyright (C) 2018 Marvell International Ltd.
#
# SPDX-License-Identifier: BSD-3-Clause
# https://spdx.org/licenses
#
PCI_EP_SUPPORT
:=
0
DOIMAGE_SEC
:=
tools/doimage/secure/sec_img_8K.cfg
MARVELL_MOCHI_DRV
:=
drivers/marvell/mochi/apn806_setup.c
include
plat/marvell/a8k/common/a8k_common.mk
include
plat/marvell/common/marvell_common.mk
plat/marvell/a8k/common/a8k_common.mk
0 → 100644
View file @
ba0248b5
#
# Copyright (C) 2016 - 2018 Marvell International Ltd.
#
# SPDX-License-Identifier: BSD-3-Clause
# https://spdx.org/licenses
include
tools/doimage/doimage.mk
PLAT_FAMILY
:=
a8k
PLAT_FAMILY_BASE
:=
plat/marvell/
$(PLAT_FAMILY)
PLAT_INCLUDE_BASE
:=
include/plat/marvell/
$(PLAT_FAMILY)
PLAT_COMMON_BASE
:=
$(PLAT_FAMILY_BASE)
/common
MARVELL_DRV_BASE
:=
drivers/marvell
MARVELL_COMMON_BASE
:=
plat/marvell/common
ERRATA_A72_859971
:=
1
# Enable MSS support for a8k family
MSS_SUPPORT
:=
1
# Disable EL3 cache for power management
BL31_CACHE_DISABLE
:=
1
$(eval
$(call
add_define,BL31_CACHE_DISABLE))
$(eval
$(call
add_define,PCI_EP_SUPPORT))
$(eval
$(call
assert_boolean,PCI_EP_SUPPORT))
DOIMAGEPATH
?=
tools/doimage
DOIMAGETOOL
?=
${DOIMAGEPATH}
/doimage
ROM_BIN_EXT
?=
$(BUILD_PLAT)
/ble.bin
DOIMAGE_FLAGS
+=
-b
$(ROM_BIN_EXT)
$(NAND_DOIMAGE_FLAGS)
$(DOIMAGE_SEC_FLAGS)
# This define specifies DDR type for BLE
$(eval
$(call
add_define,CONFIG_DDR4))
MARVELL_GIC_SOURCES
:=
drivers/arm/gic/common/gic_common.c
\
drivers/arm/gic/v2/gicv2_main.c
\
drivers/arm/gic/v2/gicv2_helpers.c
\
plat/common/plat_gicv2.c
ATF_INCLUDES
:=
-Iinclude
/common/tbbr
PLAT_INCLUDES
:=
-I
$(PLAT_FAMILY_BASE)
/
$(PLAT)
\
-I
$(PLAT_COMMON_BASE)
/include
\
-I
$(PLAT_INCLUDE_BASE)
/common
\
-Iinclude
/drivers/marvell
\
-Iinclude
/drivers/marvell/mochi
\
$(ATF_INCLUDES)
PLAT_BL_COMMON_SOURCES
:=
$(PLAT_COMMON_BASE)
/aarch64/a8k_common.c
\
drivers/console/aarch64/console.S
\
drivers/ti/uart/aarch64/16550_console.S
BLE_PORTING_SOURCES
:=
$(PLAT_FAMILY_BASE)
/
$(PLAT)
/board/dram_port.c
\
$(PLAT_FAMILY_BASE)
/
$(PLAT)
/board/marvell_plat_config.c
MARVELL_MOCHI_DRV
+=
$(MARVELL_DRV_BASE)
/mochi/cp110_setup.c
BLE_SOURCES
:=
$(PLAT_COMMON_BASE)
/plat_ble_setup.c
\
$(MARVELL_MOCHI_DRV)
\
$(MARVELL_DRV_BASE)
/i2c/a8k_i2c.c
\
$(PLAT_COMMON_BASE)
/plat_pm.c
\
$(MARVELL_DRV_BASE)
/thermal.c
\
$(PLAT_COMMON_BASE)
/plat_thermal.c
\
$(BLE_PORTING_SOURCES)
\
$(MARVELL_DRV_BASE)
/ccu.c
\
$(MARVELL_DRV_BASE)
/io_win.c
BL1_SOURCES
+=
$(PLAT_COMMON_BASE)
/aarch64/plat_helpers.S
\
lib/cpus/aarch64/cortex_a72.S
MARVELL_DRV
:=
$(MARVELL_DRV_BASE)
/io_win.c
\
$(MARVELL_DRV_BASE)
/iob.c
\
$(MARVELL_DRV_BASE)
/mci.c
\
$(MARVELL_DRV_BASE)
/amb_adec.c
\
$(MARVELL_DRV_BASE)
/ccu.c
\
$(MARVELL_DRV_BASE)
/cache_llc.c
\
$(MARVELL_DRV_BASE)
/comphy/phy-comphy-cp110.c
BL31_PORTING_SOURCES
:=
$(PLAT_FAMILY_BASE)
/
$(PLAT)
/board/marvell_plat_config.c
BL31_SOURCES
+=
lib/cpus/aarch64/cortex_a72.S
\
$(PLAT_COMMON_BASE)
/aarch64/plat_helpers.S
\
$(PLAT_COMMON_BASE)
/aarch64/plat_arch_config.c
\
$(PLAT_COMMON_BASE)
/plat_pm.c
\
$(PLAT_COMMON_BASE)
/plat_bl31_setup.c
\
$(MARVELL_COMMON_BASE)
/marvell_gicv2.c
\
$(MARVELL_COMMON_BASE)
/mrvl_sip_svc.c
\
$(MARVELL_COMMON_BASE)
/marvell_ddr_info.c
\
$(BL31_PORTING_SOURCES)
\
$(MARVELL_DRV)
\
$(MARVELL_MOCHI_DRV)
\
$(MARVELL_GIC_SOURCES)
# Add trace functionality for PM
BL31_SOURCES
+=
$(PLAT_COMMON_BASE)
/plat_pm_trace.c
# Disable the PSCI platform compatibility layer (allows porting
# from Old Platform APIs to the new APIs).
# It is not needed since Marvell platform already used the new platform APIs.
ENABLE_PLAT_COMPAT
:=
0
# Force builds with BL2 image on a80x0 platforms
ifndef
SCP_BL2
$(error "Error
:
SCP_BL2 image is mandatory for a8k family")
endif
# MSS (SCP) build
include
$(PLAT_COMMON_BASE)/mss/mss_a8k.mk
# BLE (ROM context execution code, AKA binary extension)
BLE_PATH
?=
ble
include
${BLE_PATH}/ble.mk
$(eval
$(call
MAKE_BL,e))
mrvl_flash
:
${BUILD_PLAT}/${FIP_NAME} ${DOIMAGETOOL} ${BUILD_PLAT}/ble.bin
$(
shell
truncate
-s
%128K
${BUILD_PLAT}
/bl1.bin
)
$(
shell
cat
${BUILD_PLAT}
/bl1.bin
${BUILD_PLAT}
/
${FIP_NAME}
>
${BUILD_PLAT}
/
${BOOT_IMAGE}
)
${DOIMAGETOOL}
${DOIMAGE_FLAGS}
${BUILD_PLAT}
/
${BOOT_IMAGE}
${BUILD_PLAT}
/
${FLASH_IMAGE}
plat/marvell/a8k/common/aarch64/a8k_common.c
0 → 100644
View file @
ba0248b5
/*
* Copyright (C) 2018 Marvell International Ltd.
*
* SPDX-License-Identifier: BSD-3-Clause
* https://spdx.org/licenses
*/
#include <plat_marvell.h>
/* MMU entry for internal (register) space access */
#define MAP_DEVICE0 MAP_REGION_FLAT(DEVICE0_BASE, \
DEVICE0_SIZE, \
MT_DEVICE | MT_RW | MT_SECURE)
/*
* Table of regions for various BL stages to map using the MMU.
*/
#if IMAGE_BL1
const
mmap_region_t
plat_marvell_mmap
[]
=
{
MARVELL_MAP_SHARED_RAM
,
MAP_DEVICE0
,
{
0
}
};
#endif
#if IMAGE_BL2
const
mmap_region_t
plat_marvell_mmap
[]
=
{
MARVELL_MAP_SHARED_RAM
,
MAP_DEVICE0
,
MARVELL_MAP_DRAM
,
{
0
}
};
#endif
#if IMAGE_BL2U
const
mmap_region_t
plat_marvell_mmap
[]
=
{
MAP_DEVICE0
,
{
0
}
};
#endif
#if IMAGE_BLE
const
mmap_region_t
plat_marvell_mmap
[]
=
{
MAP_DEVICE0
,
{
0
}
};
#endif
#if IMAGE_BL31
const
mmap_region_t
plat_marvell_mmap
[]
=
{
MARVELL_MAP_SHARED_RAM
,
MAP_DEVICE0
,
MARVELL_MAP_DRAM
,
{
0
}
};
#endif
#if IMAGE_BL32
const
mmap_region_t
plat_marvell_mmap
[]
=
{
MAP_DEVICE0
,
{
0
}
};
#endif
MARVELL_CASSERT_MMAP
;
plat/marvell/a8k/common/aarch64/plat_arch_config.c
0 → 100644
View file @
ba0248b5
/*
* Copyright (C) 2018 Marvell International Ltd.
*
* SPDX-License-Identifier: BSD-3-Clause
* https://spdx.org/licenses
*/
#include <platform.h>
#include <arch_helpers.h>
#include <mmio.h>
#include <debug.h>
#include <cache_llc.h>
#define CCU_HTC_ASET (MVEBU_CCU_BASE(MVEBU_AP0) + 0x264)
#define MVEBU_IO_AFFINITY (0xF00)
static
void
plat_enable_affinity
(
void
)
{
int
cluster_id
;
int
affinity
;
/* set CPU Affinity */
cluster_id
=
plat_my_core_pos
()
/
PLAT_MARVELL_CLUSTER_CORE_COUNT
;
affinity
=
(
MVEBU_IO_AFFINITY
|
(
1
<<
cluster_id
));
mmio_write_32
(
CCU_HTC_ASET
,
affinity
);
/* set barier */
isb
();
}
void
marvell_psci_arch_init
(
int
die_index
)
{
#if LLC_ENABLE
/* check if LLC is in exclusive mode
* as L2 is configured to UniqueClean eviction
* (in a8k reset handler)
*/
if
(
llc_is_exclusive
(
0
)
==
0
)
ERROR
(
"LLC should be configured to exclusice mode
\n
"
);
#endif
/* Enable Affinity */
plat_enable_affinity
();
}
plat/marvell/a8k/common/aarch64/plat_helpers.S
0 → 100644
View file @
ba0248b5
/*
*
Copyright
(
C
)
2018
Marvell
International
Ltd
.
*
*
SPDX
-
License
-
Identifier
:
BSD
-
3
-
Clause
*
https
:
//
spdx
.
org
/
licenses
*/
#include <asm_macros.S>
#include <platform_def.h>
#include <marvell_pm.h>
.
globl
plat_secondary_cold_boot_setup
.
globl
plat_get_my_entrypoint
.
globl
plat_is_my_cpu_primary
.
globl
plat_reset_handler
/
*
-----------------------------------------------------
*
void
plat_secondary_cold_boot_setup
(
void
)
;
*
*
This
function
performs
any
platform
specific
actions
*
needed
for
a
secondary
cpu
after
a
cold
reset
.
Right
*
now
this
is
a
stub
function
.
*
-----------------------------------------------------
*/
func
plat_secondary_cold_boot_setup
mov
x0
,
#
0
ret
endfunc
plat_secondary_cold_boot_setup
/
*
---------------------------------------------------------------------
*
unsigned
long
plat_get_my_entrypoint
(
void
)
;
*
*
Main
job
of
this
routine
is
to
distinguish
*
between
a
cold
and
warm
boot
*
For
a
cold
boot
,
return
0
.
*
For
a
warm
boot
,
read
the
mailbox
and
return
the
address
it
contains
.
*
*
---------------------------------------------------------------------
*/
func
plat_get_my_entrypoint
/
*
Read
first
word
and
compare
it
with
magic
num
*/
mov_imm
x0
,
PLAT_MARVELL_MAILBOX_BASE
ldr
x1
,
[
x0
]
mov_imm
x2
,
MVEBU_MAILBOX_MAGIC_NUM
cmp
x1
,
x2
beq
warm_boot
/*
If
compare
failed
,
return
0
,
i
.
e
.
cold
boot
*/
mov
x0
,
#
0
ret
warm_boot
:
mov_imm
x1
,
MBOX_IDX_SEC_ADDR
/*
Get
the
jump
address
*/
subs
x1
,
x1
,
#
1
mov
x2
,
#(
MBOX_IDX_SEC_ADDR
*
8
)
lsl
x3
,
x2
,
x1
add
x0
,
x0
,
x3
ldr
x0
,
[
x0
]
ret
endfunc
plat_get_my_entrypoint
/
*
-----------------------------------------------------
*
unsigned
int
plat_is_my_cpu_primary
(
void
)
;
*
*
Find
out
whether
the
current
cpu
is
the
primary
*
cpu
.
*
-----------------------------------------------------
*/
func
plat_is_my_cpu_primary
mrs
x0
,
mpidr_el1
and
x0
,
x0
,
#(
MPIDR_CLUSTER_MASK
|
MPIDR_CPU_MASK
)
cmp
x0
,
#
MVEBU_PRIMARY_CPU
cset
w0
,
eq
ret
endfunc
plat_is_my_cpu_primary
/
*
-----------------------------------------------------
*
void
plat_reset_handler
(
void
)
;
*
*
Platform
specific
configuration
right
after
cpu
is
*
is
our
of
reset
.
*
*
The
plat_reset_handler
can
clobber
x0
-
x18
,
x30
.
*
-----------------------------------------------------
*/
func
plat_reset_handler
/
*
*
Note
:
the
configurations
below
should
be
done
before
MMU
,
*
I
Cache
and
L2are
enabled
.
*
The
reset
handler
is
executed
right
after
reset
*
and
before
Caches
are
enabled
.
*/
/
*
Enable
L1
/
L2
ECC
and
Parity
*/
mrs
x5
,
s3_1_c11_c0_2
/*
L2
Ctrl
*/
orr
x5
,
x5
,
#(
1
<<
21
)
/*
Enable
L1
/
L2
cache
ECC
&
Parity
*/
msr
s3_1_c11_c0_2
,
x5
/*
L2
Ctrl
*/
#if LLC_ENABLE
/
*
*
Enable
L2
UniqueClean
evictions
*
Note
:
this
configuration
assumes
that
LLC
is
configured
*
in
exclusive
mode
.
*
Later
on
in
the
code
this
assumption
will
be
validated
*/
mrs
x5
,
s3_1_c15_c0_0
/*
L2
Ctrl
*/
orr
x5
,
x5
,
#(
1
<<
14
)
/*
Enable
UniqueClean
evictions
with
data
*/
msr
s3_1_c15_c0_0
,
x5
/*
L2
Ctrl
*/
#endif
/
*
Instruction
Barrier
to
allow
msr
command
completion
*/
isb
ret
endfunc
plat_reset_handler
plat/marvell/a8k/common/include/a8k_plat_def.h
0 → 100644
View file @
ba0248b5
/*
* Copyright (C) 2018 Marvell International Ltd.
*
* SPDX-License-Identifier: BSD-3-Clause
* https://spdx.org/licenses
*/
#ifndef __A8K_PLAT_DEF_H__
#define __A8K_PLAT_DEF_H__
#include <marvell_def.h>
#define MVEBU_PRIMARY_CPU 0x0
#define MVEBU_AP0 0x0
/* APN806 revision ID */
#define MVEBU_CSS_GWD_CTRL_IIDR2_REG (MVEBU_REGS_BASE + 0x610FCC)
#define GWD_IIDR2_REV_ID_OFFSET 12
#define GWD_IIDR2_REV_ID_MASK 0xF
#define GWD_IIDR2_CHIP_ID_OFFSET 20
#define GWD_IIDR2_CHIP_ID_MASK (0xFFF << GWD_IIDR2_CHIP_ID_OFFSET)
#define CHIP_ID_AP806 0x806
#define CHIP_ID_AP807 0x807
#define COUNTER_FREQUENCY 25000000
#define MVEBU_REGS_BASE 0xF0000000
#define MVEBU_REGS_BASE_MASK 0xF0000000
#define MVEBU_REGS_BASE_AP(ap) MVEBU_REGS_BASE
#define MVEBU_CP_REGS_BASE(cp_index) (0xF2000000 + (cp_index) * 0x2000000)
#define MVEBU_RFU_BASE (MVEBU_REGS_BASE + 0x6F0000)
#define MVEBU_IO_WIN_BASE(ap_index) (MVEBU_RFU_BASE)
#define MVEBU_IO_WIN_GCR_OFFSET (0x70)
#define MVEBU_IO_WIN_MAX_WINS (7)
/* Misc SoC configurations Base */
#define MVEBU_MISC_SOC_BASE (MVEBU_REGS_BASE + 0x6F4300)
#define MVEBU_CCU_BASE(ap_index) (MVEBU_REGS_BASE + 0x4000)
#define MVEBU_CCU_MAX_WINS (8)
#define MVEBU_LLC_BASE(ap_index) (MVEBU_REGS_BASE + 0x8000)
#define MVEBU_DRAM_MAC_BASE (MVEBU_REGS_BASE + 0x20000)
#define MVEBU_DRAM_PHY_BASE (MVEBU_REGS_BASE + 0x20000)
#define MVEBU_SMMU_BASE (MVEBU_REGS_BASE + 0x100000)
#define MVEBU_CP_MPP_REGS(cp_index, n) (MVEBU_CP_REGS_BASE(cp_index) + \
0x440000 + ((n) << 2))
#define MVEBU_PM_MPP_REGS(cp_index, n) (MVEBU_CP_REGS_BASE(cp_index) + \
0x440000 + ((n / 8) << 2))
#define MVEBU_CP_GPIO_DATA_OUT(cp_index, n) \
(MVEBU_CP_REGS_BASE(cp_index) + \
0x440100 + ((n > 32) ? 0x40 : 0x00))
#define MVEBU_CP_GPIO_DATA_OUT_EN(cp_index, n) \
(MVEBU_CP_REGS_BASE(cp_index) + \
0x440104 + ((n > 32) ? 0x40 : 0x00))
#define MVEBU_CP_GPIO_DATA_IN(cp_index, n) (MVEBU_CP_REGS_BASE(cp_index) + \
0x440110 + ((n > 32) ? 0x40 : 0x00))
#define MVEBU_AP_MPP_REGS(n) (MVEBU_RFU_BASE + 0x4000 + ((n) << 2))
#define MVEBU_AP_GPIO_REGS (MVEBU_RFU_BASE + 0x5040)
#define MVEBU_AP_GPIO_DATA_IN (MVEBU_AP_GPIO_REGS + 0x10)
#define MVEBU_AP_I2C_BASE (MVEBU_REGS_BASE + 0x511000)
#define MVEBU_CP0_I2C_BASE (MVEBU_CP_REGS_BASE(0) + 0x701000)
#define MVEBU_AP_EXT_TSEN_BASE (MVEBU_RFU_BASE + 0x8084)
#define MVEBU_AP_MC_TRUSTZONE_REG_LOW(ap, win) (MVEBU_REGS_BASE_AP(ap) + \
0x20080 + ((win) * 0x8))
#define MVEBU_AP_MC_TRUSTZONE_REG_HIGH(ap, win) (MVEBU_REGS_BASE_AP(ap) + \
0x20084 + ((win) * 0x8))
/* MCI indirect access definitions */
#define MCI_MAX_UNIT_ID 2
/* SoC RFU / IHBx4 Control */
#define MCIX4_REG_START_ADDRESS_REG(unit_id) (MVEBU_RFU_BASE + \
0x4218 + (unit_id * 0x20))
#define MCI_REMAP_OFF_SHIFT 8
#define MVEBU_MCI_REG_BASE_REMAP(index) (0xFD000000 + \
((index) * 0x1000000))
#define MVEBU_PCIE_X4_MAC_BASE(x) (MVEBU_CP_REGS_BASE(x) + 0x600000)
#define MVEBU_COMPHY_BASE(x) (MVEBU_CP_REGS_BASE(x) + 0x441000)
#define MVEBU_HPIPE_BASE(x) (MVEBU_CP_REGS_BASE(x) + 0x120000)
#define MVEBU_CP_DFX_OFFSET (0x400200)
/*****************************************************************************
* MVEBU memory map related constants
*****************************************************************************
*/
/* Aggregate of all devices in the first GB */
#define DEVICE0_BASE MVEBU_REGS_BASE
#define DEVICE0_SIZE 0x10000000
/*****************************************************************************
* GIC-400 & interrupt handling related constants
*****************************************************************************
*/
/* Base MVEBU compatible GIC memory map */
#define MVEBU_GICD_BASE 0x210000
#define MVEBU_GICC_BASE 0x220000
/*****************************************************************************
* AXI Configuration
*****************************************************************************
*/
#define MVEBU_AXI_ATTR_ARCACHE_OFFSET 4
#define MVEBU_AXI_ATTR_ARCACHE_MASK (0xF << \
MVEBU_AXI_ATTR_ARCACHE_OFFSET)
#define MVEBU_AXI_ATTR_ARDOMAIN_OFFSET 12
#define MVEBU_AXI_ATTR_ARDOMAIN_MASK (0x3 << \
MVEBU_AXI_ATTR_ARDOMAIN_OFFSET)
#define MVEBU_AXI_ATTR_AWCACHE_OFFSET 20
#define MVEBU_AXI_ATTR_AWCACHE_MASK (0xF << \
MVEBU_AXI_ATTR_AWCACHE_OFFSET)
#define MVEBU_AXI_ATTR_AWDOMAIN_OFFSET 28
#define MVEBU_AXI_ATTR_AWDOMAIN_MASK (0x3 << \
MVEBU_AXI_ATTR_AWDOMAIN_OFFSET)
/* SATA MBUS to AXI configuration */
#define MVEBU_SATA_M2A_AXI_ARCACHE_OFFSET 1
#define MVEBU_SATA_M2A_AXI_ARCACHE_MASK (0xF << \
MVEBU_SATA_M2A_AXI_ARCACHE_OFFSET)
#define MVEBU_SATA_M2A_AXI_AWCACHE_OFFSET 5
#define MVEBU_SATA_M2A_AXI_AWCACHE_MASK (0xF << \
MVEBU_SATA_M2A_AXI_AWCACHE_OFFSET)
/* ARM cache attributes */
#define CACHE_ATTR_BUFFERABLE 0x1
#define CACHE_ATTR_CACHEABLE 0x2
#define CACHE_ATTR_READ_ALLOC 0x4
#define CACHE_ATTR_WRITE_ALLOC 0x8
/* Domain */
#define DOMAIN_NON_SHAREABLE 0x0
#define DOMAIN_INNER_SHAREABLE 0x1
#define DOMAIN_OUTER_SHAREABLE 0x2
#define DOMAIN_SYSTEM_SHAREABLE 0x3
/************************************************************************
* Required platform porting definitions common to all
* Management Compute SubSystems (MSS)
************************************************************************
*/
/*
* Load address of SCP_BL2
* SCP_BL2 is loaded to the same place as BL31.
* Once SCP_BL2 is transferred to the SCP,
* it is discarded and BL31 is loaded over the top.
*/
#ifdef SCP_IMAGE
#define SCP_BL2_BASE BL31_BASE
#endif
#ifndef __ASSEMBLER__
enum
ap806_sar_target_dev
{
SAR_PIDI_MCIX2
=
0x0
,
SAR_MCIX4
=
0x1
,
SAR_SPI
=
0x2
,
SAR_SD
=
0x3
,
SAR_PIDI_MCIX2_BD
=
0x4
,
/* BootRom disabled */
SAR_MCIX4_DB
=
0x5
,
/* BootRom disabled */
SAR_SPI_DB
=
0x6
,
/* BootRom disabled */
SAR_EMMC
=
0x7
};
enum
io_win_target_ids
{
MCI_0_TID
=
0x0
,
MCI_1_TID
=
0x1
,
MCI_2_TID
=
0x2
,
PIDI_TID
=
0x3
,
SPI_TID
=
0x4
,
STM_TID
=
0x5
,
BOOTROM_TID
=
0x6
,
IO_WIN_MAX_TID
};
enum
ccu_target_ids
{
IO_0_TID
=
0x00
,
DRAM_0_TID
=
0x03
,
IO_1_TID
=
0x0F
,
CFG_REG_TID
=
0x10
,
RAR_TID
=
0x20
,
SRAM_TID
=
0x40
,
DRAM_1_TID
=
0xC0
,
CCU_MAX_TID
,
INVALID_TID
=
0xFF
};
#endif
/* __ASSEMBLER__ */
#endif
/* __A8K_PLAT_DEF_H__ */
plat/marvell/a8k/common/include/ddr_info.h
0 → 100644
View file @
ba0248b5
/*
* Copyright (C) 2018 Marvell International Ltd.
*
* SPDX-License-Identifier: BSD-3-Clause
* https://spdx.org/licenses
*/
#define DRAM_MAX_IFACE 1
#define DRAM_CH0_MMAP_LOW_OFFSET 0x20200
plat/marvell/a8k/common/include/plat_macros.S
0 → 100644
View file @
ba0248b5
/*
*
Copyright
(
C
)
2018
Marvell
International
Ltd
.
*
*
SPDX
-
License
-
Identifier
:
BSD
-
3
-
Clause
*
https
:
//
spdx
.
org
/
licenses
*/
#ifndef __PLAT_MACROS_S__
#define __PLAT_MACROS_S__
#include <marvell_macros.S>
/*
*
Required
platform
porting
macros
*
(
Provided
by
included
headers
)
*/
.
macro
plat_crash_print_regs
.
endm
#endif /* __PLAT_MACROS_S__ */
plat/marvell/a8k/common/include/platform_def.h
0 → 100644
View file @
ba0248b5
/*
* Copyright (C) 2018 Marvell International Ltd.
*
* SPDX-License-Identifier: BSD-3-Clause
* https://spdx.org/licenses
*/
#ifndef __PLATFORM_DEF_H__
#define __PLATFORM_DEF_H__
#include <board_marvell_def.h>
#include <gic_common.h>
#include <interrupt_props.h>
#include <mvebu_def.h>
#ifndef __ASSEMBLY__
#include <stdio.h>
#endif
/* __ASSEMBLY__ */
/*
* Most platform porting definitions provided by included headers
*/
/*
* DRAM Memory layout:
* +-----------------------+
* : :
* : Linux :
* 0x04X00000-->+-----------------------+
* | BL3-3(u-boot) |>>}>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
* |-----------------------| } |
* | BL3-[0,1, 2] | }---------------------------------> |
* |-----------------------| } || |
* | BL2 | }->FIP (loaded by || |
* |-----------------------| } BootROM to DRAM) || |
* | FIP_TOC | } || |
* 0x04120000-->|-----------------------| || |
* | BL1 (RO) | || |
* 0x04100000-->+-----------------------+ || |
* : : || |
* : Trusted SRAM section : \/ |
* 0x04040000-->+-----------------------+ Replaced by BL2 +----------------+ |
* | BL1 (RW) | <<<<<<<<<<<<<<<< | BL3-1 NOBITS | |
* 0x04037000-->|-----------------------| <<<<<<<<<<<<<<<< |----------------| |
* | | <<<<<<<<<<<<<<<< | BL3-1 PROGBITS | |
* 0x04023000-->|-----------------------| +----------------+ |
* | BL2 | |
* |-----------------------| |
* | | |
* 0x04001000-->|-----------------------| |
* | Shared | |
* 0x04000000-->+-----------------------+ |
* : : |
* : Linux : |
* : : |
* |-----------------------| |
* | | U-Boot(BL3-3) Loaded by BL2 |
* | U-Boot | <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
* 0x00000000-->+-----------------------+
*
* Trusted SRAM section 0x4000000..0x4200000:
* ----------------------------------------
* SRAM_BASE = 0x4001000
* BL2_BASE = 0x4006000
* BL2_LIMIT = BL31_BASE
* BL31_BASE = 0x4023000 = (64MB + 256KB - 0x1D000)
* BL31_PROGBITS_LIMIT = BL1_RW_BASE
* BL1_RW_BASE = 0x4037000 = (64MB + 256KB - 0x9000)
* BL1_RW_LIMIT = BL31_LIMIT = 0x4040000
*
*
* PLAT_MARVELL_FIP_BASE = 0x4120000
*/
/*
* Since BL33 is loaded by BL2 (and validated by BL31) to DRAM offset 0,
* it is allowed to load/copy images to 'NULL' pointers
*/
#if defined(IMAGE_BL2) || defined(IMAGE_BL31)
#define PLAT_ALLOW_ZERO_ADDR_COPY
#endif
#define PLAT_MARVELL_SRAM_BASE 0xFFE1C048
#define PLAT_MARVELL_SRAM_END 0xFFE78000
#define PLAT_MARVELL_ATF_BASE 0x4000000
#define PLAT_MARVELL_ATF_LOAD_ADDR (PLAT_MARVELL_ATF_BASE + \
0x100000)
#define PLAT_MARVELL_FIP_BASE (PLAT_MARVELL_ATF_LOAD_ADDR + \
0x20000)
#define PLAT_MARVELL_FIP_MAX_SIZE 0x4000000
#define PLAT_MARVELL_NORTHB_COUNT 1
#define PLAT_MARVELL_CLUSTER_COUNT 2
#define PLAT_MARVELL_CLUSTER_CORE_COUNT 2
#define PLAT_MARVELL_CORE_COUNT (PLAT_MARVELL_CLUSTER_COUNT * \
PLAT_MARVELL_CLUSTER_CORE_COUNT)
/* DRAM[2MB..66MB] is used as Trusted ROM */
#define PLAT_MARVELL_TRUSTED_ROM_BASE PLAT_MARVELL_ATF_LOAD_ADDR
/* 64 MB TODO: reduce this to minimum needed according to fip image size */
#define PLAT_MARVELL_TRUSTED_ROM_SIZE 0x04000000
/* Reserve 16M for SCP (Secure PayLoad) Trusted DRAM */
#define PLAT_MARVELL_TRUSTED_DRAM_BASE 0x04400000
#define PLAT_MARVELL_TRUSTED_DRAM_SIZE 0x01000000
/* 16 MB */
/*
* PLAT_ARM_MAX_BL1_RW_SIZE is calculated using the current BL1 RW debug size
* plus a little space for growth.
*/
#define PLAT_MARVELL_MAX_BL1_RW_SIZE 0xA000
/*
* PLAT_ARM_MAX_BL2_SIZE is calculated using the current BL2 debug size plus a
* little space for growth.
*/
#define PLAT_MARVELL_MAX_BL2_SIZE 0xF000
/*
* PLAT_ARM_MAX_BL31_SIZE is calculated using the current BL31 debug size plus a
* little space for growth.
*/
#define PLAT_MARVEL_MAX_BL31_SIZE 0x5D000
#define PLAT_MARVELL_CPU_ENTRY_ADDR BL1_RO_BASE
/* GIC related definitions */
#define PLAT_MARVELL_GICD_BASE (MVEBU_REGS_BASE + MVEBU_GICD_BASE)
#define PLAT_MARVELL_GICC_BASE (MVEBU_REGS_BASE + MVEBU_GICC_BASE)
#define PLAT_MARVELL_G0_IRQ_PROPS(grp) \
INTR_PROP_DESC(MARVELL_IRQ_SEC_SGI_0, GIC_HIGHEST_SEC_PRIORITY, grp, \
GIC_INTR_CFG_LEVEL), \
INTR_PROP_DESC(MARVELL_IRQ_SEC_SGI_6, GIC_HIGHEST_SEC_PRIORITY, grp, \
GIC_INTR_CFG_LEVEL)
#define PLAT_MARVELL_G1S_IRQ_PROPS(grp) \
INTR_PROP_DESC(MARVELL_IRQ_SEC_PHY_TIMER, GIC_HIGHEST_SEC_PRIORITY, \
grp, GIC_INTR_CFG_LEVEL), \
INTR_PROP_DESC(MARVELL_IRQ_SEC_SGI_1, GIC_HIGHEST_SEC_PRIORITY, grp, \
GIC_INTR_CFG_LEVEL), \
INTR_PROP_DESC(MARVELL_IRQ_SEC_SGI_2, GIC_HIGHEST_SEC_PRIORITY, grp, \
GIC_INTR_CFG_LEVEL), \
INTR_PROP_DESC(MARVELL_IRQ_SEC_SGI_3, GIC_HIGHEST_SEC_PRIORITY, grp, \
GIC_INTR_CFG_LEVEL), \
INTR_PROP_DESC(MARVELL_IRQ_SEC_SGI_4, GIC_HIGHEST_SEC_PRIORITY, grp, \
GIC_INTR_CFG_LEVEL), \
INTR_PROP_DESC(MARVELL_IRQ_SEC_SGI_5, GIC_HIGHEST_SEC_PRIORITY, grp, \
GIC_INTR_CFG_LEVEL), \
INTR_PROP_DESC(MARVELL_IRQ_SEC_SGI_7, GIC_HIGHEST_SEC_PRIORITY, grp, \
GIC_INTR_CFG_LEVEL)
#define PLAT_MARVELL_SHARED_RAM_CACHED 1
/*
* Load address of BL3-3 for this platform port
*/
#define PLAT_MARVELL_NS_IMAGE_OFFSET 0x0
/* System Reference Clock*/
#define PLAT_REF_CLK_IN_HZ COUNTER_FREQUENCY
/*
* PL011 related constants
*/
#define PLAT_MARVELL_BOOT_UART_BASE (MVEBU_REGS_BASE + 0x512000)
#define PLAT_MARVELL_BOOT_UART_CLK_IN_HZ 200000000
#define PLAT_MARVELL_CRASH_UART_BASE PLAT_MARVELL_BOOT_UART_BASE
#define PLAT_MARVELL_CRASH_UART_CLK_IN_HZ PLAT_MARVELL_BOOT_UART_CLK_IN_HZ
#define PLAT_MARVELL_BL31_RUN_UART_BASE PLAT_MARVELL_BOOT_UART_BASE
#define PLAT_MARVELL_BL31_RUN_UART_CLK_IN_HZ PLAT_MARVELL_BOOT_UART_CLK_IN_HZ
/* Recovery image enable */
#define PLAT_RECOVERY_IMAGE_ENABLE 0
/* Required platform porting definitions */
#define PLAT_MAX_PWR_LVL MPIDR_AFFLVL1
/* System timer related constants */
#define PLAT_MARVELL_NSTIMER_FRAME_ID 1
/* Mailbox base address (note the lower memory space
* is reserved for BLE data)
*/
#define PLAT_MARVELL_MAILBOX_BASE (MARVELL_TRUSTED_SRAM_BASE \
+ 0x400)
#define PLAT_MARVELL_MAILBOX_SIZE 0x100
#define PLAT_MARVELL_MAILBOX_MAGIC_NUM 0x6D72766C
/* mrvl */
/* Securities */
#define IRQ_SEC_OS_TICK_INT MARVELL_IRQ_SEC_PHY_TIMER
#define TRUSTED_DRAM_BASE PLAT_MARVELL_TRUSTED_DRAM_BASE
#define TRUSTED_DRAM_SIZE PLAT_MARVELL_TRUSTED_DRAM_SIZE
#define BL32_BASE TRUSTED_DRAM_BASE
#endif
/* __PLATFORM_DEF_H__ */
Prev
1
2
3
4
5
6
Next
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