Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
93 changes: 93 additions & 0 deletions Documentation/devicetree/bindings/pci/ultrarisc,dp1000-pcie.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/pci/ultrarisc,dp1000-pcie.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#

title: UltraRISC DP1000 PCIe Host Controller

description:
UltraRISC DP1000 SoC PCIe host controller is based on the DesignWare PCIe IP.

maintainers:
- Xincheng Zhang <zhangxincheng@ultrarisc.com>
- Jia Wang <wangjia@ultrarisc.com>

allOf:
- $ref: /schemas/pci/snps,dw-pcie.yaml#

properties:
compatible:
const: ultrarisc,dp1000-pcie

reg:
items:
- description: Data Bus Interface (DBI) registers.
- description: PCIe configuration space region.

reg-names:
items:
- const: dbi
- const: config

num-lanes:
$ref: /schemas/types.yaml#/definitions/uint32
enum: [4, 16]
description: Number of lanes to use.

interrupts:
items:
- description: MSI interrupt
- description: Legacy INTA interrupt
- description: Legacy INTB interrupt
- description: Legacy INTC interrupt
- description: Legacy INTD interrupt

interrupt-names:
items:
- const: msi
- const: inta
- const: intb
- const: intc
- const: intd

required:
- compatible
- reg
- reg-names
- interrupts
- interrupt-names

unevaluatedProperties: false

examples:
- |
soc {
#address-cells = <2>;
#size-cells = <2>;

pcie@21000000 {
compatible = "ultrarisc,dp1000-pcie";
reg = <0x0 0x21000000 0x0 0x01000000>,
<0x0 0x4fff0000 0x0 0x00010000>;
reg-names = "dbi", "config";
ranges = <0x81000000 0x0 0x4fbf0000 0x0 0x4fbf0000 0x0 0x00400000>,
<0x82000000 0x0 0x40000000 0x0 0x40000000 0x0 0x0fbf0000>,
<0xc3000000 0x40 0x00000000 0x40 0x00000000 0xd 0x00000000>;
#address-cells = <3>;
#size-cells = <2>;
#interrupt-cells = <1>;
device_type = "pci";
dma-coherent;
bus-range = <0x0 0xff>;
num-lanes = <16>;
interrupt-parent = <&plic>;
interrupts = <43>, <44>, <45>, <46>, <47>;
interrupt-names = "msi", "inta", "intb", "intc", "intd";
interrupt-map-mask = <0x0 0x0 0x0 0x7>;
interrupt-map = <0x0 0x0 0x0 0x1 &plic 44>,
<0x0 0x0 0x0 0x2 &plic 45>,
<0x0 0x0 0x0 0x3 &plic 46>,
<0x0 0x0 0x0 0x4 &plic 47>;
};
};
8 changes: 8 additions & 0 deletions MAINTAINERS
Original file line number Diff line number Diff line change
Expand Up @@ -20573,6 +20573,14 @@ S: Maintained
F: Documentation/devicetree/bindings/pci/starfive,jh7110-pcie.yaml
F: drivers/pci/controller/plda/pcie-starfive.c

PCIE DRIVER FOR ULTRARISC DP1000
M: Xincheng Zhang <zhangxincheng@ultrarisc.com>
M: Jia Wang <wangjia@ultrarisc.com>
L: linux-pci@vger.kernel.org
S: Maintained
F: Documentation/devicetree/bindings/pci/ultrarisc,dp1000-pcie.yaml
F: drivers/pci/controller/dwc/pcie-ultrarisc.c

PCIE ENDPOINT DRIVER FOR QUALCOMM
M: Manivannan Sadhasivam <mani@kernel.org>
L: linux-pci@vger.kernel.org
Expand Down
6 changes: 6 additions & 0 deletions arch/riscv/Kconfig.socs
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,12 @@ config ARCH_THEAD
help
This enables support for the RISC-V based T-HEAD SoCs.

config ARCH_ULTRARISC
bool "UltraRISC RISC-V SoCs"
help
This enables support for UltraRISC SoC platform hardware,
including boards based on the UR-DP1000.

config ARCH_VIRT
bool "QEMU Virt Machine"
select POWER_RESET
Expand Down
12 changes: 12 additions & 0 deletions drivers/pci/controller/dwc/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -548,4 +548,16 @@ config PCIE_VISCONTI_HOST
Say Y here if you want PCIe controller support on Toshiba Visconti SoC.
This driver supports TMPV7708 SoC.

config PCIE_ULTRARISC
tristate "UltraRISC PCIe host controller"
depends on ARCH_ULTRARISC || COMPILE_TEST
select PCIE_DW_HOST
select PCI_MSI
default y if ARCH_ULTRARISC
help
Enables support for the PCIe controller in the UltraRISC SoC.
This driver supports UR-DP1000 SoC.
By default, this symbol is enabled when ARCH_ULTRARISC is active,
requiring no further configuration on that platform.

