Commit 1bcf2331 authored by Bjorn Helgaas's avatar Bjorn Helgaas

Merge branch 'pci/controller/mediatek-gen3'

- Add per-SoC struct mtk_gen3_pcie_pdata to support multiple SoC types
  (Lorenzo Bianconi)

- Use reset_bulk APIs to manage PHY reset lines (Lorenzo Bianconi)

- Add DT and driver support for Airoha EN7581 PCIe controller (Lorenzo
  Bianconi)

* pci/controller/mediatek-gen3:
  PCI: mediatek-gen3: Add Airoha EN7581 support
  PCI: mediatek-gen3: Rely on reset_bulk APIs for PHY reset lines
  PCI: mediatek-gen3: Add mtk_gen3_pcie_pdata data structure
  dt-bindings: PCI: mediatek-gen3: Add support for Airoha EN7581
parents 487ce3e5 f6ab8983
...@@ -53,6 +53,7 @@ properties: ...@@ -53,6 +53,7 @@ properties:
- mediatek,mt8195-pcie - mediatek,mt8195-pcie
- const: mediatek,mt8192-pcie - const: mediatek,mt8192-pcie
- const: mediatek,mt8192-pcie - const: mediatek,mt8192-pcie
- const: airoha,en7581-pcie
reg: reg:
maxItems: 1 maxItems: 1
...@@ -76,20 +77,20 @@ properties: ...@@ -76,20 +77,20 @@ properties:
resets: resets:
minItems: 1 minItems: 1
maxItems: 2 maxItems: 3
reset-names: reset-names:
minItems: 1 minItems: 1
maxItems: 2 maxItems: 3
items: items:
enum: [ phy, mac ] enum: [ phy, mac, phy-lane0, phy-lane1, phy-lane2 ]
clocks: clocks:
minItems: 4 minItems: 1
maxItems: 6 maxItems: 6
clock-names: clock-names:
minItems: 4 minItems: 1
maxItems: 6 maxItems: 6
assigned-clocks: assigned-clocks:
...@@ -147,6 +148,9 @@ allOf: ...@@ -147,6 +148,9 @@ allOf:
const: mediatek,mt8192-pcie const: mediatek,mt8192-pcie
then: then:
properties: properties:
clocks:
minItems: 4
clock-names: clock-names:
items: items:
- const: pl_250m - const: pl_250m
...@@ -155,6 +159,15 @@ allOf: ...@@ -155,6 +159,15 @@ allOf:
- const: tl_32k - const: tl_32k
- const: peri_26m - const: peri_26m
- const: top_133m - const: top_133m
resets:
minItems: 1
maxItems: 2
reset-names:
minItems: 1
maxItems: 2
- if: - if:
properties: properties:
compatible: compatible:
...@@ -164,6 +177,9 @@ allOf: ...@@ -164,6 +177,9 @@ allOf:
- mediatek,mt8195-pcie - mediatek,mt8195-pcie
then: then:
properties: properties:
clocks:
minItems: 4
clock-names: clock-names:
items: items:
- const: pl_250m - const: pl_250m
...@@ -172,6 +188,15 @@ allOf: ...@@ -172,6 +188,15 @@ allOf:
- const: tl_32k - const: tl_32k
- const: peri_26m - const: peri_26m
- const: peri_mem - const: peri_mem
resets:
minItems: 1
maxItems: 2
reset-names:
minItems: 1
maxItems: 2
- if: - if:
properties: properties:
compatible: compatible:
...@@ -180,6 +205,9 @@ allOf: ...@@ -180,6 +205,9 @@ allOf:
- mediatek,mt7986-pcie - mediatek,mt7986-pcie
then: then:
properties: properties:
clocks:
minItems: 4
clock-names: clock-names:
items: items:
- const: pl_250m - const: pl_250m
...@@ -187,6 +215,36 @@ allOf: ...@@ -187,6 +215,36 @@ allOf:
- const: peri_26m - const: peri_26m
- const: top_133m - const: top_133m
resets:
minItems: 1
maxItems: 2
reset-names:
minItems: 1
maxItems: 2
- if:
properties:
compatible:
const: airoha,en7581-pcie
then:
properties:
clocks:
maxItems: 1
clock-names:
items:
- const: sys-ck
resets:
minItems: 3
reset-names:
items:
- const: phy-lane0
- const: phy-lane1
- const: phy-lane2
unevaluatedProperties: false unevaluatedProperties: false
examples: examples:
......
...@@ -196,7 +196,7 @@ config PCIE_MEDIATEK ...@@ -196,7 +196,7 @@ config PCIE_MEDIATEK
config PCIE_MEDIATEK_GEN3 config PCIE_MEDIATEK_GEN3
tristate "MediaTek Gen3 PCIe controller" tristate "MediaTek Gen3 PCIe controller"
depends on ARCH_MEDIATEK || COMPILE_TEST depends on ARCH_AIROHA || ARCH_MEDIATEK || COMPILE_TEST
depends on PCI_MSI depends on PCI_MSI
help help
Adds support for PCIe Gen3 MAC controller for MediaTek SoCs. Adds support for PCIe Gen3 MAC controller for MediaTek SoCs.
......
...@@ -6,7 +6,9 @@ ...@@ -6,7 +6,9 @@
* Author: Jianjun Wang <jianjun.wang@mediatek.com> * Author: Jianjun Wang <jianjun.wang@mediatek.com>
*/ */
#include <linux/bitfield.h>
#include <linux/clk.h> #include <linux/clk.h>
#include <linux/clk-provider.h>
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/iopoll.h> #include <linux/iopoll.h>
#include <linux/irq.h> #include <linux/irq.h>
...@@ -15,6 +17,8 @@ ...@@ -15,6 +17,8 @@
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/msi.h> #include <linux/msi.h>
#include <linux/of_device.h>
#include <linux/of_pci.h>
#include <linux/pci.h> #include <linux/pci.h>
#include <linux/phy/phy.h> #include <linux/phy/phy.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
...@@ -29,6 +33,12 @@ ...@@ -29,6 +33,12 @@
#define PCI_CLASS(class) (class << 8) #define PCI_CLASS(class) (class << 8)
#define PCIE_RC_MODE BIT(0) #define PCIE_RC_MODE BIT(0)
#define PCIE_EQ_PRESET_01_REG 0x100
#define PCIE_VAL_LN0_DOWNSTREAM GENMASK(6, 0)
#define PCIE_VAL_LN0_UPSTREAM GENMASK(14, 8)
#define PCIE_VAL_LN1_DOWNSTREAM GENMASK(22, 16)
#define PCIE_VAL_LN1_UPSTREAM GENMASK(30, 24)
#define PCIE_CFGNUM_REG 0x140 #define PCIE_CFGNUM_REG 0x140
#define PCIE_CFG_DEVFN(devfn) ((devfn) & GENMASK(7, 0)) #define PCIE_CFG_DEVFN(devfn) ((devfn) & GENMASK(7, 0))
#define PCIE_CFG_BUS(bus) (((bus) << 8) & GENMASK(15, 8)) #define PCIE_CFG_BUS(bus) (((bus) << 8) & GENMASK(15, 8))
...@@ -68,6 +78,14 @@ ...@@ -68,6 +78,14 @@
#define PCIE_MSI_SET_ENABLE_REG 0x190 #define PCIE_MSI_SET_ENABLE_REG 0x190
#define PCIE_MSI_SET_ENABLE GENMASK(PCIE_MSI_SET_NUM - 1, 0) #define PCIE_MSI_SET_ENABLE GENMASK(PCIE_MSI_SET_NUM - 1, 0)
#define PCIE_PIPE4_PIE8_REG 0x338
#define PCIE_K_FINETUNE_MAX GENMASK(5, 0)
#define PCIE_K_FINETUNE_ERR GENMASK(7, 6)
#define PCIE_K_PRESET_TO_USE GENMASK(18, 8)
#define PCIE_K_PHYPARAM_QUERY BIT(19)
#define PCIE_K_QUERY_TIMEOUT BIT(20)
#define PCIE_K_PRESET_TO_USE_16G GENMASK(31, 21)
#define PCIE_MSI_SET_BASE_REG 0xc00 #define PCIE_MSI_SET_BASE_REG 0xc00
#define PCIE_MSI_SET_OFFSET 0x10 #define PCIE_MSI_SET_OFFSET 0x10
#define PCIE_MSI_SET_STATUS_OFFSET 0x04 #define PCIE_MSI_SET_STATUS_OFFSET 0x04
...@@ -100,6 +118,26 @@ ...@@ -100,6 +118,26 @@
#define PCIE_ATR_TLP_TYPE_MEM PCIE_ATR_TLP_TYPE(0) #define PCIE_ATR_TLP_TYPE_MEM PCIE_ATR_TLP_TYPE(0)
#define PCIE_ATR_TLP_TYPE_IO PCIE_ATR_TLP_TYPE(2) #define PCIE_ATR_TLP_TYPE_IO PCIE_ATR_TLP_TYPE(2)
#define MAX_NUM_PHY_RESETS 3
/* Time in ms needed to complete PCIe reset on EN7581 SoC */
#define PCIE_EN7581_RESET_TIME_MS 100
struct mtk_gen3_pcie;
/**
* struct mtk_gen3_pcie_pdata - differentiate between host generations
* @power_up: pcie power_up callback
* @phy_resets: phy reset lines SoC data.
*/
struct mtk_gen3_pcie_pdata {
int (*power_up)(struct mtk_gen3_pcie *pcie);
struct {
const char *id[MAX_NUM_PHY_RESETS];
int num_resets;
} phy_resets;
};
/** /**
* struct mtk_msi_set - MSI information for each set * struct mtk_msi_set - MSI information for each set
* @base: IO mapped register base * @base: IO mapped register base
...@@ -118,7 +156,7 @@ struct mtk_msi_set { ...@@ -118,7 +156,7 @@ struct mtk_msi_set {
* @base: IO mapped register base * @base: IO mapped register base
* @reg_base: physical register base * @reg_base: physical register base
* @mac_reset: MAC reset control * @mac_reset: MAC reset control
* @phy_reset: PHY reset control * @phy_resets: PHY reset controllers
* @phy: PHY controller block * @phy: PHY controller block
* @clks: PCIe clocks * @clks: PCIe clocks
* @num_clks: PCIe clocks count for this port * @num_clks: PCIe clocks count for this port
...@@ -131,13 +169,14 @@ struct mtk_msi_set { ...@@ -131,13 +169,14 @@ struct mtk_msi_set {
* @msi_sets: MSI sets information * @msi_sets: MSI sets information
* @lock: lock protecting IRQ bit map * @lock: lock protecting IRQ bit map
* @msi_irq_in_use: bit map for assigned MSI IRQ * @msi_irq_in_use: bit map for assigned MSI IRQ
* @soc: pointer to SoC-dependent operations
*/ */
struct mtk_gen3_pcie { struct mtk_gen3_pcie {
struct device *dev; struct device *dev;
void __iomem *base; void __iomem *base;
phys_addr_t reg_base; phys_addr_t reg_base;
struct reset_control *mac_reset; struct reset_control *mac_reset;
struct reset_control *phy_reset; struct reset_control_bulk_data phy_resets[MAX_NUM_PHY_RESETS];
struct phy *phy; struct phy *phy;
struct clk_bulk_data *clks; struct clk_bulk_data *clks;
int num_clks; int num_clks;
...@@ -151,6 +190,8 @@ struct mtk_gen3_pcie { ...@@ -151,6 +190,8 @@ struct mtk_gen3_pcie {
struct mtk_msi_set msi_sets[PCIE_MSI_SET_NUM]; struct mtk_msi_set msi_sets[PCIE_MSI_SET_NUM];
struct mutex lock; struct mutex lock;
DECLARE_BITMAP(msi_irq_in_use, PCIE_MSI_IRQS_NUM); DECLARE_BITMAP(msi_irq_in_use, PCIE_MSI_IRQS_NUM);
const struct mtk_gen3_pcie_pdata *soc;
}; };
/* LTSSM state in PCIE_LTSSM_STATUS_REG bit[28:24] */ /* LTSSM state in PCIE_LTSSM_STATUS_REG bit[28:24] */
...@@ -768,10 +809,10 @@ static int mtk_pcie_setup_irq(struct mtk_gen3_pcie *pcie) ...@@ -768,10 +809,10 @@ static int mtk_pcie_setup_irq(struct mtk_gen3_pcie *pcie)
static int mtk_pcie_parse_port(struct mtk_gen3_pcie *pcie) static int mtk_pcie_parse_port(struct mtk_gen3_pcie *pcie)
{ {
int i, ret, num_resets = pcie->soc->phy_resets.num_resets;
struct device *dev = pcie->dev; struct device *dev = pcie->dev;
struct platform_device *pdev = to_platform_device(dev); struct platform_device *pdev = to_platform_device(dev);
struct resource *regs; struct resource *regs;
int ret;
regs = platform_get_resource_byname(pdev, IORESOURCE_MEM, "pcie-mac"); regs = platform_get_resource_byname(pdev, IORESOURCE_MEM, "pcie-mac");
if (!regs) if (!regs)
...@@ -784,12 +825,12 @@ static int mtk_pcie_parse_port(struct mtk_gen3_pcie *pcie) ...@@ -784,12 +825,12 @@ static int mtk_pcie_parse_port(struct mtk_gen3_pcie *pcie)
pcie->reg_base = regs->start; pcie->reg_base = regs->start;
pcie->phy_reset = devm_reset_control_get_optional_exclusive(dev, "phy"); for (i = 0; i < num_resets; i++)
if (IS_ERR(pcie->phy_reset)) { pcie->phy_resets[i].id = pcie->soc->phy_resets.id[i];
ret = PTR_ERR(pcie->phy_reset);
if (ret != -EPROBE_DEFER)
dev_err(dev, "failed to get PHY reset\n");
ret = devm_reset_control_bulk_get_optional_shared(dev, num_resets, pcie->phy_resets);
if (ret) {
dev_err(dev, "failed to get PHY bulk reset\n");
return ret; return ret;
} }
...@@ -820,13 +861,96 @@ static int mtk_pcie_parse_port(struct mtk_gen3_pcie *pcie) ...@@ -820,13 +861,96 @@ static int mtk_pcie_parse_port(struct mtk_gen3_pcie *pcie)
return 0; return 0;
} }
static int mtk_pcie_en7581_power_up(struct mtk_gen3_pcie *pcie)
{
struct device *dev = pcie->dev;
int err;
u32 val;
/*
* Wait for the time needed to complete the bulk assert in
* mtk_pcie_setup for EN7581 SoC.
*/
mdelay(PCIE_EN7581_RESET_TIME_MS);
err = phy_init(pcie->phy);
if (err) {
dev_err(dev, "failed to initialize PHY\n");
return err;
}
err = phy_power_on(pcie->phy);
if (err) {
dev_err(dev, "failed to power on PHY\n");
goto err_phy_on;
}
err = reset_control_bulk_deassert(pcie->soc->phy_resets.num_resets, pcie->phy_resets);
if (err) {
dev_err(dev, "failed to deassert PHYs\n");
goto err_phy_deassert;
}
/*
* Wait for the time needed to complete the bulk de-assert above.
* This time is specific for EN7581 SoC.
*/
mdelay(PCIE_EN7581_RESET_TIME_MS);
pm_runtime_enable(dev);
pm_runtime_get_sync(dev);
err = clk_bulk_prepare(pcie->num_clks, pcie->clks);
if (err) {
dev_err(dev, "failed to prepare clock\n");
goto err_clk_prepare;
}
val = FIELD_PREP(PCIE_VAL_LN0_DOWNSTREAM, 0x47) |
FIELD_PREP(PCIE_VAL_LN1_DOWNSTREAM, 0x47) |
FIELD_PREP(PCIE_VAL_LN0_UPSTREAM, 0x41) |
FIELD_PREP(PCIE_VAL_LN1_UPSTREAM, 0x41);
writel_relaxed(val, pcie->base + PCIE_EQ_PRESET_01_REG);
val = PCIE_K_PHYPARAM_QUERY | PCIE_K_QUERY_TIMEOUT |
FIELD_PREP(PCIE_K_PRESET_TO_USE_16G, 0x80) |
FIELD_PREP(PCIE_K_PRESET_TO_USE, 0x2) |
FIELD_PREP(PCIE_K_FINETUNE_MAX, 0xf);
writel_relaxed(val, pcie->base + PCIE_PIPE4_PIE8_REG);
err = clk_bulk_enable(pcie->num_clks, pcie->clks);
if (err) {
dev_err(dev, "failed to prepare clock\n");
goto err_clk_enable;
}
return 0;
err_clk_enable:
clk_bulk_unprepare(pcie->num_clks, pcie->clks);
err_clk_prepare:
pm_runtime_put_sync(dev);
pm_runtime_disable(dev);
reset_control_bulk_assert(pcie->soc->phy_resets.num_resets, pcie->phy_resets);
err_phy_deassert:
phy_power_off(pcie->phy);
err_phy_on:
phy_exit(pcie->phy);
return err;
}
static int mtk_pcie_power_up(struct mtk_gen3_pcie *pcie) static int mtk_pcie_power_up(struct mtk_gen3_pcie *pcie)
{ {
struct device *dev = pcie->dev; struct device *dev = pcie->dev;
int err; int err;
/* PHY power on and enable pipe clock */ /* PHY power on and enable pipe clock */
reset_control_deassert(pcie->phy_reset); err = reset_control_bulk_deassert(pcie->soc->phy_resets.num_resets, pcie->phy_resets);
if (err) {
dev_err(dev, "failed to deassert PHYs\n");
return err;
}
err = phy_init(pcie->phy); err = phy_init(pcie->phy);
if (err) { if (err) {
...@@ -862,7 +986,7 @@ static int mtk_pcie_power_up(struct mtk_gen3_pcie *pcie) ...@@ -862,7 +986,7 @@ static int mtk_pcie_power_up(struct mtk_gen3_pcie *pcie)
err_phy_on: err_phy_on:
phy_exit(pcie->phy); phy_exit(pcie->phy);
err_phy_init: err_phy_init:
reset_control_assert(pcie->phy_reset); reset_control_bulk_assert(pcie->soc->phy_resets.num_resets, pcie->phy_resets);
return err; return err;
} }
...@@ -877,7 +1001,7 @@ static void mtk_pcie_power_down(struct mtk_gen3_pcie *pcie) ...@@ -877,7 +1001,7 @@ static void mtk_pcie_power_down(struct mtk_gen3_pcie *pcie)
phy_power_off(pcie->phy); phy_power_off(pcie->phy);
phy_exit(pcie->phy); phy_exit(pcie->phy);
reset_control_assert(pcie->phy_reset); reset_control_bulk_assert(pcie->soc->phy_resets.num_resets, pcie->phy_resets);
} }
static int mtk_pcie_setup(struct mtk_gen3_pcie *pcie) static int mtk_pcie_setup(struct mtk_gen3_pcie *pcie)
...@@ -888,16 +1012,22 @@ static int mtk_pcie_setup(struct mtk_gen3_pcie *pcie) ...@@ -888,16 +1012,22 @@ static int mtk_pcie_setup(struct mtk_gen3_pcie *pcie)
if (err) if (err)
return err; return err;
/*
* Deassert the line in order to avoid unbalance in deassert_count
* counter since the bulk is shared.
*/
reset_control_bulk_deassert(pcie->soc->phy_resets.num_resets, pcie->phy_resets);
/* /*
* The controller may have been left out of reset by the bootloader * The controller may have been left out of reset by the bootloader
* so make sure that we get a clean start by asserting resets here. * so make sure that we get a clean start by asserting resets here.
*/ */
reset_control_assert(pcie->phy_reset); reset_control_bulk_assert(pcie->soc->phy_resets.num_resets, pcie->phy_resets);
reset_control_assert(pcie->mac_reset); reset_control_assert(pcie->mac_reset);
usleep_range(10, 20); usleep_range(10, 20);
/* Don't touch the hardware registers before power up */ /* Don't touch the hardware registers before power up */
err = mtk_pcie_power_up(pcie); err = pcie->soc->power_up(pcie);
if (err) if (err)
return err; return err;
...@@ -932,6 +1062,7 @@ static int mtk_pcie_probe(struct platform_device *pdev) ...@@ -932,6 +1062,7 @@ static int mtk_pcie_probe(struct platform_device *pdev)
pcie = pci_host_bridge_priv(host); pcie = pci_host_bridge_priv(host);
pcie->dev = dev; pcie->dev = dev;
pcie->soc = device_get_match_data(dev);
platform_set_drvdata(pdev, pcie); platform_set_drvdata(pdev, pcie);
err = mtk_pcie_setup(pcie); err = mtk_pcie_setup(pcie);
...@@ -1047,7 +1178,7 @@ static int mtk_pcie_resume_noirq(struct device *dev) ...@@ -1047,7 +1178,7 @@ static int mtk_pcie_resume_noirq(struct device *dev)
struct mtk_gen3_pcie *pcie = dev_get_drvdata(dev); struct mtk_gen3_pcie *pcie = dev_get_drvdata(dev);
int err; int err;
err = mtk_pcie_power_up(pcie); err = pcie->soc->power_up(pcie);
if (err) if (err)
return err; return err;
...@@ -1067,8 +1198,27 @@ static const struct dev_pm_ops mtk_pcie_pm_ops = { ...@@ -1067,8 +1198,27 @@ static const struct dev_pm_ops mtk_pcie_pm_ops = {
mtk_pcie_resume_noirq) mtk_pcie_resume_noirq)
}; };
static const struct mtk_gen3_pcie_pdata mtk_pcie_soc_mt8192 = {
.power_up = mtk_pcie_power_up,
.phy_resets = {
.id[0] = "phy",
.num_resets = 1,
},
};
static const struct mtk_gen3_pcie_pdata mtk_pcie_soc_en7581 = {
.power_up = mtk_pcie_en7581_power_up,
.phy_resets = {
.id[0] = "phy-lane0",
.id[1] = "phy-lane1",
.id[2] = "phy-lane2",
.num_resets = 3,
},
};
static const struct of_device_id mtk_pcie_of_match[] = { static const struct of_device_id mtk_pcie_of_match[] = {
{ .compatible = "mediatek,mt8192-pcie" }, { .compatible = "airoha,en7581-pcie", .data = &mtk_pcie_soc_en7581 },
{ .compatible = "mediatek,mt8192-pcie", .data = &mtk_pcie_soc_mt8192 },
{}, {},
}; };
MODULE_DEVICE_TABLE(of, mtk_pcie_of_match); MODULE_DEVICE_TABLE(of, mtk_pcie_of_match);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment