Compare commits

...

3 Commits

Author SHA1 Message Date
Heisath
3426ba3b9b Move to 6.8 2024-05-14 18:43:06 +02:00
lanefu
b16aff0787 Merge branch 'main' into mvebu-rmk 2024-05-13 14:58:04 -04:00
Heisath
ef933e875b Add mvebu 6.7 patches, move to rmk tree 2024-01-30 19:56:28 +01:00
13 changed files with 1407 additions and 43 deletions

File diff suppressed because it is too large Load Diff

View File

@@ -29,7 +29,13 @@ case $BRANCH in
edge)
declare -g KERNEL_MAJOR_MINOR="6.7" # Major and minor versions of this kernel.
declare -g KERNEL_MAJOR_MINOR="6.8" # Major and minor versions of this kernel.
declare -g KERNEL_SKIP_MAKEFILE_VERSION="yes" # Armbian patches change the version here, so no use having it in the version string.
declare -g KERNELSOURCE="git://git.armlinux.org.uk/~rmk/linux-arm.git"
declare -g KERNELBRANCH="branch:clearfog"
declare -g KERNELDIR="linux-clearfog"
;;
esac

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 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

View File

@@ -0,0 +1,35 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: John Doe <john.doe@somewhere.on.planet>
Date: Tue, 30 Jan 2024 19:44:13 +0100
Subject: Patching kernel mvebu files
drivers/net/dsa/mv88e6xxx/mv88e6xxx_debugfs.cDisable dsa-port slave print
Signed-off-by: John Doe <john.doe@somewhere.on.planet>
---
drivers/net/dsa/mv88e6xxx/mv88e6xxx_debugfs.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/drivers/net/dsa/mv88e6xxx/mv88e6xxx_debugfs.c b/drivers/net/dsa/mv88e6xxx/mv88e6xxx_debugfs.c
index 4005a4760884..a5cba5a2965a 100644
--- a/drivers/net/dsa/mv88e6xxx/mv88e6xxx_debugfs.c
+++ b/drivers/net/dsa/mv88e6xxx/mv88e6xxx_debugfs.c
@@ -218,14 +218,14 @@ static int mv88e6xxx_name_show(struct seq_file *s, void *p)
i = dp->index;
if (!ds->cd->port_names[i])
continue;
seq_printf(s, "%4d %s", i, ds->cd->port_names[i]);
-
+#if 0
if (dp->slave)
seq_printf(s, " (%s)", netdev_name(dp->slave));
-
+#endif
seq_puts(s, "\n");
}
return 0;
}
--
Created with Armbian build tools https://github.com/armbian/build

View File

@@ -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;
};

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,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

View File

@@ -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 = <&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/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";
};
};

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,