Skip to content

Commit

Permalink
Merge pull request linux4kix#4 from linux4kix/linux-linaro-lsk-v3.14-mx6
Browse files Browse the repository at this point in the history
Working PCIe support for the HB
  • Loading branch information
rabeeh committed Sep 7, 2014
2 parents 4a2f77e + d4e29b7 commit 8856fbf
Show file tree
Hide file tree
Showing 6 changed files with 97 additions and 16 deletions.
15 changes: 15 additions & 0 deletions arch/arm/boot/dts/imx6qdl-hummingboard.dtsi
Original file line number Diff line number Diff line change
Expand Up @@ -267,6 +267,12 @@
MX6QDL_PAD_SD2_DAT3__SD2_DATA3 0x13059
>;
};

pinctrl_hummingboard_pcie_reset: hummingboard-pcie-reset {
fsl,pins = <
MX6QDL_PAD_EIM_DA4__GPIO3_IO04 0x80000000
>;
};
};
};

Expand Down Expand Up @@ -322,3 +328,12 @@
fsl,cpu_pdnscr_iso2sw = <0x1>;
fsl,cpu_pdnscr_iso = <0x1>;
};

&pcie {
pinctrl-names = "default";
pinctrl-0 = <
&pinctrl_hummingboard_pcie_reset
>;
reset-gpio = <&gpio3 4 0>;
status = "okay";
};
8 changes: 4 additions & 4 deletions arch/arm/boot/dts/imx6qdl.dtsi
Original file line number Diff line number Diff line change
Expand Up @@ -149,16 +149,16 @@
0x81000000 0 0 0x01f80000 0 0x00010000 /* downstream I/O */
0x82000000 0 0x01000000 0x01000000 0 0x00f00000>; /* non-prefetchable memory */
num-lanes = <1>;
interrupts = <GIC_SPI 120 IRQ_TYPE_LEVEL_HIGH>;
interrupt-names = "msi";
interrupts = <GIC_SPI 123 IRQ_TYPE_LEVEL_HIGH>;
interrupt-names = "pme";
#interrupt-cells = <1>;
interrupt-map-mask = <0 0 0 0x7>;
interrupt-map = <0 0 0 1 &intc GIC_SPI 123 IRQ_TYPE_LEVEL_HIGH>,
<0 0 0 2 &intc GIC_SPI 122 IRQ_TYPE_LEVEL_HIGH>,
<0 0 0 3 &intc GIC_SPI 121 IRQ_TYPE_LEVEL_HIGH>,
<0 0 0 4 &intc GIC_SPI 120 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&clks 144>, <&clks 206>, <&clks 189>, <&clks 221>;
clock-names = "pcie", "pcie_bus", "pcie_phy", "lvds_gate";
clocks = <&clks 144>, <&clks 221>, <&clks 189>, <&clks 187>;
clock-names = "pcie_axi", "lvds_gate", "pcie_ref_125m", "sata_ref_100m";
status = "disabled";
};