endmenu
1 change: 1 addition & 0 deletions drivers/pci/controller/dwc/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ obj-$(CONFIG_PCIE_RCAR_GEN4) += pcie-rcar-gen4.o
obj-$(CONFIG_PCIE_SPACEMIT_K1) += pcie-spacemit-k1.o
obj-$(CONFIG_PCIE_STM32_HOST) += pcie-stm32.o
obj-$(CONFIG_PCIE_STM32_EP) += pcie-stm32-ep.o
obj-$(CONFIG_PCIE_ULTRARISC) += pcie-ultrarisc.o

# The following drivers are for devices that use the generic ACPI
# pci_root.c driver but don't support standard ECAM config access.
Expand Down
22 changes: 22 additions & 0 deletions drivers/pci/controller/dwc/pcie-designware.h
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,8 @@

/* Synopsys-specific PCIe configuration registers */
#define PCIE_PORT_FORCE 0x708
/* Bit[7:0] LINK_NUM: Link Number. Not used for endpoint */
#define PORT_LINK_NUM_MASK GENMASK(7, 0)
#define PORT_FORCE_DO_DESKEW_FOR_SRIS BIT(23)

#define PCIE_PORT_AFR 0x70C
Expand Down Expand Up @@ -96,6 +98,26 @@
#define PCIE_PORT_LANE_SKEW 0x714
#define PORT_LANE_SKEW_INSERT_MASK GENMASK(23, 0)

/*
* PCIE_TIMER_CTRL_MAX_FUNC_NUM: Timer Control and Max Function Number
* Register.
* This register holds the ack frequency, latency, replay, fast link
* scaling timers, and max function number values.
* Bit[30:29] FAST_LINK_SCALING_FACTOR: Fast Link Timer Scaling Factor.
* 0x0 (SF_1024):Scaling Factor is 1024 (1ms is 1us).
* When the LTSSM is in Config or L12 Entry State, 1ms
* timer is 2us, 2ms timer is 4us and 3ms timer is 6us.
* 0x1 (SF_256): Scaling Factor is 256 (1ms is 4us)
* 0x2 (SF_64): Scaling Factor is 64 (1ms is 16us)
* 0x3 (SF_16): Scaling Factor is 16 (1ms is 64us)
*/
#define PCIE_TIMER_CTRL_MAX_FUNC_NUM 0x718
#define PORT_FLT_SF_MASK GENMASK(30, 29)
#define PORT_FLT_SF_VAL_1024 0x0
#define PORT_FLT_SF_VAL_256 0x1
#define PORT_FLT_SF_VAL_64 0x2
#define PORT_FLT_SF_VAL_16 0x3

#define PCIE_PORT_DEBUG0 0x728
#define PORT_LOGIC_LTSSM_STATE_MASK 0x3f
#define PORT_LOGIC_LTSSM_STATE_L0 0x11
Expand Down
186 changes: 186 additions & 0 deletions drivers/pci/controller/dwc/pcie-ultrarisc.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,186 @@
// SPDX-License-Identifier: GPL-2.0
/*
* DWC PCIe RC driver for UltraRISC DP1000 SoC
*
* Copyright (C) 2026 UltraRISC Technology (Shanghai) Co., Ltd.
*/

#include <linux/clk.h>
#include <linux/delay.h>
#include <linux/interrupt.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/of_device.h>
#include <linux/pci.h>
#include <linux/platform_device.h>
#include <linux/resource.h>
#include <linux/types.h>

#include "pcie-designware.h"

#define PCIE_CUS_CORE 0x400000

#define LTSSM_ENABLE BIT(7)
#define FAST_LINK_MODE BIT(12)
#define HOLD_PHY_RST BIT(14)
#define L1SUB_DISABLE BIT(15)

struct ultrarisc_pcie {
struct dw_pcie *pci;
};

static struct pci_ops ultrarisc_pci_ops = {
.map_bus = dw_pcie_own_conf_map_bus,
.read = pci_generic_config_read32,
.write = pci_generic_config_write32,
};

static int ultrarisc_pcie_host_init(struct dw_pcie_rp *pp)
{
struct pci_host_bridge *bridge = pp->bridge;

bridge->ops = &ultrarisc_pci_ops;

return 0;
}

static void ultrarisc_pcie_pme_turn_off(struct dw_pcie_rp *pp)
{
/*
* DP1000 does not support sending PME_Turn_Off from the RC.
* Keep this callback empty to skip the generic MSG TLP path.
*/
}

static const struct dw_pcie_host_ops ultrarisc_pcie_host_ops = {
.init = ultrarisc_pcie_host_init,
.pme_turn_off = ultrarisc_pcie_pme_turn_off,
};

