pcie: add pcie phy control register access.

PD#142470: pcie: add pcie phy control register access.

Change-Id: I832b05763a722c074980f19682c6249915c0363d
Signed-off-by: Yue Wang <yue.wang@amlogic.com>
This commit is contained in:
Yue Wang
2017-06-02 15:58:45 +08:00
committed by Victor Wan
parent ccb6b33083
commit f8a52fe548
2 changed files with 290 additions and 1 deletions

View File

@@ -27,6 +27,7 @@
#include <linux/resource.h>
#include <linux/signal.h>
#include <linux/types.h>
#include <linux/module.h>
#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", &reg) != 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", &reg, &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);

View File

@@ -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