Correctly create a new mvebu-6.2 patch folder, update symlink, update/fix patches for mvebu-edge

This commit is contained in:
Heisath
2023-03-12 11:28:28 +01:00
committed by Igor
parent 9405302871
commit 46ae5155c5
18 changed files with 2831 additions and 1 deletions

View File

@@ -0,0 +1,43 @@
From: Russell King <rmk+kernel@arm.linux.org.uk>
Subject: [PATCH 01/30] cpuidle: mvebu: indicate failure to enter deeper sleep
states
MIME-Version: 1.0
Content-Disposition: inline
Content-Transfer-Encoding: 8bit
Content-Type: text/plain; charset="utf-8"
The cpuidle ->enter method expects the return value to be the sleep
state we entered. Returning negative numbers or other codes is not
permissible since coupled CPU idle was merged.
At least some of the mvebu_v7_cpu_suspend() implementations return the
value from cpu_suspend(), which returns zero if the CPU vectors back
into the kernel via cpu_resume() (the success case), or the non-zero
return value of the suspend actor, or one (failure cases).
We do not want to be returning the failure case value back to CPU idle
as that indicates that we successfully entered one of the deeper idle
states. Always return zero instead, indicating that we slept for the
shortest amount of time.
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
drivers/cpuidle/cpuidle-mvebu-v7.c | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
--- a/drivers/cpuidle/cpuidle-mvebu-v7.c
+++ b/drivers/cpuidle/cpuidle-mvebu-v7.c
@@ -39,8 +39,12 @@ static int mvebu_v7_enter_idle(struct cp
ret = mvebu_v7_cpu_suspend(deepidle);
cpu_pm_exit();
+ /*
+ * If we failed to enter the desired state, indicate that we
+ * slept lightly.
+ */
if (ret)
- return ret;
+ return 0;
return index;
}

View File

