Unverified Commit eb47f14d authored by Antonio Niño Díaz's avatar Antonio Niño Díaz Committed by GitHub
Browse files

Merge pull request #1623 from MISL-EBU-System-SW/a3700-support

Add support for Armada 3700 and COMPHY porting layer
parents d03823d4 1e66bacb
Showing with 2698 additions and 292 deletions
+2698 -292
.. _porting:
TF-A Porting Guide
=================
......@@ -64,3 +66,53 @@ Armada-70x0/Armada-80x0 Porting
- Please refer to '<path_to_mv_ddr_sources>/doc/porting_guide.txt' for detailed porting description.
- The build target directory is "build/<platform>/release/ble".
- Comphy Porting (phy-porting-layer.h or phy-default-porting-layer.h)
- Background:
Some of the comphy's parameters value depend on the HW connection between the SoC and the PHY. Every
board type has specific HW characteristics like wire length. Due to those differences some comphy
parameters vary between board types. Therefore each board type can have its own list of values for
all relevant comphy parameters. The PHY porting layer specifies which parameters need to be suited and
the board designer should provide relevant values.
.. seealso::
For XFI/SFI comphy type there is procedure "rx_training" which eases process of suiting some of
the parameters. Please see :ref:`uboot_cmd` section: rx_training.
The PHY porting layer simplifies updating static values per board type, which are now grouped in one place.
.. note::
The parameters for the same type of comphy may vary even for the same board type, it is because
the lanes from comphy-x to some PHY may have different HW characteristic than lanes from
comphy-y to the same (multiplexed) or other PHY.
- Porting:
The porting layer for PHY was introduced in TF-A. There is one file
``drivers/marvell/comphy/phy-default-porting-layer.h`` which contains the defaults. Those default
parameters are used only if there is no appropriate phy-porting-layer.h file under:
``plat/marvell/<soc family>/<platform>/board/phy-porting-layer.h``. If the phy-porting-layer.h exists,
the phy-default-porting-layer.h is not going to be included.
.. warning::
Not all comphy types are already reworked to support the PHY porting layer, currently the porting
layer is supported for XFI/SFI and SATA comphy types.
The easiest way to prepare the PHY porting layer for custom board is to copy existing example to a new
platform:
- cp ``plat/marvell/a8k/a80x0/board/phy-porting-layer.h`` "plat/marvell/<soc family>/<platform>/board/phy-porting-layer.h"
- adjust relevant parameters or
- if different comphy index is used for specific feature, move it to proper table entry and then adjust.
.. note::
The final table size with comphy parameters can be different, depending on the CP module count for
given SoC type.
- Example:
Example porting layer for armada-8040-db is under: ``plat/marvell/a8k/a80x0/board/phy-porting-layer.h``
.. note::
If there is no PHY porting layer for new platform (missing phy-porting-layer.h), the default
values are used (drivers/marvell/comphy/phy-default-porting-layer.h) and the user is warned:
.. warning::
"Using default comphy parameters - it may be required to suit them for your board".
......@@ -199,6 +199,11 @@
#define HPIPE_DFE_F3_F5_DFE_CTRL_MASK \
(0x1 << HPIPE_DFE_F3_F5_DFE_CTRL_OFFSET)
#define HPIPE_ADAPTED_DFE_COEFFICIENT_1_REG 0x30
#define HPIPE_ADAPTED_DFE_RES_OFFSET 13
#define HPIPE_ADAPTED_DFE_RES_MASK \
(0x3 << HPIPE_ADAPTED_DFE_RES_OFFSET)
#define HPIPE_G1_SET_0_REG 0x34
#define HPIPE_G1_SET_0_G1_TX_AMP_OFFSET 1
#define HPIPE_G1_SET_0_G1_TX_AMP_MASK \
......@@ -326,6 +331,16 @@
#define HPIPE_PHY_TEST_DATA_MASK \
(0xffff << HPIPE_PHY_TEST_DATA_OFFSET)
#define HPIPE_PHY_TEST_PRBS_ERROR_COUNTER_1_REG 0x80
#define HPIPE_PHY_TEST_OOB_0_REGISTER 0x84
#define HPIPE_PHY_PT_OOB_EN_OFFSET 14
#define HPIPE_PHY_PT_OOB_EN_MASK \
(0x1 << HPIPE_PHY_PT_OOB_EN_OFFSET)
#define HPIPE_PHY_TEST_PT_TESTMODE_OFFSET 12
#define HPIPE_PHY_TEST_PT_TESTMODE_MASK \
(0x3 << HPIPE_PHY_TEST_PT_TESTMODE_OFFSET)
#define HPIPE_LOOPBACK_REG 0x8c
#define HPIPE_LOOPBACK_SEL_OFFSET 1
#define HPIPE_LOOPBACK_SEL_MASK \
......@@ -357,10 +372,27 @@
(0x1 << HPIPE_G1_SET_2_G1_TX_EMPH0_EN_OFFSET)
#define HPIPE_G2_SET_2_REG 0xf8
#define HPIPE_G2_SET_2_G2_TX_EMPH0_OFFSET 0
#define HPIPE_G2_SET_2_G2_TX_EMPH0_MASK \
(0xf << HPIPE_G2_SET_2_G2_TX_EMPH0_OFFSET)
#define HPIPE_G2_SET_2_G2_TX_EMPH0_EN_OFFSET 4
#define HPIPE_G2_SET_2_G2_TX_EMPH0_EN_MASK \
(0x1 << HPIPE_G2_SET_2_G2_TX_EMPH0_EN_OFFSET)
#define HPIPE_G2_TX_SSC_AMP_OFFSET 9
#define HPIPE_G2_TX_SSC_AMP_MASK \
(0x7f << HPIPE_G2_TX_SSC_AMP_OFFSET)
#define HPIPE_G3_SET_2_REG 0xfc
#define HPIPE_G3_SET_2_G3_TX_EMPH0_OFFSET 0
#define HPIPE_G3_SET_2_G3_TX_EMPH0_MASK \
(0xf << HPIPE_G3_SET_2_G3_TX_EMPH0_OFFSET)
#define HPIPE_G3_SET_2_G3_TX_EMPH0_EN_OFFSET 4
#define HPIPE_G3_SET_2_G3_TX_EMPH0_EN_MASK \
(0x1 << HPIPE_G3_SET_2_G3_TX_EMPH0_EN_OFFSET)
#define HPIPE_G3_TX_SSC_AMP_OFFSET 9
#define HPIPE_G3_TX_SSC_AMP_MASK \
(0x7f << HPIPE_G3_TX_SSC_AMP_OFFSET)
#define HPIPE_VDD_CAL_0_REG 0x108
#define HPIPE_CAL_VDD_CONT_MODE_OFFSET 15
#define HPIPE_CAL_VDD_CONT_MODE_MASK \
......@@ -434,6 +466,15 @@
#define HPIPE_SPD_DIV_FORCE_TX_SPD_DIV_FORCE_MASK \
(0x1 << HPIPE_SPD_DIV_FORCE_TX_SPD_DIV_FORCE_OFFSET)
/* HPIPE_RX_CLK_ALIGN90_AND_TX_IDLE_CALIBRATION_CTRL_REG */
#define HPIPE_RX_CLK_ALIGN90_AND_TX_IDLE_CALIB_CTRL_REG 0x168
#define HPIPE_CAL_RXCLKALIGN_90_EXT_EN_OFFSET 15
#define HPIPE_CAL_RXCLKALIGN_90_EXT_EN_MASK \
(0x1 << HPIPE_CAL_RXCLKALIGN_90_EXT_EN_OFFSET)
#define HPIPE_CAL_OS_PH_EXT_OFFSET 8
#define HPIPE_CAL_OS_PH_EXT_MASK \
(0x7f << HPIPE_CAL_OS_PH_EXT_OFFSET)
#define HPIPE_SAMPLER_N_PROC_CALIB_CTRL_REG 0x16C
#define HPIPE_RX_SAMPLER_OS_GAIN_OFFSET 6
#define HPIPE_RX_SAMPLER_OS_GAIN_MASK \
......@@ -484,6 +525,19 @@
#define HPIPE_OS_PH_VALID_MASK \
(0x1 << HPIPE_OS_PH_VALID_OFFSET)
#define HPIPE_DATA_PHASE_OFF_CTRL_REG 0x1A0
#define HPIPE_DATA_PHASE_ADAPTED_OS_PH_OFFSET 9
#define HPIPE_DATA_PHASE_ADAPTED_OS_PH_MASK \
(0x7f << HPIPE_DATA_PHASE_ADAPTED_OS_PH_OFFSET)
#define HPIPE_ADAPTED_FFE_CAPACITOR_COUNTER_CTRL_REG 0x1A4
#define HPIPE_ADAPTED_FFE_ADAPTED_FFE_RES_OFFSET 12
#define HPIPE_ADAPTED_FFE_ADAPTED_FFE_RES_MASK \
(0x3 << HPIPE_ADAPTED_FFE_ADAPTED_FFE_RES_OFFSET)
#define HPIPE_ADAPTED_FFE_ADAPTED_FFE_CAP_OFFSET 8
#define HPIPE_ADAPTED_FFE_ADAPTED_FFE_CAP_MASK \
(0xf << HPIPE_ADAPTED_FFE_ADAPTED_FFE_CAP_OFFSET)
#define HPIPE_SQ_GLITCH_FILTER_CTRL 0x1c8
#define HPIPE_SQ_DEGLITCH_WIDTH_P_OFFSET 0
#define HPIPE_SQ_DEGLITCH_WIDTH_P_MASK \
......@@ -510,6 +564,26 @@
#define HPIPE_DME_ETHERNET_MODE_MASK \
(0x1 << HPIPE_DME_ETHERNET_MODE_OFFSET)
#define HPIPE_TRX_TRAIN_CTRL_0_REG 0x22c
#define HPIPE_TRX_TX_F0T_EO_BASED_OFFSET 14
#define HPIPE_TRX_TX_F0T_EO_BASED_MASK \
(1 << HPIPE_TRX_TX_F0T_EO_BASED_OFFSET)
#define HPIPE_TRX_UPDATE_THEN_HOLD_OFFSET 6
#define HPIPE_TRX_UPDATE_THEN_HOLD_MASK \
(1 << HPIPE_TRX_UPDATE_THEN_HOLD_OFFSET)
#define HPIPE_TRX_TX_CTRL_CLK_EN_OFFSET 5
#define HPIPE_TRX_TX_CTRL_CLK_EN_MASK \
(1 << HPIPE_TRX_TX_CTRL_CLK_EN_OFFSET)
#define HPIPE_TRX_RX_ANA_IF_CLK_ENE_OFFSET 4
#define HPIPE_TRX_RX_ANA_IF_CLK_ENE_MASK \
(1 << HPIPE_TRX_RX_ANA_IF_CLK_ENE_OFFSET)
#define HPIPE_TRX_TX_TRAIN_EN_OFFSET 1
#define HPIPE_TRX_TX_TRAIN_EN_MASK \
(1 << HPIPE_TRX_TX_TRAIN_EN_OFFSET)
#define HPIPE_TRX_RX_TRAIN_EN_OFFSET 0
#define HPIPE_TRX_RX_TRAIN_EN_MASK \
(1 << HPIPE_TRX_RX_TRAIN_EN_OFFSET)
#define HPIPE_TX_TRAIN_CTRL_0_REG 0x268
#define HPIPE_TX_TRAIN_P2P_HOLD_OFFSET 15
#define HPIPE_TX_TRAIN_P2P_HOLD_MASK \
......@@ -548,6 +622,23 @@
#define HPIPE_TX_TRAIN_WAIT_TIME_EN_MASK \
(0x1 << HPIPE_TX_TRAIN_WAIT_TIME_EN_OFFSET)
#define HPIPE_INTERRUPT_1_REGISTER 0x2AC
#define HPIPE_TRX_TRAIN_FAILED_OFFSET 6
#define HPIPE_TRX_TRAIN_FAILED_MASK \
(1 << HPIPE_TRX_TRAIN_FAILED_OFFSET)
#define HPIPE_TRX_TRAIN_TIME_OUT_INT_OFFSET 5
#define HPIPE_TRX_TRAIN_TIME_OUT_INT_MASK \
(1 << HPIPE_TRX_TRAIN_TIME_OUT_INT_OFFSET)
#define HPIPE_INTERRUPT_TRX_TRAIN_DONE_OFFSET 4
#define HPIPE_INTERRUPT_TRX_TRAIN_DONE_MASK \
(1 << HPIPE_INTERRUPT_TRX_TRAIN_DONE_OFFSET)
#define HPIPE_INTERRUPT_DFE_DONE_INT_OFFSET 3
#define HPIPE_INTERRUPT_DFE_DONE_INT_MASK \
(1 << HPIPE_INTERRUPT_DFE_DONE_INT_OFFSET)
#define HPIPE_INTERRUPT_RX_TRAIN_COMPLETE_INT_OFFSET 1
#define HPIPE_INTERRUPT_RX_TRAIN_COMPLETE_INT_MASK \
(1 << HPIPE_INTERRUPT_RX_TRAIN_COMPLETE_INT_OFFSET)
#define HPIPE_TX_TRAIN_REG 0x31C
#define HPIPE_TX_TRAIN_CHK_INIT_OFFSET 4
#define HPIPE_TX_TRAIN_CHK_INIT_MASK \
......
/*
* Copyright (C) 2018 Marvell International Ltd.
*
* SPDX-License-Identifier: BSD-3-Clause
* https://spdx.org/licenses
*/
#include <debug.h>
#include <delay_timer.h>
#include <errno.h>
#include <mmio.h>
#include <mvebu.h>
#include <mvebu_def.h>
#include <spinlock.h>
#include "phy-comphy-3700.h"
#include "phy-comphy-common.h"
/*
* COMPHY_INDIRECT_REG points to ahci address space but the ahci region used in
* Linux is up to 0x178 so none will access it from Linux in runtime
* concurrently.
*/
#define COMPHY_INDIRECT_REG (MVEBU_REGS_BASE + 0xE0178)
/* The USB3_GBE1_PHY range is above USB3 registers used in dts */
#define USB3_GBE1_PHY (MVEBU_REGS_BASE + 0x5C000)
#define COMPHY_SD_ADDR (MVEBU_REGS_BASE + 0x1F000)
/*
* Below address in used only for reading, therefore no problem with concurrent
* Linux access.
*/
#define MVEBU_TEST_PIN_LATCH_N (MVEBU_NB_GPIO_REG_BASE + 0x8)
#define MVEBU_XTAL_MODE_MASK BIT(9)
#define MVEBU_XTAL_MODE_OFFS 9
#define MVEBU_XTAL_CLOCK_25MHZ 0x0
struct sgmii_phy_init_data_fix {
uint16_t addr;
uint16_t value;
};
/* Changes to 40M1G25 mode data required for running 40M3G125 init mode */
static struct sgmii_phy_init_data_fix sgmii_phy_init_fix[] = {
{0x005, 0x07CC}, {0x015, 0x0000}, {0x01B, 0x0000}, {0x01D, 0x0000},
{0x01E, 0x0000}, {0x01F, 0x0000}, {0x020, 0x0000}, {0x021, 0x0030},
{0x026, 0x0888}, {0x04D, 0x0152}, {0x04F, 0xA020}, {0x050, 0x07CC},
{0x053, 0xE9CA}, {0x055, 0xBD97}, {0x071, 0x3015}, {0x076, 0x03AA},
{0x07C, 0x0FDF}, {0x0C2, 0x3030}, {0x0C3, 0x8000}, {0x0E2, 0x5550},
{0x0E3, 0x12A4}, {0x0E4, 0x7D00}, {0x0E6, 0x0C83}, {0x101, 0xFCC0},
{0x104, 0x0C10}
};
/* 40M1G25 mode init data */
static uint16_t sgmii_phy_init[512] = {
/* 0 1 2 3 4 5 6 7 */
/*-----------------------------------------------------------*/
/* 8 9 A B C D E F */
0x3110, 0xFD83, 0x6430, 0x412F, 0x82C0, 0x06FA, 0x4500, 0x6D26, /* 00 */
0xAFC0, 0x8000, 0xC000, 0x0000, 0x2000, 0x49CC, 0x0BC9, 0x2A52, /* 08 */
0x0BD2, 0x0CDE, 0x13D2, 0x0CE8, 0x1149, 0x10E0, 0x0000, 0x0000, /* 10 */
0x0000, 0x0000, 0x0000, 0x0001, 0x0000, 0x4134, 0x0D2D, 0xFFFF, /* 18 */
0xFFE0, 0x4030, 0x1016, 0x0030, 0x0000, 0x0800, 0x0866, 0x0000, /* 20 */
0x0000, 0x0000, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, /* 28 */
0xFFFF, 0xFFFF, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 30 */
0x0000, 0x0000, 0x000F, 0x6A62, 0x1988, 0x3100, 0x3100, 0x3100, /* 38 */
0x3100, 0xA708, 0x2430, 0x0830, 0x1030, 0x4610, 0xFF00, 0xFF00, /* 40 */
0x0060, 0x1000, 0x0400, 0x0040, 0x00F0, 0x0155, 0x1100, 0xA02A, /* 48 */
0x06FA, 0x0080, 0xB008, 0xE3ED, 0x5002, 0xB592, 0x7A80, 0x0001, /* 50 */
0x020A, 0x8820, 0x6014, 0x8054, 0xACAA, 0xFC88, 0x2A02, 0x45CF, /* 58 */
0x000F, 0x1817, 0x2860, 0x064F, 0x0000, 0x0204, 0x1800, 0x6000, /* 60 */
0x810F, 0x4F23, 0x4000, 0x4498, 0x0850, 0x0000, 0x000E, 0x1002, /* 68 */
0x9D3A, 0x3009, 0xD066, 0x0491, 0x0001, 0x6AB0, 0x0399, 0x3780, /* 70 */
0x0040, 0x5AC0, 0x4A80, 0x0000, 0x01DF, 0x0000, 0x0007, 0x0000, /* 78 */
0x2D54, 0x00A1, 0x4000, 0x0100, 0xA20A, 0x0000, 0x0000, 0x0000, /* 80 */
0x0000, 0x0000, 0x0000, 0x7400, 0x0E81, 0x1000, 0x1242, 0x0210, /* 88 */
0x80DF, 0x0F1F, 0x2F3F, 0x4F5F, 0x6F7F, 0x0F1F, 0x2F3F, 0x4F5F, /* 90 */
0x6F7F, 0x4BAD, 0x0000, 0x0000, 0x0800, 0x0000, 0x2400, 0xB651, /* 98 */
0xC9E0, 0x4247, 0x0A24, 0x0000, 0xAF19, 0x1004, 0x0000, 0x0000, /* A0 */
0x0000, 0x0013, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* A8 */
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* B0 */
0x0000, 0x0000, 0x0000, 0x0060, 0x0000, 0x0000, 0x0000, 0x0000, /* B8 */
0x0000, 0x0000, 0x3010, 0xFA00, 0x0000, 0x0000, 0x0000, 0x0003, /* C0 */
0x1618, 0x8200, 0x8000, 0x0400, 0x050F, 0x0000, 0x0000, 0x0000, /* C8 */
0x4C93, 0x0000, 0x1000, 0x1120, 0x0010, 0x1242, 0x1242, 0x1E00, /* D0 */
0x0000, 0x0000, 0x0000, 0x00F8, 0x0000, 0x0041, 0x0800, 0x0000, /* D8 */
0x82A0, 0x572E, 0x2490, 0x14A9, 0x4E00, 0x0000, 0x0803, 0x0541, /* E0 */
0x0C15, 0x0000, 0x0000, 0x0400, 0x2626, 0x0000, 0x0000, 0x4200, /* E8 */
0x0000, 0xAA55, 0x1020, 0x0000, 0x0000, 0x5010, 0x0000, 0x0000, /* F0 */
0x0000, 0x0000, 0x5000, 0x0000, 0x0000, 0x0000, 0x02F2, 0x0000, /* F8 */
0x101F, 0xFDC0, 0x4000, 0x8010, 0x0110, 0x0006, 0x0000, 0x0000, /*100 */
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /*108 */
0x04CF, 0x0000, 0x04CF, 0x0000, 0x04CF, 0x0000, 0x04C6, 0x0000, /*110 */
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /*118 */
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /*120 */
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /*128 */
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /*130 */
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /*138 */
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /*140 */
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /*148 */
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /*150 */
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /*158 */
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /*160 */
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /*168 */
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /*170 */
0x0000, 0x0000, 0x0000, 0x00F0, 0x08A2, 0x3112, 0x0A14, 0x0000, /*178 */
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /*180 */
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /*188 */
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /*190 */
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /*198 */
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /*1A0 */
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /*1A8 */
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /*1B0 */
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /*1B8 */
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /*1C0 */
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /*1C8 */
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /*1D0 */
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /*1D8 */
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /*1E0 */
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /*1E8 */
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /*1F0 */
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 /*1F8 */
};
/* returns reference clock in MHz (25 or 40) */
static uint32_t get_ref_clk(void)
{
uint32_t val;
val = (mmio_read_32(MVEBU_TEST_PIN_LATCH_N) & MVEBU_XTAL_MODE_MASK) >>
MVEBU_XTAL_MODE_OFFS;
if (val == MVEBU_XTAL_CLOCK_25MHZ)
return 25;
else
return 40;
}
/* PHY selector configures with corresponding modes */
static void mvebu_a3700_comphy_set_phy_selector(uint8_t comphy_index,
uint32_t comphy_mode)
{
uint32_t reg;
int mode = COMPHY_GET_MODE(comphy_mode);
reg = mmio_read_32(MVEBU_COMPHY_REG_BASE + COMPHY_SELECTOR_PHY_REG);
switch (mode) {
case (COMPHY_SATA_MODE):
/* SATA must be in Lane2 */
if (comphy_index == COMPHY_LANE2)
reg &= ~COMPHY_SELECTOR_USB3_PHY_SEL_BIT;
else
goto error;
break;
case (COMPHY_SGMII_MODE):
case (COMPHY_HS_SGMII_MODE):
if (comphy_index == COMPHY_LANE0)
reg &= ~COMPHY_SELECTOR_USB3_GBE1_SEL_BIT;
else if (comphy_index == COMPHY_LANE1)
reg &= ~COMPHY_SELECTOR_PCIE_GBE0_SEL_BIT;
else
goto error;
break;
case (COMPHY_USB3H_MODE):
case (COMPHY_USB3D_MODE):
case (COMPHY_USB3_MODE):
if (comphy_index == COMPHY_LANE2)
reg |= COMPHY_SELECTOR_USB3_PHY_SEL_BIT;
else if (comphy_index == COMPHY_LANE0)
reg |= COMPHY_SELECTOR_USB3_GBE1_SEL_BIT;
else
goto error;
break;
case (COMPHY_PCIE_MODE):
/* PCIE must be in Lane1 */
if (comphy_index == COMPHY_LANE1)
reg |= COMPHY_SELECTOR_PCIE_GBE0_SEL_BIT;
else
goto error;
break;
default:
goto error;
}
mmio_write_32(MVEBU_COMPHY_REG_BASE + COMPHY_SELECTOR_PHY_REG, reg);
return;
error:
ERROR("COMPHY[%d] mode[%d] is invalid\n", comphy_index, mode);
}
/* It is only used for SATA and USB3 on comphy lane2. */
static void comphy_set_indirect(uintptr_t addr, uint32_t offset, uint16_t data,
uint16_t mask, int mode)
{
/*
* When Lane 2 PHY is for USB3, access the PHY registers
* through indirect Address and Data registers:
* INDIR_ACC_PHY_ADDR (RD00E0178h [31:0]),
* INDIR_ACC_PHY_DATA (RD00E017Ch [31:0]),
* within the SATA Host Controller registers, Lane 2 base register
* offset is 0x200
*/
if (mode == COMPHY_UNUSED)
return;
if (mode == COMPHY_SATA_MODE)
mmio_write_32(addr + COMPHY_LANE2_INDIR_ADDR_OFFSET, offset);
else
mmio_write_32(addr + COMPHY_LANE2_INDIR_ADDR_OFFSET,
offset + USB3PHY_LANE2_REG_BASE_OFFSET);
reg_set(addr + COMPHY_LANE2_INDIR_DATA_OFFSET, data, mask);
}
/* It is only used USB3 direct access not on comphy lane2. */
static void comphy_usb3_set_direct(uintptr_t addr, uint32_t reg_offset,
uint16_t data, uint16_t mask, int mode)
{
reg_set16((reg_offset * PHY_SHFT(USB3) + addr), data, mask);
}
static void comphy_sgmii_phy_init(uint32_t comphy_index, uint32_t mode,
uintptr_t sd_ip_addr)
{
const int fix_arr_sz = ARRAY_SIZE(sgmii_phy_init_fix);
int addr, fix_idx;
uint16_t val;
fix_idx = 0;
for (addr = 0; addr < 512; addr++) {
/*
* All PHY register values are defined in full for 3.125Gbps
* SERDES speed. The values required for 1.25 Gbps are almost
* the same and only few registers should be "fixed" in
* comparison to 3.125 Gbps values. These register values are
* stored in "sgmii_phy_init_fix" array.
*/
if ((mode != COMPHY_SGMII_MODE) &&
(sgmii_phy_init_fix[fix_idx].addr == addr)) {
/* Use new value */
val = sgmii_phy_init_fix[fix_idx].value;
if (fix_idx < fix_arr_sz)
fix_idx++;
} else {
val = sgmii_phy_init[addr];
}
reg_set16(SGMIIPHY_ADDR(addr, sd_ip_addr), val, 0xFFFF);
}
}
static int mvebu_a3700_comphy_sata_power_on(uint8_t comphy_index,
uint32_t comphy_mode)
{
int ret = 0;
uint32_t offset, data = 0, ref_clk;
uintptr_t comphy_indir_regs = COMPHY_INDIRECT_REG;
int mode = COMPHY_GET_MODE(comphy_mode);
int invert = COMPHY_GET_POLARITY_INVERT(comphy_mode);
debug_enter();
/* Configure phy selector for SATA */
mvebu_a3700_comphy_set_phy_selector(comphy_index, comphy_mode);
/* Clear phy isolation mode to make it work in normal mode */
offset = COMPHY_ISOLATION_CTRL_REG + SATAPHY_LANE2_REG_BASE_OFFSET;
comphy_set_indirect(comphy_indir_regs, offset, 0, PHY_ISOLATE_MODE,
mode);
/* 0. Check the Polarity invert bits */
if (invert & COMPHY_POLARITY_TXD_INVERT)
data |= TXD_INVERT_BIT;
if (invert & COMPHY_POLARITY_RXD_INVERT)
data |= RXD_INVERT_BIT;
offset = COMPHY_SYNC_PATTERN_REG + SATAPHY_LANE2_REG_BASE_OFFSET;
comphy_set_indirect(comphy_indir_regs, offset, data, TXD_INVERT_BIT |
RXD_INVERT_BIT, mode);
/* 1. Select 40-bit data width width */
offset = COMPHY_LOOPBACK_REG0 + SATAPHY_LANE2_REG_BASE_OFFSET;
comphy_set_indirect(comphy_indir_regs, offset, DATA_WIDTH_40BIT,
SEL_DATA_WIDTH_MASK, mode);
/* 2. Select reference clock(25M) and PHY mode (SATA) */
offset = COMPHY_POWER_PLL_CTRL + SATAPHY_LANE2_REG_BASE_OFFSET;
if (get_ref_clk() == 40)
ref_clk = REF_CLOCK_SPEED_40M;
else
ref_clk = REF_CLOCK_SPEED_25M;
comphy_set_indirect(comphy_indir_regs, offset, ref_clk | PHY_MODE_SATA,
REF_FREF_SEL_MASK | PHY_MODE_MASK, mode);
/* 3. Use maximum PLL rate (no power save) */
offset = COMPHY_KVCO_CAL_CTRL + SATAPHY_LANE2_REG_BASE_OFFSET;
comphy_set_indirect(comphy_indir_regs, offset, USE_MAX_PLL_RATE_BIT,
USE_MAX_PLL_RATE_BIT, mode);
/* 4. Reset reserved bit */
comphy_set_indirect(comphy_indir_regs, COMPHY_RESERVED_REG, 0,
PHYCTRL_FRM_PIN_BIT, mode);
/* 5. Set vendor-specific configuration (It is done in sata driver) */
/* XXX: in U-Boot below sequence was executed in this place, in Linux
* not. Now it is done only in U-Boot before this comphy
* initialization - tests shows that it works ok, but in case of any
* future problem it is left for reference.
* reg_set(MVEBU_REGS_BASE + 0xe00a0, 0, 0xffffffff);
* reg_set(MVEBU_REGS_BASE + 0xe00a4, BIT(6), BIT(6));
*/
/* Wait for > 55 us to allow PLL be enabled */
udelay(PLL_SET_DELAY_US);
/* Polling status */
mmio_write_32(comphy_indir_regs + COMPHY_LANE2_INDIR_ADDR_OFFSET,
COMPHY_LOOPBACK_REG0 + SATAPHY_LANE2_REG_BASE_OFFSET);
ret = polling_with_timeout(comphy_indir_regs +
COMPHY_LANE2_INDIR_DATA_OFFSET,
PLL_READY_TX_BIT, PLL_READY_TX_BIT,
COMPHY_PLL_TIMEOUT, REG_32BIT);
debug_exit();
return ret;
}
static int mvebu_a3700_comphy_sgmii_power_on(uint8_t comphy_index,
uint32_t comphy_mode)
{
int ret = 0;
uint32_t mask, data, offset;
uintptr_t sd_ip_addr;
int mode = COMPHY_GET_MODE(comphy_mode);
int invert = COMPHY_GET_POLARITY_INVERT(comphy_mode);
debug_enter();
/* Set selector */
mvebu_a3700_comphy_set_phy_selector(comphy_index, comphy_mode);
/* Serdes IP Base address
* COMPHY Lane0 -- USB3/GBE1
* COMPHY Lane1 -- PCIe/GBE0
*/
if (comphy_index == COMPHY_LANE0) {
/* Get usb3 and gbe */
sd_ip_addr = USB3_GBE1_PHY;
} else
sd_ip_addr = COMPHY_SD_ADDR;
/*
* 1. Reset PHY by setting PHY input port PIN_RESET=1.
* 2. Set PHY input port PIN_TX_IDLE=1, PIN_PU_IVREF=1 to keep
* PHY TXP/TXN output to idle state during PHY initialization
* 3. Set PHY input port PIN_PU_PLL=0, PIN_PU_RX=0, PIN_PU_TX=0.
*/
data = PIN_PU_IVEREF_BIT | PIN_TX_IDLE_BIT | PIN_RESET_COMPHY_BIT;
mask = PIN_RESET_CORE_BIT | PIN_PU_PLL_BIT | PIN_PU_RX_BIT |
PIN_PU_TX_BIT;
offset = MVEBU_COMPHY_REG_BASE + COMPHY_PHY_CFG1_OFFSET(comphy_index);
reg_set(offset, data, mask);
/* 4. Release reset to the PHY by setting PIN_RESET=0. */
data = 0;
mask = PIN_RESET_COMPHY_BIT;
reg_set(offset, data, mask);
/*
* 5. Set PIN_PHY_GEN_TX[3:0] and PIN_PHY_GEN_RX[3:0] to decide COMPHY
* bit rate
*/
if (mode == COMPHY_SGMII_MODE) {
/* SGMII 1G, SerDes speed 1.25G */
data |= SD_SPEED_1_25_G << GEN_RX_SEL_OFFSET;
data |= SD_SPEED_1_25_G << GEN_TX_SEL_OFFSET;
} else if (mode == COMPHY_HS_SGMII_MODE) {
/* HS SGMII (2.5G), SerDes speed 3.125G */
data |= SD_SPEED_2_5_G << GEN_RX_SEL_OFFSET;
data |= SD_SPEED_2_5_G << GEN_TX_SEL_OFFSET;
} else {
/* Other rates are not supported */
ERROR("unsupported SGMII speed on comphy lane%d\n",
comphy_index);
return -EINVAL;
}
mask = GEN_RX_SEL_MASK | GEN_TX_SEL_MASK;
reg_set(offset, data, mask);
/*
* 6. Wait 10mS for bandgap and reference clocks to stabilize; then
* start SW programming.
*/
mdelay(10);
/* 7. Program COMPHY register PHY_MODE */
data = PHY_MODE_SGMII;
mask = PHY_MODE_MASK;
reg_set16(SGMIIPHY_ADDR(COMPHY_POWER_PLL_CTRL, sd_ip_addr), data, mask);
/*
* 8. Set COMPHY register REFCLK_SEL to select the correct REFCLK
* source
*/
data = 0;
mask = PHY_REF_CLK_SEL;
reg_set16(SGMIIPHY_ADDR(COMPHY_MISC_REG0_ADDR, sd_ip_addr), data, mask);
/*
* 9. Set correct reference clock frequency in COMPHY register
* REF_FREF_SEL.
*/
if (get_ref_clk() == 40)
data = REF_CLOCK_SPEED_50M;
else
data = REF_CLOCK_SPEED_25M;
mask = REF_FREF_SEL_MASK;
reg_set16(SGMIIPHY_ADDR(COMPHY_POWER_PLL_CTRL, sd_ip_addr), data, mask);
/* 10. Program COMPHY register PHY_GEN_MAX[1:0]
* This step is mentioned in the flow received from verification team.
* However the PHY_GEN_MAX value is only meaningful for other interfaces
* (not SGMII). For instance, it selects SATA speed 1.5/3/6 Gbps or PCIe
* speed 2.5/5 Gbps
*/
/*
* 11. Program COMPHY register SEL_BITS to set correct parallel data
* bus width
*/
data = DATA_WIDTH_10BIT;
mask = SEL_DATA_WIDTH_MASK;
reg_set16(SGMIIPHY_ADDR(COMPHY_LOOPBACK_REG0, sd_ip_addr), data, mask);
/*
* 12. As long as DFE function needs to be enabled in any mode,
* COMPHY register DFE_UPDATE_EN[5:0] shall be programmed to 0x3F
* for real chip during COMPHY power on.
* The step 14 exists (and empty) in the original initialization flow
* obtained from the verification team. According to the functional
* specification DFE_UPDATE_EN already has the default value 0x3F
*/
/*
* 13. Program COMPHY GEN registers.
* These registers should be programmed based on the lab testing result
* to achieve optimal performance. Please contact the CEA group to get
* the related GEN table during real chip bring-up. We only required to
* run though the entire registers programming flow defined by
* "comphy_sgmii_phy_init" when the REF clock is 40 MHz. For REF clock
* 25 MHz the default values stored in PHY registers are OK.
*/
debug("Running C-DPI phy init %s mode\n",
mode == COMPHY_HS_SGMII_MODE ? "2G5" : "1G");
if (get_ref_clk() == 40)
comphy_sgmii_phy_init(comphy_index, mode, sd_ip_addr);
/*
* 14. [Simulation Only] should not be used for real chip.
* By pass power up calibration by programming EXT_FORCE_CAL_DONE
* (R02h[9]) to 1 to shorten COMPHY simulation time.
*/
/*
* 15. [Simulation Only: should not be used for real chip]
* Program COMPHY register FAST_DFE_TIMER_EN=1 to shorten RX training
* simulation time.
*/
/*
* 16. Check the PHY Polarity invert bit
*/
data = 0x0;
if (invert & COMPHY_POLARITY_TXD_INVERT)
data |= TXD_INVERT_BIT;
if (invert & COMPHY_POLARITY_RXD_INVERT)
data |= RXD_INVERT_BIT;
reg_set16(SGMIIPHY_ADDR(COMPHY_SYNC_PATTERN_REG, sd_ip_addr), data, 0);
/*
* 17. Set PHY input ports PIN_PU_PLL, PIN_PU_TX and PIN_PU_RX to 1 to
* start PHY power up sequence. All the PHY register programming should
* be done before PIN_PU_PLL=1. There should be no register programming
* for normal PHY operation from this point.
*/
reg_set(MVEBU_COMPHY_REG_BASE + COMPHY_PHY_CFG1_OFFSET(comphy_index),
PIN_PU_PLL_BIT | PIN_PU_RX_BIT | PIN_PU_TX_BIT,
PIN_PU_PLL_BIT | PIN_PU_RX_BIT | PIN_PU_TX_BIT);
/*
* 18. Wait for PHY power up sequence to finish by checking output ports
* PIN_PLL_READY_TX=1 and PIN_PLL_READY_RX=1.
*/
ret = polling_with_timeout(MVEBU_COMPHY_REG_BASE +
COMPHY_PHY_STATUS_OFFSET(comphy_index),
PHY_PLL_READY_TX_BIT | PHY_PLL_READY_RX_BIT,
PHY_PLL_READY_TX_BIT | PHY_PLL_READY_RX_BIT,
COMPHY_PLL_TIMEOUT, REG_32BIT);
if (ret)
ERROR("Failed to lock PLL for SGMII PHY %d\n", comphy_index);
/*
* 19. Set COMPHY input port PIN_TX_IDLE=0
*/
reg_set(MVEBU_COMPHY_REG_BASE + COMPHY_PHY_CFG1_OFFSET(comphy_index),
0x0, PIN_TX_IDLE_BIT);
/*
* 20. After valid data appear on PIN_RXDATA bus, set PIN_RX_INIT=1. To
* start RX initialization. PIN_RX_INIT_DONE will be cleared to 0 by the
* PHY After RX initialization is done, PIN_RX_INIT_DONE will be set to
* 1 by COMPHY Set PIN_RX_INIT=0 after PIN_RX_INIT_DONE= 1. Please
* refer to RX initialization part for details.
*/
reg_set(MVEBU_COMPHY_REG_BASE + COMPHY_PHY_CFG1_OFFSET(comphy_index),
PHY_RX_INIT_BIT, 0x0);
ret = polling_with_timeout(MVEBU_COMPHY_REG_BASE +
COMPHY_PHY_STATUS_OFFSET(comphy_index),
PHY_PLL_READY_TX_BIT | PHY_PLL_READY_RX_BIT,
PHY_PLL_READY_TX_BIT | PHY_PLL_READY_RX_BIT,
COMPHY_PLL_TIMEOUT, REG_32BIT);
if (ret)
ERROR("Failed to lock PLL for SGMII PHY %d\n", comphy_index);
ret = polling_with_timeout(MVEBU_COMPHY_REG_BASE +
COMPHY_PHY_STATUS_OFFSET(comphy_index),
PHY_RX_INIT_DONE_BIT, PHY_RX_INIT_DONE_BIT,
COMPHY_PLL_TIMEOUT, REG_32BIT);
if (ret)
ERROR("Failed to init RX of SGMII PHY %d\n", comphy_index);
debug_exit();
return ret;
}
static int mvebu_a3700_comphy_usb3_power_on(uint8_t comphy_index,
uint32_t comphy_mode)
{
int ret = 0;
uintptr_t reg_base = 0;
uint32_t mask, data, addr, cfg, ref_clk;
void (*usb3_reg_set)(uintptr_t addr, uint32_t reg_offset, uint16_t data,
uint16_t mask, int mode);
int mode = COMPHY_GET_MODE(comphy_mode);
int invert = COMPHY_GET_POLARITY_INVERT(comphy_mode);
debug_enter();
/* Set phy seclector */
mvebu_a3700_comphy_set_phy_selector(comphy_index, comphy_mode);
/* Set usb3 reg access func, Lane2 is indirect access */
if (comphy_index == COMPHY_LANE2) {
usb3_reg_set = &comphy_set_indirect;
reg_base = COMPHY_INDIRECT_REG;
} else {
/* Get the direct access register resource and map */
usb3_reg_set = &comphy_usb3_set_direct;
reg_base = USB3_GBE1_PHY;
}
/*
* 0. Set PHY OTG Control(0x5d034), bit 4, Power up OTG module The
* register belong to UTMI module, so it is set in UTMI phy driver.
*/
/*
* 1. Set PRD_TXDEEMPH (3.5db de-emph)
*/
mask = PRD_TXDEEMPH0_MASK | PRD_TXMARGIN_MASK | PRD_TXSWING_MASK |
CFG_TX_ALIGN_POS_MASK;
usb3_reg_set(reg_base, COMPHY_REG_LANE_CFG0_ADDR, PRD_TXDEEMPH0_MASK,
mask, mode);
/*
* 2. Set BIT0: enable transmitter in high impedance mode
* Set BIT[3:4]: delay 2 clock cycles for HiZ off latency
* Set BIT6: Tx detect Rx at HiZ mode
* Unset BIT15: set to 0 to set USB3 De-emphasize level to -3.5db
* together with bit 0 of COMPHY_REG_LANE_CFG0_ADDR register
*/
mask = PRD_TXDEEMPH1_MASK | TX_DET_RX_MODE | GEN2_TX_DATA_DLY_MASK |
TX_ELEC_IDLE_MODE_EN;
data = TX_DET_RX_MODE | GEN2_TX_DATA_DLY_DEFT | TX_ELEC_IDLE_MODE_EN;
usb3_reg_set(reg_base, COMPHY_REG_LANE_CFG1_ADDR, data, mask, mode);
/*
* 3. Set Spread Spectrum Clock Enabled
*/
usb3_reg_set(reg_base, COMPHY_REG_LANE_CFG4_ADDR,
SPREAD_SPECTRUM_CLK_EN, SPREAD_SPECTRUM_CLK_EN, mode);
/*
* 4. Set Override Margining Controls From the MAC:
* Use margining signals from lane configuration
*/
usb3_reg_set(reg_base, COMPHY_REG_TEST_MODE_CTRL_ADDR,
MODE_MARGIN_OVERRIDE, REG_16_BIT_MASK, mode);
/*
* 5. Set Lane-to-Lane Bundle Clock Sampling Period = per PCLK cycles
* set Mode Clock Source = PCLK is generated from REFCLK
*/
usb3_reg_set(reg_base, COMPHY_REG_GLOB_CLK_SRC_LO_ADDR, 0x0,
(MODE_CLK_SRC | BUNDLE_PERIOD_SEL | BUNDLE_PERIOD_SCALE |
BUNDLE_SAMPLE_CTRL | PLL_READY_DLY), mode);
/*
* 6. Set G2 Spread Spectrum Clock Amplitude at 4K
*/
usb3_reg_set(reg_base, COMPHY_REG_GEN2_SET_2,
G2_TX_SSC_AMP_VALUE_20, G2_TX_SSC_AMP_MASK, mode);
/*
* 7. Unset G3 Spread Spectrum Clock Amplitude
* set G3 TX and RX Register Master Current Select
*/
mask = G3_TX_SSC_AMP_MASK | G3_VREG_RXTX_MAS_ISET_MASK |
RSVD_PH03FH_6_0_MASK;
usb3_reg_set(reg_base, COMPHY_REG_GEN2_SET_3,
G3_VREG_RXTX_MAS_ISET_60U, mask, mode);
/*
* 8. Check crystal jumper setting and program the Power and PLL Control
* accordingly Change RX wait
*/
if (get_ref_clk() == 40) {
ref_clk = REF_CLOCK_SPEED_40M;
cfg = CFG_PM_RXDLOZ_WAIT_12_UNIT;
} else {
/* 25 MHz */
ref_clk = USB3_REF_CLOCK_SPEED_25M;
cfg = CFG_PM_RXDLOZ_WAIT_7_UNIT;
}
mask = PU_IVREF_BIT | PU_PLL_BIT | PU_RX_BIT | PU_TX_BIT |
PU_TX_INTP_BIT | PU_DFE_BIT | PLL_LOCK_BIT | PHY_MODE_MASK |
REF_FREF_SEL_MASK;
data = PU_IVREF_BIT | PU_PLL_BIT | PU_RX_BIT | PU_TX_BIT |
PU_TX_INTP_BIT | PU_DFE_BIT | PHY_MODE_USB3 | ref_clk;
usb3_reg_set(reg_base, COMPHY_POWER_PLL_CTRL, data, mask, mode);
mask = CFG_PM_OSCCLK_WAIT_MASK | CFG_PM_RXDEN_WAIT_MASK |
CFG_PM_RXDLOZ_WAIT_MASK;
data = CFG_PM_RXDEN_WAIT_1_UNIT | cfg;
usb3_reg_set(reg_base, COMPHY_REG_PWR_MGM_TIM1_ADDR, data, mask, mode);
/*
* 9. Enable idle sync
*/
data = UNIT_CTRL_DEFAULT_VALUE | IDLE_SYNC_EN;
usb3_reg_set(reg_base, COMPHY_REG_UNIT_CTRL_ADDR, data, REG_16_BIT_MASK,
mode);
/*
* 10. Enable the output of 500M clock
*/
data = MISC_REG0_DEFAULT_VALUE | CLK500M_EN;
usb3_reg_set(reg_base, COMPHY_MISC_REG0_ADDR, data, REG_16_BIT_MASK,
mode);
/*
* 11. Set 20-bit data width
*/
usb3_reg_set(reg_base, COMPHY_LOOPBACK_REG0, DATA_WIDTH_20BIT,
REG_16_BIT_MASK, mode);
/*
* 12. Override Speed_PLL value and use MAC PLL
*/
usb3_reg_set(reg_base, COMPHY_KVCO_CAL_CTRL,
(SPEED_PLL_VALUE_16 | USE_MAX_PLL_RATE_BIT),
REG_16_BIT_MASK, mode);
/*
* 13. Check the Polarity invert bit
*/
if (invert & COMPHY_POLARITY_TXD_INVERT)
usb3_reg_set(reg_base, COMPHY_SYNC_PATTERN_REG, TXD_INVERT_BIT,
TXD_INVERT_BIT, mode);
if (invert & COMPHY_POLARITY_RXD_INVERT)
usb3_reg_set(reg_base, COMPHY_SYNC_PATTERN_REG, RXD_INVERT_BIT,
RXD_INVERT_BIT, mode);
/*
* 14. Set max speed generation to USB3.0 5Gbps
*/
usb3_reg_set(reg_base, COMPHY_SYNC_MASK_GEN_REG, PHY_GEN_USB3_5G,
PHY_GEN_MAX_MASK, mode);
/*
* 15. Set capacitor value for FFE gain peaking to 0xF
*/
usb3_reg_set(reg_base, COMPHY_REG_GEN3_SETTINGS_3,
COMPHY_GEN_FFE_CAP_SEL_VALUE, COMPHY_GEN_FFE_CAP_SEL_MASK,
mode);
/*
* 16. Release SW reset
*/
data = MODE_CORE_CLK_FREQ_SEL | MODE_PIPE_WIDTH_32 | MODE_REFDIV_BY_4;
usb3_reg_set(reg_base, COMPHY_REG_GLOB_PHY_CTRL0_ADDR, data,
REG_16_BIT_MASK, mode);
/* Wait for > 55 us to allow PCLK be enabled */
udelay(PLL_SET_DELAY_US);
if (comphy_index == COMPHY_LANE2) {
data = COMPHY_LOOPBACK_REG0 + USB3PHY_LANE2_REG_BASE_OFFSET;
mmio_write_32(reg_base + COMPHY_LANE2_INDIR_ADDR_OFFSET,
data);
addr = COMPHY_LOOPBACK_REG0 + USB3PHY_LANE2_REG_BASE_OFFSET;
ret = polling_with_timeout(addr, TXDCLK_PCLK_EN, TXDCLK_PCLK_EN,
COMPHY_PLL_TIMEOUT, REG_32BIT);
} else {
ret = polling_with_timeout(LANE_STATUS1_ADDR(USB3) + reg_base,
TXDCLK_PCLK_EN, TXDCLK_PCLK_EN,
COMPHY_PLL_TIMEOUT, REG_16BIT);
}
if (ret)
ERROR("Failed to lock USB3 PLL\n");
debug_exit();
return ret;
}
static int mvebu_a3700_comphy_pcie_power_on(uint8_t comphy_index,
uint32_t comphy_mode)
{
int ret;
uint32_t ref_clk;
int invert = COMPHY_GET_POLARITY_INVERT(comphy_mode);
debug_enter();
/* 1. Enable max PLL. */
reg_set16(LANE_CFG1_ADDR(PCIE) + COMPHY_SD_ADDR,
USE_MAX_PLL_RATE_EN, 0x0);
/* 2. Select 20 bit SERDES interface. */
reg_set16(GLOB_CLK_SRC_LO_ADDR(PCIE) + COMPHY_SD_ADDR,
CFG_SEL_20B, 0);
/* 3. Force to use reg setting for PCIe mode */
reg_set16(MISC_REG1_ADDR(PCIE) + COMPHY_SD_ADDR,
SEL_BITS_PCIE_FORCE, 0);
/* 4. Change RX wait */
reg_set16(PWR_MGM_TIM1_ADDR(PCIE) + COMPHY_SD_ADDR,
CFG_PM_RXDEN_WAIT_1_UNIT | CFG_PM_RXDLOZ_WAIT_12_UNIT,
(CFG_PM_OSCCLK_WAIT_MASK | CFG_PM_RXDEN_WAIT_MASK |
CFG_PM_RXDLOZ_WAIT_MASK));
/* 5. Enable idle sync */
reg_set16(UNIT_CTRL_ADDR(PCIE) + COMPHY_SD_ADDR,
UNIT_CTRL_DEFAULT_VALUE | IDLE_SYNC_EN, REG_16_BIT_MASK);
/* 6. Enable the output of 100M/125M/500M clock */
reg_set16(MISC_REG0_ADDR(PCIE) + COMPHY_SD_ADDR,
MISC_REG0_DEFAULT_VALUE | CLK500M_EN | CLK100M_125M_EN,
REG_16_BIT_MASK);
/*
* 7. Enable TX, PCIE global register, 0xd0074814, it is done in
* PCI-E driver
*/
/*
* 8. Check crystal jumper setting and program the Power and PLL
* Control accordingly
*/
if (get_ref_clk() == 40)
ref_clk = REF_CLOCK_SPEED_40M;
else
ref_clk = PCIE_REF_CLOCK_SPEED_25M;
reg_set16(PWR_PLL_CTRL_ADDR(PCIE) + COMPHY_SD_ADDR,
(PU_IVREF_BIT | PU_PLL_BIT | PU_RX_BIT | PU_TX_BIT |
PU_TX_INTP_BIT | PU_DFE_BIT | ref_clk | PHY_MODE_PCIE),
REG_16_BIT_MASK);
/* 9. Override Speed_PLL value and use MAC PLL */
reg_set16(KVCO_CAL_CTRL_ADDR(PCIE) + COMPHY_SD_ADDR,
SPEED_PLL_VALUE_16 | USE_MAX_PLL_RATE_BIT, REG_16_BIT_MASK);
/* 10. Check the Polarity invert bit */
if (invert & COMPHY_POLARITY_TXD_INVERT)
reg_set16(SYNC_PATTERN_REG_ADDR(PCIE) + COMPHY_SD_ADDR,
TXD_INVERT_BIT, 0x0);
if (invert & COMPHY_POLARITY_RXD_INVERT)
reg_set16(SYNC_PATTERN_REG_ADDR(PCIE) + COMPHY_SD_ADDR,
RXD_INVERT_BIT, 0x0);
/* 11. Release SW reset */
reg_set16(GLOB_PHY_CTRL0_ADDR(PCIE) + COMPHY_SD_ADDR,
MODE_CORE_CLK_FREQ_SEL | MODE_PIPE_WIDTH_32,
SOFT_RESET | MODE_REFDIV);
/* Wait for > 55 us to allow PCLK be enabled */
udelay(PLL_SET_DELAY_US);
ret = polling_with_timeout(LANE_STATUS1_ADDR(PCIE) + COMPHY_SD_ADDR,
TXDCLK_PCLK_EN, TXDCLK_PCLK_EN,
COMPHY_PLL_TIMEOUT, REG_16BIT);
if (ret)
ERROR("Failed to lock PCIE PLL\n");
debug_exit();
return ret;
}
int mvebu_3700_comphy_power_on(uint8_t comphy_index, uint32_t comphy_mode)
{
int mode = COMPHY_GET_MODE(comphy_mode);
int ret = 0;
debug_enter();
switch (mode) {
case(COMPHY_SATA_MODE):
ret = mvebu_a3700_comphy_sata_power_on(comphy_index,
comphy_mode);
break;
case(COMPHY_SGMII_MODE):
case(COMPHY_HS_SGMII_MODE):
ret = mvebu_a3700_comphy_sgmii_power_on(comphy_index,
comphy_mode);
break;
case (COMPHY_USB3_MODE):
case (COMPHY_USB3H_MODE):
ret = mvebu_a3700_comphy_usb3_power_on(comphy_index,
comphy_mode);
break;
case (COMPHY_PCIE_MODE):
ret = mvebu_a3700_comphy_pcie_power_on(comphy_index,
comphy_mode);
break;
default:
ERROR("comphy%d: unsupported comphy mode\n", comphy_index);
ret = -EINVAL;
break;
}
debug_exit();
return ret;
}
static int mvebu_a3700_comphy_usb3_power_off(void)
{
/*
* Currently the USB3 MAC will control the USB3 PHY to set it to low
* state, thus do not need to power off USB3 PHY again.
*/
debug_enter();
debug_exit();
return 0;
}
static int mvebu_a3700_comphy_sata_power_off(uint32_t comphy_mode)
{
uintptr_t comphy_indir_regs = COMPHY_INDIRECT_REG;
int mode = COMPHY_GET_MODE(comphy_mode);
uint32_t offset;
debug_enter();
/* Set phy isolation mode */
offset = COMPHY_ISOLATION_CTRL_REG + SATAPHY_LANE2_REG_BASE_OFFSET;
comphy_set_indirect(comphy_indir_regs, offset, PHY_ISOLATE_MODE,
PHY_ISOLATE_MODE, mode);
/* Power off PLL, Tx, Rx */
offset = COMPHY_POWER_PLL_CTRL + SATAPHY_LANE2_REG_BASE_OFFSET;
comphy_set_indirect(comphy_indir_regs, offset, 0,
PU_PLL_BIT | PU_RX_BIT | PU_TX_BIT, mode);
debug_exit();
return 0;
}
int mvebu_3700_comphy_power_off(uint8_t comphy_index, uint32_t comphy_mode)
{
int mode = COMPHY_GET_MODE(comphy_mode);
int err = 0;
debug_enter();
switch (mode) {
case (COMPHY_USB3_MODE):
case (COMPHY_USB3H_MODE):
err = mvebu_a3700_comphy_usb3_power_off();
break;
case (COMPHY_SATA_MODE):
err = mvebu_a3700_comphy_sata_power_off(comphy_mode);
break;
default:
debug("comphy%d: power off is not implemented for mode %d\n",
comphy_index, mode);
break;
}
debug_exit();
return err;
}
static int mvebu_a3700_comphy_sata_is_pll_locked(void)
{
uint32_t data, addr;
uintptr_t comphy_indir_regs = COMPHY_INDIRECT_REG;
int ret = 0;
debug_enter();
/* Polling status */
mmio_write_32(comphy_indir_regs + COMPHY_LANE2_INDIR_ADDR_OFFSET,
COMPHY_LOOPBACK_REG0 + SATAPHY_LANE2_REG_BASE_OFFSET);
addr = comphy_indir_regs + COMPHY_LANE2_INDIR_DATA_OFFSET;
data = polling_with_timeout(addr, PLL_READY_TX_BIT, PLL_READY_TX_BIT,
COMPHY_PLL_TIMEOUT, REG_32BIT);
if (data != 0) {
ERROR("TX PLL is not locked\n");
ret = -ETIMEDOUT;
}
debug_exit();
return ret;
}
int mvebu_3700_comphy_is_pll_locked(uint8_t comphy_index, uint32_t comphy_mode)
{
int mode = COMPHY_GET_MODE(comphy_mode);
int ret = 0;
debug_enter();
switch (mode) {
case(COMPHY_SATA_MODE):
ret = mvebu_a3700_comphy_sata_is_pll_locked();
break;
default:
ERROR("comphy[%d] mode[%d] doesn't support PLL lock check\n",
comphy_index, mode);
ret = -EINVAL;
break;
}
debug_exit();
return ret;
}
/*
* Copyright (C) 2018 Marvell International Ltd.
*
* SPDX-License-Identifier: BSD-3-Clause
* https://spdx.org/licenses
*/
#ifndef _PHY_COMPHY_3700_H
#define _PHY_COMPHY_3700_H
#define PLL_SET_DELAY_US 600
#define COMPHY_PLL_TIMEOUT 1000
#define REG_16_BIT_MASK 0xFFFF
#define COMPHY_SELECTOR_PHY_REG 0xFC
/* bit0: 0: Lane0 is GBE0; 1: Lane1 is PCIE */
#define COMPHY_SELECTOR_PCIE_GBE0_SEL_BIT BIT(0)
/* bit4: 0: Lane1 is GBE1; 1: Lane1 is USB3 */
#define COMPHY_SELECTOR_USB3_GBE1_SEL_BIT BIT(4)
/* bit8: 0: Lane1 is USB, Lane2 is SATA; 1: Lane2 is USB3 */
#define COMPHY_SELECTOR_USB3_PHY_SEL_BIT BIT(8)
/* SATA PHY register offset */
#define SATAPHY_LANE2_REG_BASE_OFFSET 0x200
/* USB3 PHY offset compared to SATA PHY */
#define USB3PHY_LANE2_REG_BASE_OFFSET 0x200
/* Comphy lane2 indirect access register offset */
#define COMPHY_LANE2_INDIR_ADDR_OFFSET 0x0
#define COMPHY_LANE2_INDIR_DATA_OFFSET 0x4
/* PHY shift to get related register address */
enum {
PCIE = 1,
USB3,
};
#define PCIEPHY_SHFT 2
#define USB3PHY_SHFT 2
#define PHY_SHFT(unit) ((unit == PCIE) ? PCIEPHY_SHFT : USB3PHY_SHFT)
/* PHY register */
#define COMPHY_POWER_PLL_CTRL 0x01
#define PWR_PLL_CTRL_ADDR(unit) (COMPHY_POWER_PLL_CTRL * PHY_SHFT(unit))
#define PU_IVREF_BIT BIT(15)
#define PU_PLL_BIT BIT(14)
#define PU_RX_BIT BIT(13)
#define PU_TX_BIT BIT(12)
#define PU_TX_INTP_BIT BIT(11)
#define PU_DFE_BIT BIT(10)
#define RESET_DTL_RX_BIT BIT(9)
#define PLL_LOCK_BIT BIT(8)
#define REF_FREF_SEL_OFFSET 0
#define REF_FREF_SEL_MASK (0x1F << REF_FREF_SEL_OFFSET)
#define REF_CLOCK_SPEED_25M (0x1 << REF_FREF_SEL_OFFSET)
#define REF_CLOCK_SPEED_30M (0x2 << REF_FREF_SEL_OFFSET)
#define PCIE_REF_CLOCK_SPEED_25M REF_CLOCK_SPEED_30M
#define USB3_REF_CLOCK_SPEED_25M REF_CLOCK_SPEED_30M
#define REF_CLOCK_SPEED_40M (0x3 << REF_FREF_SEL_OFFSET)
#define REF_CLOCK_SPEED_50M (0x4 << REF_FREF_SEL_OFFSET)
#define PHY_MODE_OFFSET 5
#define PHY_MODE_MASK (7 << PHY_MODE_OFFSET)
#define PHY_MODE_SATA (0x0 << PHY_MODE_OFFSET)
#define PHY_MODE_PCIE (0x3 << PHY_MODE_OFFSET)
#define PHY_MODE_SGMII (0x4 << PHY_MODE_OFFSET)
#define PHY_MODE_USB3 (0x5 << PHY_MODE_OFFSET)
#define COMPHY_KVCO_CAL_CTRL 0x02
#define KVCO_CAL_CTRL_ADDR(unit) (COMPHY_KVCO_CAL_CTRL * PHY_SHFT(unit))
#define USE_MAX_PLL_RATE_BIT BIT(12)
#define SPEED_PLL_OFFSET 2
#define SPEED_PLL_MASK (0x3F << SPEED_PLL_OFFSET)
#define SPEED_PLL_VALUE_16 (0x10 << SPEED_PLL_OFFSET)
#define COMPHY_RESERVED_REG 0x0E
#define PHYCTRL_FRM_PIN_BIT BIT(13)
#define COMPHY_LOOPBACK_REG0 0x23
#define DIG_LB_EN_ADDR(unit) (COMPHY_LOOPBACK_REG0 * PHY_SHFT(unit))
#define SEL_DATA_WIDTH_OFFSET 10
#define SEL_DATA_WIDTH_MASK (0x3 << SEL_DATA_WIDTH_OFFSET)
#define DATA_WIDTH_10BIT (0x0 << SEL_DATA_WIDTH_OFFSET)
#define DATA_WIDTH_20BIT (0x1 << SEL_DATA_WIDTH_OFFSET)
#define DATA_WIDTH_40BIT (0x2 << SEL_DATA_WIDTH_OFFSET)
#define PLL_READY_TX_BIT BIT(4)
#define COMPHY_SYNC_PATTERN_REG 0x24
#define SYNC_PATTERN_REG_ADDR(unit) (COMPHY_SYNC_PATTERN_REG * \
PHY_SHFT(unit))
#define TXD_INVERT_BIT BIT(10)
#define RXD_INVERT_BIT BIT(11)
#define COMPHY_SYNC_MASK_GEN_REG 0x25
#define PHY_GEN_MAX_OFFSET 10
#define PHY_GEN_MAX_MASK (3 << PHY_GEN_MAX_OFFSET)
#define PHY_GEN_USB3_5G (1 << PHY_GEN_MAX_OFFSET)
#define COMPHY_ISOLATION_CTRL_REG 0x26
#define ISOLATION_CTRL_REG_ADDR(unit) (COMPHY_ISOLATION_CTRL_REG * \
PHY_SHFT(unit))
#define PHY_ISOLATE_MODE BIT(15)
#define COMPHY_MISC_REG0_ADDR 0x4F
#define MISC_REG0_ADDR(unit) (COMPHY_MISC_REG0_ADDR * PHY_SHFT(unit))
#define CLK100M_125M_EN BIT(4)
#define CLK500M_EN BIT(7)
#define PHY_REF_CLK_SEL BIT(10)
#define MISC_REG0_DEFAULT_VALUE 0xA00D
#define COMPHY_REG_GEN2_SET_2 0x3e
#define GEN2_SETTING_2_ADDR(unit) (COMPHY_REG_GEN2_SET_2 * PHY_SHFT(unit))
#define G2_TX_SSC_AMP_VALUE_20 BIT(14)
#define G2_TX_SSC_AMP_OFF 9
#define G2_TX_SSC_AMP_LEN 7
#define G2_TX_SSC_AMP_MASK (((1 << G2_TX_SSC_AMP_LEN) - 1) << \
G2_TX_SSC_AMP_OFF)
#define COMPHY_REG_GEN2_SET_3 0x3f
#define GEN2_SETTING_3_ADDR(unit) (COMPHY_REG_GEN2_SET_3 * PHY_SHFT(unit))
#define G3_TX_SSC_AMP_OFF 9
#define G3_TX_SSC_AMP_LEN 7
#define G3_TX_SSC_AMP_MASK (((1 << G2_TX_SSC_AMP_LEN) - 1) << \
G2_TX_SSC_AMP_OFF)
#define G3_VREG_RXTX_MAS_ISET_OFF 7
#define G3_VREG_RXTX_MAS_ISET_60U (0 << G3_VREG_RXTX_MAS_ISET_OFF)
#define G3_VREG_RXTX_MAS_ISET_80U (1 << G3_VREG_RXTX_MAS_ISET_OFF)
#define G3_VREG_RXTX_MAS_ISET_100U (2 << G3_VREG_RXTX_MAS_ISET_OFF)
#define G3_VREG_RXTX_MAS_ISET_120U (3 << G3_VREG_RXTX_MAS_ISET_OFF)
#define G3_VREG_RXTX_MAS_ISET_MASK (BIT(7) | BIT(8))
#define RSVD_PH03FH_6_0_OFF 0
#define RSVD_PH03FH_6_0_LEN 7
#define RSVD_PH03FH_6_0_MASK (((1 << RSVD_PH03FH_6_0_LEN) - 1) << \
RSVD_PH03FH_6_0_OFF)
#define COMPHY_REG_UNIT_CTRL_ADDR 0x48
#define UNIT_CTRL_ADDR(unit) (COMPHY_REG_UNIT_CTRL_ADDR * \
PHY_SHFT(unit))
#define IDLE_SYNC_EN BIT(12)
#define UNIT_CTRL_DEFAULT_VALUE 0x60
#define COMPHY_MISC_REG1_ADDR 0x73
#define MISC_REG1_ADDR(unit) (COMPHY_MISC_REG1_ADDR * PHY_SHFT(unit))
#define SEL_BITS_PCIE_FORCE BIT(15)
#define COMPHY_REG_GEN3_SETTINGS_3 0x112
#define COMPHY_GEN_FFE_CAP_SEL_MASK 0xF
#define COMPHY_GEN_FFE_CAP_SEL_VALUE 0xF
#define COMPHY_REG_LANE_CFG0_ADDR 0x180
#define LANE_CFG0_ADDR(unit) (COMPHY_REG_LANE_CFG0_ADDR * \
PHY_SHFT(unit))
#define PRD_TXDEEMPH0_MASK BIT(0)
#define PRD_TXMARGIN_MASK (BIT(1) | BIT(2) | BIT(3))
#define PRD_TXSWING_MASK BIT(4)
#define CFG_TX_ALIGN_POS_MASK (BIT(5) | BIT(6) | BIT(7) | BIT(8))
#define COMPHY_REG_LANE_CFG1_ADDR 0x181
#define LANE_CFG1_ADDR(unit) (COMPHY_REG_LANE_CFG1_ADDR * \
PHY_SHFT(unit))
#define PRD_TXDEEMPH1_MASK BIT(15)
#define USE_MAX_PLL_RATE_EN BIT(9)
#define TX_DET_RX_MODE BIT(6)
#define GEN2_TX_DATA_DLY_MASK (BIT(3) | BIT(4))
#define GEN2_TX_DATA_DLY_DEFT (2 << 3)
#define TX_ELEC_IDLE_MODE_EN BIT(0)
#define COMPHY_REG_LANE_STATUS1_ADDR 0x183
#define LANE_STATUS1_ADDR(unit) (COMPHY_REG_LANE_STATUS1_ADDR * \
PHY_SHFT(unit))
#define TXDCLK_PCLK_EN BIT(0)
#define COMPHY_REG_LANE_CFG4_ADDR 0x188
#define LANE_CFG4_ADDR(unit) (COMPHY_REG_LANE_CFG4_ADDR * \
PHY_SHFT(unit))
#define SPREAD_SPECTRUM_CLK_EN BIT(7)
#define COMPHY_REG_GLOB_PHY_CTRL0_ADDR 0x1C1
#define GLOB_PHY_CTRL0_ADDR(unit) (COMPHY_REG_GLOB_PHY_CTRL0_ADDR * \
PHY_SHFT(unit))
#define SOFT_RESET BIT(0)
#define MODE_REFDIV 0x30
#define MODE_CORE_CLK_FREQ_SEL BIT(9)
#define MODE_PIPE_WIDTH_32 BIT(3)
#define MODE_REFDIV_OFFSET 4
#define MODE_REFDIV_LEN 2
#define MODE_REFDIV_MASK (0x3 << MODE_REFDIV_OFFSET)
#define MODE_REFDIV_BY_4 (0x2 << MODE_REFDIV_OFFSET)
#define COMPHY_REG_TEST_MODE_CTRL_ADDR 0x1C2
#define TEST_MODE_CTRL_ADDR(unit) (COMPHY_REG_TEST_MODE_CTRL_ADDR * \
PHY_SHFT(unit))
#define MODE_MARGIN_OVERRIDE BIT(2)
#define COMPHY_REG_GLOB_CLK_SRC_LO_ADDR 0x1C3
#define GLOB_CLK_SRC_LO_ADDR(unit) (COMPHY_REG_GLOB_CLK_SRC_LO_ADDR * \
PHY_SHFT(unit))
#define MODE_CLK_SRC BIT(0)
#define BUNDLE_PERIOD_SEL BIT(1)
#define BUNDLE_PERIOD_SCALE (BIT(2) | BIT(3))
#define BUNDLE_SAMPLE_CTRL BIT(4)
#define PLL_READY_DLY (BIT(5) | BIT(6) | BIT(7))
#define CFG_SEL_20B BIT(15)
#define COMPHY_REG_PWR_MGM_TIM1_ADDR 0x1D0
#define PWR_MGM_TIM1_ADDR(unit) (COMPHY_REG_PWR_MGM_TIM1_ADDR * \
PHY_SHFT(unit))
#define CFG_PM_OSCCLK_WAIT_OFF 12
#define CFG_PM_OSCCLK_WAIT_LEN 4
#define CFG_PM_OSCCLK_WAIT_MASK (((1 << CFG_PM_OSCCLK_WAIT_LEN) - 1) \
<< CFG_PM_OSCCLK_WAIT_OFF)
#define CFG_PM_RXDEN_WAIT_OFF 8
#define CFG_PM_RXDEN_WAIT_LEN 4
#define CFG_PM_RXDEN_WAIT_MASK (((1 << CFG_PM_RXDEN_WAIT_LEN) - 1) \
<< CFG_PM_RXDEN_WAIT_OFF)
#define CFG_PM_RXDEN_WAIT_1_UNIT (1 << CFG_PM_RXDEN_WAIT_OFF)
#define CFG_PM_RXDLOZ_WAIT_OFF 0
#define CFG_PM_RXDLOZ_WAIT_LEN 8
#define CFG_PM_RXDLOZ_WAIT_MASK (((1 << CFG_PM_RXDLOZ_WAIT_LEN) - 1) \
<< CFG_PM_RXDLOZ_WAIT_OFF)
#define CFG_PM_RXDLOZ_WAIT_7_UNIT (7 << CFG_PM_RXDLOZ_WAIT_OFF)
#define CFG_PM_RXDLOZ_WAIT_12_UNIT (0xC << CFG_PM_RXDLOZ_WAIT_OFF)
/* SGMII */
#define COMPHY_PHY_CFG1_OFFSET(lane) ((1 - (lane)) * 0x28)
#define PIN_PU_IVEREF_BIT BIT(1)
#define PIN_RESET_CORE_BIT BIT(11)
#define PIN_RESET_COMPHY_BIT BIT(12)
#define PIN_PU_PLL_BIT BIT(16)
#define PIN_PU_RX_BIT BIT(17)
#define PIN_PU_TX_BIT BIT(18)
#define PIN_TX_IDLE_BIT BIT(19)
#define GEN_RX_SEL_OFFSET 22
#define GEN_RX_SEL_MASK (0xF << GEN_RX_SEL_OFFSET)
#define GEN_TX_SEL_OFFSET 26
#define GEN_TX_SEL_MASK (0xF << GEN_TX_SEL_OFFSET)
#define PHY_RX_INIT_BIT BIT(30)
#define SD_SPEED_1_25_G 0x6
#define SD_SPEED_2_5_G 0x8
/* COMPHY status reg:
* lane0: PCIe/GbE0 PHY Status 1
* lane1: USB3/GbE1 PHY Status 1
*/
#define COMPHY_PHY_STATUS_OFFSET(lane) (0x18 + (1 - (lane)) * 0x28)
#define PHY_RX_INIT_DONE_BIT BIT(0)
#define PHY_PLL_READY_RX_BIT BIT(2)
#define PHY_PLL_READY_TX_BIT BIT(3)
#define SGMIIPHY_ADDR(off, base) ((((off) & 0x00007FF) * 2) + (base))
#define MAX_LANE_NR 3
/* comphy API */
int mvebu_3700_comphy_is_pll_locked(uint8_t comphy_index, uint32_t comphy_mode);
int mvebu_3700_comphy_power_off(uint8_t comphy_index, uint32_t comphy_mode);
int mvebu_3700_comphy_power_on(uint8_t comphy_index, uint32_t comphy_mode);
#endif /* _PHY_COMPHY_3700_H */
/*
* Copyright (C) 2018 Marvell International Ltd.
*
* SPDX-License-Identifier: BSD-3-Clause
* https://spdx.org/licenses
*/
/* Marvell CP110 ana A3700 common */
#ifndef _PHY_COMPHY_COMMON_H
#define _PHY_COMPHY_COMMON_H
/* #define DEBUG_COMPHY */
#ifdef DEBUG_COMPHY
#define debug(format...) printf(format)
#else
#define debug(format, arg...)
#endif
/* A lane is described by 4 fields:
* - bit 1~0 represent comphy polarity invert
* - bit 7~2 represent comphy speed
* - bit 11~8 represent unit index
* - bit 16~12 represent mode
* - bit 17 represent comphy indication of clock source
* - bit 19-18 represents pcie width (in case of pcie comphy config.)
* - bit 31~20 reserved
*/
#define COMPHY_INVERT_OFFSET 0
#define COMPHY_INVERT_LEN 2
#define COMPHY_INVERT_MASK COMPHY_MASK(COMPHY_INVERT_OFFSET, \
COMPHY_INVERT_LEN)
#define COMPHY_SPEED_OFFSET (COMPHY_INVERT_OFFSET + COMPHY_INVERT_LEN)
#define COMPHY_SPEED_LEN 6
#define COMPHY_SPEED_MASK COMPHY_MASK(COMPHY_SPEED_OFFSET, \
COMPHY_SPEED_LEN)
#define COMPHY_UNIT_ID_OFFSET (COMPHY_SPEED_OFFSET + COMPHY_SPEED_LEN)
#define COMPHY_UNIT_ID_LEN 4
#define COMPHY_UNIT_ID_MASK COMPHY_MASK(COMPHY_UNIT_ID_OFFSET, \
COMPHY_UNIT_ID_LEN)
#define COMPHY_MODE_OFFSET (COMPHY_UNIT_ID_OFFSET + COMPHY_UNIT_ID_LEN)
#define COMPHY_MODE_LEN 5
#define COMPHY_MODE_MASK COMPHY_MASK(COMPHY_MODE_OFFSET, COMPHY_MODE_LEN)
#define COMPHY_CLK_SRC_OFFSET (COMPHY_MODE_OFFSET + COMPHY_MODE_LEN)
#define COMPHY_CLK_SRC_LEN 1
#define COMPHY_CLK_SRC_MASK COMPHY_MASK(COMPHY_CLK_SRC_OFFSET, \
COMPHY_CLK_SRC_LEN)
#define COMPHY_PCI_WIDTH_OFFSET (COMPHY_CLK_SRC_OFFSET + COMPHY_CLK_SRC_LEN)
#define COMPHY_PCI_WIDTH_LEN 3
#define COMPHY_PCI_WIDTH_MASK COMPHY_MASK(COMPHY_PCI_WIDTH_OFFSET, \
COMPHY_PCI_WIDTH_LEN)
#define COMPHY_MASK(offset, len) (((1 << (len)) - 1) << (offset))
/* Macro which extracts mode from lane description */
#define COMPHY_GET_MODE(x) (((x) & COMPHY_MODE_MASK) >> \
COMPHY_MODE_OFFSET)
/* Macro which extracts unit index from lane description */
#define COMPHY_GET_ID(x) (((x) & COMPHY_UNIT_ID_MASK) >> \
COMPHY_UNIT_ID_OFFSET)
/* Macro which extracts speed from lane description */
#define COMPHY_GET_SPEED(x) (((x) & COMPHY_SPEED_MASK) >> \
COMPHY_SPEED_OFFSET)
/* Macro which extracts clock source indication from lane description */
#define COMPHY_GET_CLK_SRC(x) (((x) & COMPHY_CLK_SRC_MASK) >> \
COMPHY_CLK_SRC_OFFSET)
/* Macro which extracts pcie width indication from lane description */
#define COMPHY_GET_PCIE_WIDTH(x) (((x) & COMPHY_PCI_WIDTH_MASK) >> \
COMPHY_PCI_WIDTH_OFFSET)
/* Macro which extracts the polarity invert from lane description */
#define COMPHY_GET_POLARITY_INVERT(x) (((x) & COMPHY_INVERT_MASK) >> \
COMPHY_INVERT_OFFSET)
#define COMPHY_SATA_MODE 0x1
#define COMPHY_SGMII_MODE 0x2 /* SGMII 1G */
#define COMPHY_HS_SGMII_MODE 0x3 /* SGMII 2.5G */
#define COMPHY_USB3H_MODE 0x4
#define COMPHY_USB3D_MODE 0x5
#define COMPHY_PCIE_MODE 0x6
#define COMPHY_RXAUI_MODE 0x7
#define COMPHY_XFI_MODE 0x8
#define COMPHY_SFI_MODE 0x9
#define COMPHY_USB3_MODE 0xa
#define COMPHY_AP_MODE 0xb
#define COMPHY_UNUSED 0xFFFFFFFF
/* Polarity invert macro */
#define COMPHY_POLARITY_NO_INVERT 0
#define COMPHY_POLARITY_TXD_INVERT 1
#define COMPHY_POLARITY_RXD_INVERT 2
#define COMPHY_POLARITY_ALL_INVERT (COMPHY_POLARITY_TXD_INVERT | \
COMPHY_POLARITY_RXD_INVERT)
enum reg_width_type {
REG_16BIT = 0,
REG_32BIT,
};
enum {
COMPHY_LANE0 = 0,
COMPHY_LANE1,
COMPHY_LANE2,
COMPHY_LANE3,
COMPHY_LANE4,
COMPHY_LANE5,
COMPHY_LANE_MAX,
};
static inline uint32_t polling_with_timeout(uintptr_t addr, uint32_t val,
uint32_t mask,
uint32_t usec_timeout,
enum reg_width_type type)
{
uint32_t data;
do {
udelay(1);
if (type == REG_16BIT)
data = mmio_read_16(addr) & mask;
else
data = mmio_read_32(addr) & mask;
} while (data != val && --usec_timeout > 0);
if (usec_timeout == 0)
return data;
return 0;
}
static inline void reg_set(uintptr_t addr, uint32_t data, uint32_t mask)
{
debug("<atf>: WR to addr = 0x%lx, data = 0x%x (mask = 0x%x) - ",
addr, data, mask);
debug("old value = 0x%x ==> ", mmio_read_32(addr));
mmio_clrsetbits_32(addr, mask, data);
debug("new val 0x%x\n", mmio_read_32(addr));
}
static inline void __unused reg_set16(uintptr_t addr, uint16_t data,
uint16_t mask)
{
debug("<atf>: WR to addr = 0x%lx, data = 0x%x (mask = 0x%x) - ",
addr, data, mask);
debug("old value = 0x%x ==> ", mmio_read_16(addr));
mmio_clrsetbits_16(addr, mask, data);
debug("new val 0x%x\n", mmio_read_16(addr));
}
#endif /* _PHY_COMPHY_COMMON_H */
......@@ -15,78 +15,15 @@
#include <spinlock.h>
#include "mvebu.h"
#include "comphy-cp110.h"
#include "phy-comphy-cp110.h"
#include "phy-comphy-common.h"
/* #define DEBUG_COMPHY */
#ifdef DEBUG_COMPHY
#define debug(format...) printf(format)
#if __has_include("phy-porting-layer.h")
#include "phy-porting-layer.h"
#else
#define debug(format, arg...)
#include "phy-default-porting-layer.h"
#endif
/* A lane is described by 4 fields:
* - bit 1~0 represent comphy polarity invert
* - bit 7~2 represent comphy speed
* - bit 11~8 represent unit index
* - bit 16~12 represent mode
* - bit 17 represent comphy indication of clock source
* - bit 19-18 represents pcie width (in case of pcie comphy config.)
* - bit 31~20 reserved
*/
#define COMPHY_INVERT_OFFSET 0
#define COMPHY_INVERT_LEN 2
#define COMPHY_INVERT_MASK COMPHY_MASK(COMPHY_INVERT_OFFSET, \
COMPHY_INVERT_LEN)
#define COMPHY_SPEED_OFFSET (COMPHY_INVERT_OFFSET + COMPHY_INVERT_LEN)
#define COMPHY_SPEED_LEN 6
#define COMPHY_SPEED_MASK COMPHY_MASK(COMPHY_SPEED_OFFSET, \
COMPHY_SPEED_LEN)
#define COMPHY_UNIT_ID_OFFSET (COMPHY_SPEED_OFFSET + COMPHY_SPEED_LEN)
#define COMPHY_UNIT_ID_LEN 4
#define COMPHY_UNIT_ID_MASK COMPHY_MASK(COMPHY_UNIT_ID_OFFSET, \
COMPHY_UNIT_ID_LEN)
#define COMPHY_MODE_OFFSET (COMPHY_UNIT_ID_OFFSET + COMPHY_UNIT_ID_LEN)
#define COMPHY_MODE_LEN 5
#define COMPHY_MODE_MASK COMPHY_MASK(COMPHY_MODE_OFFSET, COMPHY_MODE_LEN)
#define COMPHY_CLK_SRC_OFFSET (COMPHY_MODE_OFFSET + COMPHY_MODE_LEN)
#define COMPHY_CLK_SRC_LEN 1
#define COMPHY_CLK_SRC_MASK COMPHY_MASK(COMPHY_CLK_SRC_OFFSET, \
COMPHY_CLK_SRC_LEN)
#define COMPHY_PCI_WIDTH_OFFSET (COMPHY_CLK_SRC_OFFSET + COMPHY_CLK_SRC_LEN)
#define COMPHY_PCI_WIDTH_LEN 3
#define COMPHY_PCI_WIDTH_MASK COMPHY_MASK(COMPHY_PCI_WIDTH_OFFSET, \
COMPHY_PCI_WIDTH_LEN)
#define COMPHY_MASK(offset, len) (((1 << (len)) - 1) << (offset))
/* Macro which extracts mode from lane description */
#define COMPHY_GET_MODE(x) (((x) & COMPHY_MODE_MASK) >> \
COMPHY_MODE_OFFSET)
/* Macro which extracts unit index from lane description */
#define COMPHY_GET_ID(x) (((x) & COMPHY_UNIT_ID_MASK) >> \
COMPHY_UNIT_ID_OFFSET)
/* Macro which extracts speed from lane description */
#define COMPHY_GET_SPEED(x) (((x) & COMPHY_SPEED_MASK) >> \
COMPHY_SPEED_OFFSET)
/* Macro which extracts clock source indication from lane description */
#define COMPHY_GET_CLK_SRC(x) (((x) & COMPHY_CLK_SRC_MASK) >> \
COMPHY_CLK_SRC_OFFSET)
/* Macro which extracts pcie width indication from lane description */
#define COMPHY_GET_PCIE_WIDTH(x) (((x) & COMPHY_PCI_WIDTH_MASK) >> \
COMPHY_PCI_WIDTH_OFFSET)
#define COMPHY_SATA_MODE 0x1
#define COMPHY_SGMII_MODE 0x2 /* SGMII 1G */
#define COMPHY_HS_SGMII_MODE 0x3 /* SGMII 2.5G */
#define COMPHY_USB3H_MODE 0x4
#define COMPHY_USB3D_MODE 0x5
#define COMPHY_PCIE_MODE 0x6
#define COMPHY_RXAUI_MODE 0x7
#define COMPHY_XFI_MODE 0x8
#define COMPHY_SFI_MODE 0x9
#define COMPHY_USB3_MODE 0xa
#define COMPHY_AP_MODE 0xb
/* COMPHY speed macro */
#define COMPHY_SPEED_1_25G 0 /* SGMII 1G */
#define COMPHY_SPEED_2_5G 1
......@@ -129,21 +66,6 @@
*/
spinlock_t cp110_mac_reset_lock;
enum reg_width_type {
REG_16BIT = 0,
REG_32BIT,
};
enum {
COMPHY_LANE0 = 0,
COMPHY_LANE1,
COMPHY_LANE2,
COMPHY_LANE3,
COMPHY_LANE4,
COMPHY_LANE5,
COMPHY_LANE_MAX,
};
/* These values come from the PCI Express Spec */
enum pcie_link_width {
PCIE_LNK_WIDTH_RESRV = 0x00,
......@@ -157,36 +79,24 @@ enum pcie_link_width {
PCIE_LNK_WIDTH_UNKNOWN = 0xFF,
};
static inline uint32_t polling_with_timeout(uintptr_t addr,
uint32_t val,
uint32_t mask,
uint32_t usec_timeout,
enum reg_width_type type)
{
uint32_t data;
do {
udelay(1);
if (type == REG_16BIT)
data = mmio_read_16(addr) & mask;
else
data = mmio_read_32(addr) & mask;
} while (data != val && --usec_timeout > 0);
if (usec_timeout == 0)
return data;
_Bool rx_trainng_done[AP_NUM][CP_NUM][MAX_LANE_NR] = {0};
return 0;
}
static inline void reg_set(uintptr_t addr, uint32_t data, uint32_t mask)
static void mvebu_cp110_get_ap_and_cp_nr(uint8_t *ap_nr, uint8_t *cp_nr,
uint64_t comphy_base)
{
debug("<atf>: WR to addr = %#010lx, data = %#010x (mask = %#010x) - ",
addr, data, mask);
debug("old value = %#010x ==> ", mmio_read_32(addr));
mmio_clrsetbits_32(addr, mask, data);
#if (AP_NUM == 1)
*ap_nr = 0;
#else
*ap_nr = (((comphy_base & ~0xffffff) - MVEBU_AP_IO_BASE(0)) /
AP_IO_OFFSET);
#endif
*cp_nr = (((comphy_base & ~0xffffff) - MVEBU_AP_IO_BASE(*ap_nr)) /
MVEBU_CP_OFFSET);
debug("new val %#010x\n", mmio_read_32(addr));
debug("cp_base 0x%llx, ap_io_base 0x%lx, cp_offset 0x%lx\n",
comphy_base, (unsigned long)MVEBU_AP_IO_BASE(*ap_nr),
(unsigned long)MVEBU_CP_OFFSET);
}
/* Clear PIPE selector - avoid collision with previous configuration */
......@@ -413,10 +323,17 @@ static int mvebu_cp110_comphy_sata_power_on(uint64_t comphy_base,
{
uintptr_t hpipe_addr, sd_ip_addr, comphy_addr;
uint32_t mask, data;
uint8_t ap_nr, cp_nr;
int ret = 0;
debug_enter();
mvebu_cp110_get_ap_and_cp_nr(&ap_nr, &cp_nr, comphy_base);
const struct sata_params *sata_static_values =
&sata_static_values_tab[ap_nr][cp_nr][comphy_index];
/* configure phy selector for SATA */
mvebu_cp110_comphy_set_phy_selector(comphy_base,
comphy_index, comphy_mode);
......@@ -480,13 +397,17 @@ static int mvebu_cp110_comphy_sata_power_on(uint64_t comphy_base,
debug("stage: Analog parameters from ETP(HW)\n");
/* G1 settings */
mask = HPIPE_G1_SET_1_G1_RX_SELMUPI_MASK;
data = 0x0 << HPIPE_G1_SET_1_G1_RX_SELMUPI_OFFSET;
data = sata_static_values->g1_rx_selmupi <<
HPIPE_G1_SET_1_G1_RX_SELMUPI_OFFSET;
mask |= HPIPE_G1_SET_1_G1_RX_SELMUPF_MASK;
data |= 0x1 << HPIPE_G1_SET_1_G1_RX_SELMUPF_OFFSET;
data |= sata_static_values->g1_rx_selmupf <<
HPIPE_G1_SET_1_G1_RX_SELMUPF_OFFSET;
mask |= HPIPE_G1_SET_1_G1_RX_SELMUFI_MASK;
data |= 0x0 << HPIPE_G1_SET_1_G1_RX_SELMUFI_OFFSET;
data |= sata_static_values->g1_rx_selmufi <<
HPIPE_G1_SET_1_G1_RX_SELMUFI_OFFSET;
mask |= HPIPE_G1_SET_1_G1_RX_SELMUFF_MASK;
data |= 0x3 << HPIPE_G1_SET_1_G1_RX_SELMUFF_OFFSET;
data |= sata_static_values->g1_rx_selmuff <<
HPIPE_G1_SET_1_G1_RX_SELMUFF_OFFSET;
mask |= HPIPE_G1_SET_1_G1_RX_DIGCK_DIV_MASK;
data |= 0x1 << HPIPE_G1_SET_1_G1_RX_DIGCK_DIV_OFFSET;
reg_set(hpipe_addr + HPIPE_G1_SET_1_REG, data, mask);
......@@ -505,26 +426,34 @@ static int mvebu_cp110_comphy_sata_power_on(uint64_t comphy_base,
/* G2 settings */
mask = HPIPE_G2_SET_1_G2_RX_SELMUPI_MASK;
data = 0x0 << HPIPE_G2_SET_1_G2_RX_SELMUPI_OFFSET;
data = sata_static_values->g2_rx_selmupi <<
HPIPE_G2_SET_1_G2_RX_SELMUPI_OFFSET;
mask |= HPIPE_G2_SET_1_G2_RX_SELMUPF_MASK;
data |= 0x1 << HPIPE_G2_SET_1_G2_RX_SELMUPF_OFFSET;
data |= sata_static_values->g2_rx_selmupf <<
HPIPE_G2_SET_1_G2_RX_SELMUPF_OFFSET;
mask |= HPIPE_G2_SET_1_G2_RX_SELMUFI_MASK;
data |= 0x0 << HPIPE_G2_SET_1_G2_RX_SELMUFI_OFFSET;
data |= sata_static_values->g2_rx_selmufi <<
HPIPE_G2_SET_1_G2_RX_SELMUFI_OFFSET;
mask |= HPIPE_G2_SET_1_G2_RX_SELMUFF_MASK;
data |= 0x3 << HPIPE_G2_SET_1_G2_RX_SELMUFF_OFFSET;
data |= sata_static_values->g2_rx_selmuff <<
HPIPE_G2_SET_1_G2_RX_SELMUFF_OFFSET;
mask |= HPIPE_G2_SET_1_G2_RX_DIGCK_DIV_MASK;
data |= 0x1 << HPIPE_G2_SET_1_G2_RX_DIGCK_DIV_OFFSET;
reg_set(hpipe_addr + HPIPE_G2_SET_1_REG, data, mask);
/* G3 settings */
mask = HPIPE_G3_SET_1_G3_RX_SELMUPI_MASK;
data = 0x2 << HPIPE_G3_SET_1_G3_RX_SELMUPI_OFFSET;
data = sata_static_values->g3_rx_selmupi <<
HPIPE_G3_SET_1_G3_RX_SELMUPI_OFFSET;
mask |= HPIPE_G3_SET_1_G3_RX_SELMUPF_MASK;
data |= 0x2 << HPIPE_G3_SET_1_G3_RX_SELMUPF_OFFSET;
data |= sata_static_values->g3_rx_selmupf <<
HPIPE_G3_SET_1_G3_RX_SELMUPF_OFFSET;
mask |= HPIPE_G3_SET_1_G3_RX_SELMUFI_MASK;
data |= 0x3 << HPIPE_G3_SET_1_G3_RX_SELMUFI_OFFSET;
data |= sata_static_values->g3_rx_selmufi <<
HPIPE_G3_SET_1_G3_RX_SELMUFI_OFFSET;
mask |= HPIPE_G3_SET_1_G3_RX_SELMUFF_MASK;
data |= 0x3 << HPIPE_G3_SET_1_G3_RX_SELMUFF_OFFSET;
data |= sata_static_values->g3_rx_selmuff <<
HPIPE_G3_SET_1_G3_RX_SELMUFF_OFFSET;
mask |= HPIPE_G3_SET_1_G3_RX_DFE_EN_MASK;
data |= 0x1 << HPIPE_G3_SET_1_G3_RX_DFE_EN_OFFSET;
mask |= HPIPE_G3_SET_1_G3_RX_DIGCK_DIV_MASK;
......@@ -577,9 +506,11 @@ static int mvebu_cp110_comphy_sata_power_on(uint64_t comphy_base,
/* G3 Setting 3 */
mask = HPIPE_G3_FFE_CAP_SEL_MASK;
data = 0xf << HPIPE_G3_FFE_CAP_SEL_OFFSET;
data = sata_static_values->g3_ffe_cap_sel <<
HPIPE_G3_FFE_CAP_SEL_OFFSET;
mask |= HPIPE_G3_FFE_RES_SEL_MASK;
data |= 0x4 << HPIPE_G3_FFE_RES_SEL_OFFSET;
data |= sata_static_values->g3_ffe_res_sel <<
HPIPE_G3_FFE_RES_SEL_OFFSET;
mask |= HPIPE_G3_FFE_SETTING_FORCE_MASK;
data |= 0x1 << HPIPE_G3_FFE_SETTING_FORCE_OFFSET;
mask |= HPIPE_G3_FFE_DEG_RES_LEVEL_MASK;
......@@ -590,12 +521,12 @@ static int mvebu_cp110_comphy_sata_power_on(uint64_t comphy_base,
/* G3 Setting 4 */
mask = HPIPE_G3_DFE_RES_MASK;
data = 0x1 << HPIPE_G3_DFE_RES_OFFSET;
data = sata_static_values->g3_dfe_res << HPIPE_G3_DFE_RES_OFFSET;
reg_set(hpipe_addr + HPIPE_G3_SETTING_4_REG, data, mask);
/* Offset Phase Control */
mask = HPIPE_OS_PH_OFFSET_MASK;
data = 0x61 << HPIPE_OS_PH_OFFSET_OFFSET;
data = sata_static_values->align90 << HPIPE_OS_PH_OFFSET_OFFSET;
mask |= HPIPE_OS_PH_OFFSET_FORCE_MASK;
data |= 0x1 << HPIPE_OS_PH_OFFSET_FORCE_OFFSET;
mask |= HPIPE_OS_PH_VALID_MASK;
......@@ -610,41 +541,77 @@ static int mvebu_cp110_comphy_sata_power_on(uint64_t comphy_base,
/* Set G1 TX amplitude and TX post emphasis value */
mask = HPIPE_G1_SET_0_G1_TX_AMP_MASK;
data = 0x8 << HPIPE_G1_SET_0_G1_TX_AMP_OFFSET;
data = sata_static_values->g1_amp << HPIPE_G1_SET_0_G1_TX_AMP_OFFSET;
mask |= HPIPE_G1_SET_0_G1_TX_AMP_ADJ_MASK;
data |= 0x1 << HPIPE_G1_SET_0_G1_TX_AMP_ADJ_OFFSET;
data |= sata_static_values->g1_tx_amp_adj <<
HPIPE_G1_SET_0_G1_TX_AMP_ADJ_OFFSET;
mask |= HPIPE_G1_SET_0_G1_TX_EMPH1_MASK;
data |= 0x1 << HPIPE_G1_SET_0_G1_TX_EMPH1_OFFSET;
data |= sata_static_values->g1_emph <<
HPIPE_G1_SET_0_G1_TX_EMPH1_OFFSET;
mask |= HPIPE_G1_SET_0_G1_TX_EMPH1_EN_MASK;
data |= 0x1 << HPIPE_G1_SET_0_G1_TX_EMPH1_EN_OFFSET;
data |= sata_static_values->g1_emph_en <<
HPIPE_G1_SET_0_G1_TX_EMPH1_EN_OFFSET;
reg_set(hpipe_addr + HPIPE_G1_SET_0_REG, data, mask);
/* Set G1 emph */
mask = HPIPE_G1_SET_2_G1_TX_EMPH0_EN_MASK;
data = sata_static_values->g1_tx_emph_en <<
HPIPE_G1_SET_2_G1_TX_EMPH0_EN_OFFSET;
mask |= HPIPE_G1_SET_2_G1_TX_EMPH0_MASK;
data |= sata_static_values->g1_tx_emph <<
HPIPE_G1_SET_2_G1_TX_EMPH0_OFFSET;
reg_set(hpipe_addr + HPIPE_G1_SET_2_REG, data, mask);
/* Set G2 TX amplitude and TX post emphasis value */
mask = HPIPE_G2_SET_0_G2_TX_AMP_MASK;
data = 0xa << HPIPE_G2_SET_0_G2_TX_AMP_OFFSET;
data = sata_static_values->g2_amp << HPIPE_G2_SET_0_G2_TX_AMP_OFFSET;
mask |= HPIPE_G2_SET_0_G2_TX_AMP_ADJ_MASK;
data |= 0x1 << HPIPE_G2_SET_0_G2_TX_AMP_ADJ_OFFSET;
data |= sata_static_values->g2_tx_amp_adj <<
HPIPE_G2_SET_0_G2_TX_AMP_ADJ_OFFSET;
mask |= HPIPE_G2_SET_0_G2_TX_EMPH1_MASK;
data |= 0x2 << HPIPE_G2_SET_0_G2_TX_EMPH1_OFFSET;
data |= sata_static_values->g2_emph <<
HPIPE_G2_SET_0_G2_TX_EMPH1_OFFSET;
mask |= HPIPE_G2_SET_0_G2_TX_EMPH1_EN_MASK;
data |= 0x1 << HPIPE_G2_SET_0_G2_TX_EMPH1_EN_OFFSET;
data |= sata_static_values->g2_emph_en <<
HPIPE_G2_SET_0_G2_TX_EMPH1_EN_OFFSET;
reg_set(hpipe_addr + HPIPE_G2_SET_0_REG, data, mask);
/* Set G2 emph */
mask = HPIPE_G2_SET_2_G2_TX_EMPH0_EN_MASK;
data = sata_static_values->g2_tx_emph_en <<
HPIPE_G2_SET_2_G2_TX_EMPH0_EN_OFFSET;
mask |= HPIPE_G2_SET_2_G2_TX_EMPH0_MASK;
data |= sata_static_values->g2_tx_emph <<
HPIPE_G2_SET_2_G2_TX_EMPH0_OFFSET;
reg_set(hpipe_addr + HPIPE_G2_SET_2_REG, data, mask);
/* Set G3 TX amplitude and TX post emphasis value */
mask = HPIPE_G3_SET_0_G3_TX_AMP_MASK;
data = 0x1e << HPIPE_G3_SET_0_G3_TX_AMP_OFFSET;
data = sata_static_values->g3_amp << HPIPE_G3_SET_0_G3_TX_AMP_OFFSET;
mask |= HPIPE_G3_SET_0_G3_TX_AMP_ADJ_MASK;
data |= 0x1 << HPIPE_G3_SET_0_G3_TX_AMP_ADJ_OFFSET;
data |= sata_static_values->g3_tx_amp_adj <<
HPIPE_G3_SET_0_G3_TX_AMP_ADJ_OFFSET;
mask |= HPIPE_G3_SET_0_G3_TX_EMPH1_MASK;
data |= 0xe << HPIPE_G3_SET_0_G3_TX_EMPH1_OFFSET;
data |= sata_static_values->g3_emph <<
HPIPE_G3_SET_0_G3_TX_EMPH1_OFFSET;
mask |= HPIPE_G3_SET_0_G3_TX_EMPH1_EN_MASK;
data |= 0x1 << HPIPE_G3_SET_0_G3_TX_EMPH1_EN_OFFSET;
data |= sata_static_values->g3_emph_en <<
HPIPE_G3_SET_0_G3_TX_EMPH1_EN_OFFSET;
mask |= HPIPE_G3_SET_0_G3_TX_SLEW_RATE_SEL_MASK;
data |= 0x4 << HPIPE_G3_SET_0_G3_TX_SLEW_RATE_SEL_OFFSET;
mask |= HPIPE_G3_SET_0_G3_TX_SLEW_CTRL_EN_MASK;
data |= 0x0 << HPIPE_G3_SET_0_G3_TX_SLEW_CTRL_EN_OFFSET;
reg_set(hpipe_addr + HPIPE_G3_SET_0_REG, data, mask);
/* Set G3 emph */
mask = HPIPE_G3_SET_2_G3_TX_EMPH0_EN_MASK;
data = sata_static_values->g3_tx_emph_en <<
HPIPE_G3_SET_2_G3_TX_EMPH0_EN_OFFSET;
mask |= HPIPE_G3_SET_2_G3_TX_EMPH0_MASK;
data |= sata_static_values->g3_tx_emph <<
HPIPE_G3_SET_2_G3_TX_EMPH0_OFFSET;
reg_set(hpipe_addr + HPIPE_G3_SET_2_REG, data, mask);
/* SERDES External Configuration 2 register */
mask = SD_EXTERNAL_CONFIG2_SSC_ENABLE_MASK;
data = 0x1 << SD_EXTERNAL_CONFIG2_SSC_ENABLE_OFFSET;
......@@ -779,7 +746,7 @@ static int mvebu_cp110_comphy_sgmii_power_on(uint64_t comphy_base,
data = 0x0 << HPIPE_PWR_CTR_DTL_FLOOP_EN_OFFSET;
reg_set(hpipe_addr + HPIPE_PWR_CTR_DTL_REG, data, mask);
/* Set analog parameters from ETP(HW) - for now use the default datas */
/* Set analog parameters from ETP(HW) - for now use the default data */
debug("stage: Analog parameters from ETP(HW)\n");
reg_set(hpipe_addr + HPIPE_G1_SET_0_REG,
......@@ -835,9 +802,37 @@ static int mvebu_cp110_comphy_xfi_power_on(uint64_t comphy_base,
uintptr_t hpipe_addr, sd_ip_addr, comphy_addr, addr;
uint32_t mask, data, speed = COMPHY_GET_SPEED(comphy_mode);
int ret = 0;
uint8_t ap_nr, cp_nr;
debug_enter();
mvebu_cp110_get_ap_and_cp_nr(&ap_nr, &cp_nr, comphy_base);
if (rx_trainng_done[ap_nr][cp_nr][comphy_index]) {
debug("Skip %s for comphy[%d][%d][%d], due to rx training\n",
__func__, ap_nr, cp_nr, comphy_index);
return 0;
}
const struct xfi_params *xfi_static_values =
&xfi_static_values_tab[ap_nr][cp_nr][comphy_index];
debug("%s: the ap_nr = %d, cp_nr = %d, comphy_index %d\n",
__func__, ap_nr, cp_nr, comphy_index);
debug("g1_ffe_cap_sel= 0x%x, g1_ffe_res_sel= 0x%x, g1_dfe_res= 0x%x\n",
xfi_static_values->g1_ffe_cap_sel,
xfi_static_values->g1_ffe_res_sel,
xfi_static_values->g1_dfe_res);
if (!xfi_static_values->valid) {
ERROR("[ap%d][cp[%d][comphy:%d]: Has no valid static params\n",
ap_nr, cp_nr, comphy_index);
ERROR("[ap%d][cp[%d][comphy:%d]: porting layer needs update\n",
ap_nr, cp_nr, comphy_index);
return -EINVAL;
}
if ((speed != COMPHY_SPEED_5_15625G) &&
(speed != COMPHY_SPEED_10_3125G) &&
(speed != COMPHY_SPEED_DEFAULT)) {
......@@ -966,16 +961,27 @@ static int mvebu_cp110_comphy_xfi_power_on(uint64_t comphy_base,
data = 0x6 << HPIPE_G1_SET_0_G1_TX_EMPH1_OFFSET;
} else {
mask = HPIPE_G1_SET_0_G1_TX_AMP_MASK;
data = 0x1c << HPIPE_G1_SET_0_G1_TX_AMP_OFFSET;
data = xfi_static_values->g1_amp <<
HPIPE_G1_SET_0_G1_TX_AMP_OFFSET;
mask |= HPIPE_G1_SET_0_G1_TX_EMPH1_MASK;
data |= 0xe << HPIPE_G1_SET_0_G1_TX_EMPH1_OFFSET;
data |= xfi_static_values->g1_emph <<
HPIPE_G1_SET_0_G1_TX_EMPH1_OFFSET;
mask |= HPIPE_G1_SET_0_G1_TX_EMPH1_EN_MASK;
data |= xfi_static_values->g1_emph_en <<
HPIPE_G1_SET_0_G1_TX_EMPH1_EN_OFFSET;
mask |= HPIPE_G1_SET_0_G1_TX_AMP_ADJ_MASK;
data |= xfi_static_values->g1_tx_amp_adj <<
HPIPE_G1_SET_0_G1_TX_AMP_ADJ_OFFSET;
}
reg_set(hpipe_addr + HPIPE_G1_SET_0_REG, data, mask);
/* Genration 1 setting 2 (G1_Setting_2) */
mask = HPIPE_G1_SET_2_G1_TX_EMPH0_MASK;
data = 0x0 << HPIPE_G1_SET_2_G1_TX_EMPH0_OFFSET;
data = xfi_static_values->g1_tx_emph <<
HPIPE_G1_SET_2_G1_TX_EMPH0_OFFSET;
mask |= HPIPE_G1_SET_2_G1_TX_EMPH0_EN_MASK;
data |= 0x1 << HPIPE_G1_SET_2_G1_TX_EMPH0_EN_OFFSET;
data |= xfi_static_values->g1_tx_emph_en <<
HPIPE_G1_SET_2_G1_TX_EMPH0_EN_OFFSET;
reg_set(hpipe_addr + HPIPE_G1_SET_2_REG, data, mask);
/* Transmitter Slew Rate Control register (tx_reg1) */
mask = HPIPE_TX_REG1_TX_EMPH_RES_MASK;
......@@ -1004,13 +1010,17 @@ static int mvebu_cp110_comphy_xfi_power_on(uint64_t comphy_base,
data |= 0x1 << HPIPE_G1_SET_1_G1_RX_SELMUPF_OFFSET;
} else {
mask |= HPIPE_G1_SET_1_G1_RX_SELMUPI_MASK;
data |= 0x2 << HPIPE_G1_SET_1_G1_RX_SELMUPI_OFFSET;
data |= xfi_static_values->g1_rx_selmupi <<
HPIPE_G1_SET_1_G1_RX_SELMUPI_OFFSET;
mask |= HPIPE_G1_SET_1_G1_RX_SELMUPF_MASK;
data |= 0x2 << HPIPE_G1_SET_1_G1_RX_SELMUPF_OFFSET;
data |= xfi_static_values->g1_rx_selmupf <<
HPIPE_G1_SET_1_G1_RX_SELMUPF_OFFSET;
mask |= HPIPE_G1_SET_1_G1_RX_SELMUFI_MASK;
data |= 0x0 << HPIPE_G1_SET_1_G1_RX_SELMUFI_OFFSET;
data |= xfi_static_values->g1_rx_selmufi <<
HPIPE_G1_SET_1_G1_RX_SELMUFI_OFFSET;
mask |= HPIPE_G1_SET_1_G1_RX_SELMUFF_MASK;
data |= 0x1 << HPIPE_G1_SET_1_G1_RX_SELMUFF_OFFSET;
data |= xfi_static_values->g1_rx_selmuff <<
HPIPE_G1_SET_1_G1_RX_SELMUFF_OFFSET;
mask |= HPIPE_G1_SET_1_G1_RX_DIGCK_DIV_MASK;
data |= 0x3 << HPIPE_G1_SET_1_G1_RX_DIGCK_DIV_OFFSET;
}
......@@ -1038,8 +1048,43 @@ static int mvebu_cp110_comphy_xfi_power_on(uint64_t comphy_base,
data |= 0x4 << HPIPE_G1_SETTINGS_3_G1_FFE_RES_SEL_OFFSET;
mask |= HPIPE_G1_SETTINGS_3_G1_FFE_SETTING_FORCE_MASK;
data |= 0x1 << HPIPE_G1_SETTINGS_3_G1_FFE_SETTING_FORCE_OFFSET;
reg_set(hpipe_addr + HPIPE_G1_SETTINGS_3_REG, data, mask);
} else {
mask |= HPIPE_G1_SETTINGS_3_G1_FFE_CAP_SEL_MASK;
data |= xfi_static_values->g1_ffe_cap_sel <<
HPIPE_G1_SETTINGS_3_G1_FFE_CAP_SEL_OFFSET;
mask |= HPIPE_G1_SETTINGS_3_G1_FFE_RES_SEL_MASK;
data |= xfi_static_values->g1_ffe_res_sel <<
HPIPE_G1_SETTINGS_3_G1_FFE_RES_SEL_OFFSET;
mask |= HPIPE_G1_SETTINGS_3_G1_FFE_SETTING_FORCE_MASK;
data |= 0x1 << HPIPE_G1_SETTINGS_3_G1_FFE_SETTING_FORCE_OFFSET;
reg_set(hpipe_addr + HPIPE_G1_SETTINGS_3_REG, data, mask);
/* Use the value from CAL_OS_PH_EXT */
mask = HPIPE_CAL_RXCLKALIGN_90_EXT_EN_MASK;
data = 1 << HPIPE_CAL_RXCLKALIGN_90_EXT_EN_OFFSET;
reg_set(hpipe_addr +
HPIPE_RX_CLK_ALIGN90_AND_TX_IDLE_CALIB_CTRL_REG,
data, mask);
/* Update align90 */
mask = HPIPE_CAL_OS_PH_EXT_MASK;
data = xfi_static_values->align90 << HPIPE_CAL_OS_PH_EXT_OFFSET;
reg_set(hpipe_addr +
HPIPE_RX_CLK_ALIGN90_AND_TX_IDLE_CALIB_CTRL_REG,
data, mask);
/* Force DFE resolution (use gen table value) */
mask = HPIPE_DFE_RES_FORCE_MASK;
data = 0x0 << HPIPE_DFE_RES_FORCE_OFFSET;
reg_set(hpipe_addr + HPIPE_DFE_REG0, data, mask);
/* 0x111-G1 DFE_Setting_4 */
mask = HPIPE_G1_SETTINGS_4_G1_DFE_RES_MASK;
data = xfi_static_values->g1_dfe_res <<
HPIPE_G1_SETTINGS_4_G1_DFE_RES_OFFSET;
reg_set(hpipe_addr + HPIPE_G1_SETTINGS_4_REG, data, mask);
}
reg_set(hpipe_addr + HPIPE_G1_SETTINGS_3_REG, data, mask);
/* Connfigure RX training timer */
mask = HPIPE_RX_TRAIN_TIMER_MASK;
......@@ -1949,192 +1994,255 @@ static int mvebu_cp110_comphy_usb3_power_on(uint64_t comphy_base,
return ret;
}
/* This function performs RX training for one Feed Forward Equalization (FFE)
* value.
* The RX traiing result is stored in 'Saved DFE values Register' (SAV_F0D).
*
* Return '0' on success, error code in a case of failure.
*/
static int mvebu_cp110_comphy_test_single_ffe(uint64_t comphy_base,
uint8_t comphy_index,
uint32_t ffe, uint32_t *result)
int mvebu_cp110_comphy_xfi_rx_training(uint64_t comphy_base,
uint8_t comphy_index)
{
uint32_t mask, data, timeout;
uint32_t g1_ffe_cap_sel, g1_ffe_res_sel, align90, g1_dfe_res;
uintptr_t hpipe_addr, sd_ip_addr;
uint8_t ap_nr, cp_nr;
mvebu_cp110_get_ap_and_cp_nr(&ap_nr, &cp_nr, comphy_base);
hpipe_addr = HPIPE_ADDR(COMPHY_PIPE_FROM_COMPHY_ADDR(comphy_base),
comphy_index);
sd_ip_addr = SD_ADDR(COMPHY_PIPE_FROM_COMPHY_ADDR(comphy_base),
comphy_index);
debug_enter();
debug("stage: RF Reset\n");
/* Release from hard reset */
mask = SD_EXTERNAL_CONFIG1_RESET_IN_MASK;
data = 0x0 << SD_EXTERNAL_CONFIG1_RESET_IN_OFFSET;
mask |= SD_EXTERNAL_CONFIG1_RESET_CORE_MASK;
data |= 0x0 << SD_EXTERNAL_CONFIG1_RESET_CORE_OFFSET;
mask |= SD_EXTERNAL_CONFIG1_RF_RESET_IN_MASK;
data |= 0x0 << SD_EXTERNAL_CONFIG1_RF_RESET_IN_OFFSET;
reg_set(sd_ip_addr + SD_EXTERNAL_CONFIG1_REG, data, mask);
mask = SD_EXTERNAL_CONFIG1_RESET_IN_MASK;
data = 0x1 << SD_EXTERNAL_CONFIG1_RESET_IN_OFFSET;
mask |= SD_EXTERNAL_CONFIG1_RESET_CORE_MASK;
data |= 0x1 << SD_EXTERNAL_CONFIG1_RESET_CORE_OFFSET;
reg_set(sd_ip_addr + SD_EXTERNAL_CONFIG1_REG, data, mask);
/* Wait 50ms - until band gap and ref clock ready */
mdelay(50);
debug("Preparation for rx_training\n\n");
/* Use the FFE table */
mask = HPIPE_G1_SETTINGS_3_G1_FFE_SETTING_FORCE_MASK;
data = 0 << HPIPE_G1_SETTINGS_3_G1_FFE_SETTING_FORCE_OFFSET;
reg_set(hpipe_addr + HPIPE_G1_SETTINGS_3_REG, data, mask);
/* Use auto-calibration value */
mask = HPIPE_CAL_RXCLKALIGN_90_EXT_EN_MASK;
data = 0 << HPIPE_CAL_RXCLKALIGN_90_EXT_EN_OFFSET;
reg_set(hpipe_addr + HPIPE_RX_CLK_ALIGN90_AND_TX_IDLE_CALIB_CTRL_REG,
data, mask);
/* Use Tx/Rx training results */
mask = HPIPE_DFE_RES_FORCE_MASK;
data = 0 << HPIPE_DFE_RES_FORCE_OFFSET;
reg_set(hpipe_addr + HPIPE_DFE_REG0, data, mask);
debug("PRBS31 loppback\n\n");
/* Configure PRBS counters */
mask = HPIPE_PHY_TEST_PATTERN_SEL_MASK;
data = 0xe << HPIPE_PHY_TEST_PATTERN_SEL_OFFSET;
reg_set(hpipe_addr + HPIPE_PHY_TEST_CONTROL_REG, data, mask);
mask = HPIPE_PHY_TEST_DATA_MASK;
data = 0x64 << HPIPE_PHY_TEST_DATA_OFFSET;
data = 0xc4 << HPIPE_PHY_TEST_DATA_OFFSET;
reg_set(hpipe_addr + HPIPE_PHY_TEST_DATA_REG, data, mask);
mask = HPIPE_PHY_TEST_EN_MASK;
data = 0x1 << HPIPE_PHY_TEST_EN_OFFSET;
reg_set(hpipe_addr + HPIPE_PHY_TEST_CONTROL_REG, data, mask);
mdelay(50);
/* Set the FFE value */
mask = HPIPE_G1_SETTINGS_3_G1_FFE_RES_SEL_MASK;
data = ffe << HPIPE_G1_SETTINGS_3_G1_FFE_RES_SEL_OFFSET;
reg_set(hpipe_addr + HPIPE_G1_SETTINGS_3_REG, data, mask);
/* Start RX training */
mask = SD_EXTERNAL_STATUS_START_RX_TRAINING_MASK;
data = 1 << SD_EXTERNAL_STATUS_START_RX_TRAINING_OFFSET;
reg_set(sd_ip_addr + SD_EXTERNAL_STATUS_REG, data, mask);
mdelay(10);
debug("Enable TX/RX training\n\n");
mask = HPIPE_TRX_RX_TRAIN_EN_MASK;
data = 0x1 << HPIPE_TRX_RX_TRAIN_EN_OFFSET;
mask |= HPIPE_TRX_RX_ANA_IF_CLK_ENE_MASK;
data |= 0x1 << HPIPE_TRX_RX_ANA_IF_CLK_ENE_OFFSET;
mask |= HPIPE_TRX_TX_CTRL_CLK_EN_MASK;
data |= 0x1 << HPIPE_TRX_TX_CTRL_CLK_EN_OFFSET;
mask |= HPIPE_TRX_UPDATE_THEN_HOLD_MASK;
data |= 0x1 << HPIPE_TRX_UPDATE_THEN_HOLD_OFFSET;
mask |= HPIPE_TRX_TX_F0T_EO_BASED_MASK;
data |= 0x1 << HPIPE_TRX_TX_F0T_EO_BASED_OFFSET;
reg_set(hpipe_addr + HPIPE_TRX_TRAIN_CTRL_0_REG, data, mask);
/* Check the result of RX training */
timeout = RX_TRAINING_TIMEOUT;
mask = HPIPE_INTERRUPT_TRX_TRAIN_DONE_OFFSET |
HPIPE_INTERRUPT_DFE_DONE_INT_OFFSET |
HPIPE_INTERRUPT_RX_TRAIN_COMPLETE_INT_MASK;
while (timeout) {
data = mmio_read_32(sd_ip_addr + SD_EXTERNAL_STATAUS1_REG);
if (data & SD_EXTERNAL_STATAUS1_REG_RX_TRAIN_COMP_MASK)
data = mmio_read_32(hpipe_addr + HPIPE_INTERRUPT_1_REGISTER);
if (data & mask)
break;
mdelay(1);
timeout--;
}
if (timeout == 0)
debug("RX training result: interrupt reg 0x%lx = 0x%x\n\n",
hpipe_addr + HPIPE_INTERRUPT_1_REGISTER, data);
if (timeout == 0 || data & HPIPE_TRX_TRAIN_TIME_OUT_INT_MASK) {
ERROR("Rx training timeout...\n");
return -ETIMEDOUT;
}
if (data & SD_EXTERNAL_STATAUS1_REG_RX_TRAIN_FAILED_MASK)
if (data & HPIPE_TRX_TRAIN_FAILED_MASK) {
ERROR("Rx training failed...\n");
return -EINVAL;
}
/* Stop RX training */
mask = SD_EXTERNAL_STATUS_START_RX_TRAINING_MASK;
data = 0 << SD_EXTERNAL_STATUS_START_RX_TRAINING_OFFSET;
reg_set(sd_ip_addr + SD_EXTERNAL_STATUS_REG, data, mask);
mask = HPIPE_TRX_RX_TRAIN_EN_MASK;
data = 0x0 << HPIPE_TRX_RX_TRAIN_EN_OFFSET;
reg_set(hpipe_addr + HPIPE_TRX_TRAIN_CTRL_0_REG, data, mask);
debug("Training done, reading results...\n\n");
mask = HPIPE_ADAPTED_FFE_ADAPTED_FFE_RES_MASK;
g1_ffe_res_sel = ((mmio_read_32(hpipe_addr +
HPIPE_ADAPTED_FFE_CAPACITOR_COUNTER_CTRL_REG)
& mask) >> HPIPE_ADAPTED_FFE_ADAPTED_FFE_RES_OFFSET);
mask = HPIPE_ADAPTED_FFE_ADAPTED_FFE_CAP_MASK;
g1_ffe_cap_sel = ((mmio_read_32(hpipe_addr +
HPIPE_ADAPTED_FFE_CAPACITOR_COUNTER_CTRL_REG)
& mask) >> HPIPE_ADAPTED_FFE_ADAPTED_FFE_CAP_OFFSET);
mask = HPIPE_DATA_PHASE_ADAPTED_OS_PH_MASK;
align90 = ((mmio_read_32(hpipe_addr + HPIPE_DATA_PHASE_OFF_CTRL_REG)
& mask) >> HPIPE_DATA_PHASE_ADAPTED_OS_PH_OFFSET);
mask = HPIPE_ADAPTED_DFE_RES_MASK;
g1_dfe_res = ((mmio_read_32(hpipe_addr +
HPIPE_ADAPTED_DFE_COEFFICIENT_1_REG)
& mask) >> HPIPE_ADAPTED_DFE_RES_OFFSET);
debug("================================================\n");
debug("Switching to static configuration:\n");
debug("FFE_RES = 0x%x FFE_CAP = 0x%x align90 = 0x%x g1_dfe_res 0x%x\n",
g1_ffe_res_sel, g1_ffe_cap_sel, align90, g1_dfe_res);
debug("Result after training: 0x%lx= 0x%x, 0x%lx= 0x%x, 0x%lx = 0x%x\n",
(hpipe_addr + HPIPE_ADAPTED_FFE_CAPACITOR_COUNTER_CTRL_REG),
mmio_read_32(hpipe_addr +
HPIPE_ADAPTED_FFE_CAPACITOR_COUNTER_CTRL_REG),
(hpipe_addr + HPIPE_DATA_PHASE_OFF_CTRL_REG),
mmio_read_32(hpipe_addr + HPIPE_DATA_PHASE_OFF_CTRL_REG),
(hpipe_addr + HPIPE_ADAPTED_DFE_COEFFICIENT_1_REG),
mmio_read_32(hpipe_addr + HPIPE_ADAPTED_DFE_COEFFICIENT_1_REG));
debug("================================================\n");
/* Update FFE_RES */
mask = HPIPE_G1_SETTINGS_3_G1_FFE_RES_SEL_MASK;
data = g1_ffe_res_sel << HPIPE_G1_SETTINGS_3_G1_FFE_RES_SEL_OFFSET;
reg_set(hpipe_addr + HPIPE_G1_SETTINGS_3_REG, data, mask);
/* Read the result */
data = mmio_read_32(hpipe_addr + HPIPE_SAVED_DFE_VALUES_REG);
data &= HPIPE_SAVED_DFE_VALUES_SAV_F0D_MASK;
data >>= HPIPE_SAVED_DFE_VALUES_SAV_F0D_OFFSET;
*result = data;
/* Update FFE_CAP */
mask = HPIPE_G1_SETTINGS_3_G1_FFE_CAP_SEL_MASK;
data = g1_ffe_cap_sel << HPIPE_G1_SETTINGS_3_G1_FFE_CAP_SEL_OFFSET;
reg_set(hpipe_addr + HPIPE_G1_SETTINGS_3_REG, data, mask);
mask = HPIPE_PHY_TEST_RESET_MASK;
data = 0x1 << HPIPE_PHY_TEST_RESET_OFFSET;
mask |= HPIPE_PHY_TEST_EN_MASK;
data |= 0x0 << HPIPE_PHY_TEST_EN_OFFSET;
reg_set(hpipe_addr + HPIPE_PHY_TEST_CONTROL_REG, data, mask);
/* Bypass the FFE table settings and use the FFE settings directly from
* registers FFE_RES_SEL and FFE_CAP_SEL
*/
mask = HPIPE_G1_SETTINGS_3_G1_FFE_SETTING_FORCE_MASK;
data = 1 << HPIPE_G1_SETTINGS_3_G1_FFE_SETTING_FORCE_OFFSET;
reg_set(hpipe_addr + HPIPE_G1_SETTINGS_3_REG, data, mask);
mask = HPIPE_PHY_TEST_RESET_MASK;
data = 0x0 << HPIPE_PHY_TEST_RESET_OFFSET;
reg_set(hpipe_addr + HPIPE_PHY_TEST_CONTROL_REG, data, mask);
/* Use the value from CAL_OS_PH_EXT */
mask = HPIPE_CAL_RXCLKALIGN_90_EXT_EN_MASK;
data = 1 << HPIPE_CAL_RXCLKALIGN_90_EXT_EN_OFFSET;
reg_set(hpipe_addr + HPIPE_RX_CLK_ALIGN90_AND_TX_IDLE_CALIB_CTRL_REG,
data, mask);
return 0;
}
/* This function runs complete RX training sequence:
* - Run RX training for all possible Feed Forward Equalization values
* - Choose the FFE which gives the best result.
* - Run RX training again with the best result.
*
* Return '0' on success, error code in a case of failure.
*/
int mvebu_cp110_comphy_xfi_rx_training(uint64_t comphy_base,
uint8_t comphy_index)
{
uint32_t mask, data, max_rx_train = 0, max_rx_train_index = 0;
uintptr_t hpipe_addr;
uint32_t rx_train_result;
int ret, i;
/* Update align90 */
mask = HPIPE_CAL_OS_PH_EXT_MASK;
data = align90 << HPIPE_CAL_OS_PH_EXT_OFFSET;
reg_set(hpipe_addr + HPIPE_RX_CLK_ALIGN90_AND_TX_IDLE_CALIB_CTRL_REG,
data, mask);
hpipe_addr = HPIPE_ADDR(COMPHY_PIPE_FROM_COMPHY_ADDR(comphy_base),
comphy_index);
/* Force DFE resolution (use gen table value) */
mask = HPIPE_DFE_RES_FORCE_MASK;
data = 0x0 << HPIPE_DFE_RES_FORCE_OFFSET;
reg_set(hpipe_addr + HPIPE_DFE_REG0, data, mask);
debug_enter();
/* 0x111-G1 DFE_Setting_4 */
mask = HPIPE_G1_SETTINGS_4_G1_DFE_RES_MASK;
data = g1_dfe_res << HPIPE_G1_SETTINGS_4_G1_DFE_RES_OFFSET;
reg_set(hpipe_addr + HPIPE_G1_SETTINGS_4_REG, data, mask);
/* Configure SQ threshold and CDR lock */
mask = HPIPE_SQUELCH_THRESH_IN_MASK;
data = 0xc << HPIPE_SQUELCH_THRESH_IN_OFFSET;
reg_set(hpipe_addr + HPIPE_SQUELCH_FFE_SETTING_REG, data, mask);
mask = HPIPE_SQ_DEGLITCH_WIDTH_P_MASK;
data = 0xf << HPIPE_SQ_DEGLITCH_WIDTH_P_OFFSET;
mask |= HPIPE_SQ_DEGLITCH_WIDTH_N_MASK;
data |= 0xf << HPIPE_SQ_DEGLITCH_WIDTH_N_OFFSET;
mask |= HPIPE_SQ_DEGLITCH_EN_MASK;
data |= 0x1 << HPIPE_SQ_DEGLITCH_EN_OFFSET;
reg_set(hpipe_addr + HPIPE_SQ_GLITCH_FILTER_CTRL, data, mask);
mask = HPIPE_CDR_LOCK_DET_EN_MASK;
data = 0x1 << HPIPE_CDR_LOCK_DET_EN_OFFSET;
reg_set(hpipe_addr + HPIPE_LOOPBACK_REG, data, mask);
debug("PRBS31 loppback\n\n");
udelay(100);
mask = HPIPE_PHY_TEST_PT_TESTMODE_MASK;
data = 0x1 << HPIPE_PHY_TEST_PT_TESTMODE_OFFSET;
reg_set(hpipe_addr + HPIPE_PHY_TEST_OOB_0_REGISTER, data, mask);
/* Determine if we have a cable attached to this comphy, if not,
* we can't perform RX training.
*/
data = mmio_read_32(hpipe_addr + HPIPE_SQUELCH_FFE_SETTING_REG);
if (data & HPIPE_SQUELCH_DETECTED_MASK) {
ERROR("Squelsh is not detected, can't perform RX training\n");
return -EINVAL;
}
data = mmio_read_32(hpipe_addr + HPIPE_LOOPBACK_REG);
if (!(data & HPIPE_CDR_LOCK_MASK)) {
ERROR("CDR is not locked, can't perform RX training\n");
return -EINVAL;
}
/* Configure PRBS counters */
mask = HPIPE_PHY_TEST_PATTERN_SEL_MASK;
data = 0xe << HPIPE_PHY_TEST_PATTERN_SEL_OFFSET;
reg_set(hpipe_addr + HPIPE_PHY_TEST_CONTROL_REG, data, mask);
/* Do preparations for RX training */
mask = HPIPE_DFE_RES_FORCE_MASK;
data = 0x0 << HPIPE_DFE_RES_FORCE_OFFSET;
reg_set(hpipe_addr + HPIPE_DFE_REG0, data, mask);
mask = HPIPE_PHY_TEST_DATA_MASK;
data = 0xc4 << HPIPE_PHY_TEST_DATA_OFFSET;
reg_set(hpipe_addr + HPIPE_PHY_TEST_DATA_REG, data, mask);
mask = HPIPE_G1_SETTINGS_3_G1_FFE_CAP_SEL_MASK;
data = 0xf << HPIPE_G1_SETTINGS_3_G1_FFE_CAP_SEL_OFFSET;
mask |= HPIPE_G1_SETTINGS_3_G1_FFE_SETTING_FORCE_MASK;
data |= 1 << HPIPE_G1_SETTINGS_3_G1_FFE_SETTING_FORCE_OFFSET;
reg_set(hpipe_addr + HPIPE_G1_SETTINGS_3_REG, data, mask);
mask = HPIPE_PHY_TEST_EN_MASK;
data = 0x1 << HPIPE_PHY_TEST_EN_OFFSET;
reg_set(hpipe_addr + HPIPE_PHY_TEST_CONTROL_REG, data, mask);
/* Perform RX training for all possible FFE (Feed Forward
* Equalization, possible values are 0-7).
* We update the best value reached and the FFE which gave this value.
*/
for (i = 0; i < MAX_NUM_OF_FFE; i++) {
rx_train_result = 0;
ret = mvebu_cp110_comphy_test_single_ffe(comphy_base,
comphy_index, i,
&rx_train_result);
if ((!ret) && (rx_train_result > max_rx_train)) {
max_rx_train = rx_train_result;
max_rx_train_index = i;
}
}
/* Reset PRBS error counter */
mask = HPIPE_PHY_TEST_PATTERN_SEL_MASK;
data = 0x1 << HPIPE_PHY_TEST_RESET_OFFSET;
reg_set(hpipe_addr + HPIPE_PHY_TEST_CONTROL_REG, data, mask);
/* If we were able to determine which FFE gives the best value,
* now we need to set it and run RX training again (only for this
* FFE).
*/
if (max_rx_train) {
ret = mvebu_cp110_comphy_test_single_ffe(comphy_base,
comphy_index,
max_rx_train_index,
&rx_train_result);
if (ret == 0)
debug("RX Training passed (FFE = %d, result = 0x%x)\n",
max_rx_train_index, rx_train_result);
} else {
ERROR("RX Training failed for comphy%d\n", comphy_index);
ret = -EINVAL;
}
mask = HPIPE_PHY_TEST_PATTERN_SEL_MASK;
data = 0x0 << HPIPE_PHY_TEST_RESET_OFFSET;
reg_set(hpipe_addr + HPIPE_PHY_TEST_CONTROL_REG, data, mask);
debug_exit();
mask = HPIPE_PHY_TEST_PT_TESTMODE_MASK;
data = 0x1 << HPIPE_PHY_TEST_PT_TESTMODE_OFFSET;
reg_set(hpipe_addr + HPIPE_PHY_TEST_OOB_0_REGISTER, data, mask);
printf("########################################################\n");
printf("# To use trained values update the ATF sources:\n");
printf("# plat/marvell/a8k/<board_type>/board/phy-porting-layer.h ");
printf("file\n# with new values as below (for appropriate AP nr %d",
ap_nr);
printf("and CP nr: %d comphy_index %d\n\n",
cp_nr, comphy_index);
printf("static struct xfi_params xfi_static_values_tab[AP_NUM]");
printf("[CP_NUM][MAX_LANE_NR] = {\n");
printf("\t...\n");
printf("\t.g1_ffe_res_sel = 0x%x,\n", g1_ffe_res_sel);
printf("\t.g1_ffe_cap_sel = 0x%x,\n", g1_ffe_cap_sel);
printf("\t.align90 = 0x%x,\n", align90);
printf("\t.g1_dfe_res = 0x%x\n", g1_dfe_res);
printf("\t...\n");
printf("};\n\n");
printf("########################################################\n");
/* check */
debug("PRBS error counter[0x%lx] 0x%x\n\n",
hpipe_addr + HPIPE_PHY_TEST_PRBS_ERROR_COUNTER_1_REG,
mmio_read_32(hpipe_addr +
HPIPE_PHY_TEST_PRBS_ERROR_COUNTER_1_REG));
rx_trainng_done[ap_nr][cp_nr][comphy_index] = 1;
return ret;
return 0;
}
/* During AP the proper mode is auto-negotiated and the mac, pcs and serdes
......@@ -2237,6 +2345,7 @@ int mvebu_cp110_comphy_power_on(uint64_t comphy_base, uint8_t comphy_index,
err = mvebu_cp110_comphy_rxaui_power_on(comphy_base,
comphy_index,
comphy_mode);
break;
case (COMPHY_USB3H_MODE):
case (COMPHY_USB3D_MODE):
err = mvebu_cp110_comphy_usb3_power_on(comphy_base,
......@@ -2261,9 +2370,18 @@ int mvebu_cp110_comphy_power_off(uint64_t comphy_base, uint8_t comphy_index)
{
uintptr_t sd_ip_addr, comphy_ip_addr;
uint32_t mask, data;
uint8_t ap_nr, cp_nr;
debug_enter();
mvebu_cp110_get_ap_and_cp_nr(&ap_nr, &cp_nr, comphy_base);
if (rx_trainng_done[ap_nr][cp_nr][comphy_index]) {
debug("Skip %s for comphy[%d][%d][%d], due to rx training\n",
__func__, ap_nr, cp_nr, comphy_index);
return 0;
}
sd_ip_addr = SD_ADDR(COMPHY_PIPE_FROM_COMPHY_ADDR(comphy_base),
comphy_index);
comphy_ip_addr = COMPHY_ADDR(comphy_base, comphy_index);
......
......@@ -5,7 +5,79 @@
* https://spdx.org/licenses
*/
/* Marvell CP110 SoC COMPHY unit driver */
/* Those are parameters for xfi mode, which need to be tune for each board type.
* For known DB boards the parameters was already calibrated and placed under
* the plat/marvell/a8k/<board_type>/board/phy-porting-layer.h
*/
struct xfi_params {
uint8_t g1_ffe_res_sel;
uint8_t g1_ffe_cap_sel;
uint8_t align90;
uint8_t g1_dfe_res;
uint8_t g1_amp;
uint8_t g1_emph;
uint8_t g1_emph_en;
uint8_t g1_tx_amp_adj;
uint8_t g1_tx_emph_en;
uint8_t g1_tx_emph;
uint8_t g1_rx_selmuff;
uint8_t g1_rx_selmufi;
uint8_t g1_rx_selmupf;
uint8_t g1_rx_selmupi;
_Bool valid;
};
struct sata_params {
uint8_t g1_amp;
uint8_t g2_amp;
uint8_t g3_amp;
uint8_t g1_emph;
uint8_t g2_emph;
uint8_t g3_emph;
uint8_t g1_emph_en;
uint8_t g2_emph_en;
uint8_t g3_emph_en;
uint8_t g1_tx_amp_adj;
uint8_t g2_tx_amp_adj;
uint8_t g3_tx_amp_adj;
uint8_t g1_tx_emph_en;
uint8_t g2_tx_emph_en;
uint8_t g3_tx_emph_en;
uint8_t g1_tx_emph;
uint8_t g2_tx_emph;
uint8_t g3_tx_emph;
uint8_t g3_dfe_res;
uint8_t g3_ffe_res_sel;
uint8_t g3_ffe_cap_sel;
uint8_t align90;
uint8_t g1_rx_selmuff;
uint8_t g2_rx_selmuff;
uint8_t g3_rx_selmuff;
uint8_t g1_rx_selmufi;
uint8_t g2_rx_selmufi;
uint8_t g3_rx_selmufi;
uint8_t g1_rx_selmupf;
uint8_t g2_rx_selmupf;
uint8_t g3_rx_selmupf;
uint8_t g1_rx_selmupi;
uint8_t g2_rx_selmupi;
uint8_t g3_rx_selmupi;
_Bool valid;
};
int mvebu_cp110_comphy_is_pll_locked(uint64_t comphy_base,
uint8_t comphy_index);
......
/*
* Copyright (C) 2018 Marvell International Ltd.
*
* SPDX-License-Identifier: BSD-3-Clause
* https://spdx.org/licenses
*/
#ifndef __PHY_DEFAULT_PORTING_LAYER_H
#define __PHY_DEFAULT_PORTING_LAYER_H
#define MAX_LANE_NR 6
#warning "Using default comphy params - you may need to suit them to your board"
static const struct xfi_params
xfi_static_values_tab[AP_NUM][CP_NUM][MAX_LANE_NR] = {
[0 ... AP_NUM-1][0 ... CP_NUM-1][0 ... MAX_LANE_NR-1] = {
.g1_ffe_res_sel = 0x3, .g1_ffe_cap_sel = 0xf, .align90 = 0x5f,
.g1_dfe_res = 0x2, .g1_amp = 0x1c, .g1_emph = 0xe,
.g1_emph_en = 0x1, .g1_tx_amp_adj = 0x1, .g1_tx_emph_en = 0x1,
.g1_tx_emph = 0x0, .g1_rx_selmuff = 0x1, .g1_rx_selmufi = 0x0,
.g1_rx_selmupf = 0x2, .g1_rx_selmupi = 0x2, .valid = 1
}
};
static const struct sata_params
sata_static_values_tab[AP_NUM][CP_NUM][MAX_LANE_NR] = {
[0 ... AP_NUM-1][0 ... CP_NUM-1][0 ... MAX_LANE_NR-1] = {
.g1_amp = 0x8, .g2_amp = 0xa, .g3_amp = 0x1e,
.g1_emph = 0x1, .g2_emph = 0x2, .g3_emph = 0xe,
.g1_emph_en = 0x1, .g2_emph_en = 0x1, .g3_emph_en = 0x1,
.g1_tx_amp_adj = 0x1, .g2_tx_amp_adj = 0x1,
.g3_tx_amp_adj = 0x1,
.g1_tx_emph_en = 0x0, .g2_tx_emph_en = 0x0,
.g3_tx_emph_en = 0x0,
.g1_tx_emph = 0x1, .g2_tx_emph = 0x1, .g3_tx_emph = 0x1,
.g3_dfe_res = 0x1, .g3_ffe_res_sel = 0x4, .g3_ffe_cap_sel = 0xf,
.align90 = 0x61,
.g1_rx_selmuff = 0x3, .g2_rx_selmuff = 0x3,
.g3_rx_selmuff = 0x3,
.g1_rx_selmufi = 0x0, .g2_rx_selmufi = 0x0,
.g3_rx_selmufi = 0x3,
.g1_rx_selmupf = 0x1, .g2_rx_selmupf = 0x1,
.g3_rx_selmupf = 0x2,
.g1_rx_selmupi = 0x0, .g2_rx_selmupi = 0x0,
.g3_rx_selmupi = 0x2,
.valid = 0x1
},
};
#endif /* __PHY_DEFAULT_PORTING_LAYER_H */
/*
* Copyright (C) 2016 Marvell International Ltd.
*
* SPDX-License-Identifier: BSD-3-Clause
* https://spdx.org/licenses
*/
#include <asm_macros.S>
#include <a3700_console.h>
.globl console_core_init
.globl console_core_putc
.globl console_core_getc
.globl console_core_flush
/* -----------------------------------------------
* int console_core_init(unsigned long base_addr,
* unsigned int uart_clk, unsigned int baud_rate)
* Function to initialize the console without a
* C Runtime to print debug information. This
* function will be accessed by console_init and
* crash reporting.
* In: x0 - console base address
* w1 - Uart clock in Hz
* w2 - Baud rate
* Out: return 1 on success
* Clobber list : x1, x2, x3
* -----------------------------------------------
*/
func console_core_init
/* Check the input base address */
cbz x0, init_fail
/* Check baud rate and uart clock for sanity */
cbz w1, init_fail
cbz w2, init_fail
/* Program the baudrate */
/* Divisor = Uart clock / (16 * baudrate) */
lsl w2, w2, #4
udiv w2, w1, w2
and w2, w2, #0x3ff
ldr w3, [x0, #UART_BAUD_REG]
bic w3, w3, 0x3ff
orr w3, w3, w2
str w3, [x0, #UART_BAUD_REG]/* set baud rate divisor */
/* Set UART to default 16X scheme */
mov w3, #0
str w3, [x0, #UART_POSSR_REG]
/*
* Wait for the TX FIFO to be empty. If wait for 20ms, the TX FIFO is
* still not empty, TX FIFO will reset by all means.
*/
mov w1, #20 /* max time out 20ms */
2:
/* Check whether TX FIFO is empty */
ldr w3, [x0, #UART_STATUS_REG]
and w3, w3, #UARTLSR_TXFIFOEMPTY
cmp w3, #0
b.ne 4f
/* Delay */
mov w2, #30000
3:
sub w2, w2, #1
cmp w2, #0
b.ne 3b
/* Check whether 10ms is waited */
sub w1, w1, #1
cmp w1, #0
b.ne 2b
4:
/* Reset FIFO */
mov w3, #UART_CTRL_RXFIFO_RESET
orr w3, w3, #UART_CTRL_TXFIFO_RESET
str w3, [x0, #UART_CTRL_REG]
/* Delay */
mov w2, #2000
1:
sub w2, w2, #1
cmp w2, #0
b.ne 1b
/* No Parity, 1 Stop */
mov w3, #0
str w3, [x0, #UART_CTRL_REG]
mov w0, #1
ret
init_fail:
mov w0, #0
ret
endfunc console_core_init
/* --------------------------------------------------------
* int console_core_putc(int c, unsigned int base_addr)
* Function to output a character over the console. It
* returns the character printed on success or -1 on error.
* In : w0 - character to be printed
* x1 - console base address
* Out : return -1 on error else return character.
* Clobber list : x2
* --------------------------------------------------------
*/
func console_core_putc
/* Check the input parameter */
cbz x1, putc_error
/* Prepend '\r' to '\n' */
cmp w0, #0xA
b.ne 2f
/* Check if the transmit FIFO is full */
1: ldr w2, [x1, #UART_STATUS_REG]
and w2, w2, #UARTLSR_TXFIFOFULL
cmp w2, #UARTLSR_TXFIFOFULL
b.eq 1b
mov w2, #0xD /* '\r' */
str w2, [x1, #UART_TX_REG]
/* Check if the transmit FIFO is full */
2: ldr w2, [x1, #UART_STATUS_REG]
and w2, w2, #UARTLSR_TXFIFOFULL
cmp w2, #UARTLSR_TXFIFOFULL
b.eq 2b
str w0, [x1, #UART_TX_REG]
ret
putc_error:
mov w0, #-1
ret
endfunc console_core_putc
/* ---------------------------------------------
* int console_core_getc(void)
* Function to get a character from the console.
* It returns the character grabbed on success
* or -1 on error.
* In : w0 - console base address
* Out : return -1 on error else return character.
* Clobber list : x0, x1
* ---------------------------------------------
*/
func console_core_getc
/* Check if the receive FIFO is empty */
ret
getc_error:
mov w0, #-1
ret
endfunc console_core_getc
/* ---------------------------------------------
* int console_core_flush(uintptr_t base_addr)
* Function to force a write of all buffered
* data that hasn't been output.
* In : x0 - console base address
* Out : return -1 on error else return 0.
* Clobber list : x0, x1
* ---------------------------------------------
*/
func console_core_flush
/* Placeholder */
mov w0, #0
ret
endfunc console_core_flush
/*
* Copyright (C) 2016 Marvell International Ltd.
*
* SPDX-License-Identifier: BSD-3-Clause
* https://spdx.org/licenses
*/
#ifndef __A3700_CONSOLE_H__
#define __A3700_CONSOLE_H__
/* MVEBU UART Registers */
#define UART_RX_REG 0x00
#define UART_TX_REG 0x04
#define UART_CTRL_REG 0x08
#define UART_STATUS_REG 0x0c
#define UART_BAUD_REG 0x10
#define UART_POSSR_REG 0x14
/* FIFO Control Register bits */
#define UARTFCR_FIFOMD_16450 (0 << 6)
#define UARTFCR_FIFOMD_16550 (1 << 6)
#define UARTFCR_RXTRIG_1 (0 << 6)
#define UARTFCR_RXTRIG_4 (1 << 6)
#define UARTFCR_RXTRIG_8 (2 << 6)
#define UARTFCR_RXTRIG_16 (3 << 6)
#define UARTFCR_TXTRIG_1 (0 << 4)
#define UARTFCR_TXTRIG_4 (1 << 4)
#define UARTFCR_TXTRIG_8 (2 << 4)
#define UARTFCR_TXTRIG_16 (3 << 4)
#define UARTFCR_DMAEN (1 << 3) /* Enable DMA mode */
#define UARTFCR_TXCLR (1 << 2) /* Clear contents of Tx FIFO */
#define UARTFCR_RXCLR (1 << 1) /* Clear contents of Rx FIFO */
#define UARTFCR_FIFOEN (1 << 0) /* Enable the Tx/Rx FIFO */
/* Line Control Register bits */
#define UARTLCR_DLAB (1 << 7) /* Divisor Latch Access */
#define UARTLCR_SETB (1 << 6) /* Set BREAK Condition */
#define UARTLCR_SETP (1 << 5) /* Set Parity to LCR[4] */
#define UARTLCR_EVEN (1 << 4) /* Even Parity Format */
#define UARTLCR_PAR (1 << 3) /* Parity */
#define UARTLCR_STOP (1 << 2) /* Stop Bit */
#define UARTLCR_WORDSZ_5 0 /* Word Length of 5 */
#define UARTLCR_WORDSZ_6 1 /* Word Length of 6 */
#define UARTLCR_WORDSZ_7 2 /* Word Length of 7 */
#define UARTLCR_WORDSZ_8 3 /* Word Length of 8 */
/* Line Status Register bits */
#define UARTLSR_TXFIFOFULL (1 << 11) /* Tx Fifo Full */
/* UART Control Register bits */
#define UART_CTRL_RXFIFO_RESET (1 << 14)
#define UART_CTRL_TXFIFO_RESET (1 << 15)
#define UARTLSR_TXFIFOEMPTY (1 << 6)
#endif /* __A3700_CONSOLE_H__ */
......@@ -29,6 +29,13 @@ static inline uint16_t mmio_read_16(uintptr_t addr)
return *(volatile uint16_t*)addr;
}
static inline void mmio_clrsetbits_16(uintptr_t addr,
uint16_t clear,
uint16_t set)
{
mmio_write_16(addr, (mmio_read_16(addr) & ~clear) | set);
}
static inline void mmio_write_32(uintptr_t addr, uint32_t value)
{
*(volatile uint32_t*)addr = value;
......
/*
* Copyright (C) 2018 Marvell International Ltd.
*
* SPDX-License-Identifier: BSD-3-Clause
* https://spdx.org/licenses
*/
#ifndef __ARMADA_COMMON_H__
#define __ARMADA_COMMON_H__
#include <io_addr_dec.h>
#include <stdint.h>
int marvell_get_io_dec_win_conf(struct dec_win_config **win, uint32_t *size);
#endif /* __ARMADA_COMMON_H__ */
/*
* Copyright (C) 2018 Marvell International Ltd.
*
* SPDX-License-Identifier: BSD-3-Clause
* https://spdx.org/licenses
*/
#ifndef __BOARD_MARVELL_DEF_H__
#define __BOARD_MARVELL_DEF_H__
/*
* Required platform porting definitions common to all ARM
* development platforms
*/
/* Size of cacheable stacks */
#if IMAGE_BL1
#if TRUSTED_BOARD_BOOT
# define PLATFORM_STACK_SIZE 0x1000
#else
# define PLATFORM_STACK_SIZE 0x440
#endif
#elif IMAGE_BL2
# if TRUSTED_BOARD_BOOT
# define PLATFORM_STACK_SIZE 0x1000
# else
# define PLATFORM_STACK_SIZE 0x400
# endif
#elif IMAGE_BL31
# define PLATFORM_STACK_SIZE 0x400
#elif IMAGE_BL32
# define PLATFORM_STACK_SIZE 0x440
#endif
/*
* PLAT_MARVELL_MMAP_ENTRIES depends on the number of entries in the
* plat_arm_mmap array defined for each BL stage.
*/
#if IMAGE_BLE
# define PLAT_MARVELL_MMAP_ENTRIES 3
#endif
#if IMAGE_BL1
# if TRUSTED_BOARD_BOOT
# define PLAT_MARVELL_MMAP_ENTRIES 7
# else
# define PLAT_MARVELL_MMAP_ENTRIES 6
# endif /* TRUSTED_BOARD_BOOT */
#endif
#if IMAGE_BL2
# define PLAT_MARVELL_MMAP_ENTRIES 8
#endif
#if IMAGE_BL31
#define PLAT_MARVELL_MMAP_ENTRIES 5
#endif
/*
* Platform specific page table and MMU setup constants
*/
#if IMAGE_BL1
#define MAX_XLAT_TABLES 4
#elif IMAGE_BLE
# define MAX_XLAT_TABLES 4
#elif IMAGE_BL2
# define MAX_XLAT_TABLES 4
#elif IMAGE_BL31
# define MAX_XLAT_TABLES 4
#elif IMAGE_BL32
# define MAX_XLAT_TABLES 4
#endif
#define MAX_IO_DEVICES 3
#define MAX_IO_HANDLES 4
#define PLAT_MARVELL_TRUSTED_SRAM_SIZE 0x80000 /* 512 KB */
#endif /* __BOARD_MARVELL_DEF_H__ */
/*
* Copyright (C) 2018 Marvell International Ltd.
*
* SPDX-License-Identifier: BSD-3-Clause
* https://spdx.org/licenses
*/
#ifndef __MARVELL_DEF_H__
#define __MARVELL_DEF_H__
#include <arch.h>
#include <common_def.h>
#include <platform_def.h>
#include <tbbr_img_def.h>
#include <xlat_tables.h>
/****************************************************************************
* Definitions common to all MARVELL standard platforms
****************************************************************************
*/
/* Special value used to verify platform parameters from BL2 to BL31 */
#define MARVELL_BL31_PLAT_PARAM_VAL 0x0f1e2d3c4b5a6978ULL
#define PLAT_MARVELL_NORTHB_COUNT 1
#define PLAT_MARVELL_CLUSTER_COUNT 1
#define MARVELL_CACHE_WRITEBACK_SHIFT 6
/*
* Macros mapping the MPIDR Affinity levels to MARVELL Platform Power levels.
* The power levels have a 1:1 mapping with the MPIDR affinity levels.
*/
#define MARVELL_PWR_LVL0 MPIDR_AFFLVL0
#define MARVELL_PWR_LVL1 MPIDR_AFFLVL1
#define MARVELL_PWR_LVL2 MPIDR_AFFLVL2
/*
* Macros for local power states in Marvell platforms encoded by State-ID field
* within the power-state parameter.
*/
/* Local power state for power domains in Run state. */
#define MARVELL_LOCAL_STATE_RUN 0
/* Local power state for retention. Valid only for CPU power domains */
#define MARVELL_LOCAL_STATE_RET 1
/* Local power state for OFF/power-down.
* Valid for CPU and cluster power domains
*/
#define MARVELL_LOCAL_STATE_OFF 2
/* The first 4KB of Trusted SRAM are used as shared memory */
#define MARVELL_TRUSTED_SRAM_BASE PLAT_MARVELL_ATF_BASE
#define MARVELL_SHARED_RAM_BASE MARVELL_TRUSTED_SRAM_BASE
#define MARVELL_SHARED_RAM_SIZE 0x00001000 /* 4 KB */
/* The remaining Trusted SRAM is used to load the BL images */
#define MARVELL_BL_RAM_BASE (MARVELL_SHARED_RAM_BASE + \
MARVELL_SHARED_RAM_SIZE)
#define MARVELL_BL_RAM_SIZE (PLAT_MARVELL_TRUSTED_SRAM_SIZE - \
MARVELL_SHARED_RAM_SIZE)
#define MARVELL_DRAM_BASE ULL(0x0)
#define MARVELL_DRAM_SIZE ULL(0x20000000)
#define MARVELL_DRAM_END (MARVELL_DRAM_BASE + \
MARVELL_DRAM_SIZE - 1)
#define MARVELL_IRQ_SEC_PHY_TIMER 29
#define MARVELL_IRQ_SEC_SGI_0 8
#define MARVELL_IRQ_SEC_SGI_1 9
#define MARVELL_IRQ_SEC_SGI_2 10
#define MARVELL_IRQ_SEC_SGI_3 11
#define MARVELL_IRQ_SEC_SGI_4 12
#define MARVELL_IRQ_SEC_SGI_5 13
#define MARVELL_IRQ_SEC_SGI_6 14
#define MARVELL_IRQ_SEC_SGI_7 15
#define MARVELL_MAP_SHARED_RAM MAP_REGION_FLAT( \
MARVELL_SHARED_RAM_BASE, \
MARVELL_SHARED_RAM_SIZE, \
MT_MEMORY | MT_RW | MT_SECURE)
#define MARVELL_MAP_DRAM MAP_REGION_FLAT( \
MARVELL_DRAM_BASE, \
MARVELL_DRAM_SIZE, \
MT_MEMORY | MT_RW | MT_NS)
/*
* The number of regions like RO(code), coherent and data required by
* different BL stages which need to be mapped in the MMU.
*/
#if USE_COHERENT_MEM
#define MARVELL_BL_REGIONS 3
#else
#define MARVELL_BL_REGIONS 2
#endif
#define MAX_MMAP_REGIONS (PLAT_MARVELL_MMAP_ENTRIES + \
MARVELL_BL_REGIONS)
#define MARVELL_CONSOLE_BAUDRATE 115200
/****************************************************************************
* Required platform porting definitions common to all MARVELL std. platforms
****************************************************************************
*/
#define PLAT_PHY_ADDR_SPACE_SIZE (1ULL << 32)
#define PLAT_VIRT_ADDR_SPACE_SIZE (1ULL << 32)
/*
* This macro defines the deepest retention state possible. A higher state
* id will represent an invalid or a power down state.
*/
#define PLAT_MAX_RET_STATE MARVELL_LOCAL_STATE_RET
/*
* This macro defines the deepest power down states possible. Any state ID
* higher than this is invalid.
*/
#define PLAT_MAX_OFF_STATE MARVELL_LOCAL_STATE_OFF
#define PLATFORM_CORE_COUNT PLAT_MARVELL_CLUSTER_CORE_COUNT
/*
* Some data must be aligned on the biggest cache line size in the platform.
* This is known only to the platform as it might have a combination of
* integrated and external caches.
*/
#define CACHE_WRITEBACK_GRANULE (1 << MARVELL_CACHE_WRITEBACK_SHIFT)
/*****************************************************************************
* BL1 specific defines.
* BL1 RW data is relocated from ROM to RAM at runtime so we need 2 sets of
* addresses.
*****************************************************************************
*/
#define BL1_RO_BASE PLAT_MARVELL_TRUSTED_ROM_BASE
#define BL1_RO_LIMIT (PLAT_MARVELL_TRUSTED_ROM_BASE \
+ PLAT_MARVELL_TRUSTED_ROM_SIZE)
/*
* Put BL1 RW at the top of the Trusted SRAM.
*/
#define BL1_RW_BASE (MARVELL_BL_RAM_BASE + \
MARVELL_BL_RAM_SIZE - \
PLAT_MARVELL_MAX_BL1_RW_SIZE)
#define BL1_RW_LIMIT (MARVELL_BL_RAM_BASE + MARVELL_BL_RAM_SIZE)
/*****************************************************************************
* BL2 specific defines.
*****************************************************************************
*/
/*
* Put BL2 just below BL31.
*/
#define BL2_BASE (BL31_BASE - PLAT_MARVELL_MAX_BL2_SIZE)
#define BL2_LIMIT BL31_BASE
/*****************************************************************************
* BL31 specific defines.
*****************************************************************************
*/
/*
* Put BL31 at the top of the Trusted SRAM.
*/
#define BL31_BASE (MARVELL_BL_RAM_BASE + \
MARVELL_BL_RAM_SIZE - \
PLAT_MARVEL_MAX_BL31_SIZE)
#define BL31_PROGBITS_LIMIT BL1_RW_BASE
#define BL31_LIMIT (MARVELL_BL_RAM_BASE + \
MARVELL_BL_RAM_SIZE)
#endif /* __MARVELL_DEF_H__ */
/*
* Copyright (C) 2016 Marvell International Ltd.
*
* SPDX-License-Identifier: BSD-3-Clause
* https://spdx.org/licenses
*/
#ifndef __PLAT_MARVELL_H__
#define __PLAT_MARVELL_H__
#include <bl_common.h>
#include <cassert.h>
#include <cpu_data.h>
#include <stdint.h>
#include <xlat_tables.h>
/*
* Extern declarations common to Marvell standard platforms
*/
extern const mmap_region_t plat_marvell_mmap[];
#define MARVELL_CASSERT_MMAP \
CASSERT((ARRAY_SIZE(plat_marvell_mmap) + MARVELL_BL_REGIONS) \
<= MAX_MMAP_REGIONS, \
assert_max_mmap_regions)
/*
* Utility functions common to Marvell standard platforms
*/
void marvell_setup_page_tables(uintptr_t total_base,
size_t total_size,
uintptr_t code_start,
uintptr_t code_limit,
uintptr_t rodata_start,
uintptr_t rodata_limit
#if USE_COHERENT_MEM
, uintptr_t coh_start,
uintptr_t coh_limit
#endif
);
/* IO storage utility functions */
void marvell_io_setup(void);
/* Systimer utility function */
void marvell_configure_sys_timer(void);
/* Topology utility function */
int marvell_check_mpidr(u_register_t mpidr);
/* BL1 utility functions */
void marvell_bl1_early_platform_setup(void);
void marvell_bl1_platform_setup(void);
void marvell_bl1_plat_arch_setup(void);
/* BL2 utility functions */
void marvell_bl2_early_platform_setup(meminfo_t *mem_layout);
void marvell_bl2_platform_setup(void);
void marvell_bl2_plat_arch_setup(void);
uint32_t marvell_get_spsr_for_bl32_entry(void);
uint32_t marvell_get_spsr_for_bl33_entry(void);
/* BL31 utility functions */
void marvell_bl31_early_platform_setup(void *from_bl2,
uintptr_t soc_fw_config,
uintptr_t hw_config,
void *plat_params_from_bl2);
void marvell_bl31_platform_setup(void);
void marvell_bl31_plat_runtime_setup(void);
void marvell_bl31_plat_arch_setup(void);
/* FIP TOC validity check */
int marvell_io_is_toc_valid(void);
/*
* PSCI functionality
*/
void marvell_psci_arch_init(int idx);
void plat_marvell_system_reset(void);
/*
* Optional functions required in Marvell standard platforms
*/
void plat_marvell_io_setup(void);
int plat_marvell_get_alt_image_source(
unsigned int image_id,
uintptr_t *dev_handle,
uintptr_t *image_spec);
unsigned int plat_marvell_calc_core_pos(u_register_t mpidr);
void plat_marvell_interconnect_init(void);
void plat_marvell_interconnect_enter_coherency(void);
const mmap_region_t *plat_marvell_get_mmap(void);
#endif /* __PLAT_MARVELL_H__ */
......@@ -5,8 +5,8 @@
* https://spdx.org/licenses
*/
#ifndef __A8K_COMMON_H__
#define __A8K_COMMON_H__
#ifndef __ARMADA_COMMON_H__
#define __ARMADA_COMMON_H__
#include <amb_adec.h>
#include <io_win.h>
......
......@@ -45,7 +45,7 @@ spacer:
* Clobbers: x0 - x10, sp
* ---------------------------------------------
*/
.macro arm_print_gic_regs
.macro marvell_print_gic_regs
/* Check for GICv3 system register access */
mrs x7, id_aa64pfr0_el1
ubfx x7, x7, #ID_AA64PFR0_GIC_SHIFT, #ID_AA64PFR0_GIC_WIDTH
......
......@@ -32,7 +32,8 @@
#define ROUND_UP_TO_POW_OF_2(number) (1 << \
(32 - __builtin_clz((number) - 1)))
#define _1MB_ (1024ULL*1024ULL)
#define _1GB_ (_1MB_*1024ULL)
#define _1MB_ (1024ULL * 1024ULL)
#define _1GB_ (_1MB_ * 1024ULL)
#define _2GB_ (2 * _1GB_)
#endif /* MVEBU_H */
......@@ -89,7 +89,7 @@ Marvell platform ports and SoC drivers
:F: docs/plat/marvell/
:F: plat/marvell/
:F: drivers/marvell/
:F: tools/doimage/
:F: tools/marvell/
NVidia platform ports
---------------------
......
/*
* Copyright (C) 2018 Marvell International Ltd.
*
* SPDX-License-Identifier: BSD-3-Clause
* https://spdx.org/licenses
*/
#include <a3700_pm.h>
#include <plat_marvell.h>
/* This struct provides the PM wake up src configuration */
static struct pm_wake_up_src_config wake_up_src_cfg = {
.wake_up_src_num = 3,
.wake_up_src[0] = {
.wake_up_src_type = WAKE_UP_SRC_GPIO,
.wake_up_data = {
.gpio_data.bank_num = 0, /* North Bridge */
.gpio_data.gpio_num = 14
}
},
.wake_up_src[1] = {
.wake_up_src_type = WAKE_UP_SRC_GPIO,
.wake_up_data = {
.gpio_data.bank_num = 1, /* South Bridge */
.gpio_data.gpio_num = 2
}
},
.wake_up_src[2] = {
.wake_up_src_type = WAKE_UP_SRC_UART1,
}
};
struct pm_wake_up_src_config *mv_wake_up_src_config_get(void)
{
return &wake_up_src_cfg;
}
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment