mirror of
https://github.com/armbian/build
synced 2025-09-24 19:47:06 +07:00
Add patches to 6.10 folder
This commit is contained in:
@@ -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, ®32);
|
||||
+ 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, ®32);
|
||||
+ 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, ®16);
|
||||
+ 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 int pcie_retrain_link(struct pcie_link_state *link)
|
||||
{
|
||||
struct pci_dev *parent = link->pdev;
|
||||
int rc;
|
||||
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;
|
||||
+ }
|
||||
+
|
||||
/*
|
||||
* Ensure the updated LNKCTL parameters are used during link
|
||||
* training by checking that there is no ongoing link training to
|
||||
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
|
||||
@@ -0,0 +1,136 @@
|
||||
Index: 6.1__mvebu__armhf/drivers/ata/Kconfig
|
||||
===================================================================
|
||||
--- 6.1__mvebu__armhf.orig/drivers/ata/Kconfig
|
||||
+++ 6.1__mvebu__armhf/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
|
||||
Index: 6.1__mvebu__armhf/drivers/ata/libata-core.c
|
||||
===================================================================
|
||||
--- 6.1__mvebu__armhf.orig/drivers/ata/libata-core.c
|
||||
+++ 6.1__mvebu__armhf/drivers/ata/libata-core.c
|
||||
@@ -663,6 +663,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
|
||||
* @qc: Metadata associated with the taskfile to build
|
||||
@@ -4813,6 +4826,10 @@ void ata_qc_issue(struct ata_queued_cmd
|
||||
struct ata_link *link = qc->dev->link;
|
||||
u8 prot = qc->tf.protocol;
|
||||
|
||||
+#ifdef CONFIG_ATA_LEDS
|
||||
+ ata_led_act(ap);
|
||||
+#endif
|
||||
+
|
||||
/* Make sure only one non-NCQ command is outstanding. */
|
||||
WARN_ON_ONCE(ata_tag_valid(link->active_tag));
|
||||
|
||||
@@ -5328,6 +5345,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;
|
||||
@@ -5363,6 +5383,12 @@ static void ata_host_release(struct kref
|
||||
|
||||
kfree(ap->slave_link);
|
||||
kfree(ap->ncq_sense_buf);
|
||||
+#ifdef CONFIG_ATA_LEDS
|
||||
+ if (ap->ledtrig) {
|
||||
+ led_trigger_unregister(ap->ledtrig);
|
||||
+ kfree(ap->ledtrig);
|
||||
+ };
|
||||
+#endif
|
||||
kfree(ap);
|
||||
host->ports[i] = NULL;
|
||||
}
|
||||
@@ -5765,7 +5791,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]);
|
||||
Index: 6.1__mvebu__armhf/include/linux/libata.h
|
||||
===================================================================
|
||||
--- 6.1__mvebu__armhf.orig/include/linux/libata.h
|
||||
+++ 6.1__mvebu__armhf/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
|
||||
@@ -857,6 +860,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;
|
||||
};
|
||||
@@ -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
|
||||
@@ -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;
|
||||
@@ -0,0 +1,411 @@
|
||||
Removes the hardcoded timer assignment of timers to pwm controllers.
|
||||
This allows to use more than one pwm per gpio bank.
|
||||
|
||||
Original patch with chip_data interface by Heisath <jannis@imserv.org>
|
||||
|
||||
Link: https://wiki.kobol.io/helios4/pwm/#patch-requirement
|
||||
Co-developed-by: Yureka Lilian <yuka@yuka.dev>
|
||||
Signed-off-by: Yureka Lilian <yuka@yuka.dev>
|
||||
Signed-off-by: Finn Behrens <me@kloenk.de>
|
||||
---
|
||||
drivers/gpio/gpio-mvebu.c | 223 ++++++++++++++++++++++++--------------
|
||||
1 file changed, 139 insertions(+), 84 deletions(-)
|
||||
|
||||
diff --git a/drivers/gpio/gpio-mvebu.c b/drivers/gpio/gpio-mvebu.c
|
||||
index a13f3c18ccd4..303ea3be0b69 100644
|
||||
--- a/drivers/gpio/gpio-mvebu.c
|
||||
+++ b/drivers/gpio/gpio-mvebu.c
|
||||
@@ -94,21 +94,43 @@
|
||||
|
||||
#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_controller;
|
||||
+
|
||||
+ /* Used to preserve GPIO/PWM registers across suspend/resume */
|
||||
+ u32 blink_select;
|
||||
+ struct mvebu_pwm_chip_drv drv[];
|
||||
+};
|
||||
+
|
||||
+static struct mvebu_pwmchip *mvebu_pwm_list[MVEBU_PWM_CTRL_MAX];
|
||||
+
|
||||
struct mvebu_gpio_chip {
|
||||
struct gpio_chip chip;
|
||||
struct regmap *regs;
|
||||
@@ -285,12 +307,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;
|
||||
}
|
||||
@@ -623,39 +645,71 @@ 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 *drv = &mvpwm->drv[pwm->hwpwm];
|
||||
|
||||
- spin_lock_irqsave(&mvpwm->lock, flags);
|
||||
+ spin_lock_irqsave(&mvpwm->controller.lock, flags);
|
||||
|
||||
- if (mvpwm->gpiod) {
|
||||
+ if (drv->gpiod || (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;
|
||||
+ }
|
||||
|
||||
- mvpwm->gpiod = desc;
|
||||
+ ret = gpiod_direction_output(desc, 0);
|
||||
+ if (ret) {
|
||||
+ gpiochip_free_own_desc(desc);
|
||||
+ goto out;
|
||||
}
|
||||
+
|
||||
+ for (id = MVEBU_PWM_CTRL_SET_A; id < MVEBU_PWM_CTRL_MAX; id++) {
|
||||
+ if (!mvebu_pwm_list[id]->in_use) {
|
||||
+ drv->ctrl = id;
|
||||
+ drv->master = true;
|
||||
+ mvebu_pwm_list[id]->in_use = true;
|
||||
+ break;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ if (!drv->master)
|
||||
+ drv->ctrl = mvpwm->default_controller;
|
||||
+
|
||||
+ regmap_update_bits(mvchip->regs, GPIO_BLINK_CNT_SELECT_OFF + mvchip->offset,
|
||||
+ BIT(pwm->hwpwm), drv->ctrl ? BIT(pwm->hwpwm) : 0);
|
||||
+
|
||||
+ drv->gpiod = desc;
|
||||
+
|
||||
+ 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 *drv = &mvpwm->drv[pwm->hwpwm];
|
||||
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 (drv->master)
|
||||
+ mvebu_pwm_list[drv->ctrl]->in_use = false;
|
||||
+
|
||||
+ gpiochip_free_own_desc(drv->gpiod);
|
||||
+ memset(drv, 0, sizeof(struct mvebu_pwm_chip_drv));
|
||||
+
|
||||
+ spin_unlock_irqrestore(&mvpwm->controller.lock, flags);
|
||||
}
|
||||
|
||||
static int mvebu_pwm_get_state(struct pwm_chip *chip,
|
||||
@@ -665,28 +719,35 @@ static int mvebu_pwm_get_state(struct pwm_chip *chip,
|
||||
|
||||
struct mvebu_pwm *mvpwm = to_mvebu_pwm(chip);
|
||||
struct mvebu_gpio_chip *mvchip = mvpwm->mvchip;
|
||||
+ struct mvebu_pwm_chip_drv *drv = &mvpwm->drv[pwm->hwpwm];
|
||||
+ struct mvebu_pwmchip *controller;
|
||||
unsigned long long val;
|
||||
unsigned long flags;
|
||||
u32 u;
|
||||
|
||||
- spin_lock_irqsave(&mvpwm->lock, flags);
|
||||
+ if (drv->gpiod)
|
||||
+ controller = mvebu_pwm_list[drv->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)
|
||||
@@ -694,7 +755,7 @@ static int 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;
|
||||
}
|
||||
@@ -703,6 +764,8 @@ 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 *drv = &mvpwm->drv[pwm->hwpwm];
|
||||
+ struct mvebu_pwmchip *controller;
|
||||
struct mvebu_gpio_chip *mvchip = mvpwm->mvchip;
|
||||
unsigned long long val;
|
||||
unsigned long flags;
|
||||
@@ -711,7 +774,11 @@ 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 (drv->gpiod)
|
||||
+ controller = mvebu_pwm_list[drv->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;
|
||||
@@ -726,7 +793,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)
|
||||
@@ -738,16 +805,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;
|
||||
}
|
||||
@@ -762,25 +829,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,
|
||||
@@ -792,6 +861,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,
|
||||
@@ -813,57 +883,39 @@ static int mvebu_pwm_probe(struct platform_device *pdev,
|
||||
if (IS_ERR(mvchip->clk))
|
||||
return PTR_ERR(mvchip->clk);
|
||||
|
||||
- mvpwm = devm_kzalloc(dev, sizeof(struct mvebu_pwm), GFP_KERNEL);
|
||||
+ mvpwm = devm_kzalloc(dev, struct_size(mvpwm, drv, mvchip->chip.ngpio), GFP_KERNEL);
|
||||
if (!mvpwm)
|
||||
return -ENOMEM;
|
||||
mvchip->mvpwm = mvpwm;
|
||||
mvpwm->mvchip = mvchip;
|
||||
- mvpwm->offset = offset;
|
||||
|
||||
- if (mvchip->soc_variant == MVEBU_GPIO_SOC_VARIANT_A8K) {
|
||||
- mvpwm->regs = mvchip->regs;
|
||||
+ base = devm_platform_ioremap_resource_byname(pdev, "pwm");
|
||||
+ if (IS_ERR(base))
|
||||
+ return PTR_ERR(base);
|
||||
+ 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;
|
||||
- }
|
||||
+ /*
|
||||
+ * User 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;
|
||||
}
|
||||
@@ -872,7 +924,10 @@ static int mvebu_pwm_probe(struct platform_device *pdev,
|
||||
mvpwm->chip.ops = &mvebu_pwm_ops;
|
||||
mvpwm->chip.npwm = mvchip->chip.ngpio;
|
||||
|
||||
- spin_lock_init(&mvpwm->lock);
|
||||
+ spin_lock_init(&mvpwm->controller.lock);
|
||||
+
|
||||
+ mvpwm->default_controller = ctrl_set;
|
||||
+ mvebu_pwm_list[ctrl_set] = &mvpwm->controller;
|
||||
|
||||
return devm_pwmchip_add(dev, &mvpwm->chip);
|
||||
}
|
||||
--
|
||||
2.43.0
|
||||
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
--- a/arch/arm/boot/dts/marvell/armada-388-helios4.dts
|
||||
+++ b/arch/arm/boot/dts/marvell/armada-388-helios4.dts
|
||||
@@ -84,6 +84,18 @@
|
||||
};
|
||||
};
|
||||
|
||||
+ gpio-keys {
|
||||
+ compatible = "gpio-keys";
|
||||
+ pinctrl-0 = <µsom_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 {
|
||||
@@ -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 \
|
||||
@@ -0,0 +1,10 @@
|
||||
--- a/arch/arm/boot/dts/marvell/armada-38x-solidrun-microsom.dtsi
|
||||
+++ b/arch/arm/boot/dts/marvell/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";
|
||||
};
|
||||
};
|
||||
|
||||
@@ -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;
|
||||
@@ -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,
|
||||
Reference in New Issue
Block a user