| /* |
| * (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 |