lantiq: Add support for linux 4.1

All (still relevant) patches were refresh.
The following patches were dropped because they are applied upstream:
- 0003-MIPS-lantiq-handle-vmmc-memory-reservation.patch
- 0005-MIPS-lantiq-add-reset-controller-api-support.patch
- 0006-MIPS-lantiq-reboot-gphy-on-restart.patch
- 0009-MIPS-lantiq-command-line-work-around.patch
- 0010-MIPS-lantiq-export-soc-type.patch
- 0011-lantiq-add-support-for-xrx200-firmware-depending-on-.patch
- 0037-MIPS-lantiq-move-eiu-init-after-irq_domain-register.patch

Signed-off-by: Martin Blumenstingl <martin.blumenstingl@googlemail.com>

SVN-Revision: 46216
v19.07.3_mercusys_ac12_duma
John Crispin 9 years ago
parent 2658b33f68
commit ff08b09570

@ -0,0 +1,163 @@
CONFIG_ARCH_BINFMT_ELF_RANDOMIZE_PIE=y
CONFIG_ARCH_DISCARD_MEMBLOCK=y
CONFIG_ARCH_HAS_ATOMIC64_DEC_IF_POSITIVE=y
CONFIG_ARCH_HAVE_CUSTOM_GPIO_H=y
CONFIG_ARCH_HIBERNATION_POSSIBLE=y
CONFIG_ARCH_REQUIRE_GPIOLIB=y
CONFIG_ARCH_SUPPORTS_MSI=y
CONFIG_ARCH_SUSPEND_POSSIBLE=y
CONFIG_ARCH_WANT_IPC_PARSE_VERSION=y
CONFIG_CEVT_R4K=y
CONFIG_CLKDEV_LOOKUP=y
CONFIG_CPU_BIG_ENDIAN=y
CONFIG_CPU_GENERIC_DUMP_TLB=y
CONFIG_CPU_HAS_PREFETCH=y
CONFIG_CPU_HAS_SYNC=y
CONFIG_CPU_MIPS32=y
# CONFIG_CPU_MIPS32_R1 is not set
CONFIG_CPU_MIPS32_R2=y
CONFIG_CPU_MIPSR2=y
CONFIG_CPU_R4K_CACHE_TLB=y
CONFIG_CPU_R4K_FPU=y
CONFIG_CPU_SUPPORTS_32BIT_KERNEL=y
CONFIG_CPU_SUPPORTS_HIGHMEM=y
CONFIG_CRYPTO_HASH=y
CONFIG_CRYPTO_HASH2=y
CONFIG_CSRC_R4K=y
CONFIG_DECOMPRESS_LZMA=y
CONFIG_DMA_NONCOHERENT=y
CONFIG_DTC=y
CONFIG_DT_EASY50712=y
CONFIG_EARLY_PRINTK=y
CONFIG_ETHERNET_PACKET_MANGLE=y
CONFIG_GENERIC_ATOMIC64=y
CONFIG_GENERIC_CLOCKEVENTS=y
CONFIG_GENERIC_CLOCKEVENTS_BUILD=y
CONFIG_GENERIC_CMOS_UPDATE=y
CONFIG_GENERIC_GPIO=y
CONFIG_GENERIC_IO=y
CONFIG_GENERIC_IRQ_SHOW=y
CONFIG_GENERIC_PCI_IOMAP=y
CONFIG_GENERIC_SMP_IDLE_THREAD=y
CONFIG_GPIOLIB=y
CONFIG_GPIO_MM_LANTIQ=y
CONFIG_GPIO_STP_XWAY=y
CONFIG_GPIO_SYSFS=y
CONFIG_HARDWARE_WATCHPOINTS=y
CONFIG_HAS_DMA=y
CONFIG_HAS_IOMEM=y
CONFIG_HAS_IOPORT=y
CONFIG_HAVE_ARCH_JUMP_LABEL=y
CONFIG_HAVE_ARCH_KGDB=y
CONFIG_HAVE_ARCH_TRANSPARENT_HUGEPAGE=y
CONFIG_HAVE_CLK=y
CONFIG_HAVE_C_RECORDMCOUNT=y
CONFIG_HAVE_DEBUG_KMEMLEAK=y
CONFIG_HAVE_DMA_API_DEBUG=y
CONFIG_HAVE_DMA_ATTRS=y
CONFIG_HAVE_DYNAMIC_FTRACE=y
CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y
CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y
CONFIG_HAVE_FUNCTION_TRACER=y
CONFIG_HAVE_FUNCTION_TRACE_MCOUNT_TEST=y
CONFIG_HAVE_GENERIC_DMA_COHERENT=y
CONFIG_HAVE_GENERIC_HARDIRQS=y
CONFIG_HAVE_IDE=y
CONFIG_HAVE_KVM=y
CONFIG_HAVE_MACH_CLKDEV=y
CONFIG_HAVE_MEMBLOCK=y
CONFIG_HAVE_MEMBLOCK_NODE_MAP=y
CONFIG_HAVE_MOD_ARCH_SPECIFIC=y
CONFIG_HAVE_NET_DSA=y
CONFIG_HAVE_OPROFILE=y
CONFIG_HAVE_PERF_EVENTS=y
CONFIG_HW_HAS_PCI=y
CONFIG_HW_RANDOM=y
CONFIG_HZ=250
# CONFIG_HZ_100 is not set
CONFIG_HZ_250=y
CONFIG_INITRAMFS_SOURCE=""
CONFIG_IRQ_CPU=y
CONFIG_IRQ_DOMAIN=y
CONFIG_IRQ_FORCED_THREADING=y
CONFIG_LANTIQ=y
CONFIG_LANTIQ_ETOP=y
# CONFIG_LANTIQ_PHY is not set
CONFIG_LANTIQ_WDT=y
# CONFIG_LANTIQ_XRX200 is not set
CONFIG_LEDS_GPIO=y
CONFIG_MDIO_BOARDINFO=y
CONFIG_MIPS=y
# CONFIG_MIPS_CDMM is not set
# CONFIG_MIPS_HUGE_TLB_SUPPORT is not set
CONFIG_MIPS_L1_CACHE_SHIFT=5
# CONFIG_MIPS_MACHINE is not set
CONFIG_MIPS_MT_DISABLED=y
# CONFIG_MIPS_MT_SMP is not set
# CONFIG_MIPS_MT_SMTC is not set
# CONFIG_MIPS_VPE_LOADER is not set
CONFIG_MODULES_USE_ELF_REL=y
CONFIG_MTD_CFI_ADV_OPTIONS=y
CONFIG_MTD_CFI_GEOMETRY=y
CONFIG_MTD_CMDLINE_PARTS=y
CONFIG_MTD_JEDECPROBE=y
CONFIG_MTD_LANTIQ=y
CONFIG_MTD_M25P80=y
# CONFIG_MTD_NAND_XWAY is not set
CONFIG_MTD_SPI_NOR=y
CONFIG_MTD_SPLIT_FIRMWARE=y
CONFIG_MTD_UIMAGE_SPLIT=y
CONFIG_NEED_DMA_MAP_STATE=y
CONFIG_NEED_PER_CPU_KM=y
CONFIG_NO_GENERIC_PCI_IOPORT_MAP=y
CONFIG_OF=y
CONFIG_OF_ADDRESS=y
CONFIG_OF_DEVICE=y
CONFIG_OF_EARLY_FLATTREE=y
CONFIG_OF_FLATTREE=y
CONFIG_OF_GPIO=y
CONFIG_OF_IRQ=y
CONFIG_OF_MDIO=y
CONFIG_OF_MTD=y
CONFIG_OF_NET=y
CONFIG_OF_PCI=y
CONFIG_OF_PCI_IRQ=y
CONFIG_PAGEFLAGS_EXTENDED=y
CONFIG_PCI=y
# CONFIG_PCIE_LANTIQ is not set
CONFIG_PCI_DOMAINS=y
CONFIG_PCI_LANTIQ=y
CONFIG_PERCPU_RWSEM=y
CONFIG_PERF_USE_VMALLOC=y
CONFIG_PHYLIB=y
CONFIG_PINCTRL=y
# CONFIG_PINCTRL_AMD is not set
CONFIG_PINCTRL_LANTIQ=y
# CONFIG_PINCTRL_SINGLE is not set
CONFIG_PINCTRL_XWAY=y
# CONFIG_PREEMPT_RCU is not set
CONFIG_PROC_DEVICETREE=y
CONFIG_PSB6970_PHY=y
CONFIG_RTL8366RB_PHY=y
CONFIG_RTL8366_SMI=y
# CONFIG_SCSI_DMA is not set
# CONFIG_SERIAL_8250 is not set
CONFIG_SERIAL_LANTIQ=y
# CONFIG_SOC_AMAZON_SE is not set
# CONFIG_SOC_FALCON is not set
CONFIG_SOC_TYPE_XWAY=y
CONFIG_SOC_XWAY=y
CONFIG_SWAP_IO_SPACE=y
CONFIG_SWCONFIG=y
CONFIG_SYS_HAS_CPU_MIPS32_R1=y
CONFIG_SYS_HAS_CPU_MIPS32_R2=y
CONFIG_SYS_HAS_EARLY_PRINTK=y
CONFIG_SYS_SUPPORTS_32BIT_KERNEL=y
CONFIG_SYS_SUPPORTS_ARBIT_HZ=y
CONFIG_SYS_SUPPORTS_BIG_ENDIAN=y
CONFIG_SYS_SUPPORTS_MULTITHREADING=y
CONFIG_TICK_CPU_ACCOUNTING=y
CONFIG_UIDGID_CONVERTED=y
CONFIG_USB_ARCH_HAS_XHCI=y
CONFIG_USE_OF=y
CONFIG_ZONE_DMA_FLAG=0

@ -0,0 +1,31 @@
From 17348293f7f8103c97c8d2a6b0ef36eae06ec371 Mon Sep 17 00:00:00 2001
From: John Crispin <blogic@openwrt.org>
Date: Wed, 13 Mar 2013 09:36:16 +0100
Subject: [PATCH 02/36] MIPS: lantiq: dtb image hack
Signed-off-by: John Crispin <blogic@openwrt.org>
---
arch/mips/lantiq/Makefile | 2 --
arch/mips/lantiq/prom.c | 4 +++-
2 files changed, 3 insertions(+), 3 deletions(-)
--- a/arch/mips/lantiq/prom.c
+++ b/arch/mips/lantiq/prom.c
@@ -63,6 +63,8 @@ static void __init prom_init_cmdline(voi
}
}
+extern struct boot_param_header __image_dtb;
+
void __init plat_mem_setup(void)
{
ioport_resource.start = IOPORT_RESOURCE_START;
@@ -76,7 +78,7 @@ void __init plat_mem_setup(void)
* Load the builtin devicetree. This causes the chosen node to be
* parsed resulting in our memory appearing
*/
- __dt_setup_arch(__dtb_start);
+ __dt_setup_arch(&__image_dtb);
strlcpy(arcs_cmdline, boot_command_line, COMMAND_LINE_SIZE);
}

