* [PATCH 0/5 RFC] R-Car Gen2 PCIe host driver
@ 2014-02-26 16:08 Phil Edworthy
2014-02-26 16:08 ` [PATCH 1/5] PCI: host: Add Renesas R-Car PCIe driver Phil Edworthy
` (4 more replies)
0 siblings, 5 replies; 10+ messages in thread
From: Phil Edworthy @ 2014-02-26 16:08 UTC (permalink / raw)
To: linux-pci
Cc: linux-sh, Bjorn Helgaas, Valentine Barshak, Simon Horman,
Magnus Damm, Phil Edworthy
This is an initial version of a PCIe Host driver for the R-Car Gen2 devices,
i.e. R-Car H2 (r8a7790) and R-Car M2 (r8a7791).
This is RFC as there is some work required for DT support.
All feedback welcome!
Phil
root@koelsch:~# lspci -vv
00:00.0 PCI bridge: Renesas Technology Corp. Device 001f (prog-if 00 [Normal decode])
Control: I/O+ Mem+ BusMaster+ SpecCycle- MemWINV- VGASnoop- ParErr+ Stepping- SERR+ FastB2B- DisINTx-
Status: Cap+ 66MHz- UDF- FastB2B- ParErr- DEVSELúst >TAbort- <TAbort- <MAbort- >SERR- <PERR- INTx-
Latency: 0, Cache Line Size: 64 bytes
Bus: primary\0, secondary\x01, subordinate\x01, sec-latency=0
I/O behind bridge: 00000000-00000fff
Memory behind bridge: 00000000-000fffff
Prefetchable memory behind bridge: 00000000-000fffff
Secondary status: 66MHz- FastB2B- ParErr- DEVSELúst >TAbort- <TAbort- <MAbort- <SERR- <PERR-
BridgeCtl: Parity+ SERR- NoISA- VGA- MAbort- >Reset- FastB2B-
PriDiscTmr- SecDiscTmr- DiscTmrStat- DiscTmrSERREn-
Capabilities: [40] Power Management version 3
Flags: PMEClk- DSI- D1- D2- AuxCurrent=0mA PME(D0+,D1-,D2-,D3hot+,D3cold+)
Status: D0 NoSoftRst- PME-Enable- DSel=0 DScale=0 PME-
Capabilities: [50] MSI: Enable- Count=1/1 Maskable+ 64bit+
Address: 0000000000000000 Data: 0000
Masking: fffffffe Pending: 00000000
Capabilities: [70] Express (v2) Root Port (Slot-), MSI 00
DevCap: MaxPayload 128 bytes, PhantFunc 0, Latency L0s <64ns, L1 <1us
ExtTag+ RBE+ FLReset-
DevCtl: Report errors: Correctable- Non-Fatal- Fatal- Unsupported-
RlxdOrd+ ExtTag- PhantFunc- AuxPwr- NoSnoop+
MaxPayload 128 bytes, MaxReadReq 512 bytes
DevSta: CorrErr- UncorrErr- FatalErr- UnsuppReq- AuxPwr- TransPend-
LnkCap: Port #0, Speed 5GT/s, Width x1, ASPM L0s, Latency L0 unlimited, L1 unlimited
ClockPM- Surprise- LLActRep+ BwNot-
LnkCtl: ASPM Disabled; RCB 64 bytes Disabled- Retrain- CommClk-
ExtSynch- ClockPM- AutWidDis- BWInt- AutBWInt-
LnkSta: Speed 5GT/s, Width x1, TrErr- Train- SlotClk- DLActive+ BWMgmt- ABWMgmt-
RootCtl: ErrCorrectable- ErrNon-Fatal- ErrFatal- PMEIntEna- CRSVisible-
RootCap: CRSVisible-
RootSta: PME ReqID 0000, PMEStatus- PMEPending-
DevCap2: Completion Timeout: Not Supported, TimeoutDis+, LTR-, OBFF Not Supported ARIFwd-
DevCtl2: Completion Timeout: 50us to 50ms, TimeoutDis-, LTR-, OBFF Disabled ARIFwd-
LnkCtl2: Target Link Speed: 5GT/s, EnterCompliance- SpeedDis-
Transmit Margin: Normal Operating Range, EnterModifiedCompliance- ComplianceSOS-
Compliance De-emphasis: -6dB
LnkSta2: Current De-emphasis Level: -6dB, EqualizationComplete-, EqualizationPhase1-
EqualizationPhase2-, EqualizationPhase3-, LinkEqualizationRequest-
Capabilities: [100 v1] Virtual Channel
Caps: LPEVC=0 RefClk\x100ns PATEntryBits=1
Arb: Fixed- WRR32- WRR64- WRR128-
Ctrl: ArbSelect=Fixed
Status: InProgress-
VC0: Caps: PATOffset\0 MaxTimeSlots=1 RejSnoopTrans-
Arb: Fixed- WRR32- WRR64- WRR128- TWRR128- WRR256-
Ctrl: Enable+ ID=0 ArbSelect=Fixed TC/VCÿ
Status: NegoPending- InProgress-
Capabilities: [1b0 v1] Device Serial Number 00-00-00-00-00-00-00-00
Kernel driver in use: pcieport
01:00.0 Ethernet controller: Intel Corporation I350 Gigabit Network Connection (rev 01)
Subsystem: Intel Corporation Ethernet Server Adapter I350-T2
Control: I/O- Mem+ BusMaster+ SpecCycle- MemWINV- VGASnoop- ParErr+ Stepping- SERR+ FastB2B- DisINTx-
Status: Cap+ 66MHz- UDF- FastB2B- ParErr- DEVSELúst >TAbort- <TAbort- <MAbort- >SERR- <PERR- INTx-
Latency: 0, Cache Line Size: 64 bytes
Interrupt: pin A routed to IRQ 148
Region 0: Memory at 30000000 (32-bit, non-prefetchable) [size=1M]
Region 3: Memory at 30200000 (32-bit, non-prefetchable) [size\x16K]
Capabilities: [40] Power Management version 3
Flags: PMEClk- DSI+ D1- D2- AuxCurrent=0mA PME(D0+,D1-,D2-,D3hot+,D3cold+)
Status: D0 NoSoftRst+ PME-Enable- DSel=0 DScale=1 PME-
Capabilities: [50] MSI: Enable- Count=1/1 Maskable+ 64bit+
Address: 0000000000000000 Data: 0000
Masking: 00000000 Pending: 00000000
Capabilities: [70] MSI-X: Enable- Count\x10 Masked-
Vector table: BAR=3 offset\0000000
PBA: BAR=3 offset\0002000
Capabilities: [a0] Express (v2) Endpoint, MSI 00
DevCap: MaxPayload 512 bytes, PhantFunc 0, Latency L0s <512ns, L1 <64us
ExtTag- AttnBtn- AttnInd- PwrInd- RBE+ FLReset+
DevCtl: Report errors: Correctable+ Non-Fatal+ Fatal+ Unsupported+
RlxdOrd+ ExtTag- PhantFunc- AuxPwr- NoSnoop+ FLReset-
MaxPayload 128 bytes, MaxReadReq 512 bytes
DevSta: CorrErr- UncorrErr- FatalErr- UnsuppReq- AuxPwr+ TransPend-
LnkCap: Port #0, Speed 5GT/s, Width x4, ASPM L0s L1, Latency L0 <4us, L1 <32us
ClockPM- Surprise- LLActRep- BwNot-
LnkCtl: ASPM Disabled; RCB 64 bytes Disabled- Retrain- CommClk-
ExtSynch- ClockPM- AutWidDis- BWInt- AutBWInt-
LnkSta: Speed 5GT/s, Width x1, TrErr- Train- SlotClk+ DLActive- BWMgmt- ABWMgmt-
DevCap2: Completion Timeout: Range ABCD, TimeoutDis+, LTR+, OBFF Not Supported
DevCtl2: Completion Timeout: 50us to 50ms, TimeoutDis-, LTR-, OBFF Disabled
LnkCtl2: Target Link Speed: 5GT/s, EnterCompliance- SpeedDis-
Transmit Margin: Normal Operating Range, EnterModifiedCompliance- ComplianceSOS-
Compliance De-emphasis: -6dB
LnkSta2: Current De-emphasis Level: -6dB, EqualizationComplete-, EqualizationPhase1-
EqualizationPhase2-, EqualizationPhase3-, LinkEqualizationRequest-
Capabilities: [100 v2] Advanced Error Reporting
UESta: DLP- SDES- TLP- FCP- CmpltTO- CmpltAbrt- UnxCmplt- RxOF- MalfTLP- ECRC- UnsupReq- ACSViol-
UEMsk: DLP- SDES- TLP- FCP- CmpltTO- CmpltAbrt- UnxCmplt- RxOF- MalfTLP- ECRC- UnsupReq- ACSViol-
UESvrt: DLP+ SDES+ TLP- FCP+ CmpltTO- CmpltAbrt- UnxCmplt- RxOF+ MalfTLP+ ECRC- UnsupReq- ACSViol-
CESta: RxErr- BadTLP- BadDLLP- Rollover- Timeout- NonFatalErr+
CEMsk: RxErr- BadTLP- BadDLLP- Rollover- Timeout- NonFatalErr+
AERCap: First Error Pointer: 00, GenCap+ CGenEn- ChkCap+ ChkEn-
Capabilities: [140 v1] Device Serial Number a0-36-9f-ff-ff-23-18-c0
Capabilities: [150 v1] Alternative Routing-ID Interpretation (ARI)
ARICap: MFVC- ACS-, Next Function: 1
ARICtl: MFVC- ACS-, Function Group: 0
Capabilities: [160 v1] Single Root I/O Virtualization (SR-IOV)
IOVCap: Migration-, Interrupt Message Number: 000
IOVCtl: Enable- Migration- Interrupt- MSE- ARIHierarchy-
IOVSta: Migration-
Initial VFs: 8, Total VFs: 8, Number of VFs: 0, Function Dependency Link: 00
VF offset: 384, stride: 4, Device ID: 1520
Supported Page Size: 00000553, System Page Size: 00000001
Region 0: Memory at 0000000000000000 (64-bit, prefetchable)
Region 3: Memory at 0000000000000000 (64-bit, prefetchable)
VF Migration: offset: 00000000, BIR: 0
Capabilities: [1a0 v1] Transaction Processing Hints
Device specific mode supported
Steering table in TPH capability structure
Capabilities: [1c0 v1] Latency Tolerance Reporting
Max snoop latency: 0ns
Max no snoop latency: 0ns
Capabilities: [1d0 v1] Access Control Services
ACSCap: SrcValid- TransBlk- ReqRedir- CmpltRedir- UpstreamFwd- EgressCtrl- DirectTrans-
ACSCtl: SrcValid- TransBlk- ReqRedir- CmpltRedir- UpstreamFwd- EgressCtrl- DirectTrans-
Kernel driver in use: igb
Kernel modules: igb
01:00.1 Ethernet controller: Intel Corporation I350 Gigabit Network Connection (rev 01)
Subsystem: Intel Corporation Ethernet Server Adapter I350-T2
Control: I/O- Mem+ BusMaster+ SpecCycle- MemWINV- VGASnoop- ParErr+ Stepping- SERR+ FastB2B- DisINTx-
Status: Cap+ 66MHz- UDF- FastB2B- ParErr- DEVSELúst >TAbort- <TAbort- <MAbort- >SERR- <PERR- INTx-
Latency: 0, Cache Line Size: 64 bytes
Interrupt: pin B routed to IRQ 148
Region 0: Memory at 30100000 (32-bit, non-prefetchable) [size=1M]
Region 3: Memory at 30204000 (32-bit, non-prefetchable) [size\x16K]
Capabilities: [40] Power Management version 3
Flags: PMEClk- DSI+ D1- D2- AuxCurrent=0mA PME(D0+,D1-,D2-,D3hot+,D3cold+)
Status: D0 NoSoftRst+ PME-Enable- DSel=0 DScale=1 PME-
Capabilities: [50] MSI: Enable- Count=1/1 Maskable+ 64bit+
Address: 0000000000000000 Data: 0000
Masking: 00000000 Pending: 00000000
Capabilities: [70] MSI-X: Enable- Count\x10 Masked-
Vector table: BAR=3 offset\0000000
PBA: BAR=3 offset\0002000
Capabilities: [a0] Express (v2) Endpoint, MSI 00
DevCap: MaxPayload 512 bytes, PhantFunc 0, Latency L0s <512ns, L1 <64us
ExtTag- AttnBtn- AttnInd- PwrInd- RBE+ FLReset+
DevCtl: Report errors: Correctable+ Non-Fatal+ Fatal+ Unsupported+
RlxdOrd+ ExtTag- PhantFunc- AuxPwr- NoSnoop+ FLReset-
MaxPayload 128 bytes, MaxReadReq 512 bytes
DevSta: CorrErr- UncorrErr- FatalErr- UnsuppReq- AuxPwr+ TransPend-
LnkCap: Port #0, Speed 5GT/s, Width x4, ASPM L0s L1, Latency L0 <4us, L1 <32us
ClockPM- Surprise- LLActRep- BwNot-
LnkCtl: ASPM Disabled; RCB 64 bytes Disabled- Retrain- CommClk-
ExtSynch- ClockPM- AutWidDis- BWInt- AutBWInt-
LnkSta: Speed 5GT/s, Width x1, TrErr- Train- SlotClk+ DLActive- BWMgmt- ABWMgmt-
DevCap2: Completion Timeout: Range ABCD, TimeoutDis+, LTR+, OBFF Not Supported
DevCtl2: Completion Timeout: 50us to 50ms, TimeoutDis-, LTR-, OBFF Disabled
LnkSta2: Current De-emphasis Level: -6dB, EqualizationComplete-, EqualizationPhase1-
EqualizationPhase2-, EqualizationPhase3-, LinkEqualizationRequest-
Capabilities: [100 v2] Advanced Error Reporting
UESta: DLP- SDES- TLP- FCP- CmpltTO- CmpltAbrt- UnxCmplt- RxOF- MalfTLP- ECRC- UnsupReq- ACSViol-
UEMsk: DLP- SDES- TLP- FCP- CmpltTO- CmpltAbrt- UnxCmplt- RxOF- MalfTLP- ECRC- UnsupReq- ACSViol-
UESvrt: DLP+ SDES+ TLP- FCP+ CmpltTO- CmpltAbrt- UnxCmplt- RxOF+ MalfTLP+ ECRC- UnsupReq- ACSViol-
CESta: RxErr- BadTLP- BadDLLP- Rollover- Timeout- NonFatalErr+
CEMsk: RxErr- BadTLP- BadDLLP- Rollover- Timeout- NonFatalErr+
AERCap: First Error Pointer: 00, GenCap+ CGenEn- ChkCap+ ChkEn-
Capabilities: [140 v1] Device Serial Number a0-36-9f-ff-ff-23-18-c0
Capabilities: [150 v1] Alternative Routing-ID Interpretation (ARI)
ARICap: MFVC- ACS-, Next Function: 0
ARICtl: MFVC- ACS-, Function Group: 0
Capabilities: [160 v1] Single Root I/O Virtualization (SR-IOV)
IOVCap: Migration-, Interrupt Message Number: 000
IOVCtl: Enable- Migration- Interrupt- MSE- ARIHierarchy-
IOVSta: Migration-
Initial VFs: 8, Total VFs: 8, Number of VFs: 0, Function Dependency Link: 01
VF offset: 384, stride: 4, Device ID: 1520
Supported Page Size: 00000553, System Page Size: 00000001
Region 0: Memory at 0000000000000000 (64-bit, prefetchable)
Region 3: Memory at 0000000000000000 (64-bit, prefetchable)
VF Migration: offset: 00000000, BIR: 0
Capabilities: [1a0 v1] Transaction Processing Hints
Device specific mode supported
Steering table in TPH capability structure
Capabilities: [1d0 v1] Access Control Services
ACSCap: SrcValid- TransBlk- ReqRedir- CmpltRedir- UpstreamFwd- EgressCtrl- DirectTrans-
ACSCtl: SrcValid- TransBlk- ReqRedir- CmpltRedir- UpstreamFwd- EgressCtrl- DirectTrans-
Kernel driver in use: igb
Kernel modules: igb
Phil Edworthy (5):
PCI: host: Add Renesas R-Car PCIe driver
ARM: shmobile: r8a7791: Add PCIe clock
ARM: shmobile: Add PCIe resources to r8a7791 device
ARM: shmobile: Add PCIe to r8a7791 device Kconfig
ARM: koelsch: Add PCIe to defconfig
arch/arm/configs/koelsch_defconfig | 3 +
arch/arm/mach-shmobile/Kconfig | 2 +
arch/arm/mach-shmobile/clock-r8a7791.c | 3 +
arch/arm/mach-shmobile/setup-r8a7791.c | 13 +
drivers/pci/host/Kconfig | 6 +
drivers/pci/host/Makefile | 1 +
drivers/pci/host/pcie-rcar.c | 614 ++++++++++++++++++++++++++++++++
drivers/pci/host/pcie-rcar.h | 84 +++++
10 files changed, 744 insertions(+), 1 deletion(-)
create mode 100644 drivers/pci/host/pcie-rcar.c
create mode 100644 drivers/pci/host/pcie-rcar.h
--
1.7.9.5
^ permalink raw reply [flat|nested] 10+ messages in thread
* [PATCH 1/5] PCI: host: Add Renesas R-Car PCIe driver
2014-02-26 16:08 [PATCH 0/5 RFC] R-Car Gen2 PCIe host driver Phil Edworthy
@ 2014-02-26 16:08 ` Phil Edworthy
2014-02-26 16:34 ` Ben Dooks
2014-02-26 16:08 ` [PATCH 2/5] ARM: shmobile: r8a7791: Add PCIe clock Phil Edworthy
` (3 subsequent siblings)
4 siblings, 1 reply; 10+ messages in thread
From: Phil Edworthy @ 2014-02-26 16:08 UTC (permalink / raw)
To: linux-pci
Cc: linux-sh, Bjorn Helgaas, Valentine Barshak, Simon Horman,
Magnus Damm, Phil Edworthy
This PCIe Host driver currently does not support MSI, so cards
fall back to INTx interrupts.
Signed-off-by: Phil Edworthy <phil.edworthy@renesas.com>
---
drivers/pci/host/Kconfig | 6 +
drivers/pci/host/Makefile | 1 +
drivers/pci/host/pcie-rcar.c | 614 ++++++++++++++++++++++++++++++++++++++++++
drivers/pci/host/pcie-rcar.h | 84 ++++++
4 files changed, 705 insertions(+)
create mode 100644 drivers/pci/host/pcie-rcar.c
create mode 100644 drivers/pci/host/pcie-rcar.h
diff --git a/drivers/pci/host/Kconfig b/drivers/pci/host/Kconfig
index 47d46c6..b1c1787 100644
--- a/drivers/pci/host/Kconfig
+++ b/drivers/pci/host/Kconfig
@@ -33,4 +33,10 @@ config PCI_RCAR_GEN2
There are 3 internal PCI controllers available with a single
built-in EHCI/OHCI host controller present on each one.
+config PCI_RCAR_GEN2_PCIE
+ bool "Renesas R-Car PCIe controller"
+ depends on ARM && (ARCH_R8A7790 || ARCH_R8A7791 || COMPILE_TEST)
+ help
+ Say Y here if you want PCIe controller support on R-Car Gen2 SoCs.
+
endmenu
diff --git a/drivers/pci/host/Makefile b/drivers/pci/host/Makefile
index 13fb333..19946f9 100644
--- a/drivers/pci/host/Makefile
+++ b/drivers/pci/host/Makefile
@@ -4,3 +4,4 @@ obj-$(CONFIG_PCI_IMX6) += pci-imx6.o
obj-$(CONFIG_PCI_MVEBU) += pci-mvebu.o
obj-$(CONFIG_PCI_TEGRA) += pci-tegra.o
obj-$(CONFIG_PCI_RCAR_GEN2) += pci-rcar-gen2.o
+obj-$(CONFIG_PCI_RCAR_GEN2_PCIE) += pcie-rcar.o
diff --git a/drivers/pci/host/pcie-rcar.c b/drivers/pci/host/pcie-rcar.c
new file mode 100644
index 0000000..d9a315f
--- /dev/null
+++ b/drivers/pci/host/pcie-rcar.c
@@ -0,0 +1,614 @@
+/*
+ * PCIe driver for Renesas R-Car SoCs
+ * Copyright (C) 2013 Renesas Electronics Europe Ltd
+ *
+ * Based on:
+ * arch/sh/drivers/pci/pcie-sh7786.c
+ * arch/sh/drivers/pci/ops-sh7786.c
+ * Copyright (C) 2009 - 2011 Paul Mundt
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+#include <linux/of_pci.h>
+#include <linux/of_platform.h>
+#include <linux/pci.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include "pcie-rcar.h"
+
+#define DRV_NAME "rcar-pcie"
+
+enum chip_id {
+ RCAR_GENERIC,
+ RCAR_H1,
+};
+
+#define RCONF(x) (PCICONF(0)+(x))
+#define REXPCAP(x) (EXPCAP(0)+(x))
+#define RVCCAP(x) (VCCAP(0)+(x))
+
+#define PCIE_CONF_BUS(b) (((b) & 0xff) << 24)
+#define PCIE_CONF_DEV(d) (((d) & 0x1f) << 19)
+#define PCIE_CONF_FUNC(f) (((f) & 0x7) << 16)
+
+#define NR_PCI_RESOURCES 4
+
+/* Structure representing the PCIe interface */
+struct rcar_pcie {
+ struct device *dev;
+ void __iomem *base;
+ int irq;
+ struct clk *clk;
+ struct resource *res[NR_PCI_RESOURCES];
+ int haslink;
+ enum chip_id chip;
+ u8 root_bus_nr;
+};
+
+static inline struct rcar_pcie *sys_to_pcie(struct pci_sys_data *sys)
+{
+ return sys->private_data;
+}
+
+static void
+pci_write_reg(struct rcar_pcie *pcie, unsigned long val, unsigned long reg)
+{
+ writel(val, pcie->base + reg);
+}
+
+static unsigned long
+pci_read_reg(struct rcar_pcie *pcie, unsigned long reg)
+{
+ return readl(pcie->base + reg);
+}
+
+enum {
+ PCI_ACCESS_READ,
+ PCI_ACCESS_WRITE,
+};
+
+static void rcar_rmw32(struct rcar_pcie *pcie,
+ int where, u32 mask, u32 data)
+{
+ int shift = 8 * (where & 3);
+ u32 val = pci_read_reg(pcie, where & ~3);
+ val &= ~(mask << shift);
+ val |= data << shift;
+ pci_write_reg(pcie, val, where & ~3);
+}
+
+static u32 rcar_read_conf(struct rcar_pcie *pcie, int where)
+{
+ int shift = 8 * (where & 3);
+ u32 val = pci_read_reg(pcie, where & ~3);
+ return val >> shift;
+}
+
+static int rcar_pcie_config_access(struct rcar_pcie *pcie,
+ unsigned char access_type, struct pci_bus *bus,
+ unsigned int devfn, int where, u32 *data)
+{
+ int dev, func, reg, index;
+
+ dev = PCI_SLOT(devfn);
+ func = PCI_FUNC(devfn);
+ reg = where & ~3;
+ index = reg / 4;
+
+ if (bus->number > 255 || dev > 31 || func > 7)
+ return PCIBIOS_FUNC_NOT_SUPPORTED;
+
+ /*
+ * While each channel has its own memory-mapped extended config
+ * space, it's generally only accessible when in endpoint mode.
+ * When in root complex mode, the controller is unable to target
+ * itself with either type 0 or type 1 accesses, and indeed, any
+ * controller initiated target transfer to its own config space
+ * result in a completer abort.
+ *
+ * Each channel effectively only supports a single device, but as
+ * the same channel <-> device access works for any PCI_SLOT()
+ * value, we cheat a bit here and bind the controller's config
+ * space to devfn 0 in order to enable self-enumeration. In this
+ * case the regular ECAR/ECDR path is sidelined and the mangled
+ * config access itself is initiated as an internal bus transaction.
+ */
+ if (pci_is_root_bus(bus)) {
+ if (dev != 0)
+ return PCIBIOS_DEVICE_NOT_FOUND;
+
+ if (access_type = PCI_ACCESS_READ)
+ *data = pci_read_reg(pcie, PCICONF(index));
+ else
+ pci_write_reg(pcie, *data, PCICONF(index));
+
+ return PCIBIOS_SUCCESSFUL;
+ }
+
+ /* Clear errors */
+ pci_write_reg(pcie, pci_read_reg(pcie, PCIEERRFR), PCIEERRFR);
+
+ /* Set the PIO address */
+ pci_write_reg(pcie, PCIE_CONF_BUS(bus->number) | PCIE_CONF_DEV(dev) |
+ PCIE_CONF_FUNC(func) | reg, PCIECAR);
+
+ /* Enable the configuration access */
+ if (bus->parent->number = pcie->root_bus_nr)
+ pci_write_reg(pcie, CONFIG_SEND_ENABLE | TYPE0, PCIECCTLR);
+ else
+ pci_write_reg(pcie, CONFIG_SEND_ENABLE | TYPE1, PCIECCTLR);
+
+ /* Check for errors */
+ if (pci_read_reg(pcie, PCIEERRFR) & UNSUPPORTED_REQUEST)
+ return PCIBIOS_DEVICE_NOT_FOUND;
+
+ /* Check for master and target aborts */
+ if (rcar_read_conf(pcie, RCONF(PCI_STATUS)) &
+ (PCI_STATUS_REC_MASTER_ABORT | PCI_STATUS_REC_TARGET_ABORT))
+ return PCIBIOS_DEVICE_NOT_FOUND;
+
+ if (access_type = PCI_ACCESS_READ)
+ *data = pci_read_reg(pcie, PCIECDR);
+ else
+ pci_write_reg(pcie, *data, PCIECDR);
+
+ /* Disable the configuration access */
+ pci_write_reg(pcie, 0, PCIECCTLR);
+
+ return PCIBIOS_SUCCESSFUL;
+}
+
+static int rcar_pcie_read_conf(struct pci_bus *bus, unsigned int devfn,
+ int where, int size, u32 *val)
+{
+ struct rcar_pcie *pcie = sys_to_pcie(bus->sysdata);
+ int ret;
+
+ if ((size = 2) && (where & 1))
+ return PCIBIOS_BAD_REGISTER_NUMBER;
+ else if ((size = 4) && (where & 3))
+ return PCIBIOS_BAD_REGISTER_NUMBER;
+
+ ret = rcar_pcie_config_access(pcie, PCI_ACCESS_READ,
+ bus, devfn, where, val);
+ if (ret != PCIBIOS_SUCCESSFUL) {
+ *val = 0xffffffff;
+ return ret;
+ }
+
+ if (size = 1)
+ *val = (*val >> (8 * (where & 3))) & 0xff;
+ else if (size = 2)
+ *val = (*val >> (8 * (where & 2))) & 0xffff;
+
+ dev_dbg(&bus->dev, "pcie-config-read: bus=%3d devfn=0x%04x "
+ "where=0x%04x size=%d val=0x%08lx\n", bus->number,
+ devfn, where, size, (unsigned long)*val);
+
+ return ret;
+}
+
+static int rcar_pcie_write_conf(struct pci_bus *bus, unsigned int devfn,
+ int where, int size, u32 val)
+{
+ struct rcar_pcie *pcie = sys_to_pcie(bus->sysdata);
+ int shift, ret;
+ u32 data;
+
+ if ((size = 2) && (where & 1))
+ return PCIBIOS_BAD_REGISTER_NUMBER;
+ else if ((size = 4) && (where & 3))
+ return PCIBIOS_BAD_REGISTER_NUMBER;
+
+ ret = rcar_pcie_config_access(pcie, PCI_ACCESS_READ,
+ bus, devfn, where, &data);
+ if (ret != PCIBIOS_SUCCESSFUL)
+ return ret;
+
+ dev_dbg(&bus->dev, "pcie-config-write: bus=%3d devfn=0x%04x "
+ "where=0x%04x size=%d val=0x%08lx\n", bus->number,
+ devfn, where, size, (unsigned long)val);
+
+ if (size = 1) {
+ shift = 8 * (where & 3);
+ data &= ~(0xff << shift);
+ data |= ((val & 0xff) << shift);
+ } else if (size = 2) {
+ shift = 8 * (where & 2);
+ data &= ~(0xffff << shift);
+ data |= ((val & 0xffff) << shift);
+ } else
+ data = val;
+
+ ret = rcar_pcie_config_access(pcie, PCI_ACCESS_WRITE,
+ bus, devfn, where, &data);
+
+ return ret;
+}
+
+static struct pci_ops rcar_pcie_ops = {
+ .read = rcar_pcie_read_conf,
+ .write = rcar_pcie_write_conf,
+};
+
+static int rcar_pcie_setup(int nr, struct pci_sys_data *sys)
+{
+ struct rcar_pcie *pcie = sys_to_pcie(sys);
+ int ret, i, win;
+
+ pcie->root_bus_nr = sys->busnr;
+
+ /* Setup IO mapped memory accesses */
+ ret = pci_ioremap_io(0, pcie->res[0]->start);
+ if (ret)
+ return ret;
+
+ /* Setup PCI resources */
+ /* Ignore first resource, as it's for IO */
+ for (i = 1; i < NR_PCI_RESOURCES; i++) {
+ struct resource *res = pcie->res[i];
+ pci_add_resource_offset(&sys->resources, res, sys->mem_offset);
+ }
+
+ /* Setup PCIe address space mappings for each resource */
+ for (i = win = 0; i < NR_PCI_RESOURCES; i++) {
+ struct resource *res = pcie->res[i];
+ resource_size_t size, bus_addr;
+ u32 mask;
+
+ pci_write_reg(pcie, 0x00000000, PCIEPTCTLR(win));
+
+ /*
+ * The PAMR mask is calculated in units of 128Bytes, which
+ * keeps things pretty simple.
+ */
+ size = resource_size(res);
+ mask = (roundup_pow_of_two(size) / SZ_128) - 1;
+ pci_write_reg(pcie, mask << 7, PCIEPAMR(win));
+
+ bus_addr = i ? res->start : 0;
+ pci_write_reg(pcie, upper_32_bits(bus_addr), PCIEPARH(win));
+ pci_write_reg(pcie, lower_32_bits(bus_addr), PCIEPARL(win));
+
+ mask = PAR_ENABLE;
+ /* First resource is for IO */
+ if (i = 0)
+ mask |= IO_SPACE;
+
+ pci_write_reg(pcie, mask, PCIEPTCTLR(win));
+
+ win++;
+ }
+
+ return 1;
+}
+
+static int rcar_pcie_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
+{
+ struct rcar_pcie *pcie = sys_to_pcie(dev->bus->sysdata);
+ return pcie->irq;
+}
+
+static void __init rcar_pcie_enable(struct rcar_pcie *pcie)
+{
+ struct hw_pci hw;
+
+ memset(&hw, 0, sizeof(hw));
+
+ hw.nr_controllers = 1;
+ hw.private_data = (void **)&pcie;
+ hw.setup = rcar_pcie_setup,
+ hw.map_irq = rcar_pcie_map_irq,
+ hw.ops = &rcar_pcie_ops,
+
+ pci_common_init(&hw);
+}
+
+static int __init phy_wait_for_ack(struct rcar_pcie *pcie)
+{
+ unsigned int timeout = 100;
+
+ while (timeout--) {
+ if (pci_read_reg(pcie, H1_PCIEPHYADRR) & PHY_ACK)
+ return 0;
+
+ udelay(100);
+ }
+
+ dev_err(pcie->dev, "Access to PCIe phy timed out\n");
+
+ return -ETIMEDOUT;
+}
+
+static void __init phy_write_reg(struct rcar_pcie *pcie,
+ unsigned int rate, unsigned int addr,
+ unsigned int lane, unsigned int data)
+{
+ unsigned long phyaddr;
+
+ phyaddr = WRITE_CMD |
+ ((rate & 1) << RATE_POS) |
+ ((lane & 0xf) << LANE_POS) |
+ ((addr & 0xff) << ADR_POS);
+
+ /* Set write data */
+ pci_write_reg(pcie, data, H1_PCIEPHYDOUTR);
+ pci_write_reg(pcie, phyaddr, H1_PCIEPHYADRR);
+
+ /* Ignore errors as they will be dealt with if the data link is down */
+ phy_wait_for_ack(pcie);
+
+ /* Clear command */
+ pci_write_reg(pcie, 0, H1_PCIEPHYDOUTR);
+ pci_write_reg(pcie, 0, H1_PCIEPHYADRR);
+
+ /* Ignore errors as they will be dealt with if the data link is down */
+ phy_wait_for_ack(pcie);
+}
+
+static int __init rcar_pcie_phy_init_rcar_h1(struct rcar_pcie *pcie)
+{
+ unsigned int timeout = 100;
+
+ /* Initialize the phy */
+ phy_write_reg(pcie, 0, 0x42, 0x1, 0x0EC34191);
+ phy_write_reg(pcie, 1, 0x42, 0x1, 0x0EC34180);
+ phy_write_reg(pcie, 0, 0x43, 0x1, 0x00210188);
+ phy_write_reg(pcie, 1, 0x43, 0x1, 0x00210188);
+ phy_write_reg(pcie, 0, 0x44, 0x1, 0x015C0014);
+ phy_write_reg(pcie, 1, 0x44, 0x1, 0x015C0014);
+ phy_write_reg(pcie, 1, 0x4C, 0x1, 0x786174A0);
+ phy_write_reg(pcie, 1, 0x4D, 0x1, 0x048000BB);
+ phy_write_reg(pcie, 0, 0x51, 0x1, 0x079EC062);
+ phy_write_reg(pcie, 0, 0x52, 0x1, 0x20000000);
+ phy_write_reg(pcie, 1, 0x52, 0x1, 0x20000000);
+ phy_write_reg(pcie, 1, 0x56, 0x1, 0x00003806);
+
+ phy_write_reg(pcie, 0, 0x60, 0x1, 0x004B03A5);
+ phy_write_reg(pcie, 0, 0x64, 0x1, 0x3F0F1F0F);
+ phy_write_reg(pcie, 0, 0x66, 0x1, 0x00008000);
+
+ while (timeout--) {
+ if (pci_read_reg(pcie, H1_PCIEPHYSR))
+ return 0;
+
+ udelay(100);
+ }
+
+ return -ETIMEDOUT;
+}
+
+static int __init rcar_pcie_wait_for_dl(struct rcar_pcie *pcie)
+{
+ unsigned int timeout = 100;
+
+ while (timeout--) {
+ if ((pci_read_reg(pcie, PCIETSTR) & DATA_LINK_ACTIVE))
+ return 0;
+
+ udelay(100);
+ }
+
+ return -ETIMEDOUT;
+}
+
+static void __init rcar_pcie_hw_init(struct rcar_pcie *pcie)
+{
+ /* Initialise R-Car H1 PHY & wait for it to be ready */
+ if (pcie->chip = RCAR_H1)
+ if (rcar_pcie_phy_init_rcar_h1(pcie))
+ return;
+
+ /* Begin initialization */
+ pci_write_reg(pcie, 0, PCIETCTLR);
+
+ /* Set mode */
+ pci_write_reg(pcie, 1, PCIEMSR);
+
+ /*
+ * For target transfers, setup a single 64-bit 4GB mapping at address
+ * 0. The hardware can only map memory that starts on a power of two
+ * boundary, and size is power of 2, so best to ignore it.
+ */
+ pci_write_reg(pcie, 0, PCIEPRAR(0));
+ pci_write_reg(pcie, 0, PCIELAR(0));
+ pci_write_reg(pcie, 0xfffffff0UL | LAM_PREFETCH |
+ LAM_64BIT | LAR_ENABLE, PCIELAMR(0));
+ pci_write_reg(pcie, 0, PCIELAR(1));
+ pci_write_reg(pcie, 0, PCIEPRAR(1));
+ pci_write_reg(pcie, 0, PCIELAMR(1));
+
+ /*
+ * Initial header for port config space is type 1, set the device
+ * class to match. Hardware takes care of propagating the IDSETR
+ * settings, so there is no need to bother with a quirk.
+ */
+ pci_write_reg(pcie, PCI_CLASS_BRIDGE_PCI << 16, IDSETR1);
+
+ /*
+ * Setup Secondary Bus Number & Subordinate Bus Number, even though
+ * they aren't used, to avoid bridge being detected as broken.
+ */
+ rcar_rmw32(pcie, RCONF(PCI_SECONDARY_BUS), 0xff, 1);
+ rcar_rmw32(pcie, RCONF(PCI_SUBORDINATE_BUS), 0xff, 1);
+
+ /* Initialize default capabilities. */
+ rcar_rmw32(pcie, REXPCAP(0), 0, PCI_CAP_ID_EXP);
+ rcar_rmw32(pcie, REXPCAP(PCI_EXP_FLAGS),
+ PCI_EXP_FLAGS_TYPE, PCI_EXP_TYPE_ROOT_PORT << 4);
+ rcar_rmw32(pcie, RCONF(PCI_HEADER_TYPE), 0x7f,
+ PCI_HEADER_TYPE_BRIDGE);
+
+ /* Enable data link layer active state reporting */
+ rcar_rmw32(pcie, REXPCAP(PCI_EXP_LNKCAP), 0, PCI_EXP_LNKCAP_DLLLARC);
+
+ /* Write out the physical slot number = 0 */
+ rcar_rmw32(pcie, REXPCAP(PCI_EXP_SLTCAP), PCI_EXP_SLTCAP_PSN, 0);
+
+ /* Set the completion timer timeout to the maximum 50ms. */
+ rcar_rmw32(pcie, TLCTLR+1, 0x3f, 50);
+
+ /* Terminate list of capabilities (Next Capability Offset=0) */
+ rcar_rmw32(pcie, RVCCAP(0), 0xfff0, 0);
+
+ /* Enable MAC data scrambling. */
+ rcar_rmw32(pcie, MACCTLR, SCRAMBLE_DISABLE, 0);
+
+ /* Finish initialization - establish a PCI Express link */
+ pci_write_reg(pcie, CFINIT, PCIETCTLR);
+
+ /* This will timeout if we don't have a link. */
+ pcie->haslink = !rcar_pcie_wait_for_dl(pcie);
+
+ /* Enable INTx interrupts */
+ rcar_rmw32(pcie, RCONF(PCI_INTERRUPT_LINE), 0xff, 0);
+ rcar_rmw32(pcie, RCONF(PCI_INTERRUPT_PIN), 0xff, 1);
+ rcar_rmw32(pcie, PCIEINTXR, 0, 0xF << 8);
+
+ /* Enable slave Bus Mastering */
+ rcar_rmw32(pcie, RCONF(PCI_STATUS), PCI_STATUS_DEVSEL_MASK,
+ PCI_COMMAND_IO | PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER |
+ PCI_STATUS_CAP_LIST | PCI_STATUS_DEVSEL_FAST);
+
+ wmb();
+}
+
+static int rcar_pcie_clocks_get(struct rcar_pcie *pcie)
+{
+ int err = 0;
+
+ pcie->clk = clk_get(pcie->dev, NULL);
+ if (IS_ERR(pcie->clk))
+ err = PTR_ERR(pcie->clk);
+ else
+ clk_enable(pcie->clk);
+
+ return err;
+}
+
+static void rcar_pcie_clocks_put(struct rcar_pcie *pcie)
+{
+ clk_put(pcie->clk);
+}
+
+struct rcar_pcie_errs {
+ int bit;
+ const char *description;
+};
+
+static int __init rcar_pcie_get_resources(struct platform_device *pdev,
+ struct rcar_pcie *pcie)
+{
+ struct resource *res;
+ int i;
+ int err;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+
+ i = platform_get_irq(pdev, 0);
+ if (!res || i < 0) {
+ dev_err(pcie->dev, "cannot get platform resources\n");
+ return -ENOENT;
+ }
+ pcie->irq = i;
+
+ err = rcar_pcie_clocks_get(pcie);
+ if (err) {
+ dev_err(&pdev->dev, "failed to get clocks: %d\n", err);
+ return err;
+ }
+
+ pcie->base = devm_request_and_ioremap(&pdev->dev, res);
+ if (!pcie->base) {
+ dev_err(&pdev->dev, "failed to map PCIe registers: %d\n", err);
+ err = -ENOMEM;
+ goto err_map_reg;
+ }
+
+ return 0;
+
+err_map_reg:
+ rcar_pcie_clocks_put(pcie);
+
+ return err;
+}
+
+static struct platform_device_id rcar_pcie_id_table[] = {
+ { "r8a7779-pcie", RCAR_H1 },
+ { "r8a7790-pcie", RCAR_GENERIC },
+ { "r8a7791-pcie", RCAR_GENERIC },
+ {},
+};
+MODULE_DEVICE_TABLE(platform, rcar_pcie_id_table);
+
+static int __init rcar_pcie_probe(struct platform_device *pdev)
+{
+ struct rcar_pcie *pcie;
+ struct resource *res;
+ unsigned int data;
+ int i, err;
+
+ pcie = devm_kzalloc(&pdev->dev, sizeof(*pcie), GFP_KERNEL);
+ if (!pcie)
+ return -ENOMEM;
+
+ pcie->dev = &pdev->dev;
+ pcie->chip = pdev->id_entry->driver_data;
+
+ /* Get resources */
+ err = rcar_pcie_get_resources(pdev, pcie);
+ if (err < 0) {
+ dev_err(&pdev->dev, "failed to request resources: %d\n", err);
+ return err;
+ }
+
+ /* Get the I/O and memory ranges */
+ for (i = 0; i < NR_PCI_RESOURCES; i++) {
+ res = platform_get_resource(pdev, IORESOURCE_MEM, i+1);
+ if (!res) {
+ dev_err(&pdev->dev, "cannot get MEM%d resources\n", i);
+ return -ENOENT;
+ }
+ pcie->res[i] = res;
+ }
+
+ rcar_pcie_hw_init(pcie);
+
+ if (!pcie->haslink) {
+ dev_info(&pdev->dev, "PCI: PCIe link down\n");
+ return 0;
+ }
+
+ data = pci_read_reg(pcie, MACSR);
+ dev_info(&pdev->dev, "PCIe x%d: link up\n", (data >> 20) & 0x3f);
+
+ rcar_pcie_enable(pcie);
+
+ platform_set_drvdata(pdev, pcie);
+ return 0;
+}
+
+static struct platform_driver rcar_pcie_driver = {
+ .probe = rcar_pcie_probe,
+ .driver = {
+ .name = DRV_NAME,
+ .owner = THIS_MODULE,
+ },
+ .id_table = rcar_pcie_id_table,
+};
+
+module_platform_driver(rcar_pcie_driver);
+
+MODULE_AUTHOR("Phil Edworthy <phil.edworthy@renesas.com>");
+MODULE_DESCRIPTION("Renesas R-Car PCIe driver");
+MODULE_LICENSE("GPLv2");
diff --git a/drivers/pci/host/pcie-rcar.h b/drivers/pci/host/pcie-rcar.h
new file mode 100644
index 0000000..a6b407f
--- /dev/null
+++ b/drivers/pci/host/pcie-rcar.h
@@ -0,0 +1,84 @@
+/*
+ * PCI Express definitions for Renesas R-Car SoCs
+ */
+#ifndef __PCI_RCAR_H
+#define __PCI_RCAR_H
+
+#define PCI_DEVICE_ID_RENESAS_RCAR 0x0018
+
+#define PCIECAR 0x000010
+#define PCIECCTLR 0x000018
+#define CONFIG_SEND_ENABLE (1 << 31)
+#define TYPE0 (0 << 8)
+#define TYPE1 (1 << 8)
+#define PCIECDR 0x000020
+#define PCIEMSR 0x000028
+#define PCIEINTXR 0x000400
+#define PCIEPHYSR 0x0007f0
+
+/* Transfer control */
+#define PCIETCTLR 0x02000
+#define CFINIT 1
+#define PCIETSTR 0x02004
+#define DATA_LINK_ACTIVE 1
+#define PCIEINTR 0x02008
+#define PCIEINTER 0x0200c
+#define PCIEERRFR 0x02020
+#define UNSUPPORTED_REQUEST (1 << 4)
+#define PCIEERRFER 0x02024
+#define PCIEERRFR2 0x02028
+#define PCIEPMSR 0x02034
+#define PCIEPMSCIER 0x02038
+#define PCIEMSIFR 0x02044
+
+/* root port address */
+#define PCIEPRAR(x) (0x02080 + ((x) * 0x4))
+
+/* local address reg & mask */
+#define PCIELAR(x) (0x02200 + ((x) * 0x20))
+#define PCIELAMR(x) (0x02208 + ((x) * 0x20))
+#define LAM_PMIOLAMnB3 (1 << 3)
+#define LAM_PMIOLAMnB2 (1 << 2)
+#define LAM_PREFETCH (1 << 3)
+#define LAM_64BIT (1 << 2)
+#define LAR_ENABLE (1 << 1)
+
+/* PCIe address reg & mask */
+#define PCIEPARL(x) (0x03400 + ((x) * 0x20))
+#define PCIEPARH(x) (0x03404 + ((x) * 0x20))
+#define PCIEPAMR(x) (0x03408 + ((x) * 0x20))
+#define PCIEPTCTLR(x) (0x0340c + ((x) * 0x20))
+#define PAR_ENABLE (1 << 31)
+#define IO_SPACE (1 << 8)
+
+/* Configuration */
+#define PCICONF(x) (0x010000 + ((x) * 0x4))
+#define PMCAP(x) (0x010040 + ((x) * 0x4))
+#define MSICAP(x) (0x010050 + ((x) * 0x4))
+#define EXPCAP(x) (0x010070 + ((x) * 0x4))
+#define VCCAP(x) (0x010100 + ((x) * 0x4))
+#define SERNUMCAP(x) (0x0101b0 + ((x) * 0x4))
+
+/* link layer */
+#define IDSETR0 0x011000
+#define IDSETR1 0x011004
+#define SUBIDSETR 0x011024
+#define DSERSETR0 0x01102c
+#define DSERSETR1 0x011030
+#define TLCTLR 0x011048
+#define MACSR 0x011054
+#define MACCTLR 0x011058
+#define SCRAMBLE_DISABLE (1 << 27)
+
+/* R-Car H1 PHY */
+#define H1_PCIEPHYCTLR 0x040008
+#define H1_PCIEPHYADRR 0x04000c
+#define WRITE_CMD (1 << 16)
+#define PHY_ACK (1 << 24)
+#define RATE_POS 12
+#define LANE_POS 8
+#define ADR_POS 0
+#define H1_PCIEPHYDOUTR 0x040014
+#define H1_PCIEPHYSR 0x040018
+
+#endif /* __PCI_RCAR_H */
--
1.7.9.5
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [PATCH 2/5] ARM: shmobile: r8a7791: Add PCIe clock
2014-02-26 16:08 [PATCH 0/5 RFC] R-Car Gen2 PCIe host driver Phil Edworthy
2014-02-26 16:08 ` [PATCH 1/5] PCI: host: Add Renesas R-Car PCIe driver Phil Edworthy
@ 2014-02-26 16:08 ` Phil Edworthy
2014-02-26 16:08 ` [PATCH 3/5] ARM: shmobile: Add PCIe resources to r8a7791 device Phil Edworthy
` (2 subsequent siblings)
4 siblings, 0 replies; 10+ messages in thread
From: Phil Edworthy @ 2014-02-26 16:08 UTC (permalink / raw)
To: linux-pci
Cc: linux-sh, Bjorn Helgaas, Valentine Barshak, Simon Horman,
Magnus Damm, Phil Edworthy
Signed-off-by: Phil Edworthy <phil.edworthy@renesas.com>
---
arch/arm/mach-shmobile/clock-r8a7791.c | 3 +++
1 file changed, 3 insertions(+)
diff --git a/arch/arm/mach-shmobile/clock-r8a7791.c b/arch/arm/mach-shmobile/clock-r8a7791.c
index c574292..cba9b3c 100644
--- a/arch/arm/mach-shmobile/clock-r8a7791.c
+++ b/arch/arm/mach-shmobile/clock-r8a7791.c
@@ -123,6 +123,7 @@ enum {
MSTP813,
MSTP721, MSTP720,
MSTP719, MSTP718, MSTP715, MSTP714,
+ MSTP319,
MSTP216, MSTP207, MSTP206,
MSTP204, MSTP203, MSTP202, MSTP1105, MSTP1106, MSTP1107,
MSTP124,
@@ -137,6 +138,7 @@ static struct clk mstp_clks[MSTP_NR] = {
[MSTP718] = SH_CLK_MSTP32(&p_clk, SMSTPCR7, 18, 0), /* SCIF3 */
[MSTP715] = SH_CLK_MSTP32(&p_clk, SMSTPCR7, 15, 0), /* SCIF4 */
[MSTP714] = SH_CLK_MSTP32(&p_clk, SMSTPCR7, 14, 0), /* SCIF5 */
+ [MSTP319] = SH_CLK_MSTP32(&mp_clk, SMSTPCR3, 19, 0), /* PCIEC */
[MSTP216] = SH_CLK_MSTP32(&mp_clk, SMSTPCR2, 16, 0), /* SCIFB2 */
[MSTP207] = SH_CLK_MSTP32(&mp_clk, SMSTPCR2, 7, 0), /* SCIFB1 */
[MSTP206] = SH_CLK_MSTP32(&mp_clk, SMSTPCR2, 6, 0), /* SCIFB0 */
@@ -166,6 +168,7 @@ static struct clk_lookup lookups[] = {
CLKDEV_CON_ID("peripheral_clk", &hp_clk),
/* MSTP */
+ CLKDEV_DEV_ID("r8a7791-pcie", &mstp_clks[MSTP319]),
CLKDEV_DEV_ID("sh-sci.0", &mstp_clks[MSTP204]), /* SCIFA0 */
CLKDEV_DEV_ID("sh-sci.1", &mstp_clks[MSTP203]), /* SCIFA1 */
CLKDEV_DEV_ID("sh-sci.2", &mstp_clks[MSTP206]), /* SCIFB0 */
--
1.7.9.5
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [PATCH 3/5] ARM: shmobile: Add PCIe resources to r8a7791 device
2014-02-26 16:08 [PATCH 0/5 RFC] R-Car Gen2 PCIe host driver Phil Edworthy
2014-02-26 16:08 ` [PATCH 1/5] PCI: host: Add Renesas R-Car PCIe driver Phil Edworthy
2014-02-26 16:08 ` [PATCH 2/5] ARM: shmobile: r8a7791: Add PCIe clock Phil Edworthy
@ 2014-02-26 16:08 ` Phil Edworthy
2014-02-26 16:08 ` [PATCH 4/5] ARM: shmobile: Add PCIe to r8a7791 device Kconfig Phil Edworthy
2014-02-26 16:08 ` [PATCH 5/5] ARM: koelsch: Add PCIe to defconfig Phil Edworthy
4 siblings, 0 replies; 10+ messages in thread
From: Phil Edworthy @ 2014-02-26 16:08 UTC (permalink / raw)
To: linux-pci
Cc: linux-sh, Bjorn Helgaas, Valentine Barshak, Simon Horman,
Magnus Damm, Phil Edworthy
Signed-off-by: Phil Edworthy <phil.edworthy@renesas.com>
---
arch/arm/mach-shmobile/setup-r8a7791.c | 13 +++++++++++++
1 file changed, 13 insertions(+)
diff --git a/arch/arm/mach-shmobile/setup-r8a7791.c b/arch/arm/mach-shmobile/setup-r8a7791.c
index d9393d6..7751aae 100644
--- a/arch/arm/mach-shmobile/setup-r8a7791.c
+++ b/arch/arm/mach-shmobile/setup-r8a7791.c
@@ -136,6 +136,16 @@ static struct resource irqc0_resources[] = {
&irqc##idx##_data, \
sizeof(struct renesas_irqc_config))
+/* PCI Express */
+static struct resource pcie_resources[] = {
+ DEFINE_RES_MEM(0xfe000000, SZ_512K),
+ DEFINE_RES_MEM(0xfe100000, SZ_1M),
+ DEFINE_RES_MEM(0xfe200000, SZ_2M),
+ DEFINE_RES_MEM(0x30000000, SZ_128M),
+ DEFINE_RES_MEM(0x38000000, SZ_128M),
+ DEFINE_RES_IRQ(gic_spi(116)),
+};
+
void __init r8a7791_add_dt_devices(void)
{
r8a7791_register_scif(SCIFA0);
@@ -160,6 +170,9 @@ void __init r8a7791_add_standard_devices(void)
{
r8a7791_add_dt_devices();
r8a7791_register_irqc(0);
+ platform_device_register_simple("r8a7791-pcie", -1,
+ pcie_resources,
+ ARRAY_SIZE(pcie_resources));
}
void __init r8a7791_init_early(void)
--
1.7.9.5
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [PATCH 4/5] ARM: shmobile: Add PCIe to r8a7791 device Kconfig
2014-02-26 16:08 [PATCH 0/5 RFC] R-Car Gen2 PCIe host driver Phil Edworthy
` (2 preceding siblings ...)
2014-02-26 16:08 ` [PATCH 3/5] ARM: shmobile: Add PCIe resources to r8a7791 device Phil Edworthy
@ 2014-02-26 16:08 ` Phil Edworthy
2014-02-26 16:08 ` [PATCH 5/5] ARM: koelsch: Add PCIe to defconfig Phil Edworthy
4 siblings, 0 replies; 10+ messages in thread
From: Phil Edworthy @ 2014-02-26 16:08 UTC (permalink / raw)
To: linux-pci
Cc: linux-sh, Bjorn Helgaas, Valentine Barshak, Simon Horman,
Magnus Damm, Phil Edworthy
Signed-off-by: Phil Edworthy <phil.edworthy@renesas.com>
---
arch/arm/mach-shmobile/Kconfig | 2 ++
1 file changed, 2 insertions(+)
diff --git a/arch/arm/mach-shmobile/Kconfig b/arch/arm/mach-shmobile/Kconfig
index a4a4b75..c623633 100644
--- a/arch/arm/mach-shmobile/Kconfig
+++ b/arch/arm/mach-shmobile/Kconfig
@@ -100,6 +100,8 @@ config ARCH_R8A7791
select ARM_GIC
select CPU_V7
select SH_CLK_CPG
+ select MIGHT_HAVE_PCI
+ select PCI_QUIRKS if PCI
config ARCH_EMEV2
bool "Emma Mobile EV2"
--
1.7.9.5
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [PATCH 5/5] ARM: koelsch: Add PCIe to defconfig
2014-02-26 16:08 [PATCH 0/5 RFC] R-Car Gen2 PCIe host driver Phil Edworthy
` (3 preceding siblings ...)
2014-02-26 16:08 ` [PATCH 4/5] ARM: shmobile: Add PCIe to r8a7791 device Kconfig Phil Edworthy
@ 2014-02-26 16:08 ` Phil Edworthy
4 siblings, 0 replies; 10+ messages in thread
From: Phil Edworthy @ 2014-02-26 16:08 UTC (permalink / raw)
To: linux-pci
Cc: linux-sh, Bjorn Helgaas, Valentine Barshak, Simon Horman,
Magnus Damm, Phil Edworthy
Signed-off-by: Phil Edworthy <phil.edworthy@renesas.com>
---
arch/arm/configs/koelsch_defconfig | 3 +++
1 file changed, 3 insertions(+)
diff --git a/arch/arm/configs/koelsch_defconfig b/arch/arm/configs/koelsch_defconfig
index c59768e..adb67d5 100644
--- a/arch/arm/configs/koelsch_defconfig
+++ b/arch/arm/configs/koelsch_defconfig
@@ -20,6 +20,9 @@ CONFIG_MACH_KOELSCH=y
CONFIG_CPU_BPREDICT_DISABLE=y
CONFIG_PL310_ERRATA_588369=y
CONFIG_ARM_ERRATA_754322=y
+CONFIG_PCI=y
+CONFIG_PCI_RCAR_GEN2_PCIE=y
+CONFIG_PCIEPORTBUS=y
CONFIG_SMP=y
CONFIG_SCHED_MC=y
CONFIG_NR_CPUS=8
--
1.7.9.5
^ permalink raw reply related [flat|nested] 10+ messages in thread
* Re: [PATCH 1/5] PCI: host: Add Renesas R-Car PCIe driver
2014-02-26 16:08 ` [PATCH 1/5] PCI: host: Add Renesas R-Car PCIe driver Phil Edworthy
@ 2014-02-26 16:34 ` Ben Dooks
2014-02-26 17:13 ` Phil.Edworthy
0 siblings, 1 reply; 10+ messages in thread
From: Ben Dooks @ 2014-02-26 16:34 UTC (permalink / raw)
To: Phil Edworthy
Cc: linux-pci, linux-sh, Bjorn Helgaas, Valentine Barshak,
Simon Horman, Magnus Damm
On 26/02/14 16:08, Phil Edworthy wrote:
> This PCIe Host driver currently does not support MSI, so cards
> fall back to INTx interrupts.
>
> Signed-off-by: Phil Edworthy <phil.edworthy@renesas.com>
> + bool "Renesas R-Car PCIe controller"
> + depends on ARM && (ARCH_R8A7790 || ARCH_R8A7791 || COMPILE_TEST)
> + help
> + Say Y here if you want PCIe controller support on R-Car Gen2 SoCs.
> +
> endmenu
> diff --git a/drivers/pci/host/Makefile b/drivers/pci/host/Makefile
> index 13fb333..19946f9 100644
> --- a/drivers/pci/host/Makefile
> +++ b/drivers/pci/host/Makefile
> @@ -4,3 +4,4 @@ obj-$(CONFIG_PCI_IMX6) += pci-imx6.o
> obj-$(CONFIG_PCI_MVEBU) += pci-mvebu.o
> obj-$(CONFIG_PCI_TEGRA) += pci-tegra.o
> obj-$(CONFIG_PCI_RCAR_GEN2) += pci-rcar-gen2.o
> +obj-$(CONFIG_PCI_RCAR_GEN2_PCIE) += pcie-rcar.o
> diff --git a/drivers/pci/host/pcie-rcar.c b/drivers/pci/host/pcie-rcar.c
> new file mode 100644
> index 0000000..d9a315f
> --- /dev/null
> +++ b/drivers/pci/host/pcie-rcar.c
> @@ -0,0 +1,614 @@
> +/*
> + * PCIe driver for Renesas R-Car SoCs
> + * Copyright (C) 2013 Renesas Electronics Europe Ltd
> + *
> + * Based on:
> + * arch/sh/drivers/pci/pcie-sh7786.c
> + * arch/sh/drivers/pci/ops-sh7786.c
> + * Copyright (C) 2009 - 2011 Paul Mundt
> + *
> + * This file is licensed under the terms of the GNU General Public
> + * License version 2. This program is licensed "as is" without any
> + * warranty of any kind, whether express or implied.
> + */
> +
> +#include <linux/clk.h>
> +#include <linux/delay.h>
> +#include <linux/interrupt.h>
> +#include <linux/module.h>
> +#include <linux/kernel.h>
> +#include <linux/of_address.h>
> +#include <linux/of_irq.h>
> +#include <linux/of_pci.h>
> +#include <linux/of_platform.h>
> +#include <linux/pci.h>
> +#include <linux/platform_device.h>
> +#include <linux/slab.h>
> +#include "pcie-rcar.h"
> +
> +#define DRV_NAME "rcar-pcie"
> +
> +enum chip_id {
> + RCAR_GENERIC,
> + RCAR_H1,
> +};
> +
> +#define RCONF(x) (PCICONF(0)+(x))
> +#define REXPCAP(x) (EXPCAP(0)+(x))
> +#define RVCCAP(x) (VCCAP(0)+(x))
> +
> +#define PCIE_CONF_BUS(b) (((b) & 0xff) << 24)
> +#define PCIE_CONF_DEV(d) (((d) & 0x1f) << 19)
> +#define PCIE_CONF_FUNC(f) (((f) & 0x7) << 16)
> +
> +#define NR_PCI_RESOURCES 4
> +
> +/* Structure representing the PCIe interface */
> +struct rcar_pcie {
> + struct device *dev;
> + void __iomem *base;
> + int irq;
> + struct clk *clk;
> + struct resource *res[NR_PCI_RESOURCES];
> + int haslink;
> + enum chip_id chip;
> + u8 root_bus_nr;
> +};
> +
> +static inline struct rcar_pcie *sys_to_pcie(struct pci_sys_data *sys)
> +{
> + return sys->private_data;
> +}
> +
> +static void
> +pci_write_reg(struct rcar_pcie *pcie, unsigned long val, unsigned long reg)
> +{
> + writel(val, pcie->base + reg);
> +}
Do we really need wrappers like these?
> +static unsigned long
> +pci_read_reg(struct rcar_pcie *pcie, unsigned long reg)
> +{
> + return readl(pcie->base + reg);
> +}
> +
> +enum {
> + PCI_ACCESS_READ,
> + PCI_ACCESS_WRITE,
> +};
> +static int rcar_pcie_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
> +{
> + struct rcar_pcie *pcie = sys_to_pcie(dev->bus->sysdata);
> + return pcie->irq;
> +}
> +
> +static void __init rcar_pcie_enable(struct rcar_pcie *pcie)
> +{
> + struct hw_pci hw;
> +
> + memset(&hw, 0, sizeof(hw));
> +
> + hw.nr_controllers = 1;
> + hw.private_data = (void **)&pcie;
> + hw.setup = rcar_pcie_setup,
> + hw.map_irq = rcar_pcie_map_irq,
> + hw.ops = &rcar_pcie_ops,
> +
> + pci_common_init(&hw);
> +}
> +
> +static int __init phy_wait_for_ack(struct rcar_pcie *pcie)
> +{
> + unsigned int timeout = 100;
> +
> + while (timeout--) {
> + if (pci_read_reg(pcie, H1_PCIEPHYADRR) & PHY_ACK)
> + return 0;
> +
> + udelay(100);
> + }
> +
> + dev_err(pcie->dev, "Access to PCIe phy timed out\n");
> +
> + return -ETIMEDOUT;
> +}
Could this be done with some sort of sleep, instead of having
to keep delaying? How long is the average wait for pci to finish
a write?
> +
> +static void __init phy_write_reg(struct rcar_pcie *pcie,
> + unsigned int rate, unsigned int addr,
> + unsigned int lane, unsigned int data)
> +{
> + unsigned long phyaddr;
> +
> + phyaddr = WRITE_CMD |
> + ((rate & 1) << RATE_POS) |
> + ((lane & 0xf) << LANE_POS) |
> + ((addr & 0xff) << ADR_POS);
> +
> + /* Set write data */
> + pci_write_reg(pcie, data, H1_PCIEPHYDOUTR);
> + pci_write_reg(pcie, phyaddr, H1_PCIEPHYADRR);
> +
> + /* Ignore errors as they will be dealt with if the data link is down */
> + phy_wait_for_ack(pcie);
> +
> + /* Clear command */
> + pci_write_reg(pcie, 0, H1_PCIEPHYDOUTR);
> + pci_write_reg(pcie, 0, H1_PCIEPHYADRR);
> +
> + /* Ignore errors as they will be dealt with if the data link is down */
> + phy_wait_for_ack(pcie);
> +}
> +
>
> +static int __init rcar_pcie_wait_for_dl(struct rcar_pcie *pcie)
> +{
> + unsigned int timeout = 100;
> +
> + while (timeout--) {
> + if ((pci_read_reg(pcie, PCIETSTR) & DATA_LINK_ACTIVE))
> + return 0;
> +
> + udelay(100);
> + }
> +
> + return -ETIMEDOUT;
> +}
Same comments as for previous delay loop
> +static void __init rcar_pcie_hw_init(struct rcar_pcie *pcie)
> +{
> + /* Initialise R-Car H1 PHY & wait for it to be ready */
> + if (pcie->chip = RCAR_H1)
> + if (rcar_pcie_phy_init_rcar_h1(pcie))
> + return;
> +
> + /* Begin initialization */
> + pci_write_reg(pcie, 0, PCIETCTLR);
> +
> + /* Set mode */
> + pci_write_reg(pcie, 1, PCIEMSR);
> +
> + /*
> + * For target transfers, setup a single 64-bit 4GB mapping at address
> + * 0. The hardware can only map memory that starts on a power of two
> + * boundary, and size is power of 2, so best to ignore it.
> + */
> + pci_write_reg(pcie, 0, PCIEPRAR(0));
> + pci_write_reg(pcie, 0, PCIELAR(0));
> + pci_write_reg(pcie, 0xfffffff0UL | LAM_PREFETCH |
> + LAM_64BIT | LAR_ENABLE, PCIELAMR(0));
> + pci_write_reg(pcie, 0, PCIELAR(1));
> + pci_write_reg(pcie, 0, PCIEPRAR(1));
> + pci_write_reg(pcie, 0, PCIELAMR(1));
> +
> + /*
> + * Initial header for port config space is type 1, set the device
> + * class to match. Hardware takes care of propagating the IDSETR
> + * settings, so there is no need to bother with a quirk.
> + */
> + pci_write_reg(pcie, PCI_CLASS_BRIDGE_PCI << 16, IDSETR1);
> +
> + /*
> + * Setup Secondary Bus Number & Subordinate Bus Number, even though
> + * they aren't used, to avoid bridge being detected as broken.
> + */
> + rcar_rmw32(pcie, RCONF(PCI_SECONDARY_BUS), 0xff, 1);
> + rcar_rmw32(pcie, RCONF(PCI_SUBORDINATE_BUS), 0xff, 1);
> +
> + /* Initialize default capabilities. */
> + rcar_rmw32(pcie, REXPCAP(0), 0, PCI_CAP_ID_EXP);
> + rcar_rmw32(pcie, REXPCAP(PCI_EXP_FLAGS),
> + PCI_EXP_FLAGS_TYPE, PCI_EXP_TYPE_ROOT_PORT << 4);
> + rcar_rmw32(pcie, RCONF(PCI_HEADER_TYPE), 0x7f,
> + PCI_HEADER_TYPE_BRIDGE);
> +
> + /* Enable data link layer active state reporting */
> + rcar_rmw32(pcie, REXPCAP(PCI_EXP_LNKCAP), 0, PCI_EXP_LNKCAP_DLLLARC);
> +
> + /* Write out the physical slot number = 0 */
> + rcar_rmw32(pcie, REXPCAP(PCI_EXP_SLTCAP), PCI_EXP_SLTCAP_PSN, 0);
> +
> + /* Set the completion timer timeout to the maximum 50ms. */
> + rcar_rmw32(pcie, TLCTLR+1, 0x3f, 50);
> +
> + /* Terminate list of capabilities (Next Capability Offset=0) */
> + rcar_rmw32(pcie, RVCCAP(0), 0xfff0, 0);
> +
> + /* Enable MAC data scrambling. */
> + rcar_rmw32(pcie, MACCTLR, SCRAMBLE_DISABLE, 0);
> +
> + /* Finish initialization - establish a PCI Express link */
> + pci_write_reg(pcie, CFINIT, PCIETCTLR);
> +
> + /* This will timeout if we don't have a link. */
> + pcie->haslink = !rcar_pcie_wait_for_dl(pcie);
> +
> + /* Enable INTx interrupts */
> + rcar_rmw32(pcie, RCONF(PCI_INTERRUPT_LINE), 0xff, 0);
> + rcar_rmw32(pcie, RCONF(PCI_INTERRUPT_PIN), 0xff, 1);
> + rcar_rmw32(pcie, PCIEINTXR, 0, 0xF << 8);
> +
> + /* Enable slave Bus Mastering */
> + rcar_rmw32(pcie, RCONF(PCI_STATUS), PCI_STATUS_DEVSEL_MASK,
> + PCI_COMMAND_IO | PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER |
> + PCI_STATUS_CAP_LIST | PCI_STATUS_DEVSEL_FAST);
> +
> + wmb();
> +}
> +
> +static int rcar_pcie_clocks_get(struct rcar_pcie *pcie)
> +{
> + int err = 0;
> +
> + pcie->clk = clk_get(pcie->dev, NULL);
> + if (IS_ERR(pcie->clk))
> + err = PTR_ERR(pcie->clk);
> + else
> + clk_enable(pcie->clk);
> +
> + return err;
> +}
Shouldn't you be using pm_runtime for this?
> +static void rcar_pcie_clocks_put(struct rcar_pcie *pcie)
> +{
> + clk_put(pcie->clk);
> +}
> +
> +struct rcar_pcie_errs {
> + int bit;
> + const char *description;
> +};
> +
> +static int __init rcar_pcie_get_resources(struct platform_device *pdev,
> + struct rcar_pcie *pcie)
> +{
> + struct resource *res;
> + int i;
> + int err;
> +
> + res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> +
> + i = platform_get_irq(pdev, 0);
> + if (!res || i < 0) {
> + dev_err(pcie->dev, "cannot get platform resources\n");
> + return -ENOENT;
> + }
> + pcie->irq = i;
> +
> + err = rcar_pcie_clocks_get(pcie);
> + if (err) {
> + dev_err(&pdev->dev, "failed to get clocks: %d\n", err);
> + return err;
> + }
> +
> + pcie->base = devm_request_and_ioremap(&pdev->dev, res);
> + if (!pcie->base) {
> + dev_err(&pdev->dev, "failed to map PCIe registers: %d\n", err);
> + err = -ENOMEM;
> + goto err_map_reg;
> + }
> +
> + return 0;
> +
> +err_map_reg:
> + rcar_pcie_clocks_put(pcie);
> +
> + return err;
> +}
> +
> +static struct platform_device_id rcar_pcie_id_table[] = {
> + { "r8a7779-pcie", RCAR_H1 },
> + { "r8a7790-pcie", RCAR_GENERIC },
> + { "r8a7791-pcie", RCAR_GENERIC },
> + {},
> +};
> +MODULE_DEVICE_TABLE(platform, rcar_pcie_id_table);
Really, are you still going to submit drivers without OF bindings?
NAK!
> +static int __init rcar_pcie_probe(struct platform_device *pdev)
> +{
> + struct rcar_pcie *pcie;
> + struct resource *res;
> + unsigned int data;
> + int i, err;
> +
> + pcie = devm_kzalloc(&pdev->dev, sizeof(*pcie), GFP_KERNEL);
> + if (!pcie)
> + return -ENOMEM;
> +
> + pcie->dev = &pdev->dev;
> + pcie->chip = pdev->id_entry->driver_data;
> +
> + /* Get resources */
> + err = rcar_pcie_get_resources(pdev, pcie);
> + if (err < 0) {
> + dev_err(&pdev->dev, "failed to request resources: %d\n", err);
> + return err;
> + }
> +
> + /* Get the I/O and memory ranges */
> + for (i = 0; i < NR_PCI_RESOURCES; i++) {
> + res = platform_get_resource(pdev, IORESOURCE_MEM, i+1);
> + if (!res) {
> + dev_err(&pdev->dev, "cannot get MEM%d resources\n", i);
> + return -ENOENT;
> + }
> + pcie->res[i] = res;
> + }
> +
> + rcar_pcie_hw_init(pcie);
> +
> + if (!pcie->haslink) {
> + dev_info(&pdev->dev, "PCI: PCIe link down\n");
> + return 0;
> + }
> +
> + data = pci_read_reg(pcie, MACSR);
> + dev_info(&pdev->dev, "PCIe x%d: link up\n", (data >> 20) & 0x3f);
> +
> + rcar_pcie_enable(pcie);
> +
> + platform_set_drvdata(pdev, pcie);
> + return 0;
> +}
> +
> +static struct platform_driver rcar_pcie_driver = {
> + .probe = rcar_pcie_probe,
> + .driver = {
> + .name = DRV_NAME,
> + .owner = THIS_MODULE,
> + },
> + .id_table = rcar_pcie_id_table,
> +};
> +
> +module_platform_driver(rcar_pcie_driver);
> +
> +MODULE_AUTHOR("Phil Edworthy <phil.edworthy@renesas.com>");
> +MODULE_DESCRIPTION("Renesas R-Car PCIe driver");
> +MODULE_LICENSE("GPLv2");
> diff --git a/drivers/pci/host/pcie-rcar.h b/drivers/pci/host/pcie-rcar.h
> new file mode 100644
> index 0000000..a6b407f
> --- /dev/null
> +++ b/drivers/pci/host/pcie-rcar.h
> @@ -0,0 +1,84 @@
> +/*
> + * PCI Express definitions for Renesas R-Car SoCs
> + */
> +#ifndef __PCI_RCAR_H
> +#define __PCI_RCAR_H
> +
> +#define PCI_DEVICE_ID_RENESAS_RCAR 0x0018
should this go into pci ids header?
> +#define PCIECAR 0x000010
> +#define PCIECCTLR 0x000018
> +#define CONFIG_SEND_ENABLE (1 << 31)
> +#define TYPE0 (0 << 8)
> +#define TYPE1 (1 << 8)
> +#define PCIECDR 0x000020
> +#define PCIEMSR 0x000028
> +#define PCIEINTXR 0x000400
> +#define PCIEPHYSR 0x0007f0
> +
> +/* Transfer control */
> +#define PCIETCTLR 0x02000
> +#define CFINIT 1
> +#define PCIETSTR 0x02004
> +#define DATA_LINK_ACTIVE 1
> +#define PCIEINTR 0x02008
> +#define PCIEINTER 0x0200c
> +#define PCIEERRFR 0x02020
> +#define UNSUPPORTED_REQUEST (1 << 4)
> +#define PCIEERRFER 0x02024
> +#define PCIEERRFR2 0x02028
> +#define PCIEPMSR 0x02034
> +#define PCIEPMSCIER 0x02038
> +#define PCIEMSIFR 0x02044
> +
> +/* root port address */
> +#define PCIEPRAR(x) (0x02080 + ((x) * 0x4))
> +
> +/* local address reg & mask */
> +#define PCIELAR(x) (0x02200 + ((x) * 0x20))
> +#define PCIELAMR(x) (0x02208 + ((x) * 0x20))
> +#define LAM_PMIOLAMnB3 (1 << 3)
> +#define LAM_PMIOLAMnB2 (1 << 2)
> +#define LAM_PREFETCH (1 << 3)
> +#define LAM_64BIT (1 << 2)
> +#define LAR_ENABLE (1 << 1)
> +
> +/* PCIe address reg & mask */
> +#define PCIEPARL(x) (0x03400 + ((x) * 0x20))
> +#define PCIEPARH(x) (0x03404 + ((x) * 0x20))
> +#define PCIEPAMR(x) (0x03408 + ((x) * 0x20))
> +#define PCIEPTCTLR(x) (0x0340c + ((x) * 0x20))
> +#define PAR_ENABLE (1 << 31)
> +#define IO_SPACE (1 << 8)
> +
> +/* Configuration */
> +#define PCICONF(x) (0x010000 + ((x) * 0x4))
> +#define PMCAP(x) (0x010040 + ((x) * 0x4))
> +#define MSICAP(x) (0x010050 + ((x) * 0x4))
> +#define EXPCAP(x) (0x010070 + ((x) * 0x4))
> +#define VCCAP(x) (0x010100 + ((x) * 0x4))
> +#define SERNUMCAP(x) (0x0101b0 + ((x) * 0x4))
> +
> +/* link layer */
> +#define IDSETR0 0x011000
> +#define IDSETR1 0x011004
> +#define SUBIDSETR 0x011024
> +#define DSERSETR0 0x01102c
> +#define DSERSETR1 0x011030
> +#define TLCTLR 0x011048
> +#define MACSR 0x011054
> +#define MACCTLR 0x011058
> +#define SCRAMBLE_DISABLE (1 << 27)
> +
> +/* R-Car H1 PHY */
> +#define H1_PCIEPHYCTLR 0x040008
> +#define H1_PCIEPHYADRR 0x04000c
> +#define WRITE_CMD (1 << 16)
> +#define PHY_ACK (1 << 24)
> +#define RATE_POS 12
> +#define LANE_POS 8
> +#define ADR_POS 0
> +#define H1_PCIEPHYDOUTR 0x040014
> +#define H1_PCIEPHYSR 0x040018
> +
> +#endif /* __PCI_RCAR_H */
>
--
Ben Dooks http://www.codethink.co.uk/
Senior Engineer Codethink - Providing Genius
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH 1/5] PCI: host: Add Renesas R-Car PCIe driver
2014-02-26 16:34 ` Ben Dooks
@ 2014-02-26 17:13 ` Phil.Edworthy
2014-02-26 17:19 ` Ben Dooks
0 siblings, 1 reply; 10+ messages in thread
From: Phil.Edworthy @ 2014-02-26 17:13 UTC (permalink / raw)
To: Ben Dooks
Cc: Bjorn Helgaas, Simon Horman, linux-pci, linux-sh, Magnus Damm,
Valentine Barshak
Hi Ben,
Thanks for your comments.
On 26/02/2014 16:33, Ben Dooks wrote:
> On 26/02/14 16:08, Phil Edworthy wrote:
> > This PCIe Host driver currently does not support MSI, so cards
> > fall back to INTx interrupts.
> >
> > Signed-off-by: Phil Edworthy <phil.edworthy@renesas.com>
>
> > + bool "Renesas R-Car PCIe controller"
> > + depends on ARM && (ARCH_R8A7790 || ARCH_R8A7791 || COMPILE_TEST)
> > + help
> > + Say Y here if you want PCIe controller support on R-Car Gen2
SoCs.
> > +
> > endmenu
> > diff --git a/drivers/pci/host/Makefile b/drivers/pci/host/Makefile
> > index 13fb333..19946f9 100644
> > --- a/drivers/pci/host/Makefile
> > +++ b/drivers/pci/host/Makefile
> > @@ -4,3 +4,4 @@ obj-$(CONFIG_PCI_IMX6) += pci-imx6.o
> > obj-$(CONFIG_PCI_MVEBU) += pci-mvebu.o
> > obj-$(CONFIG_PCI_TEGRA) += pci-tegra.o
> > obj-$(CONFIG_PCI_RCAR_GEN2) += pci-rcar-gen2.o
> > +obj-$(CONFIG_PCI_RCAR_GEN2_PCIE) += pcie-rcar.o
> > diff --git a/drivers/pci/host/pcie-rcar.c
b/drivers/pci/host/pcie-rcar.c
> > new file mode 100644
> > index 0000000..d9a315f
> > --- /dev/null
> > +++ b/drivers/pci/host/pcie-rcar.c
> > @@ -0,0 +1,614 @@
> > +/*
> > + * PCIe driver for Renesas R-Car SoCs
> > + * Copyright (C) 2013 Renesas Electronics Europe Ltd
> > + *
> > + * Based on:
> > + * arch/sh/drivers/pci/pcie-sh7786.c
> > + * arch/sh/drivers/pci/ops-sh7786.c
> > + * Copyright (C) 2009 - 2011 Paul Mundt
> > + *
> > + * This file is licensed under the terms of the GNU General Public
> > + * License version 2. This program is licensed "as is" without any
> > + * warranty of any kind, whether express or implied.
> > + */
> > +
> > +#include <linux/clk.h>
> > +#include <linux/delay.h>
> > +#include <linux/interrupt.h>
> > +#include <linux/module.h>
> > +#include <linux/kernel.h>
> > +#include <linux/of_address.h>
> > +#include <linux/of_irq.h>
> > +#include <linux/of_pci.h>
> > +#include <linux/of_platform.h>
> > +#include <linux/pci.h>
> > +#include <linux/platform_device.h>
> > +#include <linux/slab.h>
> > +#include "pcie-rcar.h"
> > +
> > +#define DRV_NAME "rcar-pcie"
> > +
> > +enum chip_id {
> > + RCAR_GENERIC,
> > + RCAR_H1,
> > +};
> > +
> > +#define RCONF(x) (PCICONF(0)+(x))
> > +#define REXPCAP(x) (EXPCAP(0)+(x))
> > +#define RVCCAP(x) (VCCAP(0)+(x))
> > +
> > +#define PCIE_CONF_BUS(b) (((b) & 0xff) << 24)
> > +#define PCIE_CONF_DEV(d) (((d) & 0x1f) << 19)
> > +#define PCIE_CONF_FUNC(f) (((f) & 0x7) << 16)
> > +
> > +#define NR_PCI_RESOURCES 4
> > +
> > +/* Structure representing the PCIe interface */
> > +struct rcar_pcie {
> > + struct device *dev;
> > + void __iomem *base;
> > + int irq;
> > + struct clk *clk;
> > + struct resource *res[NR_PCI_RESOURCES];
> > + int haslink;
> > + enum chip_id chip;
> > + u8 root_bus_nr;
> > +};
> > +
> > +static inline struct rcar_pcie *sys_to_pcie(struct pci_sys_data *sys)
> > +{
> > + return sys->private_data;
> > +}
> > +
> > +static void
> > +pci_write_reg(struct rcar_pcie *pcie, unsigned long val, unsigned
long reg)
> > +{
> > + writel(val, pcie->base + reg);
> > +}
>
> Do we really need wrappers like these?
They were handy during development, but I guess not.
> > +static unsigned long
> > +pci_read_reg(struct rcar_pcie *pcie, unsigned long reg)
> > +{
> > + return readl(pcie->base + reg);
> > +}
> > +
> > +enum {
> > + PCI_ACCESS_READ,
> > + PCI_ACCESS_WRITE,
> > +};
>
> > +static int rcar_pcie_map_irq(const struct pci_dev *dev, u8 slot, u8
pin)
> > +{
> > + struct rcar_pcie *pcie = sys_to_pcie(dev->bus->sysdata);
> > + return pcie->irq;
> > +}
> > +
> > +static void __init rcar_pcie_enable(struct rcar_pcie *pcie)
> > +{
> > + struct hw_pci hw;
> > +
> > + memset(&hw, 0, sizeof(hw));
> > +
> > + hw.nr_controllers = 1;
> > + hw.private_data = (void **)&pcie;
> > + hw.setup = rcar_pcie_setup,
> > + hw.map_irq = rcar_pcie_map_irq,
> > + hw.ops = &rcar_pcie_ops,
> > +
> > + pci_common_init(&hw);
> > +}
> > +
> > +static int __init phy_wait_for_ack(struct rcar_pcie *pcie)
> > +{
> > + unsigned int timeout = 100;
> > +
> > + while (timeout--) {
> > + if (pci_read_reg(pcie, H1_PCIEPHYADRR) & PHY_ACK)
> > + return 0;
> > +
> > + udelay(100);
> > + }
> > +
> > + dev_err(pcie->dev, "Access to PCIe phy timed out\n");
> > +
> > + return -ETIMEDOUT;
> > +}
>
> Could this be done with some sort of sleep, instead of having
> to keep delaying? How long is the average wait for pci to finish
> a write?
I haven't measured how long, but yes, I can use mdelay instead.
> > +
> > +static void __init phy_write_reg(struct rcar_pcie *pcie,
> > + unsigned int rate, unsigned int addr,
> > + unsigned int lane, unsigned int data)
> > +{
> > + unsigned long phyaddr;
> > +
> > + phyaddr = WRITE_CMD |
> > + ((rate & 1) << RATE_POS) |
> > + ((lane & 0xf) << LANE_POS) |
> > + ((addr & 0xff) << ADR_POS);
> > +
> > + /* Set write data */
> > + pci_write_reg(pcie, data, H1_PCIEPHYDOUTR);
> > + pci_write_reg(pcie, phyaddr, H1_PCIEPHYADRR);
> > +
> > + /* Ignore errors as they will be dealt with if the data link is
down */
> > + phy_wait_for_ack(pcie);
> > +
> > + /* Clear command */
> > + pci_write_reg(pcie, 0, H1_PCIEPHYDOUTR);
> > + pci_write_reg(pcie, 0, H1_PCIEPHYADRR);
> > +
> > + /* Ignore errors as they will be dealt with if the data link is
down */
> > + phy_wait_for_ack(pcie);
> > +}
> > +
> >
>
> > +static int __init rcar_pcie_wait_for_dl(struct rcar_pcie *pcie)
> > +{
> > + unsigned int timeout = 100;
> > +
> > + while (timeout--) {
> > + if ((pci_read_reg(pcie, PCIETSTR) & DATA_LINK_ACTIVE))
> > + return 0;
> > +
> > + udelay(100);
> > + }
> > +
> > + return -ETIMEDOUT;
> > +}
>
> Same comments as for previous delay loop
>
>
> > +static void __init rcar_pcie_hw_init(struct rcar_pcie *pcie)
> > +{
> > + /* Initialise R-Car H1 PHY & wait for it to be ready */
> > + if (pcie->chip = RCAR_H1)
> > + if (rcar_pcie_phy_init_rcar_h1(pcie))
> > + return;
> > +
> > + /* Begin initialization */
> > + pci_write_reg(pcie, 0, PCIETCTLR);
> > +
> > + /* Set mode */
> > + pci_write_reg(pcie, 1, PCIEMSR);
> > +
> > + /*
> > + * For target transfers, setup a single 64-bit 4GB mapping at
address
> > + * 0. The hardware can only map memory that starts on a power of
two
> > + * boundary, and size is power of 2, so best to ignore it.
> > + */
> > + pci_write_reg(pcie, 0, PCIEPRAR(0));
> > + pci_write_reg(pcie, 0, PCIELAR(0));
> > + pci_write_reg(pcie, 0xfffffff0UL | LAM_PREFETCH |
> > + LAM_64BIT | LAR_ENABLE, PCIELAMR(0));
> > + pci_write_reg(pcie, 0, PCIELAR(1));
> > + pci_write_reg(pcie, 0, PCIEPRAR(1));
> > + pci_write_reg(pcie, 0, PCIELAMR(1));
> > +
> > + /*
> > + * Initial header for port config space is type 1, set the device
> > + * class to match. Hardware takes care of propagating the IDSETR
> > + * settings, so there is no need to bother with a quirk.
> > + */
> > + pci_write_reg(pcie, PCI_CLASS_BRIDGE_PCI << 16, IDSETR1);
> > +
> > + /*
> > + * Setup Secondary Bus Number & Subordinate Bus Number, even
though
> > + * they aren't used, to avoid bridge being detected as broken.
> > + */
> > + rcar_rmw32(pcie, RCONF(PCI_SECONDARY_BUS), 0xff, 1);
> > + rcar_rmw32(pcie, RCONF(PCI_SUBORDINATE_BUS), 0xff, 1);
> > +
> > + /* Initialize default capabilities. */
> > + rcar_rmw32(pcie, REXPCAP(0), 0, PCI_CAP_ID_EXP);
> > + rcar_rmw32(pcie, REXPCAP(PCI_EXP_FLAGS),
> > + PCI_EXP_FLAGS_TYPE, PCI_EXP_TYPE_ROOT_PORT << 4);
> > + rcar_rmw32(pcie, RCONF(PCI_HEADER_TYPE), 0x7f,
> > + PCI_HEADER_TYPE_BRIDGE);
> > +
> > + /* Enable data link layer active state reporting */
> > + rcar_rmw32(pcie, REXPCAP(PCI_EXP_LNKCAP), 0,
PCI_EXP_LNKCAP_DLLLARC);
> > +
> > + /* Write out the physical slot number = 0 */
> > + rcar_rmw32(pcie, REXPCAP(PCI_EXP_SLTCAP), PCI_EXP_SLTCAP_PSN, 0);
> > +
> > + /* Set the completion timer timeout to the maximum 50ms. */
> > + rcar_rmw32(pcie, TLCTLR+1, 0x3f, 50);
> > +
> > + /* Terminate list of capabilities (Next Capability Offset=0) */
> > + rcar_rmw32(pcie, RVCCAP(0), 0xfff0, 0);
> > +
> > + /* Enable MAC data scrambling. */
> > + rcar_rmw32(pcie, MACCTLR, SCRAMBLE_DISABLE, 0);
> > +
> > + /* Finish initialization - establish a PCI Express link */
> > + pci_write_reg(pcie, CFINIT, PCIETCTLR);
> > +
> > + /* This will timeout if we don't have a link. */
> > + pcie->haslink = !rcar_pcie_wait_for_dl(pcie);
> > +
> > + /* Enable INTx interrupts */
> > + rcar_rmw32(pcie, RCONF(PCI_INTERRUPT_LINE), 0xff, 0);
> > + rcar_rmw32(pcie, RCONF(PCI_INTERRUPT_PIN), 0xff, 1);
> > + rcar_rmw32(pcie, PCIEINTXR, 0, 0xF << 8);
> > +
> > + /* Enable slave Bus Mastering */
> > + rcar_rmw32(pcie, RCONF(PCI_STATUS), PCI_STATUS_DEVSEL_MASK,
> > + PCI_COMMAND_IO | PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER |
> > + PCI_STATUS_CAP_LIST | PCI_STATUS_DEVSEL_FAST);
> > +
> > + wmb();
> > +}
> > +
> > +static int rcar_pcie_clocks_get(struct rcar_pcie *pcie)
> > +{
> > + int err = 0;
> > +
> > + pcie->clk = clk_get(pcie->dev, NULL);
> > + if (IS_ERR(pcie->clk))
> > + err = PTR_ERR(pcie->clk);
> > + else
> > + clk_enable(pcie->clk);
> > +
> > + return err;
> > +}
>
> Shouldn't you be using pm_runtime for this?
Yes, I'll fix this
> > +static void rcar_pcie_clocks_put(struct rcar_pcie *pcie)
> > +{
> > + clk_put(pcie->clk);
> > +}
> > +
> > +struct rcar_pcie_errs {
> > + int bit;
> > + const char *description;
> > +};
> > +
> > +static int __init rcar_pcie_get_resources(struct platform_device
*pdev,
> > + struct rcar_pcie *pcie)
> > +{
> > + struct resource *res;
> > + int i;
> > + int err;
> > +
> > + res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> > +
> > + i = platform_get_irq(pdev, 0);
> > + if (!res || i < 0) {
> > + dev_err(pcie->dev, "cannot get platform resources\n");
> > + return -ENOENT;
> > + }
> > + pcie->irq = i;
> > +
> > + err = rcar_pcie_clocks_get(pcie);
> > + if (err) {
> > + dev_err(&pdev->dev, "failed to get clocks: %d\n", err);
> > + return err;
> > + }
> > +
> > + pcie->base = devm_request_and_ioremap(&pdev->dev, res);
> > + if (!pcie->base) {
> > + dev_err(&pdev->dev, "failed to map PCIe registers: %d\n", err);
> > + err = -ENOMEM;
> > + goto err_map_reg;
> > + }
> > +
> > + return 0;
> > +
> > +err_map_reg:
> > + rcar_pcie_clocks_put(pcie);
> > +
> > + return err;
> > +}
> > +
> > +static struct platform_device_id rcar_pcie_id_table[] = {
> > + { "r8a7779-pcie", RCAR_H1 },
> > + { "r8a7790-pcie", RCAR_GENERIC },
> > + { "r8a7791-pcie", RCAR_GENERIC },
> > + {},
> > +};
> > +MODULE_DEVICE_TABLE(platform, rcar_pcie_id_table);
>
> Really, are you still going to submit drivers without OF bindings?
>
> NAK!
I totally agree, hence my comment in the cover email:
"This is RFC as there is some work required for DT support."
Perhaps I should have marked each patch as RFC.
> > +static int __init rcar_pcie_probe(struct platform_device *pdev)
> > +{
> > + struct rcar_pcie *pcie;
> > + struct resource *res;
> > + unsigned int data;
> > + int i, err;
> > +
> > + pcie = devm_kzalloc(&pdev->dev, sizeof(*pcie), GFP_KERNEL);
> > + if (!pcie)
> > + return -ENOMEM;
> > +
> > + pcie->dev = &pdev->dev;
> > + pcie->chip = pdev->id_entry->driver_data;
> > +
> > + /* Get resources */
> > + err = rcar_pcie_get_resources(pdev, pcie);
> > + if (err < 0) {
> > + dev_err(&pdev->dev, "failed to request resources: %d\n", err);
> > + return err;
> > + }
> > +
> > + /* Get the I/O and memory ranges */
> > + for (i = 0; i < NR_PCI_RESOURCES; i++) {
> > + res = platform_get_resource(pdev, IORESOURCE_MEM, i+1);
> > + if (!res) {
> > + dev_err(&pdev->dev, "cannot get MEM%d resources\n", i);
> > + return -ENOENT;
> > + }
> > + pcie->res[i] = res;
> > + }
> > +
> > + rcar_pcie_hw_init(pcie);
> > +
> > + if (!pcie->haslink) {
> > + dev_info(&pdev->dev, "PCI: PCIe link down\n");
> > + return 0;
> > + }
> > +
> > + data = pci_read_reg(pcie, MACSR);
> > + dev_info(&pdev->dev, "PCIe x%d: link up\n", (data >> 20) & 0x3f);
> > +
> > + rcar_pcie_enable(pcie);
> > +
> > + platform_set_drvdata(pdev, pcie);
> > + return 0;
> > +}
> > +
> > +static struct platform_driver rcar_pcie_driver = {
> > + .probe = rcar_pcie_probe,
> > + .driver = {
> > + .name = DRV_NAME,
> > + .owner = THIS_MODULE,
> > + },
> > + .id_table = rcar_pcie_id_table,
> > +};
> > +
> > +module_platform_driver(rcar_pcie_driver);
> > +
> > +MODULE_AUTHOR("Phil Edworthy <phil.edworthy@renesas.com>");
> > +MODULE_DESCRIPTION("Renesas R-Car PCIe driver");
> > +MODULE_LICENSE("GPLv2");
> > diff --git a/drivers/pci/host/pcie-rcar.h
b/drivers/pci/host/pcie-rcar.h
> > new file mode 100644
> > index 0000000..a6b407f
> > --- /dev/null
> > +++ b/drivers/pci/host/pcie-rcar.h
> > @@ -0,0 +1,84 @@
> > +/*
> > + * PCI Express definitions for Renesas R-Car SoCs
> > + */
> > +#ifndef __PCI_RCAR_H
> > +#define __PCI_RCAR_H
> > +
> > +#define PCI_DEVICE_ID_RENESAS_RCAR 0x0018
>
> should this go into pci ids header?
This is not used so I'll remove it.
> > +#define PCIECAR 0x000010
> > +#define PCIECCTLR 0x000018
> > +#define CONFIG_SEND_ENABLE (1 << 31)
> > +#define TYPE0 (0 << 8)
> > +#define TYPE1 (1 << 8)
> > +#define PCIECDR 0x000020
> > +#define PCIEMSR 0x000028
> > +#define PCIEINTXR 0x000400
> > +#define PCIEPHYSR 0x0007f0
> > +
> > +/* Transfer control */
> > +#define PCIETCTLR 0x02000
> > +#define CFINIT 1
> > +#define PCIETSTR 0x02004
> > +#define DATA_LINK_ACTIVE 1
> > +#define PCIEINTR 0x02008
> > +#define PCIEINTER 0x0200c
> > +#define PCIEERRFR 0x02020
> > +#define UNSUPPORTED_REQUEST (1 << 4)
> > +#define PCIEERRFER 0x02024
> > +#define PCIEERRFR2 0x02028
> > +#define PCIEPMSR 0x02034
> > +#define PCIEPMSCIER 0x02038
> > +#define PCIEMSIFR 0x02044
> > +
> > +/* root port address */
> > +#define PCIEPRAR(x) (0x02080 + ((x) * 0x4))
> > +
> > +/* local address reg & mask */
> > +#define PCIELAR(x) (0x02200 + ((x) * 0x20))
> > +#define PCIELAMR(x) (0x02208 + ((x) * 0x20))
> > +#define LAM_PMIOLAMnB3 (1 << 3)
> > +#define LAM_PMIOLAMnB2 (1 << 2)
> > +#define LAM_PREFETCH (1 << 3)
> > +#define LAM_64BIT (1 << 2)
> > +#define LAR_ENABLE (1 << 1)
> > +
> > +/* PCIe address reg & mask */
> > +#define PCIEPARL(x) (0x03400 + ((x) * 0x20))
> > +#define PCIEPARH(x) (0x03404 + ((x) * 0x20))
> > +#define PCIEPAMR(x) (0x03408 + ((x) * 0x20))
> > +#define PCIEPTCTLR(x) (0x0340c + ((x) * 0x20))
> > +#define PAR_ENABLE (1 << 31)
> > +#define IO_SPACE (1 << 8)
> > +
> > +/* Configuration */
> > +#define PCICONF(x) (0x010000 + ((x) * 0x4))
> > +#define PMCAP(x) (0x010040 + ((x) * 0x4))
> > +#define MSICAP(x) (0x010050 + ((x) * 0x4))
> > +#define EXPCAP(x) (0x010070 + ((x) * 0x4))
> > +#define VCCAP(x) (0x010100 + ((x) * 0x4))
> > +#define SERNUMCAP(x) (0x0101b0 + ((x) * 0x4))
> > +
> > +/* link layer */
> > +#define IDSETR0 0x011000
> > +#define IDSETR1 0x011004
> > +#define SUBIDSETR 0x011024
> > +#define DSERSETR0 0x01102c
> > +#define DSERSETR1 0x011030
> > +#define TLCTLR 0x011048
> > +#define MACSR 0x011054
> > +#define MACCTLR 0x011058
> > +#define SCRAMBLE_DISABLE (1 << 27)
> > +
> > +/* R-Car H1 PHY */
> > +#define H1_PCIEPHYCTLR 0x040008
> > +#define H1_PCIEPHYADRR 0x04000c
> > +#define WRITE_CMD (1 << 16)
> > +#define PHY_ACK (1 << 24)
> > +#define RATE_POS 12
> > +#define LANE_POS 8
> > +#define ADR_POS 0
> > +#define H1_PCIEPHYDOUTR 0x040014
> > +#define H1_PCIEPHYSR 0x040018
> > +
> > +#endif /* __PCI_RCAR_H */
> >
>
>
> --
> Ben Dooks http://www.codethink.co.uk/
> Senior Engineer Codethink - Providing Genius
Thanks
Phil
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH 1/5] PCI: host: Add Renesas R-Car PCIe driver
2014-02-26 17:13 ` Phil.Edworthy
@ 2014-02-26 17:19 ` Ben Dooks
2014-02-26 17:34 ` Phil.Edworthy
0 siblings, 1 reply; 10+ messages in thread
From: Ben Dooks @ 2014-02-26 17:19 UTC (permalink / raw)
To: Phil.Edworthy
Cc: Bjorn Helgaas, Simon Horman, linux-pci, linux-sh, Magnus Damm,
Valentine Barshak
On 26/02/14 17:13, Phil.Edworthy@renesas.com wrote:
> Hi Ben,
>
> Thanks for your comments.
>
> On 26/02/2014 16:33, Ben Dooks wrote:
>> On 26/02/14 16:08, Phil Edworthy wrote:
>>> This PCIe Host driver currently does not support MSI, so cards
>>> fall back to INTx interrupts.
>>>
>>> Signed-off-by: Phil Edworthy <phil.edworthy@renesas.com>
>>
>>> + bool "Renesas R-Car PCIe controller"
>>> + depends on ARM && (ARCH_R8A7790 || ARCH_R8A7791 || COMPILE_TEST)
>>> + help
>>> + Say Y here if you want PCIe controller support on R-Car Gen2
> SoCs.
>>> +
>>> endmenu
>>> diff --git a/drivers/pci/host/Makefile b/drivers/pci/host/Makefile
>>> index 13fb333..19946f9 100644
>>> --- a/drivers/pci/host/Makefile
>>> +++ b/drivers/pci/host/Makefile
>>> @@ -4,3 +4,4 @@ obj-$(CONFIG_PCI_IMX6) += pci-imx6.o
>>> obj-$(CONFIG_PCI_MVEBU) += pci-mvebu.o
>>> obj-$(CONFIG_PCI_TEGRA) += pci-tegra.o
>>> obj-$(CONFIG_PCI_RCAR_GEN2) += pci-rcar-gen2.o
>>> +obj-$(CONFIG_PCI_RCAR_GEN2_PCIE) += pcie-rcar.o
>>> diff --git a/drivers/pci/host/pcie-rcar.c
> b/drivers/pci/host/pcie-rcar.c
>>> new file mode 100644
>>> index 0000000..d9a315f
>>> --- /dev/null
>>> +++ b/drivers/pci/host/pcie-rcar.c
>>> @@ -0,0 +1,614 @@
>>> +/*
>>> + * PCIe driver for Renesas R-Car SoCs
>>> + * Copyright (C) 2013 Renesas Electronics Europe Ltd
>>> + *
>>> + * Based on:
>>> + * arch/sh/drivers/pci/pcie-sh7786.c
>>> + * arch/sh/drivers/pci/ops-sh7786.c
>>> + * Copyright (C) 2009 - 2011 Paul Mundt
>>> + *
>>> + * This file is licensed under the terms of the GNU General Public
>>> + * License version 2. This program is licensed "as is" without any
>>> + * warranty of any kind, whether express or implied.
>>> + */
>>> +
>>> +#include <linux/clk.h>
>>> +#include <linux/delay.h>
>>> +#include <linux/interrupt.h>
>>> +#include <linux/module.h>
>>> +#include <linux/kernel.h>
>>> +#include <linux/of_address.h>
>>> +#include <linux/of_irq.h>
>>> +#include <linux/of_pci.h>
>>> +#include <linux/of_platform.h>
>>> +#include <linux/pci.h>
>>> +#include <linux/platform_device.h>
>>> +#include <linux/slab.h>
>>> +#include "pcie-rcar.h"
>>> +
>>> +#define DRV_NAME "rcar-pcie"
>>> +
>>> +enum chip_id {
>>> + RCAR_GENERIC,
>>> + RCAR_H1,
>>> +};
>>> +
>>> +#define RCONF(x) (PCICONF(0)+(x))
>>> +#define REXPCAP(x) (EXPCAP(0)+(x))
>>> +#define RVCCAP(x) (VCCAP(0)+(x))
>>> +
>>> +#define PCIE_CONF_BUS(b) (((b) & 0xff) << 24)
>>> +#define PCIE_CONF_DEV(d) (((d) & 0x1f) << 19)
>>> +#define PCIE_CONF_FUNC(f) (((f) & 0x7) << 16)
>>> +
>>> +#define NR_PCI_RESOURCES 4
>>> +
>>> +/* Structure representing the PCIe interface */
>>> +struct rcar_pcie {
>>> + struct device *dev;
>>> + void __iomem *base;
>>> + int irq;
>>> + struct clk *clk;
>>> + struct resource *res[NR_PCI_RESOURCES];
>>> + int haslink;
>>> + enum chip_id chip;
>>> + u8 root_bus_nr;
>>> +};
>>> +
>>> +static inline struct rcar_pcie *sys_to_pcie(struct pci_sys_data *sys)
>>> +{
>>> + return sys->private_data;
>>> +}
>>> +
>>> +static void
>>> +pci_write_reg(struct rcar_pcie *pcie, unsigned long val, unsigned
> long reg)
>>> +{
>>> + writel(val, pcie->base + reg);
>>> +}
>>
>> Do we really need wrappers like these?
> They were handy during development, but I guess not.
Actually, not that big of a deal, ignore me on this.
>>> +static unsigned long
>>> +pci_read_reg(struct rcar_pcie *pcie, unsigned long reg)
>>> +{
>>> + return readl(pcie->base + reg);
>>> +}
>>> +
>>> +enum {
>>> + PCI_ACCESS_READ,
>>> + PCI_ACCESS_WRITE,
>>> +};
>>
>>> +static int rcar_pcie_map_irq(const struct pci_dev *dev, u8 slot, u8
> pin)
>>> +{
>>> + struct rcar_pcie *pcie = sys_to_pcie(dev->bus->sysdata);
>>> + return pcie->irq;
>>> +}
>>> +
>>> +static void __init rcar_pcie_enable(struct rcar_pcie *pcie)
>>> +{
>>> + struct hw_pci hw;
>>> +
>>> + memset(&hw, 0, sizeof(hw));
>>> +
>>> + hw.nr_controllers = 1;
>>> + hw.private_data = (void **)&pcie;
>>> + hw.setup = rcar_pcie_setup,
>>> + hw.map_irq = rcar_pcie_map_irq,
>>> + hw.ops = &rcar_pcie_ops,
>>> +
>>> + pci_common_init(&hw);
>>> +}
>>> +
>>> +static int __init phy_wait_for_ack(struct rcar_pcie *pcie)
>>> +{
>>> + unsigned int timeout = 100;
>>> +
>>> + while (timeout--) {
>>> + if (pci_read_reg(pcie, H1_PCIEPHYADRR) & PHY_ACK)
>>> + return 0;
>>> +
>>> + udelay(100);
>>> + }
>>> +
>>> + dev_err(pcie->dev, "Access to PCIe phy timed out\n");
>>> +
>>> + return -ETIMEDOUT;
>>> +}
>>
>> Could this be done with some sort of sleep, instead of having
>> to keep delaying? How long is the average wait for pci to finish
>> a write?
> I haven't measured how long, but yes, I can use mdelay instead.
How about something that sleeps?
Does the host have a completion IRQ you could sleep on?
>>> +
>>> +static void __init phy_write_reg(struct rcar_pcie *pcie,
>>> + unsigned int rate, unsigned int addr,
>>> + unsigned int lane, unsigned int data)
>>> +{
>>> + unsigned long phyaddr;
>>> +
>>> + phyaddr = WRITE_CMD |
>>> + ((rate & 1) << RATE_POS) |
>>> + ((lane & 0xf) << LANE_POS) |
>>> + ((addr & 0xff) << ADR_POS);
>>> +
>>> + /* Set write data */
>>> + pci_write_reg(pcie, data, H1_PCIEPHYDOUTR);
>>> + pci_write_reg(pcie, phyaddr, H1_PCIEPHYADRR);
>>> +
>>> + /* Ignore errors as they will be dealt with if the data link is
> down */
>>> + phy_wait_for_ack(pcie);
>>> +
>>> + /* Clear command */
>>> + pci_write_reg(pcie, 0, H1_PCIEPHYDOUTR);
>>> + pci_write_reg(pcie, 0, H1_PCIEPHYADRR);
>>> +
>>> + /* Ignore errors as they will be dealt with if the data link is
> down */
>>> + phy_wait_for_ack(pcie);
>>> +}
>>> +
>>>
>>
>>> +static int __init rcar_pcie_wait_for_dl(struct rcar_pcie *pcie)
>>> +{
>>> + unsigned int timeout = 100;
>>> +
>>> + while (timeout--) {
>>> + if ((pci_read_reg(pcie, PCIETSTR) & DATA_LINK_ACTIVE))
>>> + return 0;
>>> +
>>> + udelay(100);
>>> + }
>>> +
>>> + return -ETIMEDOUT;
>>> +}
>>
>> Same comments as for previous delay loop
>>
>>
>>> +static void __init rcar_pcie_hw_init(struct rcar_pcie *pcie)
>>> +{
>>> + /* Initialise R-Car H1 PHY & wait for it to be ready */
>>> + if (pcie->chip = RCAR_H1)
>>> + if (rcar_pcie_phy_init_rcar_h1(pcie))
>>> + return;
>>> +
>>> + /* Begin initialization */
>>> + pci_write_reg(pcie, 0, PCIETCTLR);
>>> +
>>> + /* Set mode */
>>> + pci_write_reg(pcie, 1, PCIEMSR);
>>> +
>>> + /*
>>> + * For target transfers, setup a single 64-bit 4GB mapping at
> address
>>> + * 0. The hardware can only map memory that starts on a power of
> two
>>> + * boundary, and size is power of 2, so best to ignore it.
>>> + */
>>> + pci_write_reg(pcie, 0, PCIEPRAR(0));
>>> + pci_write_reg(pcie, 0, PCIELAR(0));
>>> + pci_write_reg(pcie, 0xfffffff0UL | LAM_PREFETCH |
>>> + LAM_64BIT | LAR_ENABLE, PCIELAMR(0));
>>> + pci_write_reg(pcie, 0, PCIELAR(1));
>>> + pci_write_reg(pcie, 0, PCIEPRAR(1));
>>> + pci_write_reg(pcie, 0, PCIELAMR(1));
>>> +
>>> + /*
>>> + * Initial header for port config space is type 1, set the device
>>> + * class to match. Hardware takes care of propagating the IDSETR
>>> + * settings, so there is no need to bother with a quirk.
>>> + */
>>> + pci_write_reg(pcie, PCI_CLASS_BRIDGE_PCI << 16, IDSETR1);
>>> +
>>> + /*
>>> + * Setup Secondary Bus Number & Subordinate Bus Number, even
> though
>>> + * they aren't used, to avoid bridge being detected as broken.
>>> + */
>>> + rcar_rmw32(pcie, RCONF(PCI_SECONDARY_BUS), 0xff, 1);
>>> + rcar_rmw32(pcie, RCONF(PCI_SUBORDINATE_BUS), 0xff, 1);
>>> +
>>> + /* Initialize default capabilities. */
>>> + rcar_rmw32(pcie, REXPCAP(0), 0, PCI_CAP_ID_EXP);
>>> + rcar_rmw32(pcie, REXPCAP(PCI_EXP_FLAGS),
>>> + PCI_EXP_FLAGS_TYPE, PCI_EXP_TYPE_ROOT_PORT << 4);
>>> + rcar_rmw32(pcie, RCONF(PCI_HEADER_TYPE), 0x7f,
>>> + PCI_HEADER_TYPE_BRIDGE);
>>> +
>>> + /* Enable data link layer active state reporting */
>>> + rcar_rmw32(pcie, REXPCAP(PCI_EXP_LNKCAP), 0,
> PCI_EXP_LNKCAP_DLLLARC);
>>> +
>>> + /* Write out the physical slot number = 0 */
>>> + rcar_rmw32(pcie, REXPCAP(PCI_EXP_SLTCAP), PCI_EXP_SLTCAP_PSN, 0);
>>> +
>>> + /* Set the completion timer timeout to the maximum 50ms. */
>>> + rcar_rmw32(pcie, TLCTLR+1, 0x3f, 50);
>>> +
>>> + /* Terminate list of capabilities (Next Capability Offset=0) */
>>> + rcar_rmw32(pcie, RVCCAP(0), 0xfff0, 0);
>>> +
>>> + /* Enable MAC data scrambling. */
>>> + rcar_rmw32(pcie, MACCTLR, SCRAMBLE_DISABLE, 0);
>>> +
>>> + /* Finish initialization - establish a PCI Express link */
>>> + pci_write_reg(pcie, CFINIT, PCIETCTLR);
>>> +
>>> + /* This will timeout if we don't have a link. */
>>> + pcie->haslink = !rcar_pcie_wait_for_dl(pcie);
>>> +
>>> + /* Enable INTx interrupts */
>>> + rcar_rmw32(pcie, RCONF(PCI_INTERRUPT_LINE), 0xff, 0);
>>> + rcar_rmw32(pcie, RCONF(PCI_INTERRUPT_PIN), 0xff, 1);
>>> + rcar_rmw32(pcie, PCIEINTXR, 0, 0xF << 8);
>>> +
>>> + /* Enable slave Bus Mastering */
>>> + rcar_rmw32(pcie, RCONF(PCI_STATUS), PCI_STATUS_DEVSEL_MASK,
>>> + PCI_COMMAND_IO | PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER |
>>> + PCI_STATUS_CAP_LIST | PCI_STATUS_DEVSEL_FAST);
>>> +
>>> + wmb();
>>> +}
>>> +
>>> +static int rcar_pcie_clocks_get(struct rcar_pcie *pcie)
>>> +{
>>> + int err = 0;
>>> +
>>> + pcie->clk = clk_get(pcie->dev, NULL);
>>> + if (IS_ERR(pcie->clk))
>>> + err = PTR_ERR(pcie->clk);
>>> + else
>>> + clk_enable(pcie->clk);
>>> +
>>> + return err;
>>> +}
>>
>> Shouldn't you be using pm_runtime for this?
> Yes, I'll fix this
Ta. I'm still trying to fix pm_runtime issues with devicetree.
>>> +static void rcar_pcie_clocks_put(struct rcar_pcie *pcie)
>>> +{
>>> + clk_put(pcie->clk);
>>> +}
>>> +
>>> +struct rcar_pcie_errs {
>>> + int bit;
>>> + const char *description;
>>> +};
>>> +
>>> +static int __init rcar_pcie_get_resources(struct platform_device
> *pdev,
>>> + struct rcar_pcie *pcie)
>>> +{
>>> + struct resource *res;
>>> + int i;
>>> + int err;
>>> +
>>> + res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
>>> +
>>> + i = platform_get_irq(pdev, 0);
>>> + if (!res || i < 0) {
>>> + dev_err(pcie->dev, "cannot get platform resources\n");
>>> + return -ENOENT;
>>> + }
>>> + pcie->irq = i;
>>> +
>>> + err = rcar_pcie_clocks_get(pcie);
>>> + if (err) {
>>> + dev_err(&pdev->dev, "failed to get clocks: %d\n", err);
>>> + return err;
>>> + }
>>> +
>>> + pcie->base = devm_request_and_ioremap(&pdev->dev, res);
>>> + if (!pcie->base) {
>>> + dev_err(&pdev->dev, "failed to map PCIe registers: %d\n", err);
>>> + err = -ENOMEM;
>>> + goto err_map_reg;
>>> + }
>>> +
>>> + return 0;
>>> +
>>> +err_map_reg:
>>> + rcar_pcie_clocks_put(pcie);
>>> +
>>> + return err;
>>> +}
>>> +
>>> +static struct platform_device_id rcar_pcie_id_table[] = {
>>> + { "r8a7779-pcie", RCAR_H1 },
>>> + { "r8a7790-pcie", RCAR_GENERIC },
>>> + { "r8a7791-pcie", RCAR_GENERIC },
>>> + {},
>>> +};
>>> +MODULE_DEVICE_TABLE(platform, rcar_pcie_id_table);
>>
>> Really, are you still going to submit drivers without OF bindings?
>>
>> NAK!
> I totally agree, hence my comment in the cover email:
> "This is RFC as there is some work required for DT support."
> Perhaps I should have marked each patch as RFC.
Actually, it could be applied as-is, but I would prefer DT.
I didn't notice, I only reviewed this bet, so yes marking the
lot as RFC would have been better.
>>> +static int __init rcar_pcie_probe(struct platform_device *pdev)
>>> +{
>>> + struct rcar_pcie *pcie;
>>> + struct resource *res;
>>> + unsigned int data;
>>> + int i, err;
>>> +
>>> + pcie = devm_kzalloc(&pdev->dev, sizeof(*pcie), GFP_KERNEL);
>>> + if (!pcie)
>>> + return -ENOMEM;
>>> +
>>> + pcie->dev = &pdev->dev;
>>> + pcie->chip = pdev->id_entry->driver_data;
>>> +
>>> + /* Get resources */
>>> + err = rcar_pcie_get_resources(pdev, pcie);
>>> + if (err < 0) {
>>> + dev_err(&pdev->dev, "failed to request resources: %d\n", err);
>>> + return err;
>>> + }
>>> +
>>> + /* Get the I/O and memory ranges */
>>> + for (i = 0; i < NR_PCI_RESOURCES; i++) {
>>> + res = platform_get_resource(pdev, IORESOURCE_MEM, i+1);
>>> + if (!res) {
>>> + dev_err(&pdev->dev, "cannot get MEM%d resources\n", i);
>>> + return -ENOENT;
>>> + }
>>> + pcie->res[i] = res;
>>> + }
>>> +
>>> + rcar_pcie_hw_init(pcie);
>>> +
>>> + if (!pcie->haslink) {
>>> + dev_info(&pdev->dev, "PCI: PCIe link down\n");
>>> + return 0;
>>> + }
>>> +
>>> + data = pci_read_reg(pcie, MACSR);
>>> + dev_info(&pdev->dev, "PCIe x%d: link up\n", (data >> 20) & 0x3f);
>>> +
>>> + rcar_pcie_enable(pcie);
>>> +
>>> + platform_set_drvdata(pdev, pcie);
>>> + return 0;
>>> +}
>>> +
>>> +static struct platform_driver rcar_pcie_driver = {
>>> + .probe = rcar_pcie_probe,
>>> + .driver = {
>>> + .name = DRV_NAME,
>>> + .owner = THIS_MODULE,
>>> + },
>>> + .id_table = rcar_pcie_id_table,
>>> +};
>>> +
>>> +module_platform_driver(rcar_pcie_driver);
>>> +
>>> +MODULE_AUTHOR("Phil Edworthy <phil.edworthy@renesas.com>");
>>> +MODULE_DESCRIPTION("Renesas R-Car PCIe driver");
>>> +MODULE_LICENSE("GPLv2");
>>> diff --git a/drivers/pci/host/pcie-rcar.h
> b/drivers/pci/host/pcie-rcar.h
>>> new file mode 100644
>>> index 0000000..a6b407f
>>> --- /dev/null
>>> +++ b/drivers/pci/host/pcie-rcar.h
>>> @@ -0,0 +1,84 @@
>>> +/*
>>> + * PCI Express definitions for Renesas R-Car SoCs
>>> + */
>>> +#ifndef __PCI_RCAR_H
>>> +#define __PCI_RCAR_H
>>> +
>>> +#define PCI_DEVICE_ID_RENESAS_RCAR 0x0018
>>
>> should this go into pci ids header?
> This is not used so I'll remove it.
>
>>> +#define PCIECAR 0x000010
>>> +#define PCIECCTLR 0x000018
>>> +#define CONFIG_SEND_ENABLE (1 << 31)
>>> +#define TYPE0 (0 << 8)
>>> +#define TYPE1 (1 << 8)
>>> +#define PCIECDR 0x000020
>>> +#define PCIEMSR 0x000028
>>> +#define PCIEINTXR 0x000400
>>> +#define PCIEPHYSR 0x0007f0
>>> +
>>> +/* Transfer control */
>>> +#define PCIETCTLR 0x02000
>>> +#define CFINIT 1
>>> +#define PCIETSTR 0x02004
>>> +#define DATA_LINK_ACTIVE 1
>>> +#define PCIEINTR 0x02008
>>> +#define PCIEINTER 0x0200c
>>> +#define PCIEERRFR 0x02020
>>> +#define UNSUPPORTED_REQUEST (1 << 4)
>>> +#define PCIEERRFER 0x02024
>>> +#define PCIEERRFR2 0x02028
>>> +#define PCIEPMSR 0x02034
>>> +#define PCIEPMSCIER 0x02038
>>> +#define PCIEMSIFR 0x02044
>>> +
>>> +/* root port address */
>>> +#define PCIEPRAR(x) (0x02080 + ((x) * 0x4))
>>> +
>>> +/* local address reg & mask */
>>> +#define PCIELAR(x) (0x02200 + ((x) * 0x20))
>>> +#define PCIELAMR(x) (0x02208 + ((x) * 0x20))
>>> +#define LAM_PMIOLAMnB3 (1 << 3)
>>> +#define LAM_PMIOLAMnB2 (1 << 2)
>>> +#define LAM_PREFETCH (1 << 3)
>>> +#define LAM_64BIT (1 << 2)
>>> +#define LAR_ENABLE (1 << 1)
>>> +
>>> +/* PCIe address reg & mask */
>>> +#define PCIEPARL(x) (0x03400 + ((x) * 0x20))
>>> +#define PCIEPARH(x) (0x03404 + ((x) * 0x20))
>>> +#define PCIEPAMR(x) (0x03408 + ((x) * 0x20))
>>> +#define PCIEPTCTLR(x) (0x0340c + ((x) * 0x20))
>>> +#define PAR_ENABLE (1 << 31)
>>> +#define IO_SPACE (1 << 8)
>>> +
>>> +/* Configuration */
>>> +#define PCICONF(x) (0x010000 + ((x) * 0x4))
>>> +#define PMCAP(x) (0x010040 + ((x) * 0x4))
>>> +#define MSICAP(x) (0x010050 + ((x) * 0x4))
>>> +#define EXPCAP(x) (0x010070 + ((x) * 0x4))
>>> +#define VCCAP(x) (0x010100 + ((x) * 0x4))
>>> +#define SERNUMCAP(x) (0x0101b0 + ((x) * 0x4))
>>> +
>>> +/* link layer */
>>> +#define IDSETR0 0x011000
>>> +#define IDSETR1 0x011004
>>> +#define SUBIDSETR 0x011024
>>> +#define DSERSETR0 0x01102c
>>> +#define DSERSETR1 0x011030
>>> +#define TLCTLR 0x011048
>>> +#define MACSR 0x011054
>>> +#define MACCTLR 0x011058
>>> +#define SCRAMBLE_DISABLE (1 << 27)
>>> +
>>> +/* R-Car H1 PHY */
>>> +#define H1_PCIEPHYCTLR 0x040008
>>> +#define H1_PCIEPHYADRR 0x04000c
>>> +#define WRITE_CMD (1 << 16)
>>> +#define PHY_ACK (1 << 24)
>>> +#define RATE_POS 12
>>> +#define LANE_POS 8
>>> +#define ADR_POS 0
>>> +#define H1_PCIEPHYDOUTR 0x040014
>>> +#define H1_PCIEPHYSR 0x040018
>>> +
>>> +#endif /* __PCI_RCAR_H */
>>>
>>
>>
>> --
>> Ben Dooks http://www.codethink.co.uk/
>> Senior Engineer Codethink - Providing Genius
>
> Thanks
> Phil
> --
> To unsubscribe from this list: send the line "unsubscribe linux-sh" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
>
--
Ben Dooks http://www.codethink.co.uk/
Senior Engineer Codethink - Providing Genius
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH 1/5] PCI: host: Add Renesas R-Car PCIe driver
2014-02-26 17:19 ` Ben Dooks
@ 2014-02-26 17:34 ` Phil.Edworthy
0 siblings, 0 replies; 10+ messages in thread
From: Phil.Edworthy @ 2014-02-26 17:34 UTC (permalink / raw)
To: Ben Dooks
Cc: Bjorn Helgaas, Simon Horman, linux-pci, linux-sh, Magnus Damm,
Valentine Barshak
Hi Ben,
On 26/02/2014 17:19, Ben Dooks wrote:
> On 26/02/14 17:13, Phil.Edworthy@renesas.com wrote:
> > Hi Ben,
> >
> > Thanks for your comments.
> >
> > On 26/02/2014 16:33, Ben Dooks wrote:
> >> On 26/02/14 16:08, Phil Edworthy wrote:
> >>> This PCIe Host driver currently does not support MSI, so cards
> >>> fall back to INTx interrupts.
> >>>
> >>> Signed-off-by: Phil Edworthy <phil.edworthy@renesas.com>
> >>
> >>> + bool "Renesas R-Car PCIe controller"
> >>> + depends on ARM && (ARCH_R8A7790 || ARCH_R8A7791 || COMPILE_TEST)
> >>> + help
> >>> + Say Y here if you want PCIe controller support on R-Car Gen2
> > SoCs.
> >>> +
> >>> endmenu
> >>> diff --git a/drivers/pci/host/Makefile b/drivers/pci/host/Makefile
> >>> index 13fb333..19946f9 100644
> >>> --- a/drivers/pci/host/Makefile
> >>> +++ b/drivers/pci/host/Makefile
> >>> @@ -4,3 +4,4 @@ obj-$(CONFIG_PCI_IMX6) += pci-imx6.o
> >>> obj-$(CONFIG_PCI_MVEBU) += pci-mvebu.o
> >>> obj-$(CONFIG_PCI_TEGRA) += pci-tegra.o
> >>> obj-$(CONFIG_PCI_RCAR_GEN2) += pci-rcar-gen2.o
> >>> +obj-$(CONFIG_PCI_RCAR_GEN2_PCIE) += pcie-rcar.o
> >>> diff --git a/drivers/pci/host/pcie-rcar.c
> > b/drivers/pci/host/pcie-rcar.c
> >>> new file mode 100644
> >>> index 0000000..d9a315f
> >>> --- /dev/null
> >>> +++ b/drivers/pci/host/pcie-rcar.c
> >>> @@ -0,0 +1,614 @@
> >>> +/*
> >>> + * PCIe driver for Renesas R-Car SoCs
> >>> + * Copyright (C) 2013 Renesas Electronics Europe Ltd
> >>> + *
> >>> + * Based on:
> >>> + * arch/sh/drivers/pci/pcie-sh7786.c
> >>> + * arch/sh/drivers/pci/ops-sh7786.c
> >>> + * Copyright (C) 2009 - 2011 Paul Mundt
> >>> + *
> >>> + * This file is licensed under the terms of the GNU General Public
> >>> + * License version 2. This program is licensed "as is" without any
> >>> + * warranty of any kind, whether express or implied.
> >>> + */
> >>> +
> >>> +#include <linux/clk.h>
> >>> +#include <linux/delay.h>
> >>> +#include <linux/interrupt.h>
> >>> +#include <linux/module.h>
> >>> +#include <linux/kernel.h>
> >>> +#include <linux/of_address.h>
> >>> +#include <linux/of_irq.h>
> >>> +#include <linux/of_pci.h>
> >>> +#include <linux/of_platform.h>
> >>> +#include <linux/pci.h>
> >>> +#include <linux/platform_device.h>
> >>> +#include <linux/slab.h>
> >>> +#include "pcie-rcar.h"
> >>> +
> >>> +#define DRV_NAME "rcar-pcie"
> >>> +
> >>> +enum chip_id {
> >>> + RCAR_GENERIC,
> >>> + RCAR_H1,
> >>> +};
> >>> +
> >>> +#define RCONF(x) (PCICONF(0)+(x))
> >>> +#define REXPCAP(x) (EXPCAP(0)+(x))
> >>> +#define RVCCAP(x) (VCCAP(0)+(x))
> >>> +
> >>> +#define PCIE_CONF_BUS(b) (((b) & 0xff) << 24)
> >>> +#define PCIE_CONF_DEV(d) (((d) & 0x1f) << 19)
> >>> +#define PCIE_CONF_FUNC(f) (((f) & 0x7) << 16)
> >>> +
> >>> +#define NR_PCI_RESOURCES 4
> >>> +
> >>> +/* Structure representing the PCIe interface */
> >>> +struct rcar_pcie {
> >>> + struct device *dev;
> >>> + void __iomem *base;
> >>> + int irq;
> >>> + struct clk *clk;
> >>> + struct resource *res[NR_PCI_RESOURCES];
> >>> + int haslink;
> >>> + enum chip_id chip;
> >>> + u8 root_bus_nr;
> >>> +};
> >>> +
> >>> +static inline struct rcar_pcie *sys_to_pcie(struct pci_sys_data
*sys)
> >>> +{
> >>> + return sys->private_data;
> >>> +}
> >>> +
> >>> +static void
> >>> +pci_write_reg(struct rcar_pcie *pcie, unsigned long val, unsigned
> > long reg)
> >>> +{
> >>> + writel(val, pcie->base + reg);
> >>> +}
> >>
> >> Do we really need wrappers like these?
> > They were handy during development, but I guess not.
>
> Actually, not that big of a deal, ignore me on this.
>
> >>> +static unsigned long
> >>> +pci_read_reg(struct rcar_pcie *pcie, unsigned long reg)
> >>> +{
> >>> + return readl(pcie->base + reg);
> >>> +}
> >>> +
> >>> +enum {
> >>> + PCI_ACCESS_READ,
> >>> + PCI_ACCESS_WRITE,
> >>> +};
> >>
> >>> +static int rcar_pcie_map_irq(const struct pci_dev *dev, u8 slot, u8
> > pin)
> >>> +{
> >>> + struct rcar_pcie *pcie = sys_to_pcie(dev->bus->sysdata);
> >>> + return pcie->irq;
> >>> +}
> >>> +
> >>> +static void __init rcar_pcie_enable(struct rcar_pcie *pcie)
> >>> +{
> >>> + struct hw_pci hw;
> >>> +
> >>> + memset(&hw, 0, sizeof(hw));
> >>> +
> >>> + hw.nr_controllers = 1;
> >>> + hw.private_data = (void **)&pcie;
> >>> + hw.setup = rcar_pcie_setup,
> >>> + hw.map_irq = rcar_pcie_map_irq,
> >>> + hw.ops = &rcar_pcie_ops,
> >>> +
> >>> + pci_common_init(&hw);
> >>> +}
> >>> +
> >>> +static int __init phy_wait_for_ack(struct rcar_pcie *pcie)
> >>> +{
> >>> + unsigned int timeout = 100;
> >>> +
> >>> + while (timeout--) {
> >>> + if (pci_read_reg(pcie, H1_PCIEPHYADRR) & PHY_ACK)
> >>> + return 0;
> >>> +
> >>> + udelay(100);
> >>> + }
> >>> +
> >>> + dev_err(pcie->dev, "Access to PCIe phy timed out\n");
> >>> +
> >>> + return -ETIMEDOUT;
> >>> +}
> >>
> >> Could this be done with some sort of sleep, instead of having
> >> to keep delaying? How long is the average wait for pci to finish
> >> a write?
> > I haven't measured how long, but yes, I can use mdelay instead.
>
> How about something that sleeps?
> Does the host have a completion IRQ you could sleep on?
Not that I can see... The delay in phy_wait_for_ack() should be pretty
small (and only applies to R-Car H1), so maybe we can live with a udelay
there. For the other waits we can use msleep.
> >>> +
> >>> +static void __init phy_write_reg(struct rcar_pcie *pcie,
> >>> + unsigned int rate, unsigned int addr,
> >>> + unsigned int lane, unsigned int data)
> >>> +{
> >>> + unsigned long phyaddr;
> >>> +
> >>> + phyaddr = WRITE_CMD |
> >>> + ((rate & 1) << RATE_POS) |
> >>> + ((lane & 0xf) << LANE_POS) |
> >>> + ((addr & 0xff) << ADR_POS);
> >>> +
> >>> + /* Set write data */
> >>> + pci_write_reg(pcie, data, H1_PCIEPHYDOUTR);
> >>> + pci_write_reg(pcie, phyaddr, H1_PCIEPHYADRR);
> >>> +
> >>> + /* Ignore errors as they will be dealt with if the data link is
> > down */
> >>> + phy_wait_for_ack(pcie);
> >>> +
> >>> + /* Clear command */
> >>> + pci_write_reg(pcie, 0, H1_PCIEPHYDOUTR);
> >>> + pci_write_reg(pcie, 0, H1_PCIEPHYADRR);
> >>> +
> >>> + /* Ignore errors as they will be dealt with if the data link is
> > down */
> >>> + phy_wait_for_ack(pcie);
> >>> +}
> >>> +
> >>>
> >>
> >>> +static int __init rcar_pcie_wait_for_dl(struct rcar_pcie *pcie)
> >>> +{
> >>> + unsigned int timeout = 100;
> >>> +
> >>> + while (timeout--) {
> >>> + if ((pci_read_reg(pcie, PCIETSTR) & DATA_LINK_ACTIVE))
> >>> + return 0;
> >>> +
> >>> + udelay(100);
> >>> + }
> >>> +
> >>> + return -ETIMEDOUT;
> >>> +}
> >>
> >> Same comments as for previous delay loop
> >>
> >>
> >>> +static void __init rcar_pcie_hw_init(struct rcar_pcie *pcie)
> >>> +{
> >>> + /* Initialise R-Car H1 PHY & wait for it to be ready */
> >>> + if (pcie->chip = RCAR_H1)
> >>> + if (rcar_pcie_phy_init_rcar_h1(pcie))
> >>> + return;
> >>> +
> >>> + /* Begin initialization */
> >>> + pci_write_reg(pcie, 0, PCIETCTLR);
> >>> +
> >>> + /* Set mode */
> >>> + pci_write_reg(pcie, 1, PCIEMSR);
> >>> +
> >>> + /*
> >>> + * For target transfers, setup a single 64-bit 4GB mapping at
> > address
> >>> + * 0. The hardware can only map memory that starts on a power of
> > two
> >>> + * boundary, and size is power of 2, so best to ignore it.
> >>> + */
> >>> + pci_write_reg(pcie, 0, PCIEPRAR(0));
> >>> + pci_write_reg(pcie, 0, PCIELAR(0));
> >>> + pci_write_reg(pcie, 0xfffffff0UL | LAM_PREFETCH |
> >>> + LAM_64BIT | LAR_ENABLE, PCIELAMR(0));
> >>> + pci_write_reg(pcie, 0, PCIELAR(1));
> >>> + pci_write_reg(pcie, 0, PCIEPRAR(1));
> >>> + pci_write_reg(pcie, 0, PCIELAMR(1));
> >>> +
> >>> + /*
> >>> + * Initial header for port config space is type 1, set the
device
> >>> + * class to match. Hardware takes care of propagating the IDSETR
> >>> + * settings, so there is no need to bother with a quirk.
> >>> + */
> >>> + pci_write_reg(pcie, PCI_CLASS_BRIDGE_PCI << 16, IDSETR1);
> >>> +
> >>> + /*
> >>> + * Setup Secondary Bus Number & Subordinate Bus Number, even
> > though
> >>> + * they aren't used, to avoid bridge being detected as broken.
> >>> + */
> >>> + rcar_rmw32(pcie, RCONF(PCI_SECONDARY_BUS), 0xff, 1);
> >>> + rcar_rmw32(pcie, RCONF(PCI_SUBORDINATE_BUS), 0xff, 1);
> >>> +
> >>> + /* Initialize default capabilities. */
> >>> + rcar_rmw32(pcie, REXPCAP(0), 0, PCI_CAP_ID_EXP);
> >>> + rcar_rmw32(pcie, REXPCAP(PCI_EXP_FLAGS),
> >>> + PCI_EXP_FLAGS_TYPE, PCI_EXP_TYPE_ROOT_PORT << 4);
> >>> + rcar_rmw32(pcie, RCONF(PCI_HEADER_TYPE), 0x7f,
> >>> + PCI_HEADER_TYPE_BRIDGE);
> >>> +
> >>> + /* Enable data link layer active state reporting */
> >>> + rcar_rmw32(pcie, REXPCAP(PCI_EXP_LNKCAP), 0,
> > PCI_EXP_LNKCAP_DLLLARC);
> >>> +
> >>> + /* Write out the physical slot number = 0 */
> >>> + rcar_rmw32(pcie, REXPCAP(PCI_EXP_SLTCAP), PCI_EXP_SLTCAP_PSN,
0);
> >>> +
> >>> + /* Set the completion timer timeout to the maximum 50ms. */
> >>> + rcar_rmw32(pcie, TLCTLR+1, 0x3f, 50);
> >>> +
> >>> + /* Terminate list of capabilities (Next Capability Offset=0) */
> >>> + rcar_rmw32(pcie, RVCCAP(0), 0xfff0, 0);
> >>> +
> >>> + /* Enable MAC data scrambling. */
> >>> + rcar_rmw32(pcie, MACCTLR, SCRAMBLE_DISABLE, 0);
> >>> +
> >>> + /* Finish initialization - establish a PCI Express link */
> >>> + pci_write_reg(pcie, CFINIT, PCIETCTLR);
> >>> +
> >>> + /* This will timeout if we don't have a link. */
> >>> + pcie->haslink = !rcar_pcie_wait_for_dl(pcie);
> >>> +
> >>> + /* Enable INTx interrupts */
> >>> + rcar_rmw32(pcie, RCONF(PCI_INTERRUPT_LINE), 0xff, 0);
> >>> + rcar_rmw32(pcie, RCONF(PCI_INTERRUPT_PIN), 0xff, 1);
> >>> + rcar_rmw32(pcie, PCIEINTXR, 0, 0xF << 8);
> >>> +
> >>> + /* Enable slave Bus Mastering */
> >>> + rcar_rmw32(pcie, RCONF(PCI_STATUS), PCI_STATUS_DEVSEL_MASK,
> >>> + PCI_COMMAND_IO | PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER |
> >>> + PCI_STATUS_CAP_LIST | PCI_STATUS_DEVSEL_FAST);
> >>> +
> >>> + wmb();
> >>> +}
> >>> +
> >>> +static int rcar_pcie_clocks_get(struct rcar_pcie *pcie)
> >>> +{
> >>> + int err = 0;
> >>> +
> >>> + pcie->clk = clk_get(pcie->dev, NULL);
> >>> + if (IS_ERR(pcie->clk))
> >>> + err = PTR_ERR(pcie->clk);
> >>> + else
> >>> + clk_enable(pcie->clk);
> >>> +
> >>> + return err;
> >>> +}
> >>
> >> Shouldn't you be using pm_runtime for this?
> > Yes, I'll fix this
>
> Ta. I'm still trying to fix pm_runtime issues with devicetree.
>
> >>> +static void rcar_pcie_clocks_put(struct rcar_pcie *pcie)
> >>> +{
> >>> + clk_put(pcie->clk);
> >>> +}
> >>> +
> >>> +struct rcar_pcie_errs {
> >>> + int bit;
> >>> + const char *description;
> >>> +};
> >>> +
> >>> +static int __init rcar_pcie_get_resources(struct platform_device
> > *pdev,
> >>> + struct rcar_pcie *pcie)
> >>> +{
> >>> + struct resource *res;
> >>> + int i;
> >>> + int err;
> >>> +
> >>> + res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> >>> +
> >>> + i = platform_get_irq(pdev, 0);
> >>> + if (!res || i < 0) {
> >>> + dev_err(pcie->dev, "cannot get platform resources\n");
> >>> + return -ENOENT;
> >>> + }
> >>> + pcie->irq = i;
> >>> +
> >>> + err = rcar_pcie_clocks_get(pcie);
> >>> + if (err) {
> >>> + dev_err(&pdev->dev, "failed to get clocks: %d\n", err);
> >>> + return err;
> >>> + }
> >>> +
> >>> + pcie->base = devm_request_and_ioremap(&pdev->dev, res);
> >>> + if (!pcie->base) {
> >>> + dev_err(&pdev->dev, "failed to map PCIe registers: %d\n",
err);
> >>> + err = -ENOMEM;
> >>> + goto err_map_reg;
> >>> + }
> >>> +
> >>> + return 0;
> >>> +
> >>> +err_map_reg:
> >>> + rcar_pcie_clocks_put(pcie);
> >>> +
> >>> + return err;
> >>> +}
> >>> +
> >>> +static struct platform_device_id rcar_pcie_id_table[] = {
> >>> + { "r8a7779-pcie", RCAR_H1 },
> >>> + { "r8a7790-pcie", RCAR_GENERIC },
> >>> + { "r8a7791-pcie", RCAR_GENERIC },
> >>> + {},
> >>> +};
> >>> +MODULE_DEVICE_TABLE(platform, rcar_pcie_id_table);
> >>
> >> Really, are you still going to submit drivers without OF bindings?
> >>
> >> NAK!
> > I totally agree, hence my comment in the cover email:
> > "This is RFC as there is some work required for DT support."
> > Perhaps I should have marked each patch as RFC.
>
> Actually, it could be applied as-is, but I would prefer DT.
>
> I didn't notice, I only reviewed this bet, so yes marking the
> lot as RFC would have been better.
I'll try to remember next time!
> >>> +static int __init rcar_pcie_probe(struct platform_device *pdev)
> >>> +{
> >>> + struct rcar_pcie *pcie;
> >>> + struct resource *res;
> >>> + unsigned int data;
> >>> + int i, err;
> >>> +
> >>> + pcie = devm_kzalloc(&pdev->dev, sizeof(*pcie), GFP_KERNEL);
> >>> + if (!pcie)
> >>> + return -ENOMEM;
> >>> +
> >>> + pcie->dev = &pdev->dev;
> >>> + pcie->chip = pdev->id_entry->driver_data;
> >>> +
> >>> + /* Get resources */
> >>> + err = rcar_pcie_get_resources(pdev, pcie);
> >>> + if (err < 0) {
> >>> + dev_err(&pdev->dev, "failed to request resources: %d\n",
err);
> >>> + return err;
> >>> + }
> >>> +
> >>> + /* Get the I/O and memory ranges */
> >>> + for (i = 0; i < NR_PCI_RESOURCES; i++) {
> >>> + res = platform_get_resource(pdev, IORESOURCE_MEM, i+1);
> >>> + if (!res) {
> >>> + dev_err(&pdev->dev, "cannot get MEM%d resources\n", i);
> >>> + return -ENOENT;
> >>> + }
> >>> + pcie->res[i] = res;
> >>> + }
> >>> +
> >>> + rcar_pcie_hw_init(pcie);
> >>> +
> >>> + if (!pcie->haslink) {
> >>> + dev_info(&pdev->dev, "PCI: PCIe link down\n");
> >>> + return 0;
> >>> + }
> >>> +
> >>> + data = pci_read_reg(pcie, MACSR);
> >>> + dev_info(&pdev->dev, "PCIe x%d: link up\n", (data >> 20) &
0x3f);
> >>> +
> >>> + rcar_pcie_enable(pcie);
> >>> +
> >>> + platform_set_drvdata(pdev, pcie);
> >>> + return 0;
> >>> +}
> >>> +
> >>> +static struct platform_driver rcar_pcie_driver = {
> >>> + .probe = rcar_pcie_probe,
> >>> + .driver = {
> >>> + .name = DRV_NAME,
> >>> + .owner = THIS_MODULE,
> >>> + },
> >>> + .id_table = rcar_pcie_id_table,
> >>> +};
> >>> +
> >>> +module_platform_driver(rcar_pcie_driver);
> >>> +
> >>> +MODULE_AUTHOR("Phil Edworthy <phil.edworthy@renesas.com>");
> >>> +MODULE_DESCRIPTION("Renesas R-Car PCIe driver");
> >>> +MODULE_LICENSE("GPLv2");
> >>> diff --git a/drivers/pci/host/pcie-rcar.h
> > b/drivers/pci/host/pcie-rcar.h
> >>> new file mode 100644
> >>> index 0000000..a6b407f
> >>> --- /dev/null
> >>> +++ b/drivers/pci/host/pcie-rcar.h
> >>> @@ -0,0 +1,84 @@
> >>> +/*
> >>> + * PCI Express definitions for Renesas R-Car SoCs
> >>> + */
> >>> +#ifndef __PCI_RCAR_H
> >>> +#define __PCI_RCAR_H
> >>> +
> >>> +#define PCI_DEVICE_ID_RENESAS_RCAR 0x0018
> >>
> >> should this go into pci ids header?
> > This is not used so I'll remove it.
> >
> >>> +#define PCIECAR 0x000010
> >>> +#define PCIECCTLR 0x000018
> >>> +#define CONFIG_SEND_ENABLE (1 << 31)
> >>> +#define TYPE0 (0 << 8)
> >>> +#define TYPE1 (1 << 8)
> >>> +#define PCIECDR 0x000020
> >>> +#define PCIEMSR 0x000028
> >>> +#define PCIEINTXR 0x000400
> >>> +#define PCIEPHYSR 0x0007f0
> >>> +
> >>> +/* Transfer control */
> >>> +#define PCIETCTLR 0x02000
> >>> +#define CFINIT 1
> >>> +#define PCIETSTR 0x02004
> >>> +#define DATA_LINK_ACTIVE 1
> >>> +#define PCIEINTR 0x02008
> >>> +#define PCIEINTER 0x0200c
> >>> +#define PCIEERRFR 0x02020
> >>> +#define UNSUPPORTED_REQUEST (1 << 4)
> >>> +#define PCIEERRFER 0x02024
> >>> +#define PCIEERRFR2 0x02028
> >>> +#define PCIEPMSR 0x02034
> >>> +#define PCIEPMSCIER 0x02038
> >>> +#define PCIEMSIFR 0x02044
> >>> +
> >>> +/* root port address */
> >>> +#define PCIEPRAR(x) (0x02080 + ((x) * 0x4))
> >>> +
> >>> +/* local address reg & mask */
> >>> +#define PCIELAR(x) (0x02200 + ((x) * 0x20))
> >>> +#define PCIELAMR(x) (0x02208 + ((x) * 0x20))
> >>> +#define LAM_PMIOLAMnB3 (1 << 3)
> >>> +#define LAM_PMIOLAMnB2 (1 << 2)
> >>> +#define LAM_PREFETCH (1 << 3)
> >>> +#define LAM_64BIT (1 << 2)
> >>> +#define LAR_ENABLE (1 << 1)
> >>> +
> >>> +/* PCIe address reg & mask */
> >>> +#define PCIEPARL(x) (0x03400 + ((x) * 0x20))
> >>> +#define PCIEPARH(x) (0x03404 + ((x) * 0x20))
> >>> +#define PCIEPAMR(x) (0x03408 + ((x) * 0x20))
> >>> +#define PCIEPTCTLR(x) (0x0340c + ((x) * 0x20))
> >>> +#define PAR_ENABLE (1 << 31)
> >>> +#define IO_SPACE (1 << 8)
> >>> +
> >>> +/* Configuration */
> >>> +#define PCICONF(x) (0x010000 + ((x) * 0x4))
> >>> +#define PMCAP(x) (0x010040 + ((x) * 0x4))
> >>> +#define MSICAP(x) (0x010050 + ((x) * 0x4))
> >>> +#define EXPCAP(x) (0x010070 + ((x) * 0x4))
> >>> +#define VCCAP(x) (0x010100 + ((x) * 0x4))
> >>> +#define SERNUMCAP(x) (0x0101b0 + ((x) * 0x4))
> >>> +
> >>> +/* link layer */
> >>> +#define IDSETR0 0x011000
> >>> +#define IDSETR1 0x011004
> >>> +#define SUBIDSETR 0x011024
> >>> +#define DSERSETR0 0x01102c
> >>> +#define DSERSETR1 0x011030
> >>> +#define TLCTLR 0x011048
> >>> +#define MACSR 0x011054
> >>> +#define MACCTLR 0x011058
> >>> +#define SCRAMBLE_DISABLE (1 << 27)
> >>> +
> >>> +/* R-Car H1 PHY */
> >>> +#define H1_PCIEPHYCTLR 0x040008
> >>> +#define H1_PCIEPHYADRR 0x04000c
> >>> +#define WRITE_CMD (1 << 16)
> >>> +#define PHY_ACK (1 << 24)
> >>> +#define RATE_POS 12
> >>> +#define LANE_POS 8
> >>> +#define ADR_POS 0
> >>> +#define H1_PCIEPHYDOUTR 0x040014
> >>> +#define H1_PCIEPHYSR 0x040018
> >>> +
> >>> +#endif /* __PCI_RCAR_H */
> >>>
> >>
> >>
> >> --
> >> Ben Dooks http://www.codethink.co.uk/
> >> Senior Engineer Codethink - Providing Genius
> >
> > Thanks
> > Phil
> > --
> > To unsubscribe from this list: send the line "unsubscribe linux-sh" in
> > the body of a message to majordomo@vger.kernel.org
> > More majordomo info at http://vger.kernel.org/majordomo-info.html
> >
>
>
> --
> Ben Dooks http://www.codethink.co.uk/
> Senior Engineer Codethink - Providing Genius
Thanks
Phil
^ permalink raw reply [flat|nested] 10+ messages in thread
end of thread, other threads:[~2014-02-26 17:34 UTC | newest]
Thread overview: 10+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2014-02-26 16:08 [PATCH 0/5 RFC] R-Car Gen2 PCIe host driver Phil Edworthy
2014-02-26 16:08 ` [PATCH 1/5] PCI: host: Add Renesas R-Car PCIe driver Phil Edworthy
2014-02-26 16:34 ` Ben Dooks
2014-02-26 17:13 ` Phil.Edworthy
2014-02-26 17:19 ` Ben Dooks
2014-02-26 17:34 ` Phil.Edworthy
2014-02-26 16:08 ` [PATCH 2/5] ARM: shmobile: r8a7791: Add PCIe clock Phil Edworthy
2014-02-26 16:08 ` [PATCH 3/5] ARM: shmobile: Add PCIe resources to r8a7791 device Phil Edworthy
2014-02-26 16:08 ` [PATCH 4/5] ARM: shmobile: Add PCIe to r8a7791 device Kconfig Phil Edworthy
2014-02-26 16:08 ` [PATCH 5/5] ARM: koelsch: Add PCIe to defconfig Phil Edworthy
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox