From: Jianjun Wang <hidden> Date: 2021-03-24 03:06:43
These series patches add pcie-mediatek-gen3.c and dt-bindings file to
support new generation PCIe controller.
Changes in v9:
1. Use mtk_pcie_parse_port() to get the hw resources;
2. Remove unnecessary logs;
3. Add local IRQ enable status save/restore instead of
the enable/disable callbacks for suspend/resume;
4. Fix typos.
Changes in v8:
1. Add irq_clock to protect IRQ register access;
2. Mask all INTx interrupt when startup port;
3. Remove activate/deactivate callbacks from bottom_domain_ops;
4. Add unmask/mask callbacks in mtk_msi_bottom_irq_chip;
5. Add property information for reg-names.
Changes in v7:
1. Split the driver patch to core PCIe, INTx, MSI and PM patches;
2. Reshape MSI init and handle flow, use msi_bottom_domain to cover all sets;
3. Replace readl/writel with their relaxed version;
4. Add MSI description in binding document;
5. Add pl_250m clock in binding document.
Changes in v6:
1. Export pci_pio_to_address() to support compiling as kernel module;
2. Replace usleep_range(100 * 1000, 120 * 1000) with msleep(100);
3. Replace dev_notice with dev_err;
4. Fix MSI get hwirq flow;
5. Fix warning for possible recursive locking in mtk_pcie_set_affinity.
Changes in v5:
1. Remove unused macros
2. Modify the config read/write callbacks, set the config byte field
in TLP header and use pci_generic_config_read32/write32
to access the config space
3. Fix the settings of translation window, both MEM and IO regions
works properly
4. Fix typos
Changes in v4:
1. Fix PCIe power up/down flow
2. Use "mac" and "phy" for reset names
3. Add clock names
4. Fix the variables type
Changes in v3:
1. Remove standard property in binding document
2. Return error number when get_optional* API throws an error
3. Use the bulk clk APIs
Changes in v2:
1. Fix the typo of dt-bindings patch
2. Remove the unnecessary properties in binding document
3. dispos the irq mappings of msi top domain when irq teardown
Jianjun Wang (7):
dt-bindings: PCI: mediatek-gen3: Add YAML schema
PCI: Export pci_pio_to_address() for module use
PCI: mediatek-gen3: Add MediaTek Gen3 driver for MT8192
PCI: mediatek-gen3: Add INTx support
PCI: mediatek-gen3: Add MSI support
PCI: mediatek-gen3: Add system PM support
MAINTAINERS: Add Jianjun Wang as MediaTek PCI co-maintainer
.../bindings/pci/mediatek-pcie-gen3.yaml | 181 +++
MAINTAINERS | 1 +
drivers/pci/controller/Kconfig | 13 +
drivers/pci/controller/Makefile | 1 +
drivers/pci/controller/pcie-mediatek-gen3.c | 1025 +++++++++++++++++
drivers/pci/pci.c | 1 +
6 files changed, 1222 insertions(+)
create mode 100644 Documentation/devicetree/bindings/pci/mediatek-pcie-gen3.yaml
create mode 100644 drivers/pci/controller/pcie-mediatek-gen3.c
--
2.25.1
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
From: Jianjun Wang <hidden> Date: 2021-03-24 03:06:44
This interface will be used by PCI host drivers for PIO translation,
export it to support compiling those drivers as kernel modules.
Signed-off-by: Jianjun Wang <redacted>
---
drivers/pci/pci.c | 1 +
1 file changed, 1 insertion(+)
From: Jianjun Wang <hidden> Date: 2021-03-24 03:06:44
MediaTek's PCIe host controller has three generation HWs, the new
generation HW is an individual bridge, it supports Gen3 speed and
compatible with Gen2, Gen1 speed.
Add support for new Gen3 controller which can be found on MT8192.
Signed-off-by: Jianjun Wang <redacted>
Acked-by: Ryder Lee <ryder.lee@mediatek.com>
---
drivers/pci/controller/Kconfig | 13 +
drivers/pci/controller/Makefile | 1 +
drivers/pci/controller/pcie-mediatek-gen3.c | 464 ++++++++++++++++++++
3 files changed, 478 insertions(+)
create mode 100644 drivers/pci/controller/pcie-mediatek-gen3.c
@@ -0,0 +1,464 @@+// SPDX-License-Identifier: GPL-2.0+/*+*MediaTekPCIehostcontrollerdriver.+*+*Copyright(c)2020MediaTekInc.+*Author:JianjunWang<jianjun.wang@mediatek.com>+*/++#include<linux/clk.h>+#include<linux/delay.h>+#include<linux/iopoll.h>+#include<linux/kernel.h>+#include<linux/module.h>+#include<linux/pci.h>+#include<linux/phy/phy.h>+#include<linux/platform_device.h>+#include<linux/pm_domain.h>+#include<linux/pm_runtime.h>+#include<linux/reset.h>++#include"../pci.h"++#define PCIE_SETTING_REG 0x80+#define PCIE_PCI_IDS_1 0x9c+#define PCI_CLASS(class) (class << 8)+#define PCIE_RC_MODE BIT(0)++#define PCIE_CFGNUM_REG 0x140+#define PCIE_CFG_DEVFN(devfn) ((devfn) & GENMASK(7, 0))+#define PCIE_CFG_BUS(bus) (((bus) << 8) & GENMASK(15, 8))+#define PCIE_CFG_BYTE_EN(bytes) (((bytes) << 16) & GENMASK(19, 16))+#define PCIE_CFG_FORCE_BYTE_EN BIT(20)+#define PCIE_CFG_OFFSET_ADDR 0x1000+#define PCIE_CFG_HEADER(bus, devfn) \+(PCIE_CFG_BUS(bus)|PCIE_CFG_DEVFN(devfn))++#define PCIE_RST_CTRL_REG 0x148+#define PCIE_MAC_RSTB BIT(0)+#define PCIE_PHY_RSTB BIT(1)+#define PCIE_BRG_RSTB BIT(2)+#define PCIE_PE_RSTB BIT(3)++#define PCIE_LTSSM_STATUS_REG 0x150++#define PCIE_LINK_STATUS_REG 0x154+#define PCIE_PORT_LINKUP BIT(8)++#define PCIE_TRANS_TABLE_BASE_REG 0x800+#define PCIE_ATR_SRC_ADDR_MSB_OFFSET 0x4+#define PCIE_ATR_TRSL_ADDR_LSB_OFFSET 0x8+#define PCIE_ATR_TRSL_ADDR_MSB_OFFSET 0xc+#define PCIE_ATR_TRSL_PARAM_OFFSET 0x10+#define PCIE_ATR_TLB_SET_OFFSET 0x20++#define PCIE_MAX_TRANS_TABLES 8+#define PCIE_ATR_EN BIT(0)+#define PCIE_ATR_SIZE(size) \+(((((size)-1)<<1)&GENMASK(6,1))|PCIE_ATR_EN)+#define PCIE_ATR_ID(id) ((id) & GENMASK(3, 0))+#define PCIE_ATR_TYPE_MEM PCIE_ATR_ID(0)+#define PCIE_ATR_TYPE_IO PCIE_ATR_ID(1)+#define PCIE_ATR_TLP_TYPE(type) (((type) << 16) & GENMASK(18, 16))+#define PCIE_ATR_TLP_TYPE_MEM PCIE_ATR_TLP_TYPE(0)+#define PCIE_ATR_TLP_TYPE_IO PCIE_ATR_TLP_TYPE(2)++/**+*structmtk_pcie_port-PCIeportinformation+*@dev:pointertoPCIedevice+*@base:IOmappedregisterbase+*@reg_base:physicalregisterbase+*@mac_reset:MACresetcontrol+*@phy_reset:PHYresetcontrol+*@phy:PHYcontrollerblock+*@clks:PCIeclocks+*@num_clks:PCIeclockscountforthisport+*/+structmtk_pcie_port{+structdevice*dev;+void__iomem*base;+phys_addr_treg_base;+structreset_control*mac_reset;+structreset_control*phy_reset;+structphy*phy;+structclk_bulk_data*clks;+intnum_clks;+};++/**+*mtk_pcie_config_tlp_header()-ConfigureaconfigurationTLPheader+*@bus:PCIbustoquery+*@devfn:device/functionnumber+*@where:offsetinconfigspace+*@size:datasizeinTLPheader+*+*SetbyteenablefieldanddeviceinformationinconfigurationTLPheader.+*/+staticvoidmtk_pcie_config_tlp_header(structpci_bus*bus,unsignedintdevfn,+intwhere,intsize)+{+structmtk_pcie_port*port=bus->sysdata;+intbytes;+u32val;++bytes=(GENMASK(size-1,0)&0xf)<<(where&0x3);++val=PCIE_CFG_FORCE_BYTE_EN|PCIE_CFG_BYTE_EN(bytes)|+PCIE_CFG_HEADER(bus->number,devfn);++writel_relaxed(val,port->base+PCIE_CFGNUM_REG);+}++staticvoid__iomem*mtk_pcie_map_bus(structpci_bus*bus,unsignedintdevfn,+intwhere)+{+structmtk_pcie_port*port=bus->sysdata;++returnport->base+PCIE_CFG_OFFSET_ADDR+where;+}++staticintmtk_pcie_config_read(structpci_bus*bus,unsignedintdevfn,+intwhere,intsize,u32*val)+{+mtk_pcie_config_tlp_header(bus,devfn,where,size);++returnpci_generic_config_read32(bus,devfn,where,size,val);+}++staticintmtk_pcie_config_write(structpci_bus*bus,unsignedintdevfn,+intwhere,intsize,u32val)+{+mtk_pcie_config_tlp_header(bus,devfn,where,size);++if(size<=2)+val<<=(where&0x3)*8;++returnpci_generic_config_write32(bus,devfn,where,4,val);+}++staticstructpci_opsmtk_pcie_ops={+.map_bus=mtk_pcie_map_bus,+.read=mtk_pcie_config_read,+.write=mtk_pcie_config_write,+};++staticintmtk_pcie_set_trans_table(structmtk_pcie_port*port,+resource_size_tcpu_addr,+resource_size_tpci_addr,+resource_size_tsize,+unsignedlongtype,intnum)+{+void__iomem*table;+u32val;++if(num>=PCIE_MAX_TRANS_TABLES){+dev_err(port->dev,"not enough translate table for addr: %#llx, limited to [%d]\n",+(unsignedlonglong)cpu_addr,PCIE_MAX_TRANS_TABLES);+return-ENODEV;+}++table=port->base+PCIE_TRANS_TABLE_BASE_REG++num*PCIE_ATR_TLB_SET_OFFSET;++writel_relaxed(lower_32_bits(cpu_addr)|PCIE_ATR_SIZE(fls(size)-1),+table);+writel_relaxed(upper_32_bits(cpu_addr),+table+PCIE_ATR_SRC_ADDR_MSB_OFFSET);+writel_relaxed(lower_32_bits(pci_addr),+table+PCIE_ATR_TRSL_ADDR_LSB_OFFSET);+writel_relaxed(upper_32_bits(pci_addr),+table+PCIE_ATR_TRSL_ADDR_MSB_OFFSET);++if(type==IORESOURCE_IO)+val=PCIE_ATR_TYPE_IO|PCIE_ATR_TLP_TYPE_IO;+else+val=PCIE_ATR_TYPE_MEM|PCIE_ATR_TLP_TYPE_MEM;++writel_relaxed(val,table+PCIE_ATR_TRSL_PARAM_OFFSET);++return0;+}++staticintmtk_pcie_startup_port(structmtk_pcie_port*port)+{+structresource_entry*entry;+structpci_host_bridge*host=pci_host_bridge_from_priv(port);+unsignedinttable_index=0;+interr;+u32val;++/* Set as RC mode */+val=readl_relaxed(port->base+PCIE_SETTING_REG);+val|=PCIE_RC_MODE;+writel_relaxed(val,port->base+PCIE_SETTING_REG);++/* Set class code */+val=readl_relaxed(port->base+PCIE_PCI_IDS_1);+val&=~GENMASK(31,8);+val|=PCI_CLASS(PCI_CLASS_BRIDGE_PCI<<8);+writel_relaxed(val,port->base+PCIE_PCI_IDS_1);++/* Assert all reset signals */+val=readl_relaxed(port->base+PCIE_RST_CTRL_REG);+val|=PCIE_MAC_RSTB|PCIE_PHY_RSTB|PCIE_BRG_RSTB|PCIE_PE_RSTB;+writel_relaxed(val,port->base+PCIE_RST_CTRL_REG);++/*+*DescribedinPCIeCEMspecificationsetctions2.2(PERST#Signal)+*and2.2.1(InitialPower-Up(G3toS0)).+*ThedeassertionofPERST#shouldbedelayed100ms(TPVPERL)+*forthepowerandclocktobecomestable.+*/+msleep(100);++/* De-assert reset signals */+val&=~(PCIE_MAC_RSTB|PCIE_PHY_RSTB|PCIE_BRG_RSTB|PCIE_PE_RSTB);+writel_relaxed(val,port->base+PCIE_RST_CTRL_REG);++/* Check if the link is up or not */+err=readl_poll_timeout(port->base+PCIE_LINK_STATUS_REG,val,+!!(val&PCIE_PORT_LINKUP),20,+PCI_PM_D3COLD_WAIT*USEC_PER_MSEC);+if(err){+val=readl_relaxed(port->base+PCIE_LTSSM_STATUS_REG);+dev_err(port->dev,"PCIe link down, ltssm reg val: %#x\n",val);+returnerr;+}++/* Set PCIe translation windows */+resource_list_for_each_entry(entry,&host->windows){+structresource*res=entry->res;+unsignedlongtype=resource_type(res);+resource_size_tcpu_addr;+resource_size_tpci_addr;+resource_size_tsize;+constchar*range_type;++if(type==IORESOURCE_IO){+cpu_addr=pci_pio_to_address(res->start);+range_type="IO";+}elseif(type==IORESOURCE_MEM){+cpu_addr=res->start;+range_type="MEM";+}else{+continue;+}++pci_addr=res->start-entry->offset;+size=resource_size(res);+err=mtk_pcie_set_trans_table(port,cpu_addr,pci_addr,size,+type,table_index);+if(err)+returnerr;++dev_dbg(port->dev,"set %s trans window[%d]: cpu_addr = %#llx, pci_addr = %#llx, size = %#llx\n",+range_type,table_index,(unsignedlonglong)cpu_addr,+(unsignedlonglong)pci_addr,(unsignedlonglong)size);++table_index++;+}++return0;+}++staticintmtk_pcie_parse_port(structmtk_pcie_port*port)+{+structdevice*dev=port->dev;+structplatform_device*pdev=to_platform_device(dev);+structresource*regs;+intret;++regs=platform_get_resource_byname(pdev,IORESOURCE_MEM,"pcie-mac");+port->base=devm_ioremap_resource(dev,regs);+if(IS_ERR(port->base)){+dev_err(dev,"failed to map register base\n");+returnPTR_ERR(port->base);+}++port->reg_base=regs->start;++port->phy_reset=devm_reset_control_get_optional_exclusive(dev,"phy");+if(IS_ERR(port->phy_reset)){+ret=PTR_ERR(port->phy_reset);+if(ret!=-EPROBE_DEFER)+dev_err(dev,"failed to get PHY reset\n");++returnret;+}++port->mac_reset=devm_reset_control_get_optional_exclusive(dev,"mac");+if(IS_ERR(port->mac_reset)){+ret=PTR_ERR(port->mac_reset);+if(ret!=-EPROBE_DEFER)+dev_err(dev,"failed to get MAC reset\n");++returnret;+}++port->phy=devm_phy_optional_get(dev,"pcie-phy");+if(IS_ERR(port->phy)){+ret=PTR_ERR(port->phy);+if(ret!=-EPROBE_DEFER)+dev_err(dev,"failed to get PHY\n");++returnret;+}++port->num_clks=devm_clk_bulk_get_all(dev,&port->clks);+if(port->num_clks<0){+dev_err(dev,"failed to get clocks\n");+returnport->num_clks;+}++return0;+}++staticintmtk_pcie_power_up(structmtk_pcie_port*port)+{+structdevice*dev=port->dev;+interr;++/* PHY power on and enable pipe clock */+reset_control_deassert(port->phy_reset);++err=phy_init(port->phy);+if(err){+dev_err(dev,"failed to initialize PHY\n");+gotoerr_phy_init;+}++err=phy_power_on(port->phy);+if(err){+dev_err(dev,"failed to power on PHY\n");+gotoerr_phy_on;+}++/* MAC power on and enable transaction layer clocks */+reset_control_deassert(port->mac_reset);++pm_runtime_enable(dev);+pm_runtime_get_sync(dev);++err=clk_bulk_prepare_enable(port->num_clks,port->clks);+if(err){+dev_err(dev,"failed to enable clocks\n");+gotoerr_clk_init;+}++return0;++err_clk_init:+pm_runtime_put_sync(dev);+pm_runtime_disable(dev);+reset_control_assert(port->mac_reset);+phy_power_off(port->phy);+err_phy_on:+phy_exit(port->phy);+err_phy_init:+reset_control_assert(port->phy_reset);++returnerr;+}++staticvoidmtk_pcie_power_down(structmtk_pcie_port*port)+{+clk_bulk_disable_unprepare(port->num_clks,port->clks);++pm_runtime_put_sync(port->dev);+pm_runtime_disable(port->dev);+reset_control_assert(port->mac_reset);++phy_power_off(port->phy);+phy_exit(port->phy);+reset_control_assert(port->phy_reset);+}++staticintmtk_pcie_setup(structmtk_pcie_port*port)+{+interr;++err=mtk_pcie_parse_port(port);+if(err)+returnerr;++/* Don't touch the hardware registers before power up */+err=mtk_pcie_power_up(port);+if(err)+returnerr;++/* Try link up */+err=mtk_pcie_startup_port(port);+if(err)+gotoerr_setup;++return0;++err_setup:+mtk_pcie_power_down(port);++returnerr;+}++staticintmtk_pcie_probe(structplatform_device*pdev)+{+structdevice*dev=&pdev->dev;+structmtk_pcie_port*port;+structpci_host_bridge*host;+interr;++host=devm_pci_alloc_host_bridge(dev,sizeof(*port));+if(!host)+return-ENOMEM;++port=pci_host_bridge_priv(host);++port->dev=dev;+platform_set_drvdata(pdev,port);++err=mtk_pcie_setup(port);+if(err)+returnerr;++host->ops=&mtk_pcie_ops;+host->sysdata=port;++err=pci_host_probe(host);+if(err){+mtk_pcie_power_down(port);+returnerr;+}++return0;+}++staticintmtk_pcie_remove(structplatform_device*pdev)+{+structmtk_pcie_port*port=platform_get_drvdata(pdev);+structpci_host_bridge*host=pci_host_bridge_from_priv(port);++pci_lock_rescan_remove();+pci_stop_root_bus(host->bus);+pci_remove_root_bus(host->bus);+pci_unlock_rescan_remove();++mtk_pcie_power_down(port);++return0;+}++staticconststructof_device_idmtk_pcie_of_match[]={+{.compatible="mediatek,mt8192-pcie"},+{},+};++staticstructplatform_drivermtk_pcie_driver={+.probe=mtk_pcie_probe,+.remove=mtk_pcie_remove,+.driver={+.name="mtk-pcie",+.of_match_table=mtk_pcie_of_match,+},+};++module_platform_driver(mtk_pcie_driver);+MODULE_LICENSE("GPL v2");
--
2.25.1
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
@@ -196,6 +234,35 @@ static int mtk_pcie_set_trans_table(struct mtk_pcie_port *port,return0;}+staticvoidmtk_pcie_enable_msi(structmtk_pcie_port*port)+{+inti;+u32val;++for(i=0;i<PCIE_MSI_SET_NUM;i++){+structmtk_msi_set*msi_set=&port->msi_sets[i];++msi_set->base=port->base+PCIE_MSI_SET_BASE_REG++i*PCIE_MSI_SET_OFFSET;+msi_set->msg_addr=port->reg_base+PCIE_MSI_SET_BASE_REG++i*PCIE_MSI_SET_OFFSET;++/* Configure the MSI capture address */+writel_relaxed(lower_32_bits(msi_set->msg_addr),msi_set->base);+writel_relaxed(upper_32_bits(msi_set->msg_addr),+port->base+PCIE_MSI_SET_ADDR_HI_BASE++i*PCIE_MSI_SET_ADDR_HI_OFFSET);+}++val=readl_relaxed(port->base+PCIE_MSI_SET_ENABLE_REG);+val|=PCIE_MSI_SET_ENABLE;+writel_relaxed(val,port->base+PCIE_MSI_SET_ENABLE_REG);++val=readl_relaxed(port->base+PCIE_INT_ENABLE_REG);+val|=PCIE_MSI_ENABLE;+writel_relaxed(val,port->base+PCIE_INT_ENABLE_REG);+}+staticintmtk_pcie_startup_port(structmtk_pcie_port*port){structresource_entry*entry;
@@ -247,6 +314,8 @@ static int mtk_pcie_startup_port(struct mtk_pcie_port *port)returnerr;}+mtk_pcie_enable_msi(port);+/* Set PCIe translation windows */resource_list_for_each_entry(entry,&host->windows){structresource*res=entry->res;
@@ -289,6 +358,147 @@ static int mtk_pcie_set_affinity(struct irq_data *data,return-EINVAL;}+staticvoidmtk_pcie_msi_irq_mask(structirq_data*data)+{+pci_msi_mask_irq(data);+irq_chip_mask_parent(data);+}++staticvoidmtk_pcie_msi_irq_unmask(structirq_data*data)+{+pci_msi_unmask_irq(data);+irq_chip_unmask_parent(data);+}++staticstructirq_chipmtk_msi_irq_chip={+.irq_ack=irq_chip_ack_parent,+.irq_mask=mtk_pcie_msi_irq_mask,+.irq_unmask=mtk_pcie_msi_irq_unmask,+.name="MSI",+};++staticstructmsi_domain_infomtk_msi_domain_info={+.flags=(MSI_FLAG_USE_DEF_DOM_OPS|MSI_FLAG_USE_DEF_CHIP_OPS|+MSI_FLAG_PCI_MSIX|MSI_FLAG_MULTI_PCI_MSI),+.chip=&mtk_msi_irq_chip,+};++staticvoidmtk_compose_msi_msg(structirq_data*data,structmsi_msg*msg)+{+structmtk_msi_set*msi_set=irq_data_get_irq_chip_data(data);+structmtk_pcie_port*port=data->domain->host_data;+unsignedlonghwirq;++hwirq=data->hwirq%PCIE_MSI_IRQS_PER_SET;++msg->address_hi=upper_32_bits(msi_set->msg_addr);+msg->address_lo=lower_32_bits(msi_set->msg_addr);+msg->data=hwirq;+dev_dbg(port->dev,"msi#%#lx address_hi %#x address_lo %#x data %d\n",+hwirq,msg->address_hi,msg->address_lo,msg->data);+}++staticvoidmtk_msi_bottom_irq_ack(structirq_data*data)+{+structmtk_msi_set*msi_set=irq_data_get_irq_chip_data(data);+unsignedlonghwirq;++hwirq=data->hwirq%PCIE_MSI_IRQS_PER_SET;++writel_relaxed(BIT(hwirq),msi_set->base+PCIE_MSI_SET_STATUS_OFFSET);+}++staticvoidmtk_msi_bottom_irq_mask(structirq_data*data)+{+structmtk_msi_set*msi_set=irq_data_get_irq_chip_data(data);+structmtk_pcie_port*port=data->domain->host_data;+unsignedlonghwirq,flags;+u32val;++hwirq=data->hwirq%PCIE_MSI_IRQS_PER_SET;++raw_spin_lock_irqsave(&port->irq_lock,flags);+val=readl_relaxed(msi_set->base+PCIE_MSI_SET_ENABLE_OFFSET);+val&=~BIT(hwirq);+writel_relaxed(val,msi_set->base+PCIE_MSI_SET_ENABLE_OFFSET);+raw_spin_unlock_irqrestore(&port->irq_lock,flags);+}++staticvoidmtk_msi_bottom_irq_unmask(structirq_data*data)+{+structmtk_msi_set*msi_set=irq_data_get_irq_chip_data(data);+structmtk_pcie_port*port=data->domain->host_data;+unsignedlonghwirq,flags;+u32val;++hwirq=data->hwirq%PCIE_MSI_IRQS_PER_SET;++raw_spin_lock_irqsave(&port->irq_lock,flags);+val=readl_relaxed(msi_set->base+PCIE_MSI_SET_ENABLE_OFFSET);+val|=BIT(hwirq);+writel_relaxed(val,msi_set->base+PCIE_MSI_SET_ENABLE_OFFSET);+raw_spin_unlock_irqrestore(&port->irq_lock,flags);+}++staticstructirq_chipmtk_msi_bottom_irq_chip={+.irq_ack=mtk_msi_bottom_irq_ack,+.irq_mask=mtk_msi_bottom_irq_mask,+.irq_unmask=mtk_msi_bottom_irq_unmask,+.irq_compose_msi_msg=mtk_compose_msi_msg,+.irq_set_affinity=mtk_pcie_set_affinity,+.name="MSI",+};++staticintmtk_msi_bottom_domain_alloc(structirq_domain*domain,+unsignedintvirq,unsignedintnr_irqs,+void*arg)+{+structmtk_pcie_port*port=domain->host_data;+structmtk_msi_set*msi_set;+inti,hwirq,set_idx;++mutex_lock(&port->lock);++hwirq=bitmap_find_free_region(port->msi_irq_in_use,PCIE_MSI_IRQS_NUM,+order_base_2(nr_irqs));++mutex_unlock(&port->lock);++if(hwirq<0)+return-ENOSPC;++set_idx=hwirq/PCIE_MSI_IRQS_PER_SET;+msi_set=&port->msi_sets[set_idx];++for(i=0;i<nr_irqs;i++)+irq_domain_set_info(domain,virq+i,hwirq+i,+&mtk_msi_bottom_irq_chip,msi_set,+handle_edge_irq,NULL,NULL);++return0;+}++staticvoidmtk_msi_bottom_domain_free(structirq_domain*domain,+unsignedintvirq,unsignedintnr_irqs)+{+structmtk_pcie_port*port=domain->host_data;+structirq_data*data=irq_domain_get_irq_data(domain,virq);++mutex_lock(&port->lock);++bitmap_release_region(port->msi_irq_in_use,data->hwirq,+order_base_2(nr_irqs));++mutex_unlock(&port->lock);++irq_domain_free_irqs_common(domain,virq,nr_irqs);+}++staticconststructirq_domain_opsmtk_msi_bottom_domain_ops={+.alloc=mtk_msi_bottom_domain_alloc,+.free=mtk_msi_bottom_domain_free,+};+staticvoidmtk_intx_mask(structirq_data*data){structmtk_pcie_port*port=irq_data_get_irq_chip_data(data);
@@ -357,6 +567,7 @@ static int mtk_pcie_init_irq_domains(struct mtk_pcie_port *port){structdevice*dev=port->dev;structdevice_node*intc_node,*node=dev->of_node;+intret;raw_spin_lock_init(&port->irq_lock);
@@ -374,7 +585,34 @@ static int mtk_pcie_init_irq_domains(struct mtk_pcie_port *port)return-ENODEV;}+/* Setup MSI */+mutex_init(&port->lock);++port->msi_bottom_domain=irq_domain_add_linear(node,PCIE_MSI_IRQS_NUM,+&mtk_msi_bottom_domain_ops,port);+if(!port->msi_bottom_domain){+dev_err(dev,"failed to create MSI bottom domain\n");+ret=-ENODEV;+gotoerr_msi_bottom_domain;+}++port->msi_domain=pci_msi_create_irq_domain(dev->fwnode,+&mtk_msi_domain_info,+port->msi_bottom_domain);+if(!port->msi_domain){+dev_err(dev,"failed to create MSI domain\n");+ret=-ENODEV;+gotoerr_msi_domain;+}+return0;++err_msi_domain:+irq_domain_remove(port->msi_bottom_domain);+err_msi_bottom_domain:+irq_domain_remove(port->intx_domain);++returnret;}staticvoidmtk_pcie_irq_teardown(structmtk_pcie_port*port)
From: Jianjun Wang <hidden> Date: 2021-03-24 03:06:45
Add suspend_noirq and resume_noirq callback functions to implement PM
system suspend and resume hooks for the MediaTek Gen3 PCIe controller.
When the system suspends, trigger the PCIe link to enter the L2 state
and pull down the PERST# pin, gating the clocks of the MAC layer, and
then power-off the physical layer to provide power-saving.
When the system resumes, the PCIe link should be re-established and the
related control register values should be restored.
Signed-off-by: Jianjun Wang <redacted>
Acked-by: Ryder Lee <ryder.lee@mediatek.com>
---
drivers/pci/controller/pcie-mediatek-gen3.c | 113 ++++++++++++++++++++
1 file changed, 113 insertions(+)
@@ -894,6 +904,108 @@ static int mtk_pcie_remove(struct platform_device *pdev)return0;}+staticvoid__maybe_unusedmtk_pcie_irq_save(structmtk_pcie_port*port)+{+inti;++raw_spin_lock(&port->irq_lock);++port->saved_irq_state=readl_relaxed(port->base+PCIE_INT_ENABLE_REG);++for(i=0;i<PCIE_MSI_SET_NUM;i++){+structmtk_msi_set*msi_set=&port->msi_sets[i];++msi_set->saved_irq_state=readl_relaxed(msi_set->base++PCIE_MSI_SET_ENABLE_OFFSET);+}++raw_spin_unlock(&port->irq_lock);+}++staticvoid__maybe_unusedmtk_pcie_irq_restore(structmtk_pcie_port*port)+{+inti;++raw_spin_lock(&port->irq_lock);++writel_relaxed(port->saved_irq_state,port->base+PCIE_INT_ENABLE_REG);++for(i=0;i<PCIE_MSI_SET_NUM;i++){+structmtk_msi_set*msi_set=&port->msi_sets[i];++writel_relaxed(msi_set->saved_irq_state,+msi_set->base+PCIE_MSI_SET_ENABLE_OFFSET);+}++raw_spin_unlock(&port->irq_lock);+}++staticint__maybe_unusedmtk_pcie_turn_off_link(structmtk_pcie_port*port)+{+u32val;++val=readl_relaxed(port->base+PCIE_ICMD_PM_REG);+val|=PCIE_TURN_OFF_LINK;+writel_relaxed(val,port->base+PCIE_ICMD_PM_REG);++/* Check the link is L2 */+returnreadl_poll_timeout(port->base+PCIE_LTSSM_STATUS_REG,val,+(PCIE_LTSSM_STATE(val)==+PCIE_LTSSM_STATE_L2_IDLE),20,+50*USEC_PER_MSEC);+}++staticint__maybe_unusedmtk_pcie_suspend_noirq(structdevice*dev)+{+structmtk_pcie_port*port=dev_get_drvdata(dev);+interr;+u32val;++/* Trigger link to L2 state */+err=mtk_pcie_turn_off_link(port);+if(err){+dev_err(port->dev,"cannot enter L2 state\n");+returnerr;+}++/* Pull down the PERST# pin */+val=readl_relaxed(port->base+PCIE_RST_CTRL_REG);+val|=PCIE_PE_RSTB;+writel_relaxed(val,port->base+PCIE_RST_CTRL_REG);++dev_dbg(port->dev,"entered L2 states successfully");++mtk_pcie_irq_save(port);+mtk_pcie_power_down(port);++return0;+}++staticint__maybe_unusedmtk_pcie_resume_noirq(structdevice*dev)+{+structmtk_pcie_port*port=dev_get_drvdata(dev);+interr;++err=mtk_pcie_power_up(port);+if(err)+returnerr;++err=mtk_pcie_startup_port(port);+if(err){+mtk_pcie_power_down(port);+returnerr;+}++mtk_pcie_irq_restore(port);++return0;+}++staticconststructdev_pm_opsmtk_pcie_pm_ops={+SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(mtk_pcie_suspend_noirq,+mtk_pcie_resume_noirq)+};+staticconststructof_device_idmtk_pcie_of_match[]={{.compatible="mediatek,mt8192-pcie"},{},
On Wednesday 24 March 2021 11:05:05 Jianjun Wang wrote:
quoted hunk
This interface will be used by PCI host drivers for PIO translation,
export it to support compiling those drivers as kernel modules.
Signed-off-by: Jianjun Wang <redacted>
---
drivers/pci/pci.c | 1 +
1 file changed, 1 insertion(+)
@@ -4052,6 +4052,7 @@ phys_addr_t pci_pio_to_address(unsigned long pio)returnaddress;}+EXPORT_SYMBOL(pci_pio_to_address);
Hello! I'm not sure if EXPORT_SYMBOL is correct because file has GPL-2.0
header. Should not be in this case used only EXPORT_SYMBOL_GPL? Maybe
other people would know what is correct?
unsigned long __weak pci_address_to_pio(phys_addr_t address)
{
--
2.25.1
From: Marc Zyngier <maz@kernel.org> Date: 2021-03-24 16:18:55
On Wed, 24 Mar 2021 03:05:07 +0000,
Jianjun Wang [off-list ref] wrote:
Add INTx support for MediaTek Gen3 PCIe controller.
Signed-off-by: Jianjun Wang <redacted>
Acked-by: Ryder Lee <ryder.lee@mediatek.com>
Reviewed-by: Marc Zyngier <maz@kernel.org>
M.
--
Without deviation from the norm, progress is not possible.
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
From: Marc Zyngier <maz@kernel.org> Date: 2021-03-24 16:19:28
On Wed, 24 Mar 2021 03:05:08 +0000,
Jianjun Wang [off-list ref] wrote:
Add MSI support for MediaTek Gen3 PCIe controller.
This PCIe controller supports up to 256 MSI vectors, the MSI hardware
block diagram is as follows:
+-----+
| GIC |
+-----+
^
|
port->irq
|
+-+-+-+-+-+-+-+-+
|0|1|2|3|4|5|6|7| (PCIe intc)
+-+-+-+-+-+-+-+-+
^ ^ ^
| | ... |
+-------+ +------+ +-----------+
| | |
+-+-+---+--+--+ +-+-+---+--+--+ +-+-+---+--+--+
|0|1|...|30|31| |0|1|...|30|31| |0|1|...|30|31| (MSI sets)
+-+-+---+--+--+ +-+-+---+--+--+ +-+-+---+--+--+
^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^
| | | | | | | | | | | | (MSI vectors)
| | | | | | | | | | | |
(MSI SET0) (MSI SET1) ... (MSI SET7)
With 256 MSI vectors supported, the MSI vectors are composed of 8 sets,
each set has its own address for MSI message, and supports 32 MSI vectors
to generate interrupt.
Signed-off-by: Jianjun Wang <redacted>
Acked-by: Ryder Lee <ryder.lee@mediatek.com>
Reviewed-by: Marc Zyngier <maz@kernel.org>
M.
--
Without deviation from the norm, progress is not possible.
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
Hello!
Just a question, cannot this while-loop cause block of processing other
interrupts?
I have done tests with different HW (aardvark) but with same while(true)
loop logic. One XHCI PCIe controller was sending MSI interrupts too fast
and interrupt handler with this while(true) logic was in infinite loop.
During one IRQ it was calling infinite many times generic_handle_irq()
as HW was feeding new and new MSI hwirq into status register.
But this is different HW, so it can have different behavior and does not
have to cause above issue.
I have just spotted same code pattern for processing MSI interrupts...
Hello!
Just a question, cannot this while-loop cause block of processing other
interrupts?
This is a level interrupt. You don't have much choice but to handle it
immediately, although an alternative would be to mask it and deal with
it in a thread. And since Linux doesn't deal with interrupt priority,
a screaming interrupt is never a good thing.
I have done tests with different HW (aardvark) but with same while(true)
loop logic. One XHCI PCIe controller was sending MSI interrupts too fast
and interrupt handler with this while(true) logic was in infinite loop.
During one IRQ it was calling infinite many times generic_handle_irq()
as HW was feeding new and new MSI hwirq into status register.
Define "too fast". If something in the system is able to program the
XHCI device in such a way that it causes a screaming interrupt, that's
the place to look for problems, and probably not in the interrupt
handling itself, which does what it is supposed to do.
But this is different HW, so it can have different behavior and does not
have to cause above issue.
I have just spotted same code pattern for processing MSI interrupts...
This is a common pattern that you will find in pretty much any
interrupt handling/demuxing, and is done this way when the cost of
taking the exception is high compared to that of handling it.
Which is pretty much any of the badly designed, level-driving,
DW-inspired, sorry excuse for MSI implementations that are popular on
low-end ARM SoCs.
Thanks,
M.
--
Without deviation from the norm, progress is not possible.
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
Hello!
Just a question, cannot this while-loop cause block of processing other
interrupts?
This is a level interrupt. You don't have much choice but to handle it
immediately, although an alternative would be to mask it and deal with
it in a thread. And since Linux doesn't deal with interrupt priority,
a screaming interrupt is never a good thing.
I see. Something like "interrupt priority" (which does not exist?) would
be needed to handle it.
quoted
I have done tests with different HW (aardvark) but with same while(true)
loop logic. One XHCI PCIe controller was sending MSI interrupts too fast
and interrupt handler with this while(true) logic was in infinite loop.
During one IRQ it was calling infinite many times generic_handle_irq()
as HW was feeding new and new MSI hwirq into status register.
Define "too fast".
Fast - next interrupt comes prior checking if while(true)-loop should stop.
If something in the system is able to program the
XHCI device in such a way that it causes a screaming interrupt, that's
the place to look for problems, and probably not in the interrupt
handling itself, which does what it is supposed to do.
quoted
But this is different HW, so it can have different behavior and does not
have to cause above issue.
I have just spotted same code pattern for processing MSI interrupts...
This is a common pattern that you will find in pretty much any
interrupt handling/demuxing, and is done this way when the cost of
taking the exception is high compared to that of handling it.
And would not help if while(true)-loop is replaced by loop with upper
limit of iterations? Or just call only one iteration?
Which is pretty much any of the badly designed, level-driving,
DW-inspired, sorry excuse for MSI implementations that are popular on
low-end ARM SoCs.
Ok. So thank you for information!
Thanks,
M.
--
Without deviation from the norm, progress is not possible.
Hello!
Just a question, cannot this while-loop cause block of processing other
interrupts?
This is a level interrupt. You don't have much choice but to handle it
immediately, although an alternative would be to mask it and deal with
it in a thread. And since Linux doesn't deal with interrupt priority,
a screaming interrupt is never a good thing.
I see. Something like "interrupt priority" (which does not exist?) would
be needed to handle it.
Interrupt priorities definitely exist, but Linux doesn't use
them. Furthermore, This wouldn't be relevant here as you get a bunch
of MSI multiplexed onto a single one. Where would you apply the
priority?
quoted
quoted
I have done tests with different HW (aardvark) but with same while(true)
loop logic. One XHCI PCIe controller was sending MSI interrupts too fast
and interrupt handler with this while(true) logic was in infinite loop.
During one IRQ it was calling infinite many times generic_handle_irq()
as HW was feeding new and new MSI hwirq into status register.
Define "too fast".
Fast - next interrupt comes prior checking if while(true)-loop should stop.
That's definitely not something you can easily fix at the interrupt
handling level. You need to prevent this from happening. That's
usually the result of a misprogramming or a HW bug.
quoted
If something in the system is able to program the
XHCI device in such a way that it causes a screaming interrupt, that's
the place to look for problems, and probably not in the interrupt
handling itself, which does what it is supposed to do.
quoted
But this is different HW, so it can have different behavior and does not
have to cause above issue.
I have just spotted same code pattern for processing MSI interrupts...
This is a common pattern that you will find in pretty much any
interrupt handling/demuxing, and is done this way when the cost of
taking the exception is high compared to that of handling it.
And would not help if while(true)-loop is replaced by loop with upper
limit of iterations? Or just call only one iteration?
That wouldn't change much: you would still have the interrupt being
pending, and it would fire again at the earliest opportunity.
At best, the root interrupt controller is able to present you with
another interrupt before forcing you to deal with the one you have
ignored again. But you cannot rely on that either.
And to be honest, other interrupts are only a part of the problem you
are describing. With a screaming interrupt, you can't execute
userspace. This is as bad as it gets.
M.
--
Without deviation from the norm, progress is not possible.
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
From: Jianjun Wang <hidden> Date: 2021-04-08 05:45:18
Hi Bjorn, Lorenzo,
Just gentle ping for this patch set, please kindly let me know your
comments about this patch set.
Thanks.
On Wed, 2021-03-24 at 11:05 +0800, Jianjun Wang wrote:
quoted hunk
MediaTek's PCIe host controller has three generation HWs, the new
generation HW is an individual bridge, it supports Gen3 speed and
compatible with Gen2, Gen1 speed.
Add support for new Gen3 controller which can be found on MT8192.
Signed-off-by: Jianjun Wang <redacted>
Acked-by: Ryder Lee <ryder.lee@mediatek.com>
---
drivers/pci/controller/Kconfig | 13 +
drivers/pci/controller/Makefile | 1 +
drivers/pci/controller/pcie-mediatek-gen3.c | 464 ++++++++++++++++++++
3 files changed, 478 insertions(+)
create mode 100644 drivers/pci/controller/pcie-mediatek-gen3.c
@@ -0,0 +1,464 @@+// SPDX-License-Identifier: GPL-2.0+/*+*MediaTekPCIehostcontrollerdriver.+*+*Copyright(c)2020MediaTekInc.+*Author:JianjunWang<jianjun.wang@mediatek.com>+*/++#include<linux/clk.h>+#include<linux/delay.h>+#include<linux/iopoll.h>+#include<linux/kernel.h>+#include<linux/module.h>+#include<linux/pci.h>+#include<linux/phy/phy.h>+#include<linux/platform_device.h>+#include<linux/pm_domain.h>+#include<linux/pm_runtime.h>+#include<linux/reset.h>++#include"../pci.h"++#define PCIE_SETTING_REG 0x80+#define PCIE_PCI_IDS_1 0x9c+#define PCI_CLASS(class) (class << 8)+#define PCIE_RC_MODE BIT(0)++#define PCIE_CFGNUM_REG 0x140+#define PCIE_CFG_DEVFN(devfn) ((devfn) & GENMASK(7, 0))+#define PCIE_CFG_BUS(bus) (((bus) << 8) & GENMASK(15, 8))+#define PCIE_CFG_BYTE_EN(bytes) (((bytes) << 16) & GENMASK(19, 16))+#define PCIE_CFG_FORCE_BYTE_EN BIT(20)+#define PCIE_CFG_OFFSET_ADDR 0x1000+#define PCIE_CFG_HEADER(bus, devfn) \+(PCIE_CFG_BUS(bus)|PCIE_CFG_DEVFN(devfn))++#define PCIE_RST_CTRL_REG 0x148+#define PCIE_MAC_RSTB BIT(0)+#define PCIE_PHY_RSTB BIT(1)+#define PCIE_BRG_RSTB BIT(2)+#define PCIE_PE_RSTB BIT(3)++#define PCIE_LTSSM_STATUS_REG 0x150++#define PCIE_LINK_STATUS_REG 0x154+#define PCIE_PORT_LINKUP BIT(8)++#define PCIE_TRANS_TABLE_BASE_REG 0x800+#define PCIE_ATR_SRC_ADDR_MSB_OFFSET 0x4+#define PCIE_ATR_TRSL_ADDR_LSB_OFFSET 0x8+#define PCIE_ATR_TRSL_ADDR_MSB_OFFSET 0xc+#define PCIE_ATR_TRSL_PARAM_OFFSET 0x10+#define PCIE_ATR_TLB_SET_OFFSET 0x20++#define PCIE_MAX_TRANS_TABLES 8+#define PCIE_ATR_EN BIT(0)+#define PCIE_ATR_SIZE(size) \+(((((size)-1)<<1)&GENMASK(6,1))|PCIE_ATR_EN)+#define PCIE_ATR_ID(id) ((id) & GENMASK(3, 0))+#define PCIE_ATR_TYPE_MEM PCIE_ATR_ID(0)+#define PCIE_ATR_TYPE_IO PCIE_ATR_ID(1)+#define PCIE_ATR_TLP_TYPE(type) (((type) << 16) & GENMASK(18, 16))+#define PCIE_ATR_TLP_TYPE_MEM PCIE_ATR_TLP_TYPE(0)+#define PCIE_ATR_TLP_TYPE_IO PCIE_ATR_TLP_TYPE(2)++/**+*structmtk_pcie_port-PCIeportinformation+*@dev:pointertoPCIedevice+*@base:IOmappedregisterbase+*@reg_base:physicalregisterbase+*@mac_reset:MACresetcontrol+*@phy_reset:PHYresetcontrol+*@phy:PHYcontrollerblock+*@clks:PCIeclocks+*@num_clks:PCIeclockscountforthisport+*/+structmtk_pcie_port{+structdevice*dev;+void__iomem*base;+phys_addr_treg_base;+structreset_control*mac_reset;+structreset_control*phy_reset;+structphy*phy;+structclk_bulk_data*clks;+intnum_clks;+};++/**+*mtk_pcie_config_tlp_header()-ConfigureaconfigurationTLPheader+*@bus:PCIbustoquery+*@devfn:device/functionnumber+*@where:offsetinconfigspace+*@size:datasizeinTLPheader+*+*SetbyteenablefieldanddeviceinformationinconfigurationTLPheader.+*/+staticvoidmtk_pcie_config_tlp_header(structpci_bus*bus,unsignedintdevfn,+intwhere,intsize)+{+structmtk_pcie_port*port=bus->sysdata;+intbytes;+u32val;++bytes=(GENMASK(size-1,0)&0xf)<<(where&0x3);++val=PCIE_CFG_FORCE_BYTE_EN|PCIE_CFG_BYTE_EN(bytes)|+PCIE_CFG_HEADER(bus->number,devfn);++writel_relaxed(val,port->base+PCIE_CFGNUM_REG);+}++staticvoid__iomem*mtk_pcie_map_bus(structpci_bus*bus,unsignedintdevfn,+intwhere)+{+structmtk_pcie_port*port=bus->sysdata;++returnport->base+PCIE_CFG_OFFSET_ADDR+where;+}++staticintmtk_pcie_config_read(structpci_bus*bus,unsignedintdevfn,+intwhere,intsize,u32*val)+{+mtk_pcie_config_tlp_header(bus,devfn,where,size);++returnpci_generic_config_read32(bus,devfn,where,size,val);+}++staticintmtk_pcie_config_write(structpci_bus*bus,unsignedintdevfn,+intwhere,intsize,u32val)+{+mtk_pcie_config_tlp_header(bus,devfn,where,size);++if(size<=2)+val<<=(where&0x3)*8;++returnpci_generic_config_write32(bus,devfn,where,4,val);+}++staticstructpci_opsmtk_pcie_ops={+.map_bus=mtk_pcie_map_bus,+.read=mtk_pcie_config_read,+.write=mtk_pcie_config_write,+};++staticintmtk_pcie_set_trans_table(structmtk_pcie_port*port,+resource_size_tcpu_addr,+resource_size_tpci_addr,+resource_size_tsize,+unsignedlongtype,intnum)+{+void__iomem*table;+u32val;++if(num>=PCIE_MAX_TRANS_TABLES){+dev_err(port->dev,"not enough translate table for addr: %#llx, limited to [%d]\n",+(unsignedlonglong)cpu_addr,PCIE_MAX_TRANS_TABLES);+return-ENODEV;+}++table=port->base+PCIE_TRANS_TABLE_BASE_REG++num*PCIE_ATR_TLB_SET_OFFSET;++writel_relaxed(lower_32_bits(cpu_addr)|PCIE_ATR_SIZE(fls(size)-1),+table);+writel_relaxed(upper_32_bits(cpu_addr),+table+PCIE_ATR_SRC_ADDR_MSB_OFFSET);+writel_relaxed(lower_32_bits(pci_addr),+table+PCIE_ATR_TRSL_ADDR_LSB_OFFSET);+writel_relaxed(upper_32_bits(pci_addr),+table+PCIE_ATR_TRSL_ADDR_MSB_OFFSET);++if(type==IORESOURCE_IO)+val=PCIE_ATR_TYPE_IO|PCIE_ATR_TLP_TYPE_IO;+else+val=PCIE_ATR_TYPE_MEM|PCIE_ATR_TLP_TYPE_MEM;++writel_relaxed(val,table+PCIE_ATR_TRSL_PARAM_OFFSET);++return0;+}++staticintmtk_pcie_startup_port(structmtk_pcie_port*port)+{+structresource_entry*entry;+structpci_host_bridge*host=pci_host_bridge_from_priv(port);+unsignedinttable_index=0;+interr;+u32val;++/* Set as RC mode */+val=readl_relaxed(port->base+PCIE_SETTING_REG);+val|=PCIE_RC_MODE;+writel_relaxed(val,port->base+PCIE_SETTING_REG);++/* Set class code */+val=readl_relaxed(port->base+PCIE_PCI_IDS_1);+val&=~GENMASK(31,8);+val|=PCI_CLASS(PCI_CLASS_BRIDGE_PCI<<8);+writel_relaxed(val,port->base+PCIE_PCI_IDS_1);++/* Assert all reset signals */+val=readl_relaxed(port->base+PCIE_RST_CTRL_REG);+val|=PCIE_MAC_RSTB|PCIE_PHY_RSTB|PCIE_BRG_RSTB|PCIE_PE_RSTB;+writel_relaxed(val,port->base+PCIE_RST_CTRL_REG);++/*+*DescribedinPCIeCEMspecificationsetctions2.2(PERST#Signal)+*and2.2.1(InitialPower-Up(G3toS0)).+*ThedeassertionofPERST#shouldbedelayed100ms(TPVPERL)+*forthepowerandclocktobecomestable.+*/+msleep(100);++/* De-assert reset signals */+val&=~(PCIE_MAC_RSTB|PCIE_PHY_RSTB|PCIE_BRG_RSTB|PCIE_PE_RSTB);+writel_relaxed(val,port->base+PCIE_RST_CTRL_REG);++/* Check if the link is up or not */+err=readl_poll_timeout(port->base+PCIE_LINK_STATUS_REG,val,+!!(val&PCIE_PORT_LINKUP),20,+PCI_PM_D3COLD_WAIT*USEC_PER_MSEC);+if(err){+val=readl_relaxed(port->base+PCIE_LTSSM_STATUS_REG);+dev_err(port->dev,"PCIe link down, ltssm reg val: %#x\n",val);+returnerr;+}++/* Set PCIe translation windows */+resource_list_for_each_entry(entry,&host->windows){+structresource*res=entry->res;+unsignedlongtype=resource_type(res);+resource_size_tcpu_addr;+resource_size_tpci_addr;+resource_size_tsize;+constchar*range_type;++if(type==IORESOURCE_IO){+cpu_addr=pci_pio_to_address(res->start);+range_type="IO";+}elseif(type==IORESOURCE_MEM){+cpu_addr=res->start;+range_type="MEM";+}else{+continue;+}++pci_addr=res->start-entry->offset;+size=resource_size(res);+err=mtk_pcie_set_trans_table(port,cpu_addr,pci_addr,size,+type,table_index);+if(err)+returnerr;++dev_dbg(port->dev,"set %s trans window[%d]: cpu_addr = %#llx, pci_addr = %#llx, size = %#llx\n",+range_type,table_index,(unsignedlonglong)cpu_addr,+(unsignedlonglong)pci_addr,(unsignedlonglong)size);++table_index++;+}++return0;+}++staticintmtk_pcie_parse_port(structmtk_pcie_port*port)+{+structdevice*dev=port->dev;+structplatform_device*pdev=to_platform_device(dev);+structresource*regs;+intret;++regs=platform_get_resource_byname(pdev,IORESOURCE_MEM,"pcie-mac");+port->base=devm_ioremap_resource(dev,regs);+if(IS_ERR(port->base)){+dev_err(dev,"failed to map register base\n");+returnPTR_ERR(port->base);+}++port->reg_base=regs->start;++port->phy_reset=devm_reset_control_get_optional_exclusive(dev,"phy");+if(IS_ERR(port->phy_reset)){+ret=PTR_ERR(port->phy_reset);+if(ret!=-EPROBE_DEFER)+dev_err(dev,"failed to get PHY reset\n");++returnret;+}++port->mac_reset=devm_reset_control_get_optional_exclusive(dev,"mac");+if(IS_ERR(port->mac_reset)){+ret=PTR_ERR(port->mac_reset);+if(ret!=-EPROBE_DEFER)+dev_err(dev,"failed to get MAC reset\n");++returnret;+}++port->phy=devm_phy_optional_get(dev,"pcie-phy");+if(IS_ERR(port->phy)){+ret=PTR_ERR(port->phy);+if(ret!=-EPROBE_DEFER)+dev_err(dev,"failed to get PHY\n");++returnret;+}++port->num_clks=devm_clk_bulk_get_all(dev,&port->clks);+if(port->num_clks<0){+dev_err(dev,"failed to get clocks\n");+returnport->num_clks;+}++return0;+}++staticintmtk_pcie_power_up(structmtk_pcie_port*port)+{+structdevice*dev=port->dev;+interr;++/* PHY power on and enable pipe clock */+reset_control_deassert(port->phy_reset);++err=phy_init(port->phy);+if(err){+dev_err(dev,"failed to initialize PHY\n");+gotoerr_phy_init;+}++err=phy_power_on(port->phy);+if(err){+dev_err(dev,"failed to power on PHY\n");+gotoerr_phy_on;+}++/* MAC power on and enable transaction layer clocks */+reset_control_deassert(port->mac_reset);++pm_runtime_enable(dev);+pm_runtime_get_sync(dev);++err=clk_bulk_prepare_enable(port->num_clks,port->clks);+if(err){+dev_err(dev,"failed to enable clocks\n");+gotoerr_clk_init;+}++return0;++err_clk_init:+pm_runtime_put_sync(dev);+pm_runtime_disable(dev);+reset_control_assert(port->mac_reset);+phy_power_off(port->phy);+err_phy_on:+phy_exit(port->phy);+err_phy_init:+reset_control_assert(port->phy_reset);++returnerr;+}++staticvoidmtk_pcie_power_down(structmtk_pcie_port*port)+{+clk_bulk_disable_unprepare(port->num_clks,port->clks);++pm_runtime_put_sync(port->dev);+pm_runtime_disable(port->dev);+reset_control_assert(port->mac_reset);++phy_power_off(port->phy);+phy_exit(port->phy);+reset_control_assert(port->phy_reset);+}++staticintmtk_pcie_setup(structmtk_pcie_port*port)+{+interr;++err=mtk_pcie_parse_port(port);+if(err)+returnerr;++/* Don't touch the hardware registers before power up */+err=mtk_pcie_power_up(port);+if(err)+returnerr;++/* Try link up */+err=mtk_pcie_startup_port(port);+if(err)+gotoerr_setup;++return0;++err_setup:+mtk_pcie_power_down(port);++returnerr;+}++staticintmtk_pcie_probe(structplatform_device*pdev)+{+structdevice*dev=&pdev->dev;+structmtk_pcie_port*port;+structpci_host_bridge*host;+interr;++host=devm_pci_alloc_host_bridge(dev,sizeof(*port));+if(!host)+return-ENOMEM;++port=pci_host_bridge_priv(host);++port->dev=dev;+platform_set_drvdata(pdev,port);++err=mtk_pcie_setup(port);+if(err)+returnerr;++host->ops=&mtk_pcie_ops;+host->sysdata=port;++err=pci_host_probe(host);+if(err){+mtk_pcie_power_down(port);+returnerr;+}++return0;+}++staticintmtk_pcie_remove(structplatform_device*pdev)+{+structmtk_pcie_port*port=platform_get_drvdata(pdev);+structpci_host_bridge*host=pci_host_bridge_from_priv(port);++pci_lock_rescan_remove();+pci_stop_root_bus(host->bus);+pci_remove_root_bus(host->bus);+pci_unlock_rescan_remove();++mtk_pcie_power_down(port);++return0;+}++staticconststructof_device_idmtk_pcie_of_match[]={+{.compatible="mediatek,mt8192-pcie"},+{},+};++staticstructplatform_drivermtk_pcie_driver={+.probe=mtk_pcie_probe,+.remove=mtk_pcie_remove,+.driver={+.name="mtk-pcie",+.of_match_table=mtk_pcie_of_match,+},+};++module_platform_driver(mtk_pcie_driver);+MODULE_LICENSE("GPL v2");
From: Lorenzo Pieralisi <hidden> Date: 2021-04-13 09:53:32
On Wed, Mar 24, 2021 at 10:09:42AM +0100, Pali Rohár wrote:
On Wednesday 24 March 2021 11:05:05 Jianjun Wang wrote:
quoted
This interface will be used by PCI host drivers for PIO translation,
export it to support compiling those drivers as kernel modules.
Signed-off-by: Jianjun Wang <redacted>
---
drivers/pci/pci.c | 1 +
1 file changed, 1 insertion(+)
@@ -4052,6 +4052,7 @@ phys_addr_t pci_pio_to_address(unsigned long pio)returnaddress;}+EXPORT_SYMBOL(pci_pio_to_address);
Hello! I'm not sure if EXPORT_SYMBOL is correct because file has GPL-2.0
header. Should not be in this case used only EXPORT_SYMBOL_GPL? Maybe
other people would know what is correct?
I think this should be EXPORT_SYMBOL_GPL(), I can make this change
but this requires Bjorn's ACK to go upstream (Bjorn, it is my fault,
it was assigned to me on patchwork, now updated, please have a look).
Thanks,
Lorenzo
quoted
unsigned long __weak pci_address_to_pio(phys_addr_t address)
{
--
2.25.1
On Tue, Apr 13, 2021 at 10:53:05AM +0100, Lorenzo Pieralisi wrote:
On Wed, Mar 24, 2021 at 10:09:42AM +0100, Pali Rohár wrote:
quoted
On Wednesday 24 March 2021 11:05:05 Jianjun Wang wrote:
quoted
This interface will be used by PCI host drivers for PIO translation,
export it to support compiling those drivers as kernel modules.
Signed-off-by: Jianjun Wang <redacted>
---
drivers/pci/pci.c | 1 +
1 file changed, 1 insertion(+)
@@ -4052,6 +4052,7 @@ phys_addr_t pci_pio_to_address(unsigned long pio)returnaddress;}+EXPORT_SYMBOL(pci_pio_to_address);
Hello! I'm not sure if EXPORT_SYMBOL is correct because file has GPL-2.0
header. Should not be in this case used only EXPORT_SYMBOL_GPL? Maybe
other people would know what is correct?
I think this should be EXPORT_SYMBOL_GPL(), I can make this change
but this requires Bjorn's ACK to go upstream (Bjorn, it is my fault,
it was assigned to me on patchwork, now updated, please have a look).
Yep, looks good to me, and I agree it should be EXPORT_SYMBOL_GPL().
Acked-by: Bjorn Helgaas <bhelgaas@google.com>
quoted
quoted
unsigned long __weak pci_address_to_pio(phys_addr_t address)
{
--
2.25.1
Jianjun will update the series accordingly (and please add to v10 the
review tags you received.
Lorenzo
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
Jianjun will update the series accordingly (and please add to v10 the
review tags you received.
Lorenzo
Yes, I will update this series in v10 to fix the subject line format and
use EXPORT_SYMBOL_GPL(), thanks for your comments.
Thanks.
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel