mirror of
				https://gitlab.alpinelinux.org/alpine/aports.git
				synced 2025-10-31 00:12:05 +01:00 
			
		
		
		
	https://www.kernel.org starfive (development kernel) this is moved from https://gitlab.alpinelinux.org/nmeum/alpine-visionfive/-/tree/main/starfive/linux-starfive
		
			
				
	
	
		
			5024 lines
		
	
	
		
			158 KiB
		
	
	
	
		
			Diff
		
	
	
	
	
	
			
		
		
	
	
			5024 lines
		
	
	
		
			158 KiB
		
	
	
	
		
			Diff
		
	
	
	
	
	
| From 28015397cb6568ef62f56b1cc87a95f7bcd01320 Mon Sep 17 00:00:00 2001
 | |
| From: Minda Chen <minda.chen@starfivetech.com>
 | |
| Date: Mon, 8 Jan 2024 19:05:51 +0800
 | |
| Subject: [PATCH 01/23] dt-bindings: PCI: Add PLDA XpressRICH PCIe host common
 | |
|  properties
 | |
| 
 | |
| Add PLDA XpressRICH PCIe host common properties dt-binding doc.
 | |
| PolarFire PCIe host using PLDA IP. Move common properties from Microchip
 | |
| PolarFire PCIe host to PLDA files.
 | |
| 
 | |
| Signed-off-by: Minda Chen <minda.chen@starfivetech.com>
 | |
| Reviewed-by: Hal Feng <hal.feng@starfivetech.com>
 | |
| Reviewed-by: Conor Dooley <conor.dooley@microchip.com>
 | |
| Reviewed-by: Rob Herring <robh@kernel.org>
 | |
| Tested-by: John Clark <inindev@gmail.com>
 | |
| Message-ID: <20240108110612.19048-2-minda.chen@starfivetech.com>
 | |
| Signed-off-by: Aurelien Jarno <aurelien@aurel32.net>
 | |
| ---
 | |
|  .../bindings/pci/microchip,pcie-host.yaml     | 55 +-------------
 | |
|  .../pci/plda,xpressrich3-axi-common.yaml      | 75 +++++++++++++++++++
 | |
|  2 files changed, 76 insertions(+), 54 deletions(-)
 | |
|  create mode 100644 Documentation/devicetree/bindings/pci/plda,xpressrich3-axi-common.yaml
 | |
| 
 | |
| diff --git a/Documentation/devicetree/bindings/pci/microchip,pcie-host.yaml b/Documentation/devicetree/bindings/pci/microchip,pcie-host.yaml
 | |
| index f7a3c2636355..7c2d51221f65 100644
 | |
| --- a/Documentation/devicetree/bindings/pci/microchip,pcie-host.yaml
 | |
| +++ b/Documentation/devicetree/bindings/pci/microchip,pcie-host.yaml
 | |
| @@ -10,21 +10,13 @@ maintainers:
 | |
|    - Daire McNamara <daire.mcnamara@microchip.com>
 | |
|  
 | |
|  allOf:
 | |
| -  - $ref: /schemas/pci/pci-bus.yaml#
 | |
| +  - $ref: plda,xpressrich3-axi-common.yaml#
 | |
|    - $ref: /schemas/interrupt-controller/msi-controller.yaml#
 | |
|  
 | |
|  properties:
 | |
|    compatible:
 | |
|      const: microchip,pcie-host-1.0 # PolarFire
 | |
|  
 | |
| -  reg:
 | |
| -    maxItems: 2
 | |
| -
 | |
| -  reg-names:
 | |
| -    items:
 | |
| -      - const: cfg
 | |
| -      - const: apb
 | |
| -
 | |
|    clocks:
 | |
|      description:
 | |
|        Fabric Interface Controllers, FICs, are the interface between the FPGA
 | |
| @@ -52,18 +44,6 @@ properties:
 | |
|      items:
 | |
|        pattern: '^fic[0-3]$'
 | |
|  
 | |
| -  interrupts:
 | |
| -    minItems: 1
 | |
| -    items:
 | |
| -      - description: PCIe host controller
 | |
| -      - description: builtin MSI controller
 | |
| -
 | |
| -  interrupt-names:
 | |
| -    minItems: 1
 | |
| -    items:
 | |
| -      - const: pcie
 | |
| -      - const: msi
 | |
| -
 | |
|    ranges:
 | |
|      maxItems: 1
 | |
|  
 | |
| @@ -71,39 +51,6 @@ properties:
 | |
|      minItems: 1
 | |
|      maxItems: 6
 | |
|  
 | |
| -  msi-controller:
 | |
| -    description: Identifies the node as an MSI controller.
 | |
| -
 | |
| -  msi-parent:
 | |
| -    description: MSI controller the device is capable of using.
 | |
| -
 | |
| -  interrupt-controller:
 | |
| -    type: object
 | |
| -    properties:
 | |
| -      '#address-cells':
 | |
| -        const: 0
 | |
| -
 | |
| -      '#interrupt-cells':
 | |
| -        const: 1
 | |
| -
 | |
| -      interrupt-controller: true
 | |
| -
 | |
| -    required:
 | |
| -      - '#address-cells'
 | |
| -      - '#interrupt-cells'
 | |
| -      - interrupt-controller
 | |
| -
 | |
| -    additionalProperties: false
 | |
| -
 | |
| -required:
 | |
| -  - reg
 | |
| -  - reg-names
 | |
| -  - "#interrupt-cells"
 | |
| -  - interrupts
 | |
| -  - interrupt-map-mask
 | |
| -  - interrupt-map
 | |
| -  - msi-controller
 | |
| -
 | |
|  unevaluatedProperties: false
 | |
|  
 | |
|  examples:
 | |
| diff --git a/Documentation/devicetree/bindings/pci/plda,xpressrich3-axi-common.yaml b/Documentation/devicetree/bindings/pci/plda,xpressrich3-axi-common.yaml
 | |
| new file mode 100644
 | |
| index 000000000000..31bb17b11e58
 | |
| --- /dev/null
 | |
| +++ b/Documentation/devicetree/bindings/pci/plda,xpressrich3-axi-common.yaml
 | |
| @@ -0,0 +1,75 @@
 | |
| +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
 | |
| +%YAML 1.2
 | |
| +---
 | |
| +$id: http://devicetree.org/schemas/pci/plda,xpressrich3-axi-common.yaml#
 | |
| +$schema: http://devicetree.org/meta-schemas/core.yaml#
 | |
| +
 | |
| +title: PLDA XpressRICH PCIe host common properties
 | |
| +
 | |
| +maintainers:
 | |
| +  - Daire McNamara <daire.mcnamara@microchip.com>
 | |
| +  - Kevin Xie <kevin.xie@starfivetech.com>
 | |
| +
 | |
| +description:
 | |
| +  Generic PLDA XpressRICH PCIe host common properties.
 | |
| +
 | |
| +allOf:
 | |
| +  - $ref: /schemas/pci/pci-bus.yaml#
 | |
| +
 | |
| +properties:
 | |
| +  reg:
 | |
| +    maxItems: 2
 | |
| +
 | |
| +  reg-names:
 | |
| +    items:
 | |
| +      - const: cfg
 | |
| +      - const: apb
 | |
| +
 | |
| +  interrupts:
 | |
| +    minItems: 1
 | |
| +    items:
 | |
| +      - description: PCIe host controller
 | |
| +      - description: builtin MSI controller
 | |
| +
 | |
| +  interrupt-names:
 | |
| +    minItems: 1
 | |
| +    items:
 | |
| +      - const: pcie
 | |
| +      - const: msi
 | |
| +
 | |
| +  msi-controller:
 | |
| +    description: Identifies the node as an MSI controller.
 | |
| +
 | |
| +  msi-parent:
 | |
| +    description: MSI controller the device is capable of using.
 | |
| +
 | |
| +  interrupt-controller:
 | |
| +    type: object
 | |
| +    properties:
 | |
| +      '#address-cells':
 | |
| +        const: 0
 | |
| +
 | |
| +      '#interrupt-cells':
 | |
| +        const: 1
 | |
| +
 | |
| +      interrupt-controller: true
 | |
| +
 | |
| +    required:
 | |
| +      - '#address-cells'
 | |
| +      - '#interrupt-cells'
 | |
| +      - interrupt-controller
 | |
| +
 | |
| +    additionalProperties: false
 | |
| +
 | |
| +required:
 | |
| +  - reg
 | |
| +  - reg-names
 | |
| +  - interrupts
 | |
| +  - msi-controller
 | |
| +  - "#interrupt-cells"
 | |
| +  - interrupt-map-mask
 | |
| +  - interrupt-map
 | |
| +
 | |
| +additionalProperties: true
 | |
| +
 | |
| +...
 | |
| -- 
 | |
| 2.43.0
 | |
| 
 | |
| 
 | |
| From 3e4b15a292dc46205ccca0e73e0397936ce8a8b6 Mon Sep 17 00:00:00 2001
 | |
| From: Minda Chen <minda.chen@starfivetech.com>
 | |
| Date: Mon, 8 Jan 2024 19:05:52 +0800
 | |
| Subject: [PATCH 02/23] PCI: microchip: Move pcie-microchip-host.c to plda
 | |
|  directory
 | |
| 
 | |
| For Microchip Polarfire PCIe host is PLDA XpressRich IP, move to plda
 | |
| directory. Prepare for refactoring the codes.
 | |
| 
 | |
| Signed-off-by: Minda Chen <minda.chen@starfivetech.com>
 | |
| Reviewed-by: Conor Dooley <conor.dooley@microchip.com>
 | |
| Message-ID: <20240108110612.19048-3-minda.chen@starfivetech.com>
 | |
| Signed-off-by: Aurelien Jarno <aurelien@aurel32.net>
 | |
| ---
 | |
|  MAINTAINERS                                        |  4 ++--
 | |
|  drivers/pci/controller/Kconfig                     |  9 +--------
 | |
|  drivers/pci/controller/Makefile                    |  2 +-
 | |
|  drivers/pci/controller/plda/Kconfig                | 14 ++++++++++++++
 | |
|  drivers/pci/controller/plda/Makefile               |  2 ++
 | |
|  .../controller/{ => plda}/pcie-microchip-host.c    |  2 +-
 | |
|  6 files changed, 21 insertions(+), 12 deletions(-)
 | |
|  create mode 100644 drivers/pci/controller/plda/Kconfig
 | |
|  create mode 100644 drivers/pci/controller/plda/Makefile
 | |
|  rename drivers/pci/controller/{ => plda}/pcie-microchip-host.c (99%)
 | |
| 
 | |
| diff --git a/MAINTAINERS b/MAINTAINERS
 | |
| index a7c4cf8201e0..1a2a4d2fab74 100644
 | |
| --- a/MAINTAINERS
 | |
| +++ b/MAINTAINERS
 | |
| @@ -16789,7 +16789,7 @@ M:	Daire McNamara <daire.mcnamara@microchip.com>
 | |
|  L:	linux-pci@vger.kernel.org
 | |
|  S:	Supported
 | |
|  F:	Documentation/devicetree/bindings/pci/microchip*
 | |
| -F:	drivers/pci/controller/*microchip*
 | |
| +F:	drivers/pci/controller/plda/*microchip*
 | |
|  
 | |
|  PCIE DRIVER FOR QUALCOMM MSM
 | |
|  M:	Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
 | |
| @@ -18587,7 +18587,7 @@ F:	drivers/char/hw_random/mpfs-rng.c
 | |
|  F:	drivers/clk/microchip/clk-mpfs*.c
 | |
|  F:	drivers/i2c/busses/i2c-microchip-corei2c.c
 | |
|  F:	drivers/mailbox/mailbox-mpfs.c
 | |
| -F:	drivers/pci/controller/pcie-microchip-host.c
 | |
| +F:	drivers/pci/controller/plda/pcie-microchip-host.c
 | |
|  F:	drivers/pwm/pwm-microchip-core.c
 | |
|  F:	drivers/reset/reset-mpfs.c
 | |
|  F:	drivers/rtc/rtc-mpfs.c
 | |
| diff --git a/drivers/pci/controller/Kconfig b/drivers/pci/controller/Kconfig
 | |
| index e534c02ee34f..4d2c188f5835 100644
 | |
| --- a/drivers/pci/controller/Kconfig
 | |
| +++ b/drivers/pci/controller/Kconfig
 | |
| @@ -215,14 +215,6 @@ config PCIE_MT7621
 | |
|  	help
 | |
|  	  This selects a driver for the MediaTek MT7621 PCIe Controller.
 | |
|  
 | |
| -config PCIE_MICROCHIP_HOST
 | |
| -	tristate "Microchip AXI PCIe controller"
 | |
| -	depends on PCI_MSI && OF
 | |
| -	select PCI_HOST_COMMON
 | |
| -	help
 | |
| -	  Say Y here if you want kernel to support the Microchip AXI PCIe
 | |
| -	  Host Bridge driver.
 | |
| -
 | |
|  config PCI_HYPERV_INTERFACE
 | |
|  	tristate "Microsoft Hyper-V PCI Interface"
 | |
|  	depends on ((X86 && X86_64) || ARM64) && HYPERV && PCI_MSI
 | |
| @@ -356,4 +348,5 @@ config PCIE_XILINX_CPM
 | |
|  source "drivers/pci/controller/cadence/Kconfig"
 | |
|  source "drivers/pci/controller/dwc/Kconfig"
 | |
|  source "drivers/pci/controller/mobiveil/Kconfig"
 | |
| +source "drivers/pci/controller/plda/Kconfig"
 | |
|  endmenu
 | |
| diff --git a/drivers/pci/controller/Makefile b/drivers/pci/controller/Makefile
 | |
| index f2b19e6174af..038ccbd9e3ba 100644
 | |
| --- a/drivers/pci/controller/Makefile
 | |
| +++ b/drivers/pci/controller/Makefile
 | |
| @@ -33,7 +33,6 @@ obj-$(CONFIG_PCIE_ROCKCHIP_EP) += pcie-rockchip-ep.o
 | |
|  obj-$(CONFIG_PCIE_ROCKCHIP_HOST) += pcie-rockchip-host.o
 | |
|  obj-$(CONFIG_PCIE_MEDIATEK) += pcie-mediatek.o
 | |
|  obj-$(CONFIG_PCIE_MEDIATEK_GEN3) += pcie-mediatek-gen3.o
 | |
| -obj-$(CONFIG_PCIE_MICROCHIP_HOST) += pcie-microchip-host.o
 | |
|  obj-$(CONFIG_VMD) += vmd.o
 | |
|  obj-$(CONFIG_PCIE_BRCMSTB) += pcie-brcmstb.o
 | |
|  obj-$(CONFIG_PCI_LOONGSON) += pci-loongson.o
 | |
| @@ -44,6 +43,7 @@ obj-$(CONFIG_PCIE_MT7621) += pcie-mt7621.o
 | |
|  # pcie-hisi.o quirks are needed even without CONFIG_PCIE_DW
 | |
|  obj-y				+= dwc/
 | |
|  obj-y				+= mobiveil/
 | |
| +obj-y				+= plda/
 | |
|  
 | |
|  
 | |
|  # The following drivers are for devices that use the generic ACPI
 | |
| diff --git a/drivers/pci/controller/plda/Kconfig b/drivers/pci/controller/plda/Kconfig
 | |
| new file mode 100644
 | |
| index 000000000000..5cb3be4fc98c
 | |
| --- /dev/null
 | |
| +++ b/drivers/pci/controller/plda/Kconfig
 | |
| @@ -0,0 +1,14 @@
 | |
| +# SPDX-License-Identifier: GPL-2.0
 | |
| +
 | |
| +menu "PLDA-based PCIe controllers"
 | |
| +	depends on PCI
 | |
| +
 | |
| +config PCIE_MICROCHIP_HOST
 | |
| +	tristate "Microchip AXI PCIe controller"
 | |
| +	depends on PCI_MSI && OF
 | |
| +	select PCI_HOST_COMMON
 | |
| +	help
 | |
| +	  Say Y here if you want kernel to support the Microchip AXI PCIe
 | |
| +	  Host Bridge driver.
 | |
| +
 | |
| +endmenu
 | |
| diff --git a/drivers/pci/controller/plda/Makefile b/drivers/pci/controller/plda/Makefile
 | |
| new file mode 100644
 | |
| index 000000000000..e1a265cbf91c
 | |
| --- /dev/null
 | |
| +++ b/drivers/pci/controller/plda/Makefile
 | |
| @@ -0,0 +1,2 @@
 | |
| +# SPDX-License-Identifier: GPL-2.0
 | |
| +obj-$(CONFIG_PCIE_MICROCHIP_HOST) += pcie-microchip-host.o
 | |
| diff --git a/drivers/pci/controller/pcie-microchip-host.c b/drivers/pci/controller/plda/pcie-microchip-host.c
 | |
| similarity index 99%
 | |
| rename from drivers/pci/controller/pcie-microchip-host.c
 | |
| rename to drivers/pci/controller/plda/pcie-microchip-host.c
 | |
| index 137fb8570ba2..cb09a8137e25 100644
 | |
| --- a/drivers/pci/controller/pcie-microchip-host.c
 | |
| +++ b/drivers/pci/controller/plda/pcie-microchip-host.c
 | |
| @@ -18,7 +18,7 @@
 | |
|  #include <linux/pci-ecam.h>
 | |
|  #include <linux/platform_device.h>
 | |
|  
 | |
| -#include "../pci.h"
 | |
| +#include "../../pci.h"
 | |
|  
 | |
|  /* Number of MSI IRQs */
 | |
|  #define MC_MAX_NUM_MSI_IRQS			32
 | |
| -- 
 | |
| 2.43.0
 | |
| 
 | |
| 
 | |
| From df7fb97715c19a67eb4c19bf63752206d2f62a93 Mon Sep 17 00:00:00 2001
 | |
| From: Minda Chen <minda.chen@starfivetech.com>
 | |
| Date: Mon, 8 Jan 2024 19:05:53 +0800
 | |
| Subject: [PATCH 03/23] PCI: microchip: Move PLDA IP register macros to
 | |
|  pcie-plda.h
 | |
| 
 | |
| Move PLDA PCIe host controller IP registers macros to pcie-plda.h,
 | |
| including bridge registers and local IRQ event number.
 | |
| 
 | |
| Signed-off-by: Minda Chen <minda.chen@starfivetech.com>
 | |
| Reviewed-by: Conor Dooley <conor.dooley@microchip.com>
 | |
| Message-ID: <20240108110612.19048-4-minda.chen@starfivetech.com>
 | |
| Signed-off-by: Aurelien Jarno <aurelien@aurel32.net>
 | |
| ---
 | |
|  MAINTAINERS                                   |   8 ++
 | |
|  .../pci/controller/plda/pcie-microchip-host.c | 108 +++---------------
 | |
|  drivers/pci/controller/plda/pcie-plda.h       | 108 ++++++++++++++++++
 | |
|  3 files changed, 132 insertions(+), 92 deletions(-)
 | |
|  create mode 100644 drivers/pci/controller/plda/pcie-plda.h
 | |
| 
 | |
| diff --git a/MAINTAINERS b/MAINTAINERS
 | |
| index 1a2a4d2fab74..730fe2d640a1 100644
 | |
| --- a/MAINTAINERS
 | |
| +++ b/MAINTAINERS
 | |
| @@ -16557,6 +16557,14 @@ S:	Maintained
 | |
|  F:	Documentation/devicetree/bindings/pci/layerscape-pcie-gen4.txt
 | |
|  F:	drivers/pci/controller/mobiveil/pcie-layerscape-gen4.c
 | |
|  
 | |
| +PCI DRIVER FOR PLDA PCIE IP
 | |
| +M:	Daire McNamara <daire.mcnamara@microchip.com>
 | |
| +M:	Kevin Xie <kevin.xie@starfivetech.com>
 | |
| +L:	linux-pci@vger.kernel.org
 | |
| +S:	Maintained
 | |
| +F:	Documentation/devicetree/bindings/pci/plda,*
 | |
| +F:	drivers/pci/controller/plda/*plda*
 | |
| +
 | |
|  PCI DRIVER FOR RENESAS R-CAR
 | |
|  M:	Marek Vasut <marek.vasut+renesas@gmail.com>
 | |
|  M:	Yoshihiro Shimoda <yoshihiro.shimoda.uh@renesas.com>
 | |
| diff --git a/drivers/pci/controller/plda/pcie-microchip-host.c b/drivers/pci/controller/plda/pcie-microchip-host.c
 | |
| index cb09a8137e25..d9030d550482 100644
 | |
| --- a/drivers/pci/controller/plda/pcie-microchip-host.c
 | |
| +++ b/drivers/pci/controller/plda/pcie-microchip-host.c
 | |
| @@ -19,6 +19,7 @@
 | |
|  #include <linux/platform_device.h>
 | |
|  
 | |
|  #include "../../pci.h"
 | |
| +#include "pcie-plda.h"
 | |
|  
 | |
|  /* Number of MSI IRQs */
 | |
|  #define MC_MAX_NUM_MSI_IRQS			32
 | |
| @@ -30,84 +31,6 @@
 | |
|  #define MC_PCIE_BRIDGE_ADDR			(MC_PCIE1_BRIDGE_ADDR)
 | |
|  #define MC_PCIE_CTRL_ADDR			(MC_PCIE1_CTRL_ADDR)
 | |
|  
 | |
| -/* PCIe Bridge Phy Regs */
 | |
| -#define PCIE_PCI_IRQ_DW0			0xa8
 | |
| -#define  MSIX_CAP_MASK				BIT(31)
 | |
| -#define  NUM_MSI_MSGS_MASK			GENMASK(6, 4)
 | |
| -#define  NUM_MSI_MSGS_SHIFT			4
 | |
| -
 | |
| -#define IMASK_LOCAL				0x180
 | |
| -#define  DMA_END_ENGINE_0_MASK			0x00000000u
 | |
| -#define  DMA_END_ENGINE_0_SHIFT			0
 | |
| -#define  DMA_END_ENGINE_1_MASK			0x00000000u
 | |
| -#define  DMA_END_ENGINE_1_SHIFT			1
 | |
| -#define  DMA_ERROR_ENGINE_0_MASK		0x00000100u
 | |
| -#define  DMA_ERROR_ENGINE_0_SHIFT		8
 | |
| -#define  DMA_ERROR_ENGINE_1_MASK		0x00000200u
 | |
| -#define  DMA_ERROR_ENGINE_1_SHIFT		9
 | |
| -#define  A_ATR_EVT_POST_ERR_MASK		0x00010000u
 | |
| -#define  A_ATR_EVT_POST_ERR_SHIFT		16
 | |
| -#define  A_ATR_EVT_FETCH_ERR_MASK		0x00020000u
 | |
| -#define  A_ATR_EVT_FETCH_ERR_SHIFT		17
 | |
| -#define  A_ATR_EVT_DISCARD_ERR_MASK		0x00040000u
 | |
| -#define  A_ATR_EVT_DISCARD_ERR_SHIFT		18
 | |
| -#define  A_ATR_EVT_DOORBELL_MASK		0x00000000u
 | |
| -#define  A_ATR_EVT_DOORBELL_SHIFT		19
 | |
| -#define  P_ATR_EVT_POST_ERR_MASK		0x00100000u
 | |
| -#define  P_ATR_EVT_POST_ERR_SHIFT		20
 | |
| -#define  P_ATR_EVT_FETCH_ERR_MASK		0x00200000u
 | |
| -#define  P_ATR_EVT_FETCH_ERR_SHIFT		21
 | |
| -#define  P_ATR_EVT_DISCARD_ERR_MASK		0x00400000u
 | |
| -#define  P_ATR_EVT_DISCARD_ERR_SHIFT		22
 | |
| -#define  P_ATR_EVT_DOORBELL_MASK		0x00000000u
 | |
| -#define  P_ATR_EVT_DOORBELL_SHIFT		23
 | |
| -#define  PM_MSI_INT_INTA_MASK			0x01000000u
 | |
| -#define  PM_MSI_INT_INTA_SHIFT			24
 | |
| -#define  PM_MSI_INT_INTB_MASK			0x02000000u
 | |
| -#define  PM_MSI_INT_INTB_SHIFT			25
 | |
| -#define  PM_MSI_INT_INTC_MASK			0x04000000u
 | |
| -#define  PM_MSI_INT_INTC_SHIFT			26
 | |
| -#define  PM_MSI_INT_INTD_MASK			0x08000000u
 | |
| -#define  PM_MSI_INT_INTD_SHIFT			27
 | |
| -#define  PM_MSI_INT_INTX_MASK			0x0f000000u
 | |
| -#define  PM_MSI_INT_INTX_SHIFT			24
 | |
| -#define  PM_MSI_INT_MSI_MASK			0x10000000u
 | |
| -#define  PM_MSI_INT_MSI_SHIFT			28
 | |
| -#define  PM_MSI_INT_AER_EVT_MASK		0x20000000u
 | |
| -#define  PM_MSI_INT_AER_EVT_SHIFT		29
 | |
| -#define  PM_MSI_INT_EVENTS_MASK			0x40000000u
 | |
| -#define  PM_MSI_INT_EVENTS_SHIFT		30
 | |
| -#define  PM_MSI_INT_SYS_ERR_MASK		0x80000000u
 | |
| -#define  PM_MSI_INT_SYS_ERR_SHIFT		31
 | |
| -#define  NUM_LOCAL_EVENTS			15
 | |
| -#define ISTATUS_LOCAL				0x184
 | |
| -#define IMASK_HOST				0x188
 | |
| -#define ISTATUS_HOST				0x18c
 | |
| -#define IMSI_ADDR				0x190
 | |
| -#define ISTATUS_MSI				0x194
 | |
| -
 | |
| -/* PCIe Master table init defines */
 | |
| -#define ATR0_PCIE_WIN0_SRCADDR_PARAM		0x600u
 | |
| -#define  ATR0_PCIE_ATR_SIZE			0x25
 | |
| -#define  ATR0_PCIE_ATR_SIZE_SHIFT		1
 | |
| -#define ATR0_PCIE_WIN0_SRC_ADDR			0x604u
 | |
| -#define ATR0_PCIE_WIN0_TRSL_ADDR_LSB		0x608u
 | |
| -#define ATR0_PCIE_WIN0_TRSL_ADDR_UDW		0x60cu
 | |
| -#define ATR0_PCIE_WIN0_TRSL_PARAM		0x610u
 | |
| -
 | |
| -/* PCIe AXI slave table init defines */
 | |
| -#define ATR0_AXI4_SLV0_SRCADDR_PARAM		0x800u
 | |
| -#define  ATR_SIZE_SHIFT				1
 | |
| -#define  ATR_IMPL_ENABLE			1
 | |
| -#define ATR0_AXI4_SLV0_SRC_ADDR			0x804u
 | |
| -#define ATR0_AXI4_SLV0_TRSL_ADDR_LSB		0x808u
 | |
| -#define ATR0_AXI4_SLV0_TRSL_ADDR_UDW		0x80cu
 | |
| -#define ATR0_AXI4_SLV0_TRSL_PARAM		0x810u
 | |
| -#define  PCIE_TX_RX_INTERFACE			0x00000000u
 | |
| -#define  PCIE_CONFIG_INTERFACE			0x00000001u
 | |
| -
 | |
| -#define ATR_ENTRY_SIZE				32
 | |
| -
 | |
|  /* PCIe Controller Phy Regs */
 | |
|  #define SEC_ERROR_EVENT_CNT			0x20
 | |
|  #define DED_ERROR_EVENT_CNT			0x24
 | |
| @@ -179,20 +102,21 @@
 | |
|  #define EVENT_LOCAL_DMA_END_ENGINE_1		12
 | |
|  #define EVENT_LOCAL_DMA_ERROR_ENGINE_0		13
 | |
|  #define EVENT_LOCAL_DMA_ERROR_ENGINE_1		14
 | |
| -#define EVENT_LOCAL_A_ATR_EVT_POST_ERR		15
 | |
| -#define EVENT_LOCAL_A_ATR_EVT_FETCH_ERR		16
 | |
| -#define EVENT_LOCAL_A_ATR_EVT_DISCARD_ERR	17
 | |
| -#define EVENT_LOCAL_A_ATR_EVT_DOORBELL		18
 | |
| -#define EVENT_LOCAL_P_ATR_EVT_POST_ERR		19
 | |
| -#define EVENT_LOCAL_P_ATR_EVT_FETCH_ERR		20
 | |
| -#define EVENT_LOCAL_P_ATR_EVT_DISCARD_ERR	21
 | |
| -#define EVENT_LOCAL_P_ATR_EVT_DOORBELL		22
 | |
| -#define EVENT_LOCAL_PM_MSI_INT_INTX		23
 | |
| -#define EVENT_LOCAL_PM_MSI_INT_MSI		24
 | |
| -#define EVENT_LOCAL_PM_MSI_INT_AER_EVT		25
 | |
| -#define EVENT_LOCAL_PM_MSI_INT_EVENTS		26
 | |
| -#define EVENT_LOCAL_PM_MSI_INT_SYS_ERR		27
 | |
| -#define NUM_EVENTS				28
 | |
| +#define NUM_MC_EVENTS				15
 | |
| +#define EVENT_LOCAL_A_ATR_EVT_POST_ERR		(NUM_MC_EVENTS + PLDA_AXI_POST_ERR)
 | |
| +#define EVENT_LOCAL_A_ATR_EVT_FETCH_ERR		(NUM_MC_EVENTS + PLDA_AXI_FETCH_ERR)
 | |
| +#define EVENT_LOCAL_A_ATR_EVT_DISCARD_ERR	(NUM_MC_EVENTS + PLDA_AXI_DISCARD_ERR)
 | |
| +#define EVENT_LOCAL_A_ATR_EVT_DOORBELL		(NUM_MC_EVENTS + PLDA_AXI_DOORBELL)
 | |
| +#define EVENT_LOCAL_P_ATR_EVT_POST_ERR		(NUM_MC_EVENTS + PLDA_PCIE_POST_ERR)
 | |
| +#define EVENT_LOCAL_P_ATR_EVT_FETCH_ERR		(NUM_MC_EVENTS + PLDA_PCIE_FETCH_ERR)
 | |
| +#define EVENT_LOCAL_P_ATR_EVT_DISCARD_ERR	(NUM_MC_EVENTS + PLDA_PCIE_DISCARD_ERR)
 | |
| +#define EVENT_LOCAL_P_ATR_EVT_DOORBELL		(NUM_MC_EVENTS + PLDA_PCIE_DOORBELL)
 | |
| +#define EVENT_LOCAL_PM_MSI_INT_INTX		(NUM_MC_EVENTS + PLDA_INTX)
 | |
| +#define EVENT_LOCAL_PM_MSI_INT_MSI		(NUM_MC_EVENTS + PLDA_MSI)
 | |
| +#define EVENT_LOCAL_PM_MSI_INT_AER_EVT		(NUM_MC_EVENTS + PLDA_AER_EVENT)
 | |
| +#define EVENT_LOCAL_PM_MSI_INT_EVENTS		(NUM_MC_EVENTS + PLDA_MISC_EVENTS)
 | |
| +#define EVENT_LOCAL_PM_MSI_INT_SYS_ERR		(NUM_MC_EVENTS + PLDA_SYS_ERR)
 | |
| +#define NUM_EVENTS				(NUM_MC_EVENTS + PLDA_INT_EVENT_NUM)
 | |
|  
 | |
|  #define PCIE_EVENT_CAUSE(x, s)	\
 | |
