mirror of
https://github.com/hardkernel/linux.git
synced 2026-06-08 03:40:35 +09:00
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:
@@ -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", ®) != 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);
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user