@ -0,0 +1,500 @@
From 9afadf01b1be371ee88491819aa67364684461f9 Mon Sep 17 00:00:00 2001
From: John Crispin <blogic@openwrt.org>
Date: Fri, 3 Aug 2012 10:27:25 +0200
Subject: [PATCH 04/36] MIPS: lantiq: add atm hack
Signed-off-by: John Crispin <blogic@openwrt.org>
---
arch/mips/include/asm/mach-lantiq/lantiq_atm.h | 196 +++++++++++++++++++++++
arch/mips/include/asm/mach-lantiq/lantiq_ptm.h | 203 ++++++++++++++++++++++++
arch/mips/lantiq/irq.c | 2 +
arch/mips/mm/cache.c | 2 +
include/uapi/linux/atm.h | 6 +
net/atm/common.c | 6 +
net/atm/proc.c | 2 +-
7 files changed, 416 insertions(+), 1 deletion(-)
create mode 100644 arch/mips/include/asm/mach-lantiq/lantiq_atm.h
create mode 100644 arch/mips/include/asm/mach-lantiq/lantiq_ptm.h
--- /dev/null
+++ b/arch/mips/include/asm/mach-lantiq/lantiq_atm.h
@@ -0,0 +1,196 @@
+/******************************************************************************
+**
+** FILE NAME : ifx_atm.h
+** PROJECT : UEIP
+** MODULES : ATM
+**
+** DATE : 17 Jun 2009
+** AUTHOR : Xu Liang
+** DESCRIPTION : Global ATM driver header file
+** COPYRIGHT : Copyright (c) 2006
+** Infineon Technologies AG
+** Am Campeon 1-12, 85579 Neubiberg, Germany
+**
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU General Public License as published by
+** the Free Software Foundation; either version 2 of the License, or
+** (at your option) any later version.
+**
+** HISTORY
+** $Date $Author $Comment
+** 07 JUL 2009 Xu Liang Init Version
+*******************************************************************************/
+
+#ifndef IFX_ATM_H
+#define IFX_ATM_H
+
+
+
+/*!
+ \defgroup IFX_ATM UEIP Project - ATM driver module
+ \brief UEIP Project - ATM driver module, support Danube, Amazon-SE, AR9, VR9.
+ */
+
+/*!
+ \defgroup IFX_ATM_IOCTL IOCTL Commands
+ \ingroup IFX_ATM
+ \brief IOCTL Commands used by user application.
+ */
+
+/*!
+ \defgroup IFX_ATM_STRUCT Structures
+ \ingroup IFX_ATM
+ \brief Structures used by user application.
+ */
+
+/*!
+ \file ifx_atm.h
+ \ingroup IFX_ATM
+ \brief ATM driver header file
+ */
+
+
+
+/*
+ * ####################################
+ * Definition
+ * ####################################
+ */
+
+/*!
+ \addtogroup IFX_ATM_STRUCT
+ */
+/*@{*/
+
+/*
+ * ATM MIB
+ */
+
+/*!
+ \struct atm_cell_ifEntry_t
+ \brief Structure used for Cell Level MIB Counters.
+
+ User application use this structure to call IOCTL command "PPE_ATM_MIB_CELL".
+ */
+typedef struct {
+ __u32 ifHCInOctets_h; /*!< byte counter of ingress cells (upper 32 bits, total 64 bits) */
+ __u32 ifHCInOctets_l; /*!< byte counter of ingress cells (lower 32 bits, total 64 bits) */
+ __u32 ifHCOutOctets_h; /*!< byte counter of egress cells (upper 32 bits, total 64 bits) */
+ __u32 ifHCOutOctets_l; /*!< byte counter of egress cells (lower 32 bits, total 64 bits) */
+ __u32 ifInErrors; /*!< counter of error ingress cells */
+ __u32 ifInUnknownProtos; /*!< counter of unknown ingress cells */
+ __u32 ifOutErrors; /*!< counter of error egress cells */
+} atm_cell_ifEntry_t;
+
+/*!
+ \struct atm_aal5_ifEntry_t
+ \brief Structure used for AAL5 Frame Level MIB Counters.
+
+ User application use this structure to call IOCTL command "PPE_ATM_MIB_AAL5".
+ */
+typedef struct {
+ __u32 ifHCInOctets_h; /*!< byte counter of ingress packets (upper 32 bits, total 64 bits) */
+ __u32 ifHCInOctets_l; /*!< byte counter of ingress packets (lower 32 bits, total 64 bits) */
+ __u32 ifHCOutOctets_h; /*!< byte counter of egress packets (upper 32 bits, total 64 bits) */
+ __u32 ifHCOutOctets_l; /*!< byte counter of egress packets (lower 32 bits, total 64 bits) */
+ __u32 ifInUcastPkts; /*!< counter of ingress packets */
+ __u32 ifOutUcastPkts; /*!< counter of egress packets */
+ __u32 ifInErrors; /*!< counter of error ingress packets */
+ __u32 ifInDiscards; /*!< counter of dropped ingress packets */
+ __u32 ifOutErros; /*!< counter of error egress packets */
+ __u32 ifOutDiscards; /*!< counter of dropped egress packets */
+} atm_aal5_ifEntry_t;
+
+/*!
+ \struct atm_aal5_vcc_t
+ \brief Structure used for per PVC AAL5 Frame Level MIB Counters.
+
+ This structure is a part of structure "atm_aal5_vcc_x_t".
+ */
+typedef struct {
+ __u32 aal5VccCrcErrors; /*!< counter of ingress packets with CRC error */
+ __u32 aal5VccSarTimeOuts; /*!< counter of ingress packets with Re-assemble timeout */ //no timer support yet
+ __u32 aal5VccOverSizedSDUs; /*!< counter of oversized ingress packets */
+} atm_aal5_vcc_t;
+
+/*!
+ \struct atm_aal5_vcc_x_t
+ \brief Structure used for per PVC AAL5 Frame Level MIB Counters.
+
+ User application use this structure to call IOCTL command "PPE_ATM_MIB_VCC".
+ */
+typedef struct {
+ int vpi; /*!< VPI of the VCC to get MIB counters */
+ int vci; /*!< VCI of the VCC to get MIB counters */
+ atm_aal5_vcc_t mib_vcc; /*!< structure to get MIB counters */
+} atm_aal5_vcc_x_t;
+
+/*@}*/
+
+
+
+/*
+ * ####################################
+ * IOCTL
+ * ####################################
+ */
+
+/*!
+ \addtogroup IFX_ATM_IOCTL
+ */
+/*@{*/
+
+/*
+ * ioctl Command
+ */
+/*!
+ \brief ATM IOCTL Magic Number
+ */
+#define PPE_ATM_IOC_MAGIC 'o'
+/*!
+ \brief ATM IOCTL Command - Get Cell Level MIB Counters
+
+ This command is obsolete. User can get cell level MIB from DSL API.
+ This command uses structure "atm_cell_ifEntry_t" as parameter for output of MIB counters.
+ */
+#define PPE_ATM_MIB_CELL _IOW(PPE_ATM_IOC_MAGIC, 0, atm_cell_ifEntry_t)
+/*!
+ \brief ATM IOCTL Command - Get AAL5 Level MIB Counters
+
+ Get AAL5 packet counters.
+ This command uses structure "atm_aal5_ifEntry_t" as parameter for output of MIB counters.
+ */
+#define PPE_ATM_MIB_AAL5 _IOW(PPE_ATM_IOC_MAGIC, 1, atm_aal5_ifEntry_t)
+/*!
+ \brief ATM IOCTL Command - Get Per PVC MIB Counters
+
+ Get AAL5 packet counters for each PVC.
+ This command uses structure "atm_aal5_vcc_x_t" as parameter for input of VPI/VCI information and output of MIB counters.
+ */
+#define PPE_ATM_MIB_VCC _IOWR(PPE_ATM_IOC_MAGIC, 2, atm_aal5_vcc_x_t)
+/*!
+ \brief Total Number of ATM IOCTL Commands
+ */
+#define PPE_ATM_IOC_MAXNR 3
+
+/*@}*/
+
+
+
+/*
+ * ####################################
+ * API
+ * ####################################
+ */
+
+#ifdef __KERNEL__
+struct port_cell_info {
+ unsigned int port_num;
+ unsigned int tx_link_rate[2];
+};
+#endif
+
+
+
+#endif // IFX_ATM_H
+
--- /dev/null
+++ b/arch/mips/include/asm/mach-lantiq/lantiq_ptm.h
@@ -0,0 +1,203 @@
+/******************************************************************************
+**
+** FILE NAME : ifx_ptm.h
+** PROJECT : UEIP
+** MODULES : PTM
+**
+** DATE : 17 Jun 2009
+** AUTHOR : Xu Liang
+** DESCRIPTION : Global PTM driver header file
+** COPYRIGHT : Copyright (c) 2006
+** Infineon Technologies AG
+** Am Campeon 1-12, 85579 Neubiberg, Germany
+**
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU General Public License as published by
+** the Free Software Foundation; either version 2 of the License, or
+** (at your option) any later version.
+**
+** HISTORY
+** $Date $Author $Comment
+** 07 JUL 2009 Xu Liang Init Version
+*******************************************************************************/
+
+#ifndef IFX_PTM_H
+#define IFX_PTM_H
+
+
+
+/*!
+ \defgroup IFX_PTM UEIP Project - PTM driver module
+ \brief UEIP Project - PTM driver module, support Danube, Amazon-SE, AR9, VR9.
+ */
+
+/*!
+ \defgroup IFX_PTM_IOCTL IOCTL Commands
+ \ingroup IFX_PTM
+ \brief IOCTL Commands used by user application.
+ */
+
+/*!
+ \defgroup IFX_PTM_STRUCT Structures
+ \ingroup IFX_PTM
+ \brief Structures used by user application.
+ */
+
+/*!
+ \file ifx_ptm.h
+ \ingroup IFX_PTM
+ \brief PTM driver header file
+ */
+
+
+
+/*
+ * ####################################
+ * Definition
+ * ####################################
+ */
+
+
+
+/*
+ * ####################################
+ * IOCTL
+ * ####################################
+ */
+
+/*!
+ \addtogroup IFX_PTM_IOCTL
+ */
+/*@{*/
+
+/*
+ * ioctl Command
+ */
+/*!
+ \brief PTM IOCTL Command - Get codeword MIB counters.
+
+ This command uses structure "PTM_CW_IF_ENTRY_T" to get codeword level MIB counters.
+ */
+#define IFX_PTM_MIB_CW_GET SIOCDEVPRIVATE + 1
+/*!
+ \brief PTM IOCTL Command - Get packet MIB counters.
+
+ This command uses structure "PTM_FRAME_MIB_T" to get packet level MIB counters.
+ */
+#define IFX_PTM_MIB_FRAME_GET SIOCDEVPRIVATE + 2
+/*!
+ \brief PTM IOCTL Command - Get firmware configuration (CRC).
+
+ This command uses structure "IFX_PTM_CFG_T" to get firmware configuration (CRC).
+ */
+#define IFX_PTM_CFG_GET SIOCDEVPRIVATE + 3
+/*!
+ \brief PTM IOCTL Command - Set firmware configuration (CRC).
+
+ This command uses structure "IFX_PTM_CFG_T" to set firmware configuration (CRC).
+ */
+#define IFX_PTM_CFG_SET SIOCDEVPRIVATE + 4
+/*!
+ \brief PTM IOCTL Command - Program priority value to TX queue mapping.
+
+ This command uses structure "IFX_PTM_PRIO_Q_MAP_T" to program priority value to TX queue mapping.
+ */
+#define IFX_PTM_MAP_PKT_PRIO_TO_Q SIOCDEVPRIVATE + 14
+
+/*@}*/
+
+
+/*!
+ \addtogroup IFX_PTM_STRUCT
+ */
+/*@{*/
+
+/*
+ * ioctl Data Type
+ */
+
+/*!
+ \typedef PTM_CW_IF_ENTRY_T
+ \brief Wrapping of structure "ptm_cw_ifEntry_t".
+ */
+/*!
+ \struct ptm_cw_ifEntry_t
+ \brief Structure used for CodeWord level MIB counters.
+ */
+typedef struct ptm_cw_ifEntry_t {
+ uint32_t ifRxNoIdleCodewords; /*!< output, number of ingress user codeword */
+ uint32_t ifRxIdleCodewords; /*!< output, number of ingress idle codeword */
+ uint32_t ifRxCodingViolation; /*!< output, number of error ingress codeword */
+ uint32_t ifTxNoIdleCodewords; /*!< output, number of egress user codeword */
+ uint32_t ifTxIdleCodewords; /*!< output, number of egress idle codeword */
+} PTM_CW_IF_ENTRY_T;
+
+/*!
+ \typedef PTM_FRAME_MIB_T
+ \brief Wrapping of structure "ptm_frame_mib_t".
+ */
+/*!
+ \struct ptm_frame_mib_t
+ \brief Structure used for packet level MIB counters.
+ */
+typedef struct ptm_frame_mib_t {
+ uint32_t RxCorrect; /*!< output, number of ingress packet */
+ uint32_t TC_CrcError; /*!< output, number of egress packet with CRC error */
+ uint32_t RxDropped; /*!< output, number of dropped ingress packet */
+ uint32_t TxSend; /*!< output, number of egress packet */
+} PTM_FRAME_MIB_T;
+
+/*!
+ \typedef IFX_PTM_CFG_T
+ \brief Wrapping of structure "ptm_cfg_t".
+ */
+/*!
+ \struct ptm_cfg_t
+ \brief Structure used for ETH/TC CRC configuration.
+ */
+typedef struct ptm_cfg_t {
+ uint32_t RxEthCrcPresent; /*!< input/output, ingress packet has ETH CRC */
+ uint32_t RxEthCrcCheck; /*!< input/output, check ETH CRC of ingress packet */
+ uint32_t RxTcCrcCheck; /*!< input/output, check TC CRC of ingress codeword */
+ uint32_t RxTcCrcLen; /*!< input/output, length of TC CRC of ingress codeword */
+ uint32_t TxEthCrcGen; /*!< input/output, generate ETH CRC for egress packet */
+ uint32_t TxTcCrcGen; /*!< input/output, generate TC CRC for egress codeword */
+ uint32_t TxTcCrcLen; /*!< input/output, length of TC CRC of egress codeword */
+} IFX_PTM_CFG_T;
+
+/*!
+ \typedef IFX_PTM_PRIO_Q_MAP_T
+ \brief Wrapping of structure "ppe_prio_q_map".
+ */
+/*!
+ \struct ppe_prio_q_map
+ \brief Structure used for Priority Value to TX Queue mapping.
+ */
+typedef struct ppe_prio_q_map {
+ int pkt_prio;
+ int qid;
+ int vpi; // ignored in eth interface
+ int vci; // ignored in eth interface
+} IFX_PTM_PRIO_Q_MAP_T;
+
+/*@}*/
+
+
+
+/*
+ * ####################################
+ * API
+ * ####################################
+ */
+
+#ifdef __KERNEL__
+struct port_cell_info {
+ unsigned int port_num;
+ unsigned int tx_link_rate[2];
+};
+#endif
+
+
+
+#endif // IFX_PTM_H
+
--- a/arch/mips/lantiq/irq.c
+++ b/arch/mips/lantiq/irq.c
@@ -14,6 +14,7 @@
#include <linux/of_platform.h>
#include <linux/of_address.h>
#include <linux/of_irq.h>
+#include <linux/module.h>
#include <asm/bootinfo.h>
#include <asm/irq_cpu.h>
@@ -100,6 +101,7 @@ void ltq_mask_and_ack_irq(struct irq_dat
ltq_icu_w32(im, ltq_icu_r32(im, ier) & ~BIT(offset), ier);
ltq_icu_w32(im, BIT(offset), isr);
}
+EXPORT_SYMBOL(ltq_mask_and_ack_irq);
static void ltq_ack_irq(struct irq_data *d)
{
--- a/arch/mips/mm/cache.c
+++ b/arch/mips/mm/cache.c
@@ -59,6 +59,8 @@ void (*_dma_cache_wback)(unsigned long s
void (*_dma_cache_inv)(unsigned long start, unsigned long size);
EXPORT_SYMBOL(_dma_cache_wback_inv);
+EXPORT_SYMBOL(_dma_cache_wback);
+EXPORT_SYMBOL(_dma_cache_inv);
#endif /* CONFIG_DMA_NONCOHERENT || CONFIG_DMA_MAYBE_COHERENT */
--- a/include/uapi/linux/atm.h
+++ b/include/uapi/linux/atm.h
@@ -130,8 +130,14 @@
#define ATM_ABR 4
#define ATM_ANYCLASS 5 /* compatible with everything */
+#define ATM_VBR_NRT ATM_VBR
+#define ATM_VBR_RT 6
+#define ATM_UBR_PLUS 7
+#define ATM_GFR 8
+
#define ATM_MAX_PCR -1 /* maximum available PCR */
+
struct atm_trafprm {
unsigned char traffic_class; /* traffic class (ATM_UBR, ...) */
int max_pcr; /* maximum PCR in cells per second */
--- a/net/atm/common.c
+++ b/net/atm/common.c
@@ -62,11 +62,17 @@ static void vcc_remove_socket(struct soc
write_unlock_irq(&vcc_sklist_lock);
}
+struct sk_buff* (*ifx_atm_alloc_tx)(struct atm_vcc *, unsigned int) = NULL;
+EXPORT_SYMBOL(ifx_atm_alloc_tx);
+
static struct sk_buff *alloc_tx(struct atm_vcc *vcc, unsigned int size)
{
struct sk_buff *skb;
struct sock *sk = sk_atm(vcc);
+ if (ifx_atm_alloc_tx != NULL)
+ return ifx_atm_alloc_tx(vcc, size);
+
if (sk_wmem_alloc_get(sk) && !atm_may_send(vcc, size)) {
pr_debug("Sorry: wmem_alloc = %d, size = %d, sndbuf = %d\n",
sk_wmem_alloc_get(sk), size, sk->sk_sndbuf);
--- a/net/atm/proc.c
+++ b/net/atm/proc.c
@@ -154,7 +154,7 @@ static void *vcc_seq_next(struct seq_fil
static void pvc_info(struct seq_file *seq, struct atm_vcc *vcc)
{
static const char *const class_name[] = {
- "off", "UBR", "CBR", "VBR", "ABR"};
+ "off","UBR","CBR","NTR-VBR","ABR","ANY","RT-VBR","UBR+","GFR"};
static const char *const aal_name[] = {
"---", "1", "2", "3/4", /* 0- 3 */
"???", "5", "???", "???", /* 4- 7 */

@ -0,0 +1,111 @@
From d27ec8bb97db0f60d81ab255d51ac4e967362067 Mon Sep 17 00:00:00 2001
From: John Crispin <blogic@openwrt.org>
Date: Thu, 7 Aug 2014 18:34:19 +0200
Subject: [PATCH 07/36] MIPS: lantiq: add basic tffs driver
Signed-off-by: John Crispin <blogic@openwrt.org>
---
arch/mips/lantiq/xway/Makefile | 2 +-
arch/mips/lantiq/xway/tffs.c | 87 ++++++++++++++++++++++++++++++++++++++++
2 files changed, 88 insertions(+), 1 deletion(-)
create mode 100644 arch/mips/lantiq/xway/tffs.c
--- a/arch/mips/lantiq/xway/Makefile
+++ b/arch/mips/lantiq/xway/Makefile
@@ -1,5 +1,5 @@
obj-y := prom.o sysctrl.o clk.o reset.o dma.o gptu.o dcdc.o
-obj-y += vmmc.o
+obj-y += vmmc.o tffs.o
obj-$(CONFIG_XRX200_PHY_FW) += xrx200_phy_fw.o
--- /dev/null
+++ b/arch/mips/lantiq/xway/tffs.c
@@ -0,0 +1,87 @@
+#include <linux/module.h>
+#include <linux/mtd/mtd.h>
+#include <linux/errno.h>
+#include <linux/slab.h>
+
+struct tffs_entry {
+ uint16_t id;
+ uint16_t len;
+};
+
+static struct tffs_id {
+ uint32_t id;
+ char *name;
+ unsigned char *val;
+ uint32_t offset;
+ uint32_t len;
+} ids[] = {
+ { 0x01A9, "annex" },
+ { 0x0188, "maca" },
+ { 0x0189, "macb" },
+ { 0x018a, "macwlan" },
+ { 0x0195, "macwlan2" },
+ { 0x018b, "macdsl" },
+ { 0x01C2, "webgui_pass" },
+ { 0x01AB, "wlan_key" },
+};
+
+static struct mtd_info *tffs1, *tffs2;
+
+static struct tffs_id* tffs_find_id(int id)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(ids); i++)
+ if (id == ids[i].id)
+ return &ids[i];
+
+ return NULL;
+}
+
+static void tffs_index(void)
+{
+ struct tffs_entry *E = NULL;
+ struct tffs_entry entry;
+ int ret, retlen;
+
+ while ((unsigned int) E + sizeof(struct tffs_entry) < tffs2->size) {
+ struct tffs_id *id;
+ int len;
+
+ ret = mtd_read(tffs2, (unsigned int) E, sizeof(struct tffs_entry), &retlen, (unsigned char *)&entry);
+ if (ret)
+ return;
+
+ if (entry.id == 0xffff)
+ return;
+
+ id = tffs_find_id(entry.id);
+ if (id) {
+ id->offset = (uint32_t) E;
+ id->len = entry.len;
+ id->val = kzalloc(entry.len + 1, GFP_KERNEL);
+ mtd_read(tffs2, ((unsigned int) E) + sizeof(struct tffs_entry), entry.len, &retlen, id->val);
+
+ }
+ //printk(KERN_INFO "found entry at 0x%08X-> [<0x%x> %u bytes]\n", (uint32_t) E, entry.id, entry.len);
+ if (id && id->name)
+ printk(KERN_INFO "found entry name -> %s=%s\n", id->name, id->val);
+
+ len = (entry.len + 3) & ~0x03;
+ E = (struct tffs_entry *)(((unsigned int)E) + sizeof(struct tffs_entry) + len);
+ }
+}
+
+static int __init tffs_init(void)
+{
+ tffs1 = get_mtd_device_nm("tffs (1)");
+ tffs2 = get_mtd_device_nm("tffs (2)");
+ if (IS_ERR(tffs1) || IS_ERR(tffs2))
+ return -1;
+
+ tffs_index();
+
+ return 0;
+}
+late_initcall(tffs_init);
+

@ -0,0 +1,79 @@
From 25494c55a4007a1409f53ddbafd661636e47ea34 Mon Sep 17 00:00:00 2001
From: John Crispin <blogic@openwrt.org>
Date: Fri, 9 Aug 2013 20:38:15 +0200
Subject: [PATCH 12/36] pinctrl/lantiq: fix up pinmux
We found out how to set the gphy led pinmuxing.
Signed-off-by: John Crispin <blogic@openwrt.org>
---
drivers/pinctrl/pinctrl-xway.c | 28 ++++++++++++++++++++++++++--
1 file changed, 26 insertions(+), 2 deletions(-)
--- a/drivers/pinctrl/pinctrl-xway.c
+++ b/drivers/pinctrl/pinctrl-xway.c
@@ -609,10 +609,9 @@ static struct pinctrl_desc xway_pctrl_de
.confops = &xway_pinconf_ops,
};
-static inline int xway_mux_apply(struct pinctrl_dev *pctrldev,
+static int mux_apply(struct ltq_pinmux_info *info,
int pin, int mux)
{
- struct ltq_pinmux_info *info = pinctrl_dev_get_drvdata(pctrldev);
int port = PORT(pin);
u32 alt1_reg = GPIO_ALT1(pin);
@@ -632,6 +631,14 @@ static inline int xway_mux_apply(struct
return 0;
}
+static inline int xway_mux_apply(struct pinctrl_dev *pctrldev,
+ int pin, int mux)
+{
+ struct ltq_pinmux_info *info = pinctrl_dev_get_drvdata(pctrldev);
+
+ return mux_apply(info, pin, mux);
+}
+
static const struct ltq_cfg_param xway_cfg_params[] = {
{"lantiq,pull", LTQ_PINCONF_PARAM_PULL},
{"lantiq,open-drain", LTQ_PINCONF_PARAM_OPEN_DRAIN},
@@ -676,6 +683,10 @@ static int xway_gpio_dir_out(struct gpio
{
struct ltq_pinmux_info *info = dev_get_drvdata(chip->dev);
+ if (PORT(pin) == PORT3)
+ gpio_setbit(info->membase[0], GPIO3_OD, PORT_PIN(pin));
+ else
+ gpio_setbit(info->membase[0], GPIO_OD(pin), PORT_PIN(pin));
gpio_setbit(info->membase[0], GPIO_DIR(pin), PORT_PIN(pin));
xway_gpio_set(chip, pin, val);
@@ -696,6 +707,18 @@ static void xway_gpio_free(struct gpio_c
pinctrl_free_gpio(gpio);
}
+static int xway_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
+{
+ struct ltq_pinmux_info *info = dev_get_drvdata(chip->dev);
+ int i;
+
+ for (i = 0; i < info->num_exin; i++)
+ if (info->exin[i] == offset)
+ return ltq_eiu_get_irq(i);
+
+ return -1;
+}
+
static struct gpio_chip xway_chip = {
.label = "gpio-xway",
.direction_input = xway_gpio_dir_in,
@@ -704,6 +727,7 @@ static struct gpio_chip xway_chip = {
.set = xway_gpio_set,
.request = xway_gpio_req,
.free = xway_gpio_free,
+ .to_irq = xway_gpio_to_irq,
.base = -1,
};

@ -0,0 +1,24 @@
From 8e34da603f442624bb70e887d8f42064bb924224 Mon Sep 17 00:00:00 2001
From: John Crispin <blogic@openwrt.org>
Date: Sun, 28 Jul 2013 18:03:54 +0200
Subject: [PATCH 13/36] MTD: lantiq: xway: fix invalid operator
xway_read_byte should use a logic or and not an add operator when working out
the nand address.
Signed-off-by: John Crispin <blogic@openwrt.org>
---
drivers/mtd/nand/xway_nand.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
--- a/drivers/mtd/nand/xway_nand.c
+++ b/drivers/mtd/nand/xway_nand.c
@@ -124,7 +124,7 @@ static unsigned char xway_read_byte(stru
int ret;
spin_lock_irqsave(&ebu_lock, flags);
- ret = ltq_r8((void __iomem *)(nandaddr + NAND_READ_DATA));
+ ret = ltq_r8((void __iomem *)(nandaddr | NAND_READ_DATA));
spin_unlock_irqrestore(&ebu_lock, flags);
return ret;

@ -0,0 +1,44 @@
From b454cefd675fc1bd3d8c690c1bd1d8f4678e9922 Mon Sep 17 00:00:00 2001
From: John Crispin <blogic@openwrt.org>
Date: Sun, 28 Jul 2013 18:06:39 +0200
Subject: [PATCH 14/36] MTD: lantiq: xway: the latched command should be
persistent
Signed-off-by: John Crispin <blogic@openwrt.org>
---
drivers/mtd/nand/xway_nand.c | 12 ++++++------
1 file changed, 6 insertions(+), 6 deletions(-)
--- a/drivers/mtd/nand/xway_nand.c
+++ b/drivers/mtd/nand/xway_nand.c
@@ -54,6 +54,8 @@
#define NAND_CON_CSMUX (1 << 1)
#define NAND_CON_NANDM 1
+static u32 xway_latchcmd;
+
static void xway_reset_chip(struct nand_chip *chip)
{
unsigned long nandaddr = (unsigned long) chip->IO_ADDR_W;
@@ -94,17 +96,15 @@ static void xway_cmd_ctrl(struct mtd_inf
unsigned long flags;
if (ctrl & NAND_CTRL_CHANGE) {
- nandaddr &= ~(NAND_WRITE_CMD | NAND_WRITE_ADDR);
if (ctrl & NAND_CLE)
- nandaddr |= NAND_WRITE_CMD;
- else
- nandaddr |= NAND_WRITE_ADDR;
- this->IO_ADDR_W = (void __iomem *) nandaddr;
+ xway_latchcmd = NAND_WRITE_CMD;
+ else if (ctrl & NAND_ALE)
+ xway_latchcmd = NAND_WRITE_ADDR;
}
if (cmd != NAND_CMD_NONE) {
spin_lock_irqsave(&ebu_lock, flags);
- writeb(cmd, this->IO_ADDR_W);
+ writeb(cmd, (void __iomem *) (nandaddr | xway_latchcmd));
while ((ltq_ebu_r32(EBU_NAND_WAIT) & NAND_WAIT_WR_C) == 0)
;
spin_unlock_irqrestore(&ebu_lock, flags);

@ -0,0 +1,41 @@
From 76e153079f02d26e3357302d2886a0c8aaaec64d Mon Sep 17 00:00:00 2001
From: John Crispin <blogic@openwrt.org>
Date: Sun, 28 Jul 2013 18:02:06 +0200
Subject: [PATCH 15/36] MTD: lantiq: xway: remove endless loop
The reset loop logic could run into a endless loop. Lets fix it as requested.
--> http://lists.infradead.org/pipermail/linux-mtd/2012-September/044240.html
Signed-off-by: John Crispin <blogic@openwrt.org>
---
drivers/mtd/nand/xway_nand.c | 10 ++++++++--
1 file changed, 8 insertions(+), 2 deletions(-)
--- a/drivers/mtd/nand/xway_nand.c
+++ b/drivers/mtd/nand/xway_nand.c
@@ -59,16 +59,22 @@ static u32 xway_latchcmd;
static void xway_reset_chip(struct nand_chip *chip)
{
unsigned long nandaddr = (unsigned long) chip->IO_ADDR_W;
+ unsigned long timeout;
unsigned long flags;
nandaddr &= ~NAND_WRITE_ADDR;
nandaddr |= NAND_WRITE_CMD;
/* finish with a reset */
+ timeout = jiffies + msecs_to_jiffies(20);
+
spin_lock_irqsave(&ebu_lock, flags);
writeb(NAND_WRITE_CMD_RESET, (void __iomem *) nandaddr);
- while ((ltq_ebu_r32(EBU_NAND_WAIT) & NAND_WAIT_WR_C) == 0)
- ;
+ do {
+ if ((ltq_ebu_r32(EBU_NAND_WAIT) & NAND_WAIT_WR_C) == 0)
+ break;
+ cond_resched();
+ } while (!time_after_eq(jiffies, timeout));
spin_unlock_irqrestore(&ebu_lock, flags);
}

@ -0,0 +1,55 @@
From 65df9d63eaee02c25e879b33dd42aceb78e57842 Mon Sep 17 00:00:00 2001
From: John Crispin <blogic@openwrt.org>
Date: Sun, 28 Jul 2013 17:59:51 +0200
Subject: [PATCH 16/36] MTD: lantiq: xway: add missing write_buf and read_buf
to nand driver
Signed-off-by: John Crispin <blogic@openwrt.org>
---
drivers/mtd/nand/xway_nand.c | 28 ++++++++++++++++++++++++++++
1 file changed, 28 insertions(+)
--- a/drivers/mtd/nand/xway_nand.c
+++ b/drivers/mtd/nand/xway_nand.c
@@ -136,6 +136,32 @@ static unsigned char xway_read_byte(stru
return ret;
}
+static void xway_read_buf(struct mtd_info *mtd, u_char *buf, int len)
+{
+ struct nand_chip *this = mtd->priv;
+ unsigned long nandaddr = (unsigned long) this->IO_ADDR_R;
+ unsigned long flags;
+ int i;
+
+ spin_lock_irqsave(&ebu_lock, flags);
+ for (i = 0; i < len; i++)
+ buf[i] = ltq_r8((void __iomem *)(nandaddr | NAND_READ_DATA));
+ spin_unlock_irqrestore(&ebu_lock, flags);
+}
+
+static void xway_write_buf(struct mtd_info *mtd, const u_char *buf, int len)
+{
+ struct nand_chip *this = mtd->priv;
+ unsigned long nandaddr = (unsigned long) this->IO_ADDR_W;
+ unsigned long flags;
+ int i;
+
+ spin_lock_irqsave(&ebu_lock, flags);
+ for (i = 0; i < len; i++)
+ ltq_w8(buf[i], (void __iomem *)(nandaddr | NAND_WRITE_DATA));
+ spin_unlock_irqrestore(&ebu_lock, flags);
+}
+
static int xway_nand_probe(struct platform_device *pdev)
{
struct nand_chip *this = platform_get_drvdata(pdev);
@@ -181,6 +207,8 @@ static struct platform_nand_data xway_na
.dev_ready = xway_dev_ready,
.select_chip = xway_select_chip,
.read_byte = xway_read_byte,
+ .read_buf = xway_read_buf,
+ .write_buf = xway_write_buf,
}
};

@ -0,0 +1,89 @@
From aa705c1b0860da91f2ed1a4c0b57337e6de689e1 Mon Sep 17 00:00:00 2001
From: John Crispin <blogic@openwrt.org>
Date: Thu, 7 Aug 2014 18:55:31 +0200
Subject: [PATCH 17/36] MTD: xway: fix nand locking
Signed-off-by: John Crispin <blogic@openwrt.org>
---
drivers/mtd/nand/xway_nand.c | 15 +++------------
1 file changed, 3 insertions(+), 12 deletions(-)
--- a/drivers/mtd/nand/xway_nand.c
+++ b/drivers/mtd/nand/xway_nand.c
@@ -80,13 +80,16 @@ static void xway_reset_chip(struct nand_
static void xway_select_chip(struct mtd_info *mtd, int chip)
{
+ static unsigned long csflags;
switch (chip) {
case -1:
ltq_ebu_w32_mask(NAND_CON_CE, 0, EBU_NAND_CON);
ltq_ebu_w32_mask(NAND_CON_NANDM, 0, EBU_NAND_CON);
+ spin_unlock_irqrestore(&ebu_lock, csflags);
break;
case 0:
+ spin_lock_irqsave(&ebu_lock, csflags);
ltq_ebu_w32_mask(0, NAND_CON_NANDM, EBU_NAND_CON);
ltq_ebu_w32_mask(0, NAND_CON_CE, EBU_NAND_CON);
break;
@@ -99,7 +102,6 @@ static void xway_cmd_ctrl(struct mtd_inf
{
struct nand_chip *this = mtd->priv;
unsigned long nandaddr = (unsigned long) this->IO_ADDR_W;
- unsigned long flags;
if (ctrl & NAND_CTRL_CHANGE) {
if (ctrl & NAND_CLE)
@@ -109,11 +111,9 @@ static void xway_cmd_ctrl(struct mtd_inf
}
if (cmd != NAND_CMD_NONE) {
- spin_lock_irqsave(&ebu_lock, flags);
writeb(cmd, (void __iomem *) (nandaddr | xway_latchcmd));
while ((ltq_ebu_r32(EBU_NAND_WAIT) & NAND_WAIT_WR_C) == 0)
;
- spin_unlock_irqrestore(&ebu_lock, flags);
}
}
@@ -126,12 +126,9 @@ static unsigned char xway_read_byte(stru
{
struct nand_chip *this = mtd->priv;
unsigned long nandaddr = (unsigned long) this->IO_ADDR_R;
- unsigned long flags;
int ret;
- spin_lock_irqsave(&ebu_lock, flags);
ret = ltq_r8((void __iomem *)(nandaddr | NAND_READ_DATA));
- spin_unlock_irqrestore(&ebu_lock, flags);
return ret;
}
@@ -140,26 +137,20 @@ static void xway_read_buf(struct mtd_inf
{
struct nand_chip *this = mtd->priv;
unsigned long nandaddr = (unsigned long) this->IO_ADDR_R;
- unsigned long flags;
int i;
- spin_lock_irqsave(&ebu_lock, flags);
for (i = 0; i < len; i++)
buf[i] = ltq_r8((void __iomem *)(nandaddr | NAND_READ_DATA));
- spin_unlock_irqrestore(&ebu_lock, flags);
}
static void xway_write_buf(struct mtd_info *mtd, const u_char *buf, int len)
{
struct nand_chip *this = mtd->priv;
unsigned long nandaddr = (unsigned long) this->IO_ADDR_W;
- unsigned long flags;
int i;
- spin_lock_irqsave(&ebu_lock, flags);
for (i = 0; i < len; i++)
ltq_w8(buf[i], (void __iomem *)(nandaddr | NAND_WRITE_DATA));
- spin_unlock_irqrestore(&ebu_lock, flags);
}
static int xway_nand_probe(struct platform_device *pdev)

@ -0,0 +1,125 @@
From 997a8965db8417266bea3fbdcfa3e5655a1b52fa Mon Sep 17 00:00:00 2001
From: John Crispin <blogic@openwrt.org>
Date: Tue, 9 Sep 2014 23:12:15 +0200
Subject: [PATCH 18/36] MTD: nand: lots of xrx200 fixes
Signed-off-by: John Crispin <blogic@openwrt.org>
---
drivers/mtd/nand/xway_nand.c | 63 ++++++++++++++++++++++++++++++++++++++++++
1 file changed, 63 insertions(+)
--- a/drivers/mtd/nand/xway_nand.c
+++ b/drivers/mtd/nand/xway_nand.c
@@ -54,8 +54,27 @@
#define NAND_CON_CSMUX (1 << 1)
#define NAND_CON_NANDM 1
+#define DANUBE_PCI_REG32( addr ) (*(volatile u32 *)(addr))
+#define PCI_CR_PR_OFFSET (KSEG1+0x1E105400)
+#define PCI_CR_PC_ARB (PCI_CR_PR_OFFSET + 0x0080)
+
static u32 xway_latchcmd;
+/*
+ * req_mask provides a mechanism to prevent interference between
+ * nand and pci (probably only relevant for the BT Home Hub 2B).
+ * Setting it causes the corresponding pci req pins to be masked
+ * during nand access, and also moves ebu locking from the read/write
+ * functions to the chip select function to ensure that the whole
+ * operation runs with interrupts disabled.
+ * In addition it switches on some extra waiting in xway_cmd_ctrl().
+ * This seems to be necessary if the ebu_cs1 pin has open-drain disabled,
+ * which in turn seems to be necessary for the nor chip to be recognised
+ * reliably, on a board (Home Hub 2B again) which has both nor and nand.
+ */
+
+static __be32 req_mask = 0;
+
static void xway_reset_chip(struct nand_chip *chip)
{
unsigned long nandaddr = (unsigned long) chip->IO_ADDR_W;
@@ -86,12 +105,24 @@ static void xway_select_chip(struct mtd_
case -1:
ltq_ebu_w32_mask(NAND_CON_CE, 0, EBU_NAND_CON);
ltq_ebu_w32_mask(NAND_CON_NANDM, 0, EBU_NAND_CON);
+
+ if (req_mask) {
+ /* Unmask all external PCI request */
+ DANUBE_PCI_REG32(PCI_CR_PC_ARB) &= ~(req_mask << 16);
+ }
spin_unlock_irqrestore(&ebu_lock, csflags);
+
break;
case 0:
spin_lock_irqsave(&ebu_lock, csflags);
+ if (req_mask) {
+ /* Mask all external PCI request */
+ DANUBE_PCI_REG32(PCI_CR_PC_ARB) |= (req_mask << 16);
+ }
+
ltq_ebu_w32_mask(0, NAND_CON_NANDM, EBU_NAND_CON);
ltq_ebu_w32_mask(0, NAND_CON_CE, EBU_NAND_CON);
+
break;
default:
BUG();
@@ -103,6 +134,12 @@ static void xway_cmd_ctrl(struct mtd_inf
struct nand_chip *this = mtd->priv;
unsigned long nandaddr = (unsigned long) this->IO_ADDR_W;
+ if (req_mask) {
+ if (cmd != NAND_CMD_STATUS)
+ ltq_ebu_w32(EBU_NAND_WAIT, 0); /* Clear nand ready */
+ }
+
+
if (ctrl & NAND_CTRL_CHANGE) {
if (ctrl & NAND_CLE)
xway_latchcmd = NAND_WRITE_CMD;
@@ -115,6 +152,24 @@ static void xway_cmd_ctrl(struct mtd_inf
while ((ltq_ebu_r32(EBU_NAND_WAIT) & NAND_WAIT_WR_C) == 0)
;
}
+
+ if (req_mask) {
+ /*
+ * program and erase have their own busy handlers
+ * status and sequential in needs no delay
+ */
+ switch (cmd) {
+ case NAND_CMD_ERASE1:
+ case NAND_CMD_SEQIN:
+ case NAND_CMD_STATUS:
+ case NAND_CMD_READID:
+ return;
+ }
+
+ /* wait until command is processed */
+ while ((ltq_ebu_r32(EBU_NAND_WAIT) & NAND_WAIT_RD) == 0)
+ ;
+ }
}
static int xway_dev_ready(struct mtd_info *mtd)
@@ -157,6 +212,8 @@ static int xway_nand_probe(struct platfo
{
struct nand_chip *this = platform_get_drvdata(pdev);
unsigned long nandaddr = (unsigned long) this->IO_ADDR_W;
+ const __be32 *req_mask_ptr = of_get_property(pdev->dev.of_node,
+ "req-mask", NULL);
const __be32 *cs = of_get_property(pdev->dev.of_node,
"lantiq,cs", NULL);
u32 cs_flag = 0;
@@ -165,6 +222,12 @@ static int xway_nand_probe(struct platfo
if (cs && (*cs == 1))
cs_flag = NAND_CON_IN_CS1 | NAND_CON_OUT_CS1;
+ /*
+ * Load the PCI req lines to mask from the device tree. If the
+ * property is not present, setting req_mask to 0 disables masking.
+ */
+ req_mask = (req_mask_ptr ? *req_mask_ptr : 0);
+
/* setup the EBU to run in NAND mode on our base addr */
ltq_ebu_w32(CPHYSADDR(nandaddr)
| ADDSEL1_MASK(3) | ADDSEL1_REGEN, EBU_ADDSEL1);

@ -0,0 +1,25 @@
From e3b20f04e9f9cae1babe091fdc1d08d7703ae344 Mon Sep 17 00:00:00 2001
From: John Crispin <blogic@openwrt.org>
Date: Thu, 7 Aug 2014 18:18:00 +0200
Subject: [PATCH 20/36] MTD: lantiq: handle NO_XIP on cfi0001 flash
Signed-off-by: John Crispin <blogic@openwrt.org>
---
drivers/mtd/maps/lantiq-flash.c | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
--- a/drivers/mtd/maps/lantiq-flash.c
+++ b/drivers/mtd/maps/lantiq-flash.c
@@ -139,7 +139,11 @@ ltq_mtd_probe(struct platform_device *pd
if (!ltq_mtd->map)
return -ENOMEM;
- ltq_mtd->map->phys = ltq_mtd->res->start;
+ if (of_find_property(pdev->dev.of_node, "lantiq,noxip", NULL))
+ ltq_mtd->map->phys = NO_XIP;
+ else
+ ltq_mtd->map->phys = ltq_mtd->res->start;
+ ltq_mtd->res->start;
ltq_mtd->map->size = resource_size(ltq_mtd->res);
ltq_mtd->map->virt = devm_ioremap_resource(&pdev->dev, ltq_mtd->res);
if (IS_ERR(ltq_mtd->map->virt))

@ -0,0 +1,44 @@
From 4400e1f593ea40a51912128adb4f53d59e62cad8 Mon Sep 17 00:00:00 2001
From: John Crispin <blogic@openwrt.org>
Date: Wed, 10 Sep 2014 22:40:18 +0200
Subject: [PATCH 22/36] MTD: m25p80: allow loading mtd name from OF
In accordance with the physmap flash we should honour the linux,mtd-name
property when deciding what name the mtd device has.
Signed-off-by: Thomas Langer <thomas.langer@lantiq.com>
Signed-off-by: John Crispin <blogic@openwrt.org>
---
drivers/mtd/devices/m25p80.c | 6 ++++++
1 file changed, 6 insertions(+)
--- a/drivers/mtd/devices/m25p80.c
+++ b/drivers/mtd/devices/m25p80.c
@@ -19,6 +19,7 @@
#include <linux/errno.h>
#include <linux/module.h>
#include <linux/device.h>
+#include <linux/of.h>
#include <linux/mtd/mtd.h>
#include <linux/mtd/partitions.h>
@@ -184,6 +185,10 @@ static int m25p_probe(struct spi_device
enum read_mode mode = SPI_NOR_NORMAL;
char *flash_name = NULL;
int ret;
+ const char __maybe_unused *of_mtd_name = NULL;
+
+ of_property_read_string(spi->dev.of_node,
+ "linux,mtd-name", &of_mtd_name);
data = dev_get_platdata(&spi->dev);
@@ -215,6 +220,8 @@ static int m25p_probe(struct spi_device
if (data && data->name)
flash->mtd.name = data->name;
+ else if (of_mtd_name)
+ flash->mtd.name = of_mtd_name;
/* For some (historical?) reason many platforms provide two different
* names in flash_platform_data: "name" and "type". Quite often name is

@ -0,0 +1,271 @@
From 0a63ab263725c427051a8bbaa0732b749627da27 Mon Sep 17 00:00:00 2001
From: John Crispin <blogic@openwrt.org>
Date: Thu, 7 Aug 2014 18:15:36 +0200
Subject: [PATCH 23/36] NET: PHY: adds driver for lantiq PHY11G
Signed-off-by: John Crispin <blogic@openwrt.org>
---
drivers/net/phy/Kconfig | 5 +
drivers/net/phy/Makefile | 1 +
drivers/net/phy/lantiq.c | 231 ++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 237 insertions(+)
create mode 100644 drivers/net/phy/lantiq.c
--- a/drivers/net/phy/Kconfig
+++ b/drivers/net/phy/Kconfig
@@ -165,6 +165,11 @@ config RTL8306_PHY
tristate "Driver for Realtek RTL8306S switches"
select SWCONFIG
+config LANTIQ_PHY
+ tristate "Driver for Lantiq PHYs"
+ ---help---
+ Supports the 11G and 22E PHYs.
+
config FIXED_PHY
tristate "Driver for MDIO Bus/PHY emulation with fixed speed/link PHYs"
depends on PHYLIB
--- a/drivers/net/phy/Makefile
+++ b/drivers/net/phy/Makefile
@@ -40,6 +40,7 @@ obj-$(CONFIG_NATIONAL_PHY) += national.o
obj-$(CONFIG_DP83640_PHY) += dp83640.o
obj-$(CONFIG_STE10XP) += ste10Xp.o
obj-$(CONFIG_MICREL_PHY) += micrel.o
+obj-$(CONFIG_LANTIQ_PHY) += lantiq.o
obj-$(CONFIG_MDIO_OCTEON) += mdio-octeon.o
obj-$(CONFIG_MICREL_KS8995MA) += spi_ks8995.o
obj-$(CONFIG_AT803X_PHY) += at803x.o
--- /dev/null
+++ b/drivers/net/phy/lantiq.c
@@ -0,0 +1,231 @@
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * Copyright (C) 2012 Daniel Schwierzeck <daniel.schwierzeck@googlemail.com>
+ */
+
+#include <linux/module.h>
+#include <linux/phy.h>
+
+#define MII_MMDCTRL 0x0d
+#define MII_MMDDATA 0x0e
+
+#define MII_VR9_11G_IMASK 0x19 /* interrupt mask */
+#define MII_VR9_11G_ISTAT 0x1a /* interrupt status */
+
+#define INT_VR9_11G_WOL BIT(15) /* Wake-On-LAN */
+#define INT_VR9_11G_ANE BIT(11) /* Auto-Neg error */
+#define INT_VR9_11G_ANC BIT(10) /* Auto-Neg complete */
+#define INT_VR9_11G_ADSC BIT(5) /* Link auto-downspeed detect */
+#define INT_VR9_11G_DXMC BIT(2) /* Duplex mode change */
+#define INT_VR9_11G_LSPC BIT(1) /* Link speed change */
+#define INT_VR9_11G_LSTC BIT(0) /* Link state change */
+#define INT_VR9_11G_MASK (INT_VR9_11G_LSTC | INT_VR9_11G_ADSC)
+
+#define ADVERTISED_MPD BIT(10) /* Multi-port device */
+
+#define MMD_DEVAD 0x1f
+#define MMD_ACTYPE_SHIFT 14
+#define MMD_ACTYPE_ADDRESS (0 << MMD_ACTYPE_SHIFT)
+#define MMD_ACTYPE_DATA (1 << MMD_ACTYPE_SHIFT)
+#define MMD_ACTYPE_DATA_PI (2 << MMD_ACTYPE_SHIFT)
+#define MMD_ACTYPE_DATA_PIWR (3 << MMD_ACTYPE_SHIFT)
+
+static __maybe_unused int vr9_gphy_mmd_read(struct phy_device *phydev,
+ u16 regnum)
+{
+ phy_write(phydev, MII_MMDCTRL, MMD_ACTYPE_ADDRESS | MMD_DEVAD);
+ phy_write(phydev, MII_MMDDATA, regnum);
+ phy_write(phydev, MII_MMDCTRL, MMD_ACTYPE_DATA | MMD_DEVAD);
+
+ return phy_read(phydev, MII_MMDDATA);
+}
+
+static __maybe_unused int vr9_gphy_mmd_write(struct phy_device *phydev,
+ u16 regnum, u16 val)
+{
+ phy_write(phydev, MII_MMDCTRL, MMD_ACTYPE_ADDRESS | MMD_DEVAD);
+ phy_write(phydev, MII_MMDDATA, regnum);
+ phy_write(phydev, MII_MMDCTRL, MMD_ACTYPE_DATA | MMD_DEVAD);
+ phy_write(phydev, MII_MMDDATA, val);
+
+ return 0;
+}
+
+static int vr9_gphy_config_init(struct phy_device *phydev)
+{
+ int err;
+
+ dev_dbg(&phydev->dev, "%s\n", __func__);
+
+ /* Mask all interrupts */
+ err = phy_write(phydev, MII_VR9_11G_IMASK, 0);
+ if (err)
+ return err;
+
+ /* Clear all pending interrupts */
+ phy_read(phydev, MII_VR9_11G_ISTAT);
+
+ vr9_gphy_mmd_write(phydev, 0x1e0, 0xc5);
+ vr9_gphy_mmd_write(phydev, 0x1e1, 0x67);
+ vr9_gphy_mmd_write(phydev, 0x1e2, 0x42);
+ vr9_gphy_mmd_write(phydev, 0x1e3, 0x10);
+ vr9_gphy_mmd_write(phydev, 0x1e4, 0x70);
+ vr9_gphy_mmd_write(phydev, 0x1e5, 0x03);
+ vr9_gphy_mmd_write(phydev, 0x1e6, 0x20);
+ vr9_gphy_mmd_write(phydev, 0x1e7, 0x00);
+ vr9_gphy_mmd_write(phydev, 0x1e8, 0x40);
+ vr9_gphy_mmd_write(phydev, 0x1e9, 0x20);
+
+ return 0;
+}
+
+static int vr9_gphy_config_aneg(struct phy_device *phydev)
+{
+ int reg, err;
+
+ /* Advertise as multi-port device */
+ reg = phy_read(phydev, MII_CTRL1000);
+ reg |= ADVERTISED_MPD;
+ err = phy_write(phydev, MII_CTRL1000, reg);
+ if (err)
+ return err;
+
+ return genphy_config_aneg(phydev);
+}
+
+static int vr9_gphy_ack_interrupt(struct phy_device *phydev)
+{
+ int reg;
+
+ /*
+ * Possible IRQ numbers:
+ * - IM3_IRL18 for GPHY0
+ * - IM3_IRL17 for GPHY1
+ *
+ * Due to a silicon bug IRQ lines are not really independent from
+ * each other. Sometimes the two lines are driven at the same time
+ * if only one GPHY core raises the interrupt.
+ */
+
+ reg = phy_read(phydev, MII_VR9_11G_ISTAT);
+
+ return (reg < 0) ? reg : 0;
+}
+
+static int vr9_gphy_did_interrupt(struct phy_device *phydev)
+{
+ int reg;
+
+ reg = phy_read(phydev, MII_VR9_11G_ISTAT);
+
+ return reg > 0;
+}
+
+static int vr9_gphy_config_intr(struct phy_device *phydev)
+{
+ int err;
+
+ if (phydev->interrupts == PHY_INTERRUPT_ENABLED)
+ err = phy_write(phydev, MII_VR9_11G_IMASK, INT_VR9_11G_MASK);
+ else
+ err = phy_write(phydev, MII_VR9_11G_IMASK, 0);
+
+ return err;
+}
+
+static struct phy_driver lantiq_phy[] = {
+ {
+ .phy_id = 0xd565a400,
+ .phy_id_mask = 0xffffffff,
+ .name = "Lantiq XWAY PEF7071",
+ .features = (PHY_GBIT_FEATURES | SUPPORTED_Pause),
+ .flags = 0, /*PHY_HAS_INTERRUPT,*/
+ .config_init = vr9_gphy_config_init,
+ .config_aneg = vr9_gphy_config_aneg,
+ .read_status = genphy_read_status,
+ .ack_interrupt = vr9_gphy_ack_interrupt,
+ .did_interrupt = vr9_gphy_did_interrupt,
+ .config_intr = vr9_gphy_config_intr,
+ .driver = { .owner = THIS_MODULE },
+ }, {
+ .phy_id = 0x030260D0,
+ .phy_id_mask = 0xfffffff0,
+ .name = "Lantiq XWAY VR9 GPHY 11G v1.3",
+ .features = (PHY_GBIT_FEATURES | SUPPORTED_Pause),
+ .flags = 0, /*PHY_HAS_INTERRUPT,*/
+ .config_init = vr9_gphy_config_init,
+ .config_aneg = vr9_gphy_config_aneg,
+ .read_status = genphy_read_status,
+ .ack_interrupt = vr9_gphy_ack_interrupt,
+ .did_interrupt = vr9_gphy_did_interrupt,
+ .config_intr = vr9_gphy_config_intr,
+ .driver = { .owner = THIS_MODULE },
+ }, {
+ .phy_id = 0xd565a408,
+ .phy_id_mask = 0xfffffff8,
+ .name = "Lantiq XWAY VR9 GPHY 11G v1.4",
+ .features = (PHY_GBIT_FEATURES | SUPPORTED_Pause),
+ .flags = 0, /*PHY_HAS_INTERRUPT,*/
+ .config_init = vr9_gphy_config_init,
+ .config_aneg = vr9_gphy_config_aneg,
+ .read_status = genphy_read_status,
+ .ack_interrupt = vr9_gphy_ack_interrupt,
+ .did_interrupt = vr9_gphy_did_interrupt,
+ .config_intr = vr9_gphy_config_intr,
+ .driver = { .owner = THIS_MODULE },
+ }, {
+ .phy_id = 0xd565a418,
+ .phy_id_mask = 0xfffffff8,
+ .name = "Lantiq XWAY XRX PHY22F v1.4",
+ .features = (PHY_BASIC_FEATURES | SUPPORTED_Pause),
+ .flags = 0, /*PHY_HAS_INTERRUPT,*/
+ .config_init = vr9_gphy_config_init,
+ .config_aneg = vr9_gphy_config_aneg,
+ .read_status = genphy_read_status,
+ .ack_interrupt = vr9_gphy_ack_interrupt,
+ .did_interrupt = vr9_gphy_did_interrupt,
+ .config_intr = vr9_gphy_config_intr,
+ .driver = { .owner = THIS_MODULE },
+ },
+};
+
+static int __init ltq_phy_init(void)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(lantiq_phy); i++) {
+ int err = phy_driver_register(&lantiq_phy[i]);
+ if (err)
+ pr_err("lantiq_phy: failed to load %s\n", lantiq_phy[i].name);
+ }
+
+ return 0;
+}
+
+static void __exit ltq_phy_exit(void)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(lantiq_phy); i++)
+ phy_driver_unregister(&lantiq_phy[i]);
+}
+
+module_init(ltq_phy_init);
+module_exit(ltq_phy_exit);
+
+MODULE_DESCRIPTION("Lantiq PHY drivers");
+MODULE_AUTHOR("Daniel Schwierzeck <daniel.schwierzeck@googlemail.com>");
+MODULE_LICENSE("GPL");

@ -0,0 +1,364 @@
From 77e89d5a28be35058041c79e9874ab26f222c603 Mon Sep 17 00:00:00 2001
From: John Crispin <blogic@openwrt.org>
Date: Mon, 22 Oct 2012 09:26:24 +0200
Subject: [PATCH 24/36] NET: lantiq: adds PHY11G firmware blobs
Signed-off-by: John Crispin <blogic@openwrt.org>
---
firmware/Makefile | 4 +
firmware/lantiq/COPYING | 286 +++++++++++++++++++++++++++++++++++++++++++++++
firmware/lantiq/README | 45 ++++++++
3 files changed, 335 insertions(+)
create mode 100644 firmware/lantiq/COPYING
create mode 100644 firmware/lantiq/README
--- a/firmware/Makefile
+++ b/firmware/Makefile
@@ -134,6 +134,10 @@ fw-shipped-$(CONFIG_USB_SERIAL_KEYSPAN_P
fw-shipped-$(CONFIG_USB_SERIAL_XIRCOM) += keyspan_pda/xircom_pgs.fw
fw-shipped-$(CONFIG_USB_VICAM) += vicam/firmware.fw
fw-shipped-$(CONFIG_VIDEO_CPIA2) += cpia2/stv0672_vp4.bin
+fw-shipped-$(CONFIG_LANTIQ_XRX200) += lantiq/vr9_phy11g_a1x.bin
+fw-shipped-$(CONFIG_LANTIQ_XRX200) += lantiq/vr9_phy11g_a2x.bin
+fw-shipped-$(CONFIG_LANTIQ_XRX200) += lantiq/vr9_phy22f_a1x.bin
+fw-shipped-$(CONFIG_LANTIQ_XRX200) += lantiq/vr9_phy22f_a2x.bin
fw-shipped-$(CONFIG_YAM) += yam/1200.bin yam/9600.bin
fw-shipped-all := $(fw-shipped-y) $(fw-shipped-m) $(fw-shipped-)
--- /dev/null
+++ b/firmware/lantiq/COPYING
@@ -0,0 +1,286 @@
+All firmware files are copyrighted by Lantiq Deutschland GmbH.
+The files have been extracted from header files found in Lantiq BSPs.
+If not stated otherwise all files are licensed under GPL.
+
+=======================================================================
+
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+ 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+ END OF TERMS AND CONDITIONS
--- /dev/null
+++ b/firmware/lantiq/README
@@ -0,0 +1,45 @@
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License as
+# published by the Free Software Foundation; either version 2 of
+# the License, or (at your option) any later version.
+#
+# This program 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.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+# MA 02111-1307 USA
+#
+# (C) Copyright 2007 - 2012
+# Lantiq Deutschland GmbH
+#
+# (C) Copyright 2012
+# Daniel Schwierzeck <daniel.schwierzeck@googlemail.com>
+#
+
+#
+# How to use
+#
+Configure kernel with:
+CONFIG_FW_LOADER=y
+CONFIG_EXTRA_FIRMWARE_DIR="FIRMWARE_DIR"
+CONFIG_EXTRA_FIRMWARE="FIRMWARE_FILES"
+
+where FIRMWARE_DIR should point to this git tree and FIRMWARE_FILES is a list
+of space separated files from list below.
+
+#
+# Firmware files
+#
+
+# GPHY core on Lantiq XWAY VR9 v1.1
+lantiq/vr9_phy11g_a1x.bin
+lantiq/vr9_phy22f_a1x.bin
+
+# GPHY core on Lantiq XWAY VR9 v1.2
+lantiq/vr9_phy11g_a2x.bin
+lantiq/vr9_phy22f_a2x.bin

@ -0,0 +1,53 @@
From c6feeeb407a3b8a6597ae377ba4dd138e185e3dd Mon Sep 17 00:00:00 2001
From: John Crispin <blogic@openwrt.org>
Date: Sun, 27 Jul 2014 09:38:50 +0100
Subject: [PATCH 26/36] NET: multi phy support
Signed-off-by: John Crispin <blogic@openwrt.org>
---
drivers/net/phy/phy.c | 9 ++++++---
include/linux/phy.h | 1 +
2 files changed, 7 insertions(+), 3 deletions(-)
--- a/drivers/net/phy/phy.c
+++ b/drivers/net/phy/phy.c
@@ -855,7 +855,8 @@ void phy_state_machine(struct work_struc
/* If the link is down, give up on negotiation for now */
if (!phydev->link) {
phydev->state = PHY_NOLINK;
- netif_carrier_off(phydev->attached_dev);
+ if (!phydev->no_auto_carrier_off)
+ netif_carrier_off(phydev->attached_dev);
phydev->adjust_link(phydev->attached_dev);
break;
}
@@ -928,7 +929,8 @@ void phy_state_machine(struct work_struc
netif_carrier_on(phydev->attached_dev);
} else {
phydev->state = PHY_NOLINK;
- netif_carrier_off(phydev->attached_dev);
+ if (!phydev->no_auto_carrier_off)
+ netif_carrier_off(phydev->attached_dev);
}
phydev->adjust_link(phydev->attached_dev);
@@ -940,7 +942,8 @@ void phy_state_machine(struct work_struc
case PHY_HALTED:
if (phydev->link) {
phydev->link = 0;
- netif_carrier_off(phydev->attached_dev);
+ if (!phydev->no_auto_carrier_off)
+ netif_carrier_off(phydev->attached_dev);
phydev->adjust_link(phydev->attached_dev);
do_suspend = true;
}
--- a/include/linux/phy.h
+++ b/include/linux/phy.h
@@ -367,6 +367,7 @@ struct phy_device {
bool is_internal;
bool has_fixups;
bool suspended;
+ bool no_auto_carrier_off;
enum phy_state state;

@ -0,0 +1,907 @@
From 870ed9cae083ff8a60a739ef7e74c5a1800533be Mon Sep 17 00:00:00 2001
From: John Crispin <blogic@openwrt.org>
Date: Tue, 9 Sep 2014 22:45:34 +0200
Subject: [PATCH 28/36] NET: lantiq: various etop fixes
Signed-off-by: John Crispin <blogic@openwrt.org>
---
drivers/net/ethernet/lantiq_etop.c | 555 +++++++++++++++++++++++++-----------
1 file changed, 389 insertions(+), 166 deletions(-)
--- a/drivers/net/ethernet/lantiq_etop.c
+++ b/drivers/net/ethernet/lantiq_etop.c
@@ -11,7 +11,7 @@
* You should have received a copy of the GNU General Public License
* along with this program; if not, see <http://www.gnu.org/licenses/>.
*
- * Copyright (C) 2011 John Crispin <blogic@openwrt.org>
+ * Copyright (C) 2011-12 John Crispin <blogic@openwrt.org>
*/
#include <linux/kernel.h>
@@ -30,11 +30,16 @@
#include <linux/mm.h>
#include <linux/platform_device.h>
#include <linux/ethtool.h>
+#include <linux/if_vlan.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/io.h>
#include <linux/dma-mapping.h>
#include <linux/module.h>
+#include <linux/clk.h>
+#include <linux/of_net.h>
+#include <linux/of_irq.h>
+#include <linux/of_platform.h>
#include <asm/checksum.h>
@@ -42,7 +47,7 @@
#include <xway_dma.h>
#include <lantiq_platform.h>
-#define LTQ_ETOP_MDIO 0x11804
+#define LTQ_ETOP_MDIO_ACC 0x11804
#define MDIO_REQUEST 0x80000000
#define MDIO_READ 0x40000000
#define MDIO_ADDR_MASK 0x1f
@@ -51,44 +56,91 @@
#define MDIO_REG_OFFSET 0x10
#define MDIO_VAL_MASK 0xffff
-#define PPE32_CGEN 0x800
-#define LQ_PPE32_ENET_MAC_CFG 0x1840
+#define LTQ_ETOP_MDIO_CFG 0x11800
+#define MDIO_CFG_MASK 0x6
+
+#define LTQ_ETOP_CFG 0x11808
+#define LTQ_ETOP_IGPLEN 0x11820
+#define LTQ_ETOP_MAC_CFG 0x11840
#define LTQ_ETOP_ENETS0 0x11850
#define LTQ_ETOP_MAC_DA0 0x1186C
#define LTQ_ETOP_MAC_DA1 0x11870
-#define LTQ_ETOP_CFG 0x16020
-#define LTQ_ETOP_IGPLEN 0x16080
+
+#define MAC_CFG_MASK 0xfff
+#define MAC_CFG_CGEN (1 << 11)
+#define MAC_CFG_DUPLEX (1 << 2)
+#define MAC_CFG_SPEED (1 << 1)
+#define MAC_CFG_LINK (1 << 0)
#define MAX_DMA_CHAN 0x8
#define MAX_DMA_CRC_LEN 0x4
#define MAX_DMA_DATA_LEN 0x600
#define ETOP_FTCU BIT(28)
-#define ETOP_MII_MASK 0xf
-#define ETOP_MII_NORMAL 0xd
-#define ETOP_MII_REVERSE 0xe
#define ETOP_PLEN_UNDER 0x40
-#define ETOP_CGEN 0x800
+#define ETOP_CFG_MII0 0x01
-/* use 2 static channels for TX/RX */
-#define LTQ_ETOP_TX_CHANNEL 1
-#define LTQ_ETOP_RX_CHANNEL 6
-#define IS_TX(x) (x == LTQ_ETOP_TX_CHANNEL)
-#define IS_RX(x) (x == LTQ_ETOP_RX_CHANNEL)
+#define ETOP_CFG_MASK 0xfff
+#define ETOP_CFG_FEN0 (1 << 8)
+#define ETOP_CFG_SEN0 (1 << 6)
+#define ETOP_CFG_OFF1 (1 << 3)
+#define ETOP_CFG_REMII0 (1 << 1)
+#define ETOP_CFG_OFF0 (1 << 0)
+
+#define LTQ_GBIT_MDIO_CTL 0xCC
+#define LTQ_GBIT_MDIO_DATA 0xd0
+#define LTQ_GBIT_GCTL0 0x68
+#define LTQ_GBIT_PMAC_HD_CTL 0x8c
+#define LTQ_GBIT_P0_CTL 0x4
+#define LTQ_GBIT_PMAC_RX_IPG 0xa8
+#define LTQ_GBIT_RGMII_CTL 0x78
+
+#define PMAC_HD_CTL_AS (1 << 19)
+#define PMAC_HD_CTL_RXSH (1 << 22)
+
+/* Switch Enable (0=disable, 1=enable) */
+#define GCTL0_SE 0x80000000
+/* Disable MDIO auto polling (0=disable, 1=enable) */
+#define PX_CTL_DMDIO 0x00400000
+
+/* MDC clock divider, clock = 25MHz/((MDC_CLOCK + 1) * 2) */
+#define MDC_CLOCK_MASK 0xff000000
+#define MDC_CLOCK_OFFSET 24
+
+/* register information for the gbit's MDIO bus */
+#define MDIO_XR9_REQUEST 0x00008000
+#define MDIO_XR9_READ 0x00000800
+#define MDIO_XR9_WRITE 0x00000400
+#define MDIO_XR9_REG_MASK 0x1f
+#define MDIO_XR9_ADDR_MASK 0x1f
+#define MDIO_XR9_RD_MASK 0xffff
+#define MDIO_XR9_REG_OFFSET 0
+#define MDIO_XR9_ADDR_OFFSET 5
+#define MDIO_XR9_WR_OFFSET 16
+#define LTQ_DMA_ETOP ((of_machine_is_compatible("lantiq,ase")) ? \
+ (INT_NUM_IM3_IRL0) : (INT_NUM_IM2_IRL0))
+
+/* the newer xway socks have a embedded 3/7 port gbit multiplexer */
#define ltq_etop_r32(x) ltq_r32(ltq_etop_membase + (x))
#define ltq_etop_w32(x, y) ltq_w32(x, ltq_etop_membase + (y))
#define ltq_etop_w32_mask(x, y, z) \
ltq_w32_mask(x, y, ltq_etop_membase + (z))
-#define DRV_VERSION "1.0"
+#define ltq_gbit_r32(x) ltq_r32(ltq_gbit_membase + (x))
+#define ltq_gbit_w32(x, y) ltq_w32(x, ltq_gbit_membase + (y))
+#define ltq_gbit_w32_mask(x, y, z) \
+ ltq_w32_mask(x, y, ltq_gbit_membase + (z))
+
+#define DRV_VERSION "1.2"
static void __iomem *ltq_etop_membase;
+static void __iomem *ltq_gbit_membase;
struct ltq_etop_chan {
- int idx;
int tx_free;
+ int irq;
struct net_device *netdev;
struct napi_struct napi;
struct ltq_dma_channel dma;
@@ -98,22 +150,35 @@ struct ltq_etop_chan {
struct ltq_etop_priv {
struct net_device *netdev;
struct platform_device *pdev;
- struct ltq_eth_data *pldata;
struct resource *res;
struct mii_bus *mii_bus;
struct phy_device *phydev;
- struct ltq_etop_chan ch[MAX_DMA_CHAN];
- int tx_free[MAX_DMA_CHAN >> 1];
+ struct ltq_etop_chan txch;
+ struct ltq_etop_chan rxch;
+
+ int tx_irq;
+ int rx_irq;
+
+ const void *mac;
+ int mii_mode;
spinlock_t lock;
+
+ struct clk *clk_ppe;
+ struct clk *clk_switch;
+ struct clk *clk_ephy;
+ struct clk *clk_ephycgu;
};
+static int ltq_etop_mdio_wr(struct mii_bus *bus, int phy_addr,
+ int phy_reg, u16 phy_data);
+
static int
ltq_etop_alloc_skb(struct ltq_etop_chan *ch)
{
- ch->skb[ch->dma.desc] = netdev_alloc_skb(ch->netdev, MAX_DMA_DATA_LEN);
+ ch->skb[ch->dma.desc] = dev_alloc_skb(MAX_DMA_DATA_LEN);
if (!ch->skb[ch->dma.desc])
return -ENOMEM;
ch->dma.desc_base[ch->dma.desc].addr = dma_map_single(NULL,
@@ -148,8 +213,11 @@ ltq_etop_hw_receive(struct ltq_etop_chan
spin_unlock_irqrestore(&priv->lock, flags);
skb_put(skb, len);
+ skb->dev = ch->netdev;
skb->protocol = eth_type_trans(skb, ch->netdev);
netif_receive_skb(skb);
+ ch->netdev->stats.rx_packets++;
+ ch->netdev->stats.rx_bytes += len;
}
static int
@@ -157,8 +225,10 @@ ltq_etop_poll_rx(struct napi_struct *nap
{
struct ltq_etop_chan *ch = container_of(napi,
struct ltq_etop_chan, napi);
+ struct ltq_etop_priv *priv = netdev_priv(ch->netdev);
int rx = 0;
int complete = 0;
+ unsigned long flags;
while ((rx < budget) && !complete) {
struct ltq_dma_desc *desc = &ch->dma.desc_base[ch->dma.desc];
@@ -172,7 +242,9 @@ ltq_etop_poll_rx(struct napi_struct *nap
}
if (complete || !rx) {
napi_complete(&ch->napi);
+ spin_lock_irqsave(&priv->lock, flags);
ltq_dma_ack_irq(&ch->dma);
+ spin_unlock_irqrestore(&priv->lock, flags);
}
return rx;
}
@@ -184,12 +256,14 @@ ltq_etop_poll_tx(struct napi_struct *nap
container_of(napi, struct ltq_etop_chan, napi);
struct ltq_etop_priv *priv = netdev_priv(ch->netdev);
struct netdev_queue *txq =
- netdev_get_tx_queue(ch->netdev, ch->idx >> 1);
+ netdev_get_tx_queue(ch->netdev, ch->dma.nr >> 1);
unsigned long flags;
spin_lock_irqsave(&priv->lock, flags);
while ((ch->dma.desc_base[ch->tx_free].ctl &
(LTQ_DMA_OWN | LTQ_DMA_C)) == LTQ_DMA_C) {
+ ch->netdev->stats.tx_packets++;
+ ch->netdev->stats.tx_bytes += ch->skb[ch->tx_free]->len;
dev_kfree_skb_any(ch->skb[ch->tx_free]);
ch->skb[ch->tx_free] = NULL;
memset(&ch->dma.desc_base[ch->tx_free], 0,
@@ -202,7 +276,9 @@ ltq_etop_poll_tx(struct napi_struct *nap
if (netif_tx_queue_stopped(txq))
netif_tx_start_queue(txq);
napi_complete(&ch->napi);
+ spin_lock_irqsave(&priv->lock, flags);
ltq_dma_ack_irq(&ch->dma);
+ spin_unlock_irqrestore(&priv->lock, flags);
return 1;
}
@@ -210,9 +286,10 @@ static irqreturn_t
ltq_etop_dma_irq(int irq, void *_priv)
{
struct ltq_etop_priv *priv = _priv;
- int ch = irq - LTQ_DMA_CH0_INT;
-
- napi_schedule(&priv->ch[ch].napi);
+ if (irq == priv->txch.dma.irq)
+ napi_schedule(&priv->txch.napi);
+ else
+ napi_schedule(&priv->rxch.napi);
return IRQ_HANDLED;
}
@@ -224,7 +301,7 @@ ltq_etop_free_channel(struct net_device
ltq_dma_free(&ch->dma);
if (ch->dma.irq)
free_irq(ch->dma.irq, priv);
- if (IS_RX(ch->idx)) {
+ if (ch == &priv->txch) {
int desc;
for (desc = 0; desc < LTQ_DESC_NUM; desc++)
dev_kfree_skb_any(ch->skb[ch->dma.desc]);
@@ -235,65 +312,133 @@ static void
ltq_etop_hw_exit(struct net_device *dev)
{
struct ltq_etop_priv *priv = netdev_priv(dev);
- int i;
- ltq_pmu_disable(PMU_PPE);
- for (i = 0; i < MAX_DMA_CHAN; i++)
- if (IS_TX(i) || IS_RX(i))
- ltq_etop_free_channel(dev, &priv->ch[i]);
+ clk_disable(priv->clk_ppe);
+
+ if (of_machine_is_compatible("lantiq,ar9"))
+ clk_disable(priv->clk_switch);
+
+ if (of_machine_is_compatible("lantiq,ase")) {
+ clk_disable(priv->clk_ephy);
+ clk_disable(priv->clk_ephycgu);
+ }
+
+ ltq_etop_free_channel(dev, &priv->txch);
+ ltq_etop_free_channel(dev, &priv->rxch);
+}
+
+static void
+ltq_etop_gbit_init(struct net_device *dev)
+{
+ struct ltq_etop_priv *priv = netdev_priv(dev);
+
+ clk_enable(priv->clk_switch);
+
+ /* enable gbit port0 on the SoC */
+ ltq_gbit_w32_mask((1 << 17), (1 << 18), LTQ_GBIT_P0_CTL);
+
+ ltq_gbit_w32_mask(0, GCTL0_SE, LTQ_GBIT_GCTL0);
+ /* disable MDIO auto polling mode */
+ ltq_gbit_w32_mask(0, PX_CTL_DMDIO, LTQ_GBIT_P0_CTL);
+ /* set 1522 packet size */
+ ltq_gbit_w32_mask(0x300, 0, LTQ_GBIT_GCTL0);
+ /* disable pmac & dmac headers */
+ ltq_gbit_w32_mask(PMAC_HD_CTL_AS | PMAC_HD_CTL_RXSH, 0,
+ LTQ_GBIT_PMAC_HD_CTL);
+ /* Due to traffic halt when burst length 8,
+ replace default IPG value with 0x3B */
+ ltq_gbit_w32(0x3B, LTQ_GBIT_PMAC_RX_IPG);
+ /* set mdc clock to 2.5 MHz */
+ ltq_gbit_w32_mask(MDC_CLOCK_MASK, 4 << MDC_CLOCK_OFFSET,
+ LTQ_GBIT_RGMII_CTL);
}
static int
ltq_etop_hw_init(struct net_device *dev)
{
struct ltq_etop_priv *priv = netdev_priv(dev);
- int i;
+ int mii_mode = priv->mii_mode;
- ltq_pmu_enable(PMU_PPE);
+ clk_enable(priv->clk_ppe);
+
+ if (of_machine_is_compatible("lantiq,ar9")) {
+ ltq_etop_gbit_init(dev);
+ /* force the etops link to the gbit to MII */
+ mii_mode = PHY_INTERFACE_MODE_MII;
+ }
+ ltq_etop_w32_mask(MDIO_CFG_MASK, 0, LTQ_ETOP_MDIO_CFG);
+ ltq_etop_w32_mask(MAC_CFG_MASK, MAC_CFG_CGEN | MAC_CFG_DUPLEX |
+ MAC_CFG_SPEED | MAC_CFG_LINK, LTQ_ETOP_MAC_CFG);
- switch (priv->pldata->mii_mode) {
+ switch (mii_mode) {
case PHY_INTERFACE_MODE_RMII:
- ltq_etop_w32_mask(ETOP_MII_MASK,
- ETOP_MII_REVERSE, LTQ_ETOP_CFG);
+ ltq_etop_w32_mask(ETOP_CFG_MASK, ETOP_CFG_REMII0 | ETOP_CFG_OFF1 |
+ ETOP_CFG_SEN0 | ETOP_CFG_FEN0, LTQ_ETOP_CFG);
break;
case PHY_INTERFACE_MODE_MII:
- ltq_etop_w32_mask(ETOP_MII_MASK,
- ETOP_MII_NORMAL, LTQ_ETOP_CFG);
+ ltq_etop_w32_mask(ETOP_CFG_MASK, ETOP_CFG_OFF1 |
+ ETOP_CFG_SEN0 | ETOP_CFG_FEN0, LTQ_ETOP_CFG);
break;
default:
+ if (of_machine_is_compatible("lantiq,ase")) {
+ clk_enable(priv->clk_ephy);
+ /* disable external MII */
+ ltq_etop_w32_mask(0, ETOP_CFG_MII0, LTQ_ETOP_CFG);
+ /* enable clock for internal PHY */
+ clk_enable(priv->clk_ephycgu);
+ /* we need to write this magic to the internal phy to
+ make it work */
+ ltq_etop_mdio_wr(NULL, 0x8, 0x12, 0xC020);
+ pr_info("Selected EPHY mode\n");
+ break;
+ }
netdev_err(dev, "unknown mii mode %d\n",
- priv->pldata->mii_mode);
+ mii_mode);
return -ENOTSUPP;
}
- /* enable crc generation */
- ltq_etop_w32(PPE32_CGEN, LQ_PPE32_ENET_MAC_CFG);
+ return 0;
+}
+
+static int
+ltq_etop_dma_init(struct net_device *dev)
+{
+ struct ltq_etop_priv *priv = netdev_priv(dev);
+ int tx = priv->tx_irq - LTQ_DMA_ETOP;
+ int rx = priv->rx_irq - LTQ_DMA_ETOP;
+ int err;
ltq_dma_init_port(DMA_PORT_ETOP);
- for (i = 0; i < MAX_DMA_CHAN; i++) {
- int irq = LTQ_DMA_CH0_INT + i;
- struct ltq_etop_chan *ch = &priv->ch[i];
-
- ch->idx = ch->dma.nr = i;
-
- if (IS_TX(i)) {
- ltq_dma_alloc_tx(&ch->dma);
- request_irq(irq, ltq_etop_dma_irq, 0, "etop_tx", priv);
- } else if (IS_RX(i)) {
- ltq_dma_alloc_rx(&ch->dma);
- for (ch->dma.desc = 0; ch->dma.desc < LTQ_DESC_NUM;
- ch->dma.desc++)
- if (ltq_etop_alloc_skb(ch))
- return -ENOMEM;
- ch->dma.desc = 0;
- request_irq(irq, ltq_etop_dma_irq, 0, "etop_rx", priv);
+ priv->txch.dma.nr = tx;
+ ltq_dma_alloc_tx(&priv->txch.dma);
+ err = request_irq(priv->tx_irq, ltq_etop_dma_irq, 0, "eth_tx", priv);
+ if (err) {
+ netdev_err(dev, "failed to allocate tx irq\n");
+ goto err_out;
+ }
+ priv->txch.dma.irq = priv->tx_irq;
+
+ priv->rxch.dma.nr = rx;
+ ltq_dma_alloc_rx(&priv->rxch.dma);
+ for (priv->rxch.dma.desc = 0; priv->rxch.dma.desc < LTQ_DESC_NUM;
+ priv->rxch.dma.desc++) {
+ if (ltq_etop_alloc_skb(&priv->rxch)) {
+ netdev_err(dev, "failed to allocate skbs\n");
+ err = -ENOMEM;
+ goto err_out;
}
- ch->dma.irq = irq;
}
- return 0;
+ priv->rxch.dma.desc = 0;
+ err = request_irq(priv->rx_irq, ltq_etop_dma_irq, 0, "eth_rx", priv);
+ if (err)
+ netdev_err(dev, "failed to allocate rx irq\n");
+ else
+ priv->rxch.dma.irq = priv->rx_irq;
+err_out:
+ return err;
}
static void
@@ -309,7 +454,10 @@ ltq_etop_get_settings(struct net_device
{
struct ltq_etop_priv *priv = netdev_priv(dev);
- return phy_ethtool_gset(priv->phydev, cmd);
+ if (priv->phydev)
+ return phy_ethtool_gset(priv->phydev, cmd);
+ else
+ return 0;
}
static int
@@ -317,7 +465,10 @@ ltq_etop_set_settings(struct net_device
{
struct ltq_etop_priv *priv = netdev_priv(dev);
- return phy_ethtool_sset(priv->phydev, cmd);
+ if (priv->phydev)
+ return phy_ethtool_sset(priv->phydev, cmd);
+ else
+ return 0;
}
static int
@@ -325,7 +476,10 @@ ltq_etop_nway_reset(struct net_device *d
{
struct ltq_etop_priv *priv = netdev_priv(dev);
- return phy_start_aneg(priv->phydev);
+ if (priv->phydev)
+ return phy_start_aneg(priv->phydev);
+ else
+ return 0;
}
static const struct ethtool_ops ltq_etop_ethtool_ops = {
@@ -336,6 +490,39 @@ static const struct ethtool_ops ltq_etop
};
static int
+ltq_etop_mdio_wr_xr9(struct mii_bus *bus, int phy_addr,
+ int phy_reg, u16 phy_data)
+{
+ u32 val = MDIO_XR9_REQUEST | MDIO_XR9_WRITE |
+ (phy_data << MDIO_XR9_WR_OFFSET) |
+ ((phy_addr & MDIO_XR9_ADDR_MASK) << MDIO_XR9_ADDR_OFFSET) |
+ ((phy_reg & MDIO_XR9_REG_MASK) << MDIO_XR9_REG_OFFSET);
+
+ while (ltq_gbit_r32(LTQ_GBIT_MDIO_CTL) & MDIO_XR9_REQUEST)
+ ;
+ ltq_gbit_w32(val, LTQ_GBIT_MDIO_CTL);
+ while (ltq_gbit_r32(LTQ_GBIT_MDIO_CTL) & MDIO_XR9_REQUEST)
+ ;
+ return 0;
+}
+
+static int
+ltq_etop_mdio_rd_xr9(struct mii_bus *bus, int phy_addr, int phy_reg)
+{
+ u32 val = MDIO_XR9_REQUEST | MDIO_XR9_READ |
+ ((phy_addr & MDIO_XR9_ADDR_MASK) << MDIO_XR9_ADDR_OFFSET) |
+ ((phy_reg & MDIO_XR9_REG_MASK) << MDIO_XR9_REG_OFFSET);
+
+ while (ltq_gbit_r32(LTQ_GBIT_MDIO_CTL) & MDIO_XR9_REQUEST)
+ ;
+ ltq_gbit_w32(val, LTQ_GBIT_MDIO_CTL);
+ while (ltq_gbit_r32(LTQ_GBIT_MDIO_CTL) & MDIO_XR9_REQUEST)
+ ;
+ val = ltq_gbit_r32(LTQ_GBIT_MDIO_DATA) & MDIO_XR9_RD_MASK;
+ return val;
+}
+
+static int
ltq_etop_mdio_wr(struct mii_bus *bus, int phy_addr, int phy_reg, u16 phy_data)
{
u32 val = MDIO_REQUEST |
@@ -343,9 +530,9 @@ ltq_etop_mdio_wr(struct mii_bus *bus, in
((phy_reg & MDIO_REG_MASK) << MDIO_REG_OFFSET) |
phy_data;
- while (ltq_etop_r32(LTQ_ETOP_MDIO) & MDIO_REQUEST)
+ while (ltq_etop_r32(LTQ_ETOP_MDIO_ACC) & MDIO_REQUEST)
;
- ltq_etop_w32(val, LTQ_ETOP_MDIO);
+ ltq_etop_w32(val, LTQ_ETOP_MDIO_ACC);
return 0;
}
@@ -356,12 +543,12 @@ ltq_etop_mdio_rd(struct mii_bus *bus, in
((phy_addr & MDIO_ADDR_MASK) << MDIO_ADDR_OFFSET) |
((phy_reg & MDIO_REG_MASK) << MDIO_REG_OFFSET);
- while (ltq_etop_r32(LTQ_ETOP_MDIO) & MDIO_REQUEST)
+ while (ltq_etop_r32(LTQ_ETOP_MDIO_ACC) & MDIO_REQUEST)
;
- ltq_etop_w32(val, LTQ_ETOP_MDIO);
- while (ltq_etop_r32(LTQ_ETOP_MDIO) & MDIO_REQUEST)
+ ltq_etop_w32(val, LTQ_ETOP_MDIO_ACC);
+ while (ltq_etop_r32(LTQ_ETOP_MDIO_ACC) & MDIO_REQUEST)
;
- val = ltq_etop_r32(LTQ_ETOP_MDIO) & MDIO_VAL_MASK;
+ val = ltq_etop_r32(LTQ_ETOP_MDIO_ACC) & MDIO_VAL_MASK;
return val;
}
@@ -376,14 +563,18 @@ ltq_etop_mdio_probe(struct net_device *d
{
struct ltq_etop_priv *priv = netdev_priv(dev);
struct phy_device *phydev = NULL;
- int phy_addr;
+ u32 phy_supported = (SUPPORTED_10baseT_Half
+ | SUPPORTED_10baseT_Full
+ | SUPPORTED_100baseT_Half
+ | SUPPORTED_100baseT_Full
+ | SUPPORTED_Autoneg
+ | SUPPORTED_MII
+ | SUPPORTED_TP);
- for (phy_addr = 0; phy_addr < PHY_MAX_ADDR; phy_addr++) {
- if (priv->mii_bus->phy_map[phy_addr]) {
- phydev = priv->mii_bus->phy_map[phy_addr];
- break;
- }
- }
+ if (of_machine_is_compatible("lantiq,ase"))
+ phydev = priv->mii_bus->phy_map[8];
+ else
+ phydev = priv->mii_bus->phy_map[0];
if (!phydev) {
netdev_err(dev, "no PHY found\n");
@@ -391,21 +582,18 @@ ltq_etop_mdio_probe(struct net_device *d
}
phydev = phy_connect(dev, dev_name(&phydev->dev),
- &ltq_etop_mdio_link, priv->pldata->mii_mode);
+ &ltq_etop_mdio_link, priv->mii_mode);
if (IS_ERR(phydev)) {
netdev_err(dev, "Could not attach to PHY\n");
return PTR_ERR(phydev);
}
- phydev->supported &= (SUPPORTED_10baseT_Half
- | SUPPORTED_10baseT_Full
- | SUPPORTED_100baseT_Half
- | SUPPORTED_100baseT_Full
- | SUPPORTED_Autoneg
- | SUPPORTED_MII
- | SUPPORTED_TP);
+ if (of_machine_is_compatible("lantiq,ar9"))
+ phy_supported |= SUPPORTED_1000baseT_Half
+ | SUPPORTED_1000baseT_Full;
+ phydev->supported &= phy_supported;
phydev->advertising = phydev->supported;
priv->phydev = phydev;
pr_info("%s: attached PHY [%s] (phy_addr=%s, irq=%d)\n",
@@ -430,8 +618,13 @@ ltq_etop_mdio_init(struct net_device *de
}
priv->mii_bus->priv = dev;
- priv->mii_bus->read = ltq_etop_mdio_rd;
- priv->mii_bus->write = ltq_etop_mdio_wr;
+ if (of_machine_is_compatible("lantiq,ar9")) {
+ priv->mii_bus->read = ltq_etop_mdio_rd_xr9;
+ priv->mii_bus->write = ltq_etop_mdio_wr_xr9;
+ } else {
+ priv->mii_bus->read = ltq_etop_mdio_rd;
+ priv->mii_bus->write = ltq_etop_mdio_wr;
+ }
priv->mii_bus->name = "ltq_mii";
snprintf(priv->mii_bus->id, MII_BUS_ID_SIZE, "%s-%x",
priv->pdev->name, priv->pdev->id);
@@ -480,17 +673,19 @@ static int
ltq_etop_open(struct net_device *dev)
{
struct ltq_etop_priv *priv = netdev_priv(dev);
- int i;
+ unsigned long flags;
- for (i = 0; i < MAX_DMA_CHAN; i++) {
- struct ltq_etop_chan *ch = &priv->ch[i];
+ napi_enable(&priv->txch.napi);
+ napi_enable(&priv->rxch.napi);
+
+ spin_lock_irqsave(&priv->lock, flags);
+ ltq_dma_open(&priv->txch.dma);
+ ltq_dma_open(&priv->rxch.dma);
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ if (priv->phydev)
+ phy_start(priv->phydev);
- if (!IS_TX(i) && (!IS_RX(i)))
- continue;
- ltq_dma_open(&ch->dma);
- napi_enable(&ch->napi);
- }
- phy_start(priv->phydev);
netif_tx_start_all_queues(dev);
return 0;
}
@@ -499,18 +694,19 @@ static int
ltq_etop_stop(struct net_device *dev)
{
struct ltq_etop_priv *priv = netdev_priv(dev);
- int i;
+ unsigned long flags;
netif_tx_stop_all_queues(dev);
- phy_stop(priv->phydev);
- for (i = 0; i < MAX_DMA_CHAN; i++) {
- struct ltq_etop_chan *ch = &priv->ch[i];
-
- if (!IS_RX(i) && !IS_TX(i))
- continue;
- napi_disable(&ch->napi);
- ltq_dma_close(&ch->dma);
- }
+ if (priv->phydev)
+ phy_stop(priv->phydev);
+ napi_disable(&priv->txch.napi);
+ napi_disable(&priv->rxch.napi);
+
+ spin_lock_irqsave(&priv->lock, flags);
+ ltq_dma_close(&priv->txch.dma);
+ ltq_dma_close(&priv->rxch.dma);
+ spin_unlock_irqrestore(&priv->lock, flags);
+
return 0;
}
@@ -520,16 +716,16 @@ ltq_etop_tx(struct sk_buff *skb, struct
int queue = skb_get_queue_mapping(skb);
struct netdev_queue *txq = netdev_get_tx_queue(dev, queue);
struct ltq_etop_priv *priv = netdev_priv(dev);
- struct ltq_etop_chan *ch = &priv->ch[(queue << 1) | 1];
- struct ltq_dma_desc *desc = &ch->dma.desc_base[ch->dma.desc];
- int len;
+ struct ltq_dma_desc *desc =
+ &priv->txch.dma.desc_base[priv->txch.dma.desc];
unsigned long flags;
u32 byte_offset;
+ int len;
len = skb->len < ETH_ZLEN ? ETH_ZLEN : skb->len;
- if ((desc->ctl & (LTQ_DMA_OWN | LTQ_DMA_C)) || ch->skb[ch->dma.desc]) {
- dev_kfree_skb_any(skb);
+ if ((desc->ctl & (LTQ_DMA_OWN | LTQ_DMA_C)) ||
+ priv->txch.skb[priv->txch.dma.desc]) {
netdev_err(dev, "tx ring full\n");
netif_tx_stop_queue(txq);
return NETDEV_TX_BUSY;
@@ -537,7 +733,7 @@ ltq_etop_tx(struct sk_buff *skb, struct
/* dma needs to start on a 16 byte aligned address */
byte_offset = CPHYSADDR(skb->data) % 16;
- ch->skb[ch->dma.desc] = skb;
+ priv->txch.skb[priv->txch.dma.desc] = skb;
dev->trans_start = jiffies;
@@ -547,11 +743,11 @@ ltq_etop_tx(struct sk_buff *skb, struct
wmb();
desc->ctl = LTQ_DMA_OWN | LTQ_DMA_SOP | LTQ_DMA_EOP |
LTQ_DMA_TX_OFFSET(byte_offset) | (len & LTQ_DMA_SIZE_MASK);
- ch->dma.desc++;
- ch->dma.desc %= LTQ_DESC_NUM;
+ priv->txch.dma.desc++;
+ priv->txch.dma.desc %= LTQ_DESC_NUM;
spin_unlock_irqrestore(&priv->lock, flags);
- if (ch->dma.desc_base[ch->dma.desc].ctl & LTQ_DMA_OWN)
+ if (priv->txch.dma.desc_base[priv->txch.dma.desc].ctl & LTQ_DMA_OWN)
netif_tx_stop_queue(txq);
return NETDEV_TX_OK;
@@ -566,8 +762,10 @@ ltq_etop_change_mtu(struct net_device *d
struct ltq_etop_priv *priv = netdev_priv(dev);
unsigned long flags;
+ int max = ETH_HLEN + VLAN_HLEN + new_mtu + ETH_FCS_LEN;
+
spin_lock_irqsave(&priv->lock, flags);
- ltq_etop_w32((ETOP_PLEN_UNDER << 16) | new_mtu,
+ ltq_etop_w32((ETOP_PLEN_UNDER << 16) | max,
LTQ_ETOP_IGPLEN);
spin_unlock_irqrestore(&priv->lock, flags);
}
@@ -638,6 +836,9 @@ ltq_etop_init(struct net_device *dev)
if (err)
goto err_hw;
ltq_etop_change_mtu(dev, 1500);
+ err = ltq_etop_dma_init(dev);
+ if (err)
+ goto err_hw;
memcpy(&mac, &priv->pldata->mac, sizeof(struct sockaddr));
if (!is_valid_ether_addr(mac.sa_data)) {
@@ -655,9 +856,10 @@ ltq_etop_init(struct net_device *dev)
dev->addr_assign_type = NET_ADDR_RANDOM;
ltq_etop_set_multicast_list(dev);
- err = ltq_etop_mdio_init(dev);
- if (err)
- goto err_netdev;
+ if (!ltq_etop_mdio_init(dev))
+ dev->ethtool_ops = &ltq_etop_ethtool_ops;
+ else
+ pr_warn("etop: mdio probe failed\n");;
return 0;
err_netdev:
@@ -677,6 +879,9 @@ ltq_etop_tx_timeout(struct net_device *d
err = ltq_etop_hw_init(dev);
if (err)
goto err_hw;
+ err = ltq_etop_dma_init(dev);
+ if (err)
+ goto err_hw;
dev->trans_start = jiffies;
netif_wake_queue(dev);
return;
@@ -700,14 +905,18 @@ static const struct net_device_ops ltq_e
.ndo_tx_timeout = ltq_etop_tx_timeout,
};
-static int __init
-ltq_etop_probe(struct platform_device *pdev)
+static int ltq_etop_probe(struct platform_device *pdev)
{
struct net_device *dev;
struct ltq_etop_priv *priv;
- struct resource *res;
+ struct resource *res, *gbit_res, irqres[2];
int err;
- int i;
+
+ err = of_irq_to_resource_table(pdev->dev.of_node, irqres, 2);
+ if (err != 2) {
+ dev_err(&pdev->dev, "failed to get etop irqs\n");
+ return -EINVAL;
+ }
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res) {
@@ -733,30 +942,58 @@ ltq_etop_probe(struct platform_device *p
goto err_out;
}
- dev = alloc_etherdev_mq(sizeof(struct ltq_etop_priv), 4);
- if (!dev) {
- err = -ENOMEM;
- goto err_out;
+ if (of_machine_is_compatible("lantiq,ar9")) {
+ gbit_res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+ if (!gbit_res) {
+ dev_err(&pdev->dev, "failed to get gbit resource\n");
+ err = -ENOENT;
+ goto err_out;
+ }
+ ltq_gbit_membase = devm_ioremap_nocache(&pdev->dev,
+ gbit_res->start, resource_size(gbit_res));
+ if (!ltq_gbit_membase) {
+ dev_err(&pdev->dev, "failed to remap gigabit switch %d\n",
+ pdev->id);
+ err = -ENOMEM;
+ goto err_out;
+ }
}
+
+ dev = alloc_etherdev_mq(sizeof(struct ltq_etop_priv), 4);
strcpy(dev->name, "eth%d");
dev->netdev_ops = &ltq_eth_netdev_ops;
- dev->ethtool_ops = &ltq_etop_ethtool_ops;
priv = netdev_priv(dev);
priv->res = res;
priv->pdev = pdev;
- priv->pldata = dev_get_platdata(&pdev->dev);
priv->netdev = dev;
+ priv->tx_irq = irqres[0].start;
+ priv->rx_irq = irqres[1].start;
+ priv->mii_mode = of_get_phy_mode(pdev->dev.of_node);
+ of_get_mac_address_mtd(pdev->dev.of_node, priv->mac);
+
+ priv->clk_ppe = clk_get(&pdev->dev, NULL);
+ if (IS_ERR(priv->clk_ppe))
+ return PTR_ERR(priv->clk_ppe);
+ if (of_machine_is_compatible("lantiq,ar9")) {
+ priv->clk_switch = clk_get(&pdev->dev, "switch");
+ if (IS_ERR(priv->clk_switch))
+ return PTR_ERR(priv->clk_switch);
+ }
+ if (of_machine_is_compatible("lantiq,ase")) {
+ priv->clk_ephy = clk_get(&pdev->dev, "ephy");
+ if (IS_ERR(priv->clk_ephy))
+ return PTR_ERR(priv->clk_ephy);
+ priv->clk_ephycgu = clk_get(&pdev->dev, "ephycgu");
+ if (IS_ERR(priv->clk_ephycgu))
+ return PTR_ERR(priv->clk_ephycgu);
+ }
+
spin_lock_init(&priv->lock);
- for (i = 0; i < MAX_DMA_CHAN; i++) {
- if (IS_TX(i))
- netif_napi_add(dev, &priv->ch[i].napi,
- ltq_etop_poll_tx, 8);
- else if (IS_RX(i))
- netif_napi_add(dev, &priv->ch[i].napi,
- ltq_etop_poll_rx, 32);
- priv->ch[i].netdev = dev;
- }
+ netif_napi_add(dev, &priv->txch.napi, ltq_etop_poll_tx, 8);
+ netif_napi_add(dev, &priv->rxch.napi, ltq_etop_poll_rx, 32);
+ priv->txch.netdev = dev;
+ priv->rxch.netdev = dev;
err = register_netdev(dev);
if (err)
@@ -785,31 +1022,22 @@ ltq_etop_remove(struct platform_device *
return 0;
}
+static const struct of_device_id ltq_etop_match[] = {
+ { .compatible = "lantiq,etop-xway" },
+ {},
+};
+MODULE_DEVICE_TABLE(of, ltq_etop_match);
+
static struct platform_driver ltq_mii_driver = {
+ .probe = ltq_etop_probe,
.remove = ltq_etop_remove,
.driver = {
.name = "ltq_etop",
+ .of_match_table = ltq_etop_match,
},
};
-int __init
-init_ltq_etop(void)
-{
- int ret = platform_driver_probe(&ltq_mii_driver, ltq_etop_probe);
-
- if (ret)
- pr_err("ltq_etop: Error registering platform driver!");
- return ret;
-}
-
-static void __exit
-exit_ltq_etop(void)
-{
- platform_driver_unregister(&ltq_mii_driver);
-}
-
-module_init(init_ltq_etop);
-module_exit(exit_ltq_etop);
+module_platform_driver(ltq_mii_driver);
MODULE_AUTHOR("John Crispin <blogic@openwrt.org>");
MODULE_DESCRIPTION("Lantiq SoC ETOP");

@ -0,0 +1,166 @@
From cc809a441d8f2924f785eb863dfa6aef47a25b0b Mon Sep 17 00:00:00 2001
From: John Crispin <blogic@openwrt.org>
Date: Tue, 12 Aug 2014 20:49:27 +0200
Subject: [PATCH 30/36] GPIO: add named gpio exports
Signed-off-by: John Crispin <blogic@openwrt.org>
---
drivers/gpio/gpiolib-of.c | 68 +++++++++++++++++++++++++++++++++++++++++
drivers/gpio/gpiolib.c | 11 +++++--
include/asm-generic/gpio.h | 5 +++
include/linux/gpio/consumer.h | 8 +++++
4 files changed, 90 insertions(+), 2 deletions(-)
--- a/drivers/gpio/gpiolib-of.c
+++ b/drivers/gpio/gpiolib-of.c
@@ -23,6 +23,8 @@
#include <linux/pinctrl/pinctrl.h>
#include <linux/slab.h>
#include <linux/gpio/machine.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
#include "gpiolib.h"
@@ -444,3 +446,69 @@ void of_gpiochip_remove(struct gpio_chip
gpiochip_remove_pin_ranges(chip);
of_node_put(chip->of_node);
}
+
+static struct of_device_id gpio_export_ids[] = {
+ { .compatible = "gpio-export" },
+ { /* sentinel */ }
+};
+
+static int __init of_gpio_export_probe(struct platform_device *pdev)
+{
+ struct device_node *np = pdev->dev.of_node;
+ struct device_node *cnp;
+ u32 val;
+ int nb = 0;
+
+ for_each_child_of_node(np, cnp) {
+ const char *name = NULL;
+ int gpio;
+ bool dmc;
+ int max_gpio = 1;
+ int i;
+
+ of_property_read_string(cnp, "gpio-export,name", &name);
+
+ if (!name)
+ max_gpio = of_gpio_count(cnp);
+
+ for (i = 0; i < max_gpio; i++) {
+ unsigned flags = 0;
+ enum of_gpio_flags of_flags;
+
+ gpio = of_get_gpio_flags(cnp, i, &of_flags);
+
+ if (of_flags == OF_GPIO_ACTIVE_LOW)
+ flags |= GPIOF_ACTIVE_LOW;
+
+ if (!of_property_read_u32(cnp, "gpio-export,output", &val))
+ flags |= val ? GPIOF_OUT_INIT_HIGH : GPIOF_OUT_INIT_LOW;
+ else
+ flags |= GPIOF_IN;
+
+ if (devm_gpio_request_one(&pdev->dev, gpio, flags, name ? name : of_node_full_name(np)))
+ continue;
+
+ dmc = of_property_read_bool(cnp, "gpio-export,direction_may_change");
+ gpio_export_with_name(gpio, dmc, name);
+ nb++;
+ }
+ }
+
+ dev_info(&pdev->dev, "%d gpio(s) exported\n", nb);
+
+ return 0;
+}
+
+static struct platform_driver gpio_export_driver = {
+ .driver = {
+ .name = "gpio-export",
+ .owner = THIS_MODULE,
+ .of_match_table = of_match_ptr(gpio_export_ids),
+ },
+};
+
+static int __init of_gpio_export_init(void)
+{
+ return platform_driver_probe(&gpio_export_driver, of_gpio_export_probe);
+}
+device_initcall(of_gpio_export_init);
--- a/include/asm-generic/gpio.h
+++ b/include/asm-generic/gpio.h
@@ -122,6 +122,12 @@ static inline int gpio_export(unsigned g
return gpiod_export(gpio_to_desc(gpio), direction_may_change);
}
+int __gpiod_export(struct gpio_desc *desc, bool direction_may_change, const char *name);
+static inline int gpio_export_with_name(unsigned gpio, bool direction_may_change, const char *name)
+{
+ return __gpiod_export(gpio_to_desc(gpio), direction_may_change, name);
+}
+
static inline int gpio_export_link(struct device *dev, const char *name,
unsigned gpio)
{
--- a/include/linux/gpio/consumer.h
+++ b/include/linux/gpio/consumer.h
@@ -446,6 +446,7 @@ static inline int desc_to_gpio(const str
#if IS_ENABLED(CONFIG_GPIOLIB) && IS_ENABLED(CONFIG_GPIO_SYSFS)
+int _gpiod_export(struct gpio_desc *desc, bool direction_may_change, const char *name);
int gpiod_export(struct gpio_desc *desc, bool direction_may_change);
int gpiod_export_link(struct device *dev, const char *name,
struct gpio_desc *desc);
@@ -454,6 +455,13 @@ void gpiod_unexport(struct gpio_desc *de
#else /* CONFIG_GPIOLIB && CONFIG_GPIO_SYSFS */
+static inline int _gpiod_export(struct gpio_desc *desc,
+ bool direction_may_change,
+ const char *name)
+{
+ return -ENOSYS;
+}
+
static inline int gpiod_export(struct gpio_desc *desc,
bool direction_may_change)
{
--- a/drivers/gpio/gpiolib-sysfs.c
+++ b/drivers/gpio/gpiolib-sysfs.c
@@ -549,7 +549,7 @@ static struct class gpio_class = {
*
* Returns zero on success, else an error.
*/
-int gpiod_export(struct gpio_desc *desc, bool direction_may_change)
+int __gpiod_export(struct gpio_desc *desc, bool direction_may_change, const char *name)
{
struct gpio_chip *chip;
unsigned long flags;
@@ -601,6 +601,8 @@ int gpiod_export(struct gpio_desc *desc,
offset = gpio_chip_hwgpio(desc);
if (desc->chip->names && desc->chip->names[offset])
ioname = desc->chip->names[offset];
+ if (name)
+ ioname = name;
dev = device_create_with_groups(&gpio_class, desc->chip->dev,
MKDEV(0, 0), desc, gpio_groups,
@@ -620,6 +622,12 @@ fail_unlock:
gpiod_dbg(desc, "%s: status %d\n", __func__, status);
return status;
}
+EXPORT_SYMBOL_GPL(__gpiod_export);
+
+int gpiod_export(struct gpio_desc *desc, bool direction_may_change)
+{
+ return __gpiod_export(desc, direction_may_change, NULL);
+}
EXPORT_SYMBOL_GPL(gpiod_export);
static int match_export(struct device *dev, const void *data)

@ -0,0 +1,31 @@
From 326714a47233e4a524afa0c8398276fddf0dbd4d Mon Sep 17 00:00:00 2001
From: John Crispin <blogic@openwrt.org>
Date: Thu, 6 Dec 2012 19:59:53 +0100
Subject: [PATCH 32/36] USB: fix roothub for IFXHCD
---
arch/mips/lantiq/Kconfig | 1 +
drivers/usb/core/hub.c | 2 +-
2 files changed, 2 insertions(+), 1 deletion(-)
--- a/arch/mips/lantiq/Kconfig
+++ b/arch/mips/lantiq/Kconfig
@@ -3,6 +3,7 @@ if LANTIQ
config SOC_TYPE_XWAY
bool
select PINCTRL_XWAY
+ select USB_ARCH_HAS_HCD
default n
choice
--- a/drivers/usb/core/hub.c
+++ b/drivers/usb/core/hub.c
@@ -4314,7 +4314,7 @@ hub_port_init (struct usb_hub *hub, stru
udev->ttport = hdev->ttport;
} else if (udev->speed != USB_SPEED_HIGH
&& hdev->speed == USB_SPEED_HIGH) {
- if (!hub->tt.hub) {
+ if (hdev->parent && !hub->tt.hub) {
dev_err(&udev->dev, "parent hub has no TT\n");
retval = -EINVAL;
goto fail;

@ -0,0 +1,45 @@
From b1b9fca8c317afc3f2b78bb54f877e8a830a819d Mon Sep 17 00:00:00 2001
From: John Crispin <blogic@openwrt.org>
Date: Fri, 9 Aug 2013 18:47:27 +0200
Subject: [PATCH 34/36] reset: Fix compile when reset RESET_CONTROLLER is not
selected
Drivers need to protect their reset api calls with #ifdef to avoid compile
errors.
This patch adds dummy wrappers in the same way that linux/of.h does it.
Cc: linux-kernel@vger.kernel.org
Cc: Philipp Zabel <p.zabel@pengutronix.de>
Cc: Gabor Juhos <juhosg@openwrt.org>
---
include/linux/reset-controller.h | 16 ++++++++++++++
include/linux/reset.h | 43 ++++++++++++++++++++++++++++++++++++++
2 files changed, 59 insertions(+)
--- a/include/linux/reset-controller.h
+++ b/include/linux/reset-controller.h
@@ -48,7 +48,23 @@ struct reset_controller_dev {
unsigned int nr_resets;
};
+#if defined(CONFIG_RESET_CONTROLLER)
+
int reset_controller_register(struct reset_controller_dev *rcdev);
void reset_controller_unregister(struct reset_controller_dev *rcdev);
+#else
+
+static inline int reset_controller_register(struct reset_controller_dev *rcdev)
+{
+ return -ENOSYS;
+}
+
+void reset_controller_unregister(struct reset_controller_dev *rcdev)
+{
+
+}
+
+#endif
+
#endif

@ -0,0 +1,614 @@
From f8c5db89e793a4bc6c1e87bd7b3a5cec16b75bc3 Mon Sep 17 00:00:00 2001
From: John Crispin <blogic@openwrt.org>
Date: Wed, 10 Sep 2014 22:42:14 +0200
Subject: [PATCH 35/36] owrt: lantiq: wifi and ethernet eeprom handling
Signed-off-by: John Crispin <blogic@openwrt.org>
---
arch/mips/include/asm/mach-lantiq/pci-ath-fixup.h | 6 +
.../mips/include/asm/mach-lantiq/xway/lantiq_soc.h | 3 +
arch/mips/lantiq/xway/Makefile | 3 +
arch/mips/lantiq/xway/ath_eep.c | 282 ++++++++++++++++++++
arch/mips/lantiq/xway/eth_mac.c | 76 ++++++
arch/mips/lantiq/xway/pci-ath-fixup.c | 109 ++++++++
arch/mips/lantiq/xway/rt_eep.c | 60 +++++
7 files changed, 539 insertions(+)
create mode 100644 arch/mips/include/asm/mach-lantiq/pci-ath-fixup.h
create mode 100644 arch/mips/lantiq/xway/ath_eep.c
create mode 100644 arch/mips/lantiq/xway/eth_mac.c
create mode 100644 arch/mips/lantiq/xway/pci-ath-fixup.c
create mode 100644 arch/mips/lantiq/xway/rt_eep.c
--- /dev/null
+++ b/arch/mips/include/asm/mach-lantiq/pci-ath-fixup.h
@@ -0,0 +1,6 @@
+#ifndef _PCI_ATH_FIXUP
+#define _PCI_ATH_FIXUP
+
+void ltq_pci_ath_fixup(unsigned slot, u16 *cal_data) __init;
+
+#endif /* _PCI_ATH_FIXUP */
--- a/arch/mips/include/asm/mach-lantiq/xway/lantiq_soc.h
+++ b/arch/mips/include/asm/mach-lantiq/xway/lantiq_soc.h
@@ -90,5 +90,8 @@ int xrx200_gphy_boot(struct device *dev,
extern void ltq_pmu_enable(unsigned int module);
extern void ltq_pmu_disable(unsigned int module);
+/* allow the ethernet driver to load a flash mapped mac addr */
+const u8* ltq_get_eth_mac(void);
+
#endif /* CONFIG_SOC_TYPE_XWAY */
#endif /* _LTQ_XWAY_H__ */
--- a/arch/mips/lantiq/xway/Makefile
+++ b/arch/mips/lantiq/xway/Makefile
@@ -2,4 +2,7 @@ obj-y := prom.o sysctrl.o clk.o reset.o
obj-y += vmmc.o tffs.o
+obj-y += eth_mac.o
+obj-$(CONFIG_PCI) += ath_eep.o rt_eep.o pci-ath-fixup.o
+
obj-$(CONFIG_XRX200_PHY_FW) += xrx200_phy_fw.o
--- /dev/null
+++ b/arch/mips/lantiq/xway/ath_eep.c
@@ -0,0 +1,282 @@
+/*
+ * Copyright (C) 2011 Luca Olivetti <luca@ventoso.org>
+ * Copyright (C) 2011 John Crispin <blogic@openwrt.org>
+ * Copyright (C) 2011 Andrej Vlašić <andrej.vlasic0@gmail.com>
+ * Copyright (C) 2013 Álvaro Fernández Rojas <noltari@gmail.com>
+ * Copyright (C) 2013 Daniel Gimpelevich <daniel@gimpelevich.san-francisco.ca.us>
+ *
+ * This program 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.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/etherdevice.h>
+#include <linux/ath5k_platform.h>
+#include <linux/ath9k_platform.h>
+#include <linux/pci.h>
+#include <linux/err.h>
+#include <linux/mtd/mtd.h>
+#include <pci-ath-fixup.h>
+#include <lantiq_soc.h>
+
+extern int (*ltq_pci_plat_dev_init)(struct pci_dev *dev);
+struct ath5k_platform_data ath5k_pdata;
+struct ath9k_platform_data ath9k_pdata = {
+ .led_pin = -1,
+};
+static u8 athxk_eeprom_mac[6];
+
+static int ath9k_pci_plat_dev_init(struct pci_dev *dev)
+{
+ dev->dev.platform_data = &ath9k_pdata;
+ return 0;
+}
+
+static int ath9k_eep_load;
+int __init of_ath9k_eeprom_probe(struct platform_device *pdev)
+{
+ struct device_node *np = pdev->dev.of_node, *mtd_np;
+ struct resource *eep_res, *mac_res = NULL;
+ void __iomem *eep, *mac;
+ int mac_offset, led_pin;
+ u32 mac_inc = 0, pci_slot = 0;
+ int i;
+ struct mtd_info *the_mtd;
+ size_t flash_readlen;
+ const __be32 *list;
+ const char *part;
+ phandle phandle;
+
+ if ((list = of_get_property(np, "ath,eep-flash", &i)) && i == 2 *
+ sizeof(*list) && (phandle = be32_to_cpup(list++)) &&
+ (mtd_np = of_find_node_by_phandle(phandle)) && ((part =
+ of_get_property(mtd_np, "label", NULL)) || (part =
+ mtd_np->name)) && (the_mtd = get_mtd_device_nm(part))
+ != ERR_PTR(-ENODEV)) {
+ i = mtd_read(the_mtd, be32_to_cpup(list),
+ ATH9K_PLAT_EEP_MAX_WORDS << 1, &flash_readlen,
+ (void *) ath9k_pdata.eeprom_data);
+ if (!of_property_read_u32(np, "ath,mac-offset", &mac_offset)) {
+ size_t mac_readlen;
+ mtd_read(the_mtd, mac_offset, 6, &mac_readlen,
+ (void *) athxk_eeprom_mac);
+ }
+ put_mtd_device(the_mtd);
+ if ((sizeof(ath9k_pdata.eeprom_data) != flash_readlen) || i) {
+ dev_err(&pdev->dev, "failed to load eeprom from mtd\n");
+ return -ENODEV;
+ }
+ } else {
+ eep_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ mac_res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+
+ if (!eep_res) {
+ dev_err(&pdev->dev, "failed to load eeprom address\n");
+ return -ENODEV;
+ }
+ if (resource_size(eep_res) != ATH9K_PLAT_EEP_MAX_WORDS << 1) {
+ dev_err(&pdev->dev, "eeprom has an invalid size\n");
+ return -EINVAL;
+ }
+
+ eep = ioremap(eep_res->start, resource_size(eep_res));
+ memcpy_fromio(ath9k_pdata.eeprom_data, eep,
+ ATH9K_PLAT_EEP_MAX_WORDS << 1);
+ }
+
+ if (of_find_property(np, "ath,eep-swap", NULL))
+ for (i = 0; i < ATH9K_PLAT_EEP_MAX_WORDS; i++)
+ ath9k_pdata.eeprom_data[i] = swab16(ath9k_pdata.eeprom_data[i]);
+
+ if (of_find_property(np, "ath,eep-endian", NULL)) {
+ ath9k_pdata.endian_check = true;
+
+ dev_info(&pdev->dev, "endian check enabled.\n");
+ }
+
+ if (!is_valid_ether_addr(athxk_eeprom_mac)) {
+ if (mac_res) {
+ if (resource_size(mac_res) != 6) {
+ dev_err(&pdev->dev, "mac has an invalid size\n");
+ return -EINVAL;
+ }
+ mac = ioremap(mac_res->start, resource_size(mac_res));
+ memcpy_fromio(athxk_eeprom_mac, mac, 6);
+ } else if (ltq_get_eth_mac()) {
+ memcpy(athxk_eeprom_mac, ltq_get_eth_mac(), 6);
+ }
+ }
+ if (!is_valid_ether_addr(athxk_eeprom_mac)) {
+ dev_warn(&pdev->dev, "using random mac\n");
+ random_ether_addr(athxk_eeprom_mac);
+ }
+
+ if (!of_property_read_u32(np, "ath,mac-increment", &mac_inc))
+ athxk_eeprom_mac[5] += mac_inc;
+
+ ath9k_pdata.macaddr = athxk_eeprom_mac;
+ ltq_pci_plat_dev_init = ath9k_pci_plat_dev_init;
+
+ if (!of_property_read_u32(np, "ath,pci-slot", &pci_slot)) {
+ ltq_pci_ath_fixup(pci_slot, ath9k_pdata.eeprom_data);
+
+ dev_info(&pdev->dev, "pci slot: %u\n", pci_slot);
+ if (ath9k_eep_load) {
+ struct pci_dev *d = NULL;
+ while ((d = pci_get_device(PCI_VENDOR_ID_ATHEROS,
+ PCI_ANY_ID, d)) != NULL)
+ pci_fixup_device(pci_fixup_early, d);
+ }
+
+ }
+
+ if (!of_property_read_u32(np, "ath,led-pin", &led_pin)) {
+ ath9k_pdata.led_pin = led_pin;
+ dev_info(&pdev->dev, "using led pin %d.\n", led_pin);
+ }
+
+ dev_info(&pdev->dev, "loaded ath9k eeprom\n");
+
+ return 0;
+}
+
+static struct of_device_id ath9k_eeprom_ids[] = {
+ { .compatible = "ath9k,eeprom" },
+ { }
+};
+
+static struct platform_driver ath9k_eeprom_driver = {
+ .driver = {
+ .name = "ath9k,eeprom",
+ .owner = THIS_MODULE,
+ .of_match_table = of_match_ptr(ath9k_eeprom_ids),
+ },
+};
+
+static int __init of_ath9k_eeprom_init(void)
+{
+ int ret = platform_driver_probe(&ath9k_eeprom_driver, of_ath9k_eeprom_probe);
+
+ if (ret)
+ ath9k_eep_load = 1;
+
+ return ret;
+}
+
+static int __init of_ath9k_eeprom_init_late(void)
+{
+ if (!ath9k_eep_load)
+ return 0;
+ return platform_driver_probe(&ath9k_eeprom_driver, of_ath9k_eeprom_probe);
+}
+late_initcall(of_ath9k_eeprom_init_late);
+subsys_initcall(of_ath9k_eeprom_init);
+
+
+static int ath5k_pci_plat_dev_init(struct pci_dev *dev)
+{
+ dev->dev.platform_data = &ath5k_pdata;
+ return 0;
+}
+
+int __init of_ath5k_eeprom_probe(struct platform_device *pdev)
+{
+ struct device_node *np = pdev->dev.of_node, *mtd_np;
+ struct resource *eep_res, *mac_res = NULL;
+ void __iomem *eep, *mac;
+ int mac_offset;
+ u32 mac_inc = 0;
+ int i;
+ struct mtd_info *the_mtd;
+ size_t flash_readlen;
+ const __be32 *list;
+ const char *part;
+ phandle phandle;
+
+ if ((list = of_get_property(np, "ath,eep-flash", &i)) && i == 2 *
+ sizeof(*list) && (phandle = be32_to_cpup(list++)) &&
+ (mtd_np = of_find_node_by_phandle(phandle)) && ((part =
+ of_get_property(mtd_np, "label", NULL)) || (part =
+ mtd_np->name)) && (the_mtd = get_mtd_device_nm(part))
+ != ERR_PTR(-ENODEV)) {
+ i = mtd_read(the_mtd, be32_to_cpup(list),
+ ATH5K_PLAT_EEP_MAX_WORDS << 1, &flash_readlen,
+ (void *) ath5k_pdata.eeprom_data);
+ put_mtd_device(the_mtd);
+ if ((sizeof(ATH5K_PLAT_EEP_MAX_WORDS << 1) != flash_readlen)
+ || i) {
+ dev_err(&pdev->dev, "failed to load eeprom from mtd\n");
+ return -ENODEV;
+ }
+ } else {
+ eep_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ mac_res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+
+ if (!eep_res) {
+ dev_err(&pdev->dev, "failed to load eeprom address\n");
+ return -ENODEV;
+ }
+ if (resource_size(eep_res) != ATH5K_PLAT_EEP_MAX_WORDS << 1) {
+ dev_err(&pdev->dev, "eeprom has an invalid size\n");
+ return -EINVAL;
+ }
+
+ eep = ioremap(eep_res->start, resource_size(eep_res));
+ ath5k_pdata.eeprom_data = kmalloc(ATH5K_PLAT_EEP_MAX_WORDS<<1,
+ GFP_KERNEL);
+ memcpy_fromio(ath5k_pdata.eeprom_data, eep,
+ ATH5K_PLAT_EEP_MAX_WORDS << 1);
+ }
+
+ if (of_find_property(np, "ath,eep-swap", NULL))
+ for (i = 0; i < ATH5K_PLAT_EEP_MAX_WORDS; i++)
+ ath5k_pdata.eeprom_data[i] = swab16(ath5k_pdata.eeprom_data[i]);
+
+ if (!of_property_read_u32(np, "ath,mac-offset", &mac_offset)) {
+ memcpy_fromio(athxk_eeprom_mac, (void*) ath5k_pdata.eeprom_data + mac_offset, 6);
+ } else if (mac_res) {
+ if (resource_size(mac_res) != 6) {
+ dev_err(&pdev->dev, "mac has an invalid size\n");
+ return -EINVAL;
+ }
+ mac = ioremap(mac_res->start, resource_size(mac_res));
+ memcpy_fromio(athxk_eeprom_mac, mac, 6);
+ } else if (ltq_get_eth_mac())
+ memcpy(athxk_eeprom_mac, ltq_get_eth_mac(), 6);
+ else {
+ dev_warn(&pdev->dev, "using random mac\n");
+ random_ether_addr(athxk_eeprom_mac);
+ }
+
+ if (!of_property_read_u32(np, "ath,mac-increment", &mac_inc))
+ athxk_eeprom_mac[5] += mac_inc;
+
+ ath5k_pdata.macaddr = athxk_eeprom_mac;
+ ltq_pci_plat_dev_init = ath5k_pci_plat_dev_init;
+
+ dev_info(&pdev->dev, "loaded ath5k eeprom\n");
+
+ return 0;
+}
+
+static struct of_device_id ath5k_eeprom_ids[] = {
+ { .compatible = "ath5k,eeprom" },
+ { }
+};
+
+static struct platform_driver ath5k_eeprom_driver = {
+ .driver = {
+ .name = "ath5k,eeprom",
+ .owner = THIS_MODULE,
+ .of_match_table = of_match_ptr(ath5k_eeprom_ids),
+ },
+};
+
+static int __init of_ath5k_eeprom_init(void)
+{
+ return platform_driver_probe(&ath5k_eeprom_driver, of_ath5k_eeprom_probe);
+}
+device_initcall(of_ath5k_eeprom_init);
--- /dev/null
+++ b/arch/mips/lantiq/xway/eth_mac.c
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2012 John Crispin <blogic@openwrt.org>
+ *
+ * This program 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.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/of_platform.h>
+#include <linux/if_ether.h>
+
+static u8 eth_mac[6];
+static int eth_mac_set;
+
+const u8* ltq_get_eth_mac(void)
+{
+ return eth_mac;
+}
+
+static int __init setup_ethaddr(char *str)
+{
+ eth_mac_set = mac_pton(str, eth_mac);
+ return !eth_mac_set;
+}
+__setup("ethaddr=", setup_ethaddr);
+
+int __init of_eth_mac_probe(struct platform_device *pdev)
+{
+ struct device_node *np = pdev->dev.of_node;
+ struct resource *mac_res;
+ void __iomem *mac;
+ u32 mac_inc = 0;
+
+ if (eth_mac_set) {
+ dev_err(&pdev->dev, "mac was already set by bootloader\n");
+ return -EINVAL;
+ }
+ mac_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+
+ if (!mac_res) {
+ dev_err(&pdev->dev, "failed to load mac\n");
+ return -EINVAL;
+ }
+ if (resource_size(mac_res) != 6) {
+ dev_err(&pdev->dev, "mac has an invalid size\n");
+ return -EINVAL;
+ }
+ mac = ioremap(mac_res->start, resource_size(mac_res));
+ memcpy_fromio(eth_mac, mac, 6);
+
+ if (!of_property_read_u32(np, "mac-increment", &mac_inc))
+ eth_mac[5] += mac_inc;
+
+ return 0;
+}
+
+static struct of_device_id eth_mac_ids[] = {
+ { .compatible = "lantiq,eth-mac" },
+ { /* sentinel */ }
+};
+
+static struct platform_driver eth_mac_driver = {
+ .driver = {
+ .name = "lantiq,eth-mac",
+ .owner = THIS_MODULE,
+ .of_match_table = of_match_ptr(eth_mac_ids),
+ },
+};
+
+static int __init of_eth_mac_init(void)
+{
+ return platform_driver_probe(&eth_mac_driver, of_eth_mac_probe);
+}
+device_initcall(of_eth_mac_init);
--- /dev/null
+++ b/arch/mips/lantiq/xway/pci-ath-fixup.c
@@ -0,0 +1,109 @@
+/*
+ * Atheros AP94 reference board PCI initialization
+ *
+ * Copyright (C) 2009-2010 Gabor Juhos <juhosg@openwrt.org>
+ *
+ * This program 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.
+ */
+
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <lantiq_soc.h>
+
+#define LTQ_PCI_MEM_BASE 0x18000000
+
+struct ath_fixup {
+ u16 *cal_data;
+ unsigned slot;
+};
+
+static int ath_num_fixups;
+static struct ath_fixup ath_fixups[2];
+
+static void ath_pci_fixup(struct pci_dev *dev)
+{
+ void __iomem *mem;
+ u16 *cal_data = NULL;
+ u16 cmd;
+ u32 bar0;
+ u32 val;
+ unsigned i;
+
+ for (i = 0; i < ath_num_fixups; i++) {
+ if (ath_fixups[i].cal_data == NULL)
+ continue;
+
+ if (ath_fixups[i].slot != PCI_SLOT(dev->devfn))
+ continue;
+
+ cal_data = ath_fixups[i].cal_data;
+ break;
+ }
+
+ if (cal_data == NULL)
+ return;
+
+ if (*cal_data != 0xa55a) {
+ pr_err("pci %s: invalid calibration data\n", pci_name(dev));
+ return;
+ }
+
+ pr_info("pci %s: fixup device configuration\n", pci_name(dev));
+
+ mem = ioremap(LTQ_PCI_MEM_BASE, 0x10000);
+ if (!mem) {
+ pr_err("pci %s: ioremap error\n", pci_name(dev));
+ return;
+ }
+
+ pci_read_config_dword(dev, PCI_BASE_ADDRESS_0, &bar0);
+ pci_write_config_dword(dev, PCI_BASE_ADDRESS_0, LTQ_PCI_MEM_BASE);
+ pci_read_config_word(dev, PCI_COMMAND, &cmd);
+ cmd |= PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY;
+ pci_write_config_word(dev, PCI_COMMAND, cmd);
+
+ /* set pointer to first reg address */
+ cal_data += 3;
+ while (*cal_data != 0xffff) {
+ u32 reg;
+ reg = *cal_data++;
+ val = *cal_data++;
+ val |= (*cal_data++) << 16;
+
+ ltq_w32(swab32(val), mem + reg);
+ udelay(100);
+ }
+
+ pci_read_config_dword(dev, PCI_VENDOR_ID, &val);
+ dev->vendor = val & 0xffff;
+ dev->device = (val >> 16) & 0xffff;
+
+ pci_read_config_dword(dev, PCI_CLASS_REVISION, &val);
+ dev->revision = val & 0xff;
+ dev->class = val >> 8; /* upper 3 bytes */
+
+ pr_info("pci %s: fixup info: [%04x:%04x] revision %02x class %#08x\n",
+ pci_name(dev), dev->vendor, dev->device, dev->revision, dev->class);
+
+ pci_read_config_word(dev, PCI_COMMAND, &cmd);
+ cmd &= ~(PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY);
+ pci_write_config_word(dev, PCI_COMMAND, cmd);
+
+ pci_write_config_dword(dev, PCI_BASE_ADDRESS_0, bar0);
+
+ iounmap(mem);
+}
+DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_ATHEROS, PCI_ANY_ID, ath_pci_fixup);
+
+void __init ltq_pci_ath_fixup(unsigned slot, u16 *cal_data)
+{
+ if (ath_num_fixups >= ARRAY_SIZE(ath_fixups))
+ return;
+
+ ath_fixups[ath_num_fixups].slot = slot;
+ ath_fixups[ath_num_fixups].cal_data = cal_data;
+ ath_num_fixups++;
+}
--- /dev/null
+++ b/arch/mips/lantiq/xway/rt_eep.c
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2011 John Crispin <blogic@openwrt.org>
+ *
+ * This program 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.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/platform_device.h>
+#include <linux/rt2x00_platform.h>
+
+extern int (*ltq_pci_plat_dev_init)(struct pci_dev *dev);
+static struct rt2x00_platform_data rt2x00_pdata;
+
+static int rt2x00_pci_plat_dev_init(struct pci_dev *dev)
+{
+ dev->dev.platform_data = &rt2x00_pdata;
+ return 0;
+}
+
+int __init of_ralink_eeprom_probe(struct platform_device *pdev)
+{
+ struct device_node *np = pdev->dev.of_node;
+ const char *eeprom;
+
+ if (of_property_read_string(np, "ralink,eeprom", &eeprom)) {
+ dev_err(&pdev->dev, "failed to load eeprom filename\n");
+ return 0;
+ }
+
+ rt2x00_pdata.eeprom_file_name = kstrdup(eeprom, GFP_KERNEL);
+// rt2x00_pdata.mac_address = mac;
+ ltq_pci_plat_dev_init = rt2x00_pci_plat_dev_init;
+
+ dev_info(&pdev->dev, "using %s as eeprom\n", eeprom);
+
+ return 0;
+}
+
+static struct of_device_id ralink_eeprom_ids[] = {
+ { .compatible = "ralink,eeprom" },
+ { }
+};
+
+static struct platform_driver ralink_eeprom_driver = {
+ .driver = {
+ .name = "ralink,eeprom",
+ .owner = THIS_MODULE,
+ .of_match_table = of_match_ptr(ralink_eeprom_ids),
+ },
+};
+
+static int __init of_ralink_eeprom_init(void)
+{
+ return platform_driver_probe(&ralink_eeprom_driver, of_ralink_eeprom_probe);
+}
+device_initcall(of_ralink_eeprom_init);
--- a/drivers/net/ethernet/lantiq_etop.c
+++ b/drivers/net/ethernet/lantiq_etop.c
@@ -161,7 +161,7 @@ struct ltq_etop_priv {
int tx_irq;
int rx_irq;
- const void *mac;
+ void *mac;
int mii_mode;
spinlock_t lock;
@@ -840,7 +840,11 @@ ltq_etop_init(struct net_device *dev)
if (err)
goto err_hw;
- memcpy(&mac, &priv->pldata->mac, sizeof(struct sockaddr));
+ if (priv->mac)
+ memcpy(&mac.sa_data, priv->mac, ETH_ALEN);
+ else
+ memcpy(&mac.sa_data, ltq_get_eth_mac(), ETH_ALEN);
+
if (!is_valid_ether_addr(mac.sa_data)) {
pr_warn("etop: invalid MAC, using random\n");
eth_random_addr(mac.sa_data);

@ -0,0 +1,32 @@
From dba8578e06aedf1e67312ebfc6162e2fadc9448d Mon Sep 17 00:00:00 2001
From: John Crispin <blogic@openwrt.org>
Date: Thu, 7 Aug 2014 18:32:12 +0200
Subject: [PATCH 36/36] owrt: generic dtb image hack
Signed-off-by: John Crispin <blogic@openwrt.org>
---
arch/mips/kernel/head.S | 3 +++
1 file changed, 3 insertions(+)
--- a/arch/mips/kernel/head.S
+++ b/arch/mips/kernel/head.S
@@ -86,6 +86,9 @@ EXPORT(__image_cmdline)
.fill 0x400
#endif /* CONFIG_IMAGE_CMDLINE_HACK */
+ .ascii "OWRTDTB:"
+ EXPORT(__image_dtb)
+ .fill 0x4000
__REF
NESTED(kernel_entry, 16, sp) # kernel entry point
--- a/arch/mips/lantiq/Kconfig
+++ b/arch/mips/lantiq/Kconfig
@@ -32,7 +32,6 @@ choice
config DT_EASY50712
bool "Easy50712"
depends on SOC_XWAY
- select BUILTIN_DTB
endchoice
config PCI_LANTIQ

@ -0,0 +1,21 @@
Return correct value for fpi clock on ar9.
Signed-off-by: Ben Mulvihill <ben.mulvihill@gmail.com>
---
arch/mips/lantiq/xway/clk.c | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
--- a/arch/mips/lantiq/xway/clk.c
+++ b/arch/mips/lantiq/xway/clk.c
@@ -87,8 +87,9 @@ unsigned long ltq_ar9_fpi_hz(void)
unsigned long sys = ltq_ar9_sys_hz();
if (ltq_cgu_r32(CGU_SYS) & BIT(0))
- return sys;
- return sys >> 1;
+ return sys / 3;
+ else
+ return sys / 2;
}
unsigned long ltq_ar9_cpu_hz(void)

@ -0,0 +1,96 @@
--- a/arch/mips/lantiq/xway/reset.c
+++ b/arch/mips/lantiq/xway/reset.c
@@ -44,6 +44,37 @@
#define RCU_BOOT_SEL(x) ((x >> 18) & 0x7)
#define RCU_BOOT_SEL_XRX200(x) (((x >> 17) & 0xf) | ((x >> 8) & 0x10))
+/* dwc2 USB configuration registers */
+#define RCU_USB1CFG 0x0018
+#define RCU_USB2CFG 0x0034
+
+/* USB DMA endianness bits */
+#define RCU_USBCFG_HDSEL_BIT BIT(11)
+#define RCU_USBCFG_HOST_END_BIT BIT(10)
+#define RCU_USBCFG_SLV_END_BIT BIT(9)
+
+/* USB reset bits */
+#define RCU_USBRESET 0x0010
+
+#define USBRESET_BIT BIT(4)
+
+#define RCU_USBRESET2 0x0048
+
+#define USB1RESET_BIT BIT(4)
+#define USB2RESET_BIT BIT(5)
+
+#define RCU_CFG1A 0x0038
+#define RCU_CFG1B 0x003C
+
+/* USB PMU devices */
+#define PMU_AHBM BIT(15)
+#define PMU_USB0 BIT(6)
+#define PMU_USB1 BIT(27)
+
+/* USB PHY PMU devices */
+#define PMU_USB0_P BIT(0)
+#define PMU_USB1_P BIT(26)
+
/* remapped base addr of the reset control unit */
static void __iomem *ltq_rcu_membase;
static struct device_node *ltq_rcu_np;
@@ -200,6 +231,45 @@ static void ltq_machine_power_off(void)
unreachable();
}
+static void ltq_usb_init(void)
+{
+ /* Power for USB cores 1 & 2 */
+ ltq_pmu_enable(PMU_AHBM);
+ ltq_pmu_enable(PMU_USB0);
+ ltq_pmu_enable(PMU_USB1);
+
+ ltq_rcu_w32(ltq_rcu_r32(RCU_CFG1A) | BIT(0), RCU_CFG1A);
+ ltq_rcu_w32(ltq_rcu_r32(RCU_CFG1B) | BIT(0), RCU_CFG1B);
+
+ /* Enable USB PHY power for cores 1 & 2 */
+ ltq_pmu_enable(PMU_USB0_P);
+ ltq_pmu_enable(PMU_USB1_P);
+
+ /* Configure cores to host mode */
+ ltq_rcu_w32(ltq_rcu_r32(RCU_USB1CFG) & ~RCU_USBCFG_HDSEL_BIT,
+ RCU_USB1CFG);
+ ltq_rcu_w32(ltq_rcu_r32(RCU_USB2CFG) & ~RCU_USBCFG_HDSEL_BIT,
+ RCU_USB2CFG);
+
+ /* Select DMA endianness (Host-endian: big-endian) */
+ ltq_rcu_w32((ltq_rcu_r32(RCU_USB1CFG) & ~RCU_USBCFG_SLV_END_BIT)
+ | RCU_USBCFG_HOST_END_BIT, RCU_USB1CFG);
+ ltq_rcu_w32(ltq_rcu_r32((RCU_USB2CFG) & ~RCU_USBCFG_SLV_END_BIT)
+ | RCU_USBCFG_HOST_END_BIT, RCU_USB2CFG);
+
+ /* Hard reset USB state machines */
+ ltq_rcu_w32(ltq_rcu_r32(RCU_USBRESET) | USBRESET_BIT, RCU_USBRESET);
+ udelay(50 * 1000);
+ ltq_rcu_w32(ltq_rcu_r32(RCU_USBRESET) & ~USBRESET_BIT, RCU_USBRESET);
+
+ /* Soft reset USB state machines */
+ ltq_rcu_w32(ltq_rcu_r32(RCU_USBRESET2)
+ | USB1RESET_BIT | USB2RESET_BIT, RCU_USBRESET2);
+ udelay(50 * 1000);
+ ltq_rcu_w32(ltq_rcu_r32(RCU_USBRESET2)
+ & ~(USB1RESET_BIT | USB2RESET_BIT), RCU_USBRESET2);
+}
+
static int __init mips_reboot_setup(void)
{
struct resource res;
@@ -223,6 +293,9 @@ static int __init mips_reboot_setup(void
if (!ltq_rcu_membase)
panic("Failed to remap core memory");
+ if (of_machine_is_compatible("lantiq,vr9"))
+ ltq_usb_init();
+
_machine_restart = ltq_machine_restart;
_machine_halt = ltq_machine_halt;
pm_power_off = ltq_machine_power_off;

@ -0,0 +1,35 @@
--- a/drivers/usb/dwc2/platform.c
+++ b/drivers/usb/dwc2/platform.c
@@ -41,6 +41,7 @@
#include <linux/dma-mapping.h>
#include <linux/of_device.h>
#include <linux/mutex.h>
+#include <linux/of_gpio.h>
#include <linux/platform_device.h>
#include <linux/usb/of.h>
@@ -161,6 +162,7 @@ static int dwc2_driver_probe(struct plat
struct usb_phy *uphy;
int retval;
int irq;
+ int gpio_count;
match = of_match_device(dwc2_of_match_table, &dev->dev);
if (match && match->data) {
@@ -177,6 +179,16 @@ static int dwc2_driver_probe(struct plat
defparams.dma_desc_enable = 0;
}
+ gpio_count = of_gpio_count(dev->dev.of_node);
+ while (gpio_count > 0) {
+ enum of_gpio_flags flags;
+ int gpio = of_get_gpio_flags(dev->dev.of_node, --gpio_count, &flags);
+ if (gpio_request(gpio, "usb"))
+ continue;
+ dev_info(&dev->dev, "requested GPIO %d\n", gpio);
+ gpio_direction_output(gpio, (flags & OF_GPIO_ACTIVE_LOW) ? (0) : (1));
+ }
+
hsotg = devm_kzalloc(&dev->dev, sizeof(*hsotg), GFP_KERNEL);
if (!hsotg)
return -ENOMEM;

@ -0,0 +1,45 @@
--- a/drivers/usb/dwc2/platform.c
+++ b/drivers/usb/dwc2/platform.c
@@ -107,6 +107,34 @@ static const struct dwc2_core_params par
.uframe_sched = -1,
};
+static const struct dwc2_core_params params_ltq = {
+ .otg_cap = -1,
+ .otg_ver = -1,
+ .dma_enable = -1,
+ .dma_desc_enable = -1,
+ .speed = -1,
+ .enable_dynamic_fifo = -1,
+ .en_multiple_tx_fifo = -1,
+ .host_rx_fifo_size = 240, /* 240 DWORDs */
+ .host_nperio_tx_fifo_size = 240, /* 240 DWORDs */
+ .host_perio_tx_fifo_size = 32, /* 32 DWORDs */
+ .max_transfer_size = -1,
+ .max_packet_count = -1,
+ .host_channels = -1,
+ .phy_type = -1,
+ .phy_utmi_width = -1,
+ .phy_ulpi_ddr = -1,
+ .phy_ulpi_ext_vbus = -1,
+ .i2c_enable = -1,
+ .ulpi_fs_ls = -1,
+ .host_support_fs_ls_low_power = -1,
+ .host_ls_low_power_phy_clk = -1,
+ .ts_dline = -1,
+ .reload_ctl = -1,
+ .ahbcfg = -1,
+ .uframe_sched = -1,
+};
+
/**
* dwc2_driver_remove() - Called when the DWC_otg core is unregistered with the
* DWC_otg driver
@@ -133,6 +161,7 @@ static int dwc2_driver_remove(struct pla
static const struct of_device_id dwc2_of_match_table[] = {
{ .compatible = "brcm,bcm2835-usb", .data = &params_bcm2835 },
{ .compatible = "rockchip,rk3066-usb", .data = &params_rk3066 },
+ { .compatible = "lantiq,ifxhcd-xrx200-dwc2", .data = &params_ltq },
{ .compatible = "snps,dwc2", .data = NULL },
{ .compatible = "samsung,s3c6400-hsotg", .data = NULL},
{},

@ -0,0 +1,23 @@
From 08b085a07efe12568d86dff064e6f089e2971744 Mon Sep 17 00:00:00 2001
From: Martin Blumenstingl <martin.blumenstingl@googlemail.com>
Date: Mon, 25 May 2015 22:39:50 +0200
Subject: gpio-stp-xway: Fix enabling the highest bit of the PHY LEDs
0x3 only masks two bits, but three bits have to be allowed. This fixes
GPHY0 LED2 (which is the highest bit of phy2) on my board.
Signed-off-by: Martin Blumenstingl <martin.blumenstingl@googlemail.com>
Acked-by: John Crispin <blogic@openwrt.org>
Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
--- a/drivers/gpio/gpio-stp-xway.c
+++ b/drivers/gpio/gpio-stp-xway.c
@@ -58,7 +58,7 @@
#define XWAY_STP_ADSL_MASK 0x3
/* 2 groups of 3 bits can be driven by the phys */
-#define XWAY_STP_PHY_MASK 0x3
+#define XWAY_STP_PHY_MASK 0x7
#define XWAY_STP_PHY1_SHIFT 27
#define XWAY_STP_PHY2_SHIFT 15

@ -0,0 +1,25 @@
--- a/drivers/net/ethernet/lantiq_xrx200.c
+++ b/drivers/net/ethernet/lantiq_xrx200.c
@@ -143,6 +143,7 @@
#define PMAC_IPG_MASK 0xf
#define PMAC_HD_CTL_AS 0x0008
#define PMAC_HD_CTL_AC 0x0004
+#define PMAC_HD_CTL_RC 0x0010
#define PMAC_HD_CTL_RXSH 0x0040
#define PMAC_HD_CTL_AST 0x0080
#define PMAC_HD_CTL_RST 0x0100
@@ -1502,12 +1503,12 @@ static void xrx200_hw_init(struct xrx200
#ifdef SW_ROUTING
/* enable status header, enable CRC */
ltq_pmac_w32_mask(0,
- PMAC_HD_CTL_RST | PMAC_HD_CTL_AST | PMAC_HD_CTL_RXSH | PMAC_HD_CTL_AS | PMAC_HD_CTL_AC,
+ PMAC_HD_CTL_RST | PMAC_HD_CTL_AST | PMAC_HD_CTL_RXSH | PMAC_HD_CTL_AS | PMAC_HD_CTL_AC | PMAC_HD_CTL_RC,
PMAC_HD_CTL);
#else
/* disable status header, enable CRC */
ltq_pmac_w32_mask(PMAC_HD_CTL_AST | PMAC_HD_CTL_RXSH | PMAC_HD_CTL_AS,
- PMAC_HD_CTL_AC,
+ PMAC_HD_CTL_AC | PMAC_HD_CTL_RC,
PMAC_HD_CTL);
#endif

@ -0,0 +1,192 @@
--- a/arch/mips/lantiq/xway/Makefile
+++ b/arch/mips/lantiq/xway/Makefile
@@ -1,6 +1,6 @@
obj-y := prom.o sysctrl.o clk.o reset.o dma.o timer.o dcdc.o
-obj-y += vmmc.o tffs.o
+obj-y += vmmc.o tffs.o mtd_split.o
obj-y += eth_mac.o
obj-$(CONFIG_PCI) += ath_eep.o rt_eep.o pci-ath-fixup.o
--- /dev/null
+++ b/arch/mips/lantiq/xway/mtd_split.c
@@ -0,0 +1,129 @@
+#include <linux/magic.h>
+#include <linux/root_dev.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/partitions.h>
+
+#define ROOTFS_SPLIT_NAME "rootfs_data"
+
+struct squashfs_super_block {
+ __le32 s_magic;
+ __le32 pad0[9];
+ __le64 bytes_used;
+};
+
+static void split_brnimage_kernel(struct mtd_info *master, const char *name,
+ int offset, int size)
+{
+ unsigned long buf[4];
+ // Assume at most 2MB of kernel image
+ unsigned long end = offset + (2 << 20);
+ unsigned long part_size = offset + 0x400 - 12;
+ size_t len;
+ int ret;
+
+ if (strcmp(name, "firmware") != 0)
+ return;
+ while (part_size < end) {
+ long size_min = part_size - 0x400 - 12 - offset;
+ long size_max = part_size + 12 - offset;
+ ret = mtd_read(master, part_size, 16, &len, (void *)buf);
+ if (ret || len != 16)
+ return;
+
+ if (le32_to_cpu(buf[0]) < size_min ||
+ le32_to_cpu(buf[0]) > size_max) {
+ part_size += 0x400;
+ continue;
+ }
+
+ if (le32_to_cpu(buf[3]) == SQUASHFS_MAGIC) {
+ part_size += 12 - offset;
+ __mtd_add_partition(master, "rootfs", offset + part_size,
+ size - part_size, false);
+ return;
+ }
+ part_size += 0x400;
+ }
+}
+
+static void split_eva_kernel(struct mtd_info *master, const char *name,
+ int offset, int size)
+{
+#define EVA_MAGIC 0xfeed1281
+ unsigned long magic = 0;
+ unsigned long part_size = 0, p;
+ size_t len;
+ int ret;
+
+ if (strcmp(name, CONFIG_MTD_SPLIT_FIRMWARE_NAME) != 0)
+ return;
+
+ ret = mtd_read(master, offset, 4, &len, (void *)&magic);
+ if (ret || len != sizeof(magic))
+ return;
+
+ if (le32_to_cpu(magic) != EVA_MAGIC)
+ return;
+
+ ret = mtd_read(master, offset + 4, 4, &len, (void *)&part_size);
+ if (ret || len != sizeof(part_size))
+ return;
+
+ p = part_size = le32_to_cpu(part_size) + 0x18;
+ p &= ~0xffff;
+ p += 0x10000;
+
+ ret = mtd_read(master, offset + p, 4, &len, (void *)&magic);
+ if (ret || len != sizeof(magic))
+ return;
+
+ if (magic == SQUASHFS_MAGIC)
+ part_size = p + 0x100;
+ else
+ part_size = mtd_pad_erasesize(master, offset, len);
+
+ if (part_size + master->erasesize > size)
+ return;
+
+ __mtd_add_partition(master, "rootfs", offset + part_size,
+ size - part_size, false);
+}
+
+static void split_tplink_kernel(struct mtd_info *master, const char *name,
+ int offset, int size)
+{
+#define TPLINK_MAGIC 0x00000002
+ unsigned long magic = 0;
+ unsigned long part_size = 0;
+ size_t len;
+ int ret;
+
+ if (strcmp(name, CONFIG_MTD_SPLIT_FIRMWARE_NAME) != 0)
+ return;
+
+ ret = mtd_read(master, offset, 4, &len, (void *)&magic);
+ if (ret || len != sizeof(magic))
+ return;
+
+ if (le32_to_cpu(magic) != TPLINK_MAGIC)
+ return;
+
+ ret = mtd_read(master, offset + 0x78, 4, &len, (void *)&part_size);
+ if (ret || len != sizeof(part_size))
+ return;
+
+ part_size = be32_to_cpu(part_size) + 0x200;
+ if (part_size + master->erasesize > size)
+ return;
+
+ __mtd_add_partition(master, "rootfs", offset + part_size,
+ size - part_size, false);
+}
+
+void arch_split_mtd_part(struct mtd_info *master, const char *name,
+ int offset, int size)
+{
+ split_tplink_kernel(master, name, offset, size);
+ split_eva_kernel(master, name, offset, size);
+ split_brnimage_kernel(master, name, offset, size);
+}
--- a/include/linux/mtd/partitions.h
+++ b/include/linux/mtd/partitions.h
@@ -89,12 +89,17 @@ extern void deregister_mtd_parser(struct
int mtd_is_partition(const struct mtd_info *mtd);
int mtd_add_partition(struct mtd_info *master, const char *name,
long long offset, long long length);
+int __mtd_add_partition(struct mtd_info *master, const char *name,
+ long long offset, long long length, bool dup_check);
+
int mtd_del_partition(struct mtd_info *master, int partno);
struct mtd_info *mtdpart_get_master(const struct mtd_info *mtd);
uint64_t mtdpart_get_offset(const struct mtd_info *mtd);
uint64_t mtd_get_device_size(const struct mtd_info *mtd);
-extern void __weak arch_split_mtd_part(struct mtd_info *master,
- const char *name, int offset, int size);
+void __weak arch_split_mtd_part(struct mtd_info *master,
+ const char *name, int offset, int size);
+unsigned long
+mtd_pad_erasesize(struct mtd_info *mtd, int offset, int len);
int parse_mtd_partitions_by_type(struct mtd_info *master,
enum mtd_parser_type type,
--- a/drivers/mtd/mtdpart.c
+++ b/drivers/mtd/mtdpart.c
@@ -658,7 +658,7 @@ static int mtd_add_partition_attrs(struc
}
-static int
+int
__mtd_add_partition(struct mtd_info *master, const char *name,
long long offset, long long length, bool dup_check)
{
@@ -762,7 +762,7 @@ run_parsers_by_type(struct mtd_part *sla
return nr_parts;
}
-static inline unsigned long
+unsigned long
mtd_pad_erasesize(struct mtd_info *mtd, int offset, int len)
{
unsigned long mask = mtd->erasesize - 1;
@@ -832,7 +832,6 @@ static void split_uimage(struct mtd_info
return;
len = be32_to_cpu(hdr.size) + 0x40;
- len = mtd_pad_erasesize(master, part->offset, len);
if (len + master->erasesize > part->mtd.size)
return;

@ -0,0 +1,15 @@
--- a/drivers/pinctrl/pinctrl-xway.c
+++ b/drivers/pinctrl/pinctrl-xway.c
@@ -152,10 +152,10 @@ static const struct ltq_mfp_pin xway_mfp
MFP_XWAY(GPIO41, GPIO, NONE, NONE, NONE),
MFP_XWAY(GPIO42, GPIO, MDIO, NONE, NONE),
MFP_XWAY(GPIO43, GPIO, MDIO, NONE, NONE),
- MFP_XWAY(GPIO44, GPIO, NONE, GPHY, SIN),
+ MFP_XWAY(GPIO44, GPIO, MII, SIN, GPHY),
MFP_XWAY(GPIO45, GPIO, NONE, GPHY, SIN),
MFP_XWAY(GPIO46, GPIO, NONE, NONE, EXIN),
- MFP_XWAY(GPIO47, GPIO, NONE, GPHY, SIN),
+ MFP_XWAY(GPIO47, GPIO, MII, GPHY, SIN),
MFP_XWAY(GPIO48, GPIO, EBU, NONE, NONE),
MFP_XWAY(GPIO49, GPIO, EBU, NONE, NONE),
MFP_XWAY(GPIO50, GPIO, NONE, NONE, NONE),

@ -0,0 +1,51 @@
--- a/arch/mips/pci/ifxmips_pcie.c
+++ b/arch/mips/pci/ifxmips_pcie.c
@@ -18,6 +18,8 @@
#include <linux/pci_regs.h>
#include <linux/module.h>
+#include <linux/of_platform.h>
+
#include "ifxmips_pcie.h"
#include "ifxmips_pcie_reg.h"
@@ -1045,7 +1047,7 @@ pcie_rc_initialize(int pcie_port)
return 0;
}
-static int __init ifx_pcie_bios_init(void)
+static int __init ifx_pcie_bios_probe(struct platform_device *pdev)
{
void __iomem *io_map_base;
int pcie_port;
@@ -1083,6 +1085,30 @@ static int __init ifx_pcie_bios_init(voi
return 0;
}
+
+static const struct of_device_id ifxmips_pcie_match[] = {
+ { .compatible = "lantiq,pcie-xrx200" },
+ {},
+};
+MODULE_DEVICE_TABLE(of, ifxmips_pcie_match);
+
+static struct platform_driver ltq_pci_driver = {
+ .probe = ifx_pcie_bios_probe,
+ .driver = {
+ .name = "pcie-xrx200",
+ .owner = THIS_MODULE,
+ .of_match_table = ifxmips_pcie_match,
+ },
+};
+
+int __init ifx_pcie_bios_init(void)
+{
+ int ret = platform_driver_register(&ltq_pci_driver);
+ if (ret)
+ pr_info("pcie-xrx200: Error registering platform driver!");
+ return ret;
+}
+
arch_initcall(ifx_pcie_bios_init);
MODULE_LICENSE("GPL");

@ -0,0 +1,217 @@
--- a/drivers/mtd/maps/lantiq-flash.c
+++ b/drivers/mtd/maps/lantiq-flash.c
@@ -19,6 +19,7 @@
#include <linux/mtd/cfi.h>
#include <linux/platform_device.h>
#include <linux/mtd/physmap.h>
+#include <linux/mtd/concat.h>
#include <linux/of.h>
#include <lantiq_soc.h>
@@ -38,10 +39,12 @@ enum {
LTQ_NOR_NORMAL
};
+#define MAX_RESOURCES 4
+
struct ltq_mtd {
- struct resource *res;
- struct mtd_info *mtd;
- struct map_info *map;
+ struct mtd_info *mtd[MAX_RESOURCES];
+ struct mtd_info *cmtd;
+ struct map_info map[MAX_RESOURCES];
};
static const char ltq_map_name[] = "ltq_nor";
@@ -109,12 +112,44 @@ ltq_copy_to(struct map_info *map, unsign
}
static int
+ltq_mtd_remove(struct platform_device *pdev)
+{
+ struct ltq_mtd *ltq_mtd = platform_get_drvdata(pdev);
+ int i;
+
+ if (ltq_mtd == NULL)
+ return 0;
+
+ if (ltq_mtd->cmtd) {
+ mtd_device_unregister(ltq_mtd->cmtd);
+ if (ltq_mtd->cmtd != ltq_mtd->mtd[0])
+ mtd_concat_destroy(ltq_mtd->cmtd);
+ }
+
+ for (i = 0; i < MAX_RESOURCES; i++) {
+ if (ltq_mtd->mtd[i] != NULL)
+ map_destroy(ltq_mtd->mtd[i]);
+ }
+
+ kfree(ltq_mtd);
+
+ return 0;
+}
+
+static int
ltq_mtd_probe(struct platform_device *pdev)
{
struct mtd_part_parser_data ppdata;
struct ltq_mtd *ltq_mtd;
struct cfi_private *cfi;
- int err;
+ int err = 0;
+ int i;
+ int devices_found = 0;
+
+ static const char *rom_probe_types[] = {
+ "cfi_probe", "jedec_probe", NULL
+ };
+ const char **type;
if (of_machine_is_compatible("lantiq,falcon") &&
(ltq_boot_select() != BS_FLASH)) {
@@ -128,76 +163,88 @@ ltq_mtd_probe(struct platform_device *pd
platform_set_drvdata(pdev, ltq_mtd);
- ltq_mtd->res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!ltq_mtd->res) {
- dev_err(&pdev->dev, "failed to get memory resource\n");
- return -ENOENT;
+ for (i = 0; i < pdev->num_resources; i++) {
+ printk(KERN_NOTICE "lantiq nor flash device: %.8llx at %.8llx\n",
+ (unsigned long long)resource_size(&pdev->resource[i]),
+ (unsigned long long)pdev->resource[i].start);
+
+ if (!devm_request_mem_region(&pdev->dev,
+ pdev->resource[i].start,
+ resource_size(&pdev->resource[i]),
+ dev_name(&pdev->dev))) {
+ dev_err(&pdev->dev, "Could not reserve memory region\n");
+ return -ENOMEM;
+ }
+
+ ltq_mtd->map[i].name = ltq_map_name;
+ ltq_mtd->map[i].bankwidth = 2;
+ ltq_mtd->map[i].read = ltq_read16;
+ ltq_mtd->map[i].write = ltq_write16;
+ ltq_mtd->map[i].copy_from = ltq_copy_from;
+ ltq_mtd->map[i].copy_to = ltq_copy_to;
+
+ if (of_find_property(pdev->dev.of_node, "lantiq,noxip", NULL))
+ ltq_mtd->map[i].phys = NO_XIP;
+ else
+ ltq_mtd->map[i].phys = pdev->resource[i].start;
+ ltq_mtd->map[i].size = resource_size(&pdev->resource[i]);
+ ltq_mtd->map[i].virt = devm_ioremap(&pdev->dev, pdev->resource[i].start,
+ ltq_mtd->map[i].size);
+ if (IS_ERR(ltq_mtd->map[i].virt))
+ return PTR_ERR(ltq_mtd->map[i].virt);
+
+ if (ltq_mtd->map[i].virt == NULL) {
+ dev_err(&pdev->dev, "Failed to ioremap flash region\n");
+ err = PTR_ERR(ltq_mtd->map[i].virt);
+ goto err_out;
+ }
+
+ ltq_mtd->map[i].map_priv_1 = LTQ_NOR_PROBING;
+ for (type = rom_probe_types; !ltq_mtd->mtd[i] && *type; type++)
+ ltq_mtd->mtd[i] = do_map_probe(*type, &ltq_mtd->map[i]);
+ ltq_mtd->map[i].map_priv_1 = LTQ_NOR_NORMAL;
+
+ if (!ltq_mtd->mtd[i]) {
+ dev_err(&pdev->dev, "probing failed\n");
+ return -ENXIO;
+ } else {
+ devices_found++;
+ }
+
+ ltq_mtd->mtd[i]->owner = THIS_MODULE;
+ ltq_mtd->mtd[i]->dev.parent = &pdev->dev;
+
+ cfi = ltq_mtd->map[i].fldrv_priv;
+ cfi->addr_unlock1 ^= 1;
+ cfi->addr_unlock2 ^= 1;
}
- ltq_mtd->map = devm_kzalloc(&pdev->dev, sizeof(struct map_info),
- GFP_KERNEL);
- if (!ltq_mtd->map)
- return -ENOMEM;
-
- if (of_find_property(pdev->dev.of_node, "lantiq,noxip", NULL))
- ltq_mtd->map->phys = NO_XIP;
- else
- ltq_mtd->map->phys = ltq_mtd->res->start;
- ltq_mtd->res->start;
- ltq_mtd->map->size = resource_size(ltq_mtd->res);
- ltq_mtd->map->virt = devm_ioremap_resource(&pdev->dev, ltq_mtd->res);
- if (IS_ERR(ltq_mtd->map->virt))
- return PTR_ERR(ltq_mtd->map->virt);
-
- ltq_mtd->map->name = ltq_map_name;
- ltq_mtd->map->bankwidth = 2;
- ltq_mtd->map->read = ltq_read16;
- ltq_mtd->map->write = ltq_write16;
- ltq_mtd->map->copy_from = ltq_copy_from;
- ltq_mtd->map->copy_to = ltq_copy_to;
-
- ltq_mtd->map->map_priv_1 = LTQ_NOR_PROBING;
- ltq_mtd->mtd = do_map_probe("cfi_probe", ltq_mtd->map);
- ltq_mtd->map->map_priv_1 = LTQ_NOR_NORMAL;
-
- if (!ltq_mtd->mtd) {
- dev_err(&pdev->dev, "probing failed\n");
- return -ENXIO;
- }
-
- ltq_mtd->mtd->owner = THIS_MODULE;
-
- cfi = ltq_mtd->map->fldrv_priv;
- cfi->addr_unlock1 ^= 1;
- cfi->addr_unlock2 ^= 1;
+ if (devices_found == 1) {
+ ltq_mtd->cmtd = ltq_mtd->mtd[0];
+ } else if (devices_found > 1) {
+ /*
+ * We detected multiple devices. Concatenate them together.
+ */
+ ltq_mtd->cmtd = mtd_concat_create(ltq_mtd->mtd, devices_found, dev_name(&pdev->dev));
+ if (ltq_mtd->cmtd == NULL)
+ err = -ENXIO;
+ }
ppdata.of_node = pdev->dev.of_node;
- err = mtd_device_parse_register(ltq_mtd->mtd, ltq_probe_types,
+ err = mtd_device_parse_register(ltq_mtd->cmtd, ltq_probe_types,
&ppdata, NULL, 0);
if (err) {
dev_err(&pdev->dev, "failed to add partitions\n");
- goto err_destroy;
+ goto err_out;
}
return 0;
-err_destroy:
- map_destroy(ltq_mtd->mtd);
+err_out:
+ ltq_mtd_remove(pdev);
return err;
}
-static int
-ltq_mtd_remove(struct platform_device *pdev)
-{
- struct ltq_mtd *ltq_mtd = platform_get_drvdata(pdev);
-
- if (ltq_mtd && ltq_mtd->mtd) {
- mtd_device_unregister(ltq_mtd->mtd);
- map_destroy(ltq_mtd->mtd);
- }
- return 0;
-}
-
static const struct of_device_id ltq_mtd_match[] = {
{ .compatible = "lantiq,nor" },
{},

@ -0,0 +1,11 @@
--- a/drivers/mtd/chips/cfi_cmdset_0001.c
+++ b/drivers/mtd/chips/cfi_cmdset_0001.c
@@ -39,7 +39,7 @@
/* #define CMDSET0001_DISABLE_WRITE_SUSPEND */
// debugging, turns off buffer write mode if set to 1
-#define FORCE_WORD_WRITE 0
+#define FORCE_WORD_WRITE 1
/* Intel chips */
#define I82802AB 0x00ad
Loading…
Cancel
Save