|  	[EVENT_PCIE_ ## x] = { __stringify(x), s }
 | |
| diff --git a/drivers/pci/controller/plda/pcie-plda.h b/drivers/pci/controller/plda/pcie-plda.h
 | |
| new file mode 100644
 | |
| index 000000000000..cad3a98d967e
 | |
| --- /dev/null
 | |
| +++ b/drivers/pci/controller/plda/pcie-plda.h
 | |
| @@ -0,0 +1,108 @@
 | |
| +/* SPDX-License-Identifier: GPL-2.0 */
 | |
| +/*
 | |
| + * PLDA PCIe host controller driver
 | |
| + */
 | |
| +
 | |
| +#ifndef _PCIE_PLDA_H
 | |
| +#define _PCIE_PLDA_H
 | |
| +
 | |
| +/* PCIe Bridge Phy Regs */
 | |
| +#define PCIE_PCI_IRQ_DW0			0xa8
 | |
| +#define  MSIX_CAP_MASK				BIT(31)
 | |
| +#define  NUM_MSI_MSGS_MASK			GENMASK(6, 4)
 | |
| +#define  NUM_MSI_MSGS_SHIFT			4
 | |
| +
 | |
| +#define IMASK_LOCAL				0x180
 | |
| +#define  DMA_END_ENGINE_0_MASK			0x00000000u
 | |
| +#define  DMA_END_ENGINE_0_SHIFT			0
 | |
| +#define  DMA_END_ENGINE_1_MASK			0x00000000u
 | |
| +#define  DMA_END_ENGINE_1_SHIFT			1
 | |
| +#define  DMA_ERROR_ENGINE_0_MASK		0x00000100u
 | |
| +#define  DMA_ERROR_ENGINE_0_SHIFT		8
 | |
| +#define  DMA_ERROR_ENGINE_1_MASK		0x00000200u
 | |
| +#define  DMA_ERROR_ENGINE_1_SHIFT		9
 | |
| +#define  A_ATR_EVT_POST_ERR_MASK		0x00010000u
 | |
| +#define  A_ATR_EVT_POST_ERR_SHIFT		16
 | |
| +#define  A_ATR_EVT_FETCH_ERR_MASK		0x00020000u
 | |
| +#define  A_ATR_EVT_FETCH_ERR_SHIFT		17
 | |
| +#define  A_ATR_EVT_DISCARD_ERR_MASK		0x00040000u
 | |
| +#define  A_ATR_EVT_DISCARD_ERR_SHIFT		18
 | |
| +#define  A_ATR_EVT_DOORBELL_MASK		0x00000000u
 | |
| +#define  A_ATR_EVT_DOORBELL_SHIFT		19
 | |
| +#define  P_ATR_EVT_POST_ERR_MASK		0x00100000u
 | |
| +#define  P_ATR_EVT_POST_ERR_SHIFT		20
 | |
| +#define  P_ATR_EVT_FETCH_ERR_MASK		0x00200000u
 | |
| +#define  P_ATR_EVT_FETCH_ERR_SHIFT		21
 | |
| +#define  P_ATR_EVT_DISCARD_ERR_MASK		0x00400000u
 | |
| +#define  P_ATR_EVT_DISCARD_ERR_SHIFT		22
 | |
| +#define  P_ATR_EVT_DOORBELL_MASK		0x00000000u
 | |
| +#define  P_ATR_EVT_DOORBELL_SHIFT		23
 | |
| +#define  PM_MSI_INT_INTA_MASK			0x01000000u
 | |
| +#define  PM_MSI_INT_INTA_SHIFT			24
 | |
| +#define  PM_MSI_INT_INTB_MASK			0x02000000u
 | |
| +#define  PM_MSI_INT_INTB_SHIFT			25
 | |
| +#define  PM_MSI_INT_INTC_MASK			0x04000000u
 | |
| +#define  PM_MSI_INT_INTC_SHIFT			26
 | |
| +#define  PM_MSI_INT_INTD_MASK			0x08000000u
 | |
| +#define  PM_MSI_INT_INTD_SHIFT			27
 | |
| +#define  PM_MSI_INT_INTX_MASK			0x0f000000u
 | |
| +#define  PM_MSI_INT_INTX_SHIFT			24
 | |
| +#define  PM_MSI_INT_MSI_MASK			0x10000000u
 | |
| +#define  PM_MSI_INT_MSI_SHIFT			28
 | |
| +#define  PM_MSI_INT_AER_EVT_MASK		0x20000000u
 | |
| +#define  PM_MSI_INT_AER_EVT_SHIFT		29
 | |
| +#define  PM_MSI_INT_EVENTS_MASK			0x40000000u
 | |
| +#define  PM_MSI_INT_EVENTS_SHIFT		30
 | |
| +#define  PM_MSI_INT_SYS_ERR_MASK		0x80000000u
 | |
| +#define  PM_MSI_INT_SYS_ERR_SHIFT		31
 | |
| +#define  NUM_LOCAL_EVENTS			15
 | |
| +#define ISTATUS_LOCAL				0x184
 | |
| +#define IMASK_HOST				0x188
 | |
| +#define ISTATUS_HOST				0x18c
 | |
| +#define IMSI_ADDR				0x190
 | |
| +#define ISTATUS_MSI				0x194
 | |
| +
 | |
| +/* PCIe Master table init defines */
 | |
| +#define ATR0_PCIE_WIN0_SRCADDR_PARAM		0x600u
 | |
| +#define  ATR0_PCIE_ATR_SIZE			0x25
 | |
| +#define  ATR0_PCIE_ATR_SIZE_SHIFT		1
 | |
| +#define ATR0_PCIE_WIN0_SRC_ADDR			0x604u
 | |
| +#define ATR0_PCIE_WIN0_TRSL_ADDR_LSB		0x608u
 | |
| +#define ATR0_PCIE_WIN0_TRSL_ADDR_UDW		0x60cu
 | |
| +#define ATR0_PCIE_WIN0_TRSL_PARAM		0x610u
 | |
| +
 | |
| +/* PCIe AXI slave table init defines */
 | |
| +#define ATR0_AXI4_SLV0_SRCADDR_PARAM		0x800u
 | |
| +#define  ATR_SIZE_SHIFT				1
 | |
| +#define  ATR_IMPL_ENABLE			1
 | |
| +#define ATR0_AXI4_SLV0_SRC_ADDR			0x804u
 | |
| +#define ATR0_AXI4_SLV0_TRSL_ADDR_LSB		0x808u
 | |
| +#define ATR0_AXI4_SLV0_TRSL_ADDR_UDW		0x80cu
 | |
| +#define ATR0_AXI4_SLV0_TRSL_PARAM		0x810u
 | |
| +#define  PCIE_TX_RX_INTERFACE			0x00000000u
 | |
| +#define  PCIE_CONFIG_INTERFACE			0x00000001u
 | |
| +
 | |
| +#define ATR_ENTRY_SIZE				32
 | |
| +
 | |
| +enum plda_int_event {
 | |
| +	PLDA_AXI_POST_ERR,
 | |
| +	PLDA_AXI_FETCH_ERR,
 | |
| +	PLDA_AXI_DISCARD_ERR,
 | |
| +	PLDA_AXI_DOORBELL,
 | |
| +	PLDA_PCIE_POST_ERR,
 | |
| +	PLDA_PCIE_FETCH_ERR,
 | |
| +	PLDA_PCIE_DISCARD_ERR,
 | |
| +	PLDA_PCIE_DOORBELL,
 | |
| +	PLDA_INTX,
 | |
| +	PLDA_MSI,
 | |
| +	PLDA_AER_EVENT,
 | |
| +	PLDA_MISC_EVENTS,
 | |
| +	PLDA_SYS_ERR,
 | |
| +	PLDA_INT_EVENT_NUM
 | |
| +};
 | |
| +
 | |
| +#define PLDA_NUM_DMA_EVENTS			16
 | |
| +
 | |
| +#define PLDA_MAX_INT_NUM			(PLDA_NUM_DMA_EVENTS + PLDA_INT_EVENT_NUM)
 | |
| +
 | |
| +#endif
 | |
| -- 
 | |
| 2.43.0
 | |
| 
 | |
| 
 | |
| From f569d322f9b4683c5f427247c374ac39889643e6 Mon Sep 17 00:00:00 2001
 | |
| From: Minda Chen <minda.chen@starfivetech.com>
 | |
| Date: Mon, 8 Jan 2024 19:05:54 +0800
 | |
| Subject: [PATCH 04/23] PCI: microchip: Add bridge_addr field to struct mc_pcie
 | |
| 
 | |
| For bridge address base is common PLDA field, Add this to struct mc_pcie
 | |
| first.
 | |
| 
 | |
| INTx and MSI codes interrupts codes will get the bridge base address from
 | |
| port->bridge_addr. These codes will be changed to common codes.
 | |
| axi_base_addr is Microchip its own data.
 | |
| 
 | |
| Signed-off-by: Minda Chen <minda.chen@starfivetech.com>
 | |
| Reviewed-by: Conor Dooley <conor.dooley@microchip.com>
 | |
| Message-ID: <20240108110612.19048-5-minda.chen@starfivetech.com>
 | |
| Signed-off-by: Aurelien Jarno <aurelien@aurel32.net>
 | |
| ---
 | |
|  .../pci/controller/plda/pcie-microchip-host.c | 23 ++++++++-----------
 | |
|  1 file changed, 9 insertions(+), 14 deletions(-)
 | |
| 
 | |
| diff --git a/drivers/pci/controller/plda/pcie-microchip-host.c b/drivers/pci/controller/plda/pcie-microchip-host.c
 | |
| index d9030d550482..c55ede80a6d0 100644
 | |
| --- a/drivers/pci/controller/plda/pcie-microchip-host.c
 | |
| +++ b/drivers/pci/controller/plda/pcie-microchip-host.c
 | |
| @@ -195,6 +195,7 @@ struct mc_pcie {
 | |
|  	struct irq_domain *event_domain;
 | |
|  	raw_spinlock_t lock;
 | |
|  	struct mc_msi msi;
 | |
| +	void __iomem *bridge_addr;
 | |
|  };
 | |
|  
 | |
|  struct cause {
 | |
| @@ -339,8 +340,7 @@ static void mc_handle_msi(struct irq_desc *desc)
 | |
|  	struct irq_chip *chip = irq_desc_get_chip(desc);
 | |
|  	struct device *dev = port->dev;
 | |
|  	struct mc_msi *msi = &port->msi;
 | |
| -	void __iomem *bridge_base_addr =
 | |
| -		port->axi_base_addr + MC_PCIE_BRIDGE_ADDR;
 | |
| +	void __iomem *bridge_base_addr = port->bridge_addr;
 | |
|  	unsigned long status;
 | |
|  	u32 bit;
 | |
|  	int ret;
 | |
| @@ -365,8 +365,7 @@ static void mc_handle_msi(struct irq_desc *desc)
 | |
|  static void mc_msi_bottom_irq_ack(struct irq_data *data)
 | |
|  {
 | |
|  	struct mc_pcie *port = irq_data_get_irq_chip_data(data);
 | |
| -	void __iomem *bridge_base_addr =
 | |
| -		port->axi_base_addr + MC_PCIE_BRIDGE_ADDR;
 | |
| +	void __iomem *bridge_base_addr = port->bridge_addr;
 | |
|  	u32 bitpos = data->hwirq;
 | |
|  
 | |
|  	writel_relaxed(BIT(bitpos), bridge_base_addr + ISTATUS_MSI);
 | |
| @@ -488,8 +487,7 @@ static void mc_handle_intx(struct irq_desc *desc)
 | |
|  	struct mc_pcie *port = irq_desc_get_handler_data(desc);
 | |
|  	struct irq_chip *chip = irq_desc_get_chip(desc);
 | |
|  	struct device *dev = port->dev;
 | |
| -	void __iomem *bridge_base_addr =
 | |
| -		port->axi_base_addr + MC_PCIE_BRIDGE_ADDR;
 | |
| +	void __iomem *bridge_base_addr = port->bridge_addr;
 | |
|  	unsigned long status;
 | |
|  	u32 bit;
 | |
|  	int ret;
 | |
| @@ -514,8 +512,7 @@ static void mc_handle_intx(struct irq_desc *desc)
 | |
|  static void mc_ack_intx_irq(struct irq_data *data)
 | |
|  {
 | |
|  	struct mc_pcie *port = irq_data_get_irq_chip_data(data);
 | |
| -	void __iomem *bridge_base_addr =
 | |
| -		port->axi_base_addr + MC_PCIE_BRIDGE_ADDR;
 | |
| +	void __iomem *bridge_base_addr = port->bridge_addr;
 | |
|  	u32 mask = BIT(data->hwirq + PM_MSI_INT_INTX_SHIFT);
 | |
|  
 | |
|  	writel_relaxed(mask, bridge_base_addr + ISTATUS_LOCAL);
 | |
| @@ -524,8 +521,7 @@ static void mc_ack_intx_irq(struct irq_data *data)
 | |
|  static void mc_mask_intx_irq(struct irq_data *data)
 | |
|  {
 | |
|  	struct mc_pcie *port = irq_data_get_irq_chip_data(data);
 | |
| -	void __iomem *bridge_base_addr =
 | |
| -		port->axi_base_addr + MC_PCIE_BRIDGE_ADDR;
 | |
| +	void __iomem *bridge_base_addr = port->bridge_addr;
 | |
|  	unsigned long flags;
 | |
|  	u32 mask = BIT(data->hwirq + PM_MSI_INT_INTX_SHIFT);
 | |
|  	u32 val;
 | |
| @@ -540,8 +536,7 @@ static void mc_mask_intx_irq(struct irq_data *data)
 | |
|  static void mc_unmask_intx_irq(struct irq_data *data)
 | |
|  {
 | |
|  	struct mc_pcie *port = irq_data_get_irq_chip_data(data);
 | |
| -	void __iomem *bridge_base_addr =
 | |
| -		port->axi_base_addr + MC_PCIE_BRIDGE_ADDR;
 | |
| +	void __iomem *bridge_base_addr = port->bridge_addr;
 | |
|  	unsigned long flags;
 | |
|  	u32 mask = BIT(data->hwirq + PM_MSI_INT_INTX_SHIFT);
 | |
|  	u32 val;
 | |
| @@ -896,8 +891,7 @@ static void mc_pcie_setup_window(void __iomem *bridge_base_addr, u32 index,
 | |
|  static int mc_pcie_setup_windows(struct platform_device *pdev,
 | |
|  				 struct mc_pcie *port)
 | |
|  {
 | |
| -	void __iomem *bridge_base_addr =
 | |
| -		port->axi_base_addr + MC_PCIE_BRIDGE_ADDR;
 | |
| +	void __iomem *bridge_base_addr = port->bridge_addr;
 | |
|  	struct pci_host_bridge *bridge = platform_get_drvdata(pdev);
 | |
|  	struct resource_entry *entry;
 | |
|  	u64 pci_addr;
 | |
| @@ -1081,6 +1075,7 @@ static int mc_host_probe(struct platform_device *pdev)
 | |
|  	mc_disable_interrupts(port);
 | |
|  
 | |
|  	bridge_base_addr = port->axi_base_addr + MC_PCIE_BRIDGE_ADDR;
 | |
| +	port->bridge_addr = bridge_base_addr;
 | |
|  
 | |
|  	/* Allow enabling MSI by disabling MSI-X */
 | |
|  	val = readl(bridge_base_addr + PCIE_PCI_IRQ_DW0);
 | |
| -- 
 | |
| 2.43.0
 | |
| 
 | |
| 
 | |
| From a863afc3ea3339f8fa682b4db2dee8f48ff84cb6 Mon Sep 17 00:00:00 2001
 | |
| From: Minda Chen <minda.chen@starfivetech.com>
 | |
| Date: Mon, 8 Jan 2024 19:05:55 +0800
 | |
| Subject: [PATCH 05/23] PCI: microchip: Rename two PCIe data structures
 | |
| 
 | |
| Add PLDA PCIe related data structures by rename data structure name from
 | |
| mc_* to plda_*.
 | |
| 
 | |
| axi_base_addr is stayed in struct mc_pcie for it's microchip its own data.
 | |
| 
 | |
| The event interrupt codes is still using struct mc_pcie because the event
 | |
| interrupt codes can not be re-used.
 | |
| 
 | |
| Signed-off-by: Minda Chen <minda.chen@starfivetech.com>
 | |
| Reviewed-by: Conor Dooley <conor.dooley@microchip.com>
 | |
| Message-ID: <20240108110612.19048-6-minda.chen@starfivetech.com>
 | |
| Signed-off-by: Aurelien Jarno <aurelien@aurel32.net>
 | |
| ---
 | |
|  .../pci/controller/plda/pcie-microchip-host.c | 96 ++++++++++---------
 | |
|  1 file changed, 53 insertions(+), 43 deletions(-)
 | |
| 
 | |
| diff --git a/drivers/pci/controller/plda/pcie-microchip-host.c b/drivers/pci/controller/plda/pcie-microchip-host.c
 | |
| index c55ede80a6d0..df0736f688ce 100644
 | |
| --- a/drivers/pci/controller/plda/pcie-microchip-host.c
 | |
| +++ b/drivers/pci/controller/plda/pcie-microchip-host.c
 | |
| @@ -22,7 +22,7 @@
 | |
|  #include "pcie-plda.h"
 | |
|  
 | |
|  /* Number of MSI IRQs */
 | |
| -#define MC_MAX_NUM_MSI_IRQS			32
 | |
| +#define PLDA_MAX_NUM_MSI_IRQS			32
 | |
|  
 | |
|  /* PCIe Bridge Phy and Controller Phy offsets */
 | |
|  #define MC_PCIE1_BRIDGE_ADDR			0x00008000u
 | |
| @@ -179,25 +179,29 @@ struct event_map {
 | |
|  	u32 event_bit;
 | |
|  };
 | |
|  
 | |
| -struct mc_msi {
 | |
| +struct plda_msi {
 | |
|  	struct mutex lock;		/* Protect used bitmap */
 | |
|  	struct irq_domain *msi_domain;
 | |
|  	struct irq_domain *dev_domain;
 | |
|  	u32 num_vectors;
 | |
|  	u64 vector_phy;
 | |
| -	DECLARE_BITMAP(used, MC_MAX_NUM_MSI_IRQS);
 | |
| +	DECLARE_BITMAP(used, PLDA_MAX_NUM_MSI_IRQS);
 | |
|  };
 | |
|  
 | |
| -struct mc_pcie {
 | |
| -	void __iomem *axi_base_addr;
 | |
| +struct plda_pcie_rp {
 | |
|  	struct device *dev;
 | |
|  	struct irq_domain *intx_domain;
 | |
|  	struct irq_domain *event_domain;
 | |
|  	raw_spinlock_t lock;
 | |
| -	struct mc_msi msi;
 | |
| +	struct plda_msi msi;
 | |
|  	void __iomem *bridge_addr;
 | |
|  };
 | |
|  
 | |
| +struct mc_pcie {
 | |
| +	struct plda_pcie_rp plda;
 | |
| +	void __iomem *axi_base_addr;
 | |
| +};
 | |
| +
 | |
|  struct cause {
 | |
|  	const char *sym;
 | |
|  	const char *str;
 | |
| @@ -313,7 +317,7 @@ static struct mc_pcie *port;
 | |
|  
 | |
|  static void mc_pcie_enable_msi(struct mc_pcie *port, void __iomem *ecam)
 | |
|  {
 | |
| -	struct mc_msi *msi = &port->msi;
 | |
| +	struct plda_msi *msi = &port->plda.msi;
 | |
|  	u16 reg;
 | |
|  	u8 queue_size;
 | |
|  
 | |
| @@ -336,10 +340,10 @@ static void mc_pcie_enable_msi(struct mc_pcie *port, void __iomem *ecam)
 | |
|  
 | |
|  static void mc_handle_msi(struct irq_desc *desc)
 | |
|  {
 | |
| -	struct mc_pcie *port = irq_desc_get_handler_data(desc);
 | |
| +	struct plda_pcie_rp *port = irq_desc_get_handler_data(desc);
 | |
|  	struct irq_chip *chip = irq_desc_get_chip(desc);
 | |
|  	struct device *dev = port->dev;
 | |
| -	struct mc_msi *msi = &port->msi;
 | |
| +	struct plda_msi *msi = &port->msi;
 | |
|  	void __iomem *bridge_base_addr = port->bridge_addr;
 | |
|  	unsigned long status;
 | |
|  	u32 bit;
 | |
| @@ -364,7 +368,7 @@ static void mc_handle_msi(struct irq_desc *desc)
 | |
|  
 | |
|  static void mc_msi_bottom_irq_ack(struct irq_data *data)
 | |
|  {
 | |
| -	struct mc_pcie *port = irq_data_get_irq_chip_data(data);
 | |
| +	struct plda_pcie_rp *port = irq_data_get_irq_chip_data(data);
 | |
|  	void __iomem *bridge_base_addr = port->bridge_addr;
 | |
|  	u32 bitpos = data->hwirq;
 | |
|  
 | |
| @@ -373,7 +377,7 @@ static void mc_msi_bottom_irq_ack(struct irq_data *data)
 | |
|  
 | |
|  static void mc_compose_msi_msg(struct irq_data *data, struct msi_msg *msg)
 | |
|  {
 | |
| -	struct mc_pcie *port = irq_data_get_irq_chip_data(data);
 | |
| +	struct plda_pcie_rp *port = irq_data_get_irq_chip_data(data);
 | |
|  	phys_addr_t addr = port->msi.vector_phy;
 | |
|  
 | |
|  	msg->address_lo = lower_32_bits(addr);
 | |
| @@ -400,8 +404,8 @@ static struct irq_chip mc_msi_bottom_irq_chip = {
 | |
|  static int mc_irq_msi_domain_alloc(struct irq_domain *domain, unsigned int virq,
 | |
|  				   unsigned int nr_irqs, void *args)
 | |
|  {
 | |
| -	struct mc_pcie *port = domain->host_data;
 | |
| -	struct mc_msi *msi = &port->msi;
 | |
| +	struct plda_pcie_rp *port = domain->host_data;
 | |
| +	struct plda_msi *msi = &port->msi;
 | |
|  	unsigned long bit;
 | |
|  
 | |
|  	mutex_lock(&msi->lock);
 | |
| @@ -425,8 +429,8 @@ static void mc_irq_msi_domain_free(struct irq_domain *domain, unsigned int virq,
 | |
|  				   unsigned int nr_irqs)
 | |
|  {
 | |
|  	struct irq_data *d = irq_domain_get_irq_data(domain, virq);
 | |
| -	struct mc_pcie *port = irq_data_get_irq_chip_data(d);
 | |
| -	struct mc_msi *msi = &port->msi;
 | |
| +	struct plda_pcie_rp *port = irq_data_get_irq_chip_data(d);
 | |
| +	struct plda_msi *msi = &port->msi;
 | |
|  
 | |
|  	mutex_lock(&msi->lock);
 | |
|  
 | |
| @@ -456,11 +460,11 @@ static struct msi_domain_info mc_msi_domain_info = {
 | |
|  	.chip = &mc_msi_irq_chip,
 | |
|  };
 | |
|  
 | |
| -static int mc_allocate_msi_domains(struct mc_pcie *port)
 | |
| +static int mc_allocate_msi_domains(struct plda_pcie_rp *port)
 | |
|  {
 | |
|  	struct device *dev = port->dev;
 | |
|  	struct fwnode_handle *fwnode = of_node_to_fwnode(dev->of_node);
 | |
| -	struct mc_msi *msi = &port->msi;
 | |
| +	struct plda_msi *msi = &port->msi;
 | |
|  
 | |
|  	mutex_init(&port->msi.lock);
 | |
|  
 | |
| @@ -484,7 +488,7 @@ static int mc_allocate_msi_domains(struct mc_pcie *port)
 | |
|  
 | |
|  static void mc_handle_intx(struct irq_desc *desc)
 | |
|  {
 | |
| -	struct mc_pcie *port = irq_desc_get_handler_data(desc);
 | |
| +	struct plda_pcie_rp *port = irq_desc_get_handler_data(desc);
 | |
|  	struct irq_chip *chip = irq_desc_get_chip(desc);
 | |
|  	struct device *dev = port->dev;
 | |
|  	void __iomem *bridge_base_addr = port->bridge_addr;
 | |
| @@ -511,7 +515,7 @@ static void mc_handle_intx(struct irq_desc *desc)
 | |
|  
 | |
|  static void mc_ack_intx_irq(struct irq_data *data)
 | |
|  {
 | |
| -	struct mc_pcie *port = irq_data_get_irq_chip_data(data);
 | |
| +	struct plda_pcie_rp *port = irq_data_get_irq_chip_data(data);
 | |
|  	void __iomem *bridge_base_addr = port->bridge_addr;
 | |
|  	u32 mask = BIT(data->hwirq + PM_MSI_INT_INTX_SHIFT);
 | |
|  
 | |
| @@ -520,7 +524,7 @@ static void mc_ack_intx_irq(struct irq_data *data)
 | |
|  
 | |
|  static void mc_mask_intx_irq(struct irq_data *data)
 | |
|  {
 | |
| -	struct mc_pcie *port = irq_data_get_irq_chip_data(data);
 | |
| +	struct plda_pcie_rp *port = irq_data_get_irq_chip_data(data);
 | |
|  	void __iomem *bridge_base_addr = port->bridge_addr;
 | |
|  	unsigned long flags;
 | |
|  	u32 mask = BIT(data->hwirq + PM_MSI_INT_INTX_SHIFT);
 | |
| @@ -535,7 +539,7 @@ static void mc_mask_intx_irq(struct irq_data *data)
 | |
|  
 | |
|  static void mc_unmask_intx_irq(struct irq_data *data)
 | |
|  {
 | |
| -	struct mc_pcie *port = irq_data_get_irq_chip_data(data);
 | |
| +	struct plda_pcie_rp *port = irq_data_get_irq_chip_data(data);
 | |
|  	void __iomem *bridge_base_addr = port->bridge_addr;
 | |
|  	unsigned long flags;
 | |
|  	u32 mask = BIT(data->hwirq + PM_MSI_INT_INTX_SHIFT);
 | |
| @@ -625,21 +629,22 @@ static u32 local_events(struct mc_pcie *port)
 | |
|  	return val;
 | |
|  }
 | |
|  
 | |
| -static u32 get_events(struct mc_pcie *port)
 | |
| +static u32 get_events(struct plda_pcie_rp *port)
 | |
|  {
 | |
| +	struct mc_pcie *mc_port = container_of(port, struct mc_pcie, plda);
 | |
|  	u32 events = 0;
 | |
|  
 | |
| -	events |= pcie_events(port);
 | |
| -	events |= sec_errors(port);
 | |
| -	events |= ded_errors(port);
 | |
| -	events |= local_events(port);
 | |
| +	events |= pcie_events(mc_port);
 | |
| +	events |= sec_errors(mc_port);
 | |
| +	events |= ded_errors(mc_port);
 | |
| +	events |= local_events(mc_port);
 | |
|  
 | |
|  	return events;
 | |
|  }
 | |
|  
 | |
|  static irqreturn_t mc_event_handler(int irq, void *dev_id)
 | |
|  {
 | |
| -	struct mc_pcie *port = dev_id;
 | |
| +	struct plda_pcie_rp *port = dev_id;
 | |
|  	struct device *dev = port->dev;
 | |
|  	struct irq_data *data;
 | |
|  
 | |
| @@ -655,7 +660,7 @@ static irqreturn_t mc_event_handler(int irq, void *dev_id)
 | |
|  
 | |
|  static void mc_handle_event(struct irq_desc *desc)
 | |
|  {
 | |
| -	struct mc_pcie *port = irq_desc_get_handler_data(desc);
 | |
| +	struct plda_pcie_rp *port = irq_desc_get_handler_data(desc);
 | |
|  	unsigned long events;
 | |
|  	u32 bit;
 | |
|  	struct irq_chip *chip = irq_desc_get_chip(desc);
 | |
| @@ -672,12 +677,13 @@ static void mc_handle_event(struct irq_desc *desc)
 | |
|  
 | |
|  static void mc_ack_event_irq(struct irq_data *data)
 | |
|  {
 | |
| -	struct mc_pcie *port = irq_data_get_irq_chip_data(data);
 | |
| +	struct plda_pcie_rp *port = irq_data_get_irq_chip_data(data);
 | |
| +	struct mc_pcie *mc_port = container_of(port, struct mc_pcie, plda);
 | |
|  	u32 event = data->hwirq;
 | |
|  	void __iomem *addr;
 | |
|  	u32 mask;
 | |
|  
 | |
| -	addr = port->axi_base_addr + event_descs[event].base +
 | |
| +	addr = mc_port->axi_base_addr + event_descs[event].base +
 | |
|  		event_descs[event].offset;
 | |
|  	mask = event_descs[event].mask;
 | |
|  	mask |= event_descs[event].enb_mask;
 | |
| @@ -687,13 +693,14 @@ static void mc_ack_event_irq(struct irq_data *data)
 | |
|  
 | |
|  static void mc_mask_event_irq(struct irq_data *data)
 | |
|  {
 | |
| -	struct mc_pcie *port = irq_data_get_irq_chip_data(data);
 | |
| +	struct plda_pcie_rp *port = irq_data_get_irq_chip_data(data);
 | |
| +	struct mc_pcie *mc_port = container_of(port, struct mc_pcie, plda);
 | |
|  	u32 event = data->hwirq;
 | |
|  	void __iomem *addr;
 | |
|  	u32 mask;
 | |
|  	u32 val;
 | |
|  
 | |
| -	addr = port->axi_base_addr + event_descs[event].base +
 | |
| +	addr = mc_port->axi_base_addr + event_descs[event].base +
 | |
|  		event_descs[event].mask_offset;
 | |
|  	mask = event_descs[event].mask;
 | |
|  	if (event_descs[event].enb_mask) {
 | |
| @@ -717,13 +724,14 @@ static void mc_mask_event_irq(struct irq_data *data)
 | |
|  
 | |
|  static void mc_unmask_event_irq(struct irq_data *data)
 | |
|  {
 | |
| -	struct mc_pcie *port = irq_data_get_irq_chip_data(data);
 | |
| +	struct plda_pcie_rp *port = irq_data_get_irq_chip_data(data);
 | |
| +	struct mc_pcie *mc_port = container_of(port, struct mc_pcie, plda);
 | |
|  	u32 event = data->hwirq;
 | |
|  	void __iomem *addr;
 | |
|  	u32 mask;
 | |
|  	u32 val;
 | |
|  
 | |
| -	addr = port->axi_base_addr + event_descs[event].base +
 | |
| +	addr = mc_port->axi_base_addr + event_descs[event].base +
 | |
|  		event_descs[event].mask_offset;
 | |
|  	mask = event_descs[event].mask;
 | |
|  
 | |
| @@ -811,7 +819,7 @@ static int mc_pcie_init_clks(struct device *dev)
 | |
|  	return 0;
 | |
|  }
 | |
|  
 | |
| -static int mc_pcie_init_irq_domains(struct mc_pcie *port)
 | |
| +static int mc_pcie_init_irq_domains(struct plda_pcie_rp *port)
 | |
|  {
 | |
|  	struct device *dev = port->dev;
 | |
|  	struct device_node *node = dev->of_node;
 | |
| @@ -889,7 +897,7 @@ static void mc_pcie_setup_window(void __iomem *bridge_base_addr, u32 index,
 | |
|  }
 | |
|  
 | |
|  static int mc_pcie_setup_windows(struct platform_device *pdev,
 | |
| -				 struct mc_pcie *port)
 | |
| +				 struct plda_pcie_rp *port)
 | |
|  {
 | |
|  	void __iomem *bridge_base_addr = port->bridge_addr;
 | |
|  	struct pci_host_bridge *bridge = platform_get_drvdata(pdev);
 | |
| @@ -970,7 +978,7 @@ static void mc_disable_interrupts(struct mc_pcie *port)
 | |
|  	writel_relaxed(GENMASK(31, 0), bridge_base_addr + ISTATUS_HOST);
 | |
|  }
 | |
|  
 | |
| -static int mc_init_interrupts(struct platform_device *pdev, struct mc_pcie *port)
 | |
| +static int mc_init_interrupts(struct platform_device *pdev, struct plda_pcie_rp *port)
 | |
|  {
 | |
|  	struct device *dev = &pdev->dev;
 | |
|  	int irq;
 | |
| @@ -1043,12 +1051,12 @@ static int mc_platform_init(struct pci_config_window *cfg)
 | |
|  	mc_pcie_enable_msi(port, cfg->win);
 | |
|  
 | |
|  	/* Configure non-config space outbound ranges */
 | |
| -	ret = mc_pcie_setup_windows(pdev, port);
 | |
| +	ret = mc_pcie_setup_windows(pdev, &port->plda);
 | |
|  	if (ret)
 | |
|  		return ret;
 | |
|  
 | |
|  	/* Address translation is up; safe to enable interrupts */
 | |
| -	ret = mc_init_interrupts(pdev, port);
 | |
| +	ret = mc_init_interrupts(pdev, &port->plda);
 | |
|  	if (ret)
 | |
|  		return ret;
 | |
|  
 | |
| @@ -1059,6 +1067,7 @@ static int mc_host_probe(struct platform_device *pdev)
 | |
|  {
 | |
|  	struct device *dev = &pdev->dev;
 | |
|  	void __iomem *bridge_base_addr;
 | |
| +	struct plda_pcie_rp *plda;
 | |
|  	int ret;
 | |
|  	u32 val;
 | |
|  
 | |
| @@ -1066,7 +1075,8 @@ static int mc_host_probe(struct platform_device *pdev)
 | |
|  	if (!port)
 | |
|  		return -ENOMEM;
 | |
|  
 | |
| -	port->dev = dev;
 | |
| +	plda = &port->plda;
 | |
| +	plda->dev = dev;
 | |
|  
 | |
|  	port->axi_base_addr = devm_platform_ioremap_resource(pdev, 1);
 | |
|  	if (IS_ERR(port->axi_base_addr))
 | |
| @@ -1075,7 +1085,7 @@ static int mc_host_probe(struct platform_device *pdev)
 | |
|  	mc_disable_interrupts(port);
 | |
|  
 | |
|  	bridge_base_addr = port->axi_base_addr + MC_PCIE_BRIDGE_ADDR;
 | |
| -	port->bridge_addr = bridge_base_addr;
 | |
| +	plda->bridge_addr = bridge_base_addr;
 | |
|  
 | |
|  	/* Allow enabling MSI by disabling MSI-X */
 | |
|  	val = readl(bridge_base_addr + PCIE_PCI_IRQ_DW0);
 | |
| @@ -1087,10 +1097,10 @@ static int mc_host_probe(struct platform_device *pdev)
 | |
|  	val &= NUM_MSI_MSGS_MASK;
 | |
|  	val >>= NUM_MSI_MSGS_SHIFT;
 | |
|  
 | |
| -	port->msi.num_vectors = 1 << val;
 | |
| +	plda->msi.num_vectors = 1 << val;
 | |
|  
 | |
|  	/* Pick vector address from design */
 | |
| -	port->msi.vector_phy = readl_relaxed(bridge_base_addr + IMSI_ADDR);
 | |
| +	plda->msi.vector_phy = readl_relaxed(bridge_base_addr + IMSI_ADDR);
 | |
|  
 | |
|  	ret = mc_pcie_init_clks(dev);
 | |
|  	if (ret) {
 | |
| -- 
 | |
| 2.43.0
 | |
| 
 | |
| 
 | |
| From 68cfb6ce3d0d855399cc6d7505cc8ac3ba56afa2 Mon Sep 17 00:00:00 2001
 | |
| From: Minda Chen <minda.chen@starfivetech.com>
 | |
| Date: Mon, 8 Jan 2024 19:05:56 +0800
 | |
| Subject: [PATCH 06/23] PCI: microchip: Move PCIe host data structures to
 | |
|  plda-pcie.h
 | |
| 
 | |
| Move the common data structures definition to head file for these two data
 | |
| structures can be re-used.
 | |
| 
 | |
| Signed-off-by: Minda Chen <minda.chen@starfivetech.com>
 | |
| Reviewed-by: Conor Dooley <conor.dooley@microchip.com>
 | |
| Message-ID: <20240108110612.19048-7-minda.chen@starfivetech.com>
 | |
| Signed-off-by: Aurelien Jarno <aurelien@aurel32.net>
 | |
| ---
 | |
|  .../pci/controller/plda/pcie-microchip-host.c | 20 ------------------
 | |
|  drivers/pci/controller/plda/pcie-plda.h       | 21 +++++++++++++++++++
 | |
|  2 files changed, 21 insertions(+), 20 deletions(-)
 | |
| 
 | |
| diff --git a/drivers/pci/controller/plda/pcie-microchip-host.c b/drivers/pci/controller/plda/pcie-microchip-host.c
 | |
| index df0736f688ce..a554a56cc0e8 100644
 | |
| --- a/drivers/pci/controller/plda/pcie-microchip-host.c
 | |
| +++ b/drivers/pci/controller/plda/pcie-microchip-host.c
 | |
| @@ -21,9 +21,6 @@
 | |
|  #include "../../pci.h"
 | |
|  #include "pcie-plda.h"
 | |
|  
 | |
| -/* Number of MSI IRQs */
 | |
| -#define PLDA_MAX_NUM_MSI_IRQS			32
 | |
| -
 | |
|  /* PCIe Bridge Phy and Controller Phy offsets */
 | |
|  #define MC_PCIE1_BRIDGE_ADDR			0x00008000u
 | |
|  #define MC_PCIE1_CTRL_ADDR			0x0000a000u
 | |
| @@ -179,23 +176,6 @@ struct event_map {
 | |
|  	u32 event_bit;
 | |
|  };
 | |
|  
 | |
| -struct plda_msi {
 | |
| -	struct mutex lock;		/* Protect used bitmap */
 | |
| -	struct irq_domain *msi_domain;
 | |
| -	struct irq_domain *dev_domain;
 | |
| -	u32 num_vectors;
 | |
| -	u64 vector_phy;
 | |
| -	DECLARE_BITMAP(used, PLDA_MAX_NUM_MSI_IRQS);
 | |
| -};
 | |
| -
 | |
| -struct plda_pcie_rp {
 | |
| -	struct device *dev;
 | |
| -	struct irq_domain *intx_domain;
 | |
| -	struct irq_domain *event_domain;
 | |
| -	raw_spinlock_t lock;
 | |
| -	struct plda_msi msi;
 | |
| -	void __iomem *bridge_addr;
 | |
| -};
 | |
|  
 | |
|  struct mc_pcie {
 | |
|  	struct plda_pcie_rp plda;
 | |
| diff --git a/drivers/pci/controller/plda/pcie-plda.h b/drivers/pci/controller/plda/pcie-plda.h
 | |
| index cad3a98d967e..7bec6a470758 100644
 | |
| --- a/drivers/pci/controller/plda/pcie-plda.h
 | |
| +++ b/drivers/pci/controller/plda/pcie-plda.h
 | |
| @@ -6,6 +6,9 @@
 | |
|  #ifndef _PCIE_PLDA_H
 | |
|  #define _PCIE_PLDA_H
 | |
|  
 | |
| +/* Number of MSI IRQs */
 | |
| +#define PLDA_MAX_NUM_MSI_IRQS			32
 | |
| +
 | |
|  /* PCIe Bridge Phy Regs */
 | |
|  #define PCIE_PCI_IRQ_DW0			0xa8
 | |
|  #define  MSIX_CAP_MASK				BIT(31)
 | |
| @@ -105,4 +108,22 @@ enum plda_int_event {
 | |
|  
 | |
|  #define PLDA_MAX_INT_NUM			(PLDA_NUM_DMA_EVENTS + PLDA_INT_EVENT_NUM)
 | |
|  
 | |
| +struct plda_msi {
 | |
| +	struct mutex lock;		/* Protect used bitmap */
 | |
| +	struct irq_domain *msi_domain;
 | |
| +	struct irq_domain *dev_domain;
 | |
| +	u32 num_vectors;
 | |
| +	u64 vector_phy;
 | |
| +	DECLARE_BITMAP(used, PLDA_MAX_NUM_MSI_IRQS);
 | |
| +};
 | |
| +
 | |
| +struct plda_pcie_rp {
 | |
| +	struct device *dev;
 | |
| +	struct irq_domain *intx_domain;
 | |
| +	struct irq_domain *event_domain;
 | |
| +	raw_spinlock_t lock;
 | |
| +	struct plda_msi msi;
 | |
| +	void __iomem *bridge_addr;
 | |
| +};
 | |
| +
 | |
|  #endif
 | |
| -- 
 | |
| 2.43.0
 | |
| 
 | |
| 
 | |
| From 5d5ba2f5b6133a3d4dc0d84d9777fa28805f14f1 Mon Sep 17 00:00:00 2001
 | |
| From: Minda Chen <minda.chen@starfivetech.com>
 | |
| Date: Mon, 8 Jan 2024 19:05:57 +0800
 | |
| Subject: [PATCH 07/23] PCI: microchip: Rename two setup functions
 | |
| 
 | |
| Rename two setup functions to plda prefix. Prepare to re-use these two
 | |
| setup function.
 | |
| 
 | |
| For two setup functions names are similar, rename mc_pcie_setup_windows()
 | |
| to plda_pcie_setup_iomems().
 | |
| 
 | |
| Signed-off-by: Minda Chen <minda.chen@starfivetech.com>
 | |
| Reviewed-by: Conor Dooley <conor.dooley@microchip.com>
 | |
| Message-ID: <20240108110612.19048-8-minda.chen@starfivetech.com>
 | |
| Signed-off-by: Aurelien Jarno <aurelien@aurel32.net>
 | |
| ---
 | |
|  .../pci/controller/plda/pcie-microchip-host.c | 24 +++++++++----------
 | |
|  1 file changed, 12 insertions(+), 12 deletions(-)
 | |
| 
 | |
| diff --git a/drivers/pci/controller/plda/pcie-microchip-host.c b/drivers/pci/controller/plda/pcie-microchip-host.c
 | |
| index a554a56cc0e8..9b367927cd32 100644
 | |
| --- a/drivers/pci/controller/plda/pcie-microchip-host.c
 | |
| +++ b/drivers/pci/controller/plda/pcie-microchip-host.c
 | |
| @@ -838,9 +838,9 @@ static int mc_pcie_init_irq_domains(struct plda_pcie_rp *port)
 | |
|  	return mc_allocate_msi_domains(port);
 | |
|  }
 | |
|  
 | |
| -static void mc_pcie_setup_window(void __iomem *bridge_base_addr, u32 index,
 | |
| -				 phys_addr_t axi_addr, phys_addr_t pci_addr,
 | |
| -				 size_t size)
 | |
| +static void plda_pcie_setup_window(void __iomem *bridge_base_addr, u32 index,
 | |
| +				   phys_addr_t axi_addr, phys_addr_t pci_addr,
 | |
| +				   size_t size)
 | |
|  {
 | |
|  	u32 atr_sz = ilog2(size) - 1;
 | |
|  	u32 val;
 | |
| @@ -876,8 +876,8 @@ static void mc_pcie_setup_window(void __iomem *bridge_base_addr, u32 index,
 | |
|  	writel(0, bridge_base_addr + ATR0_PCIE_WIN0_SRC_ADDR);
 | |
|  }
 | |
|  
 | |
| -static int mc_pcie_setup_windows(struct platform_device *pdev,
 | |
| -				 struct plda_pcie_rp *port)
 | |
| +static int plda_pcie_setup_iomems(struct platform_device *pdev,
 | |
| +				  struct plda_pcie_rp *port)
 | |
|  {
 | |
|  	void __iomem *bridge_base_addr = port->bridge_addr;
 | |
|  	struct pci_host_bridge *bridge = platform_get_drvdata(pdev);
 | |
| @@ -888,9 +888,9 @@ static int mc_pcie_setup_windows(struct platform_device *pdev,
 | |
|  	resource_list_for_each_entry(entry, &bridge->windows) {
 | |
|  		if (resource_type(entry->res) == IORESOURCE_MEM) {
 | |
|  			pci_addr = entry->res->start - entry->offset;
 | |
| -			mc_pcie_setup_window(bridge_base_addr, index,
 | |
| -					     entry->res->start, pci_addr,
 | |
| -					     resource_size(entry->res));
 | |
| +			plda_pcie_setup_window(bridge_base_addr, index,
 | |
| +					       entry->res->start, pci_addr,
 | |
| +					       resource_size(entry->res));
 | |
|  			index++;
 | |
|  		}
 | |
|  	}
 | |
| @@ -1023,15 +1023,15 @@ static int mc_platform_init(struct pci_config_window *cfg)
 | |
|  	int ret;
 | |
|  
 | |
|  	/* Configure address translation table 0 for PCIe config space */
 | |
| -	mc_pcie_setup_window(bridge_base_addr, 0, cfg->res.start,
 | |
| -			     cfg->res.start,
 | |
| -			     resource_size(&cfg->res));
 | |
| +	plda_pcie_setup_window(bridge_base_addr, 0, cfg->res.start,
 | |
| +			       cfg->res.start,
 | |
| +			       resource_size(&cfg->res));
 | |
|  
 | |
|  	/* Need some fixups in config space */
 | |
|  	mc_pcie_enable_msi(port, cfg->win);
 | |
|  
 | |
|  	/* Configure non-config space outbound ranges */
 | |
| -	ret = mc_pcie_setup_windows(pdev, &port->plda);
 | |
| +	ret = plda_pcie_setup_iomems(pdev, &port->plda);
 | |
|  	if (ret)
 | |
|  		return ret;
 | |
|  
 | |
| -- 
 | |
| 2.43.0
 | |
| 
 | |
| 
 | |
| From cc5abca4b49d346506fd44473be579fdb8949647 Mon Sep 17 00:00:00 2001
 | |
| From: Minda Chen <minda.chen@starfivetech.com>
 | |
| Date: Mon, 8 Jan 2024 19:05:58 +0800
 | |
| Subject: [PATCH 08/23] PCI: microchip: Change the argument of
 | |
|  plda_pcie_setup_iomems()
 | |
| 
 | |
| If other vendor do not select PCI_HOST_COMMON, the driver data is not
 | |
| struct pci_host_bridge.
 | |
| 
 | |
| Move calling platform_get_drvdata() to mc_platform_init().
 | |
| 
 | |
| Signed-off-by: Minda Chen <minda.chen@starfivetech.com>
 | |
| Reviewed-by: Conor Dooley <conor.dooley@microchip.com>
 | |
| Message-ID: <20240108110612.19048-9-minda.chen@starfivetech.com>
 | |
| Signed-off-by: Aurelien Jarno <aurelien@aurel32.net>
 | |
| ---
 | |
|  drivers/pci/controller/plda/pcie-microchip-host.c | 6 +++---
 | |
|  1 file changed, 3 insertions(+), 3 deletions(-)
 | |
| 
 | |
| diff --git a/drivers/pci/controller/plda/pcie-microchip-host.c b/drivers/pci/controller/plda/pcie-microchip-host.c
 | |
| index 9b367927cd32..805870aed61d 100644
 | |
| --- a/drivers/pci/controller/plda/pcie-microchip-host.c
 | |
| +++ b/drivers/pci/controller/plda/pcie-microchip-host.c
 | |
| @@ -876,11 +876,10 @@ static void plda_pcie_setup_window(void __iomem *bridge_base_addr, u32 index,
 | |
|  	writel(0, bridge_base_addr + ATR0_PCIE_WIN0_SRC_ADDR);
 | |
|  }
 | |
|  
 | |
| -static int plda_pcie_setup_iomems(struct platform_device *pdev,
 | |
| +static int plda_pcie_setup_iomems(struct pci_host_bridge *bridge,
 | |
|  				  struct plda_pcie_rp *port)
 | |
|  {
 | |
|  	void __iomem *bridge_base_addr = port->bridge_addr;
 | |
| -	struct pci_host_bridge *bridge = platform_get_drvdata(pdev);
 | |
|  	struct resource_entry *entry;
 | |
|  	u64 pci_addr;
 | |
|  	u32 index = 1;
 | |
| @@ -1018,6 +1017,7 @@ static int mc_platform_init(struct pci_config_window *cfg)
 | |
|  {
 | |
|  	struct device *dev = cfg->parent;
 | |
|  	struct platform_device *pdev = to_platform_device(dev);
 | |
| +	struct pci_host_bridge *bridge = platform_get_drvdata(pdev);
 | |
|  	void __iomem *bridge_base_addr =
 | |
|  		port->axi_base_addr + MC_PCIE_BRIDGE_ADDR;
 | |
|  	int ret;
 | |
| @@ -1031,7 +1031,7 @@ static int mc_platform_init(struct pci_config_window *cfg)
 | |
|  	mc_pcie_enable_msi(port, cfg->win);
 | |
|  
 | |
|  	/* Configure non-config space outbound ranges */
 | |
| -	ret = plda_pcie_setup_iomems(pdev, &port->plda);
 | |
| +	ret = plda_pcie_setup_iomems(bridge, &port->plda);
 | |
|  	if (ret)
 | |
|  		return ret;
 | |
|  
 | |
| -- 
 | |
| 2.43.0
 | |
| 
 | |
| 
 | |
| From f3c1d38d50a32097e65d63d14402d1b2d0b80de6 Mon Sep 17 00:00:00 2001
 | |
| From: Minda Chen <minda.chen@starfivetech.com>
 | |
| Date: Mon, 8 Jan 2024 19:05:59 +0800
 | |
| Subject: [PATCH 09/23] PCI: microchip: Move setup functions to
 | |
|  pcie-plda-host.c
 | |
| 
 | |
| Move setup functions to common pcie-plda-host.c. So these two functions
 | |
| can be re-used.
 | |
| 
 | |
| Signed-off-by: Minda Chen <minda.chen@starfivetech.com>
 | |
| Reviewed-by: Conor Dooley <conor.dooley@microchip.com>
 | |
| Message-ID: <20240108110612.19048-10-minda.chen@starfivetech.com>
 | |
| Signed-off-by: Aurelien Jarno <aurelien@aurel32.net>
 | |
| ---
 | |
|  drivers/pci/controller/plda/Kconfig           |  4 +
 | |
|  drivers/pci/controller/plda/Makefile          |  1 +
 | |
|  .../pci/controller/plda/pcie-microchip-host.c | 59 ---------------
 | |
|  drivers/pci/controller/plda/pcie-plda-host.c  | 74 +++++++++++++++++++
 | |
|  drivers/pci/controller/plda/pcie-plda.h       |  5 ++
 | |
|  5 files changed, 84 insertions(+), 59 deletions(-)
 | |
|  create mode 100644 drivers/pci/controller/plda/pcie-plda-host.c
 | |
| 
 | |
| diff --git a/drivers/pci/controller/plda/Kconfig b/drivers/pci/controller/plda/Kconfig
 | |
| index 5cb3be4fc98c..e54a82ee94f5 100644
 | |
| --- a/drivers/pci/controller/plda/Kconfig
 | |
| +++ b/drivers/pci/controller/plda/Kconfig
 | |
| @@ -3,10 +3,14 @@
 | |
|  menu "PLDA-based PCIe controllers"
 | |
|  	depends on PCI
 | |
|  
 | |
| +config PCIE_PLDA_HOST
 | |
| +	bool
 | |
| +
 | |
|  config PCIE_MICROCHIP_HOST
 | |
|  	tristate "Microchip AXI PCIe controller"
 | |
|  	depends on PCI_MSI && OF
 | |
|  	select PCI_HOST_COMMON
 | |
| +	select PCIE_PLDA_HOST
 | |
|  	help
 | |
|  	  Say Y here if you want kernel to support the Microchip AXI PCIe
 | |
|  	  Host Bridge driver.
 | |
| diff --git a/drivers/pci/controller/plda/Makefile b/drivers/pci/controller/plda/Makefile
 | |
| index e1a265cbf91c..4340ab007f44 100644
 | |
| --- a/drivers/pci/controller/plda/Makefile
 | |
| +++ b/drivers/pci/controller/plda/Makefile
 | |
| @@ -1,2 +1,3 @@
 | |
|  # SPDX-License-Identifier: GPL-2.0
 | |
| +obj-$(CONFIG_PCIE_PLDA_HOST) += pcie-plda-host.o
 | |
|  obj-$(CONFIG_PCIE_MICROCHIP_HOST) += pcie-microchip-host.o
 | |
| diff --git a/drivers/pci/controller/plda/pcie-microchip-host.c b/drivers/pci/controller/plda/pcie-microchip-host.c
 | |
| index 805870aed61d..573ad31c578a 100644
 | |
| --- a/drivers/pci/controller/plda/pcie-microchip-host.c
 | |
| +++ b/drivers/pci/controller/plda/pcie-microchip-host.c
 | |
| @@ -838,65 +838,6 @@ static int mc_pcie_init_irq_domains(struct plda_pcie_rp *port)
 | |
|  	return mc_allocate_msi_domains(port);
 | |
|  }
 | |
|  
 | |
| -static void plda_pcie_setup_window(void __iomem *bridge_base_addr, u32 index,
 | |
| -				   phys_addr_t axi_addr, phys_addr_t pci_addr,
 | |
| -				   size_t size)
 | |
| -{
 | |
| -	u32 atr_sz = ilog2(size) - 1;
 | |
| -	u32 val;
 | |
| -
 | |
| -	if (index == 0)
 | |
| -		val = PCIE_CONFIG_INTERFACE;
 | |
| -	else
 | |
| -		val = PCIE_TX_RX_INTERFACE;
 | |
| -
 | |
| -	writel(val, bridge_base_addr + (index * ATR_ENTRY_SIZE) +
 | |
| -	       ATR0_AXI4_SLV0_TRSL_PARAM);
 | |
| -
 | |
| -	val = lower_32_bits(axi_addr) | (atr_sz << ATR_SIZE_SHIFT) |
 | |
| -			    ATR_IMPL_ENABLE;
 | |
| -	writel(val, bridge_base_addr + (index * ATR_ENTRY_SIZE) +
 | |
| -	       ATR0_AXI4_SLV0_SRCADDR_PARAM);
 | |
| -
 | |
| -	val = upper_32_bits(axi_addr);
 | |
| -	writel(val, bridge_base_addr + (index * ATR_ENTRY_SIZE) +
 | |
| -	       ATR0_AXI4_SLV0_SRC_ADDR);
 | |
| -
 | |
| -	val = lower_32_bits(pci_addr);
 | |
| -	writel(val, bridge_base_addr + (index * ATR_ENTRY_SIZE) +
 | |
| -	       ATR0_AXI4_SLV0_TRSL_ADDR_LSB);
 | |
| -
 | |
| -	val = upper_32_bits(pci_addr);
 | |
| -	writel(val, bridge_base_addr + (index * ATR_ENTRY_SIZE) +
 | |
| -	       ATR0_AXI4_SLV0_TRSL_ADDR_UDW);
 | |
| -
 | |
| -	val = readl(bridge_base_addr + ATR0_PCIE_WIN0_SRCADDR_PARAM);
 | |
| -	val |= (ATR0_PCIE_ATR_SIZE << ATR0_PCIE_ATR_SIZE_SHIFT);
 | |
| -	writel(val, bridge_base_addr + ATR0_PCIE_WIN0_SRCADDR_PARAM);
 | |
| -	writel(0, bridge_base_addr + ATR0_PCIE_WIN0_SRC_ADDR);
 | |
| -}
 | |
| -
 | |
| -static int plda_pcie_setup_iomems(struct pci_host_bridge *bridge,
 | |
| -				  struct plda_pcie_rp *port)
 | |
| -{
 | |
| -	void __iomem *bridge_base_addr = port->bridge_addr;
 | |
| -	struct resource_entry *entry;
 | |
| -	u64 pci_addr;
 | |
| -	u32 index = 1;
 | |
| -
 | |
| -	resource_list_for_each_entry(entry, &bridge->windows) {
 | |
| -		if (resource_type(entry->res) == IORESOURCE_MEM) {
 | |
| -			pci_addr = entry->res->start - entry->offset;
 | |
| -			plda_pcie_setup_window(bridge_base_addr, index,
 | |
| -					       entry->res->start, pci_addr,
 | |
| -					       resource_size(entry->res));
 | |
| -			index++;
 | |
| -		}
 | |
| -	}
 | |
| -
 | |
| -	return 0;
 | |
| -}
 | |
| -
 | |
|  static inline void mc_clear_secs(struct mc_pcie *port)
 | |
|  {
 | |
|  	void __iomem *ctrl_base_addr = port->axi_base_addr + MC_PCIE_CTRL_ADDR;
 | |
| diff --git a/drivers/pci/controller/plda/pcie-plda-host.c b/drivers/pci/controller/plda/pcie-plda-host.c
 | |
| new file mode 100644
 | |
| index 000000000000..40139d998568
 | |
| --- /dev/null
 | |
| +++ b/drivers/pci/controller/plda/pcie-plda-host.c
 | |
| @@ -0,0 +1,74 @@
 | |
| +// SPDX-License-Identifier: GPL-2.0
 | |
| +/*
 | |
| + * PLDA PCIe XpressRich host controller driver
 | |
| + *
 | |
| + * Copyright (C) 2023 Microchip Co. Ltd
 | |
| + *
 | |
| + * Author: Daire McNamara <daire.mcnamara@microchip.com>
 | |
| + */
 | |
| +
 | |
| +#include <linux/pci_regs.h>
 | |
| +#include <linux/pci-ecam.h>
 | |
| +
 | |
| +#include "pcie-plda.h"
 | |
| +
 | |
| +void plda_pcie_setup_window(void __iomem *bridge_base_addr, u32 index,
 | |
| +			    phys_addr_t axi_addr, phys_addr_t pci_addr,
 | |
| +			    size_t size)
 | |
| +{
 | |
| +	u32 atr_sz = ilog2(size) - 1;
 | |
| +	u32 val;
 | |
| +
 | |
| +	if (index == 0)
 | |
| +		val = PCIE_CONFIG_INTERFACE;
 | |
| +	else
 | |
| +		val = PCIE_TX_RX_INTERFACE;
 | |
| +
 | |
| +	writel(val, bridge_base_addr + (index * ATR_ENTRY_SIZE) +
 | |
| +	       ATR0_AXI4_SLV0_TRSL_PARAM);
 | |
| +
 | |
| +	val = lower_32_bits(axi_addr) | (atr_sz << ATR_SIZE_SHIFT) |
 | |
| +			    ATR_IMPL_ENABLE;
 | |
| +	writel(val, bridge_base_addr + (index * ATR_ENTRY_SIZE) +
 | |
| +	       ATR0_AXI4_SLV0_SRCADDR_PARAM);
 | |
| +
 | |
| +	val = upper_32_bits(axi_addr);
 | |
| +	writel(val, bridge_base_addr + (index * ATR_ENTRY_SIZE) +
 | |
| +	       ATR0_AXI4_SLV0_SRC_ADDR);
 | |
| +
 | |
| +	val = lower_32_bits(pci_addr);
 | |
| +	writel(val, bridge_base_addr + (index * ATR_ENTRY_SIZE) +
 | |
| +	       ATR0_AXI4_SLV0_TRSL_ADDR_LSB);
 | |
| +
 | |
| +	val = upper_32_bits(pci_addr);
 | |
| +	writel(val, bridge_base_addr + (index * ATR_ENTRY_SIZE) +
 | |
| +	       ATR0_AXI4_SLV0_TRSL_ADDR_UDW);
 | |
| +
 | |
| +	val = readl(bridge_base_addr + ATR0_PCIE_WIN0_SRCADDR_PARAM);
 | |
| +	val |= (ATR0_PCIE_ATR_SIZE << ATR0_PCIE_ATR_SIZE_SHIFT);
 | |
| +	writel(val, bridge_base_addr + ATR0_PCIE_WIN0_SRCADDR_PARAM);
 | |
| +	writel(0, bridge_base_addr + ATR0_PCIE_WIN0_SRC_ADDR);
 | |
| +}
 | |
| +EXPORT_SYMBOL_GPL(plda_pcie_setup_window);
 | |
| +
 | |
| +int plda_pcie_setup_iomems(struct pci_host_bridge *bridge,
 | |
| +			   struct plda_pcie_rp *port)
 | |
| +{
 | |
| +	void __iomem *bridge_base_addr = port->bridge_addr;
 | |
| +	struct resource_entry *entry;
 | |
| +	u64 pci_addr;
 | |
| +	u32 index = 1;
 | |
| +
 | |
| +	resource_list_for_each_entry(entry, &bridge->windows) {
 | |
| +		if (resource_type(entry->res) == IORESOURCE_MEM) {
 | |
| +			pci_addr = entry->res->start - entry->offset;
 | |
| +			plda_pcie_setup_window(bridge_base_addr, index,
 | |
| +					       entry->res->start, pci_addr,
 | |
| +					       resource_size(entry->res));
 | |
| +			index++;
 | |
| +		}
 | |
| +	}
 | |
| +
 | |
| +	return 0;
 | |
| +}
 | |
| +EXPORT_SYMBOL_GPL(plda_pcie_setup_iomems);
 | |
| diff --git a/drivers/pci/controller/plda/pcie-plda.h b/drivers/pci/controller/plda/pcie-plda.h
 | |
| index 7bec6a470758..3a17d8ab5bb2 100644
 | |
| --- a/drivers/pci/controller/plda/pcie-plda.h
 | |
| +++ b/drivers/pci/controller/plda/pcie-plda.h
 | |
| @@ -126,4 +126,9 @@ struct plda_pcie_rp {
 | |
|  	void __iomem *bridge_addr;
 | |
|  };
 | |
|  
 | |
| +void plda_pcie_setup_window(void __iomem *bridge_base_addr, u32 index,
 | |
| +			    phys_addr_t axi_addr, phys_addr_t pci_addr,
 | |
| +			    size_t size);
 | |
| +int plda_pcie_setup_iomems(struct pci_host_bridge *bridge,
 | |
| +			   struct plda_pcie_rp *port);
 | |
|  #endif
 | |
| -- 
 | |
| 2.43.0
 | |
| 
 | |
| 
 | |
| From 530d17ad6ca6d827a3739f4f7424ba9a886df3ab Mon Sep 17 00:00:00 2001
 | |
| From: Minda Chen <minda.chen@starfivetech.com>
 | |
| Date: Mon, 8 Jan 2024 19:06:00 +0800
 | |
| Subject: [PATCH 10/23] PCI: microchip: Rename interrupt related functions
 | |
| 
 | |
| Rename mc_* to plda_* for IRQ functions and related IRQ domain ops data
 | |
| instances.
 | |
| 
 | |
| MSI, INTx interrupt code and IRQ init code are all can be re-used.
 | |
| 
 | |
| Signed-off-by: Minda Chen <minda.chen@starfivetech.com>
 | |
| Acked-by: Conor Dooley <conor.dooley@microchip.com>
 | |
| Message-ID: <20240108110612.19048-11-minda.chen@starfivetech.com>
 | |
| Signed-off-by: Aurelien Jarno <aurelien@aurel32.net>
 | |
| ---
 | |
|  .../pci/controller/plda/pcie-microchip-host.c | 109 +++++++++---------
 | |
|  1 file changed, 57 insertions(+), 52 deletions(-)
 | |
| 
 | |
| diff --git a/drivers/pci/controller/plda/pcie-microchip-host.c b/drivers/pci/controller/plda/pcie-microchip-host.c
 | |
| index 573ad31c578a..18bc352db389 100644
 | |
| --- a/drivers/pci/controller/plda/pcie-microchip-host.c
 | |
| +++ b/drivers/pci/controller/plda/pcie-microchip-host.c
 | |
| @@ -318,7 +318,7 @@ static void mc_pcie_enable_msi(struct mc_pcie *port, void __iomem *ecam)
 | |
|  		       ecam + MC_MSI_CAP_CTRL_OFFSET + PCI_MSI_ADDRESS_HI);
 | |
|  }
 | |
|  
 | |
| -static void mc_handle_msi(struct irq_desc *desc)
 | |
| +static void plda_handle_msi(struct irq_desc *desc)
 | |
|  {
 | |
|  	struct plda_pcie_rp *port = irq_desc_get_handler_data(desc);
 | |
|  	struct irq_chip *chip = irq_desc_get_chip(desc);
 | |
| @@ -346,7 +346,7 @@ static void mc_handle_msi(struct irq_desc *desc)
 | |
|  	chained_irq_exit(chip, desc);
 | |
|  }
 | |
|  
 | |
| -static void mc_msi_bottom_irq_ack(struct irq_data *data)
 | |
| +static void plda_msi_bottom_irq_ack(struct irq_data *data)
 | |
|  {
 | |
|  	struct plda_pcie_rp *port = irq_data_get_irq_chip_data(data);
 | |
|  	void __iomem *bridge_base_addr = port->bridge_addr;
 | |
| @@ -355,7 +355,7 @@ static void mc_msi_bottom_irq_ack(struct irq_data *data)
 | |
|  	writel_relaxed(BIT(bitpos), bridge_base_addr + ISTATUS_MSI);
 | |
|  }
 | |
|  
 | |
| -static void mc_compose_msi_msg(struct irq_data *data, struct msi_msg *msg)
 | |
| +static void plda_compose_msi_msg(struct irq_data *data, struct msi_msg *msg)
 | |
|  {
 | |
|  	struct plda_pcie_rp *port = irq_data_get_irq_chip_data(data);
 | |
|  	phys_addr_t addr = port->msi.vector_phy;
 | |
| @@ -368,21 +368,23 @@ static void mc_compose_msi_msg(struct irq_data *data, struct msi_msg *msg)
 | |
|  		(int)data->hwirq, msg->address_hi, msg->address_lo);
 | |
|  }
 | |
|  
 | |
| -static int mc_msi_set_affinity(struct irq_data *irq_data,
 | |
| -			       const struct cpumask *mask, bool force)
 | |
| +static int plda_msi_set_affinity(struct irq_data *irq_data,
 | |
| +				 const struct cpumask *mask, bool force)
 | |
|  {
 | |
|  	return -EINVAL;
 | |
|  }
 | |
|  
 | |
| -static struct irq_chip mc_msi_bottom_irq_chip = {
 | |
| -	.name = "Microchip MSI",
 | |
| -	.irq_ack = mc_msi_bottom_irq_ack,
 | |
| -	.irq_compose_msi_msg = mc_compose_msi_msg,
 | |
| -	.irq_set_affinity = mc_msi_set_affinity,
 | |
| +static struct irq_chip plda_msi_bottom_irq_chip = {
 | |
| +	.name = "PLDA MSI",
 | |
| +	.irq_ack = plda_msi_bottom_irq_ack,
 | |
| +	.irq_compose_msi_msg = plda_compose_msi_msg,
 | |
| +	.irq_set_affinity = plda_msi_set_affinity,
 | |
|  };
 | |
|  
 | |
| -static int mc_irq_msi_domain_alloc(struct irq_domain *domain, unsigned int virq,
 | |
| -				   unsigned int nr_irqs, void *args)
 | |
| +static int plda_irq_msi_domain_alloc(struct irq_domain *domain,
 | |
| +				     unsigned int virq,
 | |
| +				     unsigned int nr_irqs,
 | |
| +				     void *args)
 | |
|  {
 | |
|  	struct plda_pcie_rp *port = domain->host_data;
 | |
|  	struct plda_msi *msi = &port->msi;
 | |
| @@ -397,7 +399,7 @@ static int mc_irq_msi_domain_alloc(struct irq_domain *domain, unsigned int virq,
 | |
|  
 | |
|  	set_bit(bit, msi->used);
 | |
|  
 | |
| -	irq_domain_set_info(domain, virq, bit, &mc_msi_bottom_irq_chip,
 | |
| +	irq_domain_set_info(domain, virq, bit, &plda_msi_bottom_irq_chip,
 | |
|  			    domain->host_data, handle_edge_irq, NULL, NULL);
 | |
|  
 | |
|  	mutex_unlock(&msi->lock);
 | |
| @@ -405,8 +407,9 @@ static int mc_irq_msi_domain_alloc(struct irq_domain *domain, unsigned int virq,
 | |
|  	return 0;
 | |
|  }
 | |
|  
 | |
| -static void mc_irq_msi_domain_free(struct irq_domain *domain, unsigned int virq,
 | |
| -				   unsigned int nr_irqs)
 | |
| +static void plda_irq_msi_domain_free(struct irq_domain *domain,
 | |
| +				     unsigned int virq,
 | |
| +				     unsigned int nr_irqs)
 | |
|  {
 | |
|  	struct irq_data *d = irq_domain_get_irq_data(domain, virq);
 | |
|  	struct plda_pcie_rp *port = irq_data_get_irq_chip_data(d);
 | |
| @@ -423,24 +426,24 @@ static void mc_irq_msi_domain_free(struct irq_domain *domain, unsigned int virq,
 | |
|  }
 | |
|  
 | |
|  static const struct irq_domain_ops msi_domain_ops = {
 | |
| -	.alloc	= mc_irq_msi_domain_alloc,
 | |
| -	.free	= mc_irq_msi_domain_free,
 | |
| +	.alloc	= plda_irq_msi_domain_alloc,
 | |
| +	.free	= plda_irq_msi_domain_free,
 | |
|  };
 | |
|  
 | |
| -static struct irq_chip mc_msi_irq_chip = {
 | |
| -	.name = "Microchip PCIe MSI",
 | |
| +static struct irq_chip plda_msi_irq_chip = {
 | |
| +	.name = "PLDA PCIe MSI",
 | |
|  	.irq_ack = irq_chip_ack_parent,
 | |
|  	.irq_mask = pci_msi_mask_irq,
 | |
|  	.irq_unmask = pci_msi_unmask_irq,
 | |
|  };
 | |
|  
 | |
| -static struct msi_domain_info mc_msi_domain_info = {
 | |
| +static struct msi_domain_info plda_msi_domain_info = {
 | |
|  	.flags = (MSI_FLAG_USE_DEF_DOM_OPS | MSI_FLAG_USE_DEF_CHIP_OPS |
 | |
|  		  MSI_FLAG_PCI_MSIX),
 | |
| -	.chip = &mc_msi_irq_chip,
 | |
| +	.chip = &plda_msi_irq_chip,
 | |
|  };
 | |
|  
 | |
| -static int mc_allocate_msi_domains(struct plda_pcie_rp *port)
 | |
| +static int plda_allocate_msi_domains(struct plda_pcie_rp *port)
 | |
|  {
 | |
|  	struct device *dev = port->dev;
 | |
|  	struct fwnode_handle *fwnode = of_node_to_fwnode(dev->of_node);
 | |
| @@ -455,7 +458,8 @@ static int mc_allocate_msi_domains(struct plda_pcie_rp *port)
 | |
|  		return -ENOMEM;
 | |
|  	}
 | |
|  
 | |
| -	msi->msi_domain = pci_msi_create_irq_domain(fwnode, &mc_msi_domain_info,
 | |
| +	msi->msi_domain = pci_msi_create_irq_domain(fwnode,
 | |
| +						    &plda_msi_domain_info,
 | |
|  						    msi->dev_domain);
 | |
|  	if (!msi->msi_domain) {
 | |
|  		dev_err(dev, "failed to create MSI domain\n");
 | |
| @@ -466,7 +470,7 @@ static int mc_allocate_msi_domains(struct plda_pcie_rp *port)
 | |
|  	return 0;
 | |
|  }
 | |
|  
 | |
| -static void mc_handle_intx(struct irq_desc *desc)
 | |
| +static void plda_handle_intx(struct irq_desc *desc)
 | |
|  {
 | |
|  	struct plda_pcie_rp *port = irq_desc_get_handler_data(desc);
 | |
|  	struct irq_chip *chip = irq_desc_get_chip(desc);
 | |
| @@ -493,7 +497,7 @@ static void mc_handle_intx(struct irq_desc *desc)
 | |
|  	chained_irq_exit(chip, desc);
 | |
|  }
 | |
|  
 | |
| -static void mc_ack_intx_irq(struct irq_data *data)
 | |
| +static void plda_ack_intx_irq(struct irq_data *data)
 | |
|  {
 | |
|  	struct plda_pcie_rp *port = irq_data_get_irq_chip_data(data);
 | |
|  	void __iomem *bridge_base_addr = port->bridge_addr;
 | |
| @@ -502,7 +506,7 @@ static void mc_ack_intx_irq(struct irq_data *data)
 | |
|  	writel_relaxed(mask, bridge_base_addr + ISTATUS_LOCAL);
 | |
|  }
 | |
|  
 | |
| -static void mc_mask_intx_irq(struct irq_data *data)
 | |
| +static void plda_mask_intx_irq(struct irq_data *data)
 | |
|  {
 | |
|  	struct plda_pcie_rp *port = irq_data_get_irq_chip_data(data);
 | |
|  	void __iomem *bridge_base_addr = port->bridge_addr;
 | |
| @@ -517,7 +521,7 @@ static void mc_mask_intx_irq(struct irq_data *data)
 | |
|  	raw_spin_unlock_irqrestore(&port->lock, flags);
 | |
|  }
 | |
|  
 | |
| -static void mc_unmask_intx_irq(struct irq_data *data)
 | |
| +static void plda_unmask_intx_irq(struct irq_data *data)
 | |
|  {
 | |
|  	struct plda_pcie_rp *port = irq_data_get_irq_chip_data(data);
 | |
|  	void __iomem *bridge_base_addr = port->bridge_addr;
 | |
| @@ -532,24 +536,24 @@ static void mc_unmask_intx_irq(struct irq_data *data)
 | |
|  	raw_spin_unlock_irqrestore(&port->lock, flags);
 | |
|  }
 | |
|  
 | |
| -static struct irq_chip mc_intx_irq_chip = {
 | |
| -	.name = "Microchip PCIe INTx",
 | |
| -	.irq_ack = mc_ack_intx_irq,
 | |
| -	.irq_mask = mc_mask_intx_irq,
 | |
| -	.irq_unmask = mc_unmask_intx_irq,
 | |
| +static struct irq_chip plda_intx_irq_chip = {
 | |
| +	.name = "PLDA PCIe INTx",
 | |
| +	.irq_ack = plda_ack_intx_irq,
 | |
| +	.irq_mask = plda_mask_intx_irq,
 | |
| +	.irq_unmask = plda_unmask_intx_irq,
 | |
|  };
 | |
|  
 | |
| -static int mc_pcie_intx_map(struct irq_domain *domain, unsigned int irq,
 | |
| -			    irq_hw_number_t hwirq)
 | |
| +static int plda_pcie_intx_map(struct irq_domain *domain, unsigned int irq,
 | |
| +			      irq_hw_number_t hwirq)
 | |
|  {
 | |
| -	irq_set_chip_and_handler(irq, &mc_intx_irq_chip, handle_level_irq);
 | |
| +	irq_set_chip_and_handler(irq, &plda_intx_irq_chip, handle_level_irq);
 | |
|  	irq_set_chip_data(irq, domain->host_data);
 | |
|  
 | |
|  	return 0;
 | |
|  }
 | |
|  
 | |
|  static const struct irq_domain_ops intx_domain_ops = {
 | |
| -	.map = mc_pcie_intx_map,
 | |
| +	.map = plda_pcie_intx_map,
 | |
|  };
 | |
|  
 | |
|  static inline u32 reg_to_event(u32 reg, struct event_map field)
 | |
| @@ -609,7 +613,7 @@ static u32 local_events(struct mc_pcie *port)
 | |
|  	return val;
 | |
|  }
 | |
|  
 | |
| -static u32 get_events(struct plda_pcie_rp *port)
 | |
| +static u32 mc_get_events(struct plda_pcie_rp *port)
 | |
|  {
 | |
|  	struct mc_pcie *mc_port = container_of(port, struct mc_pcie, plda);
 | |
|  	u32 events = 0;
 | |
| @@ -638,7 +642,7 @@ static irqreturn_t mc_event_handler(int irq, void *dev_id)
 | |
|  	return IRQ_HANDLED;
 | |
|  }
 | |
|  
 | |
| -static void mc_handle_event(struct irq_desc *desc)
 | |
| +static void plda_handle_event(struct irq_desc *desc)
 | |
|  {
 | |
|  	struct plda_pcie_rp *port = irq_desc_get_handler_data(desc);
 | |
|  	unsigned long events;
 | |
| @@ -647,7 +651,7 @@ static void mc_handle_event(struct irq_desc *desc)
 | |
|  
 | |
|  	chained_irq_enter(chip, desc);
 | |
|  
 | |
| -	events = get_events(port);
 | |
| +	events = mc_get_events(port);
 | |
|  
 | |
|  	for_each_set_bit(bit, &events, NUM_EVENTS)
 | |
|  		generic_handle_domain_irq(port->event_domain, bit);
 | |
| @@ -741,8 +745,8 @@ static struct irq_chip mc_event_irq_chip = {
 | |
|  	.irq_unmask = mc_unmask_event_irq,
 | |
|  };
 | |
|  
 | |
| -static int mc_pcie_event_map(struct irq_domain *domain, unsigned int irq,
 | |
| -			     irq_hw_number_t hwirq)
 | |
| +static int plda_pcie_event_map(struct irq_domain *domain, unsigned int irq,
 | |
| +			       irq_hw_number_t hwirq)
 | |
|  {
 | |
|  	irq_set_chip_and_handler(irq, &mc_event_irq_chip, handle_level_irq);
 | |
|  	irq_set_chip_data(irq, domain->host_data);
 | |
| @@ -750,8 +754,8 @@ static int mc_pcie_event_map(struct irq_domain *domain, unsigned int irq,
 | |
|  	return 0;
 | |
|  }
 | |
|  
 | |
| -static const struct irq_domain_ops event_domain_ops = {
 | |
| -	.map = mc_pcie_event_map,
 | |
| +static const struct irq_domain_ops plda_event_domain_ops = {
 | |
| +	.map = plda_pcie_event_map,
 | |
|  };
 | |
|  
 | |
|  static inline void mc_pcie_deinit_clk(void *data)
 | |
| @@ -799,7 +803,7 @@ static int mc_pcie_init_clks(struct device *dev)
 | |
|  	return 0;
 | |
|  }
 | |
|  
 | |
| -static int mc_pcie_init_irq_domains(struct plda_pcie_rp *port)
 | |
| +static int plda_pcie_init_irq_domains(struct plda_pcie_rp *port)
 | |
|  {
 | |
|  	struct device *dev = port->dev;
 | |
|  	struct device_node *node = dev->of_node;
 | |
| @@ -813,7 +817,8 @@ static int mc_pcie_init_irq_domains(struct plda_pcie_rp *port)
 | |
|  	}
 | |
|  
 | |
|  	port->event_domain = irq_domain_add_linear(pcie_intc_node, NUM_EVENTS,
 | |
| -						   &event_domain_ops, port);
 | |
| +						   &plda_event_domain_ops,
 | |
| +						   port);
 | |
|  	if (!port->event_domain) {
 | |
|  		dev_err(dev, "failed to get event domain\n");
 | |
|  		of_node_put(pcie_intc_node);
 | |
| @@ -835,7 +840,7 @@ static int mc_pcie_init_irq_domains(struct plda_pcie_rp *port)
 | |
|  	of_node_put(pcie_intc_node);
 | |
|  	raw_spin_lock_init(&port->lock);
 | |
|  
 | |
| -	return mc_allocate_msi_domains(port);
 | |
| +	return plda_allocate_msi_domains(port);
 | |
|  }
 | |
|  
 | |
|  static inline void mc_clear_secs(struct mc_pcie *port)
 | |
| @@ -898,14 +903,14 @@ static void mc_disable_interrupts(struct mc_pcie *port)
 | |
|  	writel_relaxed(GENMASK(31, 0), bridge_base_addr + ISTATUS_HOST);
 | |
|  }
 | |
|  
 | |
| -static int mc_init_interrupts(struct platform_device *pdev, struct plda_pcie_rp *port)
 | |
| +static int plda_init_interrupts(struct platform_device *pdev, struct plda_pcie_rp *port)
 | |
|  {
 | |
|  	struct device *dev = &pdev->dev;
 | |
|  	int irq;
 | |
|  	int i, intx_irq, msi_irq, event_irq;
 | |
|  	int ret;
 | |
|  
 | |
| -	ret = mc_pcie_init_irq_domains(port);
 | |
| +	ret = plda_pcie_init_irq_domains(port);
 | |
|  	if (ret) {
 | |
|  		dev_err(dev, "failed creating IRQ domains\n");
 | |
|  		return ret;
 | |
| @@ -938,7 +943,7 @@ static int mc_init_interrupts(struct platform_device *pdev, struct plda_pcie_rp
 | |
|  	}
 | |
|  
 | |
|  	/* Plug the INTx chained handler */
 | |
| -	irq_set_chained_handler_and_data(intx_irq, mc_handle_intx, port);
 | |
| +	irq_set_chained_handler_and_data(intx_irq, plda_handle_intx, port);
 | |
|  
 | |
|  	msi_irq = irq_create_mapping(port->event_domain,
 | |
|  				     EVENT_LOCAL_PM_MSI_INT_MSI);
 | |
| @@ -946,10 +951,10 @@ static int mc_init_interrupts(struct platform_device *pdev, struct plda_pcie_rp
 | |
|  		return -ENXIO;
 | |
|  
 | |
|  	/* Plug the MSI chained handler */
 | |
| -	irq_set_chained_handler_and_data(msi_irq, mc_handle_msi, port);
 | |
| +	irq_set_chained_handler_and_data(msi_irq, plda_handle_msi, port);
 | |
|  
 | |
|  	/* Plug the main event chained handler */
 | |
| -	irq_set_chained_handler_and_data(irq, mc_handle_event, port);
 | |
| +	irq_set_chained_handler_and_data(irq, plda_handle_event, port);
 | |
|  
 | |
|  	return 0;
 | |
|  }
 | |
| @@ -977,7 +982,7 @@ static int mc_platform_init(struct pci_config_window *cfg)
 | |
|  		return ret;
 | |
|  
 | |
|  	/* Address translation is up; safe to enable interrupts */
 | |
| -	ret = mc_init_interrupts(pdev, &port->plda);
 | |
| +	ret = plda_init_interrupts(pdev, &port->plda);
 | |
|  	if (ret)
 | |
|  		return ret;
 | |
|  
 | |
| -- 
 | |
| 2.43.0
 | |
| 
 | |
| 
 | |
| From 0f2c8b23c449631c31774d68e54f0586719b9f83 Mon Sep 17 00:00:00 2001
 | |
| From: Minda Chen <minda.chen@starfivetech.com>
 | |
| Date: Mon, 8 Jan 2024 19:06:01 +0800
 | |
| Subject: [PATCH 11/23] PCI: microchip: Add num_events field to struct
 | |
|  plda_pcie_rp
 | |
| 
 | |
| The number of events is different across platforms. In order to share
 | |
| interrupt processing code, add a variable that defines the number of
 | |
| events so that it can be set per-platform instead of hardcoding it.
 | |
| 
 | |
| Signed-off-by: Minda Chen <minda.chen@starfivetech.com>
 | |
| Reviewed-by: Conor Dooley <conor.dooley@microchip.com>
 | |
| Message-ID: <20240108110612.19048-12-minda.chen@starfivetech.com>
 | |
| Signed-off-by: Aurelien Jarno <aurelien@aurel32.net>
 | |
| ---
 | |
|  drivers/pci/controller/plda/pcie-microchip-host.c | 8 +++++---
 | |
|  drivers/pci/controller/plda/pcie-plda.h           | 1 +
 | |
|  2 files changed, 6 insertions(+), 3 deletions(-)
 | |
| 
 | |
| diff --git a/drivers/pci/controller/plda/pcie-microchip-host.c b/drivers/pci/controller/plda/pcie-microchip-host.c
 | |
| index 18bc352db389..0a5cd8b214cd 100644
 | |
| --- a/drivers/pci/controller/plda/pcie-microchip-host.c
 | |
| +++ b/drivers/pci/controller/plda/pcie-microchip-host.c
 | |
| @@ -653,7 +653,7 @@ static void plda_handle_event(struct irq_desc *desc)
 | |
|  
 | |
|  	events = mc_get_events(port);
 | |
|  
 | |
| -	for_each_set_bit(bit, &events, NUM_EVENTS)
 | |
| +	for_each_set_bit(bit, &events, port->num_events)
 | |
|  		generic_handle_domain_irq(port->event_domain, bit);
 | |
|  
 | |
|  	chained_irq_exit(chip, desc);
 | |
| @@ -816,7 +816,8 @@ static int plda_pcie_init_irq_domains(struct plda_pcie_rp *port)
 | |
|  		return -EINVAL;
 | |
|  	}
 | |
|  
 | |
| -	port->event_domain = irq_domain_add_linear(pcie_intc_node, NUM_EVENTS,
 | |
| +	port->event_domain = irq_domain_add_linear(pcie_intc_node,
 | |
| +						   port->num_events,
 | |
|  						   &plda_event_domain_ops,
 | |
|  						   port);
 | |
|  	if (!port->event_domain) {
 | |
| @@ -920,7 +921,7 @@ static int plda_init_interrupts(struct platform_device *pdev, struct plda_pcie_r
 | |
|  	if (irq < 0)
 | |
|  		return -ENODEV;
 | |
|  
 | |
| -	for (i = 0; i < NUM_EVENTS; i++) {
 | |
| +	for (i = 0; i < port->num_events; i++) {
 | |
|  		event_irq = irq_create_mapping(port->event_domain, i);
 | |
|  		if (!event_irq) {
 | |
|  			dev_err(dev, "failed to map hwirq %d\n", i);
 | |
| @@ -1012,6 +1013,7 @@ static int mc_host_probe(struct platform_device *pdev)
 | |
|  
 | |
|  	bridge_base_addr = port->axi_base_addr + MC_PCIE_BRIDGE_ADDR;
 | |
|  	plda->bridge_addr = bridge_base_addr;
 | |
| +	plda->num_events = NUM_EVENTS;
 | |
|  
 | |
|  	/* Allow enabling MSI by disabling MSI-X */
 | |
|  	val = readl(bridge_base_addr + PCIE_PCI_IRQ_DW0);
 | |
| diff --git a/drivers/pci/controller/plda/pcie-plda.h b/drivers/pci/controller/plda/pcie-plda.h
 | |
| index 3a17d8ab5bb2..adfca9f28458 100644
 | |
| --- a/drivers/pci/controller/plda/pcie-plda.h
 | |
| +++ b/drivers/pci/controller/plda/pcie-plda.h
 | |
| @@ -124,6 +124,7 @@ struct plda_pcie_rp {
 | |
|  	raw_spinlock_t lock;
 | |
|  	struct plda_msi msi;
 | |
|  	void __iomem *bridge_addr;
 | |
| +	int num_events;
 | |
|  };
 | |
|  
 | |
|  void plda_pcie_setup_window(void __iomem *bridge_base_addr, u32 index,
 | |
| -- 
 | |
| 2.43.0
 | |
| 
 | |
| 
 | |
| From 4e90f5c96dbf6799e63d7eaea36b5735f514400e Mon Sep 17 00:00:00 2001
 | |
| From: Minda Chen <minda.chen@starfivetech.com>
 | |
| Date: Mon, 8 Jan 2024 19:06:02 +0800
 | |
| Subject: [PATCH 12/23] PCI: microchip: Add request_event_irq() callback
 | |
|  function
 | |
| 
 | |
| As PLDA dts binding doc(Documentation/devicetree/bindings/pci/
 | |
| plda,xpressrich3-axi-common.yaml) showes, PLDA PCIe contains an interrupt
 | |
| controller. Microchip Polarfire PCIe add some PCIe interrupts base on
 | |
| PLDA IP interrupt controller.
 | |
| 
 | |
| Microchip Polarfire PCIe additional intrerrupts:
 | |
| EVENT_PCIE_L2_EXIT
 | |
| EVENT_PCIE_HOTRST_EXIT
 | |
| EVENT_PCIE_DLUP_EXIT
 | |
| EVENT_SEC_TX_RAM_SEC_ERR
 | |
| EVENT_SEC_RX_RAM_SEC_ERR
 | |
| ....
 | |
| 
 | |
| Both codes of register interrupts and mc_event_handler() contain
 | |
| additional interrupts symbol names, these can not be re-used. So add a
 | |
| new plda_event_handler() functions, which implements PLDA interrupt
 | |
| defalt handler. Add request_event_irq() callback function to
 | |
| compat Microchip Polorfire PCIe additional interrupts.
 | |
| 
 | |
| Signed-off-by: Minda Chen <minda.chen@starfivetech.com>
 | |
| Acked-by: Conor Dooley <conor.dooley@microchip.com>
 | |
| Message-ID: <20240108110612.19048-13-minda.chen@starfivetech.com>
 | |
| Signed-off-by: Aurelien Jarno <aurelien@aurel32.net>
 | |
| ---
 | |
|  .../pci/controller/plda/pcie-microchip-host.c | 31 ++++++++++++++++---
 | |
|  drivers/pci/controller/plda/pcie-plda.h       |  5 +++
 | |
|  2 files changed, 32 insertions(+), 4 deletions(-)
 | |
| 
 | |
| diff --git a/drivers/pci/controller/plda/pcie-microchip-host.c b/drivers/pci/controller/plda/pcie-microchip-host.c
 | |
| index 0a5cd8b214cd..bf5ce33ee275 100644
 | |
| --- a/drivers/pci/controller/plda/pcie-microchip-host.c
 | |
| +++ b/drivers/pci/controller/plda/pcie-microchip-host.c
 | |
| @@ -642,6 +642,11 @@ static irqreturn_t mc_event_handler(int irq, void *dev_id)
 | |
|  	return IRQ_HANDLED;
 | |
|  }
 | |
|  
 | |
| +static irqreturn_t plda_event_handler(int irq, void *dev_id)
 | |
| +{
 | |
| +	return IRQ_HANDLED;
 | |
| +}
 | |
| +
 | |
|  static void plda_handle_event(struct irq_desc *desc)
 | |
|  {
 | |
|  	struct plda_pcie_rp *port = irq_desc_get_handler_data(desc);
 | |
| @@ -803,6 +808,17 @@ static int mc_pcie_init_clks(struct device *dev)
 | |
|  	return 0;
 | |
|  }
 | |
|  
 | |
| +static int mc_request_event_irq(struct plda_pcie_rp *plda, int event_irq,
 | |
| +				int event)
 | |
| +{
 | |
| +	return devm_request_irq(plda->dev, event_irq, mc_event_handler,
 | |
| +				0, event_cause[event].sym, plda);
 | |
| +}
 | |
| +
 | |
| +static const struct plda_event mc_event = {
 | |
| +	.request_event_irq = mc_request_event_irq,
 | |
| +};
 | |
| +
 | |
|  static int plda_pcie_init_irq_domains(struct plda_pcie_rp *port)
 | |
|  {
 | |
|  	struct device *dev = port->dev;
 | |
| @@ -904,7 +920,9 @@ static void mc_disable_interrupts(struct mc_pcie *port)
 | |
|  	writel_relaxed(GENMASK(31, 0), bridge_base_addr + ISTATUS_HOST);
 | |
|  }
 | |
|  
 | |
| -static int plda_init_interrupts(struct platform_device *pdev, struct plda_pcie_rp *port)
 | |
| +static int plda_init_interrupts(struct platform_device *pdev,
 | |
| +				struct plda_pcie_rp *port,
 | |
| +				const struct plda_event *event)
 | |
|  {
 | |
|  	struct device *dev = &pdev->dev;
 | |
|  	int irq;
 | |
| @@ -928,8 +946,13 @@ static int plda_init_interrupts(struct platform_device *pdev, struct plda_pcie_r
 | |
|  			return -ENXIO;
 | |
|  		}
 | |
|  
 | |
| -		ret = devm_request_irq(dev, event_irq, mc_event_handler,
 | |
| -				       0, event_cause[i].sym, port);
 | |
| +		if (event->request_event_irq)
 | |
| +			ret = event->request_event_irq(port, event_irq, i);
 | |
| +		else
 | |
| +			ret = devm_request_irq(dev, event_irq,
 | |
| +					       plda_event_handler,
 | |
| +					       0, NULL, port);
 | |
| +
 | |
|  		if (ret) {
 | |
|  			dev_err(dev, "failed to request IRQ %d\n", event_irq);
 | |
|  			return ret;
 | |
| @@ -983,7 +1006,7 @@ static int mc_platform_init(struct pci_config_window *cfg)
 | |
|  		return ret;
 | |
|  
 | |
|  	/* Address translation is up; safe to enable interrupts */
 | |
| -	ret = plda_init_interrupts(pdev, &port->plda);
 | |
| +	ret = plda_init_interrupts(pdev, &port->plda, &mc_event);
 | |
|  	if (ret)
 | |
|  		return ret;
 | |
|  
 | |
| diff --git a/drivers/pci/controller/plda/pcie-plda.h b/drivers/pci/controller/plda/pcie-plda.h
 | |
| index adfca9f28458..16b81b23c213 100644
 | |
| --- a/drivers/pci/controller/plda/pcie-plda.h
 | |
| +++ b/drivers/pci/controller/plda/pcie-plda.h
 | |
| @@ -127,6 +127,11 @@ struct plda_pcie_rp {
 | |
|  	int num_events;
 | |
|  };
 | |
|  
 | |
| +struct plda_event {
 | |
| +	int (*request_event_irq)(struct plda_pcie_rp *pcie,
 | |
| +				 int event_irq, int event);
 | |
| +};
 | |
| +
 | |
|  void plda_pcie_setup_window(void __iomem *bridge_base_addr, u32 index,
 | |
|  			    phys_addr_t axi_addr, phys_addr_t pci_addr,
 | |
|  			    size_t size);
 | |
| -- 
 | |
| 2.43.0
 | |
| 
 | |
| 
 | |
| From 5b7f9e79770f81f51a53a1adbd6bfb4f97ebe2e0 Mon Sep 17 00:00:00 2001
 | |
| From: Minda Chen <minda.chen@starfivetech.com>
 | |
| Date: Mon, 8 Jan 2024 19:06:03 +0800
 | |
| Subject: [PATCH 13/23] PCI: microchip: Add INTx and MSI event num to struct
 | |
|  plda_event
 | |
| 
 | |
| The INTx and MSI interrupt event num is different in Microchip and
 | |
| StarFive platform.
 | |
| 
 | |
| Signed-off-by: Minda Chen <minda.chen@starfivetech.com>
 | |
| Acked-by: Conor Dooley <conor.dooley@microchip.com>
 | |
| Message-ID: <20240108110612.19048-14-minda.chen@starfivetech.com>
 | |
| Signed-off-by: Aurelien Jarno <aurelien@aurel32.net>
 | |
| ---
 | |
|  drivers/pci/controller/plda/pcie-microchip-host.c | 6 ++++--
 | |
|  drivers/pci/controller/plda/pcie-plda.h           | 2 ++
 | |
|  2 files changed, 6 insertions(+), 2 deletions(-)
 | |
| 
 | |
| diff --git a/drivers/pci/controller/plda/pcie-microchip-host.c b/drivers/pci/controller/plda/pcie-microchip-host.c
 | |
| index bf5ce33ee275..8a51d3aa7e88 100644
 | |
| --- a/drivers/pci/controller/plda/pcie-microchip-host.c
 | |
| +++ b/drivers/pci/controller/plda/pcie-microchip-host.c
 | |
| @@ -817,6 +817,8 @@ static int mc_request_event_irq(struct plda_pcie_rp *plda, int event_irq,
 | |
|  
 | |
|  static const struct plda_event mc_event = {
 | |
|  	.request_event_irq = mc_request_event_irq,
 | |
| +	.intx_event        = EVENT_LOCAL_PM_MSI_INT_INTX,
 | |
| +	.msi_event         = EVENT_LOCAL_PM_MSI_INT_MSI,
 | |
|  };
 | |
|  
 | |
|  static int plda_pcie_init_irq_domains(struct plda_pcie_rp *port)
 | |
| @@ -960,7 +962,7 @@ static int plda_init_interrupts(struct platform_device *pdev,
 | |
|  	}
 | |
|  
 | |
|  	intx_irq = irq_create_mapping(port->event_domain,
 | |
| -				      EVENT_LOCAL_PM_MSI_INT_INTX);
 | |
| +				      event->intx_event);
 | |
|  	if (!intx_irq) {
 | |
|  		dev_err(dev, "failed to map INTx interrupt\n");
 | |
|  		return -ENXIO;
 | |
| @@ -970,7 +972,7 @@ static int plda_init_interrupts(struct platform_device *pdev,
 | |
|  	irq_set_chained_handler_and_data(intx_irq, plda_handle_intx, port);
 | |
|  
 | |
|  	msi_irq = irq_create_mapping(port->event_domain,
 | |
| -				     EVENT_LOCAL_PM_MSI_INT_MSI);
 | |
| +				     event->msi_event);
 | |
|  	if (!msi_irq)
 | |
|  		return -ENXIO;
 | |
|  
 | |
| diff --git a/drivers/pci/controller/plda/pcie-plda.h b/drivers/pci/controller/plda/pcie-plda.h
 | |
| index 16b81b23c213..0efe64d5f688 100644
 | |
| --- a/drivers/pci/controller/plda/pcie-plda.h
 | |
| +++ b/drivers/pci/controller/plda/pcie-plda.h
 | |
| @@ -130,6 +130,8 @@ struct plda_pcie_rp {
 | |
|  struct plda_event {
 | |
|  	int (*request_event_irq)(struct plda_pcie_rp *pcie,
 | |
|  				 int event_irq, int event);
 | |
| +	int intx_event;
 | |
| +	int msi_event;
 | |
|  };
 | |
|  
 | |
|  void plda_pcie_setup_window(void __iomem *bridge_base_addr, u32 index,
 | |
| -- 
 | |
| 2.43.0
 | |
| 
 | |
| 
 | |
| From 982d3f872fbf86323e7db898d02f3f0af36e4fa9 Mon Sep 17 00:00:00 2001
 | |
| From: Minda Chen <minda.chen@starfivetech.com>
 | |
| Date: Mon, 8 Jan 2024 19:06:04 +0800
 | |
| Subject: [PATCH 14/23] PCI: microchip: Add get_events() callback and add PLDA
 | |
|  get_event()
 | |
| 
 | |
| As PLDA dts binding doc(Documentation/devicetree/bindings/pci/
 | |
| plda,xpressrich3-axi-common.yaml) showes, PLDA PCIe contains an interrupt
 | |
| controller.
 | |
| 
 | |
| PolarFire implements its own PCIe interrupts, additional to the regular
 | |
| PCIe interrupts, due to lack of an MSI controller, so the interrupt to
 | |
| event number mapping is different to the PLDA regular interrupts,
 | |
| necessitating a custom get_events() implementation.
 | |
| 
 | |
| Microchip Polarfire PCIe additional intrerrupts:
 | |
| EVENT_PCIE_L2_EXIT
 | |
| EVENT_PCIE_HOTRST_EXIT
 | |
| EVENT_PCIE_DLUP_EXIT
 | |
| EVENT_SEC_TX_RAM_SEC_ERR
 | |
| EVENT_SEC_RX_RAM_SEC_ERR
 | |
| ....
 | |
| 
 | |
| plda_get_events() adds interrupt register to PLDA local event num mapping
 | |
| codes. All The PLDA interrupts can be seen in new added graph.
 | |
| 
 | |
| Signed-off-by: Minda Chen <minda.chen@starfivetech.com>
 | |
| Acked-by: Conor Dooley <conor.dooley@microchip.com>
 | |
| Message-ID: <20240108110612.19048-15-minda.chen@starfivetech.com>
 | |
| Signed-off-by: Aurelien Jarno <aurelien@aurel32.net>
 | |
| ---
 | |
|  .../pci/controller/plda/pcie-microchip-host.c | 35 ++++++++++++++++++-
 | |
|  drivers/pci/controller/plda/pcie-plda.h       | 32 +++++++++++++++++
 | |
|  2 files changed, 66 insertions(+), 1 deletion(-)
 | |
| 
 | |
| diff --git a/drivers/pci/controller/plda/pcie-microchip-host.c b/drivers/pci/controller/plda/pcie-microchip-host.c
 | |
| index 8a51d3aa7e88..b3df373a2141 100644
 | |
| --- a/drivers/pci/controller/plda/pcie-microchip-host.c
 | |
| +++ b/drivers/pci/controller/plda/pcie-microchip-host.c
 | |
| @@ -626,6 +626,26 @@ static u32 mc_get_events(struct plda_pcie_rp *port)
 | |
|  	return events;
 | |
|  }
 | |
|  
 | |
| +static u32 plda_get_events(struct plda_pcie_rp *port)
 | |
| +{
 | |
| +	u32 events, val, origin;
 | |
| +
 | |
| +	origin = readl_relaxed(port->bridge_addr + ISTATUS_LOCAL);
 | |
| +
 | |
| +	/* MSI event and sys events */
 | |
| +	val = (origin & SYS_AND_MSI_MASK) >> PM_MSI_INT_MSI_SHIFT;
 | |
| +	events = val << (PM_MSI_INT_MSI_SHIFT - PCI_NUM_INTX + 1);
 | |
| +
 | |
| +	/* INTx events */
 | |
| +	if (origin & PM_MSI_INT_INTX_MASK)
 | |
| +		events |= BIT(PM_MSI_INT_INTX_SHIFT);
 | |
| +
 | |
| +	/* remains are same with register */
 | |
| +	events |= origin & GENMASK(P_ATR_EVT_DOORBELL_SHIFT, 0);
 | |
| +
 | |
| +	return events;
 | |
| +}
 | |
| +
 | |
|  static irqreturn_t mc_event_handler(int irq, void *dev_id)
 | |
|  {
 | |
|  	struct plda_pcie_rp *port = dev_id;
 | |
| @@ -656,7 +676,7 @@ static void plda_handle_event(struct irq_desc *desc)
 | |
|  
 | |
|  	chained_irq_enter(chip, desc);
 | |
|  
 | |
| -	events = mc_get_events(port);
 | |
| +	events = port->event_ops->get_events(port);
 | |
|  
 | |
|  	for_each_set_bit(bit, &events, port->num_events)
 | |
|  		generic_handle_domain_irq(port->event_domain, bit);
 | |
| @@ -750,6 +770,10 @@ static struct irq_chip mc_event_irq_chip = {
 | |
|  	.irq_unmask = mc_unmask_event_irq,
 | |
|  };
 | |
|  
 | |
| +static const struct plda_event_ops plda_event_ops = {
 | |
| +	.get_events = plda_get_events,
 | |
| +};
 | |
| +
 | |
|  static int plda_pcie_event_map(struct irq_domain *domain, unsigned int irq,
 | |
|  			       irq_hw_number_t hwirq)
 | |
|  {
 | |
| @@ -815,6 +839,10 @@ static int mc_request_event_irq(struct plda_pcie_rp *plda, int event_irq,
 | |
|  				0, event_cause[event].sym, plda);
 | |
|  }
 | |
|  
 | |
| +static const struct plda_event_ops mc_event_ops = {
 | |
| +	.get_events = mc_get_events,
 | |
| +};
 | |
| +
 | |
|  static const struct plda_event mc_event = {
 | |
|  	.request_event_irq = mc_request_event_irq,
 | |
|  	.intx_event        = EVENT_LOCAL_PM_MSI_INT_INTX,
 | |
| @@ -931,6 +959,9 @@ static int plda_init_interrupts(struct platform_device *pdev,
 | |
|  	int i, intx_irq, msi_irq, event_irq;
 | |
|  	int ret;
 | |
|  
 | |
| +	if (!port->event_ops)
 | |
| +		port->event_ops = &plda_event_ops;
 | |
| +
 | |
|  	ret = plda_pcie_init_irq_domains(port);
 | |
|  	if (ret) {
 | |
|  		dev_err(dev, "failed creating IRQ domains\n");
 | |
| @@ -1007,6 +1038,8 @@ static int mc_platform_init(struct pci_config_window *cfg)
 | |
|  	if (ret)
 | |
|  		return ret;
 | |
|  
 | |
| +	port->plda.event_ops = &mc_event_ops;
 | |
| +
 | |
|  	/* Address translation is up; safe to enable interrupts */
 | |
|  	ret = plda_init_interrupts(pdev, &port->plda, &mc_event);
 | |
|  	if (ret)
 | |
| diff --git a/drivers/pci/controller/plda/pcie-plda.h b/drivers/pci/controller/plda/pcie-plda.h
 | |
| index 0efe64d5f688..9db92ccf286c 100644
 | |
| --- a/drivers/pci/controller/plda/pcie-plda.h
 | |
| +++ b/drivers/pci/controller/plda/pcie-plda.h
 | |
| @@ -58,6 +58,7 @@
 | |
|  #define  PM_MSI_INT_EVENTS_SHIFT		30
 | |
|  #define  PM_MSI_INT_SYS_ERR_MASK		0x80000000u
 | |
|  #define  PM_MSI_INT_SYS_ERR_SHIFT		31
 | |
| +#define  SYS_AND_MSI_MASK			GENMASK(31, 28)
 | |
|  #define  NUM_LOCAL_EVENTS			15
 | |
|  #define ISTATUS_LOCAL				0x184
 | |
|  #define IMASK_HOST				0x188
 | |
| @@ -108,6 +109,36 @@ enum plda_int_event {
 | |
|  
 | |
|  #define PLDA_MAX_INT_NUM			(PLDA_NUM_DMA_EVENTS + PLDA_INT_EVENT_NUM)
 | |
|  
 | |
| +/*
 | |
| + * PLDA interrupt register
 | |
| + *
 | |
| + * 31         27     23              15           7          0
 | |
| + * +--+--+--+-+------+-+-+-+-+-+-+-+-+-----------+-----------+
 | |
| + * |12|11|10|9| intx |7|6|5|4|3|2|1|0| DMA error | DMA end   |
 | |
| + * +--+--+--+-+------+-+-+-+-+-+-+-+-+-----------+-----------+
 | |
| + * bit 0-7  DMA interrupt end : reserved for vendor implement
 | |
| + * bit 8-15 DMA error : reserved for vendor implement
 | |
| + * 0:  AXI post error (PLDA_AXI_POST_ERR)
 | |
| + * 1:  AXI fetch error (PLDA_AXI_FETCH_ERR)
 | |
| + * 2:  AXI discard error (PLDA_AXI_DISCARD_ERR)
 | |
| + * 3:  AXI doorbell (PLDA_PCIE_DOORBELL)
 | |
| + * 4:  PCIe post error (PLDA_PCIE_POST_ERR)
 | |
| + * 5:  PCIe fetch error (PLDA_PCIE_FETCH_ERR)
 | |
| + * 6:  PCIe discard error (PLDA_PCIE_DISCARD_ERR)
 | |
| + * 7:  PCIe doorbell (PLDA_PCIE_DOORBELL)
 | |
| + * 8:  4 INTx interruts (PLDA_INTX)
 | |
| + * 9:  MSI interrupt (PLDA_MSI)
 | |
| + * 10: AER event (PLDA_AER_EVENT)
 | |
| + * 11: PM/LTR/Hotplug (PLDA_MISC_EVENTS)
 | |
| + * 12: System error (PLDA_SYS_ERR)
 | |
| + */
 | |
| +
 | |
| +struct plda_pcie_rp;
 | |
| +
 | |
| +struct plda_event_ops {
 | |
| +	u32 (*get_events)(struct plda_pcie_rp *pcie);
 | |
| +};
 | |
| +
 | |
|  struct plda_msi {
 | |
|  	struct mutex lock;		/* Protect used bitmap */
 | |
|  	struct irq_domain *msi_domain;
 | |
| @@ -123,6 +154,7 @@ struct plda_pcie_rp {
 | |
|  	struct irq_domain *event_domain;
 | |
|  	raw_spinlock_t lock;
 | |
|  	struct plda_msi msi;
 | |
| +	const struct plda_event_ops *event_ops;
 | |
|  	void __iomem *bridge_addr;
 | |
|  	int num_events;
 | |
|  };
 | |
| -- 
 | |
| 2.43.0
 | |
| 
 | |
| 
 | |
| From a4d9ec0a9ad3c0f3637b65c8dfd3ad3af5f38acc Mon Sep 17 00:00:00 2001
 | |
| From: Minda Chen <minda.chen@starfivetech.com>
 | |
| Date: Mon, 8 Jan 2024 19:06:05 +0800
 | |
| Subject: [PATCH 15/23] PCI: microchip: Add event irqchip field to host port
 | |
|  and add PLDA irqchip
 | |
| 
 | |
| As PLDA dts binding doc(Documentation/devicetree/bindings/pci/
 | |
| plda,xpressrich3-axi-common.yaml) showes, PLDA PCIe contains an interrupt
 | |
| controller.
 | |
| 
 | |
| Microchip PolarFire PCIE event IRQs includes PLDA interrupts and
 | |
| Polarfire their own interrupts. The interrupt irqchip ops includes
 | |
| ack/mask/unmask interrupt ops, which will write correct registers.
 | |
| Microchip Polarfire PCIe additional interrupts require to write Polarfire
 | |
| SoC self-defined registers. So Microchip PCIe event irqchip ops can not
 | |
| be re-used.
 | |
| 
 | |
| To support PLDA its own event IRQ process, implements PLDA irqchip ops and
 | |
| add event irqchip field to struct pcie_plda_rp.
 | |
| 
 | |
| Signed-off-by: Minda Chen <minda.chen@starfivetech.com>
 | |
| Acked-by: Conor Dooley <conor.dooley@microchip.com>
 | |
| Message-ID: <20240108110612.19048-16-minda.chen@starfivetech.com>
 | |
| Signed-off-by: Aurelien Jarno <aurelien@aurel32.net>
 | |
| ---
 | |
|  .../pci/controller/plda/pcie-microchip-host.c | 66 ++++++++++++++++++-
 | |
|  drivers/pci/controller/plda/pcie-plda.h       |  5 +-
 | |
|  2 files changed, 69 insertions(+), 2 deletions(-)
 | |
| 
 | |
| diff --git a/drivers/pci/controller/plda/pcie-microchip-host.c b/drivers/pci/controller/plda/pcie-microchip-host.c
 | |
| index b3df373a2141..beaf5c27da84 100644
 | |
| --- a/drivers/pci/controller/plda/pcie-microchip-host.c
 | |
| +++ b/drivers/pci/controller/plda/pcie-microchip-host.c
 | |
| @@ -770,6 +770,64 @@ static struct irq_chip mc_event_irq_chip = {
 | |
|  	.irq_unmask = mc_unmask_event_irq,
 | |
|  };
 | |
|  
 | |
| +static u32 plda_hwirq_to_mask(int hwirq)
 | |
| +{
 | |
| +	u32 mask;
 | |
| +
 | |
| +	/* hwirq 23 - 0 are the same with register */
 | |
| +	if (hwirq < EVENT_PM_MSI_INT_INTX)
 | |
| +		mask = BIT(hwirq);
 | |
| +	else if (hwirq == EVENT_PM_MSI_INT_INTX)
 | |
| +		mask = PM_MSI_INT_INTX_MASK;
 | |
| +	else
 | |
| +		mask = BIT(hwirq + PCI_NUM_INTX - 1);
 | |
| +
 | |
| +	return mask;
 | |
| +}
 | |
| +
 | |
| +static void plda_ack_event_irq(struct irq_data *data)
 | |
| +{
 | |
| +	struct plda_pcie_rp *port = irq_data_get_irq_chip_data(data);
 | |
| +
 | |
| +	writel_relaxed(plda_hwirq_to_mask(data->hwirq),
 | |
| +		       port->bridge_addr + ISTATUS_LOCAL);
 | |
| +}
 | |
| +
 | |
| +static void plda_mask_event_irq(struct irq_data *data)
 | |
| +{
 | |
| +	struct plda_pcie_rp *port = irq_data_get_irq_chip_data(data);
 | |
| +	u32 mask, val;
 | |
| +
 | |
| +	mask = plda_hwirq_to_mask(data->hwirq);
 | |
| +
 | |
| +	raw_spin_lock(&port->lock);
 | |
| +	val = readl_relaxed(port->bridge_addr + IMASK_LOCAL);
 | |
| +	val &= ~mask;
 | |
| +	writel_relaxed(val, port->bridge_addr + IMASK_LOCAL);
 | |
| +	raw_spin_unlock(&port->lock);
 | |
| +}
 | |
| +
 | |
| +static void plda_unmask_event_irq(struct irq_data *data)
 | |
| +{
 | |
| +	struct plda_pcie_rp *port = irq_data_get_irq_chip_data(data);
 | |
| +	u32 mask, val;
 | |
| +
 | |
| +	mask = plda_hwirq_to_mask(data->hwirq);
 | |
| +
 | |
| +	raw_spin_lock(&port->lock);
 | |
| +	val = readl_relaxed(port->bridge_addr + IMASK_LOCAL);
 | |
| +	val |= mask;
 | |
| +	writel_relaxed(val, port->bridge_addr + IMASK_LOCAL);
 | |
| +	raw_spin_unlock(&port->lock);
 | |
| +}
 | |
| +
 | |
| +static struct irq_chip plda_event_irq_chip = {
 | |
| +	.name = "PLDA PCIe EVENT",
 | |
| +	.irq_ack = plda_ack_event_irq,
 | |
| +	.irq_mask = plda_mask_event_irq,
 | |
| +	.irq_unmask = plda_unmask_event_irq,
 | |
| +};
 | |
| +
 | |
|  static const struct plda_event_ops plda_event_ops = {
 | |
|  	.get_events = plda_get_events,
 | |
|  };
 | |
| @@ -777,7 +835,9 @@ static const struct plda_event_ops plda_event_ops = {
 | |
|  static int plda_pcie_event_map(struct irq_domain *domain, unsigned int irq,
 | |
|  			       irq_hw_number_t hwirq)
 | |
|  {
 | |
| -	irq_set_chip_and_handler(irq, &mc_event_irq_chip, handle_level_irq);
 | |
| +	struct plda_pcie_rp *port = (void *)domain->host_data;
 | |
| +
 | |
| +	irq_set_chip_and_handler(irq, port->event_irq_chip, handle_level_irq);
 | |
|  	irq_set_chip_data(irq, domain->host_data);
 | |
|  
 | |
|  	return 0;
 | |
| @@ -962,6 +1022,9 @@ static int plda_init_interrupts(struct platform_device *pdev,
 | |
|  	if (!port->event_ops)
 | |
|  		port->event_ops = &plda_event_ops;
 | |
|  
 | |
| +	if (!port->event_irq_chip)
 | |
| +		port->event_irq_chip = &plda_event_irq_chip;
 | |
| +
 | |
|  	ret = plda_pcie_init_irq_domains(port);
 | |
|  	if (ret) {
 | |
|  		dev_err(dev, "failed creating IRQ domains\n");
 | |
| @@ -1039,6 +1102,7 @@ static int mc_platform_init(struct pci_config_window *cfg)
 | |
|  		return ret;
 | |
|  
 | |
|  	port->plda.event_ops = &mc_event_ops;
 | |
| +	port->plda.event_irq_chip = &mc_event_irq_chip;
 | |
|  
 | |
|  	/* Address translation is up; safe to enable interrupts */
 | |
|  	ret = plda_init_interrupts(pdev, &port->plda, &mc_event);
 | |
| diff --git a/drivers/pci/controller/plda/pcie-plda.h b/drivers/pci/controller/plda/pcie-plda.h
 | |
| index 9db92ccf286c..a3ce01735bea 100644
 | |
| --- a/drivers/pci/controller/plda/pcie-plda.h
 | |
| +++ b/drivers/pci/controller/plda/pcie-plda.h
 | |
| @@ -107,7 +107,9 @@ enum plda_int_event {
 | |
|  
 | |
|  #define PLDA_NUM_DMA_EVENTS			16
 | |
|  
 | |
| -#define PLDA_MAX_INT_NUM			(PLDA_NUM_DMA_EVENTS + PLDA_INT_EVENT_NUM)
 | |
| +#define EVENT_PM_MSI_INT_INTX			(PLDA_NUM_DMA_EVENTS + PLDA_INTX)
 | |
| +#define EVENT_PM_MSI_INT_MSI			(PLDA_NUM_DMA_EVENTS + PLDA_MSI)
 | |
| +#define PLDA_MAX_EVENT_NUM			(PLDA_NUM_DMA_EVENTS + PLDA_INT_EVENT_NUM)
 | |
|  
 | |
|  /*
 | |
|   * PLDA interrupt register
 | |
| @@ -155,6 +157,7 @@ struct plda_pcie_rp {
 | |
|  	raw_spinlock_t lock;
 | |
|  	struct plda_msi msi;
 | |
|  	const struct plda_event_ops *event_ops;
 | |
| +	const struct irq_chip *event_irq_chip;
 | |
|  	void __iomem *bridge_addr;
 | |
|  	int num_events;
 | |
|  };
 | |
| -- 
 | |
| 2.43.0
 | |
| 
 | |
| 
 | |
| From 874bc4a2048652f676823b6f728bae729f56fdfd Mon Sep 17 00:00:00 2001
 | |
| From: Minda Chen <minda.chen@starfivetech.com>
 | |
| Date: Mon, 8 Jan 2024 19:06:06 +0800
 | |
| Subject: [PATCH 16/23] PCI: microchip: Move IRQ functions to pcie-plda-host.c
 | |
| 
 | |
| Move IRQ related functions to pcie-plda-host.c for re-use these codes.
 | |
| Now Refactoring codes complete.
 | |
| 
 | |
| Including MSI, INTx, event interrupts and IRQ init functions.
 | |
| 
 | |
| Signed-off-by: Minda Chen <minda.chen@starfivetech.com>
 | |
| Acked-by: Conor Dooley <conor.dooley@microchip.com>
 | |
| Message-ID: <20240108110612.19048-17-minda.chen@starfivetech.com>
 | |
| Signed-off-by: Aurelien Jarno <aurelien@aurel32.net>
 | |
| ---
 | |
|  .../pci/controller/plda/pcie-microchip-host.c | 467 -----------------
 | |
|  drivers/pci/controller/plda/pcie-plda-host.c  | 472 ++++++++++++++++++
 | |
|  drivers/pci/controller/plda/pcie-plda.h       |   3 +
 | |
|  3 files changed, 475 insertions(+), 467 deletions(-)
 | |
| 
 | |
| diff --git a/drivers/pci/controller/plda/pcie-microchip-host.c b/drivers/pci/controller/plda/pcie-microchip-host.c
 | |
| index beaf5c27da84..105964306b71 100644
 | |
| --- a/drivers/pci/controller/plda/pcie-microchip-host.c
 | |
| +++ b/drivers/pci/controller/plda/pcie-microchip-host.c
 | |
| @@ -318,244 +318,6 @@ static void mc_pcie_enable_msi(struct mc_pcie *port, void __iomem *ecam)
 | |
|  		       ecam + MC_MSI_CAP_CTRL_OFFSET + PCI_MSI_ADDRESS_HI);
 | |
|  }
 | |
|  
 | |
| -static void plda_handle_msi(struct irq_desc *desc)
 | |
| -{
 | |
| -	struct plda_pcie_rp *port = irq_desc_get_handler_data(desc);
 | |
| -	struct irq_chip *chip = irq_desc_get_chip(desc);
 | |
| -	struct device *dev = port->dev;
 | |
| -	struct plda_msi *msi = &port->msi;
 | |
| -	void __iomem *bridge_base_addr = port->bridge_addr;
 | |
| -	unsigned long status;
 | |
| -	u32 bit;
 | |
| -	int ret;
 | |
| -
 | |
| -	chained_irq_enter(chip, desc);
 | |
| -
 | |
| -	status = readl_relaxed(bridge_base_addr + ISTATUS_LOCAL);
 | |
| -	if (status & PM_MSI_INT_MSI_MASK) {
 | |
| -		writel_relaxed(status & PM_MSI_INT_MSI_MASK, bridge_base_addr + ISTATUS_LOCAL);
 | |
| -		status = readl_relaxed(bridge_base_addr + ISTATUS_MSI);
 | |
| -		for_each_set_bit(bit, &status, msi->num_vectors) {
 | |
| -			ret = generic_handle_domain_irq(msi->dev_domain, bit);
 | |
| -			if (ret)
 | |
| -				dev_err_ratelimited(dev, "bad MSI IRQ %d\n",
 | |
| -						    bit);
 | |
| -		}
 | |
| -	}
 | |
| -
 | |
| -	chained_irq_exit(chip, desc);
 | |
| -}
 | |
| -
 | |
| -static void plda_msi_bottom_irq_ack(struct irq_data *data)
 | |
| -{
 | |
| -	struct plda_pcie_rp *port = irq_data_get_irq_chip_data(data);
 | |
| -	void __iomem *bridge_base_addr = port->bridge_addr;
 | |
| -	u32 bitpos = data->hwirq;
 | |
| -
 | |
| -	writel_relaxed(BIT(bitpos), bridge_base_addr + ISTATUS_MSI);
 | |
| -}
 | |
| -
 | |
| -static void plda_compose_msi_msg(struct irq_data *data, struct msi_msg *msg)
 | |
| -{
 | |
| -	struct plda_pcie_rp *port = irq_data_get_irq_chip_data(data);
 | |
| -	phys_addr_t addr = port->msi.vector_phy;
 | |
| -
 | |
| -	msg->address_lo = lower_32_bits(addr);
 | |
| -	msg->address_hi = upper_32_bits(addr);
 | |
| -	msg->data = data->hwirq;
 | |
| -
 | |
| -	dev_dbg(port->dev, "msi#%x address_hi %#x address_lo %#x\n",
 | |
| -		(int)data->hwirq, msg->address_hi, msg->address_lo);
 | |
| -}
 | |
| -
 | |
| -static int plda_msi_set_affinity(struct irq_data *irq_data,
 | |
| -				 const struct cpumask *mask, bool force)
 | |
| -{
 | |
| -	return -EINVAL;
 | |
| -}
 | |
| -
 | |
| -static struct irq_chip plda_msi_bottom_irq_chip = {
 | |
| -	.name = "PLDA MSI",
 | |
| -	.irq_ack = plda_msi_bottom_irq_ack,
 | |
| -	.irq_compose_msi_msg = plda_compose_msi_msg,
 | |
| -	.irq_set_affinity = plda_msi_set_affinity,
 | |
| -};
 | |
| -
 | |
| -static int plda_irq_msi_domain_alloc(struct irq_domain *domain,
 | |
| -				     unsigned int virq,
 | |
| -				     unsigned int nr_irqs,
 | |
| -				     void *args)
 | |
| -{
 | |
| -	struct plda_pcie_rp *port = domain->host_data;
 | |
| -	struct plda_msi *msi = &port->msi;
 | |
| -	unsigned long bit;
 | |
| -
 | |
| -	mutex_lock(&msi->lock);
 | |
| -	bit = find_first_zero_bit(msi->used, msi->num_vectors);
 | |
| -	if (bit >= msi->num_vectors) {
 | |
| -		mutex_unlock(&msi->lock);
 | |
| -		return -ENOSPC;
 | |
| -	}
 | |
| -
 | |
| -	set_bit(bit, msi->used);
 | |
| -
 | |
| -	irq_domain_set_info(domain, virq, bit, &plda_msi_bottom_irq_chip,
 | |
| -			    domain->host_data, handle_edge_irq, NULL, NULL);
 | |
| -
 | |
| -	mutex_unlock(&msi->lock);
 | |
| -
 | |
| -	return 0;
 | |
| -}
 | |
| -
 | |
| -static void plda_irq_msi_domain_free(struct irq_domain *domain,
 | |
| -				     unsigned int virq,
 | |
| -				     unsigned int nr_irqs)
 | |
| -{
 | |
| -	struct irq_data *d = irq_domain_get_irq_data(domain, virq);
 | |
| -	struct plda_pcie_rp *port = irq_data_get_irq_chip_data(d);
 | |
| -	struct plda_msi *msi = &port->msi;
 | |
| -
 | |
| -	mutex_lock(&msi->lock);
 | |
| -
 | |
| -	if (test_bit(d->hwirq, msi->used))
 | |
| -		__clear_bit(d->hwirq, msi->used);
 | |
| -	else
 | |
| -		dev_err(port->dev, "trying to free unused MSI%lu\n", d->hwirq);
 | |
| -
 | |
| -	mutex_unlock(&msi->lock);
 | |
| -}
 | |
| -
 | |
| -static const struct irq_domain_ops msi_domain_ops = {
 | |
| -	.alloc	= plda_irq_msi_domain_alloc,
 | |
| -	.free	= plda_irq_msi_domain_free,
 | |
| -};
 | |
| -
 | |
| -static struct irq_chip plda_msi_irq_chip = {
 | |
| -	.name = "PLDA PCIe MSI",
 | |
| -	.irq_ack = irq_chip_ack_parent,
 | |
| -	.irq_mask = pci_msi_mask_irq,
 | |
| -	.irq_unmask = pci_msi_unmask_irq,
 | |
| -};
 | |
| -
 | |
| -static struct msi_domain_info plda_msi_domain_info = {
 | |
| -	.flags = (MSI_FLAG_USE_DEF_DOM_OPS | MSI_FLAG_USE_DEF_CHIP_OPS |
 | |
| -		  MSI_FLAG_PCI_MSIX),
 | |
| -	.chip = &plda_msi_irq_chip,
 | |
| -};
 | |
| -
 | |
| -static int plda_allocate_msi_domains(struct plda_pcie_rp *port)
 | |
| -{
 | |
| -	struct device *dev = port->dev;
 | |
| -	struct fwnode_handle *fwnode = of_node_to_fwnode(dev->of_node);
 | |
| -	struct plda_msi *msi = &port->msi;
 | |
| -
 | |
| -	mutex_init(&port->msi.lock);
 | |
| -
 | |
| -	msi->dev_domain = irq_domain_add_linear(NULL, msi->num_vectors,
 | |
| -						&msi_domain_ops, port);
 | |
| -	if (!msi->dev_domain) {
 | |
| -		dev_err(dev, "failed to create IRQ domain\n");
 | |
| -		return -ENOMEM;
 | |
| -	}
 | |
| -
 | |
| -	msi->msi_domain = pci_msi_create_irq_domain(fwnode,
 | |
| -						    &plda_msi_domain_info,
 | |
| -						    msi->dev_domain);
 | |
| -	if (!msi->msi_domain) {
 | |
| -		dev_err(dev, "failed to create MSI domain\n");
 | |
| -		irq_domain_remove(msi->dev_domain);
 | |
| -		return -ENOMEM;
 | |
| -	}
 | |
| -
 | |
| -	return 0;
 | |
| -}
 | |
| -
 | |
| -static void plda_handle_intx(struct irq_desc *desc)
 | |
| -{
 | |
| -	struct plda_pcie_rp *port = irq_desc_get_handler_data(desc);
 | |
| -	struct irq_chip *chip = irq_desc_get_chip(desc);
 | |
| -	struct device *dev = port->dev;
 | |
| -	void __iomem *bridge_base_addr = port->bridge_addr;
 | |
| -	unsigned long status;
 | |
| -	u32 bit;
 | |
| -	int ret;
 | |
| -
 | |
| -	chained_irq_enter(chip, desc);
 | |
| -
 | |
| -	status = readl_relaxed(bridge_base_addr + ISTATUS_LOCAL);
 | |
| -	if (status & PM_MSI_INT_INTX_MASK) {
 | |
| -		status &= PM_MSI_INT_INTX_MASK;
 | |
| -		status >>= PM_MSI_INT_INTX_SHIFT;
 | |
| -		for_each_set_bit(bit, &status, PCI_NUM_INTX) {
 | |
| -			ret = generic_handle_domain_irq(port->intx_domain, bit);
 | |
| -			if (ret)
 | |
| -				dev_err_ratelimited(dev, "bad INTx IRQ %d\n",
 | |
| -						    bit);
 | |
| -		}
 | |
| -	}
 | |
| -
 | |
| -	chained_irq_exit(chip, desc);
 | |
| -}
 | |
| -
 | |
| -static void plda_ack_intx_irq(struct irq_data *data)
 | |
| -{
 | |
| -	struct plda_pcie_rp *port = irq_data_get_irq_chip_data(data);
 | |
| -	void __iomem *bridge_base_addr = port->bridge_addr;
 | |
| -	u32 mask = BIT(data->hwirq + PM_MSI_INT_INTX_SHIFT);
 | |
| -
 | |
| -	writel_relaxed(mask, bridge_base_addr + ISTATUS_LOCAL);
 | |
| -}
 | |
| -
 | |
| -static void plda_mask_intx_irq(struct irq_data *data)
 | |
| -{
 | |
| -	struct plda_pcie_rp *port = irq_data_get_irq_chip_data(data);
 | |
| -	void __iomem *bridge_base_addr = port->bridge_addr;
 | |
| -	unsigned long flags;
 | |
| -	u32 mask = BIT(data->hwirq + PM_MSI_INT_INTX_SHIFT);
 | |
| -	u32 val;
 | |
| -
 | |
| -	raw_spin_lock_irqsave(&port->lock, flags);
 | |
| -	val = readl_relaxed(bridge_base_addr + IMASK_LOCAL);
 | |
| -	val &= ~mask;
 | |
| -	writel_relaxed(val, bridge_base_addr + IMASK_LOCAL);
 | |
| -	raw_spin_unlock_irqrestore(&port->lock, flags);
 | |
| -}
 | |
| -
 | |
| -static void plda_unmask_intx_irq(struct irq_data *data)
 | |
| -{
 | |
| -	struct plda_pcie_rp *port = irq_data_get_irq_chip_data(data);
 | |
| -	void __iomem *bridge_base_addr = port->bridge_addr;
 | |
| -	unsigned long flags;
 | |
| -	u32 mask = BIT(data->hwirq + PM_MSI_INT_INTX_SHIFT);
 | |
| -	u32 val;
 | |
| -
 | |
| -	raw_spin_lock_irqsave(&port->lock, flags);
 | |
| -	val = readl_relaxed(bridge_base_addr + IMASK_LOCAL);
 | |
| -	val |= mask;
 | |
| -	writel_relaxed(val, bridge_base_addr + IMASK_LOCAL);
 | |
| -	raw_spin_unlock_irqrestore(&port->lock, flags);
 | |
| -}
 | |
| -
 | |
| -static struct irq_chip plda_intx_irq_chip = {
 | |
| -	.name = "PLDA PCIe INTx",
 | |
| -	.irq_ack = plda_ack_intx_irq,
 | |
| -	.irq_mask = plda_mask_intx_irq,
 | |
| -	.irq_unmask = plda_unmask_intx_irq,
 | |
| -};
 | |
| -
 | |
| -static int plda_pcie_intx_map(struct irq_domain *domain, unsigned int irq,
 | |
| -			      irq_hw_number_t hwirq)
 | |
| -{
 | |
| -	irq_set_chip_and_handler(irq, &plda_intx_irq_chip, handle_level_irq);
 | |
| -	irq_set_chip_data(irq, domain->host_data);
 | |
| -
 | |
| -	return 0;
 | |
| -}
 | |
| -
 | |
| -static const struct irq_domain_ops intx_domain_ops = {
 | |
| -	.map = plda_pcie_intx_map,
 | |
| -};
 | |
| -
 | |
|  static inline u32 reg_to_event(u32 reg, struct event_map field)
 | |
|  {
 | |
|  	return (reg & field.reg_mask) ? BIT(field.event_bit) : 0;
 | |
| @@ -626,26 +388,6 @@ static u32 mc_get_events(struct plda_pcie_rp *port)
 | |
|  	return events;
 | |
|  }
 | |
|  
 | |
| -static u32 plda_get_events(struct plda_pcie_rp *port)
 | |
| -{
 | |
| -	u32 events, val, origin;
 | |
| -
 | |
| -	origin = readl_relaxed(port->bridge_addr + ISTATUS_LOCAL);
 | |
| -
 | |
| -	/* MSI event and sys events */
 | |
| -	val = (origin & SYS_AND_MSI_MASK) >> PM_MSI_INT_MSI_SHIFT;
 | |
| -	events = val << (PM_MSI_INT_MSI_SHIFT - PCI_NUM_INTX + 1);
 | |
| -
 | |
| -	/* INTx events */
 | |
| -	if (origin & PM_MSI_INT_INTX_MASK)
 | |
| -		events |= BIT(PM_MSI_INT_INTX_SHIFT);
 | |
| -
 | |
| -	/* remains are same with register */
 | |
| -	events |= origin & GENMASK(P_ATR_EVT_DOORBELL_SHIFT, 0);
 | |
| -
 | |
| -	return events;
 | |
| -}
 | |
| -
 | |
|  static irqreturn_t mc_event_handler(int irq, void *dev_id)
 | |
|  {
 | |
|  	struct plda_pcie_rp *port = dev_id;
 | |
| @@ -662,28 +404,6 @@ static irqreturn_t mc_event_handler(int irq, void *dev_id)
 | |
|  	return IRQ_HANDLED;
 | |
|  }
 | |
|  
 | |
| -static irqreturn_t plda_event_handler(int irq, void *dev_id)
 | |
| -{
 | |
| -	return IRQ_HANDLED;
 | |
| -}
 | |
| -
 | |
| -static void plda_handle_event(struct irq_desc *desc)
 | |
| -{
 | |
| -	struct plda_pcie_rp *port = irq_desc_get_handler_data(desc);
 | |
| -	unsigned long events;
 | |
| -	u32 bit;
 | |
| -	struct irq_chip *chip = irq_desc_get_chip(desc);
 | |
| -
 | |
| -	chained_irq_enter(chip, desc);
 | |
| -
 | |
| -	events = port->event_ops->get_events(port);
 | |
| -
 | |
| -	for_each_set_bit(bit, &events, port->num_events)
 | |
| -		generic_handle_domain_irq(port->event_domain, bit);
 | |
| -
 | |
| -	chained_irq_exit(chip, desc);
 | |
| -}
 | |
| -
 | |
|  static void mc_ack_event_irq(struct irq_data *data)
 | |
|  {
 | |
|  	struct plda_pcie_rp *port = irq_data_get_irq_chip_data(data);
 | |
| @@ -770,83 +490,6 @@ static struct irq_chip mc_event_irq_chip = {
 | |
|  	.irq_unmask = mc_unmask_event_irq,
 | |
|  };
 | |
|  
 | |
| -static u32 plda_hwirq_to_mask(int hwirq)
 | |
| -{
 | |
| -	u32 mask;
 | |
| -
 | |
| -	/* hwirq 23 - 0 are the same with register */
 | |
| -	if (hwirq < EVENT_PM_MSI_INT_INTX)
 | |
| -		mask = BIT(hwirq);
 | |
| -	else if (hwirq == EVENT_PM_MSI_INT_INTX)
 | |
| -		mask = PM_MSI_INT_INTX_MASK;
 | |
| -	else
 | |
| -		mask = BIT(hwirq + PCI_NUM_INTX - 1);
 | |
| -
 | |
| -	return mask;
 | |
| -}
 | |
| -
 | |
| -static void plda_ack_event_irq(struct irq_data *data)
 | |
| -{
 | |
| -	struct plda_pcie_rp *port = irq_data_get_irq_chip_data(data);
 | |
| -
 | |
| -	writel_relaxed(plda_hwirq_to_mask(data->hwirq),
 | |
| -		       port->bridge_addr + ISTATUS_LOCAL);
 | |
| -}
 | |
| -
 | |
| -static void plda_mask_event_irq(struct irq_data *data)
 | |
| -{
 | |
| -	struct plda_pcie_rp *port = irq_data_get_irq_chip_data(data);
 | |
| -	u32 mask, val;
 | |
| -
 | |
| -	mask = plda_hwirq_to_mask(data->hwirq);
 | |
| -
 | |
| -	raw_spin_lock(&port->lock);
 | |
| -	val = readl_relaxed(port->bridge_addr + IMASK_LOCAL);
 | |
| -	val &= ~mask;
 | |
| -	writel_relaxed(val, port->bridge_addr + IMASK_LOCAL);
 | |
| -	raw_spin_unlock(&port->lock);
 | |
| -}
 | |
| -
 | |
| -static void plda_unmask_event_irq(struct irq_data *data)
 | |
| -{
 | |
| -	struct plda_pcie_rp *port = irq_data_get_irq_chip_data(data);
 | |
| -	u32 mask, val;
 | |
| -
 | |
| -	mask = plda_hwirq_to_mask(data->hwirq);
 | |
| -
 | |
| -	raw_spin_lock(&port->lock);
 | |
| -	val = readl_relaxed(port->bridge_addr + IMASK_LOCAL);
 | |
| -	val |= mask;
 | |
| -	writel_relaxed(val, port->bridge_addr + IMASK_LOCAL);
 | |
| -	raw_spin_unlock(&port->lock);
 | |
| -}
 | |
| -
 | |
| -static struct irq_chip plda_event_irq_chip = {
 | |
| -	.name = "PLDA PCIe EVENT",
 | |
| -	.irq_ack = plda_ack_event_irq,
 | |
| -	.irq_mask = plda_mask_event_irq,
 | |
| -	.irq_unmask = plda_unmask_event_irq,
 | |
| -};
 | |
| -
 | |
| -static const struct plda_event_ops plda_event_ops = {
 | |
| -	.get_events = plda_get_events,
 | |
| -};
 | |
| -
 | |
| -static int plda_pcie_event_map(struct irq_domain *domain, unsigned int irq,
 | |
| -			       irq_hw_number_t hwirq)
 | |
| -{
 | |
| -	struct plda_pcie_rp *port = (void *)domain->host_data;
 | |
| -
 | |
| -	irq_set_chip_and_handler(irq, port->event_irq_chip, handle_level_irq);
 | |
| -	irq_set_chip_data(irq, domain->host_data);
 | |
| -
 | |
| -	return 0;
 | |
| -}
 | |
| -
 | |
| -static const struct irq_domain_ops plda_event_domain_ops = {
 | |
| -	.map = plda_pcie_event_map,
 | |
| -};
 | |
| -
 | |
|  static inline void mc_pcie_deinit_clk(void *data)
 | |
|  {
 | |
|  	struct clk *clk = data;
 | |
| @@ -909,47 +552,6 @@ static const struct plda_event mc_event = {
 | |
|  	.msi_event         = EVENT_LOCAL_PM_MSI_INT_MSI,
 | |
|  };
 | |
|  
 | |
| -static int plda_pcie_init_irq_domains(struct plda_pcie_rp *port)
 | |
| -{
 | |
| -	struct device *dev = port->dev;
 | |
| -	struct device_node *node = dev->of_node;
 | |
| -	struct device_node *pcie_intc_node;
 | |
| -
 | |
| -	/* Setup INTx */
 | |
| -	pcie_intc_node = of_get_next_child(node, NULL);
 | |
| -	if (!pcie_intc_node) {
 | |
| -		dev_err(dev, "failed to find PCIe Intc node\n");
 | |
| -		return -EINVAL;
 | |
| -	}
 | |
| -
 | |
| -	port->event_domain = irq_domain_add_linear(pcie_intc_node,
 | |
| -						   port->num_events,
 | |
| -						   &plda_event_domain_ops,
 | |
| -						   port);
 | |
| -	if (!port->event_domain) {
 | |
| -		dev_err(dev, "failed to get event domain\n");
 | |
| -		of_node_put(pcie_intc_node);
 | |
| -		return -ENOMEM;
 | |
| -	}
 | |
| -
 | |
| -	irq_domain_update_bus_token(port->event_domain, DOMAIN_BUS_NEXUS);
 | |
| -
 | |
| -	port->intx_domain = irq_domain_add_linear(pcie_intc_node, PCI_NUM_INTX,
 | |
| -						  &intx_domain_ops, port);
 | |
| -	if (!port->intx_domain) {
 | |
| -		dev_err(dev, "failed to get an INTx IRQ domain\n");
 | |
| -		of_node_put(pcie_intc_node);
 | |
| -		return -ENOMEM;
 | |
| -	}
 | |
| -
 | |
| -	irq_domain_update_bus_token(port->intx_domain, DOMAIN_BUS_WIRED);
 | |
| -
 | |
| -	of_node_put(pcie_intc_node);
 | |
| -	raw_spin_lock_init(&port->lock);
 | |
| -
 | |
| -	return plda_allocate_msi_domains(port);
 | |
| -}
 | |
| -
 | |
|  static inline void mc_clear_secs(struct mc_pcie *port)
 | |
|  {
 | |
|  	void __iomem *ctrl_base_addr = port->axi_base_addr + MC_PCIE_CTRL_ADDR;
 | |
| @@ -1010,75 +612,6 @@ static void mc_disable_interrupts(struct mc_pcie *port)
 | |
|  	writel_relaxed(GENMASK(31, 0), bridge_base_addr + ISTATUS_HOST);
 | |
|  }
 | |
|  
 | |
| -static int plda_init_interrupts(struct platform_device *pdev,
 | |
| -				struct plda_pcie_rp *port,
 | |
| -				const struct plda_event *event)
 | |
| -{
 | |
| -	struct device *dev = &pdev->dev;
 | |
| -	int irq;
 | |
| -	int i, intx_irq, msi_irq, event_irq;
 | |
| -	int ret;
 | |
| -
 | |
| -	if (!port->event_ops)
 | |
| -		port->event_ops = &plda_event_ops;
 | |
| -
 | |
| -	if (!port->event_irq_chip)
 | |
| -		port->event_irq_chip = &plda_event_irq_chip;
 | |
| -
 | |
| -	ret = plda_pcie_init_irq_domains(port);
 | |
| -	if (ret) {
 | |
| -		dev_err(dev, "failed creating IRQ domains\n");
 | |
| -		return ret;
 | |
| -	}
 | |
| -
 | |
| -	irq = platform_get_irq(pdev, 0);
 | |
| -	if (irq < 0)
 | |
| -		return -ENODEV;
 | |
| -
 | |
| -	for (i = 0; i < port->num_events; i++) {
 | |
| -		event_irq = irq_create_mapping(port->event_domain, i);
 | |
| -		if (!event_irq) {
 | |
| -			dev_err(dev, "failed to map hwirq %d\n", i);
 | |
| -			return -ENXIO;
 | |
| -		}
 | |
| -
 | |
| -		if (event->request_event_irq)
 | |
| -			ret = event->request_event_irq(port, event_irq, i);
 | |
| -		else
 | |
| -			ret = devm_request_irq(dev, event_irq,
 | |
| -					       plda_event_handler,
 | |
| -					       0, NULL, port);
 | |
| -
 | |
| -		if (ret) {
 | |
| -			dev_err(dev, "failed to request IRQ %d\n", event_irq);
 | |
| -			return ret;
 | |
| -		}
 | |
| -	}
 | |
| -
 | |
| -	intx_irq = irq_create_mapping(port->event_domain,
 | |
| -				      event->intx_event);
 | |
| -	if (!intx_irq) {
 | |
| -		dev_err(dev, "failed to map INTx interrupt\n");
 | |
| -		return -ENXIO;
 | |
| -	}
 | |
| -
 | |
| -	/* Plug the INTx chained handler */
 | |
| -	irq_set_chained_handler_and_data(intx_irq, plda_handle_intx, port);
 | |
| -
 | |
| -	msi_irq = irq_create_mapping(port->event_domain,
 | |
| -				     event->msi_event);
 | |
| -	if (!msi_irq)
 | |
| -		return -ENXIO;
 | |
| -
 | |
| -	/* Plug the MSI chained handler */
 | |
| -	irq_set_chained_handler_and_data(msi_irq, plda_handle_msi, port);
 | |
| -
 | |
| -	/* Plug the main event chained handler */
 | |
| -	irq_set_chained_handler_and_data(irq, plda_handle_event, port);
 | |
| -
 | |
| -	return 0;
 | |
| -}
 | |
| -
 | |
|  static int mc_platform_init(struct pci_config_window *cfg)
 | |
|  {
 | |
|  	struct device *dev = cfg->parent;
 | |
| diff --git a/drivers/pci/controller/plda/pcie-plda-host.c b/drivers/pci/controller/plda/pcie-plda-host.c
 | |
| index 40139d998568..98c51e594efe 100644
 | |
| --- a/drivers/pci/controller/plda/pcie-plda-host.c
 | |
| +++ b/drivers/pci/controller/plda/pcie-plda-host.c
 | |
| @@ -7,11 +7,483 @@
 | |
|   * Author: Daire McNamara <daire.mcnamara@microchip.com>
 | |
|   */
 | |
|  
 | |
| +#include <linux/irqchip/chained_irq.h>
 | |
| +#include <linux/irqdomain.h>
 | |
| +#include <linux/msi.h>
 | |
|  #include <linux/pci_regs.h>
 | |
|  #include <linux/pci-ecam.h>
 | |
|  
 | |
|  #include "pcie-plda.h"
 | |
|  
 | |
| +static void plda_handle_msi(struct irq_desc *desc)
 | |
| +{
 | |
| +	struct plda_pcie_rp *port = irq_desc_get_handler_data(desc);
 | |
| +	struct irq_chip *chip = irq_desc_get_chip(desc);
 | |
| +	struct device *dev = port->dev;
 | |
| +	struct plda_msi *msi = &port->msi;
 | |
| +	void __iomem *bridge_base_addr = port->bridge_addr;
 | |
| +	unsigned long status;
 | |
| +	u32 bit;
 | |
| +	int ret;
 | |
| +
 | |
| +	chained_irq_enter(chip, desc);
 | |
| +
 | |
| +	status = readl_relaxed(bridge_base_addr + ISTATUS_LOCAL);
 | |
| +	if (status & PM_MSI_INT_MSI_MASK) {
 | |
| +		writel_relaxed(status & PM_MSI_INT_MSI_MASK,
 | |
| +			       bridge_base_addr + ISTATUS_LOCAL);
 | |
| +		status = readl_relaxed(bridge_base_addr + ISTATUS_MSI);
 | |
| +		for_each_set_bit(bit, &status, msi->num_vectors) {
 | |
| +			ret = generic_handle_domain_irq(msi->dev_domain, bit);
 | |
| +			if (ret)
 | |
| +				dev_err_ratelimited(dev, "bad MSI IRQ %d\n",
 | |
| +						    bit);
 | |
| +		}
 | |
| +	}
 | |
| +
 | |
| +	chained_irq_exit(chip, desc);
 | |
| +}
 | |
| +
 | |
| +static void plda_msi_bottom_irq_ack(struct irq_data *data)
 | |
| +{
 | |
| +	struct plda_pcie_rp *port = irq_data_get_irq_chip_data(data);
 | |
| +	void __iomem *bridge_base_addr = port->bridge_addr;
 | |
| +	u32 bitpos = data->hwirq;
 | |
| +
 | |
| +	writel_relaxed(BIT(bitpos), bridge_base_addr + ISTATUS_MSI);
 | |
| +}
 | |
| +
 | |
| +static void plda_compose_msi_msg(struct irq_data *data, struct msi_msg *msg)
 | |
| +{
 | |
| +	struct plda_pcie_rp *port = irq_data_get_irq_chip_data(data);
 | |
| +	phys_addr_t addr = port->msi.vector_phy;
 | |
| +
 | |
| +	msg->address_lo = lower_32_bits(addr);
 | |
| +	msg->address_hi = upper_32_bits(addr);
 | |
| +	msg->data = data->hwirq;
 | |
| +
 | |
| +	dev_dbg(port->dev, "msi#%x address_hi %#x address_lo %#x\n",
 | |
| +		(int)data->hwirq, msg->address_hi, msg->address_lo);
 | |
| +}
 | |
| +
 | |
| +static int plda_msi_set_affinity(struct irq_data *irq_data,
 | |
| +				 const struct cpumask *mask, bool force)
 | |
| +{
 | |
| +	return -EINVAL;
 | |
| +}
 | |
| +
 | |
| +static struct irq_chip plda_msi_bottom_irq_chip = {
 | |
| +	.name = "PLDA MSI",
 | |
| +	.irq_ack = plda_msi_bottom_irq_ack,
 | |
| +	.irq_compose_msi_msg = plda_compose_msi_msg,
 | |
| +	.irq_set_affinity = plda_msi_set_affinity,
 | |
| +};
 | |
| +
 | |
| +static int plda_irq_msi_domain_alloc(struct irq_domain *domain,
 | |
| +				     unsigned int virq,
 | |
| +				     unsigned int nr_irqs,
 | |
| +				     void *args)
 | |
| +{
 | |
| +	struct plda_pcie_rp *port = domain->host_data;
 | |
| +	struct plda_msi *msi = &port->msi;
 | |
| +	unsigned long bit;
 | |
| +
 | |
| +	mutex_lock(&msi->lock);
 | |
| +	bit = find_first_zero_bit(msi->used, msi->num_vectors);
 | |
| +	if (bit >= msi->num_vectors) {
 | |
| +		mutex_unlock(&msi->lock);
 | |
| +		return -ENOSPC;
 | |
| +	}
 | |
| +
 | |
| +	set_bit(bit, msi->used);
 | |
| +
 | |
| +	irq_domain_set_info(domain, virq, bit, &plda_msi_bottom_irq_chip,
 | |
| +			    domain->host_data, handle_edge_irq, NULL, NULL);
 | |
| +
 | |
| +	mutex_unlock(&msi->lock);
 | |
| +
 | |
| +	return 0;
 | |
| +}
 | |
| +
 | |
| +static void plda_irq_msi_domain_free(struct irq_domain *domain,
 | |
| +				     unsigned int virq,
 | |
| +				     unsigned int nr_irqs)
 | |
| +{
 | |
| +	struct irq_data *d = irq_domain_get_irq_data(domain, virq);
 | |
| +	struct plda_pcie_rp *port = irq_data_get_irq_chip_data(d);
 | |
| +	struct plda_msi *msi = &port->msi;
 | |
| +
 | |
| +	mutex_lock(&msi->lock);
 | |
| +
 | |
| +	if (test_bit(d->hwirq, msi->used))
 | |
| +		__clear_bit(d->hwirq, msi->used);
 | |
| +	else
 | |
| +		dev_err(port->dev, "trying to free unused MSI%lu\n", d->hwirq);
 | |
| +
 | |
| +	mutex_unlock(&msi->lock);
 | |
| +}
 | |
| +
 | |
| +static const struct irq_domain_ops msi_domain_ops = {
 | |
| +	.alloc	= plda_irq_msi_domain_alloc,
 | |
| +	.free	= plda_irq_msi_domain_free,
 | |
| +};
 | |
| +
 | |
| +static struct irq_chip plda_msi_irq_chip = {
 | |
| +	.name = "PLDA PCIe MSI",
 | |
| +	.irq_ack = irq_chip_ack_parent,
 | |
| +	.irq_mask = pci_msi_mask_irq,
 | |
| +	.irq_unmask = pci_msi_unmask_irq,
 | |
| +};
 | |
| +
 | |
| +static struct msi_domain_info plda_msi_domain_info = {
 | |
| +	.flags = (MSI_FLAG_USE_DEF_DOM_OPS | MSI_FLAG_USE_DEF_CHIP_OPS |
 | |
| +		  MSI_FLAG_PCI_MSIX),
 | |
| +	.chip = &plda_msi_irq_chip,
 | |
| +};
 | |
| +
 | |
| +static int plda_allocate_msi_domains(struct plda_pcie_rp *port)
 | |
| +{
 | |
| +	struct device *dev = port->dev;
 | |
| +	struct fwnode_handle *fwnode = of_node_to_fwnode(dev->of_node);
 | |
| +	struct plda_msi *msi = &port->msi;
 | |
| +
 | |
| +	mutex_init(&port->msi.lock);
 | |
| +
 | |
| +	msi->dev_domain = irq_domain_add_linear(NULL, msi->num_vectors,
 | |
| +						&msi_domain_ops, port);
 | |
| +	if (!msi->dev_domain) {
 | |
| +		dev_err(dev, "failed to create IRQ domain\n");
 | |
| +		return -ENOMEM;
 | |
| +	}
 | |
| +
 | |
| +	msi->msi_domain = pci_msi_create_irq_domain(fwnode,
 | |
| +						    &plda_msi_domain_info,
 | |
| +						    msi->dev_domain);
 | |
| +	if (!msi->msi_domain) {
 | |
| +		dev_err(dev, "failed to create MSI domain\n");
 | |
| +		irq_domain_remove(msi->dev_domain);
 | |
| +		return -ENOMEM;
 | |
| +	}
 | |
| +
 | |
| +	return 0;
 | |
| +}
 | |
| +
 | |
| +static void plda_handle_intx(struct irq_desc *desc)
 | |
| +{
 | |
| +	struct plda_pcie_rp *port = irq_desc_get_handler_data(desc);
 | |
| +	struct irq_chip *chip = irq_desc_get_chip(desc);
 | |
| +	struct device *dev = port->dev;
 | |
| +	void __iomem *bridge_base_addr = port->bridge_addr;
 | |
| +	unsigned long status;
 | |
| +	u32 bit;
 | |
| +	int ret;
 | |
| +
 | |
| +	chained_irq_enter(chip, desc);
 | |
| +
 | |
| +	status = readl_relaxed(bridge_base_addr + ISTATUS_LOCAL);
 | |
| +	if (status & PM_MSI_INT_INTX_MASK) {
 | |
| +		status &= PM_MSI_INT_INTX_MASK;
 | |
| +		status >>= PM_MSI_INT_INTX_SHIFT;
 | |
| +		for_each_set_bit(bit, &status, PCI_NUM_INTX) {
 | |
| +			ret = generic_handle_domain_irq(port->intx_domain, bit);
 | |
| +			if (ret)
 | |
| +				dev_err_ratelimited(dev, "bad INTx IRQ %d\n",
 | |
| +						    bit);
 | |
| +		}
 | |
| +	}
 | |
| +
 | |
| +	chained_irq_exit(chip, desc);
 | |
| +}
 | |
| +
 | |
| +static void plda_ack_intx_irq(struct irq_data *data)
 | |
| +{
 | |
| +	struct plda_pcie_rp *port = irq_data_get_irq_chip_data(data);
 | |
| +	void __iomem *bridge_base_addr = port->bridge_addr;
 | |
| +	u32 mask = BIT(data->hwirq + PM_MSI_INT_INTX_SHIFT);
 | |
| +
 | |
| +	writel_relaxed(mask, bridge_base_addr + ISTATUS_LOCAL);
 | |
| +}
 | |
| +
 | |
| +static void plda_mask_intx_irq(struct irq_data *data)
 | |
| +{
 | |
| +	struct plda_pcie_rp *port = irq_data_get_irq_chip_data(data);
 | |
| +	void __iomem *bridge_base_addr = port->bridge_addr;
 | |
| +	unsigned long flags;
 | |
| +	u32 mask = BIT(data->hwirq + PM_MSI_INT_INTX_SHIFT);
 | |
| +	u32 val;
 | |
| +
 | |
| +	raw_spin_lock_irqsave(&port->lock, flags);
 | |
| +	val = readl_relaxed(bridge_base_addr + IMASK_LOCAL);
 | |
| +	val &= ~mask;
 | |
| +	writel_relaxed(val, bridge_base_addr + IMASK_LOCAL);
 | |
| +	raw_spin_unlock_irqrestore(&port->lock, flags);
 | |
| +}
 | |
| +
 | |
| +static void plda_unmask_intx_irq(struct irq_data *data)
 | |
| +{
 | |
| +	struct plda_pcie_rp *port = irq_data_get_irq_chip_data(data);
 | |
| +	void __iomem *bridge_base_addr = port->bridge_addr;
 | |
| +	unsigned long flags;
 | |
| +	u32 mask = BIT(data->hwirq + PM_MSI_INT_INTX_SHIFT);
 | |
| +	u32 val;
 | |
| +
 | |
| +	raw_spin_lock_irqsave(&port->lock, flags);
 | |
| +	val = readl_relaxed(bridge_base_addr + IMASK_LOCAL);
 | |
| +	val |= mask;
 | |
| +	writel_relaxed(val, bridge_base_addr + IMASK_LOCAL);
 | |
| +	raw_spin_unlock_irqrestore(&port->lock, flags);
 | |
| +}
 | |
| +
 | |
| +static struct irq_chip plda_intx_irq_chip = {
 | |
| +	.name = "PLDA PCIe INTx",
 | |
| +	.irq_ack = plda_ack_intx_irq,
 | |
| +	.irq_mask = plda_mask_intx_irq,
 | |
| +	.irq_unmask = plda_unmask_intx_irq,
 | |
| +};
 | |
| +
 | |
| +static int plda_pcie_intx_map(struct irq_domain *domain, unsigned int irq,
 | |
| +			      irq_hw_number_t hwirq)
 | |
| +{
 | |
| +	irq_set_chip_and_handler(irq, &plda_intx_irq_chip, handle_level_irq);
 | |
| +	irq_set_chip_data(irq, domain->host_data);
 | |
| +
 | |
| +	return 0;
 | |
| +}
 | |
| +
 | |
| +static const struct irq_domain_ops intx_domain_ops = {
 | |
| +	.map = plda_pcie_intx_map,
 | |
| +};
 | |
| +
 | |
| +static u32 plda_get_events(struct plda_pcie_rp *port)
 | |
| +{
 | |
| +	u32 events, val, origin;
 | |
| +
 | |
| +	origin = readl_relaxed(port->bridge_addr + ISTATUS_LOCAL);
 | |
| +
 | |
| +	/* MSI event and sys events */
 | |
| +	val = (origin & SYS_AND_MSI_MASK) >> PM_MSI_INT_MSI_SHIFT;
 | |
| +	events = val << (PM_MSI_INT_MSI_SHIFT - PCI_NUM_INTX + 1);
 | |
| +
 | |
| +	/* INTx events */
 | |
| +	if (origin & PM_MSI_INT_INTX_MASK)
 | |
| +		events |= BIT(PM_MSI_INT_INTX_SHIFT);
 | |
| +
 | |
| +	/* remains are same with register */
 | |
| +	events |= origin & GENMASK(P_ATR_EVT_DOORBELL_SHIFT, 0);
 | |
| +
 | |
| +	return events;
 | |
| +}
 | |
| +
 | |
| +static irqreturn_t plda_event_handler(int irq, void *dev_id)
 | |
| +{
 | |
| +	return IRQ_HANDLED;
 | |
| +}
 | |
| +
 | |
| +static void plda_handle_event(struct irq_desc *desc)
 | |
| +{
 | |
| +	struct plda_pcie_rp *port = irq_desc_get_handler_data(desc);
 | |
| +	unsigned long events;
 | |
| +	u32 bit;
 | |
| +	struct irq_chip *chip = irq_desc_get_chip(desc);
 | |
| +
 | |
| +	chained_irq_enter(chip, desc);
 | |
| +
 | |
| +	events = port->event_ops->get_events(port);
 | |
| +
 | |
| +	for_each_set_bit(bit, &events, port->num_events)
 | |
| +		generic_handle_domain_irq(port->event_domain, bit);
 | |
| +
 | |
| +	chained_irq_exit(chip, desc);
 | |
| +}
 | |
| +
 | |
| +static u32 plda_hwirq_to_mask(int hwirq)
 | |
| +{
 | |
| +	u32 mask;
 | |
| +
 | |
| +	/* hwirq 23 - 0 are the same with register */
 | |
| +	if (hwirq < EVENT_PM_MSI_INT_INTX)
 | |
| +		mask = BIT(hwirq);
 | |
| +	else if (hwirq == EVENT_PM_MSI_INT_INTX)
 | |
| +		mask = PM_MSI_INT_INTX_MASK;
 | |
| +	else
 | |
| +		mask = BIT(hwirq + PCI_NUM_INTX - 1);
 | |
| +
 | |
| +	return mask;
 | |
| +}
 | |
| +
 | |
| +static void plda_ack_event_irq(struct irq_data *data)
 | |
| +{
 | |
| +	struct plda_pcie_rp *port = irq_data_get_irq_chip_data(data);
 | |
| +
 | |
| +	writel_relaxed(plda_hwirq_to_mask(data->hwirq),
 | |
| +		       port->bridge_addr + ISTATUS_LOCAL);
 | |
| +}
 | |
| +
 | |
| +static void plda_mask_event_irq(struct irq_data *data)
 | |
| +{
 | |
| +	struct plda_pcie_rp *port = irq_data_get_irq_chip_data(data);
 | |
| +	u32 mask, val;
 | |
| +
 | |
| +	mask = plda_hwirq_to_mask(data->hwirq);
 | |
| +
 | |
| +	raw_spin_lock(&port->lock);
 | |
| +	val = readl_relaxed(port->bridge_addr + IMASK_LOCAL);
 | |
| +	val &= ~mask;
 | |
| +	writel_relaxed(val, port->bridge_addr + IMASK_LOCAL);
 | |
| +	raw_spin_unlock(&port->lock);
 | |
| +}
 | |
| +
 | |
| +static void plda_unmask_event_irq(struct irq_data *data)
 | |
| +{
 | |
| +	struct plda_pcie_rp *port = irq_data_get_irq_chip_data(data);
 | |
| +	u32 mask, val;
 | |
| +
 | |
| +	mask = plda_hwirq_to_mask(data->hwirq);
 | |
| +
 | |
| +	raw_spin_lock(&port->lock);
 | |
| +	val = readl_relaxed(port->bridge_addr + IMASK_LOCAL);
 | |
| +	val |= mask;
 | |
| +	writel_relaxed(val, port->bridge_addr + IMASK_LOCAL);
 | |
| +	raw_spin_unlock(&port->lock);
 | |
| +}
 | |
| +
 | |
| +static struct irq_chip plda_event_irq_chip = {
 | |
| +	.name = "PLDA PCIe EVENT",
 | |
| +	.irq_ack = plda_ack_event_irq,
 | |
| +	.irq_mask = plda_mask_event_irq,
 | |
| +	.irq_unmask = plda_unmask_event_irq,
 | |
| +};
 | |
| +
 | |
| +static const struct plda_event_ops plda_event_ops = {
 | |
| +	.get_events = plda_get_events,
 | |
| +};
 | |
| +
 | |
| +static int plda_pcie_event_map(struct irq_domain *domain, unsigned int irq,
 | |
| +			       irq_hw_number_t hwirq)
 | |
| +{
 | |
| +	struct plda_pcie_rp *port = (void *)domain->host_data;
 | |
| +
 | |
| +	irq_set_chip_and_handler(irq, port->event_irq_chip, handle_level_irq);
 | |
| +	irq_set_chip_data(irq, domain->host_data);
 | |
| +
 | |
| +	return 0;
 | |
| +}
 | |
| +
 | |
| +static const struct irq_domain_ops plda_event_domain_ops = {
 | |
| +	.map = plda_pcie_event_map,
 | |
| +};
 | |
| +
 | |
| +static int plda_pcie_init_irq_domains(struct plda_pcie_rp *port)
 | |
| +{
 | |
| +	struct device *dev = port->dev;
 | |
| +	struct device_node *node = dev->of_node;
 | |
| +	struct device_node *pcie_intc_node;
 | |
| +
 | |
| +	/* Setup INTx */
 | |
| +	pcie_intc_node = of_get_next_child(node, NULL);
 | |
| +	if (!pcie_intc_node) {
 | |
| +		dev_err(dev, "failed to find PCIe Intc node\n");
 | |
| +		return -EINVAL;
 | |
| +	}
 | |
| +
 | |
| +	port->event_domain = irq_domain_add_linear(pcie_intc_node,
 | |
| +						   port->num_events,
 | |
| +						   &plda_event_domain_ops,
 | |
| +						   port);
 | |
| +	if (!port->event_domain) {
 | |
| +		dev_err(dev, "failed to get event domain\n");
 | |
| +		of_node_put(pcie_intc_node);
 | |
| +		return -ENOMEM;
 | |
| +	}
 | |
| +
 | |
| +	irq_domain_update_bus_token(port->event_domain, DOMAIN_BUS_NEXUS);
 | |
| +
 | |
| +	port->intx_domain = irq_domain_add_linear(pcie_intc_node, PCI_NUM_INTX,
 | |
| +						  &intx_domain_ops, port);
 | |
| +	if (!port->intx_domain) {
 | |
| +		dev_err(dev, "failed to get an INTx IRQ domain\n");
 | |
| +		of_node_put(pcie_intc_node);
 | |
| +		return -ENOMEM;
 | |
| +	}
 | |
| +
 | |
| +	irq_domain_update_bus_token(port->intx_domain, DOMAIN_BUS_WIRED);
 | |
| +
 | |
| +	of_node_put(pcie_intc_node);
 | |
| +	raw_spin_lock_init(&port->lock);
 | |
| +
 | |
| +	return plda_allocate_msi_domains(port);
 | |
| +}
 | |
| +
 | |
| +int plda_init_interrupts(struct platform_device *pdev,
 | |
| +			 struct plda_pcie_rp *port,
 | |
| +			 const struct plda_event *event)
 | |
| +{
 | |
| +	struct device *dev = &pdev->dev;
 | |
| +	int irq;
 | |
| +	int i, intx_irq, msi_irq, event_irq;
 | |
| +	int ret;
 | |
| +
 | |
| +	if (!port->event_ops)
 | |
| +		port->event_ops = &plda_event_ops;
 | |
| +
 | |
| +	if (!port->event_irq_chip)
 | |
| +		port->event_irq_chip = &plda_event_irq_chip;
 | |
| +
 | |
| +	ret = plda_pcie_init_irq_domains(port);
 | |
| +	if (ret) {
 | |
| +		dev_err(dev, "failed creating IRQ domains\n");
 | |
| +		return ret;
 | |
| +	}
 | |
| +
 | |
| +	irq = platform_get_irq(pdev, 0);
 | |
| +	if (irq < 0)
 | |
| +		return -ENODEV;
 | |
| +
 | |
| +	for (i = 0; i < port->num_events; i++) {
 | |
| +		event_irq = irq_create_mapping(port->event_domain, i);
 | |
| +		if (!event_irq) {
 | |
| +			dev_err(dev, "failed to map hwirq %d\n", i);
 | |
| +			return -ENXIO;
 | |
| +		}
 | |
| +
 | |
| +		if (event->request_event_irq)
 | |
| +			ret = event->request_event_irq(port, event_irq, i);
 | |
| +		else
 | |
| +			ret = devm_request_irq(dev, event_irq,
 | |
| +					       plda_event_handler,
 | |
| +					       0, NULL, port);
 | |
| +
 | |
| +		if (ret) {
 | |
| +			dev_err(dev, "failed to request IRQ %d\n", event_irq);
 | |
| +			return ret;
 | |
| +		}
 | |
| +	}
 | |
| +
 | |
| +	intx_irq = irq_create_mapping(port->event_domain,
 | |
| +				      event->intx_event);
 | |
| +	if (!intx_irq) {
 | |
| +		dev_err(dev, "failed to map INTx interrupt\n");
 | |
| +		return -ENXIO;
 | |
| +	}
 | |
| +
 | |
| +	/* Plug the INTx chained handler */
 | |
| +	irq_set_chained_handler_and_data(intx_irq, plda_handle_intx, port);
 | |
| +
 | |
| +	msi_irq = irq_create_mapping(port->event_domain,
 | |
| +				     event->msi_event);
 | |
| +	if (!msi_irq)
 | |
| +		return -ENXIO;
 | |
| +
 | |
| +	/* Plug the MSI chained handler */
 | |
| +	irq_set_chained_handler_and_data(msi_irq, plda_handle_msi, port);
 | |
| +
 | |
| +	/* Plug the main event chained handler */
 | |
| +	irq_set_chained_handler_and_data(irq, plda_handle_event, port);
 | |
| +
 | |
| +	return 0;
 | |
| +}
 | |
| +EXPORT_SYMBOL_GPL(plda_init_interrupts);
 | |
| +
 | |
|  void plda_pcie_setup_window(void __iomem *bridge_base_addr, u32 index,
 | |
|  			    phys_addr_t axi_addr, phys_addr_t pci_addr,
 | |
|  			    size_t size)
 | |
| diff --git a/drivers/pci/controller/plda/pcie-plda.h b/drivers/pci/controller/plda/pcie-plda.h
 | |
| index a3ce01735bea..6672a231a4bc 100644
 | |
| --- a/drivers/pci/controller/plda/pcie-plda.h
 | |
| +++ b/drivers/pci/controller/plda/pcie-plda.h
 | |
| @@ -169,6 +169,9 @@ struct plda_event {
 | |
|  	int msi_event;
 | |
|  };
 | |
|  
 | |
| +int plda_init_interrupts(struct platform_device *pdev,
 | |
| +			 struct plda_pcie_rp *port,
 | |
| +			 const struct plda_event *event);
 | |
|  void plda_pcie_setup_window(void __iomem *bridge_base_addr, u32 index,
 | |
|  			    phys_addr_t axi_addr, phys_addr_t pci_addr,
 | |
|  			    size_t size);
 | |
| -- 
 | |
| 2.43.0
 | |
| 
 | |
| 
 | |
| From 3ed458f3854d5e86cd34ee9e3d87a8b3c2287913 Mon Sep 17 00:00:00 2001
 | |
| From: Minda Chen <minda.chen@starfivetech.com>
 | |
| Date: Mon, 8 Jan 2024 19:06:07 +0800
 | |
| Subject: [PATCH 17/23] pci: plda: Add event bitmap field to struct
 | |
|  plda_pcie_rp
 | |
| 
 | |
| For PLDA DMA interrupts are not all implemented. The non-implemented
 | |
| interrupts should be masked. So add a bitmap field to mask the non-
 | |
| implemented interrupts.
 | |
| 
 | |
| Signed-off-by: Minda Chen <minda.chen@starfivetech.com>
 | |
| Message-ID: <20240108110612.19048-18-minda.chen@starfivetech.com>
 | |
| Signed-off-by: Aurelien Jarno <aurelien@aurel32.net>
 | |
| ---
 | |
|  drivers/pci/controller/plda/pcie-microchip-host.c | 1 +
 | |
|  drivers/pci/controller/plda/pcie-plda-host.c      | 6 ++++--
 | |
|  drivers/pci/controller/plda/pcie-plda.h           | 1 +
 | |
|  3 files changed, 6 insertions(+), 2 deletions(-)
 | |
| 
 | |
| diff --git a/drivers/pci/controller/plda/pcie-microchip-host.c b/drivers/pci/controller/plda/pcie-microchip-host.c
 | |
| index 105964306b71..48f60a04b740 100644
 | |
| --- a/drivers/pci/controller/plda/pcie-microchip-host.c
 | |
| +++ b/drivers/pci/controller/plda/pcie-microchip-host.c
 | |
| @@ -636,6 +636,7 @@ static int mc_platform_init(struct pci_config_window *cfg)
 | |
|  
 | |
|  	port->plda.event_ops = &mc_event_ops;
 | |
|  	port->plda.event_irq_chip = &mc_event_irq_chip;
 | |
| +	port->plda.events_bitmap = GENMASK(NUM_EVENTS - 1, 0);
 | |
|  
 | |
|  	/* Address translation is up; safe to enable interrupts */
 | |
|  	ret = plda_init_interrupts(pdev, &port->plda, &mc_event);
 | |
| diff --git a/drivers/pci/controller/plda/pcie-plda-host.c b/drivers/pci/controller/plda/pcie-plda-host.c
 | |
| index 98c51e594efe..a040e7e5492f 100644
 | |
| --- a/drivers/pci/controller/plda/pcie-plda-host.c
 | |
| +++ b/drivers/pci/controller/plda/pcie-plda-host.c
 | |
| @@ -290,6 +290,7 @@ static void plda_handle_event(struct irq_desc *desc)
 | |
|  
 | |
|  	events = port->event_ops->get_events(port);
 | |
|  
 | |
| +	events &= port->events_bitmap;
 | |
|  	for_each_set_bit(bit, &events, port->num_events)
 | |
|  		generic_handle_domain_irq(port->event_domain, bit);
 | |
|  
 | |
| @@ -420,8 +421,9 @@ int plda_init_interrupts(struct platform_device *pdev,
 | |
|  {
 | |
|  	struct device *dev = &pdev->dev;
 | |
|  	int irq;
 | |
| -	int i, intx_irq, msi_irq, event_irq;
 | |
| +	int intx_irq, msi_irq, event_irq;
 | |
|  	int ret;
 | |
| +	u32 i;
 | |
|  
 | |
|  	if (!port->event_ops)
 | |
|  		port->event_ops = &plda_event_ops;
 | |
| @@ -439,7 +441,7 @@ int plda_init_interrupts(struct platform_device *pdev,
 | |
|  	if (irq < 0)
 | |
|  		return -ENODEV;
 | |
|  
 | |
| -	for (i = 0; i < port->num_events; i++) {
 | |
| +	for_each_set_bit(i, &port->events_bitmap, port->num_events) {
 | |
|  		event_irq = irq_create_mapping(port->event_domain, i);
 | |
|  		if (!event_irq) {
 | |
|  			dev_err(dev, "failed to map hwirq %d\n", i);
 | |
| diff --git a/drivers/pci/controller/plda/pcie-plda.h b/drivers/pci/controller/plda/pcie-plda.h
 | |
| index 6672a231a4bc..443109d04d59 100644
 | |
| --- a/drivers/pci/controller/plda/pcie-plda.h
 | |
| +++ b/drivers/pci/controller/plda/pcie-plda.h
 | |
| @@ -159,6 +159,7 @@ struct plda_pcie_rp {
 | |
|  	const struct plda_event_ops *event_ops;
 | |
|  	const struct irq_chip *event_irq_chip;
 | |
|  	void __iomem *bridge_addr;
 | |
| +	unsigned long events_bitmap;
 | |
|  	int num_events;
 | |
|  };
 | |
|  
 | |
| -- 
 | |
| 2.43.0
 | |
| 
 | |
| 
 | |
| From 45f29fdd79438d1efe3924e796be927c79822fe5 Mon Sep 17 00:00:00 2001
 | |
| From: Minda Chen <minda.chen@starfivetech.com>
 | |
| Date: Mon, 8 Jan 2024 19:06:08 +0800
 | |
| Subject: [PATCH 18/23] PCI: plda: Add host init/deinit and map bus functions
 | |
| 
 | |
| Add PLDA host plda_pcie_host_init()/plda_pcie_host_deinit() and map bus
 | |
| function. So vendor can use it to init PLDA PCIe host core.
 | |
| 
 | |
| Signed-off-by: Minda Chen <minda.chen@starfivetech.com>
 | |
| Reviewed-by: Mason Huo <mason.huo@starfivetech.com>
 | |
| Message-ID: <20240108110612.19048-19-minda.chen@starfivetech.com>
 | |
| Signed-off-by: Aurelien Jarno <aurelien@aurel32.net>
 | |
| ---
 | |
|  drivers/pci/controller/plda/pcie-plda-host.c | 131 +++++++++++++++++--
 | |
|  drivers/pci/controller/plda/pcie-plda.h      |  22 ++++
 | |
|  2 files changed, 139 insertions(+), 14 deletions(-)
 | |
| 
 | |
| diff --git a/drivers/pci/controller/plda/pcie-plda-host.c b/drivers/pci/controller/plda/pcie-plda-host.c
 | |
| index a040e7e5492f..a18923d7cea6 100644
 | |
| --- a/drivers/pci/controller/plda/pcie-plda-host.c
 | |
| +++ b/drivers/pci/controller/plda/pcie-plda-host.c
 | |
| @@ -3,6 +3,7 @@
 | |
|   * PLDA PCIe XpressRich host controller driver
 | |
|   *
 | |
|   * Copyright (C) 2023 Microchip Co. Ltd
 | |
| + *		      StarFive Co. Ltd
 | |
|   *
 | |
|   * Author: Daire McNamara <daire.mcnamara@microchip.com>
 | |
|   */
 | |
| @@ -15,6 +16,15 @@
 | |
|  
 | |
|  #include "pcie-plda.h"
 | |
|  
 | |
| +void __iomem *plda_pcie_map_bus(struct pci_bus *bus, unsigned int devfn,
 | |
| +				int where)
 | |
| +{
 | |
| +	struct plda_pcie_rp *pcie = bus->sysdata;
 | |
| +
 | |
| +	return pcie->config_base + PCIE_ECAM_OFFSET(bus->number, devfn, where);
 | |
| +}
 | |
| +EXPORT_SYMBOL_GPL(plda_pcie_map_bus);
 | |
| +
 | |
|  static void plda_handle_msi(struct irq_desc *desc)
 | |
|  {
 | |
|  	struct plda_pcie_rp *port = irq_desc_get_handler_data(desc);
 | |
| @@ -420,9 +430,7 @@ int plda_init_interrupts(struct platform_device *pdev,
 | |
|  			 const struct plda_event *event)
 | |
|  {
 | |
|  	struct device *dev = &pdev->dev;
 | |
| -	int irq;
 | |
| -	int intx_irq, msi_irq, event_irq;
 | |
| -	int ret;
 | |
| +	int event_irq, ret;
 | |
|  	u32 i;
 | |
|  
 | |
|  	if (!port->event_ops)
 | |
| @@ -437,8 +445,8 @@ int plda_init_interrupts(struct platform_device *pdev,
 | |
|  		return ret;
 | |
|  	}
 | |
|  
 | |
| -	irq = platform_get_irq(pdev, 0);
 | |
| -	if (irq < 0)
 | |
| +	port->irq = platform_get_irq(pdev, 0);
 | |
| +	if (port->irq < 0)
 | |
|  		return -ENODEV;
 | |
|  
 | |
|  	for_each_set_bit(i, &port->events_bitmap, port->num_events) {
 | |
| @@ -461,26 +469,26 @@ int plda_init_interrupts(struct platform_device *pdev,
 | |
|  		}
 | |
|  	}
 | |
|  
 | |
| -	intx_irq = irq_create_mapping(port->event_domain,
 | |
| -				      event->intx_event);
 | |
| -	if (!intx_irq) {
 | |
| +	port->intx_irq = irq_create_mapping(port->event_domain,
 | |
| +					    event->intx_event);
 | |
| +	if (!port->intx_irq) {
 | |
|  		dev_err(dev, "failed to map INTx interrupt\n");
 | |
|  		return -ENXIO;
 | |
|  	}
 | |
|  
 | |
|  	/* Plug the INTx chained handler */
 | |
| -	irq_set_chained_handler_and_data(intx_irq, plda_handle_intx, port);
 | |
| +	irq_set_chained_handler_and_data(port->intx_irq, plda_handle_intx, port);
 | |
|  
 | |
| -	msi_irq = irq_create_mapping(port->event_domain,
 | |
| -				     event->msi_event);
 | |
| -	if (!msi_irq)
 | |
| +	port->msi_irq = irq_create_mapping(port->event_domain,
 | |
| +					   event->msi_event);
 | |
| +	if (!port->msi_irq)
 | |
|  		return -ENXIO;
 | |
|  
 | |
|  	/* Plug the MSI chained handler */
 | |
| -	irq_set_chained_handler_and_data(msi_irq, plda_handle_msi, port);
 | |
| +	irq_set_chained_handler_and_data(port->msi_irq, plda_handle_msi, port);
 | |
|  
 | |
|  	/* Plug the main event chained handler */
 | |
| -	irq_set_chained_handler_and_data(irq, plda_handle_event, port);
 | |
| +	irq_set_chained_handler_and_data(port->irq, plda_handle_event, port);
 | |
|  
 | |
|  	return 0;
 | |
|  }
 | |
| @@ -546,3 +554,98 @@ int plda_pcie_setup_iomems(struct pci_host_bridge *bridge,
 | |
|  	return 0;
 | |
|  }
 | |
|  EXPORT_SYMBOL_GPL(plda_pcie_setup_iomems);
 | |
| +
 | |
| +static void plda_pcie_irq_domain_deinit(struct plda_pcie_rp *pcie)
 | |
| +{
 | |
| +	irq_set_chained_handler_and_data(pcie->irq, NULL, NULL);
 | |
| +	irq_set_chained_handler_and_data(pcie->msi_irq, NULL, NULL);
 | |
| +	irq_set_chained_handler_and_data(pcie->intx_irq, NULL, NULL);
 | |
| +
 | |
| +	irq_domain_remove(pcie->msi.msi_domain);
 | |
| +	irq_domain_remove(pcie->msi.dev_domain);
 | |
| +
 | |
| +	irq_domain_remove(pcie->intx_domain);
 | |
| +	irq_domain_remove(pcie->event_domain);
 | |
| +}
 | |
| +
 | |
| +int plda_pcie_host_init(struct plda_pcie_rp *port, struct pci_ops *ops,
 | |
| +			const struct plda_event *plda_event)
 | |
| +{
 | |
| +	struct device *dev = port->dev;
 | |
| +	struct pci_host_bridge *bridge;
 | |
| +	struct platform_device *pdev = to_platform_device(dev);
 | |
| +	struct resource *cfg_res;
 | |
| +	int ret;
 | |
| +
 | |
| +	pdev = to_platform_device(dev);
 | |
| +
 | |
| +	port->bridge_addr =
 | |
| +		devm_platform_ioremap_resource_byname(pdev, "apb");
 | |
| +
 | |
| +	if (IS_ERR(port->bridge_addr))
 | |
| +		return dev_err_probe(dev, PTR_ERR(port->bridge_addr),
 | |
| +				     "failed to map reg memory\n");
 | |
| +
 | |
| +	cfg_res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "cfg");
 | |
| +	if (!cfg_res)
 | |
| +		return dev_err_probe(dev, -ENODEV,
 | |
| +				     "failed to get config memory\n");
 | |
| +
 | |
| +	port->config_base = devm_ioremap_resource(dev, cfg_res);
 | |
| +	if (IS_ERR(port->config_base))
 | |
| +		return dev_err_probe(dev, PTR_ERR(port->config_base),
 | |
| +				     "failed to map config memory\n");
 | |
| +
 | |
| +	bridge = devm_pci_alloc_host_bridge(dev, 0);
 | |
| +	if (!bridge)
 | |
| +		return dev_err_probe(dev, -ENOMEM,
 | |
| +				     "failed to alloc bridge\n");
 | |
| +
 | |
| +	if (port->host_ops && port->host_ops->host_init) {
 | |
| +		ret = port->host_ops->host_init(port);
 | |
| +		if (ret)
 | |
| +			return ret;
 | |
| +	}
 | |
| +
 | |
| +	port->bridge = bridge;
 | |
| +	plda_pcie_setup_window(port->bridge_addr, 0, cfg_res->start, 0,
 | |
| +			       resource_size(cfg_res));
 | |
| +	plda_pcie_setup_iomems(bridge, port);
 | |
| +	plda_set_default_msi(&port->msi);
 | |
| +	ret = plda_init_interrupts(pdev, port, plda_event);
 | |
| +	if (ret)
 | |
| +		goto err_host;
 | |
| +
 | |
| +	/* Set default bus ops */
 | |
| +	bridge->ops = ops;
 | |
| +	bridge->sysdata = port;
 | |
| +
 | |
| +	ret = pci_host_probe(bridge);
 | |
| +	if (ret < 0) {
 | |
| +		dev_err_probe(dev, ret, "failed to probe pci host\n");
 | |
| +		goto err_probe;
 | |
| +	}
 | |
| +
 | |
| +	return ret;
 | |
| +
 | |
| +err_probe:
 | |
| +	plda_pcie_irq_domain_deinit(port);
 | |
| +err_host:
 | |
| +	if (port->host_ops && port->host_ops->host_deinit)
 | |
| +		port->host_ops->host_deinit(port);
 | |
| +
 | |
| +	return ret;
 | |
| +}
 | |
| +EXPORT_SYMBOL_GPL(plda_pcie_host_init);
 | |
| +
 | |
| +void plda_pcie_host_deinit(struct plda_pcie_rp *port)
 | |
| +{
 | |
| +	pci_stop_root_bus(port->bridge->bus);
 | |
| +	pci_remove_root_bus(port->bridge->bus);
 | |
| +
 | |
| +	plda_pcie_irq_domain_deinit(port);
 | |
| +
 | |
| +	if (port->host_ops && port->host_ops->host_deinit)
 | |
| +		port->host_ops->host_deinit(port);
 | |
| +}
 | |
| +EXPORT_SYMBOL_GPL(plda_pcie_host_deinit);
 | |
| diff --git a/drivers/pci/controller/plda/pcie-plda.h b/drivers/pci/controller/plda/pcie-plda.h
 | |
| index 443109d04d59..7b69891700a4 100644
 | |
| --- a/drivers/pci/controller/plda/pcie-plda.h
 | |
| +++ b/drivers/pci/controller/plda/pcie-plda.h
 | |
| @@ -141,6 +141,11 @@ struct plda_event_ops {
 | |
|  	u32 (*get_events)(struct plda_pcie_rp *pcie);
 | |
|  };
 | |
|  
 | |
| +struct plda_pcie_host_ops {
 | |
| +	int (*host_init)(struct plda_pcie_rp *pcie);
 | |
| +	void (*host_deinit)(struct plda_pcie_rp *pcie);
 | |
| +};
 | |
| +
 | |
|  struct plda_msi {
 | |
|  	struct mutex lock;		/* Protect used bitmap */
 | |
|  	struct irq_domain *msi_domain;
 | |
| @@ -152,14 +157,20 @@ struct plda_msi {
 | |
|  
 | |
|  struct plda_pcie_rp {
 | |
|  	struct device *dev;
 | |
| +	struct pci_host_bridge *bridge;
 | |
|  	struct irq_domain *intx_domain;
 | |
|  	struct irq_domain *event_domain;
 | |
|  	raw_spinlock_t lock;
 | |
|  	struct plda_msi msi;
 | |
|  	const struct plda_event_ops *event_ops;
 | |
|  	const struct irq_chip *event_irq_chip;
 | |
| +	const struct plda_pcie_host_ops *host_ops;
 | |
|  	void __iomem *bridge_addr;
 | |
| +	void __iomem *config_base;
 | |
|  	unsigned long events_bitmap;
 | |
| +	int irq;
 | |
| +	int msi_irq;
 | |
| +	int intx_irq;
 | |
|  	int num_events;
 | |
|  };
 | |
|  
 | |
| @@ -170,6 +181,8 @@ struct plda_event {
 | |
|  	int msi_event;
 | |
|  };
 | |
|  
 | |
| +void __iomem *plda_pcie_map_bus(struct pci_bus *bus, unsigned int devfn,
 | |
| +				int where);
 | |
|  int plda_init_interrupts(struct platform_device *pdev,
 | |
|  			 struct plda_pcie_rp *port,
 | |
|  			 const struct plda_event *event);
 | |
| @@ -178,4 +191,13 @@ void plda_pcie_setup_window(void __iomem *bridge_base_addr, u32 index,
 | |
|  			    size_t size);
 | |
|  int plda_pcie_setup_iomems(struct pci_host_bridge *bridge,
 | |
|  			   struct plda_pcie_rp *port);
 | |
| +int plda_pcie_host_init(struct plda_pcie_rp *port, struct pci_ops *ops,
 | |
| +			const struct plda_event *plda_event);
 | |
| +void plda_pcie_host_deinit(struct plda_pcie_rp *pcie);
 | |
| +
 | |
| +static inline void plda_set_default_msi(struct plda_msi *msi)
 | |
| +{
 | |
| +	msi->vector_phy = IMSI_ADDR;
 | |
| +	msi->num_vectors = PLDA_MAX_NUM_MSI_IRQS;
 | |
| +}
 | |
|  #endif
 | |
| -- 
 | |
| 2.43.0
 | |
| 
 | |
| 
 | |
| From a3bcc30c729854515731b73ed6e1e3bc5f7d2bc7 Mon Sep 17 00:00:00 2001
 | |
| From: Minda Chen <minda.chen@starfivetech.com>
 | |
| Date: Mon, 8 Jan 2024 19:06:09 +0800
 | |
| Subject: [PATCH 19/23] dt-bindings: PCI: Add StarFive JH7110 PCIe controller
 | |
| 
 | |
| Add StarFive JH7110 SoC PCIe controller dt-bindings. JH7110 using PLDA
 | |
| XpressRICH PCIe host controller IP.
 | |
| 
 | |
| Signed-off-by: Minda Chen <minda.chen@starfivetech.com>
 | |
| Reviewed-by: Hal Feng <hal.feng@starfivetech.com>
 | |
| Reviewed-by: Conor Dooley <conor.dooley@microchip.com>
 | |
| Reviewed-by: Rob Herring <robh@kernel.org>
 | |
| Message-ID: <20240108110612.19048-20-minda.chen@starfivetech.com>
 | |
| Signed-off-by: Aurelien Jarno <aurelien@aurel32.net>
 | |
| ---
 | |
|  .../bindings/pci/starfive,jh7110-pcie.yaml    | 120 ++++++++++++++++++
 | |
|  1 file changed, 120 insertions(+)
 | |
|  create mode 100644 Documentation/devicetree/bindings/pci/starfive,jh7110-pcie.yaml
 | |
| 
 | |
| diff --git a/Documentation/devicetree/bindings/pci/starfive,jh7110-pcie.yaml b/Documentation/devicetree/bindings/pci/starfive,jh7110-pcie.yaml
 | |
| new file mode 100644
 | |
| index 000000000000..67151aaa3948
 | |
| --- /dev/null
 | |
| +++ b/Documentation/devicetree/bindings/pci/starfive,jh7110-pcie.yaml
 | |
| @@ -0,0 +1,120 @@
 | |
| +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
 | |
| +%YAML 1.2
 | |
| +---
 | |
| +$id: http://devicetree.org/schemas/pci/starfive,jh7110-pcie.yaml#
 | |
| +$schema: http://devicetree.org/meta-schemas/core.yaml#
 | |
| +
 | |
| +title: StarFive JH7110 PCIe host controller
 | |
| +
 | |
| +maintainers:
 | |
| +  - Kevin Xie <kevin.xie@starfivetech.com>
 | |
| +
 | |
| +allOf:
 | |
| +  - $ref: plda,xpressrich3-axi-common.yaml#
 | |
| +
 | |
| +properties:
 | |
| +  compatible:
 | |
| +    const: starfive,jh7110-pcie
 | |
| +
 | |
| +  clocks:
 | |
| +    items:
 | |
| +      - description: NOC bus clock
 | |
| +      - description: Transport layer clock
 | |
| +      - description: AXI MST0 clock
 | |
| +      - description: APB clock
 | |
| +
 | |
| +  clock-names:
 | |
| +    items:
 | |
| +      - const: noc
 | |
| +      - const: tl
 | |
| +      - const: axi_mst0
 | |
| +      - const: apb
 | |
| +
 | |
| +  resets:
 | |
| +    items:
 | |
| +      - description: AXI MST0 reset
 | |
| +      - description: AXI SLAVE0 reset
 | |
| +      - description: AXI SLAVE reset
 | |
| +      - description: PCIE BRIDGE reset
 | |
| +      - description: PCIE CORE reset
 | |
| +      - description: PCIE APB reset
 | |
| +
 | |
| +  reset-names:
 | |
| +    items:
 | |
| +      - const: mst0
 | |
| +      - const: slv0
 | |
| +      - const: slv
 | |
| +      - const: brg
 | |
| +      - const: core
 | |
| +      - const: apb
 | |
| +
 | |
| +  starfive,stg-syscon:
 | |
| +    $ref: /schemas/types.yaml#/definitions/phandle-array
 | |
| +    description:
 | |
| +      The phandle to System Register Controller syscon node.
 | |
| +
 | |
| +  perst-gpios:
 | |
| +    description: GPIO controlled connection to PERST# signal
 | |
| +    maxItems: 1
 | |
| +
 | |
| +  phys:
 | |
| +    description:
 | |
| +      Specified PHY is attached to PCIe controller.
 | |
| +    maxItems: 1
 | |
| +
 | |
| +required:
 | |
| +  - clocks
 | |
| +  - resets
 | |
| +  - starfive,stg-syscon
 | |
| +
 | |
| +unevaluatedProperties: false
 | |
| +
 | |
| +examples:
 | |
| +  - |
 | |
| +    #include <dt-bindings/gpio/gpio.h>
 | |
| +    soc {
 | |
| +        #address-cells = <2>;
 | |
| +        #size-cells = <2>;
 | |
| +
 | |
| +        pcie@940000000 {
 | |
| +            compatible = "starfive,jh7110-pcie";
 | |
| +            reg = <0x9 0x40000000 0x0 0x10000000>,
 | |
| +                  <0x0 0x2b000000 0x0 0x1000000>;
 | |
| +            reg-names = "cfg", "apb";
 | |
| +            #address-cells = <3>;
 | |
| +            #size-cells = <2>;
 | |
| +            #interrupt-cells = <1>;
 | |
| +            device_type = "pci";
 | |
| +            ranges = <0x82000000  0x0 0x30000000  0x0 0x30000000 0x0 0x08000000>,
 | |
| +                     <0xc3000000  0x9 0x00000000  0x9 0x00000000 0x0 0x40000000>;
 | |
| +            starfive,stg-syscon = <&stg_syscon>;
 | |
| +            bus-range = <0x0 0xff>;
 | |
| +            interrupt-parent = <&plic>;
 | |
| +            interrupts = <56>;
 | |
| +            interrupt-map-mask = <0x0 0x0 0x0 0x7>;
 | |
| +            interrupt-map = <0x0 0x0 0x0 0x1 &pcie_intc0 0x1>,
 | |
| +                            <0x0 0x0 0x0 0x2 &pcie_intc0 0x2>,
 | |
| +                            <0x0 0x0 0x0 0x3 &pcie_intc0 0x3>,
 | |
| +                            <0x0 0x0 0x0 0x4 &pcie_intc0 0x4>;
 | |
| +            msi-controller;
 | |
| +            clocks = <&syscrg 86>,
 | |
| +                     <&stgcrg 10>,
 | |
| +                     <&stgcrg 8>,
 | |
| +                     <&stgcrg 9>;
 | |
| +            clock-names = "noc", "tl", "axi_mst0", "apb";
 | |
| +            resets = <&stgcrg 11>,
 | |
| +                     <&stgcrg 12>,
 | |
| +                     <&stgcrg 13>,
 | |
| +                     <&stgcrg 14>,
 | |
| +                     <&stgcrg 15>,
 | |
| +                     <&stgcrg 16>;
 | |
| +            perst-gpios = <&gpios 26 GPIO_ACTIVE_LOW>;
 | |
| +            phys = <&pciephy0>;
 | |
| +
 | |
| +            pcie_intc0: interrupt-controller {
 | |
| +                #address-cells = <0>;
 | |
| +                #interrupt-cells = <1>;
 | |
| +                interrupt-controller;
 | |
| +            };
 | |
| +        };
 | |
| +    };
 | |
| -- 
 | |
| 2.43.0
 | |
| 
 | |
| 
 | |
| From 68c605686c561a1cc3a42c82bc0de854b5b4183e Mon Sep 17 00:00:00 2001
 | |
| From: Kevin Xie <kevin.xie@starfivetech.com>
 | |
| Date: Mon, 8 Jan 2024 19:06:10 +0800
 | |
| Subject: [PATCH 20/23] PCI: Add PCIE_RESET_CONFIG_DEVICE_WAIT_MS waiting time
 | |
|  value
 | |
| 
 | |
| Add the PCIE_RESET_CONFIG_DEVICE_WAIT_MS macro to define the minimum
 | |
| waiting time between exit from a conventional reset and sending the
 | |
| first configuration request to the device.
 | |
| 
 | |
| As described in PCI base specification r6.0, section 6.6.1 <Conventional
 | |
| Reset>, there are two different use cases of the value:
 | |
| 
 | |
|    - "With a Downstream Port that does not support Link speeds greater
 | |
|      than 5.0 GT/s, software must wait a minimum of 100 ms following exit
 | |
|      from a Conventional Reset before sending a Configuration Request to
 | |
|      the device immediately below that Port."
 | |
| 
 | |
|    - "With a Downstream Port that supports Link speeds greater than
 | |
|      5.0 GT/s, software must wait a minimum of 100 ms after Link training
 | |
|      completes before sending a Configuration Request to the device
 | |
|      immediately below that Port."
 | |
| 
 | |
| Signed-off-by: Kevin Xie <kevin.xie@starfivetech.com>
 | |
| Reviewed-by: Mason Huo <mason.huo@starfivetech.com>
 | |
| Acked-by: Bjorn Helgaas <bhelgaas@google.com>
 | |
| Message-ID: <20240108110612.19048-21-minda.chen@starfivetech.com>
 | |
| Signed-off-by: Aurelien Jarno <aurelien@aurel32.net>
 | |
| ---
 | |
|  drivers/pci/pci.h | 16 ++++++++++++++++
 | |
|  1 file changed, 16 insertions(+)
 | |
| 
 | |
| diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h
 | |
| index f43873049d52..6990146e14e3 100644
 | |
| --- a/drivers/pci/pci.h
 | |
| +++ b/drivers/pci/pci.h
 | |
| @@ -22,6 +22,22 @@
 | |
|   */
 | |
|  #define PCIE_PME_TO_L2_TIMEOUT_US	10000
 | |
|  
 | |
| +/*
 | |
| + * As described in PCI base specification r6.0, section 6.6.1 <Conventional
 | |
| + * Reset>, there are two different use cases of the value:
 | |
| + *
 | |
| + * - "With a Downstream Port that does not support Link speeds greater
 | |
| + *    than 5.0 GT/s, software must wait a minimum of 100 ms following exit
 | |
| + *    from a Conventional Reset before sending a Configuration Request to
 | |
| + *    the device immediately below that Port."
 | |
| + *
 | |
| + * - "With a Downstream Port that supports Link speeds greater than
 | |
| + *    5.0 GT/s, software must wait a minimum of 100 ms after Link training
 | |
| + *    completes before sending a Configuration Request to the device
 | |
| + *    immediately below that Port."
 | |
| + */
 | |
| +#define PCIE_RESET_CONFIG_DEVICE_WAIT_MS	100
 | |
| +
 | |
|  extern const unsigned char pcie_link_speed[];
 | |
|  extern bool pci_early_dump;
 | |
|  
 | |
| -- 
 | |
| 2.43.0
 | |
| 
 | |
| 
 | |
| From d595015610966f0c9e3128ce23db29dd0f212e0e Mon Sep 17 00:00:00 2001
 | |
| From: Minda Chen <minda.chen@starfivetech.com>
 | |
| Date: Mon, 8 Jan 2024 19:06:11 +0800
 | |
| Subject: [PATCH 21/23] PCI: starfive: Add JH7110 PCIe controller
 | |
| 
 | |
| Add StarFive JH7110 SoC PCIe controller platform driver codes, JH7110
 | |
| with PLDA host PCIe core.
 | |
| 
 | |
| Signed-off-by: Minda Chen <minda.chen@starfivetech.com>
 | |
| Co-developed-by: Kevin Xie <kevin.xie@starfivetech.com>
 | |
| Reviewed-by: Mason Huo <mason.huo@starfivetech.com>
 | |
| Message-ID: <20240108110612.19048-22-minda.chen@starfivetech.com>
 | |
| Signed-off-by: Aurelien Jarno <aurelien@aurel32.net>
 | |
| ---
 | |
|  MAINTAINERS                                 |   7 +
 | |
|  drivers/pci/controller/plda/Kconfig         |  12 +
 | |
|  drivers/pci/controller/plda/Makefile        |   1 +
 | |
|  drivers/pci/controller/plda/pcie-plda.h     |  71 ++-
 | |
|  drivers/pci/controller/plda/pcie-starfive.c | 473 ++++++++++++++++++++
 | |
|  5 files changed, 563 insertions(+), 1 deletion(-)
 | |
|  create mode 100644 drivers/pci/controller/plda/pcie-starfive.c
 | |
| 
 | |
| diff --git a/MAINTAINERS b/MAINTAINERS
 | |
| index 730fe2d640a1..7fa339e6c25d 100644
 | |
| --- a/MAINTAINERS
 | |
| +++ b/MAINTAINERS
 | |
| @@ -16821,6 +16821,13 @@ S:	Maintained
 | |
|  F:	Documentation/devicetree/bindings/pci/socionext,uniphier-pcie*
 | |
|  F:	drivers/pci/controller/dwc/pcie-uniphier*
 | |
|  
 | |
| +PCIE DRIVER FOR STARFIVE JH71x0
 | |
| +M:	Kevin Xie <kevin.xie@starfivetech.com>
 | |
| +L:	linux-pci@vger.kernel.org
 | |
| +S:	Maintained
 | |
| +F:	Documentation/devicetree/bindings/pci/starfive*
 | |
| +F:	drivers/pci/controller/plda/pcie-starfive.c
 | |
| +
 | |
|  PCIE DRIVER FOR ST SPEAR13XX
 | |
|  M:	Pratyush Anand <pratyush.anand@gmail.com>
 | |
|  L:	linux-pci@vger.kernel.org
 | |
| diff --git a/drivers/pci/controller/plda/Kconfig b/drivers/pci/controller/plda/Kconfig
 | |
| index e54a82ee94f5..c0e14146d7e4 100644
 | |
| --- a/drivers/pci/controller/plda/Kconfig
 | |
| +++ b/drivers/pci/controller/plda/Kconfig
 | |
| @@ -15,4 +15,16 @@ config PCIE_MICROCHIP_HOST
 | |
|  	  Say Y here if you want kernel to support the Microchip AXI PCIe
 | |
|  	  Host Bridge driver.
 | |
|  
 | |
| +config PCIE_STARFIVE_HOST
 | |
| +	tristate "StarFive PCIe host controller"
 | |
| +	depends on PCI_MSI && OF
 | |
| +	depends on ARCH_STARFIVE || COMPILE_TEST
 | |
| +	select PCIE_PLDA_HOST
 | |
| +	help
 | |
| +	  Say Y here if you want to support the StarFive PCIe controller in
 | |
| +	  host mode. StarFive PCIe controller uses PLDA PCIe core.
 | |
| +
 | |
| +	  If you choose to build this driver as module it will be dynamically
 | |
| +	  linked and module will be called pcie-starfive.ko.
 | |
| +
 | |
|  endmenu
 | |
| diff --git a/drivers/pci/controller/plda/Makefile b/drivers/pci/controller/plda/Makefile
 | |
| index 4340ab007f44..0ac6851bed48 100644
 | |
| --- a/drivers/pci/controller/plda/Makefile
 | |
| +++ b/drivers/pci/controller/plda/Makefile
 | |
| @@ -1,3 +1,4 @@
 | |
|  # SPDX-License-Identifier: GPL-2.0
 | |
|  obj-$(CONFIG_PCIE_PLDA_HOST) += pcie-plda-host.o
 | |
|  obj-$(CONFIG_PCIE_MICROCHIP_HOST) += pcie-microchip-host.o
 | |
| +obj-$(CONFIG_PCIE_STARFIVE_HOST) += pcie-starfive.o
 | |
| diff --git a/drivers/pci/controller/plda/pcie-plda.h b/drivers/pci/controller/plda/pcie-plda.h
 | |
| index 7b69891700a4..04e385758a2f 100644
 | |
| --- a/drivers/pci/controller/plda/pcie-plda.h
 | |
| +++ b/drivers/pci/controller/plda/pcie-plda.h
 | |
| @@ -10,10 +10,20 @@
 | |
|  #define PLDA_MAX_NUM_MSI_IRQS			32
 | |
|  
 | |
|  /* PCIe Bridge Phy Regs */
 | |
| +#define GEN_SETTINGS				0x80
 | |
| +#define  RP_ENABLE				1
 | |
| +#define PCIE_PCI_IDS_DW1			0x9c
 | |
| +#define  IDS_CLASS_CODE_SHIFT			16
 | |
| +#define  REVISION_ID_MASK			GENMASK(7, 0)
 | |
| +#define  CLASS_CODE_ID_MASK			GENMASK(31, 8)
 | |
|  #define PCIE_PCI_IRQ_DW0			0xa8
 | |
|  #define  MSIX_CAP_MASK				BIT(31)
 | |
|  #define  NUM_MSI_MSGS_MASK			GENMASK(6, 4)
 | |
|  #define  NUM_MSI_MSGS_SHIFT			4
 | |
| +#define PCI_MISC				0xb4
 | |
| +#define  PHY_FUNCTION_DIS			BIT(15)
 | |
| +#define PCIE_WINROM				0xfc
 | |
| +#define  PREF_MEM_WIN_64_SUPPORT		BIT(3)
 | |
|  
 | |
|  #define IMASK_LOCAL				0x180
 | |
|  #define  DMA_END_ENGINE_0_MASK			0x00000000u
 | |
| @@ -65,6 +75,8 @@
 | |
|  #define ISTATUS_HOST				0x18c
 | |
|  #define IMSI_ADDR				0x190
 | |
|  #define ISTATUS_MSI				0x194
 | |
| +#define PMSG_SUPPORT_RX				0x3f0
 | |
| +#define  PMSG_LTR_SUPPORT			BIT(2)
 | |
|  
 | |
|  /* PCIe Master table init defines */
 | |
|  #define ATR0_PCIE_WIN0_SRCADDR_PARAM		0x600u
 | |
| @@ -86,6 +98,8 @@
 | |
|  #define  PCIE_TX_RX_INTERFACE			0x00000000u
 | |
|  #define  PCIE_CONFIG_INTERFACE			0x00000001u
 | |
|  
 | |
| +#define CONFIG_SPACE_ADDR_OFFSET		0x1000u
 | |
| +
 | |
|  #define ATR_ENTRY_SIZE				32
 | |
|  
 | |
|  enum plda_int_event {
 | |
| @@ -200,4 +214,59 @@ static inline void plda_set_default_msi(struct plda_msi *msi)
 | |
|  	msi->vector_phy = IMSI_ADDR;
 | |
|  	msi->num_vectors = PLDA_MAX_NUM_MSI_IRQS;
 | |
|  }
 | |
| -#endif
 | |
| +
 | |
| +static inline void plda_pcie_enable_root_port(struct plda_pcie_rp *plda)
 | |
| +{
 | |
| +	u32 value;
 | |
| +
 | |
| +	value = readl_relaxed(plda->bridge_addr + GEN_SETTINGS);
 | |
| +	value |= RP_ENABLE;
 | |
| +	writel_relaxed(value, plda->bridge_addr + GEN_SETTINGS);
 | |
| +}
 | |
| +
 | |
| +static inline void plda_pcie_set_standard_class(struct plda_pcie_rp *plda)
 | |
| +{
 | |
| +	u32 value;
 | |
| +
 | |
| +	/* set class code and reserve revision id */
 | |
| +	value = readl_relaxed(plda->bridge_addr + PCIE_PCI_IDS_DW1);
 | |
| +	value &= REVISION_ID_MASK;
 | |
| +	value |= (PCI_CLASS_BRIDGE_PCI << IDS_CLASS_CODE_SHIFT);
 | |
| +	writel_relaxed(value, plda->bridge_addr + PCIE_PCI_IDS_DW1);
 | |
| +}
 | |
| +
 | |
| +static inline void plda_pcie_set_pref_win_64bit(struct plda_pcie_rp *plda)
 | |
| +{
 | |
| +	u32 value;
 | |
| +
 | |
| +	value = readl_relaxed(plda->bridge_addr + PCIE_WINROM);
 | |
| +	value |= PREF_MEM_WIN_64_SUPPORT;
 | |
| +	writel_relaxed(value, plda->bridge_addr + PCIE_WINROM);
 | |
| +}
 | |
| +
 | |
| +static inline void plda_pcie_disable_ltr(struct plda_pcie_rp *plda)
 | |
| +{
 | |
| +	u32 value;
 | |
| +
 | |
| +	value = readl_relaxed(plda->bridge_addr + PMSG_SUPPORT_RX);
 | |
| +	value &= ~PMSG_LTR_SUPPORT;
 | |
| +	writel_relaxed(value, plda->bridge_addr + PMSG_SUPPORT_RX);
 | |
| +}
 | |
| +
 | |
| +static inline void plda_pcie_disable_func(struct plda_pcie_rp *plda)
 | |
| +{
 | |
| +	u32 value;
 | |
| +
 | |
| +	value = readl_relaxed(plda->bridge_addr + PCI_MISC);
 | |
| +	value |= PHY_FUNCTION_DIS;
 | |
| +	writel_relaxed(value, plda->bridge_addr + PCI_MISC);
 | |
| +}
 | |
| +
 | |
| +static inline void plda_pcie_write_rc_bar(struct plda_pcie_rp *plda, u64 val)
 | |
| +{
 | |
| +	void __iomem *addr = plda->bridge_addr + CONFIG_SPACE_ADDR_OFFSET;
 | |
| +
 | |
| +	writel_relaxed(lower_32_bits(val), addr + PCI_BASE_ADDRESS_0);
 | |
| +	writel_relaxed(upper_32_bits(val), addr + PCI_BASE_ADDRESS_1);
 | |
| +}
 | |
| +#endif /* _PCIE_PLDA_H */
 | |
| diff --git a/drivers/pci/controller/plda/pcie-starfive.c b/drivers/pci/controller/plda/pcie-starfive.c
 | |
| new file mode 100644
 | |
| index 000000000000..9bb9f0e29565
 | |
| --- /dev/null
 | |
| +++ b/drivers/pci/controller/plda/pcie-starfive.c
 | |
| @@ -0,0 +1,473 @@
 | |
| +// SPDX-License-Identifier: GPL-2.0+
 | |
| +/*
 | |
| + * PCIe host controller driver for StarFive JH7110 Soc.
 | |
| + *
 | |
| + * Copyright (C) 2023 StarFive Technology Co., Ltd.
 | |
| + */
 | |
| +
 | |
| +#include <linux/bitfield.h>
 | |
| +#include <linux/clk.h>
 | |
| +#include <linux/delay.h>
 | |
| +#include <linux/gpio/consumer.h>
 | |
| +#include <linux/interrupt.h>
 | |
| +#include <linux/kernel.h>
 | |
| +#include <linux/mfd/syscon.h>
 | |
| +#include <linux/module.h>
 | |
| +#include <linux/of_address.h>
 | |
| +#include <linux/of_irq.h>
 | |
| +#include <linux/of_pci.h>
 | |
| +#include <linux/pci.h>
 | |
| +#include <linux/phy/phy.h>
 | |
| +#include <linux/platform_device.h>
 | |
| +#include <linux/pm_runtime.h>
 | |
| +#include <linux/regmap.h>
 | |
| +#include <linux/reset.h>
 | |
| +#include "../../pci.h"
 | |
| +
 | |
| +#include "pcie-plda.h"
 | |
| +
 | |
| +#define PCIE_FUNC_NUM			4
 | |
| +
 | |
| +/* system control */
 | |
| +#define STG_SYSCON_PCIE0_BASE			0x48
 | |
| +#define STG_SYSCON_PCIE1_BASE			0x1f8
 | |
| +
 | |
| +#define STG_SYSCON_AR_OFFSET			0x78
 | |
| +#define STG_SYSCON_AXI4_SLVL_AR_MASK		GENMASK(22, 8)
 | |
| +#define STG_SYSCON_AXI4_SLVL_PHY_AR(x)		FIELD_PREP(GENMASK(20, 17), x)
 | |
| +#define STG_SYSCON_AW_OFFSET			0x7c
 | |
| +#define STG_SYSCON_AXI4_SLVL_AW_MASK		GENMASK(14, 0)
 | |
| +#define STG_SYSCON_AXI4_SLVL_PHY_AW(x)		FIELD_PREP(GENMASK(12, 9), x)
 | |
| +#define STG_SYSCON_CLKREQ			BIT(22)
 | |
| +#define STG_SYSCON_CKREF_SRC_MASK		GENMASK(19, 18)
 | |
| +#define STG_SYSCON_RP_NEP_OFFSET		0xe8
 | |
| +#define STG_SYSCON_K_RP_NEP			BIT(8)
 | |
| +#define STG_SYSCON_LNKSTA_OFFSET		0x170
 | |
| +#define DATA_LINK_ACTIVE			BIT(5)
 | |
| +
 | |
| +/* Parameters for the waiting for link up routine */
 | |
| +#define LINK_WAIT_MAX_RETRIES	10
 | |
| +#define LINK_WAIT_USLEEP_MIN	90000
 | |
| +#define LINK_WAIT_USLEEP_MAX	100000
 | |
| +
 | |
| +struct starfive_jh7110_pcie {
 | |
| +	struct plda_pcie_rp plda;
 | |
| +	struct reset_control *resets;
 | |
| +	struct clk_bulk_data *clks;
 | |
| +	struct regmap *reg_syscon;
 | |
| +	struct gpio_desc *power_gpio;
 | |
| +	struct gpio_desc *reset_gpio;
 | |
| +	struct phy *phy;
 | |
| +
 | |
| +	unsigned int stg_pcie_base;
 | |
| +	int num_clks;
 | |
| +};
 | |
| +
 | |
| +/*
 | |
| + * The BAR0/1 of bridge should be hidden during enumeration to
 | |
| + * avoid the sizing and resource allocation by PCIe core.
 | |
| + */
 | |
| +static bool starfive_pcie_hide_rc_bar(struct pci_bus *bus, unsigned int devfn,
 | |
| +				      int offset)
 | |
| +{
 | |
| +	if (pci_is_root_bus(bus) && !devfn &&
 | |
| +	    (offset == PCI_BASE_ADDRESS_0 || offset == PCI_BASE_ADDRESS_1))
 | |
| +		return true;
 | |
| +
 | |
| +	return false;
 | |
| +}
 | |
| +
 | |
| +static int starfive_pcie_config_write(struct pci_bus *bus, unsigned int devfn,
 | |
| +				      int where, int size, u32 value)
 | |
| +{
 | |
| +	if (starfive_pcie_hide_rc_bar(bus, devfn, where))
 | |
| +		return PCIBIOS_SUCCESSFUL;
 | |
| +
 | |
| +	return pci_generic_config_write(bus, devfn, where, size, value);
 | |
| +}
 | |
| +
 | |
| +static int starfive_pcie_config_read(struct pci_bus *bus, unsigned int devfn,
 | |
| +				     int where, int size, u32 *value)
 | |
| +{
 | |
| +	if (starfive_pcie_hide_rc_bar(bus, devfn, where)) {
 | |
| +		*value = 0;
 | |
| +		return PCIBIOS_SUCCESSFUL;
 | |
| +	}
 | |
| +
 | |
| +	return pci_generic_config_read(bus, devfn, where, size, value);
 | |
| +}
 | |
| +
 | |
| +static int starfive_pcie_parse_dt(struct starfive_jh7110_pcie *pcie,
 | |
| +				  struct device *dev)
 | |
| +{
 | |
| +	int domain_nr;
 | |
| +
 | |
| +	pcie->num_clks = devm_clk_bulk_get_all(dev, &pcie->clks);
 | |
| +	if (pcie->num_clks < 0)
 | |
| +		return dev_err_probe(dev, pcie->num_clks,
 | |
| +				     "failed to get pcie clocks\n");
 | |
| +
 | |
| +	pcie->resets = devm_reset_control_array_get_exclusive(dev);
 | |
| +	if (IS_ERR(pcie->resets))
 | |
| +		return dev_err_probe(dev, PTR_ERR(pcie->resets),
 | |
| +				     "failed to get pcie resets");
 | |
| +
 | |
| +	pcie->reg_syscon =
 | |
| +		syscon_regmap_lookup_by_phandle(dev->of_node,
 | |
| +						"starfive,stg-syscon");
 | |
| +
 | |
| +	if (IS_ERR(pcie->reg_syscon))
 | |
| +		return dev_err_probe(dev, PTR_ERR(pcie->reg_syscon),
 | |
| +				     "failed to parse starfive,stg-syscon\n");
 | |
| +
 | |
| +	pcie->phy = devm_phy_optional_get(dev, NULL);
 | |
| +	if (IS_ERR(pcie->phy))
 | |
| +		return dev_err_probe(dev, PTR_ERR(pcie->phy),
 | |
| +				     "failed to get pcie phy\n");
 | |
| +
 | |
| +	domain_nr = of_get_pci_domain_nr(dev->of_node);
 | |
| +
 | |
| +	if (domain_nr < 0 || domain_nr > 1)
 | |
| +		return dev_err_probe(dev, -ENODEV,
 | |
| +				     "failed to get valid pcie domain\n");
 | |
| +
 | |
| +	if (domain_nr == 0)
 | |
| +		pcie->stg_pcie_base = STG_SYSCON_PCIE0_BASE;
 | |
| +	else
 | |
| +		pcie->stg_pcie_base = STG_SYSCON_PCIE1_BASE;
 | |
| +
 | |
| +	pcie->reset_gpio = devm_gpiod_get_optional(dev, "perst",
 | |
| +						   GPIOD_OUT_HIGH);
 | |
| +	if (IS_ERR(pcie->reset_gpio))
 | |
| +		return dev_err_probe(dev, PTR_ERR(pcie->reset_gpio),
 | |
| +				     "failed to get perst-gpio\n");
 | |
| +
 | |
| +	pcie->power_gpio = devm_gpiod_get_optional(dev, "enable",
 | |
| +						   GPIOD_OUT_LOW);
 | |
| +	if (IS_ERR(pcie->power_gpio))
 | |
| +		return dev_err_probe(dev, PTR_ERR(pcie->power_gpio),
 | |
| +				     "failed to get power-gpio\n");
 | |
| +
 | |
| +	return 0;
 | |
| +}
 | |
| +
 | |
| +static struct pci_ops starfive_pcie_ops = {
 | |
| +	.map_bus	= plda_pcie_map_bus,
 | |
| +	.read           = starfive_pcie_config_read,
 | |
| +	.write          = starfive_pcie_config_write,
 | |
| +};
 | |
| +
 | |
| +static int starfive_pcie_clk_rst_init(struct starfive_jh7110_pcie *pcie)
 | |
| +{
 | |
| +	struct device *dev = pcie->plda.dev;
 | |
| +	int ret;
 | |
| +
 | |
| +	ret = clk_bulk_prepare_enable(pcie->num_clks, pcie->clks);
 | |
| +	if (ret)
 | |
| +		return dev_err_probe(dev, ret, "failed to enable clocks\n");
 | |
| +
 | |
| +	ret = reset_control_deassert(pcie->resets);
 | |
| +	if (ret) {
 | |
| +		clk_bulk_disable_unprepare(pcie->num_clks, pcie->clks);
 | |
| +		dev_err_probe(dev, ret, "failed to deassert resets\n");
 | |
| +	}
 | |
| +
 | |
| +	return ret;
 | |
| +}
 | |
| +
 | |
| +static void starfive_pcie_clk_rst_deinit(struct starfive_jh7110_pcie *pcie)
 | |
| +{
 | |
| +	reset_control_assert(pcie->resets);
 | |
| +	clk_bulk_disable_unprepare(pcie->num_clks, pcie->clks);
 | |
| +}
 | |
| +
 | |
| +static bool starfive_pcie_link_up(struct plda_pcie_rp *plda)
 | |
| +{
 | |
| +	struct starfive_jh7110_pcie *pcie =
 | |
| +		container_of(plda, struct starfive_jh7110_pcie, plda);
 | |
| +	int ret;
 | |
| +	u32 stg_reg_val;
 | |
| +
 | |
| +	ret = regmap_read(pcie->reg_syscon,
 | |
| +			  pcie->stg_pcie_base + STG_SYSCON_LNKSTA_OFFSET,
 | |
| +			  &stg_reg_val);
 | |
| +	if (ret) {
 | |
| +		dev_err(pcie->plda.dev, "failed to read link status\n");
 | |
| +		return false;
 | |
| +	}
 | |
| +
 | |
| +	return !!(stg_reg_val & DATA_LINK_ACTIVE);
 | |
| +}
 | |
| +
 | |
| +static int starfive_pcie_host_wait_for_link(struct starfive_jh7110_pcie *pcie)
 | |
| +{
 | |
| +	int retries;
 | |
| +
 | |
| +	/* Check if the link is up or not */
 | |
| +	for (retries = 0; retries < LINK_WAIT_MAX_RETRIES; retries++) {
 | |
| +		if (starfive_pcie_link_up(&pcie->plda)) {
 | |
| +			dev_info(pcie->plda.dev, "port link up\n");
 | |
| +			return 0;
 | |
| +		}
 | |
| +		usleep_range(LINK_WAIT_USLEEP_MIN, LINK_WAIT_USLEEP_MAX);
 | |
| +	}
 | |
| +
 | |
| +	return -ETIMEDOUT;
 | |
| +}
 | |
| +
 | |
| +static int starfive_pcie_enable_phy(struct device *dev,
 | |
| +				    struct starfive_jh7110_pcie *pcie)
 | |
| +{
 | |
| +	int ret;
 | |
| +
 | |
| +	if (!pcie->phy)
 | |
| +		return 0;
 | |
| +
 | |
| +	ret = phy_init(pcie->phy);
 | |
| +	if (ret)
 | |
| +		return dev_err_probe(dev, ret,
 | |
| +				     "failed to initialize pcie phy\n");
 | |
| +
 | |
| +	ret = phy_set_mode(pcie->phy, PHY_MODE_PCIE);
 | |
| +	if (ret) {
 | |
| +		dev_err_probe(dev, ret, "failed to set pcie mode\n");
 | |
| +		goto err_phy_on;
 | |
| +	}
 | |
| +
 | |
| +	ret = phy_power_on(pcie->phy);
 | |
| +	if (ret) {
 | |
| +		dev_err_probe(dev, ret, "failed to power on pcie phy\n");
 | |
| +		goto err_phy_on;
 | |
| +	}
 | |
| +
 | |
| +	return 0;
 | |
| +
 | |
| +err_phy_on:
 | |
| +	phy_exit(pcie->phy);
 | |
| +	return ret;
 | |
| +}
 | |
| +
 | |
| +static void starfive_pcie_disable_phy(struct starfive_jh7110_pcie *pcie)
 | |
| +{
 | |
| +	phy_power_off(pcie->phy);
 | |
| +	phy_exit(pcie->phy);
 | |
| +}
 | |
| +
 | |
| +static void starfive_pcie_host_deinit(struct plda_pcie_rp *plda)
 | |
| +{
 | |
| +	struct starfive_jh7110_pcie *pcie =
 | |
| +		container_of(plda, struct starfive_jh7110_pcie, plda);
 | |
| +
 | |
| +	starfive_pcie_clk_rst_deinit(pcie);
 | |
| +	if (pcie->power_gpio)
 | |
| +		gpiod_set_value_cansleep(pcie->power_gpio, 0);
 | |
| +	starfive_pcie_disable_phy(pcie);
 | |
| +}
 | |
| +
 | |
| +static int starfive_pcie_host_init(struct plda_pcie_rp *plda)
 | |
| +{
 | |
| +	struct starfive_jh7110_pcie *pcie =
 | |
| +		container_of(plda, struct starfive_jh7110_pcie, plda);
 | |
| +	struct device *dev = plda->dev;
 | |
| +	int ret;
 | |
| +	int i;
 | |
| +
 | |
| +	ret = starfive_pcie_enable_phy(dev, pcie);
 | |
| +	if (ret)
 | |
| +		return ret;
 | |
| +
 | |
| +	regmap_update_bits(pcie->reg_syscon,
 | |
| +			   pcie->stg_pcie_base + STG_SYSCON_RP_NEP_OFFSET,
 | |
| +			   STG_SYSCON_K_RP_NEP, STG_SYSCON_K_RP_NEP);
 | |
| +
 | |
| +	regmap_update_bits(pcie->reg_syscon,
 | |
| +			   pcie->stg_pcie_base + STG_SYSCON_AW_OFFSET,
 | |
| +			   STG_SYSCON_CKREF_SRC_MASK,
 | |
| +			   FIELD_PREP(STG_SYSCON_CKREF_SRC_MASK, 2));
 | |
| +
 | |
| +	regmap_update_bits(pcie->reg_syscon,
 | |
| +			   pcie->stg_pcie_base + STG_SYSCON_AW_OFFSET,
 | |
| +			   STG_SYSCON_CLKREQ, STG_SYSCON_CLKREQ);
 | |
| +
 | |
| +	ret = starfive_pcie_clk_rst_init(pcie);
 | |
| +	if (ret)
 | |
| +		return ret;
 | |
| +
 | |
| +	if (pcie->power_gpio)
 | |
| +		gpiod_set_value_cansleep(pcie->power_gpio, 1);
 | |
| +
 | |
| +	if (pcie->reset_gpio)
 | |
| +		gpiod_set_value_cansleep(pcie->reset_gpio, 1);
 | |
| +
 | |
| +	/* Disable physical functions except #0 */
 | |
| +	for (i = 1; i < PCIE_FUNC_NUM; i++) {
 | |
| +		regmap_update_bits(pcie->reg_syscon,
 | |
| +				   pcie->stg_pcie_base + STG_SYSCON_AR_OFFSET,
 | |
| +				   STG_SYSCON_AXI4_SLVL_AR_MASK,
 | |
| +				   STG_SYSCON_AXI4_SLVL_PHY_AR(i));
 | |
| +
 | |
| +		regmap_update_bits(pcie->reg_syscon,
 | |
| +				   pcie->stg_pcie_base + STG_SYSCON_AW_OFFSET,
 | |
| +				   STG_SYSCON_AXI4_SLVL_AW_MASK,
 | |
| +				   STG_SYSCON_AXI4_SLVL_PHY_AW(i));
 | |
| +
 | |
| +		plda_pcie_disable_func(plda);
 | |
| +	}
 | |
| +
 | |
| +	regmap_update_bits(pcie->reg_syscon,
 | |
| +			   pcie->stg_pcie_base + STG_SYSCON_AR_OFFSET,
 | |
| +			   STG_SYSCON_AXI4_SLVL_AR_MASK, 0);
 | |
| +	regmap_update_bits(pcie->reg_syscon,
 | |
| +			   pcie->stg_pcie_base + STG_SYSCON_AW_OFFSET,
 | |
| +			   STG_SYSCON_AXI4_SLVL_AW_MASK, 0);
 | |
| +
 | |
| +	plda_pcie_enable_root_port(plda);
 | |
| +	plda_pcie_write_rc_bar(plda, 0);
 | |
| +
 | |
| +	/* PCIe PCI Standard Configuration Identification Settings. */
 | |
| +	plda_pcie_set_standard_class(plda);
 | |
| +
 | |
| +	/*
 | |
| +	 * The LTR message forwarding of PCIe Message Reception was set by core
 | |
| +	 * as default, but the forward id & addr are also need to be reset.
 | |
| +	 * If we do not disable LTR message forwarding here, or set a legal
 | |
| +	 * forwarding address, the kernel will get stuck after the driver probe.
 | |
| +	 * To workaround, disable the LTR message forwarding support on
 | |
| +	 * PCIe Message Reception.
 | |
| +	 */
 | |
| +	plda_pcie_disable_ltr(plda);
 | |
| +
 | |
| +	/* Prefetchable memory window 64-bit addressing support */
 | |
| +	plda_pcie_set_pref_win_64bit(plda);
 | |
| +
 | |
| +	/*
 | |
| +	 * Ensure that PERST has been asserted for at least 100 ms,
 | |
| +	 * the sleep value is T_PVPERL from PCIe CEM spec r2.0 (Table 2-4)
 | |
| +	 */
 | |
| +	msleep(100);
 | |
| +	if (pcie->reset_gpio)
 | |
| +		gpiod_set_value_cansleep(pcie->reset_gpio, 0);
 | |
| +
 | |
| +	/*
 | |
| +	 * With a Downstream Port (<=5GT/s), software must wait a minimum
 | |
| +	 * of 100ms following exit from a conventional reset before
 | |
| +	 * sending a configuration request to the device.
 | |
| +	 */
 | |
| +	msleep(PCIE_RESET_CONFIG_DEVICE_WAIT_MS);
 | |
| +
 | |
| +	if (starfive_pcie_host_wait_for_link(pcie))
 | |
| +		dev_info(dev, "port link down\n");
 | |
| +
 | |
| +	return 0;
 | |
| +}
 | |
| +
 | |
| +static const struct plda_pcie_host_ops sf_host_ops = {
 | |
| +	.host_init = starfive_pcie_host_init,
 | |
| +	.host_deinit = starfive_pcie_host_deinit,
 | |
| +};
 | |
| +
 | |
| +static const struct plda_event stf_pcie_event = {
 | |
| +	.intx_event = EVENT_PM_MSI_INT_INTX,
 | |
| +	.msi_event  = EVENT_PM_MSI_INT_MSI
 | |
| +};
 | |
| +
 | |
| +static int starfive_pcie_probe(struct platform_device *pdev)
 | |
| +{
 | |
| +	struct starfive_jh7110_pcie *pcie;
 | |
| +	struct device *dev = &pdev->dev;
 | |
| +	struct plda_pcie_rp *plda;
 | |
| +	int ret;
 | |
| +
 | |
| +	pcie = devm_kzalloc(dev, sizeof(*pcie), GFP_KERNEL);
 | |
| +	if (!pcie)
 | |
| +		return -ENOMEM;
 | |
| +
 | |
| +	plda = &pcie->plda;
 | |
| +	plda->dev = dev;
 | |
| +
 | |
| +	ret = starfive_pcie_parse_dt(pcie, dev);
 | |
| +	if (ret)
 | |
| +		return ret;
 | |
| +
 | |
| +	plda->host_ops = &sf_host_ops;
 | |
| +	plda->num_events = PLDA_MAX_EVENT_NUM;
 | |
| +	/* mask doorbell event */
 | |
| +	plda->events_bitmap = GENMASK(PLDA_INT_EVENT_NUM - 1, 0)
 | |
| +			     & ~BIT(PLDA_AXI_DOORBELL)
 | |
| +			     & ~BIT(PLDA_PCIE_DOORBELL);
 | |
| +	plda->events_bitmap <<= PLDA_NUM_DMA_EVENTS;
 | |
| +	ret = plda_pcie_host_init(&pcie->plda, &starfive_pcie_ops,
 | |
| +				  &stf_pcie_event);
 | |
| +	if (ret)
 | |
| +		return ret;
 | |
| +
 | |
| +	pm_runtime_enable(&pdev->dev);
 | |
| +	pm_runtime_get_sync(&pdev->dev);
 | |
| +	platform_set_drvdata(pdev, pcie);
 | |
| +
 | |
| +	return 0;
 | |
| +}
 | |
| +
 | |
| +static void starfive_pcie_remove(struct platform_device *pdev)
 | |
| +{
 | |
| +	struct starfive_jh7110_pcie *pcie = platform_get_drvdata(pdev);
 | |
| +
 | |
| +	pm_runtime_put(&pdev->dev);
 | |
| +	pm_runtime_disable(&pdev->dev);
 | |
| +	plda_pcie_host_deinit(&pcie->plda);
 | |
| +	platform_set_drvdata(pdev, NULL);
 | |
| +}
 | |
| +
 | |
| +static int starfive_pcie_suspend_noirq(struct device *dev)
 | |
| +{
 | |
| +	struct starfive_jh7110_pcie *pcie = dev_get_drvdata(dev);
 | |
| +
 | |
| +	clk_bulk_disable_unprepare(pcie->num_clks, pcie->clks);
 | |
| +	starfive_pcie_disable_phy(pcie);
 | |
| +
 | |
| +	return 0;
 | |
| +}
 | |
| +
 | |
| +static int starfive_pcie_resume_noirq(struct device *dev)
 | |
| +{
 | |
| +	struct starfive_jh7110_pcie *pcie = dev_get_drvdata(dev);
 | |
| +	int ret;
 | |
| +
 | |
| +	ret = starfive_pcie_enable_phy(dev, pcie);
 | |
| +	if (ret)
 | |
| +		return ret;
 | |
| +
 | |
| +	ret = clk_bulk_prepare_enable(pcie->num_clks, pcie->clks);
 | |
| +	if (ret) {
 | |
| +		dev_err(dev, "failed to enable clocks\n");
 | |
| +		starfive_pcie_disable_phy(pcie);
 | |
| +		return ret;
 | |
| +	}
 | |
| +
 | |
| +	return 0;
 | |
| +}
 | |
| +
 | |
| +static const struct dev_pm_ops starfive_pcie_pm_ops = {
 | |
| +	NOIRQ_SYSTEM_SLEEP_PM_OPS(starfive_pcie_suspend_noirq,
 | |
| +				  starfive_pcie_resume_noirq)
 | |
| +};
 | |
| +
 | |
| +static const struct of_device_id starfive_pcie_of_match[] = {
 | |
| +	{ .compatible = "starfive,jh7110-pcie", },
 | |
| +	{ /* sentinel */ }
 | |
| +};
 | |
| +MODULE_DEVICE_TABLE(of, starfive_pcie_of_match);
 | |
| +
 | |
| +static struct platform_driver starfive_pcie_driver = {
 | |
| +	.driver = {
 | |
| +		.name = "pcie-starfive",
 | |
| +		.of_match_table = of_match_ptr(starfive_pcie_of_match),
 | |
| +		.pm = pm_sleep_ptr(&starfive_pcie_pm_ops),
 | |
| +	},
 | |
| +	.probe = starfive_pcie_probe,
 | |
| +	.remove_new = starfive_pcie_remove,
 | |
| +};
 | |
| +module_platform_driver(starfive_pcie_driver);
 | |
| +
 | |
| +MODULE_DESCRIPTION("StarFive JH7110 PCIe host driver");
 | |
| +MODULE_LICENSE("GPL v2");
 | |
| -- 
 | |
| 2.43.0
 | |
| 
 | |
| 
 | |
| From bb33f9248da218662ccf28d1730833a18ce22d9f Mon Sep 17 00:00:00 2001
 | |
| From: Minda Chen <minda.chen@starfivetech.com>
 | |
| Date: Mon, 8 Jan 2024 19:06:12 +0800
 | |
| Subject: [PATCH 22/23] riscv: dts: starfive: add PCIe dts configuration for
 | |
|  JH7110
 | |
| 
 | |
| Add PCIe dts configuraion for JH7110 SoC platform.
 | |
| 
 | |
| Signed-off-by: Minda Chen <minda.chen@starfivetech.com>
 | |
| Reviewed-by: Hal Feng <hal.feng@starfivetech.com>
 | |
| Message-ID: <20240108110612.19048-23-minda.chen@starfivetech.com>
 | |
| Signed-off-by: Aurelien Jarno <aurelien@aurel32.net>
 | |
| ---
 | |
|  .../jh7110-starfive-visionfive-2.dtsi         | 64 ++++++++++++++
 | |
|  arch/riscv/boot/dts/starfive/jh7110.dtsi      | 86 +++++++++++++++++++
 | |
|  2 files changed, 150 insertions(+)
 | |
| 
 | |
| diff --git a/arch/riscv/boot/dts/starfive/jh7110-starfive-visionfive-2.dtsi b/arch/riscv/boot/dts/starfive/jh7110-starfive-visionfive-2.dtsi
 | |
| index b89e9791efa7..2f8056d6f817 100644
 | |
| --- a/arch/riscv/boot/dts/starfive/jh7110-starfive-visionfive-2.dtsi
 | |
| +++ b/arch/riscv/boot/dts/starfive/jh7110-starfive-visionfive-2.dtsi
 | |
| @@ -287,6 +287,22 @@ &pwmdac {
 | |
|  	status = "okay";
 | |
|  };
 | |
|  
 | |
| +&pcie0 {
 | |
| +	perst-gpios = <&sysgpio 26 GPIO_ACTIVE_LOW>;
 | |
| +	phys = <&pciephy0>;
 | |
| +	pinctrl-names = "default";
 | |
| +	pinctrl-0 = <&pcie0_pins>;
 | |
| +	status = "okay";
 | |
| +};
 | |
| +
 | |
| +&pcie1 {
 | |
| +	perst-gpios = <&sysgpio 28 GPIO_ACTIVE_LOW>;
 | |
| +	phys = <&pciephy1>;
 | |
| +	pinctrl-names = "default";
 | |
| +	pinctrl-0 = <&pcie1_pins>;
 | |
| +	status = "okay";
 | |
| +};
 | |
| +
 | |
|  &qspi {
 | |
|  	#address-cells = <1>;
 | |
|  	#size-cells = <0>;
 | |
| @@ -513,6 +529,54 @@ GPOEN_ENABLE,
 | |
|  		};
 | |
|  	};
 | |
|  
 | |
| +	pcie0_pins: pcie0-0 {
 | |
| +		clkreq-pins {
 | |
| +			pinmux = <GPIOMUX(27, GPOUT_LOW,
 | |
| +					      GPOEN_DISABLE,
 | |
| +					      GPI_NONE)>;
 | |
| +			bias-pull-down;
 | |
| +			drive-strength = <2>;
 | |
| +			input-enable;
 | |
| +			input-schmitt-disable;
 | |
| +			slew-rate = <0>;
 | |
| +		};
 | |
| +
 | |
| +		wake-pins {
 | |
| +			pinmux = <GPIOMUX(32, GPOUT_LOW,
 | |
| +					      GPOEN_DISABLE,
 | |
| +					      GPI_NONE)>;
 | |
| +			bias-pull-up;
 | |
| +			drive-strength = <2>;
 | |
| +			input-enable;
 | |
| +			input-schmitt-disable;
 | |
| +			slew-rate = <0>;
 | |
| +		};
 | |
| +	};
 | |
| +
 | |
| +	pcie1_pins: pcie1-0 {
 | |
| +		clkreq-pins {
 | |
| +			pinmux = <GPIOMUX(29, GPOUT_LOW,
 | |
| +					      GPOEN_DISABLE,
 | |
| +					      GPI_NONE)>;
 | |
| +			bias-pull-down;
 | |
| +			drive-strength = <2>;
 | |
| +			input-enable;
 | |
| +			input-schmitt-disable;
 | |
| +			slew-rate = <0>;
 | |
| +		};
 | |
| +
 | |
| +		wake-pins {
 | |
| +			pinmux = <GPIOMUX(21, GPOUT_LOW,
 | |
| +					      GPOEN_DISABLE,
 | |
| +					      GPI_NONE)>;
 | |
| +			bias-pull-up;
 | |
| +			drive-strength = <2>;
 | |
| +			input-enable;
 | |
| +			input-schmitt-disable;
 | |
| +			slew-rate = <0>;
 | |
| +		};
 | |
| +	};
 | |
| +
 | |
|  	spi0_pins: spi0-0 {
 | |
|  		mosi-pins {
 | |
|  			pinmux = <GPIOMUX(52, GPOUT_SYS_SPI0_TXD,
 | |
| diff --git a/arch/riscv/boot/dts/starfive/jh7110.dtsi b/arch/riscv/boot/dts/starfive/jh7110.dtsi
 | |
| index 45213cdf50dc..dfa2f94ed5b2 100644
 | |
| --- a/arch/riscv/boot/dts/starfive/jh7110.dtsi
 | |
| +++ b/arch/riscv/boot/dts/starfive/jh7110.dtsi
 | |
| @@ -1138,5 +1138,91 @@ voutcrg: clock-controller@295c0000 {
 | |
|  			#reset-cells = <1>;
 | |
|  			power-domains = <&pwrc JH7110_PD_VOUT>;
 | |
|  		};
 | |
| +
 | |
| +		pcie0: pcie@940000000 {
 | |
| +			compatible = "starfive,jh7110-pcie";
 | |
| +			reg = <0x9 0x40000000 0x0 0x1000000>,
 | |
| +			      <0x0 0x2b000000 0x0 0x100000>;
 | |
| +			reg-names = "cfg", "apb";
 | |
| +			linux,pci-domain = <0>;
 | |
| +			#address-cells = <3>;
 | |
| +			#size-cells = <2>;
 | |
| +			#interrupt-cells = <1>;
 | |
| +			ranges = <0x82000000  0x0 0x30000000  0x0 0x30000000 0x0 0x08000000>,
 | |
| +				 <0xc3000000  0x9 0x00000000  0x9 0x00000000 0x0 0x40000000>;
 | |
| +			interrupts = <56>;
 | |
| +			interrupt-map-mask = <0x0 0x0 0x0 0x7>;
 | |
| +			interrupt-map = <0x0 0x0 0x0 0x1 &pcie_intc0 0x1>,
 | |
| +					<0x0 0x0 0x0 0x2 &pcie_intc0 0x2>,
 | |
| +					<0x0 0x0 0x0 0x3 &pcie_intc0 0x3>,
 | |
| +					<0x0 0x0 0x0 0x4 &pcie_intc0 0x4>;
 | |
| +			msi-controller;
 | |
| +			device_type = "pci";
 | |
| +			starfive,stg-syscon = <&stg_syscon>;
 | |
| +			bus-range = <0x0 0xff>;
 | |
| +			clocks = <&syscrg JH7110_SYSCLK_NOC_BUS_STG_AXI>,
 | |
| +				 <&stgcrg JH7110_STGCLK_PCIE0_TL>,
 | |
| +				 <&stgcrg JH7110_STGCLK_PCIE0_AXI_MST0>,
 | |
| +				 <&stgcrg JH7110_STGCLK_PCIE0_APB>;
 | |
| +			clock-names = "noc", "tl", "axi_mst0", "apb";
 | |
| +			resets = <&stgcrg JH7110_STGRST_PCIE0_AXI_MST0>,
 | |
| +				 <&stgcrg JH7110_STGRST_PCIE0_AXI_SLV0>,
 | |
| +				 <&stgcrg JH7110_STGRST_PCIE0_AXI_SLV>,
 | |
| +				 <&stgcrg JH7110_STGRST_PCIE0_BRG>,
 | |
| +				 <&stgcrg JH7110_STGRST_PCIE0_CORE>,
 | |
| +				 <&stgcrg JH7110_STGRST_PCIE0_APB>;
 | |
| +			reset-names = "mst0", "slv0", "slv", "brg",
 | |
| +				      "core", "apb";
 | |
| +			status = "disabled";
 | |
| +
 | |
| +			pcie_intc0: interrupt-controller {
 | |
| +				#address-cells = <0>;
 | |
| +				#interrupt-cells = <1>;
 | |
| +				interrupt-controller;
 | |
| +			};
 | |
| +		};
 | |
| +
 | |
| +		pcie1: pcie@9c0000000 {
 | |
| +			compatible = "starfive,jh7110-pcie";
 | |
| +			reg = <0x9 0xc0000000 0x0 0x1000000>,
 | |
| +			      <0x0 0x2c000000 0x0 0x100000>;
 | |
| +			reg-names = "cfg", "apb";
 | |
| +			linux,pci-domain = <1>;
 | |
| +			#address-cells = <3>;
 | |
| +			#size-cells = <2>;
 | |
| +			#interrupt-cells = <1>;
 | |
| +			ranges = <0x82000000  0x0 0x38000000  0x0 0x38000000 0x0 0x08000000>,
 | |
| +				 <0xc3000000  0x9 0x80000000  0x9 0x80000000 0x0 0x40000000>;
 | |
| +			interrupts = <57>;
 | |
| +			interrupt-map-mask = <0x0 0x0 0x0 0x7>;
 | |
| +			interrupt-map = <0x0 0x0 0x0 0x1 &pcie_intc1 0x1>,
 | |
| +					<0x0 0x0 0x0 0x2 &pcie_intc1 0x2>,
 | |
| +					<0x0 0x0 0x0 0x3 &pcie_intc1 0x3>,
 | |
| +					<0x0 0x0 0x0 0x4 &pcie_intc1 0x4>;
 | |
| +			msi-controller;
 | |
| +			device_type = "pci";
 | |
| +			starfive,stg-syscon = <&stg_syscon>;
 | |
| +			bus-range = <0x0 0xff>;
 | |
| +			clocks = <&syscrg JH7110_SYSCLK_NOC_BUS_STG_AXI>,
 | |
| +				 <&stgcrg JH7110_STGCLK_PCIE1_TL>,
 | |
| +				 <&stgcrg JH7110_STGCLK_PCIE1_AXI_MST0>,
 | |
| +				 <&stgcrg JH7110_STGCLK_PCIE1_APB>;
 | |
| +			clock-names = "noc", "tl", "axi_mst0", "apb";
 | |
| +			resets = <&stgcrg JH7110_STGRST_PCIE1_AXI_MST0>,
 | |
| +				 <&stgcrg JH7110_STGRST_PCIE1_AXI_SLV0>,
 | |
| +				 <&stgcrg JH7110_STGRST_PCIE1_AXI_SLV>,
 | |
| +				 <&stgcrg JH7110_STGRST_PCIE1_BRG>,
 | |
| +				 <&stgcrg JH7110_STGRST_PCIE1_CORE>,
 | |
| +				 <&stgcrg JH7110_STGRST_PCIE1_APB>;
 | |
| +			reset-names = "mst0", "slv0", "slv", "brg",
 | |
| +				      "core", "apb";
 | |
| +			status = "disabled";
 | |
| +
 | |
| +			pcie_intc1: interrupt-controller {
 | |
| +				#address-cells = <0>;
 | |
| +				#interrupt-cells = <1>;
 | |
| +				interrupt-controller;
 | |
| +			};
 | |
| +		};
 | |
|  	};
 | |
|  };
 | |
| -- 
 | |
| 2.43.0
 | |
| 
 | |
| 
 | |
| From 744fa2c80f19985d27a786af5e78cc9ce945b06c Mon Sep 17 00:00:00 2001
 | |
| From: Xingyu Wu <xingyu.wu@starfivetech.com>
 | |
| Date: Mon, 21 Aug 2023 23:29:15 +0800
 | |
| Subject: [PATCH 23/23] clk: starfive: jh7110-sys: Fix lower rate of CPUfreq by
 | |
|  setting PLL0 rate to 1.5GHz
 | |
| 
 | |
| CPUfreq supports 4 cpu frequency loads on 375/500/750/1500MHz.
 | |
| But now PLL0 rate is 1GHz and the cpu frequency loads become
 | |
| 333/500/500/1000MHz in fact.
 | |
| 
 | |
| So PLL0 rate should be set to 1.5GHz. Change the parent of cpu_root clock
 | |
| and the divider of cpu_core before the setting.
 | |
| 
 | |
| Reviewed-by: Hal Feng <hal.feng@starfivetech.com>
 | |
| Fixes: e2c510d6d630 ("riscv: dts: starfive: Add cpu scaling for JH7110 SoC")
 | |
| Signed-off-by: Xingyu Wu <xingyu.wu@starfivetech.com>
 | |
| Link: https://lore.kernel.org/r/20230821152915.208366-1-xingyu.wu@starfivetech.com
 | |
| Signed-off-by: Aurelien Jarno <aurelien@aurel32.net>
 | |
| ---
 | |
|  .../clk/starfive/clk-starfive-jh7110-sys.c    | 47 ++++++++++++++++++-
 | |
|  1 file changed, 46 insertions(+), 1 deletion(-)
 | |
| 
 | |
| diff --git a/drivers/clk/starfive/clk-starfive-jh7110-sys.c b/drivers/clk/starfive/clk-starfive-jh7110-sys.c
 | |
| index 3884eff9fe93..b6b9e967dfc7 100644
 | |
| --- a/drivers/clk/starfive/clk-starfive-jh7110-sys.c
 | |
| +++ b/drivers/clk/starfive/clk-starfive-jh7110-sys.c
 | |
| @@ -501,7 +501,52 @@ static int __init jh7110_syscrg_probe(struct platform_device *pdev)
 | |
|  	if (ret)
 | |
|  		return ret;
 | |
|  
 | |
| -	return jh7110_reset_controller_register(priv, "rst-sys", 0);
 | |
| +	ret = jh7110_reset_controller_register(priv, "rst-sys", 0);
 | |
| +	if (ret)
 | |
| +		return ret;
 | |
| +
 | |
| +	/*
 | |
| +	 * Set PLL0 rate to 1.5GHz
 | |
| +	 * In order to not affect the cpu when the PLL0 rate is changing,
 | |
| +	 * we need to switch the parent of cpu_root clock to osc clock first,
 | |
| +	 * and then switch back after setting the PLL0 rate.
 | |
| +	 */
 | |
| +	pllclk = clk_get(priv->dev, "pll0_out");
 | |
| +	if (!IS_ERR(pllclk)) {
 | |
| +		struct clk *osc = clk_get(&pdev->dev, "osc");
 | |
| +		struct clk *cpu_root = priv->reg[JH7110_SYSCLK_CPU_ROOT].hw.clk;
 | |
| +		struct clk *cpu_core = priv->reg[JH7110_SYSCLK_CPU_CORE].hw.clk;
 | |
| +
 | |
| +		if (IS_ERR(osc)) {
 | |
| +			clk_put(pllclk);
 | |
| +			return PTR_ERR(osc);
 | |
| +		}
 | |
| +
 | |
| +		/*
 | |
| +		 * CPU need voltage regulation by CPUfreq if set 1.5GHz.
 | |
| +		 * So in this driver, cpu_core need to be set the divider to be 2 first
 | |
| +		 * and will be 750M after setting parent.
 | |
| +		 */
 | |
| +		ret = clk_set_rate(cpu_core, clk_get_rate(cpu_core) / 2);
 | |
| +		if (ret)
 | |
| +			goto failed_set;
 | |
| +
 | |
| +		ret = clk_set_parent(cpu_root, osc);
 | |
| +		if (ret)
 | |
| +			goto failed_set;
 | |
| +
 | |
| +		ret = clk_set_rate(pllclk, 1500000000);
 | |
| +		if (ret)
 | |
| +			goto failed_set;
 | |
| +
 | |
| +		ret = clk_set_parent(cpu_root, pllclk);
 | |
| +
 | |
| +failed_set:
 | |
| +		clk_put(pllclk);
 | |
| +		clk_put(osc);
 | |
| +	}
 | |
| +
 | |
| +	return ret;
 | |
|  }
 | |
|  
 | |
|  static const struct of_device_id jh7110_syscrg_match[] = {
 | |
| -- 
 | |
| 2.43.0
 | |
| 
 |