From f8a52fe5487f81aabac494c877a23ab9b07c4556 Mon Sep 17 00:00:00 2001 From: Yue Wang Date: Fri, 2 Jun 2017 15:58:45 +0800 Subject: [PATCH] pcie: add pcie phy control register access. PD#142470: pcie: add pcie phy control register access. Change-Id: I832b05763a722c074980f19682c6249915c0363d Signed-off-by: Yue Wang --- drivers/amlogic/pci/pcie-amlogic.c | 185 ++++++++++++++++++++++++++++- drivers/amlogic/pci/pcie-amlogic.h | 106 +++++++++++++++++ 2 files changed, 290 insertions(+), 1 deletion(-) diff --git a/drivers/amlogic/pci/pcie-amlogic.c b/drivers/amlogic/pci/pcie-amlogic.c index 02425b4b58c3..0d5601b7daac 100644 --- a/drivers/amlogic/pci/pcie-amlogic.c +++ b/drivers/amlogic/pci/pcie-amlogic.c @@ -27,6 +27,7 @@ #include #include #include +#include #include "../drivers/pci/host/pcie-designware.h" #include "pcie-amlogic.h" @@ -45,6 +46,7 @@ struct amlogic_pcie { #define to_amlogic_pcie(x) container_of(x, struct amlogic_pcie, pp) struct amlogic_pcie *g_amlogic_pcie; +struct pcie_phy_aml_regs pcie_aml_regs; static void amlogic_elb_writel(struct amlogic_pcie *amlogic_pcie, u32 val, u32 reg) @@ -68,6 +70,177 @@ static u32 amlogic_cfg_readl(struct amlogic_pcie *amlogic_pcie, u32 reg) return readl(amlogic_pcie->cfg_base + reg); } +static void cr_bus_addr(unsigned int addr) +{ + union phy_r4 phy_r4 = {.d32 = 0}; + union phy_r5 phy_r5 = {.d32 = 0}; + + phy_r4.b.phy_cr_data_in = addr; + writel(phy_r4.d32, pcie_aml_regs.pcie_phy_r[4]); + + phy_r4.b.phy_cr_cap_addr = 0; + writel(phy_r4.d32, pcie_aml_regs.pcie_phy_r[4]); + phy_r4.b.phy_cr_cap_addr = 1; + writel(phy_r4.d32, pcie_aml_regs.pcie_phy_r[4]); + + do { + phy_r5.d32 = readl(pcie_aml_regs.pcie_phy_r[5]); + } while (phy_r5.b.phy_cr_ack == 0); + + phy_r4.b.phy_cr_cap_addr = 0; + writel(phy_r4.d32, pcie_aml_regs.pcie_phy_r[4]); + + do { + phy_r5.d32 = readl(pcie_aml_regs.pcie_phy_r[5]); + } while (phy_r5.b.phy_cr_ack == 1); +} + +static int cr_bus_read(unsigned int addr) +{ + int data; + union phy_r4 phy_r4 = {.d32 = 0}; + union phy_r5 phy_r5 = {.d32 = 0}; + + cr_bus_addr(addr); + + phy_r4.b.phy_cr_read = 0; + writel(phy_r4.d32, pcie_aml_regs.pcie_phy_r[4]); + phy_r4.b.phy_cr_read = 1; + writel(phy_r4.d32, pcie_aml_regs.pcie_phy_r[4]); + + do { + phy_r5.d32 = readl(pcie_aml_regs.pcie_phy_r[5]); + } while (phy_r5.b.phy_cr_ack == 0); + + data = phy_r5.b.phy_cr_data_out; + + phy_r4.b.phy_cr_read = 0; + writel(phy_r4.d32, pcie_aml_regs.pcie_phy_r[4]); + + do { + phy_r5.d32 = readl(pcie_aml_regs.pcie_phy_r[5]); + } while (phy_r5.b.phy_cr_ack == 1); + + return data; +} + +static void cr_bus_write(unsigned int addr, unsigned int data) +{ + union phy_r4 phy_r4 = {.d32 = 0}; + union phy_r5 phy_r5 = {.d32 = 0}; + + cr_bus_addr(addr); + + phy_r4.b.phy_cr_data_in = data; + writel(phy_r4.d32, pcie_aml_regs.pcie_phy_r[4]); + + phy_r4.b.phy_cr_cap_data = 0; + writel(phy_r4.d32, pcie_aml_regs.pcie_phy_r[4]); + phy_r4.b.phy_cr_cap_data = 1; + writel(phy_r4.d32, pcie_aml_regs.pcie_phy_r[4]); + + do { + phy_r5.d32 = readl(pcie_aml_regs.pcie_phy_r[5]); + } while (phy_r5.b.phy_cr_ack == 0); + + phy_r4.b.phy_cr_cap_data = 0; + writel(phy_r4.d32, pcie_aml_regs.pcie_phy_r[4]); + + do { + phy_r5.d32 = readl(pcie_aml_regs.pcie_phy_r[5]); + } while (phy_r5.b.phy_cr_ack == 1); + + phy_r4.b.phy_cr_write = 0; + writel(phy_r4.d32, pcie_aml_regs.pcie_phy_r[4]); + phy_r4.b.phy_cr_write = 1; + writel(phy_r4.d32, pcie_aml_regs.pcie_phy_r[4]); + + do { + phy_r5.d32 = readl(pcie_aml_regs.pcie_phy_r[5]); + } while (phy_r5.b.phy_cr_ack == 0); + + phy_r4.b.phy_cr_write = 0; + writel(phy_r4.d32, pcie_aml_regs.pcie_phy_r[4]); + + do { + phy_r5.d32 = readl(pcie_aml_regs.pcie_phy_r[5]); + } while (phy_r5.b.phy_cr_ack == 1); +} + + +static void amlogic_phy_cr_writel(u32 val, u32 reg) +{ + cr_bus_write(reg, val); +} + +static u32 amlogic_phy_cr_readl(u32 reg) +{ + return cr_bus_read(reg); +} + +static ssize_t show_pcie_cr_read(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + u32 status = 0; + + return sprintf(buf, "%d\n", status); +} + + +static ssize_t store_pcie_cr_read(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + u32 reg; + u32 val; + + if (sscanf(buf, "%x", ®) != 1) + return -EINVAL; + + val = amlogic_phy_cr_readl(reg); + dev_info(dev, "reg 0x%x value is 0x%x\n", reg, val); + + return count; +} +DEVICE_ATTR(phyread, 0644, show_pcie_cr_read, store_pcie_cr_read); + +static ssize_t show_pcie_cr_write(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + u32 status = 0; + + return sprintf(buf, "%d\n", status); +} + +static ssize_t store_pcie_cr_write(struct device *dev, + struct device_attribute *attr, + const char *buf_p, size_t count) +{ + unsigned reg, val; + char buf[80]; + int ret; + + count = min_t(size_t, count, (sizeof(buf)-1)); + strncpy(buf, buf_p, (u32)count); + + buf[count] = 0; + + ret = sscanf(buf, "%x %x", ®, &val); + + switch (ret) { + case 2: + amlogic_phy_cr_writel(val, reg); + break; + default: + return -EINVAL; + } + + return count; +} +DEVICE_ATTR(phywrite, 0644, show_pcie_cr_write, store_pcie_cr_write); + static void amlogic_pcie_assert_reset(struct amlogic_pcie *amlogic_pcie) { struct pcie_port *pp = &amlogic_pcie->pp; @@ -363,6 +536,7 @@ int amlogic_pcie_link_up(struct pcie_port *pp) while (smlh_up == 0 || rdlh_up == 0 || ltssm_up == 0 || speed_okay == 0) { + udelay(20); smlh_up = amlogic_cfg_readl(amlogic_pcie, PCIE_CFG_STATUS12); smlh_up = (smlh_up >> 6) & 0x1; @@ -394,7 +568,7 @@ int amlogic_pcie_link_up(struct pcie_port *pp) return 0; } - udelay(2); + udelay(20); } if (current_data_rate == PCIE_GEN2) @@ -484,6 +658,7 @@ static int __init amlogic_pcie_probe(struct platform_device *pdev) int board_type = 0; unsigned long rate = 100000000; int err; + int j = 0; dev_info(&pdev->dev, "amlogic_pcie_probe!\n"); @@ -555,6 +730,9 @@ static int __init amlogic_pcie_probe(struct platform_device *pdev) ret = PTR_ERR(amlogic_pcie->phy_base); goto fail_bus_clk; } + for (j = 0; j < 7; j++) + pcie_aml_regs.pcie_phy_r[j] = (void __iomem *) + ((unsigned long)amlogic_pcie->phy_base + 4*j); } else { amlogic_pcie->phy_base = g_amlogic_pcie->phy_base; } @@ -584,6 +762,8 @@ static int __init amlogic_pcie_probe(struct platform_device *pdev) goto fail_bus_clk; platform_set_drvdata(pdev, amlogic_pcie); + device_create_file(&pdev->dev, &dev_attr_phyread); + device_create_file(&pdev->dev, &dev_attr_phywrite); return 0; fail_bus_clk: @@ -598,6 +778,9 @@ static int __exit amlogic_pcie_remove(struct platform_device *pdev) { struct amlogic_pcie *amlogic_pcie = platform_get_drvdata(pdev); + device_remove_file(&pdev->dev, &dev_attr_phywrite); + device_remove_file(&pdev->dev, &dev_attr_phyread); + clk_disable_unprepare(amlogic_pcie->bus_clk); clk_disable_unprepare(amlogic_pcie->clk); diff --git a/drivers/amlogic/pci/pcie-amlogic.h b/drivers/amlogic/pci/pcie-amlogic.h index 7c6e885f0f70..3a0b394c7705 100644 --- a/drivers/amlogic/pci/pcie-amlogic.h +++ b/drivers/amlogic/pci/pcie-amlogic.h @@ -45,4 +45,110 @@ enum pcie_data_rate { #define PCIE_CAP_OFFSET 0x70 #define PCIE_DEV_CTRL_DEV_STUS (PCIE_CAP_OFFSET + 0x08) +union phy_r0 { + /** raw register data */ + uint32_t d32; + /** register bits */ + struct { + unsigned phy_test_powerdown:1; + unsigned phy_ref_use_pad:1; + unsigned pipe_port_sel:2; + unsigned pcs_common_clocks:1; + unsigned reserved:27; + } b; +}; + +union phy_r1 { + /** raw register data */ + uint32_t d32; + /** register bits */ + struct { + unsigned phy_tx1_term_offset:5; + unsigned phy_tx0_term_offset:5; + unsigned phy_rx1_eq:3; + unsigned phy_rx0_eq:3; + unsigned phy_los_level:5; + unsigned phy_los_bias:3; + unsigned phy_ref_clkdiv2:1; + unsigned phy_mpll_multiplier:7; + } b; +}; + +union phy_r2 { + /** raw register data */ + uint32_t d32; + /** register bits */ + struct { + unsigned pcs_tx_deemph_gen2_6db:6; + unsigned pcs_tx_deemph_gen2_3p5db:6; + unsigned pcs_tx_deemph_gen1:6; + unsigned phy_tx_vboost_lvl:3; + unsigned reserved:11; + } b; +}; + +union phy_r3 { + /** raw register data */ + uint32_t d32; + /** register bits */ + struct { + unsigned pcs_tx_swing_low:7; + unsigned pcs_tx_swing_full:7; + unsigned reserved:18; + } b; +}; + +union phy_r4 { + /** raw register data */ + uint32_t d32; + /** register bits */ + struct { + unsigned phy_cr_write:1; + unsigned phy_cr_read:1; + unsigned phy_cr_data_in:16; + unsigned phy_cr_cap_data:1; + unsigned phy_cr_cap_addr:1; + unsigned reserved:12; + } b; +}; + +union phy_r5 { + /** raw register data */ + uint32_t d32; + /** register bits */ + struct { + unsigned phy_cr_data_out:16; + unsigned phy_cr_ack:1; + unsigned phy_bs_out:1; + unsigned reserved:14; + } b; +}; + +union phy_r6 { + /** raw register data */ + uint32_t d32; + /** register bits */ + struct { + unsigned phy_bs_update_dr:1; + unsigned phy_bs_shift_dr:1; + unsigned phy_bs_preload:1; + unsigned phy_bs_invert:1; + unsigned phy_bs_init:1; + unsigned phy_bs_in:1; + unsigned phy_bs_highz:1; + unsigned phy_bs_extest_ac:1; + unsigned phy_bs_extest:1; + unsigned phy_bs_clk:1; + unsigned phy_bs_clamp:1; + unsigned phy_bs_capture_dr:1; + unsigned phy_acjt_level:5; + unsigned reserved:15; + } b; +}; + +struct pcie_phy_aml_regs { + void __iomem *pcie_phy_r[7]; +}; + + #endif