Expand Down
2 changes: 1 addition & 1 deletion drivers/clk/clk-mux.c
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,7 @@ struct clk *clk_register_mux_table(struct device *dev, const char *name,
init.ops = &clk_mux_ro_ops;
else
init.ops = &clk_mux_ops;
init.flags = flags | CLK_IS_BASIC;
init.flags = flags | CLK_IS_BASIC | CLK_IS_BASIC_MUX;
init.parent_names = parent_names;
init.num_parents = num_parents;

Expand Down
13 changes: 13 additions & 0 deletions drivers/clk/clk.c
Original file line number Diff line number Diff line change
Expand Up @@ -1702,6 +1702,7 @@ void __clk_reparent(struct clk *clk, struct clk *new_parent)
*/
int clk_set_parent(struct clk *clk, struct clk *parent)
{
struct clk *child;
int ret = 0;
int p_index = 0;
unsigned long p_rate = 0;
Expand All @@ -1728,6 +1729,18 @@ int clk_set_parent(struct clk *clk, struct clk *parent)
goto out;
}

/* check two consecutive basic mux clocks */
if (clk->flags & CLK_IS_BASIC_MUX) {
hlist_for_each_entry(child, &clk->children, child_node) {
if (child->flags & CLK_IS_BASIC_MUX) {
pr_err("%s: failed to switch parent of %s due to child mux %s\n",
__func__, clk->name, child->name);
ret = -EBUSY;
goto out;
}
}
}

/* try finding the new parent index */
if (parent) {
p_index = clk_fetch_parent_index(clk, parent);
Expand Down
68 changes: 57 additions & 11 deletions drivers/pci/host/pci-imx6.c
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,9 @@ struct imx6_pcie {

/* PCIe Port Logic registers (memory-mapped) */
#define PL_OFFSET 0x700
#define PCIE_PL_PFLR (PL_OFFSET + 0x08)
#define PCIE_PL_PFLR_LINK_STATE_MASK (0x3f << 16)
#define PCIE_PL_PFLR_FORCE_LINK (1 << 15)
#define PCIE_PHY_DEBUG_R0 (PL_OFFSET + 0x28)
#define PCIE_PHY_DEBUG_R1 (PL_OFFSET + 0x2c)
#define PCIE_PHY_DEBUG_R1_XMLH_LINK_IN_TRAINING (1 << 29)
Expand Down Expand Up @@ -226,6 +229,18 @@ static int imx6q_pcie_abort_handler(unsigned long addr,
return 0;
}

static int imx6_pcie_assert_core_reset(struct pcie_port *pp)
{
struct imx6_pcie *imx6_pcie = to_imx6_pcie(pp);

regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR1,
IMX6Q_GPR1_PCIE_TEST_PD, 1 << 18);
regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR1,
IMX6Q_GPR1_PCIE_REF_CLK_EN, 0 << 16);

return 0;
}

static int imx6_pcie_deassert_core_reset(struct pcie_port *pp)
{
struct imx6_pcie *imx6_pcie = to_imx6_pcie(pp);
Expand All @@ -234,10 +249,6 @@ static int imx6_pcie_deassert_core_reset(struct pcie_port *pp)
if (gpio_is_valid(imx6_pcie->power_on_gpio))
gpio_set_value(imx6_pcie->power_on_gpio, 1);

regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR1,
IMX6Q_GPR1_PCIE_TEST_PD, 0 << 18);
regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR1,
IMX6Q_GPR1_PCIE_REF_CLK_EN, 1 << 16);
request_bus_freq(BUS_FREQ_HIGH);

ret = clk_prepare_enable(imx6_pcie->sata_ref_100m);
Expand Down Expand Up @@ -270,6 +281,12 @@ static int imx6_pcie_deassert_core_reset(struct pcie_port *pp)
/* allow the clocks to stabilize */
usleep_range(200, 500);

/* power up core phy and enable ref clock */
regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR1,
IMX6Q_GPR1_PCIE_TEST_PD, 0 << 18);
regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR1,
IMX6Q_GPR1_PCIE_REF_CLK_EN, 1 << 16);

