From 46ae5155c52c2d45b2658291831542813a1f1f96 Mon Sep 17 00:00:00 2001 From: Heisath Date: Sun, 12 Mar 2023 11:28:28 +0100 Subject: [PATCH] Correctly create a new mvebu-6.2 patch folder, update symlink, update/fix patches for mvebu-edge --- ...dicate-failure-to-enter-deeper-sleep.patch | 43 + .../mvebu-6.2/09-pci-link-retraining.patch | 219 +++ .../10-mvebu-clearfog-pcie-updates.patch | 196 +++ .../11-implement-slot-capabilities-SSPL.patch | 57 + .../mvebu-6.2/12-net-dsa-mv88e6xxx.patch | 1324 +++++++++++++++++ .../mvebu-6.2/20-pcie-bridge-emul.patch | 55 + ...da388-clearfog-emmc-on-clearfog-base.patch | 87 ++ ...1-libata-add-ledtrig-support.patch.disable | 149 ++ ...Enable-ATA-port-LED-trigger.patch.disabled | 30 + ...-mvebu-gpio-add_wake_on_gpio_support.patch | 88 ++ ...io-remove-hardcoded-timer-assignment.patch | 419 ++++++ ...-helios4-dts-add-wake-on-lan-support.patch | 21 + .../compile-dtb-with-symbol-support.patch | 12 + ...s-disable-spi-flash-on-a388-microsom.patch | 10 + ..._DMA_block_memory_allocation_to_2048.patch | 11 + ...lock_atheros_regulatory_restrictions.patch | 70 + .../use-1000BaseX-clearfog-switch.patch | 39 + patch/kernel/mvebu-edge | 2 +- 18 files changed, 2831 insertions(+), 1 deletion(-) create mode 100644 patch/kernel/archive/mvebu-6.2/0001-cpuidle-mvebu-indicate-failure-to-enter-deeper-sleep.patch create mode 100644 patch/kernel/archive/mvebu-6.2/09-pci-link-retraining.patch create mode 100644 patch/kernel/archive/mvebu-6.2/10-mvebu-clearfog-pcie-updates.patch create mode 100644 patch/kernel/archive/mvebu-6.2/11-implement-slot-capabilities-SSPL.patch create mode 100644 patch/kernel/archive/mvebu-6.2/12-net-dsa-mv88e6xxx.patch create mode 100644 patch/kernel/archive/mvebu-6.2/20-pcie-bridge-emul.patch create mode 100644 patch/kernel/archive/mvebu-6.2/412-ARM-dts-armada388-clearfog-emmc-on-clearfog-base.patch create mode 100644 patch/kernel/archive/mvebu-6.2/91-01-libata-add-ledtrig-support.patch.disable create mode 100644 patch/kernel/archive/mvebu-6.2/91-02-Enable-ATA-port-LED-trigger.patch.disabled create mode 100644 patch/kernel/archive/mvebu-6.2/92-mvebu-gpio-add_wake_on_gpio_support.patch create mode 100644 patch/kernel/archive/mvebu-6.2/92-mvebu-gpio-remove-hardcoded-timer-assignment.patch create mode 100644 patch/kernel/archive/mvebu-6.2/94-helios4-dts-add-wake-on-lan-support.patch create mode 100644 patch/kernel/archive/mvebu-6.2/compile-dtb-with-symbol-support.patch create mode 100644 patch/kernel/archive/mvebu-6.2/dts-disable-spi-flash-on-a388-microsom.patch create mode 100644 patch/kernel/archive/mvebu-6.2/general-increasing_DMA_block_memory_allocation_to_2048.patch create mode 100644 patch/kernel/archive/mvebu-6.2/unlock_atheros_regulatory_restrictions.patch create mode 100644 patch/kernel/archive/mvebu-6.2/use-1000BaseX-clearfog-switch.patch diff --git a/patch/kernel/archive/mvebu-6.2/0001-cpuidle-mvebu-indicate-failure-to-enter-deeper-sleep.patch b/patch/kernel/archive/mvebu-6.2/0001-cpuidle-mvebu-indicate-failure-to-enter-deeper-sleep.patch new file mode 100644 index 000000000..da5c35ff0 --- /dev/null +++ b/patch/kernel/archive/mvebu-6.2/0001-cpuidle-mvebu-indicate-failure-to-enter-deeper-sleep.patch @@ -0,0 +1,43 @@ +From: Russell King +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 +--- + 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; + } diff --git a/patch/kernel/archive/mvebu-6.2/09-pci-link-retraining.patch b/patch/kernel/archive/mvebu-6.2/09-pci-link-retraining.patch new file mode 100644 index 000000000..d3cf9df1c --- /dev/null +++ b/patch/kernel/archive/mvebu-6.2/09-pci-link-retraining.patch @@ -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 +Reported-by: Toke Høiland-Jørgensen +Tested-by: Toke Høiland-Jørgensen +Tested-by: Marek Behún +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 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, ®16); + 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 diff --git a/patch/kernel/archive/mvebu-6.2/10-mvebu-clearfog-pcie-updates.patch b/patch/kernel/archive/mvebu-6.2/10-mvebu-clearfog-pcie-updates.patch new file mode 100644 index 000000000..3ea938931 --- /dev/null +++ b/patch/kernel/archive/mvebu-6.2/10-mvebu-clearfog-pcie-updates.patch @@ -0,0 +1,196 @@ +From 6ea4b200f29c9397482b43d5ac14bd2d1ddade53 Mon Sep 17 00:00:00 2001 +From: Russell King +Date: Tue, 29 Nov 2016 10:13:46 +0000 +Subject: mvebu/clearfog pcie updates + +Signed-off-by: Russell King +--- + 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 + diff --git a/patch/kernel/archive/mvebu-6.2/11-implement-slot-capabilities-SSPL.patch b/patch/kernel/archive/mvebu-6.2/11-implement-slot-capabilities-SSPL.patch new file mode 100644 index 000000000..e61243b7a --- /dev/null +++ b/patch/kernel/archive/mvebu-6.2/11-implement-slot-capabilities-SSPL.patch @@ -0,0 +1,57 @@ +From e6a83c8b624052022b8212beabee6e4c40c6d8b2 Mon Sep 17 00:00:00 2001 +From: Russell King +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 + diff --git a/patch/kernel/archive/mvebu-6.2/12-net-dsa-mv88e6xxx.patch b/patch/kernel/archive/mvebu-6.2/12-net-dsa-mv88e6xxx.patch new file mode 100644 index 000000000..4c5b20f48 --- /dev/null +++ b/patch/kernel/archive/mvebu-6.2/12-net-dsa-mv88e6xxx.patch @@ -0,0 +1,1324 @@ +From 6dda089c4f2e277136eff3c370f514f6b1ccbe21 Mon Sep 17 00:00:00 2001 +From: Vivien Didelot +Date: Thu, 22 Oct 2015 14:31:23 -0400 +Subject: net: dsa: mv88e6xxx: add debugfs interface + +Add a debugfs directory named mv88e6xxx.X where X is the DSA switch +index. Mount the debugfs file system with: + + # mount -t debugfs none /sys/kernel/debug + +Signed-off-by: Vivien Didelot +[Modified by rmk for current kernels.] +Signed-off-by: Russell King +--- + drivers/net/dsa/mv88e6xxx/chip.c | 7 + + drivers/net/dsa/mv88e6xxx/chip.h | 2 + + drivers/net/dsa/mv88e6xxx/mv88e6xxx_debugfs.c | 1099 +++++++++++++++++++++++++ + 3 files changed, 1108 insertions(+) + create mode 100644 drivers/net/dsa/mv88e6xxx/mv88e6xxx_debugfs.c + +diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c +index 0b49d243e00b..6fde0e0fec5e 100644 +--- a/drivers/net/dsa/mv88e6xxx/chip.c ++++ b/drivers/net/dsa/mv88e6xxx/chip.c +@@ -3638,8 +3638,13 @@ static int mv88e6390_setup_errata(struct mv88e6xxx_chip *chip) + return mv88e6xxx_software_reset(chip); + } + ++#include "mv88e6xxx_debugfs.c" ++ + static void mv88e6xxx_teardown(struct dsa_switch *ds) + { ++ struct mv88e6xxx_chip *chip = ds->priv; ++ ++ mv88e6xxx_remove_debugfs(chip); + mv88e6xxx_teardown_devlink_params(ds); + dsa_devlink_resources_unregister(ds); + mv88e6xxx_teardown_devlink_regions_global(ds); +@@ -3774,6 +3779,8 @@ static int mv88e6xxx_setup(struct dsa_switch *ds) + if (err) + goto unlock; + ++ mv88e6xxx_init_debugfs(chip); ++ + unlock: + mv88e6xxx_reg_unlock(chip); + +diff --git a/drivers/net/dsa/mv88e6xxx/chip.h b/drivers/net/dsa/mv88e6xxx/chip.h +index 5e03cfe50156..b5be8a5719e1 100644 +--- a/drivers/net/dsa/mv88e6xxx/chip.h ++++ b/drivers/net/dsa/mv88e6xxx/chip.h +@@ -410,6 +410,8 @@ struct mv88e6xxx_chip { + + /* Bridge MST to SID mappings */ + struct list_head msts; ++ ++ struct dentry *dbgfs; + }; + + struct mv88e6xxx_bus_ops { +diff --git a/drivers/net/dsa/mv88e6xxx/mv88e6xxx_debugfs.c b/drivers/net/dsa/mv88e6xxx/mv88e6xxx_debugfs.c +new file mode 100644 +index 000000000000..931e769fe9ce +--- /dev/null ++++ b/drivers/net/dsa/mv88e6xxx/mv88e6xxx_debugfs.c +@@ -0,0 +1,1099 @@ ++#include ++#include ++ ++#define GLOBAL2_PVT_ADDR 0x0b ++#define GLOBAL2_PVT_ADDR_BUSY BIT(15) ++#define GLOBAL2_PVT_ADDR_OP_INIT_ONES ((0x01 << 12) | GLOBAL2_PVT_ADDR_BUSY) ++#define GLOBAL2_PVT_ADDR_OP_WRITE_PVLAN ((0x03 << 12) | GLOBAL2_PVT_ADDR_BUSY) ++#define GLOBAL2_PVT_ADDR_OP_READ ((0x04 << 12) | GLOBAL2_PVT_ADDR_BUSY) ++#define GLOBAL2_PVT_DATA 0x0c ++ ++#define ADDR_GLOBAL2 0x1c ++ ++static int mv88e6xxx_serdes_read(struct mv88e6xxx_chip *chip, int reg, u16 *val) ++{ ++ return mv88e6xxx_phy_page_read(chip, MV88E6352_ADDR_SERDES, ++ MV88E6352_SERDES_PAGE_FIBER, ++ reg, val); ++} ++ ++static int mv88e6xxx_serdes_write(struct mv88e6xxx_chip *chip, int reg, u16 val) ++{ ++ return mv88e6xxx_phy_page_write(chip, MV88E6352_ADDR_SERDES, ++ MV88E6352_SERDES_PAGE_FIBER, ++ reg, val); ++} ++ ++static int _mv88e6xxx_pvt_wait(struct mv88e6xxx_chip *chip) ++{ ++ return mv88e6xxx_wait_mask(chip, ADDR_GLOBAL2, GLOBAL2_PVT_ADDR, ++ GLOBAL2_PVT_ADDR_BUSY, 0); ++} ++ ++static int _mv88e6xxx_pvt_cmd(struct mv88e6xxx_chip *chip, int src_dev, ++ int src_port, u16 op) ++{ ++ u16 reg = op; ++ int err; ++ ++ /* 9-bit Cross-chip PVT pointer: with GLOBAL2_MISC_5_BIT_PORT cleared, ++ * source device is 5-bit, source port is 4-bit. ++ */ ++ reg |= (src_dev & 0x1f) << 4; ++ reg |= (src_port & 0xf); ++ ++ err = mv88e6xxx_g2_write(chip, GLOBAL2_PVT_ADDR, reg); ++ if (err) ++ return err; ++ ++ return _mv88e6xxx_pvt_wait(chip); ++} ++ ++static int _mv88e6xxx_pvt_read(struct mv88e6xxx_chip *chip, int src_dev, ++ int src_port, u16 *data) ++{ ++ int ret; ++ ++ ret = _mv88e6xxx_pvt_wait(chip); ++ if (ret < 0) ++ return ret; ++ ++ ret = _mv88e6xxx_pvt_cmd(chip, src_dev, src_port, ++ GLOBAL2_PVT_ADDR_OP_READ); ++ if (ret < 0) ++ return ret; ++ ++ return mv88e6xxx_g2_read(chip, GLOBAL2_PVT_DATA, data); ++} ++ ++static int _mv88e6xxx_pvt_write(struct mv88e6xxx_chip *chip, int src_dev, ++ int src_port, u16 data) ++{ ++ int err; ++ ++ err = _mv88e6xxx_pvt_wait(chip); ++ if (err) ++ return err; ++ ++ err = mv88e6xxx_g2_write(chip, GLOBAL2_PVT_DATA, data); ++ if (err) ++ return err; ++ ++ return _mv88e6xxx_pvt_cmd(chip, src_dev, src_port, ++ GLOBAL2_PVT_ADDR_OP_WRITE_PVLAN); ++} ++ ++static int mv88e6xxx_regs_show(struct seq_file *s, void *p) ++{ ++ struct mv88e6xxx_chip *chip = s->private; ++ int port, reg, ret; ++ u16 data; ++ ++ seq_puts(s, " GLOBAL GLOBAL2 SERDES "); ++ for (port = 0; port < mv88e6xxx_num_ports(chip); port++) ++ seq_printf(s, " %2d ", port); ++ seq_puts(s, "\n"); ++ ++ mutex_lock(&chip->reg_lock); ++ ++ for (reg = 0; reg < 32; reg++) { ++ seq_printf(s, "%2x:", reg); ++ ++ ret = mv88e6xxx_g1_read(chip, reg, &data); ++ if (ret < 0) ++ goto unlock; ++ seq_printf(s, " %4x ", data); ++ ++ ret = mv88e6xxx_g2_read(chip, reg, &data); ++ if (ret < 0) ++ goto unlock; ++ seq_printf(s, " %4x ", data); ++ ++ if (reg != MV88E6XXX_PHY_PAGE) { ++ ret = mv88e6xxx_serdes_read(chip, reg, &data); ++ if (ret < 0) ++ goto unlock; ++ } else { ++ data = 0; ++ } ++ seq_printf(s, " %4x ", data); ++ ++ /* Port regs 0x1a-0x1f are reserved in 6185 family */ ++ if (chip->info->family == MV88E6XXX_FAMILY_6185 && reg > 25) { ++ for (port = 0; port < mv88e6xxx_num_ports(chip); ++port) ++ seq_printf(s, "%4c ", '-'); ++ seq_puts(s, "\n"); ++ continue; ++ } ++ ++ for (port = 0; port < mv88e6xxx_num_ports(chip); ++port) { ++ ret = mv88e6xxx_port_read(chip, port, reg, &data); ++ if (ret < 0) ++ goto unlock; ++ ++ seq_printf(s, "%4x ", data); ++ } ++ ++ seq_puts(s, "\n"); ++ } ++ ++ ret = 0; ++unlock: ++ mutex_unlock(&chip->reg_lock); ++ ++ return ret; ++} ++ ++static ssize_t mv88e6xxx_regs_write(struct file *file, const char __user *buf, ++ size_t count, loff_t *ppos) ++{ ++ struct seq_file *s = file->private_data; ++ struct mv88e6xxx_chip *chip = s->private; ++ char cmd[32], name[32] = { 0 }; ++ unsigned int port, reg, val; ++ int ret; ++ ++ if (count > sizeof(name) - 1) ++ return -EINVAL; ++ ++ if (copy_from_user(cmd, buf, sizeof(cmd))) ++ return -EFAULT; ++ ++ ret = sscanf(cmd, "%s %x %x", name, ®, &val); ++ if (ret != 3) ++ return -EINVAL; ++ ++ if (reg > 0x1f || val > 0xffff) ++ return -ERANGE; ++ ++ mutex_lock(&chip->reg_lock); ++ ++ if (strcasecmp(name, "GLOBAL") == 0) ++ ret = mv88e6xxx_g1_write(chip, reg, val); ++ else if (strcasecmp(name, "GLOBAL2") == 0) ++ ret = mv88e6xxx_g2_write(chip, reg, val); ++ else if (strcasecmp(name, "SERDES") == 0) ++ ret = mv88e6xxx_serdes_write(chip, reg, val); ++ else if (kstrtouint(name, 10, &port) == 0 && port < mv88e6xxx_num_ports(chip)) ++ ret = mv88e6xxx_port_write(chip, port, reg, val); ++ else ++ ret = -EINVAL; ++ ++ mutex_unlock(&chip->reg_lock); ++ ++ return ret < 0 ? ret : count; ++} ++ ++static int mv88e6xxx_regs_open(struct inode *inode, struct file *file) ++{ ++ return single_open(file, mv88e6xxx_regs_show, inode->i_private); ++} ++ ++static const struct file_operations mv88e6xxx_regs_fops = { ++ .open = mv88e6xxx_regs_open, ++ .read = seq_read, ++ .write = mv88e6xxx_regs_write, ++ .llseek = no_llseek, ++ .release = single_release, ++ .owner = THIS_MODULE, ++}; ++ ++static int mv88e6xxx_name_show(struct seq_file *s, void *p) ++{ ++ struct mv88e6xxx_chip *chip = s->private; ++ struct dsa_switch *ds = chip->ds; ++ struct dsa_switch_tree *dst = ds->dst; ++ struct dsa_port *dp; ++ int i; ++ ++ if (!ds->cd) ++ return 0; ++ ++ seq_puts(s, " Port Name\n"); ++ ++ list_for_each_entry(dp, &dst->ports, list) { ++ if (dp->ds != ds) ++ continue; ++ ++ i = dp->index; ++ if (!ds->cd->port_names[i]) ++ continue; ++ ++ seq_printf(s, "%4d %s", i, ds->cd->port_names[i]); ++ ++ if (dp->slave) ++ seq_printf(s, " (%s)", netdev_name(dp->slave)); ++ ++ seq_puts(s, "\n"); ++ } ++ ++ return 0; ++} ++ ++static int mv88e6xxx_name_open(struct inode *inode, struct file *file) ++{ ++ return single_open(file, mv88e6xxx_name_show, inode->i_private); ++} ++ ++static const struct file_operations mv88e6xxx_name_fops = { ++ .open = mv88e6xxx_name_open, ++ .read = seq_read, ++ .llseek = no_llseek, ++ .release = single_release, ++ .owner = THIS_MODULE, ++}; ++ ++static int mv88e6xxx_atu_show(struct seq_file *s, void *p) ++{ ++ struct mv88e6xxx_chip *chip = s->private; ++ struct mv88e6xxx_atu_entry addr; ++ const char *state; ++ int fid, i, err; ++ ++ seq_puts(s, " FID MAC Addr State Trunk? DPV/Trunk ID\n"); ++ ++ for (fid = 0; fid < mv88e6xxx_num_databases(chip); ++fid) { ++ addr.state = 0; ++ eth_broadcast_addr(addr.mac); ++ ++ do { ++ mutex_lock(&chip->reg_lock); ++ err = mv88e6xxx_g1_atu_getnext(chip, fid, &addr); ++ mutex_unlock(&chip->reg_lock); ++ if (err) ++ return err; ++ ++ if (addr.state == 0) ++ break; ++ ++ /* print ATU entry */ ++ seq_printf(s, "%4d %pM", fid, addr.mac); ++ ++ if (is_multicast_ether_addr(addr.mac)) { ++ switch (addr.state) { ++ case MV88E6XXX_G1_ATU_DATA_STATE_MC_STATIC_PO: ++ state = "MC_STATIC_PO"; ++ break; ++ case MV88E6XXX_G1_ATU_DATA_STATE_MC_STATIC_DA_MGMT_PO: ++ state = "MC_STATIC_MGMT_PO"; ++ break; ++ case MV88E6XXX_G1_ATU_DATA_STATE_MC_STATIC_AVB_NRL_PO: ++ state = "MC_STATIC_NRL_PO"; ++ break; ++ case MV88E6XXX_G1_ATU_DATA_STATE_MC_STATIC_POLICY_PO: ++ state = "MC_STATIC_POLICY_PO"; ++ break; ++ case MV88E6XXX_G1_ATU_DATA_STATE_MC_STATIC: ++ state = "MC_STATIC"; ++ break; ++ case MV88E6XXX_G1_ATU_DATA_STATE_MC_STATIC_DA_MGMT: ++ state = "MC_STATIC_MGMT"; ++ break; ++ case MV88E6XXX_G1_ATU_DATA_STATE_MC_STATIC_AVB_NRL: ++ state = "MC_STATIC_NRL"; ++ break; ++ case MV88E6XXX_G1_ATU_DATA_STATE_MC_STATIC_POLICY: ++ state = "MC_STATIC_POLICY"; ++ break; ++ case 0xb: case 0xa: case 0x9: case 0x8: ++ /* Reserved for future use */ ++ case 0x3: case 0x2: case 0x1: ++ /* Reserved for future use */ ++ case MV88E6XXX_G1_ATU_DATA_STATE_MC_UNUSED: ++ default: ++ state = "???"; ++ break; ++ } ++ } else { ++ switch (addr.state) { ++ case MV88E6XXX_G1_ATU_DATA_STATE_UC_STATIC_PO: ++ state = "UC_STATIC_PO"; ++ break; ++ case MV88E6XXX_G1_ATU_DATA_STATE_UC_STATIC: ++ state = "UC_STATIC"; ++ break; ++ case MV88E6XXX_G1_ATU_DATA_STATE_UC_STATIC_DA_MGMT_PO: ++ state = "UC_STATIC_MGMT_PO"; ++ break; ++ case MV88E6XXX_G1_ATU_DATA_STATE_UC_STATIC_DA_MGMT: ++ state = "UC_STATIC_MGMT"; ++ break; ++ case MV88E6XXX_G1_ATU_DATA_STATE_UC_STATIC_AVB_NRL_PO: ++ state = "UC_STATIC_NRL_PO"; ++ break; ++ case MV88E6XXX_G1_ATU_DATA_STATE_UC_STATIC_AVB_NRL: ++ state = "UC_STATIC_NRL"; ++ break; ++ case MV88E6XXX_G1_ATU_DATA_STATE_UC_STATIC_POLICY_PO: ++ state = "UC_STATIC_POLICY_PO"; ++ break; ++ case MV88E6XXX_G1_ATU_DATA_STATE_UC_STATIC_POLICY: ++ state = "UC_STATIC_POLICY"; ++ break; ++ case MV88E6XXX_G1_ATU_DATA_STATE_UC_AGE_7_NEWEST: ++ state = "Age 7 (newest)"; ++ break; ++ case MV88E6XXX_G1_ATU_DATA_STATE_UC_AGE_6: ++ state = "Age 6"; ++ break; ++ case MV88E6XXX_G1_ATU_DATA_STATE_UC_AGE_5: ++ state = "Age 5"; ++ break; ++ case MV88E6XXX_G1_ATU_DATA_STATE_UC_AGE_4: ++ state = "Age 4"; ++ break; ++ case MV88E6XXX_G1_ATU_DATA_STATE_UC_AGE_3: ++ state = "Age 3"; ++ break; ++ case MV88E6XXX_G1_ATU_DATA_STATE_UC_AGE_2: ++ state = "Age 2"; ++ break; ++ case MV88E6XXX_G1_ATU_DATA_STATE_UC_AGE_1_OLDEST: ++ state = "Age 1 (oldest)"; ++ break; ++ case MV88E6XXX_G1_ATU_DATA_STATE_UC_UNUSED: ++ default: ++ state = "???"; ++ break; ++ } ++ } ++ ++ seq_printf(s, " %19s", state); ++ ++ if (addr.trunk) { ++ seq_printf(s, " y %d", ++ addr.portvec); ++ } else { ++ seq_puts(s, " n "); ++ for (i = 0; i < mv88e6xxx_num_ports(chip); ++i) ++ seq_printf(s, " %c", ++ addr.portvec & BIT(i) ? ++ 48 + i : '-'); ++ } ++ ++ seq_puts(s, "\n"); ++ } while (!is_broadcast_ether_addr(addr.mac)); ++ } ++ ++ return 0; ++} ++ ++static ssize_t mv88e6xxx_atu_write(struct file *file, const char __user *buf, ++ size_t count, loff_t *ppos) ++{ ++ struct seq_file *s = file->private_data; ++ struct mv88e6xxx_chip *chip = s->private; ++ char cmd[64]; ++ unsigned int fid; ++ int ret; ++ ++ if (copy_from_user(cmd, buf, sizeof(cmd))) ++ return -EFAULT; ++ ++ ret = sscanf(cmd, "%u", &fid); ++ if (ret != 1) ++ return -EINVAL; ++ ++ if (fid >= mv88e6xxx_num_databases(chip)) ++ return -ERANGE; ++ ++ mutex_lock(&chip->reg_lock); ++ ret = mv88e6xxx_g1_atu_flush(chip, fid, true); ++ mutex_unlock(&chip->reg_lock); ++ ++ return ret < 0 ? ret : count; ++} ++ ++static int mv88e6xxx_atu_open(struct inode *inode, struct file *file) ++{ ++ return single_open(file, mv88e6xxx_atu_show, inode->i_private); ++} ++ ++static const struct file_operations mv88e6xxx_atu_fops = { ++ .open = mv88e6xxx_atu_open, ++ .read = seq_read, ++ .write = mv88e6xxx_atu_write, ++ .llseek = no_llseek, ++ .release = single_release, ++ .owner = THIS_MODULE, ++}; ++ ++static int mv88e6xxx_default_vid_show(struct seq_file *s, void *p) ++{ ++ struct mv88e6xxx_chip *chip = s->private; ++ u16 pvid; ++ int i, err; ++ ++ seq_puts(s, " Port DefaultVID\n"); ++ ++ mutex_lock(&chip->reg_lock); ++ ++ for (i = 0; i < mv88e6xxx_num_ports(chip); ++i) { ++ err = mv88e6xxx_port_get_pvid(chip, i, &pvid); ++ if (err) ++ break; ++ ++ seq_printf(s, "%4d %d\n", i, pvid); ++ } ++ ++ mutex_unlock(&chip->reg_lock); ++ ++ return err; ++} ++ ++static ssize_t mv88e6xxx_default_vid_write(struct file *file, ++ const char __user *buf, size_t count, ++ loff_t *ppos) ++{ ++ struct seq_file *s = file->private_data; ++ struct mv88e6xxx_chip *chip = s->private; ++ char cmd[32]; ++ unsigned int port, pvid; ++ int ret; ++ ++ if (copy_from_user(cmd, buf, sizeof(cmd))) ++ return -EFAULT; ++ ++ ret = sscanf(cmd, "%u %u", &port, &pvid); ++ if (ret != 2) ++ return -EINVAL; ++ ++ if (port >= mv88e6xxx_num_ports(chip) || pvid > 0xfff) ++ return -ERANGE; ++ ++ mutex_lock(&chip->reg_lock); ++ ret = mv88e6xxx_port_set_pvid(chip, port, pvid); ++ mutex_unlock(&chip->reg_lock); ++ ++ return ret < 0 ? ret : count; ++} ++ ++static int mv88e6xxx_default_vid_open(struct inode *inode, struct file *file) ++{ ++ return single_open(file, mv88e6xxx_default_vid_show, inode->i_private); ++} ++ ++static const struct file_operations mv88e6xxx_default_vid_fops = { ++ .open = mv88e6xxx_default_vid_open, ++ .read = seq_read, ++ .write = mv88e6xxx_default_vid_write, ++ .llseek = no_llseek, ++ .release = single_release, ++ .owner = THIS_MODULE, ++}; ++ ++static int mv88e6xxx_fid_show(struct seq_file *s, void *p) ++{ ++ struct mv88e6xxx_chip *chip = s->private; ++ u16 fid; ++ int i, err; ++ ++ seq_puts(s, " Port FID\n"); ++ ++ mutex_lock(&chip->reg_lock); ++ ++ for (i = 0; i < mv88e6xxx_num_ports(chip); ++i) { ++ err = mv88e6xxx_port_get_fid(chip, i, &fid); ++ if (err) ++ break; ++ ++ seq_printf(s, "%4d %d\n", i, fid); ++ } ++ ++ mutex_unlock(&chip->reg_lock); ++ ++ return err; ++} ++ ++static int mv88e6xxx_fid_open(struct inode *inode, struct file *file) ++{ ++ return single_open(file, mv88e6xxx_fid_show, inode->i_private); ++} ++ ++static const struct file_operations mv88e6xxx_fid_fops = { ++ .open = mv88e6xxx_fid_open, ++ .read = seq_read, ++ .llseek = no_llseek, ++ .release = single_release, ++ .owner = THIS_MODULE, ++}; ++ ++static const char * const mv88e6xxx_port_state_names[] = { ++ [MV88E6XXX_PORT_CTL0_STATE_DISABLED] = "Disabled", ++ [MV88E6XXX_PORT_CTL0_STATE_BLOCKING] = "Blocking/Listening", ++ [MV88E6XXX_PORT_CTL0_STATE_LEARNING] = "Learning", ++ [MV88E6XXX_PORT_CTL0_STATE_FORWARDING] = "Forwarding", ++}; ++ ++static int mv88e6xxx_state_show(struct seq_file *s, void *p) ++{ ++ struct mv88e6xxx_chip *chip = s->private; ++ int i, ret; ++ u16 data; ++ ++ /* header */ ++ seq_puts(s, " Port Mode\n"); ++ ++ mutex_lock(&chip->reg_lock); ++ ++ /* One line per input port */ ++ for (i = 0; i < mv88e6xxx_num_ports(chip); ++i) { ++ seq_printf(s, "%4d ", i); ++ ++ ret = mv88e6xxx_port_read(chip, i, MV88E6XXX_PORT_CTL0, &data); ++ if (ret < 0) ++ goto unlock; ++ ++ data &= MV88E6XXX_PORT_CTL0_STATE_MASK; ++ seq_printf(s, " %s\n", mv88e6xxx_port_state_names[data]); ++ ret = 0; ++ } ++ ++unlock: ++ mutex_unlock(&chip->reg_lock); ++ ++ return ret; ++} ++ ++static int mv88e6xxx_state_open(struct inode *inode, struct file *file) ++{ ++ return single_open(file, mv88e6xxx_state_show, inode->i_private); ++} ++ ++static const struct file_operations mv88e6xxx_state_fops = { ++ .open = mv88e6xxx_state_open, ++ .read = seq_read, ++ .llseek = no_llseek, ++ .release = single_release, ++ .owner = THIS_MODULE, ++}; ++ ++static const char * const mv88e6xxx_port_8021q_mode_names[] = { ++ [MV88E6XXX_PORT_CTL2_8021Q_MODE_DISABLED] = "Disabled", ++ [MV88E6XXX_PORT_CTL2_8021Q_MODE_FALLBACK] = "Fallback", ++ [MV88E6XXX_PORT_CTL2_8021Q_MODE_CHECK] = "Check", ++ [MV88E6XXX_PORT_CTL2_8021Q_MODE_SECURE] = "Secure", ++}; ++ ++static int mv88e6xxx_8021q_mode_show(struct seq_file *s, void *p) ++{ ++ struct mv88e6xxx_chip *chip = s->private; ++ int i, ret; ++ u16 data; ++ ++ /* header */ ++ seq_puts(s, " Port Mode\n"); ++ ++ mutex_lock(&chip->reg_lock); ++ ++ /* One line per input port */ ++ for (i = 0; i < mv88e6xxx_num_ports(chip); ++i) { ++ seq_printf(s, "%4d ", i); ++ ++ ret = mv88e6xxx_port_read(chip, i, MV88E6XXX_PORT_CTL2, &data); ++ if (ret < 0) ++ goto unlock; ++ ++ data &= MV88E6XXX_PORT_CTL2_8021Q_MODE_MASK; ++ seq_printf(s, " %s\n", mv88e6xxx_port_8021q_mode_names[data]); ++ ret = 0; ++ } ++ ++unlock: ++ mutex_unlock(&chip->reg_lock); ++ ++ return ret; ++} ++ ++static int mv88e6xxx_8021q_mode_open(struct inode *inode, struct file *file) ++{ ++ return single_open(file, mv88e6xxx_8021q_mode_show, inode->i_private); ++} ++ ++static const struct file_operations mv88e6xxx_8021q_mode_fops = { ++ .open = mv88e6xxx_8021q_mode_open, ++ .read = seq_read, ++ .llseek = no_llseek, ++ .release = single_release, ++ .owner = THIS_MODULE, ++}; ++ ++static int mv88e6xxx_vlan_table_show(struct seq_file *s, void *p) ++{ ++ struct mv88e6xxx_chip *chip = s->private; ++ int i, j, ret; ++ u16 data; ++ ++ /* header */ ++ seq_puts(s, " Port"); ++ for (i = 0; i < mv88e6xxx_num_ports(chip); ++i) ++ seq_printf(s, " %2d", i); ++ seq_puts(s, "\n"); ++ ++ mutex_lock(&chip->reg_lock); ++ ++ /* One line per input port */ ++ for (i = 0; i < mv88e6xxx_num_ports(chip); ++i) { ++ seq_printf(s, "%4d ", i); ++ ++ ret = mv88e6xxx_port_read(chip, i, MV88E6XXX_PORT_BASE_VLAN, &data); ++ if (ret < 0) ++ goto unlock; ++ ++ /* One column per output port */ ++ for (j = 0; j < mv88e6xxx_num_ports(chip); ++j) ++ seq_printf(s, " %c", data & BIT(j) ? '*' : '-'); ++ seq_puts(s, "\n"); ++ } ++ ++ ret = 0; ++unlock: ++ mutex_unlock(&chip->reg_lock); ++ ++ return ret; ++} ++ ++static int mv88e6xxx_vlan_table_open(struct inode *inode, struct file *file) ++{ ++ return single_open(file, mv88e6xxx_vlan_table_show, inode->i_private); ++} ++ ++static const struct file_operations mv88e6xxx_vlan_table_fops = { ++ .open = mv88e6xxx_vlan_table_open, ++ .read = seq_read, ++ .llseek = no_llseek, ++ .release = single_release, ++ .owner = THIS_MODULE, ++}; ++ ++static int mv88e6xxx_pvt_show(struct seq_file *s, void *p) ++{ ++ struct mv88e6xxx_chip *chip = s->private; ++ struct dsa_switch_tree *dst = chip->ds->dst; ++ int port, src_dev, src_port; ++ u16 pvlan; ++ int err = 0; ++ ++ if (chip->info->family == MV88E6XXX_FAMILY_6185) ++ return -ENODEV; ++ ++ /* header */ ++ seq_puts(s, " Dev Port PVLAN"); ++ for (port = 0; port < mv88e6xxx_num_ports(chip); ++port) ++ seq_printf(s, " %2d", port); ++ seq_puts(s, "\n"); ++ ++ mutex_lock(&chip->reg_lock); ++ ++ /* One line per external port */ ++ for (src_dev = 0; src_dev < DSA_MAX_SWITCHES; ++src_dev) { ++ if (!dst->ds[src_dev]) ++ break; ++ ++ if (src_dev == chip->ds->index) ++ continue; ++ ++ seq_puts(s, "\n"); ++ for (src_port = 0; src_port < 16; ++src_port) { ++ if (src_port >= DSA_MAX_PORTS) ++ break; ++ ++ err = _mv88e6xxx_pvt_read(chip, src_dev, src_port, ++ &pvlan); ++ if (err) ++ goto unlock; ++ ++ seq_printf(s, " %d %2d %03hhx ", src_dev, src_port, ++ pvlan); ++ ++ /* One column per internal output port */ ++ for (port = 0; port < mv88e6xxx_num_ports(chip); ++port) ++ seq_printf(s, " %c", ++ pvlan & BIT(port) ? '*' : '-'); ++ seq_puts(s, "\n"); ++ } ++ } ++ ++unlock: ++ mutex_unlock(&chip->reg_lock); ++ ++ return err; ++} ++ ++static ssize_t mv88e6xxx_pvt_write(struct file *file, const char __user *buf, ++ size_t count, loff_t *ppos) ++{ ++ struct seq_file *s = file->private_data; ++ struct mv88e6xxx_chip *chip = s->private; ++ const u16 mask = (1 << mv88e6xxx_num_ports(chip)) - 1; ++ char cmd[32]; ++ unsigned int src_dev, src_port, pvlan; ++ int ret; ++ ++ if (copy_from_user(cmd, buf, sizeof(cmd))) ++ return -EFAULT; ++ ++ if (sscanf(cmd, "%d %d %x", &src_dev, &src_port, &pvlan) != 3) ++ return -EINVAL; ++ ++ if (src_dev >= 32 || src_port >= 16 || pvlan & ~mask) ++ return -ERANGE; ++ ++ mutex_lock(&chip->reg_lock); ++ ret = _mv88e6xxx_pvt_write(chip, src_dev, src_port, pvlan); ++ mutex_unlock(&chip->reg_lock); ++ ++ return ret < 0 ? ret : count; ++} ++ ++static int mv88e6xxx_pvt_open(struct inode *inode, struct file *file) ++{ ++ return single_open(file, mv88e6xxx_pvt_show, inode->i_private); ++} ++ ++static const struct file_operations mv88e6xxx_pvt_fops = { ++ .open = mv88e6xxx_pvt_open, ++ .read = seq_read, ++ .write = mv88e6xxx_pvt_write, ++ .llseek = no_llseek, ++ .release = single_release, ++ .owner = THIS_MODULE, ++}; ++ ++static int mv88e6xxx_vtu_show(struct seq_file *s, void *p) ++{ ++ struct mv88e6xxx_chip *chip = s->private; ++ struct mv88e6xxx_vtu_entry next = { 0 }; ++ int port, ret = 0; ++ ++ seq_puts(s, " VID FID SID"); ++ for (port = 0; port < mv88e6xxx_num_ports(chip); ++port) ++ seq_printf(s, " %2d", port); ++ seq_puts(s, "\n"); ++ ++ if (!chip->info->ops->vtu_getnext) ++ return 0; ++ ++ next.vid = chip->info->max_vid; /* first or lowest VID */ ++ ++ do { ++ mutex_lock(&chip->reg_lock); ++ ret = chip->info->ops->vtu_getnext(chip, &next); ++ mutex_unlock(&chip->reg_lock); ++ if (ret < 0) ++ break; ++ ++ if (!next.valid) ++ break; ++ ++ seq_printf(s, "%4d %4d %2d", next.vid, next.fid, next.sid); ++ for (port = 0; port < mv88e6xxx_num_ports(chip); ++port) { ++ switch (next.member[port]) { ++ case MV88E6XXX_G1_VTU_DATA_MEMBER_TAG_UNMODIFIED: ++ seq_puts(s, " ="); ++ break; ++ case MV88E6XXX_G1_VTU_DATA_MEMBER_TAG_UNTAGGED: ++ seq_puts(s, " u"); ++ break; ++ case MV88E6XXX_G1_VTU_DATA_MEMBER_TAG_TAGGED: ++ seq_puts(s, " t"); ++ break; ++ case MV88E6XXX_G1_VTU_DATA_MEMBER_TAG_NON_MEMBER: ++ seq_puts(s, " x"); ++ break; ++ default: ++ seq_puts(s, " ??"); ++ break; ++ } ++ } ++ seq_puts(s, "\n"); ++ } while (next.vid < chip->info->max_vid); ++ ++ return ret; ++} ++ ++static ssize_t mv88e6xxx_vtu_write(struct file *file, const char __user *buf, ++ size_t count, loff_t *ppos) ++{ ++ struct seq_file *s = file->private_data; ++ struct mv88e6xxx_chip *chip = s->private; ++ struct mv88e6xxx_vtu_entry entry = { 0 }; ++ bool valid = true; ++ char cmd[64], tags[12]; /* DSA_MAX_PORTS */ ++ int vid, fid, sid, port, ret; ++ ++ if (!chip->info->ops->vtu_loadpurge) ++ return -EOPNOTSUPP; ++ ++ if (copy_from_user(cmd, buf, sizeof(cmd))) ++ return -EFAULT; ++ ++ /* scan 12 chars instead of num_ports to avoid dynamic scanning... */ ++ ret = sscanf(cmd, "%d %d %d %c %c %c %c %c %c %c %c %c %c %c %c", &vid, ++ &fid, &sid, &tags[0], &tags[1], &tags[2], &tags[3], ++ &tags[4], &tags[5], &tags[6], &tags[7], &tags[8], &tags[9], ++ &tags[10], &tags[11]); ++ if (ret == 1) ++ valid = false; ++ else if (ret != 3 + mv88e6xxx_num_ports(chip)) ++ return -EINVAL; ++ ++ entry.vid = vid; ++ entry.valid = valid; ++ ++ if (valid) { ++ entry.fid = fid; ++ entry.sid = sid; ++ /* Note: The VTU entry pointed by VID will be loaded but not ++ * considered valid until the STU entry pointed by SID is valid. ++ */ ++ ++ for (port = 0; port < mv88e6xxx_num_ports(chip); ++port) { ++ u8 tag; ++ ++ switch (tags[port]) { ++ case 'u': ++ tag = MV88E6XXX_G1_VTU_DATA_MEMBER_TAG_UNTAGGED; ++ break; ++ case 't': ++ tag = MV88E6XXX_G1_VTU_DATA_MEMBER_TAG_TAGGED; ++ break; ++ case 'x': ++ tag = MV88E6XXX_G1_VTU_DATA_MEMBER_TAG_NON_MEMBER; ++ break; ++ case '=': ++ tag = MV88E6XXX_G1_VTU_DATA_MEMBER_TAG_UNMODIFIED; ++ break; ++ default: ++ return -EINVAL; ++ } ++ ++ entry.member[port] = tag; ++ } ++ } ++ ++ mutex_lock(&chip->reg_lock); ++ ret = chip->info->ops->vtu_loadpurge(chip, &entry); ++ mutex_unlock(&chip->reg_lock); ++ ++ return ret < 0 ? ret : count; ++} ++ ++static int mv88e6xxx_vtu_open(struct inode *inode, struct file *file) ++{ ++ return single_open(file, mv88e6xxx_vtu_show, inode->i_private); ++} ++ ++static const struct file_operations mv88e6xxx_vtu_fops = { ++ .open = mv88e6xxx_vtu_open, ++ .read = seq_read, ++ .write = mv88e6xxx_vtu_write, ++ .llseek = no_llseek, ++ .release = single_release, ++ .owner = THIS_MODULE, ++}; ++#if 0 ++static int mv88e6xxx_stats_show(struct seq_file *s, void *p) ++{ ++ struct mv88e6xxx_chip *chip = s->private; ++ char *strs; ++ u64 *stats; ++ int stat, port, num_stats, num_ports; ++ int err = 0; ++ ++ num_stats = mv88e6xxx_get_sset_count(chip->ds); ++ if (num_stats == 0) ++ return 0; ++ ++ num_ports = mv88e6xxx_num_ports(chip); ++ ++ strs = kcalloc(num_stats, ETH_GSTRING_LEN, GFP_KERNEL); ++ stats = kcalloc(num_stats, num_ports * sizeof(*stats), GFP_KERNEL); ++ if (!strs || !strs) { ++ kfree(strs); ++ kfree(stats); ++ return -ENOMEM; ++ } ++ ++ mv88e6xxx_get_strings(chip->ds, 0, strs); ++ ++ for (port = 0; port < num_ports; port++) ++ mv88e6xxx_get_ethtool_stats(chip->ds, port, stats + (port * num_stats)); ++ ++ seq_puts(s, " Statistic "); ++ for (port = 0; port < mv88e6xxx_num_ports(chip); port++) ++ seq_printf(s, " Port %2d ", port); ++ seq_puts(s, "\n"); ++ ++ for (stat = 0; stat < num_stats; stat++) { ++ seq_printf(s, "%19s: ", strs + stat * ETH_GSTRING_LEN); ++ for (port = 0 ; port < num_ports; port++) { ++ u64 value = stats[stat + port * num_stats]; ++ ++ seq_printf(s, "%8llu ", value); ++ } ++ seq_puts(s, "\n"); ++ } ++ ++ kfree(stats); ++ kfree(strs); ++ ++ return err; ++} ++ ++static int mv88e6xxx_stats_open(struct inode *inode, struct file *file) ++{ ++ return single_open(file, mv88e6xxx_stats_show, inode->i_private); ++} ++ ++static const struct file_operations mv88e6xxx_stats_fops = { ++ .open = mv88e6xxx_stats_open, ++ .read = seq_read, ++ .llseek = no_llseek, ++ .release = single_release, ++ .owner = THIS_MODULE, ++}; ++#endif ++static int mv88e6xxx_device_map_show(struct seq_file *s, void *p) ++{ ++ struct mv88e6xxx_chip *chip = s->private; ++ int target, ret; ++ u16 data, port_mask; ++ ++ seq_puts(s, "Target Port\n"); ++ ++ /* FIXME */ ++ port_mask = MV88E6390_G2_DEVICE_MAPPING_PORT_MASK; ++ ++ mutex_lock(&chip->reg_lock); ++ for (target = 0; target < 32; target++) { ++ ret = mv88e6xxx_g2_write(chip, MV88E6XXX_G2_DEVICE_MAPPING, ++ target << 8 /* MV88E6XXX_G2_DEVICE_MAPPING_DEV_MASK */); ++ if (ret < 0) ++ goto out; ++ ret = mv88e6xxx_g2_read(chip, MV88E6XXX_G2_DEVICE_MAPPING, &data); ++ if (ret < 0) ++ goto out; ++ seq_printf(s, " %2d %2d\n", target, data & port_mask); ++ } ++out: ++ mutex_unlock(&chip->reg_lock); ++ ++ return 0; ++} ++ ++static int mv88e6xxx_device_map_open(struct inode *inode, struct file *file) ++{ ++ return single_open(file, mv88e6xxx_device_map_show, inode->i_private); ++} ++ ++static const struct file_operations mv88e6xxx_device_map_fops = { ++ .open = mv88e6xxx_device_map_open, ++ .read = seq_read, ++ .llseek = no_llseek, ++ .release = single_release, ++ .owner = THIS_MODULE, ++}; ++ ++/* Must be called with SMI lock held */ ++static int _mv88e6xxx_scratch_wait(struct mv88e6xxx_chip *chip) ++{ ++ return mv88e6xxx_wait_mask(chip, ADDR_GLOBAL2, ++ MV88E6XXX_G2_SCRATCH_MISC_MISC, ++ MV88E6XXX_G2_SCRATCH_MISC_UPDATE, 0); ++} ++ ++static int mv88e6xxx_scratch_show(struct seq_file *s, void *p) ++{ ++ struct mv88e6xxx_chip *chip = s->private; ++ int reg, ret; ++ u16 data; ++ ++ seq_puts(s, "Register Value\n"); ++ ++ mutex_lock(&chip->reg_lock); ++ for (reg = 0; reg < 0x80; reg++) { ++ ret = mv88e6xxx_g2_write(chip, MV88E6XXX_G2_SCRATCH_MISC_MISC, ++ reg << 8 /* MV88E6XXX_G2_SCRATCH_MISC_PTR_MASK */); ++ if (ret < 0) ++ goto out; ++ ++ ret = _mv88e6xxx_scratch_wait(chip); ++ if (ret < 0) ++ goto out; ++ ++ ret = mv88e6xxx_g2_read(chip, MV88E6XXX_G2_SCRATCH_MISC_MISC, &data); ++ seq_printf(s, " %2x %2x\n", reg, ++ data & MV88E6XXX_G2_SCRATCH_MISC_DATA_MASK); ++ } ++out: ++ mutex_unlock(&chip->reg_lock); ++ ++ return 0; ++} ++ ++static int mv88e6xxx_scratch_open(struct inode *inode, struct file *file) ++{ ++ return single_open(file, mv88e6xxx_scratch_show, inode->i_private); ++} ++ ++static const struct file_operations mv88e6xxx_scratch_fops = { ++ .open = mv88e6xxx_scratch_open, ++ .read = seq_read, ++ .llseek = no_llseek, ++ .release = single_release, ++ .owner = THIS_MODULE, ++}; ++ ++static void mv88e6xxx_init_debugfs(struct mv88e6xxx_chip *chip) ++{ ++ char *name; ++ ++ name = kasprintf(GFP_KERNEL, "mv88e6xxx.%d", chip->ds->index); ++ chip->dbgfs = debugfs_create_dir(name, NULL); ++ ++ kfree(name); ++ ++ debugfs_create_file("regs", S_IRUGO | S_IWUSR, chip->dbgfs, chip, ++ &mv88e6xxx_regs_fops); ++ ++ debugfs_create_file("name", S_IRUGO, chip->dbgfs, chip, ++ &mv88e6xxx_name_fops); ++ ++ debugfs_create_file("atu", S_IRUGO | S_IWUSR, chip->dbgfs, chip, ++ &mv88e6xxx_atu_fops); ++ ++ debugfs_create_file("default_vid", S_IRUGO | S_IWUSR, chip->dbgfs, chip, ++ &mv88e6xxx_default_vid_fops); ++ ++ debugfs_create_file("fid", S_IRUGO, chip->dbgfs, chip, &mv88e6xxx_fid_fops); ++ ++ debugfs_create_file("state", S_IRUGO, chip->dbgfs, chip, ++ &mv88e6xxx_state_fops); ++ ++ debugfs_create_file("8021q_mode", S_IRUGO, chip->dbgfs, chip, ++ &mv88e6xxx_8021q_mode_fops); ++ ++ debugfs_create_file("vlan_table", S_IRUGO, chip->dbgfs, chip, ++ &mv88e6xxx_vlan_table_fops); ++ ++ debugfs_create_file("pvt", S_IRUGO | S_IWUSR, chip->dbgfs, chip, ++ &mv88e6xxx_pvt_fops); ++ ++ debugfs_create_file("vtu", S_IRUGO | S_IWUSR, chip->dbgfs, chip, ++ &mv88e6xxx_vtu_fops); ++#if 0 ++ debugfs_create_file("stats", S_IRUGO, chip->dbgfs, chip, ++ &mv88e6xxx_stats_fops); ++#endif ++ debugfs_create_file("device_map", S_IRUGO, chip->dbgfs, chip, ++ &mv88e6xxx_device_map_fops); ++ ++ debugfs_create_file("scratch", S_IRUGO, chip->dbgfs, chip, ++ &mv88e6xxx_scratch_fops); ++} ++ ++static void mv88e6xxx_remove_debugfs(struct mv88e6xxx_chip *chip) ++{ ++ debugfs_remove_recursive(chip->dbgfs); ++} +-- +cgit +From 88f0fb731db6e340495995aea0e6be5d7d220841 Mon Sep 17 00:00:00 2001 +From: Russell King +Date: Mon, 27 Jan 2020 14:00:12 +0000 +Subject: net: dsa: mv88e6xxx: debugfs hacks to fix the compile + +This is the problem with out-of-tree maintained patches; they break, +sometimes requiring substantial rework. It's all very well promising +to publish new versions as that happens, but it causes pain when they +aren't published in a timely manner. Hence this hack. + +Signed-off-by: Russell King +--- + drivers/net/dsa/mv88e6xxx/mv88e6xxx_debugfs.c | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +diff --git a/drivers/net/dsa/mv88e6xxx/mv88e6xxx_debugfs.c b/drivers/net/dsa/mv88e6xxx/mv88e6xxx_debugfs.c +index 931e769fe9ce..4005a4760884 100644 +--- a/drivers/net/dsa/mv88e6xxx/mv88e6xxx_debugfs.c ++++ b/drivers/net/dsa/mv88e6xxx/mv88e6xxx_debugfs.c +@@ -668,6 +668,7 @@ static const struct file_operations mv88e6xxx_vlan_table_fops = { + + static int mv88e6xxx_pvt_show(struct seq_file *s, void *p) + { ++#if 0 + struct mv88e6xxx_chip *chip = s->private; + struct dsa_switch_tree *dst = chip->ds->dst; + int port, src_dev, src_port; +@@ -716,8 +717,10 @@ static int mv88e6xxx_pvt_show(struct seq_file *s, void *p) + + unlock: + mutex_unlock(&chip->reg_lock); +- + return err; ++#else ++ return 0; ++#endif + } + + static ssize_t mv88e6xxx_pvt_write(struct file *file, const char __user *buf, +-- +cgit + +From e693b19d96a9c0a21dc767676594e99645a565ff Mon Sep 17 00:00:00 2001 +From: Russell King +Date: Thu, 28 Sep 2017 12:09:56 +0100 +Subject: Revert "net: dsa: mv88e6xxx: remove LED control register" + +This reverts commit c56a71a92114e3198e249593841cb744abaadcb7. +--- + drivers/net/dsa/mv88e6xxx/port.h | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/drivers/net/dsa/mv88e6xxx/port.h b/drivers/net/dsa/mv88e6xxx/port.h +index e0a705d82019..72e2edb6d779 100644 +--- a/drivers/net/dsa/mv88e6xxx/port.h ++++ b/drivers/net/dsa/mv88e6xxx/port.h +@@ -291,6 +291,9 @@ + /* Offset 0x13: OutFiltered Counter */ + #define MV88E6XXX_PORT_OUT_FILTERED 0x13 + ++/* Offset 0x16: LED Control */ ++#define MV88E6XXX_PORT_LED_CONTROL 0x16 ++ + /* Offset 0x18: IEEE Priority Mapping Table */ + #define MV88E6390_PORT_IEEE_PRIO_MAP_TABLE 0x18 + #define MV88E6390_PORT_IEEE_PRIO_MAP_TABLE_UPDATE 0x8000 +-- +cgit +From da28daf741e3365c3b6b021427186b64aac5e5e3 Mon Sep 17 00:00:00 2001 +From: Russell King +Date: Sat, 7 Jan 2017 20:47:36 +0000 +Subject: net: dsa: program 6176 LED registers + +Signed-off-by: Russell King +--- + drivers/net/dsa/mv88e6xxx/chip.c | 20 ++++++++++++++++++++ + 1 file changed, 20 insertions(+) + +diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c +index 6fde0e0fec5e..fdd069891f06 100644 +--- a/drivers/net/dsa/mv88e6xxx/chip.c ++++ b/drivers/net/dsa/mv88e6xxx/chip.c +@@ -3276,6 +3276,20 @@ static int mv88e6xxx_setup_upstream_port(struct mv88e6xxx_chip *chip, int port) + return 0; + } + ++static int mv88e6xxx_setup_led(struct mv88e6xxx_chip *chip, int port) ++{ ++ int err; ++ ++ /* LED0 = link/activity, LED1 = 10/100 */ ++ err = mv88e6xxx_wait_bit(chip, chip->info->port_base_addr + port, ++ MV88E6XXX_PORT_LED_CONTROL, 15, 0); ++ if (err) ++ return err; ++ ++ return mv88e6xxx_write(chip, chip->info->port_base_addr + port, ++ MV88E6XXX_PORT_LED_CONTROL, 0x80b3); ++} ++ + static int mv88e6xxx_setup_port(struct mv88e6xxx_chip *chip, int port) + { + struct device_node *phy_handle = NULL; +@@ -3334,6 +3348,12 @@ static int mv88e6xxx_setup_port(struct mv88e6xxx_chip *chip, int port) + if (err) + return err; + ++ if (chip->info->num_gpio) { ++ err = mv88e6xxx_setup_led(chip, port); ++ if (err) ++ return err; ++ } ++ + /* Port Control 2: don't force a good FCS, set the MTU size to + * 10222 bytes, disable 802.1q tags checking, don't discard + * tagged or untagged frames on this port, skip destination +-- +cgit +From 76e0fe4eb780fe291402c677d8c8d2c62736fcca Mon Sep 17 00:00:00 2001 +From: Russell King +Date: Wed, 8 Jul 2020 12:31:01 +0100 +Subject: net: dsa/mv88e6xxx: add support for rate-matching PHYs + +Add basic support for rate-matching 10G PHYs for mv88e6xxx - if we are +in RXAUI, XAUI or 10GBASE-R mode, the link speed is 10G, even if the +media is running at a slower speed. + +Signed-off-by: Russell King +--- + drivers/net/dsa/mv88e6xxx/chip.c | 12 ++++++++++++ + 1 file changed, 12 insertions(+) + +diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c +index fdd069891f06..593959612334 100644 +--- a/drivers/net/dsa/mv88e6xxx/chip.c ++++ b/drivers/net/dsa/mv88e6xxx/chip.c +@@ -951,6 +951,18 @@ static void mv88e6xxx_mac_link_up(struct dsa_switch *ds, int port, + if (err) + goto error; + ++ /* The link parameters passed in are the media side parameters. ++ * If in RXAUI, XAUI or 10GBASE-R with a rate matching PHY, we ++ * need to operate our link at 10G. Only full duplex is ++ * supported at this speed. ++ */ ++ if (interface == PHY_INTERFACE_MODE_RXAUI || ++ interface == PHY_INTERFACE_MODE_XAUI || ++ interface == PHY_INTERFACE_MODE_10GBASER) { ++ speed = SPEED_10000; ++ duplex = DUPLEX_FULL; ++ } ++ + if (ops->port_set_speed_duplex) { + err = ops->port_set_speed_duplex(chip, port, + speed, duplex); +-- +cgit diff --git a/patch/kernel/archive/mvebu-6.2/20-pcie-bridge-emul.patch b/patch/kernel/archive/mvebu-6.2/20-pcie-bridge-emul.patch new file mode 100644 index 000000000..24e6f27d2 --- /dev/null +++ b/patch/kernel/archive/mvebu-6.2/20-pcie-bridge-emul.patch @@ -0,0 +1,55 @@ +From f1149effc7fd438ac5925a8e58ee2da294033ec5 Mon Sep 17 00:00:00 2001 +From: Russell King +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 +--- + 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 + diff --git a/patch/kernel/archive/mvebu-6.2/412-ARM-dts-armada388-clearfog-emmc-on-clearfog-base.patch b/patch/kernel/archive/mvebu-6.2/412-ARM-dts-armada388-clearfog-emmc-on-clearfog-base.patch new file mode 100644 index 000000000..dd2bef7f6 --- /dev/null +++ b/patch/kernel/archive/mvebu-6.2/412-ARM-dts-armada388-clearfog-emmc-on-clearfog-base.patch @@ -0,0 +1,87 @@ +From 8137da20701c776ad3481115305a5e8e410871ba Mon Sep 17 00:00:00 2001 +From: Russell King +Date: Tue, 29 Nov 2016 10:15:45 +0000 +Subject: ARM: dts: armada388-clearfog: emmc on clearfog base + +Signed-off-by: Russell King +--- + 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 = <µsom_sdhci_pins>; ++ pinctrl-names = "default"; ++ status = "okay"; ++ wp-inverted; ++ }; ++ }; ++ }; ++}; diff --git a/patch/kernel/archive/mvebu-6.2/91-01-libata-add-ledtrig-support.patch.disable b/patch/kernel/archive/mvebu-6.2/91-01-libata-add-ledtrig-support.patch.disable new file mode 100644 index 000000000..a52e712d8 --- /dev/null +++ b/patch/kernel/archive/mvebu-6.2/91-01-libata-add-ledtrig-support.patch.disable @@ -0,0 +1,149 @@ +From: Daniel Golle +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 +--- + 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 + #include + #include ++#ifdef CONFIG_ATA_LEDS ++#include ++#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; + }; diff --git a/patch/kernel/archive/mvebu-6.2/91-02-Enable-ATA-port-LED-trigger.patch.disabled b/patch/kernel/archive/mvebu-6.2/91-02-Enable-ATA-port-LED-trigger.patch.disabled new file mode 100644 index 000000000..10680f98c --- /dev/null +++ b/patch/kernel/archive/mvebu-6.2/91-02-Enable-ATA-port-LED-trigger.patch.disabled @@ -0,0 +1,30 @@ +From 9ee6345ef82f7af5f98e17a40e667f8ad6b2fa1b Mon Sep 17 00:00:00 2001 +From: aprayoga +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 diff --git a/patch/kernel/archive/mvebu-6.2/92-mvebu-gpio-add_wake_on_gpio_support.patch b/patch/kernel/archive/mvebu-6.2/92-mvebu-gpio-add_wake_on_gpio_support.patch new file mode 100644 index 000000000..9274f2b1a --- /dev/null +++ b/patch/kernel/archive/mvebu-6.2/92-mvebu-gpio-add_wake_on_gpio_support.patch @@ -0,0 +1,88 @@ +--- a/drivers/gpio/gpio-mvebu.c ++++ b/drivers/gpio/gpio-mvebu.c +@@ -40,6 +40,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -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; diff --git a/patch/kernel/archive/mvebu-6.2/92-mvebu-gpio-remove-hardcoded-timer-assignment.patch b/patch/kernel/archive/mvebu-6.2/92-mvebu-gpio-remove-hardcoded-timer-assignment.patch new file mode 100644 index 000000000..0e2b559f4 --- /dev/null +++ b/patch/kernel/archive/mvebu-6.2/92-mvebu-gpio-remove-hardcoded-timer-assignment.patch @@ -0,0 +1,419 @@ +From e4728fcf779c37d1bcbd4b6505c9b40d4bb9ff48 Mon Sep 17 00:00:00 2001 +From: Heisath +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 +--- + +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); + } diff --git a/patch/kernel/archive/mvebu-6.2/94-helios4-dts-add-wake-on-lan-support.patch b/patch/kernel/archive/mvebu-6.2/94-helios4-dts-add-wake-on-lan-support.patch new file mode 100644 index 000000000..b3daf09f9 --- /dev/null +++ b/patch/kernel/archive/mvebu-6.2/94-helios4-dts-add-wake-on-lan-support.patch @@ -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 = <µsom_phy0_int_pins>; ++ ++ wol { ++ label = "Wake-On-LAN"; ++ linux,code = ; ++ gpios = <&gpio0 18 GPIO_ACTIVE_LOW>; ++ wakeup-source; ++ }; ++ }; ++ + io-leds { + compatible = "gpio-leds"; + sata1-led { diff --git a/patch/kernel/archive/mvebu-6.2/compile-dtb-with-symbol-support.patch b/patch/kernel/archive/mvebu-6.2/compile-dtb-with-symbol-support.patch new file mode 100644 index 000000000..a2bd279ae --- /dev/null +++ b/patch/kernel/archive/mvebu-6.2/compile-dtb-with-symbol-support.patch @@ -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 \ diff --git a/patch/kernel/archive/mvebu-6.2/dts-disable-spi-flash-on-a388-microsom.patch b/patch/kernel/archive/mvebu-6.2/dts-disable-spi-flash-on-a388-microsom.patch new file mode 100644 index 000000000..b6597a72f --- /dev/null +++ b/patch/kernel/archive/mvebu-6.2/dts-disable-spi-flash-on-a388-microsom.patch @@ -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"; + }; + }; + diff --git a/patch/kernel/archive/mvebu-6.2/general-increasing_DMA_block_memory_allocation_to_2048.patch b/patch/kernel/archive/mvebu-6.2/general-increasing_DMA_block_memory_allocation_to_2048.patch new file mode 100644 index 000000000..eef7296e7 --- /dev/null +++ b/patch/kernel/archive/mvebu-6.2/general-increasing_DMA_block_memory_allocation_to_2048.patch @@ -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; diff --git a/patch/kernel/archive/mvebu-6.2/unlock_atheros_regulatory_restrictions.patch b/patch/kernel/archive/mvebu-6.2/unlock_atheros_regulatory_restrictions.patch new file mode 100644 index 000000000..7e57c379a --- /dev/null +++ b/patch/kernel/archive/mvebu-6.2/unlock_atheros_regulatory_restrictions.patch @@ -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, diff --git a/patch/kernel/archive/mvebu-6.2/use-1000BaseX-clearfog-switch.patch b/patch/kernel/archive/mvebu-6.2/use-1000BaseX-clearfog-switch.patch new file mode 100644 index 000000000..900d0f114 --- /dev/null +++ b/patch/kernel/archive/mvebu-6.2/use-1000BaseX-clearfog-switch.patch @@ -0,0 +1,39 @@ +From 219f80b5cc03dab87fd05210b95c0b1a5afa8d33 Mon Sep 17 00:00:00 2001 +From: Russell King +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 +--- + 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 @@ + + ð1 { + /* 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 = <ð1>; +- fixed-link { +- speed = <1000>; +- full-duplex; +- }; + }; + + port@6 { diff --git a/patch/kernel/mvebu-edge b/patch/kernel/mvebu-edge index 981cc14ec..3d2d5e7f0 120000 --- a/patch/kernel/mvebu-edge +++ b/patch/kernel/mvebu-edge @@ -1 +1 @@ -archive/mvebu-6.1 \ No newline at end of file +archive/mvebu-6.2 \ No newline at end of file