static int ultrarisc_pcie_start_link(struct dw_pcie *pci)
{
u32 val;
u8 cap_exp;

val = dw_pcie_readl_dbi(pci, PCIE_CUS_CORE);
val &= ~FAST_LINK_MODE;
dw_pcie_writel_dbi(pci, PCIE_CUS_CORE, val);

val = dw_pcie_readl_dbi(pci, PCIE_TIMER_CTRL_MAX_FUNC_NUM);
FIELD_MODIFY(PORT_FLT_SF_MASK, &val, PORT_FLT_SF_VAL_64);
dw_pcie_writel_dbi(pci, PCIE_TIMER_CTRL_MAX_FUNC_NUM, val);

cap_exp = dw_pcie_find_capability(pci, PCI_CAP_ID_EXP);
val = dw_pcie_readl_dbi(pci, cap_exp + PCI_EXP_LNKCTL2);
FIELD_MODIFY(PCI_EXP_LNKCTL2_TLS, &val, PCI_EXP_LNKCTL2_TLS_16_0GT);
dw_pcie_writel_dbi(pci, cap_exp + PCI_EXP_LNKCTL2, val);

val = dw_pcie_readl_dbi(pci, PCIE_PORT_FORCE);
FIELD_MODIFY(PORT_LINK_NUM_MASK, &val, 0);
dw_pcie_writel_dbi(pci, PCIE_PORT_FORCE, val);

val = dw_pcie_readl_dbi(pci, cap_exp + PCI_EXP_DEVCTL2);
FIELD_MODIFY(PCI_EXP_DEVCTL2_COMP_TIMEOUT, &val, 0x6);
dw_pcie_writel_dbi(pci, cap_exp + PCI_EXP_DEVCTL2, val);

val = dw_pcie_readl_dbi(pci, PCIE_CUS_CORE);
val &= ~(HOLD_PHY_RST | L1SUB_DISABLE);
val |= LTSSM_ENABLE;
dw_pcie_writel_dbi(pci, PCIE_CUS_CORE, val);

return 0;
}

static const struct dw_pcie_ops dw_pcie_ops = {
.start_link = ultrarisc_pcie_start_link,
};

static int ultrarisc_pcie_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct ultrarisc_pcie *pcie;
struct dw_pcie *pci;
struct dw_pcie_rp *pp;
int ret;

pcie = devm_kzalloc(dev, sizeof(*pcie), GFP_KERNEL);
if (!pcie)
return -ENOMEM;

pci = devm_kzalloc(dev, sizeof(*pci), GFP_KERNEL);
if (!pci)
return -ENOMEM;

pci->dev = dev;
pci->ops = &dw_pcie_ops;

/* Set a default value suitable for at most 16 in and 16 out windows */
pci->atu_size = SZ_8K;
pci->max_link_speed = 4;
pcie->pci = pci;

pp = &pci->pp;

platform_set_drvdata(pdev, pcie);

pp->irq = platform_get_irq(pdev, 1);
if (pp->irq < 0)
return pp->irq;

pp->num_vectors = MAX_MSI_IRQS;
/* No L2/L3 Ready indication is available on this platform. */
pp->skip_l23_ready = true;
pp->ops = &ultrarisc_pcie_host_ops;

ret = dw_pcie_host_init(pp);
if (ret) {
dev_err(dev, "Failed to initialize host\n");
return ret;
}

return 0;
}

static int ultrarisc_pcie_suspend_noirq(struct device *dev)
{
struct ultrarisc_pcie *pcie = dev_get_drvdata(dev);
struct dw_pcie *pci = pcie->pci;

return dw_pcie_suspend_noirq(pci);
}

static int ultrarisc_pcie_resume_noirq(struct device *dev)
{
struct ultrarisc_pcie *pcie = dev_get_drvdata(dev);
struct dw_pcie *pci = pcie->pci;

return dw_pcie_resume_noirq(pci);
}

static const struct dev_pm_ops ultrarisc_pcie_pm_ops = {
NOIRQ_SYSTEM_SLEEP_PM_OPS(ultrarisc_pcie_suspend_noirq,
ultrarisc_pcie_resume_noirq)
};

static const struct of_device_id ultrarisc_pcie_of_match[] = {
{
.compatible = "ultrarisc,dp1000-pcie",
},
{},
};
MODULE_DEVICE_TABLE(of, ultrarisc_pcie_of_match);

static struct platform_driver ultrarisc_pcie_driver = {
.driver = {
.name = "ultrarisc-pcie",
.of_match_table = ultrarisc_pcie_of_match,
.suppress_bind_attrs = true,
.pm = &ultrarisc_pcie_pm_ops,
},
.probe = ultrarisc_pcie_probe,
};
module_platform_driver(ultrarisc_pcie_driver);

MODULE_DESCRIPTION("UltraRISC DP1000 DWC PCIe host controller");
MODULE_LICENSE("GPL");
Loading