/* Some boards don't have PCIe reset GPIO. */
if (gpio_is_valid(imx6_pcie->reset_gpio)) {
gpio_set_value(imx6_pcie->reset_gpio, 0);
Expand All @@ -293,6 +310,31 @@ static int imx6_pcie_deassert_core_reset(struct pcie_port *pp)
static void imx6_pcie_init_phy(struct pcie_port *pp)
{
struct imx6_pcie *imx6_pcie = to_imx6_pcie(pp);
u32 val, gpr1, gpr12;

/*
* If the bootloader already enabled the link we need some special
* handling to get the core back into a state where it is safe to
* touch it for configuration. As there is no dedicated reset signal
* wired up for MX6QDL, we need to manually force LTSSM into "detect"
* state before completely disabling LTSSM, which is a prerequisite
* for core configuration.
* If both LTSSM_ENABLE and REF_SSP_ENABLE are active we have a strong
* indication that the bootloader activated the link.
*/
regmap_read(imx6_pcie->iomuxc_gpr, IOMUXC_GPR1, &gpr1);
regmap_read(imx6_pcie->iomuxc_gpr, IOMUXC_GPR12, &gpr12);

if ((gpr1 & IMX6Q_GPR1_PCIE_REF_CLK_EN) &&
(gpr12 & IMX6Q_GPR12_PCIE_CTL_2)) {
val = readl(pp->dbi_base + PCIE_PL_PFLR);
val &= ~PCIE_PL_PFLR_LINK_STATE_MASK;
val |= PCIE_PL_PFLR_FORCE_LINK;
writel(val, pp->dbi_base + PCIE_PL_PFLR);

regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR12,
IMX6Q_GPR12_PCIE_CTL_2, 0 << 10);
}

regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR12,
IMX6Q_GPR12_PCIE_CTL_2, 0 << 10);
Expand Down Expand Up @@ -323,7 +365,6 @@ static void imx6_pcie_init_phy(struct pcie_port *pp)

static int imx6_pcie_wait_for_link(struct pcie_port *pp)
{
struct imx6_pcie *imx6_pcie = to_imx6_pcie(pp);
int count = 200;

while (!dw_pcie_link_up(pp)) {
Expand All @@ -344,12 +385,6 @@ static int imx6_pcie_wait_for_link(struct pcie_port *pp)
dw_pcie_msi_init(pp);
}

if (gpio_is_valid(imx6_pcie->reset_gpio)) {
gpio_set_value(imx6_pcie->reset_gpio, 0);
msleep(100);
gpio_set_value(imx6_pcie->reset_gpio, 1);
}

return 0;
}

Expand Down Expand Up @@ -427,6 +462,8 @@ static irqreturn_t imx_pcie_msi_irq_handler(int irq, void *arg)

static void imx6_pcie_host_init(struct pcie_port *pp)
{
imx6_pcie_assert_core_reset(pp);

imx6_pcie_init_phy(pp);

imx6_pcie_deassert_core_reset(pp);
Expand Down Expand Up @@ -989,6 +1026,14 @@ static int __init imx6_pcie_probe(struct platform_device *pdev)
return ret;
}

static void imx6_pcie_shutdown(struct platform_device *pdev)
{
struct imx6_pcie *imx6_pcie = platform_get_drvdata(pdev);

/* bring down link, so bootloader gets clean state in case of reboot */
imx6_pcie_assert_core_reset(&imx6_pcie->pp);
}

static const struct of_device_id imx6_pcie_of_match[] = {
{ .compatible = "fsl,imx6q-pcie", },
{},
Expand All @@ -1001,6 +1046,7 @@ static struct platform_driver imx6_pcie_driver = {
.owner = THIS_MODULE,
.of_match_table = imx6_pcie_of_match,
},
.shutdown = imx6_pcie_shutdown,
};

/* Freescale PCIe driver does not allow module unload */
Expand Down
7 changes: 7 additions & 0 deletions include/linux/clk-provider.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,13 @@
#define CLK_GET_RATE_NOCACHE BIT(6) /* do not use the cached clk rate */
#define CLK_SET_RATE_NO_REPARENT BIT(7) /* don't re-parent on rate change */
#define CLK_GET_ACCURACY_NOCACHE BIT(8) /* do not use the cached clk accuracy */
/*
* Basic mux clk, can't switch parent while there is another basic mux clk
* being its child. Otherwise, a glitch might be propagated to downstream
* clocks through this child mux.
*/
#define CLK_IS_BASIC_MUX BIT(9)


struct clk_hw;

Expand Down

0 comments on commit 8856fbf

Please sign in to comment.