blob: e3e38ec00f3730f64b5c802d931b6a19d7bfef4f [file] [log] [blame]
/*
* (C) Copyright 2000-2006
* Wolfgang Denk, DENX Software Engineering, wd@denx.de.
*
* See file CREDITS for list of people who contributed to this
* project.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston,
* MA 02111-1307 USA
*/
#include <common.h>
#include <command.h>
#include <linux/types.h>
#ifdef CONFIG_PCIE_PHY
/* PCIe PHY registers */
#define PCIE_PHY_PARALLEL_CR_CTRL_PORT_ADDR 0x00 /* CR_ADDR */
#define PCIE_PHY_PARALLEL_CR_CTRL_PORT_DATA 0x04 /* CR_DATA */
#define PCIE_PHY_POWER_GOOD_STATUS 0x08 /* PG_STS */
#define PCIE_PHY_MPLL_CTRL 0x0C /* MPLL_CTL */
#define PCIE_PHY_TEST_CTRL 0x10 /* TEST_CTL */
#define PCIE_PHY_TRANSMIT_LEVEL_CTRL 0x14 /* TX_LVL_CTL */
#define PCIE_PHY_LANE0_TX_CTRL 0x18 /* TX0_CTL */
#define PCIE_PHY_LANE1_TX_CTRL 0x1C /* TX1_CTL */
#define PCIE_PHY_LOS_LEVEL_CTRL 0x20 /* LOS_LVL_CTL */
#define PCIE_PHY_LANE0_RX_CTRL 0x24 /* RX0_CTL */
#define PCIE_PHY_LANE1_RX_CTRL 0x28 /* RX1_CTL */
#define PCIE_PHY_TECHNOLOGY_CTRL 0x2C /* TECH_CTL */
#define PCIE_PHY_RESISTOR_TUNE_CTRL 0x30 /* RTUNE_CTL */
#define PCIE_PHY_PCS_STATUS 0x34 /* PCS_STS */
#define PCIE_PHY_PCS_CTRL 0x38 /* PCS_CTL */
#define COMCERTO_CLK_DDR_PCIE_CLK_CNTRL 0x100B0018
#define COMCERTO_CLK_CLK_PWR_DWN 0x100B0040
#define COMCERTO_BLOCK_RESET_REG 0x100B0100 /* APB_VADDR((COMCERTO_APB_CLK_BASE + 0x100)) */
#define USB_DIV_BYPASS (1 << 30)
#define IPSEC1_DIV_BYPASS (1 << 29)
#define IPSEC0_DIV_BYPASS (1 << 28)
#define PCIE_DIV_BYPASS (1 << 27)
#define DDR_DIV_BYPASS (1 << 26)
#define USB_DIV_VAL_OFFSET 20
#define USB_DIV_VAL_MASK (0x3f << USB_DIV_VAL_OFFSET)
#define IPSEC_DIV1_VAL_OFFSET 16
#define IPSEC_DIV1_VAL_MASK (0xf << IPSEC_DIV0_VAL_OFFSET)
#define IPSEC_DIV0_VAL_OFFSET 12
#define IPSEC_DIV0_VAL_MASK (0xf << IPSEC_DIV1_VAL_OFFSET)
#define PCIE_DIV_VAL_OFFSET 8
#define PCIE_DIV_VAL_MASK (0xf << PCIE_DIV_VAL_OFFSET)
#define DDR_DIV_VAL_OFFSET 4
#define DDR_DIV_VAL_MASK (0xf << DDR_DIV_VAL_OFFSET)
#define USB_REF_RESET_N (1 << 20)
#define NO_BAL_DDR_REF_RST (1 << 19)
#define IPSEC2_AHB_RST (1 << 18)
#define RNG_RST (1 << 17)
#define IPSEC_CORE_RST (1 << 16)
#define IPSEC_AHB_RST (1 << 15)
#define USB_AHB_RESET_N (1 << 14)
#define TDM_REF_RST (1 << 13)
#define TDM_AHB_RST (1 << 12)
#define DDR_REF_RST (1 << 11)
#define DDR_AHB_RST (1 << 10)
#define PCIE1_REF_RST (1 << 9)
#define PCIE0_REF_RST (1 << 8)
#define PCIE1_AHB_RST (1 << 7)
#define PCIE0_AHB_RST (1 << 6)
#define GEMAC1_PHY_RST (1 << 5)
#define GEMAC0_PHY_RST (1 << 4)
#define GEMAC1_AHB_RST (1 << 3)
#define GEMAC0_AHB_RST (1 << 2)
#define ARM1_AHB_RST (1 << 1)
#define ARM0_AHB_RST (1 << 0)
#define USB_MUX_SEL (1 << 3)
#define IPSEC_MUX_SEL (1 << 2)
#define PCIE_MUX_SEL (1 << 1)
#define DDR_MUX_SEL (1 << 0)
#define USB_REFCLK_PD (1 << 24)
#define USB_AHBCLK_PD (1 << 19)
#define PCIE1_AHBCLK_PD (1 << 15)
#define PCIE0_AHBCLK_PD (1 << 14)
#define PCIE_REFCLK_NP_PD (1 << 6)
#define writel(val, addr) *(volatile u32 *)(addr) = (val)
#define readl(addr) *(volatile u32 *)(addr)
void *pcie_phy_baseaddr = (void *)0x10060000;
static u16 pcie_phy_reg_read(u16 addr)
{
writel(addr, pcie_phy_baseaddr + PCIE_PHY_PARALLEL_CR_CTRL_PORT_ADDR);
return (u16)(readl(pcie_phy_baseaddr + PCIE_PHY_PARALLEL_CR_CTRL_PORT_DATA) & 0xffff);
}
static void pcie_phy_reg_write(u16 val, u16 addr)
{
writel(addr, pcie_phy_baseaddr + PCIE_PHY_PARALLEL_CR_CTRL_PORT_ADDR);
writel(val, pcie_phy_baseaddr + PCIE_PHY_PARALLEL_CR_CTRL_PORT_DATA);
}
int do_txlvl (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
{
u32 tx_level;
if (argc < 2)
return -1;
tx_level = simple_strtoul(argv[1], NULL, 16) & 0x1f;
writel(tx_level, pcie_phy_baseaddr + PCIE_PHY_TRANSMIT_LEVEL_CTRL);
printf("%x=%x", pcie_phy_baseaddr + PCIE_PHY_TRANSMIT_LEVEL_CTRL, readl(pcie_phy_baseaddr + PCIE_PHY_TRANSMIT_LEVEL_CTRL));
}
U_BOOT_CMD(
txlvl, 2, 0, do_txlvl,
"txlvl - sets tx level\n",
);
#if 0
int do_loopback (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
{
u32 tx_level;
if (argc < 2)
return -1;
}
U_BOOT_CMD(
txlvl, 2, 0, do_txlvl,
"txlvl - start phy BERT test\n",
);
#endif
int do_phytest (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
{
int i;
u16 type, pat0, val;
if (argc < 3)
return -1;
type = simple_strtoul(argv[1], NULL, 16) & 0xffff;
pat0 = simple_strtoul(argv[2], NULL, 16) & 0xffff;
printf("type(%x), pat0(%x)\n", type, pat0);
/* Enable pattern output */
pcie_phy_reg_write((type & 0x7) | ((pat0 & 0x3ff) << 4), 0x2110);
/* Enable pattern matching and sync */
pcie_phy_reg_write((type & 0x7) | (1 << 3), 0x2118);
/* disable sync */
pcie_phy_reg_write((type & 0x7), 0x2118);
pcie_phy_reg_write((type & 0x7) | (1 << 3), 0x2118);
/* disable sync */
pcie_phy_reg_write((type & 0x7), 0x2118);
for (i = 0; i < 1000; i++) {
udelay(1000);
val = pcie_phy_reg_read(0x2119);
if ((val & 0x8000))
printf("error count %x\n", (val & 0x7fff) * 128);
else
printf("error count %x\n", (val & 0x7fff));
}
return 0;
}
U_BOOT_CMD(
phytest, 3, 0, do_phytest,
"phytest - start phy BERT test\n",
);
int do_initphy (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
{
u32 val;
u32 ncy = 0x4 & 0x1f;
u32 ncy5 = 0x0 & 0x3;
u32 prescale = 0x0 & 0x3;
/* Put block into reset */
writel(readl(COMCERTO_BLOCK_RESET_REG) & ~(PCIE1_REF_RST | PCIE0_REF_RST | PCIE1_AHB_RST | PCIE0_AHB_RST), COMCERTO_BLOCK_RESET_REG);
/* Power up clocks */
writel(readl(COMCERTO_CLK_CLK_PWR_DWN) & ~(PCIE_REFCLK_NP_PD | PCIE0_AHBCLK_PD | PCIE1_AHBCLK_PD), COMCERTO_CLK_CLK_PWR_DWN);
/* Set reference clock to 250/4 = 62.5 MHz */
val = readl(COMCERTO_CLK_DDR_PCIE_CLK_CNTRL);
val &= ~(PCIE_DIV_VAL_MASK | PCIE_DIV_BYPASS);
val |= 4 << PCIE_DIV_VAL_OFFSET;
writel(val, COMCERTO_CLK_DDR_PCIE_CLK_CNTRL);
/* Switch to clock output */
writel(val & ~PCIE_MUX_SEL, COMCERTO_CLK_DDR_PCIE_CLK_CNTRL);
/* Take block out of reset */
writel(readl(COMCERTO_BLOCK_RESET_REG) | (PCIE1_REF_RST | PCIE0_REF_RST | PCIE1_AHB_RST | PCIE0_AHB_RST), COMCERTO_BLOCK_RESET_REG);
udelay(10);
#if 0
/* Synopsys recommended values */
u32 tx_level = 0x6 & 0x1f;
u32 tx_boost = 0xa & 0xf;
u32 tx_atten = 0x0 & 0x7;
u32 tx_edge_rate = 0x0 & 0x3;
u32 tx_clk_align = 0x0 & 0x1;
u32 los_lvl = 0x14 & 0x1f;
u32 rx_equal_val = 0x2 & 0x7;
#elif 1
/* Default values */
u32 tx_level = 0xa & 0x1f;
u32 tx_boost = 0xb & 0xf;
u32 tx_atten = 0x0 & 0x7;
u32 tx_edge_rate = 0x0 & 0x3;
u32 tx_clk_align = 0x0 & 0x1;
u32 los_lvl = 0x11 & 0x1f;
u32 rx_equal_val = 0x2 & 0x7;
#else
/* Custom values */
/* u32 tx_level = 0xa & 0x1f; */
u32 tx_level = 0x13 & 0x1f;
u32 tx_boost = 0xb & 0xf;
u32 tx_atten = 0x0 & 0x7;
u32 tx_edge_rate = 0x0 & 0x3;
u32 tx_clk_align = 0x0 & 0x1;
u32 los_lvl = 0x10 & 0x1f;
u32 rx_equal_val = 0x2 & 0x7;
#endif
/* Baud rate = 62.5MHz * MPLL_divisor / 0.5 = 62.5MHz * 20 / 0.5 = 2.5GHz */
writel((prescale << 1) | (ncy5 << 3) | (ncy << 5), pcie_phy_baseaddr + PCIE_PHY_MPLL_CTRL);
writel(tx_level, pcie_phy_baseaddr + PCIE_PHY_TRANSMIT_LEVEL_CTRL);
#if 0
writel(tx_edge_rate | (tx_boost << 2) | (tx_atten << 6) | (tx_clk_align << 9), pcie_phy_baseaddr + PCIE_PHY_LANE0_TX_CTRL);
writel(tx_edge_rate | (tx_boost << 2) | (tx_atten << 6) | (tx_clk_align << 9), pcie_phy_baseaddr + PCIE_PHY_LANE1_TX_CTRL);
writel(los_lvl, pcie_phy_baseaddr + PCIE_PHY_LOS_LEVEL_CTRL);
writel(rx_equal_val, pcie_phy_baseaddr + PCIE_PHY_LANE0_RX_CTRL);
writel(rx_equal_val, pcie_phy_baseaddr + PCIE_PHY_LANE1_RX_CTRL);
#endif
writel(0x00000000, pcie_phy_baseaddr + PCIE_PHY_PCS_CTRL);
#if 1
/* Manual calibration of rx resistor */
udelay(1000);
writel(0x1, pcie_phy_baseaddr + PCIE_PHY_RESISTOR_TUNE_CTRL);
udelay(100);
writel(0x0, pcie_phy_baseaddr + PCIE_PHY_RESISTOR_TUNE_CTRL);
#endif
#if 0
/* Set both phys in digital loopback */
val = pcie_phy_reg_read(0x2030);
val |= (1 << 4);
pcie_phy_reg_write(val, 0x2030);
printk("lane0.rx_ana.ctrl %x\n", pcie_phy_reg_read(0x2030));
val = pcie_phy_reg_read(0x2130);
val |= (1 << 4);
pcie_phy_reg_write(val, 0x2130);
printk("lane1.rx_ana.ctrl %x\n", pcie_phy_reg_read(0x2130));
#endif
return 0;
}
U_BOOT_CMD(
initphy, 1, 0, do_initphy,
"initphy - initialize PCIe phy\n",
);
int do_dumpreg (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
{
u16 val;
printf("clock.rtune_ctl %x\n", pcie_phy_reg_read(0x9));
val = pcie_phy_reg_read(0xe);
printf("clock.freq_stat(%x) prop_ctl(%x) int_ctl(%x) ncy5(%x) ncy(%x) prescale(%x)\n",
val, (val & 0x7), (val >> 3) & 0x7, (val >> 6) & 0x3, (val >> 8) & 0x1f, (val >> 13) & 0x3);
val = pcie_phy_reg_read(0xf);
printf("clock.ctl_stat(%x) use_refclk_dat(%x) mpll_clk_off(%x) mpll_pwron(%x) mpll_ss_en(%x) cko_alive_con(%x) cko_word_con(%x) rtune_to_tune(%x) wide_xface(%x) vph_is_3p3(%x) vp_is_1p2(%x) fast_tech(%x)\n",
val, val & 0x1, (val >> 1) & 0x1, (val >> 2) & 0x1, (val >> 3) & 0x1, (val >> 4) & 0x3,
(val >> 6) & 0x7, (val >> 10) & 0x1, (val >> 11) & 0x1, (val >> 12) & 0x1, (val >> 13) & 0x1,
(val >> 14) & 0x1);
printf("clock.lvl_stat %x\n", pcie_phy_reg_read(0x10));
printf("clock.ctl_ovrd %x\n", pcie_phy_reg_read(0x13));
printf("clock.lvl_ovrd %x\n", pcie_phy_reg_read(0x14));
printf("clock.creg_ovrd %x\n", pcie_phy_reg_read(0x15));
printf("clock.mpll_ctl %x\n", pcie_phy_reg_read(0x16));
printf("clock.mpll_tst %x\n", pcie_phy_reg_read(0x17));
val = pcie_phy_reg_read(0x2001);
printf("lane0.tx_stat(%x) tx_cko_en(%x) tx_en(%x) tx_clk_align(%x) tx_boost(%x) tx_atten(%x) tx_edgerate(%x)\n",
val, val & 0x1, (val >> 1) & 0x7, (val >> 4) & 0x1,
(val >> 6) & 0xf, (val >> 10) & 0x7, (val >> 13) & 0x3);
val = pcie_phy_reg_read(0x2101);
printf("lane1.tx_stat(%x) tx_cko_en(%x) tx_en(%x) tx_clk_align(%x) tx_boost(%x) tx_atten(%x) tx_edgerate(%x)\n",
val, val & 0x1, (val >> 1) & 0x7, (val >> 4) & 0x1,
(val >> 6) & 0xf, (val >> 10) & 0x7, (val >> 13) & 0x3);
val = pcie_phy_reg_read(0x2002);
printf("lane0.rx_stat(%x) half_rate(%x) rx_pll_pwron(%x) rx_en(%x) rx_align_en(%x) rx_term_en(%x) rx_equal_val(%x) rx_dpll_mode(%x) dpll_reset(%x) los_ctl(%x)\n",
val, val & 0x1, (val >> 1) & 0x1, (val >> 2) & 0x1,
(val >> 3) & 0x1, (val >> 4) & 0x1, (val >> 5) & 0x7, (val >> 8) & 0x7, (val >> 11) & 0x1,
(val >> 12) & 0x3);
val = pcie_phy_reg_read(0x2102);
printf("lane1.rx_stat(%x) half_rate(%x) rx_pll_pwron(%x) rx_en(%x) rx_align_en(%x) rx_term_en(%x) rx_equal_val(%x) rx_dpll_mode(%x) dpll_reset(%x) los_ctl(%x)\n",
val, val & 0x1, (val >> 1) & 0x1, (val >> 2) & 0x1,
(val >> 3) & 0x1, (val >> 4) & 0x1, (val >> 5) & 0x7, (val >> 8) & 0x7, (val >> 11) & 0x1,
(val >> 12) & 0x3);
val = pcie_phy_reg_read(0x2003);
printf("lane0.out_stat(%x) rx_valid(%x) rx_pll_state(%x) los(%x) tx_done(%x) tx_rxpres(%x)\n",
val, val & 0x1, (val >> 1) & 0x1, (val >> 2) & 0x1,
(val >> 3) & 0x1, (val >> 4) & 0x1);
val = pcie_phy_reg_read(0x2103);
printf("lane1.out_stat(%x) rx_valid(%x) rx_pll_state(%x) los(%x) tx_done(%x) tx_rxpres(%x)\n",
val, val & 0x1, (val >> 1) & 0x1, (val >> 2) & 0x1,
(val >> 3) & 0x1, (val >> 4) & 0x1);
return 0;
}
U_BOOT_CMD(
dumpreg, 1, 1, do_dumpreg,
"dumpreg - dumps all PCIe phy registers\n",
);
int do_writereg (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
{
u16 val, addr;
if (argc < 3)
return -1;
val = simple_strtoul(argv[1], NULL, 16) & 0xffff;
addr = simple_strtoul(argv[2], NULL, 16) & 0xffff;
printf("%x=%x\n", addr, val);
pcie_phy_reg_write(val, addr);
return 0;
}
U_BOOT_CMD(
writereg, 3, 0, do_writereg,
"writereg - writes PCIe phy reg\n",
);
int do_readreg (cmd_tbl_t *cmdtp, int flag,
int argc, char *argv[])
{
u16 addr;
if (argc < 2)
return -1;
addr = simple_strtoul(argv[1], NULL, 16) & 0xffff;
printf("%x=%x\n", addr, pcie_phy_reg_read(addr));
return 0;
}
U_BOOT_CMD(
readreg, 2, 1, do_readreg,
"readreg - read PCIe phy reg\n",
);
#endif