@@ -0,0 +1,219 @@
Subject: [PATCH v3] PCI: Disallow retraining link for Atheros chips on non-Gen1 PCIe bridges
Atheros AR9xxx and QCA9xxx chips have behaviour issues not only after a
bus reset, but also after doing retrain link, if PCIe bridge is not in
GEN1 mode (at 2.5 GT/s speed):
- QCA9880 and QCA9890 chips throw a Link Down event and completely
disappear from the bus and their config space is not accessible
afterwards.
- QCA9377 chip throws a Link Down event followed by Link Up event, the
config space is accessible and PCI device ID is correct. But trying to
access chip's I/O space causes Uncorrected (Non-Fatal) AER error,
followed by Synchronous external abort 96000210 and Segmentation fault
of insmod while loading ath10k_pci.ko module.
- AR9390 chip throws a Link Down event followed by Link Up event, config
space is accessible, but contains nonsense values. PCI device ID is
0xABCD which indicates HW bug that chip itself was not able to read
values from internal EEPROM/OTP.
- AR9287 chip throws also Link Down and Link Up events, also has
accessible config space containing correct values. But ath9k driver
fails to initialize card from this state as it is unable to access HW
registers. This also indicates that the chip iself is not able to read
values from internal EEPROM/OTP.
These issues related to PCI device ID 0xABCD and to reading internal
EEPROM/OTP were previously discussed at ath9k-devel mailing list in
following thread:
https://www.mail-archive.com/ath9k-devel@lists.ath9k.org/msg07529.html
After experiments we've come up with a solution: it seems that Retrain
link can be called only when using GEN1 PCIe bridge or when PCIe bridge
link speed is forced to 2.5 GT/s. Applying this workaround fixes all
mentioned cards.
This issue was reproduced with more cards:
- Compex WLE900VX (QCA9880 based / device ID 0x003c)
- QCNFA435 (QCA9377 based / device ID 0x0042)
- Compex WLE200NX (AR9287 based / device ID 0x002e)
- "noname" card (QCA9890 based / device ID 0x003c)
- Wistron NKR-DNXAH1 (AR9390 based / device ID 0x0030)
on Armada 385 with pci-mvebu.c driver and also on Armada 3720 with
pci-aardvark.c driver.
To workaround this issue, this change introduces a new PCI quirk called
PCI_DEV_FLAGS_NO_RETRAIN_LINK_WHEN_NOT_GEN1, which is enabled for all
Atheros chips with PCI_DEV_FLAGS_NO_BUS_RESET quirk, and also for Atheros
chip AR9287.
When this quirk is set, kernel disallows triggering PCI_EXP_LNKCTL_RL
bit in config space of PCIe Bridge in the case when PCIe Bridge is
capable of higher speed than 2.5 GT/s and this higher speed is already
allowed. When PCIe Bridge has accessible LNKCTL2 register, we try to
force target link speed to 2.5 GT/s. After this change it is possible
to trigger PCI_EXP_LNKCTL_RL bit without issues.
Currently only PCIe ASPM kernel code triggers this PCI_EXP_LNKCTL_RL bit,
so quirk check is added only into pcie/aspm.c file.
Signed-off-by: Pali Rohár <pali@kernel.org>
Reported-by: Toke Høiland-Jørgensen <toke@redhat.com>
Tested-by: Toke Høiland-Jørgensen <toke@redhat.com>
Tested-by: Marek Behún <kabel@kernel.org>
BugLink: https://lore.kernel.org/linux-pci/87h7l8axqp.fsf@toke.dk/
BugLink: https://bugzilla.kernel.org/show_bug.cgi?id=84821
BugLink: https://bugzilla.kernel.org/show_bug.cgi?id=192441
BugLink: https://bugzilla.kernel.org/show_bug.cgi?id=209833
Cc: stable@vger.kernel.org # c80851f6ce63a ("PCI: Add PCI_EXP_LNKCTL2_TLS* macros")
---
Changes since v1:
* Move whole quirk code into pcie_downgrade_link_to_gen1() function
* Reformat to 80 chars per line where possible
* Add quirk also for cards with AR9287 chip (PCI ID 0x002e)
* Extend commit message description and add information about 0xABCD
Changes since v2:
* Add quirk also for Atheros QCA9377 chip
---
drivers/pci/pcie/aspm.c | 44 +++++++++++++++++++++++++++++++++++++++++
drivers/pci/quirks.c | 39 ++++++++++++++++++++++++++++--------
include/linux/pci.h | 2 ++
3 files changed, 77 insertions(+), 8 deletions(-)
diff --git a/drivers/pci/pcie/aspm.c b/drivers/pci/pcie/aspm.c
index ac0557a305af..729b0389562b 100644
--- a/drivers/pci/pcie/aspm.c
+++ b/drivers/pci/pcie/aspm.c
@@ -192,12 +192,56 @@ static void pcie_clkpm_cap_init(struct pcie_link_state *link, int blacklist)
link->clkpm_disable = blacklist ? 1 : 0;
}
+static int pcie_downgrade_link_to_gen1(struct pci_dev *parent)
+{
+ u16 reg16;
+ u32 reg32;
+ int ret;
+
+ /* Check if link is capable of higher speed than 2.5 GT/s */
+ pcie_capability_read_dword(parent, PCI_EXP_LNKCAP, &reg32);
+ if ((reg32 & PCI_EXP_LNKCAP_SLS) <= PCI_EXP_LNKCAP_SLS_2_5GB)
+ return 0;
+
+ /* Check if link speed can be downgraded to 2.5 GT/s */
+ pcie_capability_read_dword(parent, PCI_EXP_LNKCAP2, &reg32);
+ if (!(reg32 & PCI_EXP_LNKCAP2_SLS_2_5GB)) {
+ pci_err(parent, "ASPM: Bridge does not support changing Link Speed to 2.5 GT/s\n");
+ return -EOPNOTSUPP;
+ }
+
+ /* Force link speed to 2.5 GT/s */
+ ret = pcie_capability_clear_and_set_word(parent, PCI_EXP_LNKCTL2,
+ PCI_EXP_LNKCTL2_TLS,
+ PCI_EXP_LNKCTL2_TLS_2_5GT);
+ if (!ret) {
+ /* Verify that new value was really set */
+ pcie_capability_read_word(parent, PCI_EXP_LNKCTL2, &reg16);
+ if ((reg16 & PCI_EXP_LNKCTL2_TLS) != PCI_EXP_LNKCTL2_TLS_2_5GT)
+ ret = -EINVAL;
+ }
+
+ if (ret) {
+ pci_err(parent, "ASPM: Changing Target Link Speed to 2.5 GT/s failed: %d\n", ret);
+ return ret;
+ }
+
+ pci_info(parent, "ASPM: Target Link Speed changed to 2.5 GT/s due to quirk\n");
+ return 0;
+}
+
static bool pcie_retrain_link(struct pcie_link_state *link)
{
struct pci_dev *parent = link->pdev;
unsigned long end_jiffies;
u16 reg16;
+ if ((link->downstream->dev_flags & PCI_DEV_FLAGS_NO_RETRAIN_LINK_WHEN_NOT_GEN1) &&
+ pcie_downgrade_link_to_gen1(parent)) {
+ pci_err(parent, "ASPM: Retrain Link at higher speed is disallowed by quirk\n");
+ return false;
+ }
+
pcie_capability_read_word(parent, PCI_EXP_LNKCTL, &reg16);
reg16 |= PCI_EXP_LNKCTL_RL;
pcie_capability_write_word(parent, PCI_EXP_LNKCTL, reg16);
diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c
index 5d2acebc3..91d675e0d 100644
--- a/drivers/pci/quirks.c
+++ b/drivers/pci/quirks.c
@@ -3572,19 +3572,46 @@ static void quirk_nvidia_no_bus_reset(struct pci_dev *dev)
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_NVIDIA, PCI_ANY_ID,
quirk_nvidia_no_bus_reset);
+
+static void quirk_no_bus_reset_and_no_retrain_link(struct pci_dev *dev)
+{
+ dev->dev_flags |= PCI_DEV_FLAGS_NO_BUS_RESET |
+ PCI_DEV_FLAGS_NO_RETRAIN_LINK_WHEN_NOT_GEN1;
+}
+
/*
* Some Atheros AR9xxx and QCA988x chips do not behave after a bus reset.
+ * Atheros AR9xxx and QCA9xxx chips do not behave after a bus reset and also
+ * after retrain link when PCIe bridge is not in GEN1 mode at 2.5 GT/s speed.
* The device will throw a Link Down error on AER-capable systems and
* regardless of AER, config space of the device is never accessible again
* and typically causes the system to hang or reset when access is attempted.
+ * Or if config space is accessible again then it contains only dummy values
+ * like fixed PCI device ID 0xABCD or values not initialized at all.
+ * Retrain link can be called only when using GEN1 PCIe bridge or when
+ * PCIe bridge has forced link speed to 2.5 GT/s via PCI_EXP_LNKCTL2 register.
+ * To reset these cards it is required to do PCIe Warm Reset via PERST# pin.
* https://lore.kernel.org/r/20140923210318.498dacbd@dualc.maya.org/
+ * https://lore.kernel.org/r/87h7l8axqp.fsf@toke.dk/
+ * https://www.mail-archive.com/ath9k-devel@lists.ath9k.org/msg07529.html
*/
-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_ATHEROS, 0x0030, quirk_no_bus_reset);
-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_ATHEROS, 0x0032, quirk_no_bus_reset);
-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_ATHEROS, 0x003c, quirk_no_bus_reset);
-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_ATHEROS, 0x0033, quirk_no_bus_reset);
-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_ATHEROS, 0x0034, quirk_no_bus_reset);
-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_ATHEROS, 0x003e, quirk_no_bus_reset);
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_ATHEROS, 0x002e,
+ quirk_no_bus_reset_and_no_retrain_link);
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_ATHEROS, 0x0030,
+ quirk_no_bus_reset_and_no_retrain_link);
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_ATHEROS, 0x0032,
+ quirk_no_bus_reset_and_no_retrain_link);
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_ATHEROS, 0x0033,
+ quirk_no_bus_reset_and_no_retrain_link);
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_ATHEROS, 0x0034,
+ quirk_no_bus_reset_and_no_retrain_link);
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_ATHEROS, 0x003e,
+ quirk_no_bus_reset_and_no_retrain_link);
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_ATHEROS, 0x003c,
+ quirk_no_bus_reset_and_no_retrain_link);
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_ATHEROS, 0x0042,
+ quirk_no_bus_reset_and_no_retrain_link);
+
/*
* Root port on some Cavium CN8xxx chips do not successfully complete a bus
diff --git a/include/linux/pci.h b/include/linux/pci.h
index 86c799c97b77..fdbf7254e4ab 100644
--- a/include/linux/pci.h
+++ b/include/linux/pci.h
@@ -227,6 +227,8 @@ enum pci_dev_flags {
PCI_DEV_FLAGS_NO_RELAXED_ORDERING = (__force pci_dev_flags_t) (1 << 11),
/* Device does honor MSI masking despite saying otherwise */
PCI_DEV_FLAGS_HAS_MSI_MASKING = (__force pci_dev_flags_t) (1 << 12),
+ /* Don't Retrain Link for device when bridge is not in GEN1 mode */
+ PCI_DEV_FLAGS_NO_RETRAIN_LINK_WHEN_NOT_GEN1 = (__force pci_dev_flags_t) (1 << 12),
};
enum pci_irq_reroute_variant {
--
2.20.1

View File

@@ -0,0 +1,196 @@
From 6ea4b200f29c9397482b43d5ac14bd2d1ddade53 Mon Sep 17 00:00:00 2001
From: Russell King <rmk+kernel@arm.linux.org.uk>
Date: Tue, 29 Nov 2016 10:13:46 +0000
Subject: mvebu/clearfog pcie updates
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
drivers/pci/controller/pci-mvebu.c | 76 ++++++++++++++++++++++++++++++++++++++
drivers/pci/pci-bridge-emul.c | 2 +
drivers/pci/pcie/aspm.c | 6 +++
drivers/pci/pcie/portdrv.c | 2 +
4 files changed, 86 insertions(+)
diff --git a/drivers/pci/controller/pci-mvebu.c b/drivers/pci/controller/pci-mvebu.c
index 1dc209f6f53a..bc66f82b8616 100644
--- a/drivers/pci/controller/pci-mvebu.c
+++ b/drivers/pci/controller/pci-mvebu.c
@@ -60,6 +60,12 @@
#define PCIE_INT_INTX(i) BIT(24+i)
#define PCIE_INT_PM_PME BIT(28)
#define PCIE_INT_ALL_MASK GENMASK(31, 0)
+#define PCIE_MASK_ERR_COR BIT(18)
+#define PCIE_MASK_ERR_NONFATAL BIT(17)
+#define PCIE_MASK_ERR_FATAL BIT(16)
+#define PCIE_MASK_FERR_DET BIT(10)
+#define PCIE_MASK_NFERR_DET BIT(9)
+#define PCIE_MASK_CORERR_DET BIT(8)
#define PCIE_CTRL_OFF 0x1a00
#define PCIE_CTRL_X1_MODE 0x0001
#define PCIE_CTRL_RC_MODE BIT(1)
@@ -619,6 +625,54 @@ mvebu_pci_bridge_emul_base_conf_read(struct pci_bridge_emul *bridge,
return PCI_BRIDGE_EMUL_HANDLED;
}
+static void mvebu_pcie_handle_irq_change(struct mvebu_pcie_port *port)
+{
+ u32 reg, old;
+ u16 devctl, rtctl;
+
+ /*
+ * Errors from downstream devices:
+ * bridge control register SERR: enables reception of errors
+ * Errors from this device, or received errors:
+ * command SERR: enables ERR_NONFATAL and ERR_FATAL messages
+ * => when enabled, these conditions also flag SERR in status register
+ * devctl CERE: enables ERR_CORR messages
+ * devctl NFERE: enables ERR_NONFATAL messages
+ * devctl FERE: enables ERR_FATAL messages
+ * Enabled messages then have three paths:
+ * 1. rtctl: enables system error indication
+ * 2. root error status register updated
+ * 3. root error command register: forwarding via MSI
+ */
+ old = mvebu_readl(port, PCIE_INT_UNMASK_OFF);
+ reg = old & ~(PCIE_INT_PM_PME | PCIE_MASK_FERR_DET |
+ PCIE_MASK_NFERR_DET | PCIE_MASK_CORERR_DET |
+ PCIE_MASK_ERR_COR | PCIE_MASK_ERR_NONFATAL |
+ PCIE_MASK_ERR_FATAL);
+
+ devctl = port->bridge.pcie_conf.devctl;
+ if (devctl & PCI_EXP_DEVCTL_FERE)
+ reg |= PCIE_MASK_FERR_DET | PCIE_MASK_ERR_FATAL;
+ if (devctl & PCI_EXP_DEVCTL_NFERE)
+ reg |= PCIE_MASK_NFERR_DET | PCIE_MASK_ERR_NONFATAL;
+ if (devctl & PCI_EXP_DEVCTL_CERE)
+ reg |= PCIE_MASK_CORERR_DET | PCIE_MASK_ERR_COR;
+ if (port->bridge.conf.command & PCI_COMMAND_SERR)
+ reg |= PCIE_MASK_FERR_DET | PCIE_MASK_NFERR_DET |
+ PCIE_MASK_ERR_FATAL | PCIE_MASK_ERR_NONFATAL;
+
+ if (!(port->bridge.conf.bridgectrl & PCI_BRIDGE_CTL_SERR))
+ reg &= ~(PCIE_MASK_ERR_COR | PCIE_MASK_ERR_NONFATAL |
+ PCIE_MASK_ERR_FATAL);
+
+ rtctl = port->bridge.pcie_conf.rootctl;
+ if (rtctl & PCI_EXP_RTCTL_PMEIE)
+ reg |= PCIE_INT_PM_PME;
+
+ if (old != reg)
+ mvebu_writel(port, reg, PCIE_INT_UNMASK_OFF);
+}
+
static pci_bridge_emul_read_status_t
mvebu_pci_bridge_emul_pcie_conf_read(struct pci_bridge_emul *bridge,
int reg, u32 *value)
@@ -735,6 +789,9 @@ mvebu_pci_bridge_emul_base_conf_write(struct pci_bridge_emul *bridge,
switch (reg) {
case PCI_COMMAND:
mvebu_writel(port, new, PCIE_CMD_OFF);
+
+ if ((old ^ new) & PCI_COMMAND_SERR)
+ mvebu_pcie_handle_irq_change(port);
break;
case PCI_IO_BASE:
@@ -776,6 +833,8 @@ mvebu_pci_bridge_emul_base_conf_write(struct pci_bridge_emul *bridge,
break;
case PCI_INTERRUPT_LINE:
+ if (((old ^ new) >> 16) & PCI_BRIDGE_CTL_SERR)
+ mvebu_pcie_handle_irq_change(port);
if (mask & (PCI_BRIDGE_CTL_BUS_RESET << 16)) {
u32 ctrl = mvebu_readl(port, PCIE_CTRL_OFF);
if (new & (PCI_BRIDGE_CTL_BUS_RESET << 16))
@@ -799,7 +858,18 @@ mvebu_pci_bridge_emul_pcie_conf_write(struct pci_bridge_emul *bridge,
switch (reg) {
case PCI_EXP_DEVCTL:
+ /*
+ * Armada370 data says these bits must always
+ * be zero when in root complex mode.
+ */
+ new &= ~(PCI_EXP_DEVCTL_URRE | PCI_EXP_DEVCTL_FERE |
+ PCI_EXP_DEVCTL_NFERE | PCI_EXP_DEVCTL_CERE);
+
mvebu_writel(port, new, PCIE_CAP_PCIEXP + PCI_EXP_DEVCTL);
+
+ if ((new ^ old) & (PCI_EXP_DEVCTL_FERE | PCI_EXP_DEVCTL_NFERE |
+ PCI_EXP_DEVCTL_CERE | PCI_EXP_DEVCTL_URRE))
+ mvebu_pcie_handle_irq_change(port);
break;
case PCI_EXP_LNKCTL:
@@ -850,6 +920,12 @@ mvebu_pci_bridge_emul_pcie_conf_write(struct pci_bridge_emul *bridge,
default:
break;
+
+ case PCI_EXP_RTCTL:
+ if ((new ^ old) & (PCI_EXP_RTCTL_SECEE | PCI_EXP_RTCTL_SENFEE |
+ PCI_EXP_RTCTL_SEFEE | PCI_EXP_RTCTL_PMEIE))
+ mvebu_pcie_handle_irq_change(port);
+ break;
}
}
diff --git a/drivers/pci/pci-bridge-emul.c b/drivers/pci/pci-bridge-emul.c
index d8d37b7ad0c5..003511971108 100644
--- a/drivers/pci/pci-bridge-emul.c
+++ b/drivers/pci/pci-bridge-emul.c
@@ -157,6 +157,7 @@ struct pci_bridge_reg_behavior pci_regs_behavior[PCI_STD_HEADER_SIZEOF / 4] = {
.rw = (GENMASK(7, 0) |
((PCI_BRIDGE_CTL_PARITY |
PCI_BRIDGE_CTL_SERR |
+ /* NOTE: PCIe does not allow ISA, VGA, MASTER_ABORT */
PCI_BRIDGE_CTL_ISA |
PCI_BRIDGE_CTL_VGA |
PCI_BRIDGE_CTL_MASTER_ABORT |
@@ -355,6 +356,7 @@ int pci_bridge_emul_init(struct pci_bridge_emul *bridge,
bridge->conf.header_type = PCI_HEADER_TYPE_BRIDGE;
bridge->conf.cache_line_size = 0x10;
bridge->conf.status = cpu_to_le16(PCI_STATUS_CAP_LIST);
+ bridge->conf.bridgectrl = cpu_to_le16(PCI_BRIDGE_CTL_SERR);
bridge->pci_regs_behavior = kmemdup(pci_regs_behavior,
sizeof(pci_regs_behavior),
GFP_KERNEL);
diff --git a/drivers/pci/pcie/aspm.c b/drivers/pci/pcie/aspm.c
index 4b4184563a92..7342af76f93d 100644
--- a/drivers/pci/pcie/aspm.c
+++ b/drivers/pci/pcie/aspm.c
@@ -656,6 +656,12 @@ static void pcie_aspm_cap_init(struct pcie_link_state *link, int blacklist)
pcie_capability_read_dword(child, PCI_EXP_LNKCAP, &child_lnkcap);
pcie_capability_read_word(parent, PCI_EXP_LNKCTL, &parent_lnkctl);
pcie_capability_read_word(child, PCI_EXP_LNKCTL, &child_lnkctl);
+dev_info(&parent->dev, "up support %x enabled %x\n",
+ (parent_lnkcap & PCI_EXP_LNKCAP_ASPMS) >> 10,
+ !!(parent_lnkctl & PCI_EXP_LNKCTL_ASPMC));
+dev_info(&parent->dev, "dn support %x enabled %x\n",
+ (child_lnkcap & PCI_EXP_LNKCAP_ASPMS) >> 10,
+ !!(child_lnkctl & PCI_EXP_LNKCTL_ASPMC));
/*
* Setup L0s state
diff --git a/drivers/pci/pcie/portdrv.c b/drivers/pci/pcie/portdrv.c
index 2cc2e60bcb39..1954487a1968 100644
--- a/drivers/pci/pcie/portdrv.c
+++ b/drivers/pci/pcie/portdrv.c
@@ -335,6 +335,7 @@ static int pcie_port_device_register(struct pci_dev *dev)
/* Get and check PCI Express port services */
capabilities = get_port_device_capability(dev);
+dev_info(&dev->dev, "PCIe capabilities: 0x%x\n", capabilities);
if (!capabilities)
return 0;
@@ -347,6 +348,7 @@ static int pcie_port_device_register(struct pci_dev *dev)
* if that is to be used.
*/
status = pcie_init_service_irqs(dev, irqs, capabilities);
+dev_info(&dev->dev, "init_service_irqs: %d\n", status);
if (status) {
capabilities &= PCIE_PORT_SERVICE_HP;
if (!capabilities)
--
cgit

View File

@@ -0,0 +1,57 @@
From e6a83c8b624052022b8212beabee6e4c40c6d8b2 Mon Sep 17 00:00:00 2001
From: Russell King <rmk+kernel@arm.linux.org.uk>
Date: Tue, 29 Nov 2016 10:13:48 +0000
Subject: implement slot capabilities (SSPL)
---
drivers/pci/controller/pci-mvebu.c | 20 ++++++++++++++++++++
1 file changed, 20 insertions(+)
diff --git a/drivers/pci/controller/pci-mvebu.c b/drivers/pci/controller/pci-mvebu.c
index dba5baa2c1ed..c817cc5b2206 100644
--- a/drivers/pci/controller/pci-mvebu.c
+++ b/drivers/pci/controller/pci-mvebu.c
@@ -78,6 +78,7 @@
#define PCIE_SSPL_VALUE_MASK GENMASK(7, 0)
#define PCIE_SSPL_SCALE_SHIFT 8
#define PCIE_SSPL_SCALE_MASK GENMASK(9, 8)
+#define PCIE_SSPL_MSGEN BIT(14)
#define PCIE_SSPL_ENABLE BIT(16)
#define PCIE_RC_RTSTA 0x1a14
#define PCIE_DEBUG_CTRL 0x1a60
@@ -705,6 +706,14 @@ mvebu_pci_bridge_emul_pcie_conf_read(struct pci_bridge_emul *bridge,
(PCI_EXP_LNKSTA_DLLLA << 16) : 0);
break;
+ case PCI_EXP_SLTCAP:
+ {
+ u32 tmp = mvebu_readl(port, PCIE_SSPL_OFF);
+ *value = FIELD_GET(PCIE_SSPL_SCALE_MASK, tmp) << 15 |
+ FIELD_GET(PCIE_SSPL_VALUE_MASK, tmp) << 7;
+ break;
+ }
+
case PCI_EXP_SLTCTL: {
u16 slotctl = le16_to_cpu(bridge->pcie_conf.slotctl);
u16 slotsta = le16_to_cpu(bridge->pcie_conf.slotsta);
@@ -882,6 +891,17 @@ mvebu_pci_bridge_emul_pcie_conf_write(struct pci_bridge_emul *bridge,
mvebu_writel(port, new, PCIE_CAP_PCIEXP + PCI_EXP_LNKCTL);
break;
+ case PCI_EXP_SLTCAP:
+ {
+ u32 sspl = FIELD_PREP(PCIE_SSPL_VALUE_MASK,
+ FIELD_GET(PCI_EXP_SLTCAP_SPLV, new)) |
+ FIELD_PREP(PCIE_SSPL_SCALE_MASK,
+ FIELD_GET(PCI_EXP_SLTCAP_SPLS, new)) |
+ PCIE_SSPL_MSGEN;
+ mvebu_writel(port, sspl, PCIE_SSPL_OFF);
+ break;
+ }
+
case PCI_EXP_SLTCTL:
/*
* Allow to change PCIE_SSPL_ENABLE bit only when slot power
--
cgit

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,55 @@
From f1149effc7fd438ac5925a8e58ee2da294033ec5 Mon Sep 17 00:00:00 2001
From: Russell King <rmk+kernel@armlinux.org.uk>
Date: Tue, 2 Feb 2021 13:45:28 +0000
Subject: PCI: pci-bridge-emul: re-arrange register tests
Re-arrange the tests for which sets of registers are being accessed
so that it is easier to add further regions later. No functional
change.
Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
---
drivers/pci/pci-bridge-emul.c | 15 ++++++++++-----
1 file changed, 10 insertions(+), 5 deletions(-)
diff --git a/drivers/pci/pci-bridge-emul.c b/drivers/pci/pci-bridge-emul.c
index 9334b2dd4764..d746116104c6 100644
--- a/drivers/pci/pci-bridge-emul.c
+++ b/drivers/pci/pci-bridge-emul.c
@@ -477,8 +477,11 @@ int pci_bridge_emul_conf_read(struct pci_bridge_emul *bridge, int where,
read_op = pci_bridge_emul_read_ssid;
cfgspace = NULL;
behavior = NULL;
- } else if (reg >= bridge->pcie_start && reg < bridge->pcie_start + PCI_CAP_PCIE_SIZEOF &&
- bridge->has_pcie) {
+ } else if (!bridge->has_pcie) {
+ /* PCIe space is not implemented, and no PCI capabilities */
+ *value = 0;
+ return PCIBIOS_SUCCESSFUL;
+ } else if (reg >= bridge->pcie_start && reg < bridge->pcie_start + PCI_CAP_PCIE_SIZEOF) {
/* Our emulated PCIe capability */
reg -= bridge->pcie_start;
read_op = bridge->ops->read_pcie;
@@ -551,14 +554,16 @@ int pci_bridge_emul_conf_write(struct pci_bridge_emul *bridge, int where,
write_op = bridge->ops->write_base;
cfgspace = (__le32 *) &bridge->conf;
behavior = bridge->pci_regs_behavior;
- } else if (reg >= bridge->pcie_start && reg < bridge->pcie_start + PCI_CAP_PCIE_SIZEOF &&
- bridge->has_pcie) {
+ } else if (!bridge->has_pcie) {
+ /* PCIe space is not implemented, and no PCI capabilities */
+ return PCIBIOS_SUCCESSFUL;
+ } else if (reg >= bridge->pcie_start && reg < bridge->pcie_start + PCI_CAP_PCIE_SIZEOF) {
/* Our emulated PCIe capability */
reg -= bridge->pcie_start;
write_op = bridge->ops->write_pcie;
cfgspace = (__le32 *) &bridge->pcie_conf;
behavior = bridge->pcie_cap_regs_behavior;
- } else if (reg >= PCI_CFG_SPACE_SIZE && bridge->has_pcie) {
+ } else if (reg >= PCI_CFG_SPACE_SIZE) {
/* PCIe extended capability space */
reg -= PCI_CFG_SPACE_SIZE;
write_op = bridge->ops->write_ext;
--
cgit

View File

@@ -0,0 +1,87 @@
From 8137da20701c776ad3481115305a5e8e410871ba Mon Sep 17 00:00:00 2001
From: Russell King <rmk+kernel@armlinux.org.uk>
Date: Tue, 29 Nov 2016 10:15:45 +0000
Subject: ARM: dts: armada388-clearfog: emmc on clearfog base
Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
---
arch/arm/boot/dts/armada-388-clearfog-base.dts | 1 +
.../dts/armada-38x-solidrun-microsom-emmc.dtsi | 62 ++++++++++++++++++++++
2 files changed, 63 insertions(+)
create mode 100644 arch/arm/boot/dts/armada-38x-solidrun-microsom-emmc.dtsi
--- a/arch/arm/boot/dts/armada-388-clearfog-base.dts
+++ b/arch/arm/boot/dts/armada-388-clearfog-base.dts
@@ -7,6 +7,7 @@
/dts-v1/;
#include "armada-388-clearfog.dtsi"
+#include "armada-38x-solidrun-microsom-emmc.dtsi"
/ {
model = "SolidRun Clearfog Base A1";
--- /dev/null
+++ b/arch/arm/boot/dts/armada-38x-solidrun-microsom-emmc.dtsi
@@ -0,0 +1,62 @@
+/*
+ * Device Tree file for SolidRun Armada 38x Microsom add-on for eMMC
+ *
+ * Copyright (C) 2015 Russell King
+ *
+ * This board is in development; the contents of this file work with
+ * the A1 rev 2.0 of the board, which does not represent final
+ * production board. Things will change, don't expect this file to
+ * remain compatible info the future.
+ *
+ * This file is dual-licensed: you can use it either under the terms
+ * of the GPL or the X11 license, at your option. Note that this dual
+ * licensing only applies to this file, and not this project as a
+ * whole.
+ *
+ * a) This file is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This file is distributed in the hope that it will be useful
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * Or, alternatively
+ *
+ * b) Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED , WITHOUT WARRANTY OF ANY KIND
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+/ {
+ soc {
+ internal-regs {
+ sdhci@d8000 {
+ bus-width = <4>;
+ no-1-8-v;
+ non-removable;
+ pinctrl-0 = <&microsom_sdhci_pins>;
+ pinctrl-names = "default";
+ status = "okay";
+ wp-inverted;
+ };
+ };
+ };
+};

View File

@@ -0,0 +1,149 @@
From: Daniel Golle <daniel@makrotopia.org>
Subject: libata: add ledtrig support
This adds a LED trigger for each ATA port indicating disk activity.
As this is needed only on specific platforms (NAS SoCs and such),
these platforms should define ARCH_WANTS_LIBATA_LEDS if there
are boards with LED(s) intended to indicate ATA disk activity and
need the OS to take care of that.
In that way, if not selected, LED trigger support not will be
included in libata-core and both, codepaths and structures remain
untouched.
Signed-off-by: Daniel Golle <daniel@makrotopia.org>
---
drivers/ata/Kconfig | 16 ++++++++++++++++
drivers/ata/libata-core.c | 41 +++++++++++++++++++++++++++++++++++++++++
include/linux/libata.h | 9 +++++++++
3 files changed, 66 insertions(+)
--- a/drivers/ata/Kconfig
+++ b/drivers/ata/Kconfig
@@ -67,6 +67,22 @@ config ATA_FORCE
If unsure, say Y.
+config ARCH_WANT_LIBATA_LEDS
+ bool
+
+config ATA_LEDS
+ bool "support ATA port LED triggers"
+ depends on ARCH_WANT_LIBATA_LEDS
+ select NEW_LEDS
+ select LEDS_CLASS
+ select LEDS_TRIGGERS
+ default y
+ help
+ This option adds a LED trigger for each registered ATA port.
+ It is used to drive disk activity leds connected via GPIO.
+
+ If unsure, say N.
+
config ATA_ACPI
bool "ATA ACPI Support"
depends on ACPI
--- a/drivers/ata/libata-core.c
+++ b/drivers/ata/libata-core.c
@@ -650,6 +650,19 @@ u64 ata_tf_read_block(const struct ata_t
return block;
}
+#ifdef CONFIG_ATA_LEDS
+#define LIBATA_BLINK_DELAY 20 /* ms */
+static inline void ata_led_act(struct ata_port *ap)
+{
+ unsigned long led_delay = LIBATA_BLINK_DELAY;
+
+ if (unlikely(!ap->ledtrig))
+ return;
+
+ led_trigger_blink_oneshot(ap->ledtrig, &led_delay, &led_delay, 0);
+}
+#endif
+
/**
* ata_build_rw_tf - Build ATA taskfile for given read/write request
* @tf: Target ATA taskfile
@@ -4513,6 +4526,9 @@ struct ata_queued_cmd *ata_qc_new_init(s
if (tag < 0)
return NULL;
}
+#ifdef CONFIG_ATA_LEDS
+ ata_led_act(ap);
+#endif
qc = __ata_qc_from_tag(ap, tag);
qc->tag = qc->hw_tag = tag;
@@ -5291,6 +5307,9 @@ struct ata_port *ata_port_alloc(struct a
ap->stats.unhandled_irq = 1;
ap->stats.idle_irq = 1;
#endif
+#ifdef CONFIG_ATA_LEDS
+ ap->ledtrig = kzalloc(sizeof(struct led_trigger), GFP_KERNEL);
+#endif
ata_sff_port_init(ap);
return ap;
@@ -5326,6 +5345,12 @@ static void ata_host_release(struct kref
kfree(ap->pmp_link);
kfree(ap->slave_link);
+#ifdef CONFIG_ATA_LEDS
+ if (ap->ledtrig) {
+ led_trigger_unregister(ap->ledtrig);
+ kfree(ap->ledtrig);
+ };
+#endif
kfree(ap);
host->ports[i] = NULL;
}
@@ -5732,7 +5757,23 @@ int ata_host_register(struct ata_host *h
host->ports[i]->print_id = atomic_inc_return(&ata_print_id);
host->ports[i]->local_port_no = i + 1;
}
+#ifdef CONFIG_ATA_LEDS
+ for (i = 0; i < host->n_ports; i++) {
+ if (unlikely(!host->ports[i]->ledtrig))
+ continue;
+ snprintf(host->ports[i]->ledtrig_name,
+ sizeof(host->ports[i]->ledtrig_name), "ata%u",
+ host->ports[i]->print_id);
+
+ host->ports[i]->ledtrig->name = host->ports[i]->ledtrig_name;
+
+ if (led_trigger_register(host->ports[i]->ledtrig)) {
+ kfree(host->ports[i]->ledtrig);
+ host->ports[i]->ledtrig = NULL;
+ }
+ }
+#endif
/* Create associated sysfs transport objects */
for (i = 0; i < host->n_ports; i++) {
rc = ata_tport_add(host->dev,host->ports[i]);
--- a/include/linux/libata.h
+++ b/include/linux/libata.h
@@ -23,6 +23,9 @@
#include <linux/cdrom.h>
#include <linux/sched.h>
#include <linux/async.h>
+#ifdef CONFIG_ATA_LEDS
+#include <linux/leds.h>
+#endif
/*
* Define if arch has non-standard setup. This is a _PCI_ standard
@@ -882,6 +885,12 @@ struct ata_port {
#ifdef CONFIG_ATA_ACPI
struct ata_acpi_gtm __acpi_init_gtm; /* use ata_acpi_init_gtm() */
#endif
+
+#ifdef CONFIG_ATA_LEDS
+ struct led_trigger *ledtrig;
+ char ledtrig_name[8];
+#endif
+
/* owned by EH */
u8 sector_buf[ATA_SECT_SIZE] ____cacheline_aligned;
};

View File

@@ -0,0 +1,30 @@
From 9ee6345ef82f7af5f98e17a40e667f8ad6b2fa1b Mon Sep 17 00:00:00 2001
From: aprayoga <adit.prayoga@gmail.com>
Date: Sun, 3 Sep 2017 18:10:12 +0800
Subject: Enable ATA port LED trigger
---
arch/arm/configs/mvebu_v7_defconfig | 1 +
arch/arm/mach-mvebu/Kconfig | 1 +
2 files changed, 2 insertions(+)
--- a/arch/arm/configs/mvebu_v7_defconfig
+++ b/arch/arm/configs/mvebu_v7_defconfig
@@ -58,6 +58,7 @@ CONFIG_MTD_UBI=y
CONFIG_EEPROM_AT24=y
CONFIG_BLK_DEV_SD=y
CONFIG_ATA=y
+CONFIG_ATA_LEDS=y
CONFIG_SATA_AHCI=y
CONFIG_AHCI_MVEBU=y
CONFIG_SATA_MV=y
--- a/arch/arm/mach-mvebu/Kconfig
+++ b/arch/arm/mach-mvebu/Kconfig
@@ -56,6 +56,7 @@ config MACH_ARMADA_375
config MACH_ARMADA_38X
bool "Marvell Armada 380/385 boards"
depends on ARCH_MULTI_V7
+ select ARCH_WANT_LIBATA_LEDS
select ARM_ERRATA_720789
select PL310_ERRATA_753970
select ARM_GIC

View File

@@ -0,0 +1,88 @@
--- a/drivers/gpio/gpio-mvebu.c
+++ b/drivers/gpio/gpio-mvebu.c
@@ -40,6 +40,7 @@
#include <linux/gpio/consumer.h>
#include <linux/gpio/machine.h>
#include <linux/init.h>
+#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/irq.h>
#include <linux/irqchip/chained_irq.h>
@@ -111,7 +112,7 @@ struct mvebu_gpio_chip {
struct regmap *regs;
u32 offset;
struct regmap *percpu_regs;
- int irqbase;
+ int bank_irq[4];
struct irq_domain *domain;
int soc_variant;
@@ -601,6 +602,33 @@ static void mvebu_gpio_irq_handler(struc
}
/*
+ * Set interrupt number "irq" in the GPIO as a wake-up source.
+ * While system is running, all registered GPIO interrupts need to have
+ * wake-up enabled. When system is suspended, only selected GPIO interrupts
+ * need to have wake-up enabled.
+ * @param irq interrupt source number
+ * @param enable enable as wake-up if equal to non-zero
+ * @return This function returns 0 on success.
+ */
+static int mvebu_gpio_set_wake_irq(struct irq_data *d, unsigned int enable)
+{
+ struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d);
+ struct mvebu_gpio_chip *mvchip = gc->private;
+ int irq;
+ int bank;
+
+ bank = d->hwirq % 8;
+ irq = mvchip->bank_irq[bank];
+
+ if (enable)
+ enable_irq_wake(irq);
+ else
+ disable_irq_wake(irq);
+
+ return 0;
+}
+
+/*
* Functions implementing the pwm_chip methods
*/
static struct mvebu_pwm *to_mvebu_pwm(struct pwm_chip *chip)
@@ -1219,7 +1247,7 @@ static int mvebu_gpio_probe(struct platf
err = irq_alloc_domain_generic_chips(
mvchip->domain, ngpios, 2, np->name, handle_level_irq,
- IRQ_NOREQUEST | IRQ_NOPROBE | IRQ_LEVEL, 0, 0);
+ IRQ_NOREQUEST | IRQ_NOPROBE | IRQ_LEVEL, 0, IRQ_GC_INIT_NESTED_LOCK);
if (err) {
dev_err(&pdev->dev, "couldn't allocate irq chips %s (DT).\n",
mvchip->chip.label);
@@ -1237,6 +1265,8 @@ static int mvebu_gpio_probe(struct platf
ct->chip.irq_mask = mvebu_gpio_level_irq_mask;
ct->chip.irq_unmask = mvebu_gpio_level_irq_unmask;
ct->chip.irq_set_type = mvebu_gpio_irq_set_type;
+ ct->chip.irq_set_wake = mvebu_gpio_set_wake_irq;
+ ct->chip.flags = IRQCHIP_SET_TYPE_MASKED | IRQCHIP_MASK_ON_SUSPEND;
ct->chip.name = mvchip->chip.label;
ct = &gc->chip_types[1];
@@ -1245,6 +1275,8 @@ static int mvebu_gpio_probe(struct platf
ct->chip.irq_mask = mvebu_gpio_edge_irq_mask;
ct->chip.irq_unmask = mvebu_gpio_edge_irq_unmask;
ct->chip.irq_set_type = mvebu_gpio_irq_set_type;
+ ct->chip.irq_set_wake = mvebu_gpio_set_wake_irq;
+ ct->chip.flags = IRQCHIP_SET_TYPE_MASKED | IRQCHIP_MASK_ON_SUSPEND;
ct->handler = handle_edge_irq;
ct->chip.name = mvchip->chip.label;
@@ -1260,6 +1292,7 @@ static int mvebu_gpio_probe(struct platf
continue;
irq_set_chained_handler_and_data(irq, mvebu_gpio_irq_handler,
mvchip);
+ mvchip->bank_irq[i] = irq;
}
return 0;

View File

@@ -0,0 +1,419 @@
From e4728fcf779c37d1bcbd4b6505c9b40d4bb9ff48 Mon Sep 17 00:00:00 2001
From: Heisath <jannis@imserv.org>
Date: Thu, 03 Jun 2021 10:56:53 +0200
Subject: [PATCH] Removes the hardcoded timer assignment of timers to pwm controllers
This allows to use more than one pwm per gpio bank.
Original patch by helios4 team, updated to work on LK5.11+
Signed-off-by: Heisath <jannis@imserv.org>
---
diff --git a/drivers/gpio/gpio-mvebu.c b/drivers/gpio/gpio-mvebu.c
index bad399e3f..d3fdaf177 100644
--- a/drivers/gpio/gpio-mvebu.c
+++ b/drivers/gpio/gpio-mvebu.c
@@ -97,21 +97,42 @@
#define MVEBU_MAX_GPIO_PER_BANK 32
-struct mvebu_pwm {
+enum mvebu_pwm_ctrl {
+ MVEBU_PWM_CTRL_SET_A = 0,
+ MVEBU_PWM_CTRL_SET_B,
+ MVEBU_PWM_CTRL_MAX
+};
+
+struct mvebu_pwmchip {
struct regmap *regs;
u32 offset;
unsigned long clk_rate;
- struct gpio_desc *gpiod;
- struct pwm_chip chip;
spinlock_t lock;
- struct mvebu_gpio_chip *mvchip;
+ bool in_use;
/* Used to preserve GPIO/PWM registers across suspend/resume */
- u32 blink_select;
u32 blink_on_duration;
u32 blink_off_duration;
};
+struct mvebu_pwm_chip_drv {
+ enum mvebu_pwm_ctrl ctrl;
+ struct gpio_desc *gpiod;
+ bool master;
+};
+
+struct mvebu_pwm {
+ struct pwm_chip chip;
+ struct mvebu_gpio_chip *mvchip;
+ struct mvebu_pwmchip controller;
+ enum mvebu_pwm_ctrl default_counter;
+
+ /* Used to preserve GPIO/PWM registers across suspend/resume */
+ u32 blink_select;
+};
+
+static struct mvebu_pwmchip *mvebu_pwm_list[MVEBU_PWM_CTRL_MAX];
+
struct mvebu_gpio_chip {
struct gpio_chip chip;
struct regmap *regs;
@@ -288,12 +309,12 @@ mvebu_gpio_write_level_mask(struct mvebu_gpio_chip *mvchip, u32 val)
* Functions returning offsets of individual registers for a given
* PWM controller.
*/
-static unsigned int mvebu_pwmreg_blink_on_duration(struct mvebu_pwm *mvpwm)
+static unsigned int mvebu_pwmreg_blink_on_duration(struct mvebu_pwmchip *mvpwm)
{
return mvpwm->offset + PWM_BLINK_ON_DURATION_OFF;
}
-static unsigned int mvebu_pwmreg_blink_off_duration(struct mvebu_pwm *mvpwm)
+static unsigned int mvebu_pwmreg_blink_off_duration(struct mvebu_pwmchip *mvpwm)
{
return mvpwm->offset + PWM_BLINK_OFF_DURATION_OFF;
}
@@ -653,39 +674,84 @@ static int mvebu_pwm_request(struct pwm_chip *chip, struct pwm_device *pwm)
struct mvebu_pwm *mvpwm = to_mvebu_pwm(chip);
struct mvebu_gpio_chip *mvchip = mvpwm->mvchip;
struct gpio_desc *desc;
+ enum mvebu_pwm_ctrl id;
unsigned long flags;
int ret = 0;
+ struct mvebu_pwm_chip_drv *chip_data;
- spin_lock_irqsave(&mvpwm->lock, flags);
+ spin_lock_irqsave(&mvpwm->controller.lock, flags);
- if (mvpwm->gpiod) {
+ if (pwm->chip_data || (mvchip->blink_en_reg & BIT(pwm->hwpwm))) {
ret = -EBUSY;
- } else {
- desc = gpiochip_request_own_desc(&mvchip->chip,
- pwm->hwpwm, "mvebu-pwm",
- GPIO_ACTIVE_HIGH,
- GPIOD_OUT_LOW);
- if (IS_ERR(desc)) {
- ret = PTR_ERR(desc);
- goto out;
- }
+ goto out;
+ }
+
+
+
+ desc = gpiochip_request_own_desc(&mvchip->chip,
+ pwm->hwpwm, "mvebu-pwm",
+ GPIO_ACTIVE_HIGH,
+ GPIOD_OUT_LOW);
+
+ if (IS_ERR(desc)) {
+ ret = PTR_ERR(desc);
+ goto out;
+ }
+
+ ret = gpiod_direction_output(desc, 0);
+ if (ret) {
+ gpiochip_free_own_desc(desc);
+ goto out;
+ }
- mvpwm->gpiod = desc;
+ chip_data = kzalloc(sizeof(struct mvebu_pwm_chip_drv), GFP_KERNEL);
+ if (!chip_data) {
+ gpiochip_free_own_desc(desc);
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ for (id = MVEBU_PWM_CTRL_SET_A; id < MVEBU_PWM_CTRL_MAX; id++) {
+ if (!mvebu_pwm_list[id]->in_use) {
+ chip_data->ctrl = id;
+ chip_data->master = true;
+ mvebu_pwm_list[id]->in_use = true;
+ break;
+ }
}
+
+ if (!chip_data->master)
+ chip_data->ctrl = mvpwm->default_counter;
+
+ regmap_update_bits(mvchip->regs, GPIO_BLINK_CNT_SELECT_OFF + mvchip->offset,
+ BIT(pwm->hwpwm), chip_data->ctrl ? BIT(pwm->hwpwm) : 0);
+
+ chip_data->gpiod = desc;
+ pwm->chip_data = chip_data;
+
+ regmap_read(mvchip->regs, GPIO_BLINK_CNT_SELECT_OFF + mvchip->offset,
+ &mvpwm->blink_select);
+
out:
- spin_unlock_irqrestore(&mvpwm->lock, flags);
+ spin_unlock_irqrestore(&mvpwm->controller.lock, flags);
return ret;
}
static void mvebu_pwm_free(struct pwm_chip *chip, struct pwm_device *pwm)
{
struct mvebu_pwm *mvpwm = to_mvebu_pwm(chip);
+ struct mvebu_pwm_chip_drv *chip_data = (struct mvebu_pwm_chip_drv*) pwm->chip_data;
unsigned long flags;
- spin_lock_irqsave(&mvpwm->lock, flags);
- gpiochip_free_own_desc(mvpwm->gpiod);
- mvpwm->gpiod = NULL;
- spin_unlock_irqrestore(&mvpwm->lock, flags);
+ spin_lock_irqsave(&mvpwm->controller.lock, flags);
+ if (chip_data->master)
+ mvebu_pwm_list[chip_data->ctrl]->in_use = false;
+
+
+ gpiochip_free_own_desc(chip_data->gpiod);
+ kfree(chip_data);
+ pwm->chip_data = NULL;
+ spin_unlock_irqrestore(&mvpwm->controller.lock, flags);
}
static void mvebu_pwm_get_state(struct pwm_chip *chip,
@@ -693,29 +759,36 @@ static void mvebu_pwm_get_state(struct pwm_chip *chip,
struct pwm_state *state) {
struct mvebu_pwm *mvpwm = to_mvebu_pwm(chip);
+ struct mvebu_pwm_chip_drv *chip_data = (struct mvebu_pwm_chip_drv*) pwm->chip_data;
+ struct mvebu_pwmchip *controller;
struct mvebu_gpio_chip *mvchip = mvpwm->mvchip;
unsigned long long val;
unsigned long flags;
u32 u;
- spin_lock_irqsave(&mvpwm->lock, flags);
+ if (chip_data)
+ controller = mvebu_pwm_list[chip_data->ctrl];
+ else
+ controller = &mvpwm->controller;
+
+ spin_lock_irqsave(&controller->lock, flags);
- regmap_read(mvpwm->regs, mvebu_pwmreg_blink_on_duration(mvpwm), &u);
+ regmap_read(controller->regs, mvebu_pwmreg_blink_on_duration(controller), &u);
/* Hardware treats zero as 2^32. See mvebu_pwm_apply(). */
if (u > 0)
val = u;
else
val = UINT_MAX + 1ULL;
state->duty_cycle = DIV_ROUND_UP_ULL(val * NSEC_PER_SEC,
- mvpwm->clk_rate);
+ controller->clk_rate);
- regmap_read(mvpwm->regs, mvebu_pwmreg_blink_off_duration(mvpwm), &u);
+ regmap_read(controller->regs, mvebu_pwmreg_blink_off_duration(controller), &u);
/* period = on + off duration */
if (u > 0)
val += u;
else
val += UINT_MAX + 1ULL;
- state->period = DIV_ROUND_UP_ULL(val * NSEC_PER_SEC, mvpwm->clk_rate);
+ state->period = DIV_ROUND_UP_ULL(val * NSEC_PER_SEC, controller->clk_rate);
regmap_read(mvchip->regs, GPIO_BLINK_EN_OFF + mvchip->offset, &u);
if (u)
@@ -796,15 +796,17 @@ static void mvebu_pwm_get_state(struct pwm_chip *chip,
else
state->enabled = false;
- spin_unlock_irqrestore(&mvpwm->lock, flags);
+ spin_unlock_irqrestore(&controller->lock, flags);
return 0;
}
static int mvebu_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
const struct pwm_state *state)
{
struct mvebu_pwm *mvpwm = to_mvebu_pwm(chip);
+ struct mvebu_pwm_chip_drv *chip_data = (struct mvebu_pwm_chip_drv*) pwm->chip_data;
+ struct mvebu_pwmchip *controller;
struct mvebu_gpio_chip *mvchip = mvpwm->mvchip;
unsigned long long val;
unsigned long flags;
@@ -811,7 +813,12 @@ static int mvebu_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
if (state->polarity != PWM_POLARITY_NORMAL)
return -EINVAL;
- val = (unsigned long long) mvpwm->clk_rate * state->duty_cycle;
+ if (chip_data)
+ controller = mvebu_pwm_list[chip_data->ctrl];
+ else
+ controller = &mvpwm->controller;
+
+ val = (unsigned long long) controller->clk_rate * state->duty_cycle;
do_div(val, NSEC_PER_SEC);
if (val > UINT_MAX + 1ULL)
return -EINVAL;
@@ -750,7 +830,7 @@ static int mvebu_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
else
on = 1;
- val = (unsigned long long) mvpwm->clk_rate * state->period;
+ val = (unsigned long long) controller->clk_rate * state->period;
do_div(val, NSEC_PER_SEC);
val -= on;
if (val > UINT_MAX + 1ULL)
@@ -762,16 +842,16 @@ static int mvebu_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
else
off = 1;
- spin_lock_irqsave(&mvpwm->lock, flags);
+ spin_lock_irqsave(&controller->lock, flags);
- regmap_write(mvpwm->regs, mvebu_pwmreg_blink_on_duration(mvpwm), on);
- regmap_write(mvpwm->regs, mvebu_pwmreg_blink_off_duration(mvpwm), off);
+ regmap_write(controller->regs, mvebu_pwmreg_blink_on_duration(controller), on);
+ regmap_write(controller->regs, mvebu_pwmreg_blink_off_duration(controller), off);
if (state->enabled)
mvebu_gpio_blink(&mvchip->chip, pwm->hwpwm, 1);
else
mvebu_gpio_blink(&mvchip->chip, pwm->hwpwm, 0);
- spin_unlock_irqrestore(&mvpwm->lock, flags);
+ spin_unlock_irqrestore(&controller->lock, flags);
return 0;
}
@@ -787,25 +867,27 @@ static const struct pwm_ops mvebu_pwm_ops = {
static void __maybe_unused mvebu_pwm_suspend(struct mvebu_gpio_chip *mvchip)
{
struct mvebu_pwm *mvpwm = mvchip->mvpwm;
+ struct mvebu_pwmchip *controller = &mvpwm->controller;
regmap_read(mvchip->regs, GPIO_BLINK_CNT_SELECT_OFF + mvchip->offset,
&mvpwm->blink_select);
- regmap_read(mvpwm->regs, mvebu_pwmreg_blink_on_duration(mvpwm),
- &mvpwm->blink_on_duration);
- regmap_read(mvpwm->regs, mvebu_pwmreg_blink_off_duration(mvpwm),
- &mvpwm->blink_off_duration);
+ regmap_read(controller->regs, mvebu_pwmreg_blink_on_duration(controller),
+ &controller->blink_on_duration);
+ regmap_read(controller->regs, mvebu_pwmreg_blink_off_duration(controller),
+ &controller->blink_off_duration);
}
static void __maybe_unused mvebu_pwm_resume(struct mvebu_gpio_chip *mvchip)
{
struct mvebu_pwm *mvpwm = mvchip->mvpwm;
+ struct mvebu_pwmchip *controller = &mvpwm->controller;
regmap_write(mvchip->regs, GPIO_BLINK_CNT_SELECT_OFF + mvchip->offset,
mvpwm->blink_select);
- regmap_write(mvpwm->regs, mvebu_pwmreg_blink_on_duration(mvpwm),
- mvpwm->blink_on_duration);
- regmap_write(mvpwm->regs, mvebu_pwmreg_blink_off_duration(mvpwm),
- mvpwm->blink_off_duration);
+ regmap_write(controller->regs, mvebu_pwmreg_blink_on_duration(controller),
+ controller->blink_on_duration);
+ regmap_write(controller->regs, mvebu_pwmreg_blink_off_duration(controller),
+ controller->blink_off_duration);
}
static int mvebu_pwm_probe(struct platform_device *pdev,
@@ -902,6 +902,7 @@ static int mvebu_pwm_probe(struct platform_device *pdev,
void __iomem *base;
u32 offset;
u32 set;
+ enum mvebu_pwm_ctrl ctrl_set;
if (mvchip->soc_variant == MVEBU_GPIO_SOC_VARIANT_A8K) {
int ret = of_property_read_u32(dev->of_node,
@@ -844,54 +920,39 @@ static int mvebu_pwm_probe(struct platform_device *pdev,
mvpwm = devm_kzalloc(dev, sizeof(struct mvebu_pwm), GFP_KERNEL);
if (!mvpwm)
return -ENOMEM;
+
mvchip->mvpwm = mvpwm;
mvpwm->mvchip = mvchip;
- mvpwm->offset = offset;
+
+
+ base = devm_platform_ioremap_resource_byname(pdev, "pwm");
+ if (IS_ERR(base))
+ return PTR_ERR(base);
- if (mvchip->soc_variant == MVEBU_GPIO_SOC_VARIANT_A8K) {
- mvpwm->regs = mvchip->regs;
+ mvpwm->controller.regs = devm_regmap_init_mmio(&pdev->dev, base,
+ &mvebu_gpio_regmap_config);
+ if (IS_ERR(mvpwm->controller.regs))
+ return PTR_ERR(mvpwm->controller.regs);
- switch (mvchip->offset) {
- case AP80X_GPIO0_OFF_A8K:
- case CP11X_GPIO0_OFF_A8K:
- /* Blink counter A */
- set = 0;
- break;
- case CP11X_GPIO1_OFF_A8K:
- /* Blink counter B */
- set = U32_MAX;
- mvpwm->offset += PWM_BLINK_COUNTER_B_OFF;
- break;
- default:
- return -EINVAL;
- }
+ /*
+ * Use set A for lines of GPIO chip with id 0, B for GPIO chip
+ * with id 1. Don't allow further GPIO chips to be used for PWM.
+ */
+ if (id == 0) {
+ set = 0;
+ ctrl_set = MVEBU_PWM_CTRL_SET_A;
+ } else if (id == 1) {
+ set = U32_MAX;
+ ctrl_set = MVEBU_PWM_CTRL_SET_B;
} else {
- base = devm_platform_ioremap_resource_byname(pdev, "pwm");
- if (IS_ERR(base))
- return PTR_ERR(base);
-
- mvpwm->regs = devm_regmap_init_mmio(&pdev->dev, base,
- &mvebu_gpio_regmap_config);
- if (IS_ERR(mvpwm->regs))
- return PTR_ERR(mvpwm->regs);
-
- /*
- * Use set A for lines of GPIO chip with id 0, B for GPIO chip
- * with id 1. Don't allow further GPIO chips to be used for PWM.
- */
- if (id == 0)
- set = 0;
- else if (id == 1)
- set = U32_MAX;
- else
- return -EINVAL;
+ return -EINVAL;
}
regmap_write(mvchip->regs,
GPIO_BLINK_CNT_SELECT_OFF + mvchip->offset, set);
- mvpwm->clk_rate = clk_get_rate(mvchip->clk);
- if (!mvpwm->clk_rate) {
+ mvpwm->controller.clk_rate = clk_get_rate(mvchip->clk);
+ if (!mvpwm->controller.clk_rate) {
dev_err(dev, "failed to get clock rate\n");
return -EINVAL;
}
@@ -907,7 +968,10 @@ static int mvebu_pwm_probe(struct platform_device *pdev,
*/
mvpwm->chip.base = -1;
- spin_lock_init(&mvpwm->lock);
+ spin_lock_init(&mvpwm->controller.lock);
+
+ mvpwm->default_counter = ctrl_set;
+ mvebu_pwm_list[ctrl_set] = &mvpwm->controller;
return pwmchip_add(&mvpwm->chip);
}

View File

@@ -0,0 +1,21 @@
--- a/arch/arm/boot/dts/armada-388-helios4.dts
+++ b/arch/arm/boot/dts/armada-388-helios4.dts
@@ -84,6 +84,18 @@
};
};
+ gpio-keys {
+ compatible = "gpio-keys";
+ pinctrl-0 = <&microsom_phy0_int_pins>;
+
+ wol {
+ label = "Wake-On-LAN";
+ linux,code = <KEY_WAKEUP>;
+ gpios = <&gpio0 18 GPIO_ACTIVE_LOW>;
+ wakeup-source;
+ };
+ };
+
io-leds {
compatible = "gpio-leds";
sata1-led {

View File

@@ -0,0 +1,12 @@
--- a/scripts/Makefile.lib
+++ b/scripts/Makefile.lib
@@ -277,6 +277,9 @@ quiet_cmd_gzip = GZIP $@
DTC ?= $(objtree)/scripts/dtc/dtc
DTC_FLAGS += -Wno-interrupt_provider
+# Enable overlay support
+DTC_FLAGS += -@
+
# Disable noisy checks by default
ifeq ($(findstring 1,$(KBUILD_EXTRA_WARN)),)
DTC_FLAGS += -Wno-unit_address_vs_reg \

View File

@@ -0,0 +1,10 @@
--- a/arch/arm/boot/dts/armada-38x-solidrun-microsom.dtsi
+++ b/arch/arm/boot/dts/armada-38x-solidrun-microsom.dtsi
@@ -107,6 +107,7 @@
compatible = "w25q32", "jedec,spi-nor";
reg = <0>; /* Chip select 0 */
spi-max-frequency = <3000000>;
+ status = "disabled";
};
};

View File

@@ -0,0 +1,11 @@
--- a/arch/arm/mm/dma-mapping.c
+++ b/arch/arm/mm/dma-mapping.c
@@ -315,7 +315,7 @@ static void *__alloc_remap_buffer(struct
pgprot_t prot, struct page **ret_page,
const void *caller, bool want_vaddr);
-#define DEFAULT_DMA_COHERENT_POOL_SIZE SZ_256K
+#define DEFAULT_DMA_COHERENT_POOL_SIZE SZ_2M
static struct gen_pool *atomic_pool __ro_after_init;
static size_t atomic_pool_size __initdata = DEFAULT_DMA_COHERENT_POOL_SIZE;

View File

@@ -0,0 +1,70 @@
--- a/drivers/net/wireless/ath/regd.c
+++ b/drivers/net/wireless/ath/regd.c
@@ -50,12 +50,9 @@ static int __ath_regd_init(struct ath_re
#define ATH_5GHZ_5725_5850 REG_RULE(5725-10, 5850+10, 80, 0, 30,\
NL80211_RRF_NO_IR)
-#define ATH_2GHZ_ALL ATH_2GHZ_CH01_11, \
- ATH_2GHZ_CH12_13, \
- ATH_2GHZ_CH14
+#define ATH_2GHZ_ALL REG_RULE(2400, 2483, 40, 0, 30, 0)
-#define ATH_5GHZ_ALL ATH_5GHZ_5150_5350, \
- ATH_5GHZ_5470_5850
+#define ATH_5GHZ_ALL REG_RULE(5140, 5860, 40, 0, 30, 0)
/* This one skips what we call "mid band" */
#define ATH_5GHZ_NO_MIDBAND ATH_5GHZ_5150_5350, \
@@ -77,9 +74,8 @@ static const struct ieee80211_regdomain
.n_reg_rules = 4,
.alpha2 = "99",
.reg_rules = {
- ATH_2GHZ_CH01_11,
- ATH_2GHZ_CH12_13,
- ATH_5GHZ_NO_MIDBAND,
+ ATH_2GHZ_ALL,
+ ATH_5GHZ_ALL,
}
};
@@ -88,8 +84,8 @@ static const struct ieee80211_regdomain
.n_reg_rules = 3,
.alpha2 = "99",
.reg_rules = {
- ATH_2GHZ_CH01_11,
- ATH_5GHZ_NO_MIDBAND,
+ ATH_2GHZ_ALL,
+ ATH_5GHZ_ALL,
}
};
@@ -98,7 +94,7 @@ static const struct ieee80211_regdomain
.n_reg_rules = 3,
.alpha2 = "99",
.reg_rules = {
- ATH_2GHZ_CH01_11,
+ ATH_2GHZ_ALL,
ATH_5GHZ_ALL,
}
};
@@ -108,8 +104,7 @@ static const struct ieee80211_regdomain
.n_reg_rules = 4,
.alpha2 = "99",
.reg_rules = {
- ATH_2GHZ_CH01_11,
- ATH_2GHZ_CH12_13,
+ ATH_2GHZ_ALL,
ATH_5GHZ_ALL,
}
};
@@ -258,9 +253,7 @@ static bool ath_is_radar_freq(u16 center
struct ath_regulatory *reg)
{
- if (reg->country_code == CTRY_INDIA)
- return (center_freq >= 5500 && center_freq <= 5700);
- return (center_freq >= 5260 && center_freq <= 5700);
+ return false;
}
static void ath_force_clear_no_ir_chan(struct wiphy *wiphy,

View File

@@ -0,0 +1,39 @@
From 219f80b5cc03dab87fd05210b95c0b1a5afa8d33 Mon Sep 17 00:00:00 2001
From: Russell King <rmk+kernel@armlinux.org.uk>
Date: Thu, 14 Jul 2016 15:31:42 +0100
Subject: ARM: dts: armada388-clearfog: use 1000BaseX mode for 88e6176 switch
Use 1000BaseX mode for the 88e6176 switch, which allows mvneta to
negotiate correctly without needing to be forced.
Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
---
arch/arm/boot/dts/armada-388-clearfog.dts | 10 ++--------
1 file changed, 2 insertions(+), 8 deletions(-)
--- a/arch/arm/boot/dts/armada-388-clearfog.dts
+++ b/arch/arm/boot/dts/armada-388-clearfog.dts
@@ -47,10 +47,8 @@
&eth1 {
/* ethernet@30000 */
- fixed-link {
- speed = <1000>;
- full-duplex;
- };
+ phy-mode = "1000base-x";
+ managed = "in-band-status";
};
&expander0 {
@@ -131,10 +129,6 @@
reg = <5>;
label = "cpu";
ethernet = <&eth1>;
- fixed-link {
- speed = <1000>;
- full-duplex;
- };
};
port@6 {

View File

@@ -1 +1 @@
archive/mvebu-6.1
archive/mvebu-6.2