ramips: copy patches and kernel config to 5.4
Copy patches and kernel config to 5.4 for ramips Signed-off-by: DENG Qingfang <dengqf6@mail2.sysu.edu.cn>
This commit is contained in:
		 DENG Qingfang
					DENG Qingfang
				
			
				
					committed by
					
						 Chuanhong Guo
						Chuanhong Guo
					
				
			
			
				
	
			
			
			 Chuanhong Guo
						Chuanhong Guo
					
				
			
						parent
						
							b51ea43f90
						
					
				
				
					commit
					c70545f397
				
			
							
								
								
									
										315
									
								
								target/linux/ramips/mt7621/config-5.4
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										315
									
								
								target/linux/ramips/mt7621/config-5.4
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,315 @@ | |||||||
|  | CONFIG_ARCH_BINFMT_ELF_STATE=y | ||||||
|  | CONFIG_ARCH_CLOCKSOURCE_DATA=y | ||||||
|  | CONFIG_ARCH_DISCARD_MEMBLOCK=y | ||||||
|  | CONFIG_ARCH_HAS_ELF_RANDOMIZE=y | ||||||
|  | # CONFIG_ARCH_HAS_GCOV_PROFILE_ALL is not set | ||||||
|  | CONFIG_ARCH_HAS_RESET_CONTROLLER=y | ||||||
|  | # CONFIG_ARCH_HAS_SG_CHAIN is not set | ||||||
|  | # CONFIG_ARCH_HAS_STRICT_KERNEL_RWX is not set | ||||||
|  | # CONFIG_ARCH_HAS_STRICT_MODULE_RWX is not set | ||||||
|  | CONFIG_ARCH_HAS_TICK_BROADCAST=y | ||||||
|  | CONFIG_ARCH_HIBERNATION_POSSIBLE=y | ||||||
|  | CONFIG_ARCH_MIGHT_HAVE_PC_PARPORT=y | ||||||
|  | CONFIG_ARCH_MIGHT_HAVE_PC_SERIO=y | ||||||
|  | CONFIG_ARCH_MMAP_RND_BITS_MAX=15 | ||||||
|  | CONFIG_ARCH_MMAP_RND_COMPAT_BITS_MAX=15 | ||||||
|  | # CONFIG_ARCH_OPTIONAL_KERNEL_RWX is not set | ||||||
|  | # CONFIG_ARCH_OPTIONAL_KERNEL_RWX_DEFAULT is not set | ||||||
|  | CONFIG_ARCH_SUPPORTS_UPROBES=y | ||||||
|  | CONFIG_ARCH_SUSPEND_POSSIBLE=y | ||||||
|  | CONFIG_ARCH_USE_BUILTIN_BSWAP=y | ||||||
|  | CONFIG_ARCH_USE_QUEUED_RWLOCKS=y | ||||||
|  | CONFIG_ARCH_USE_QUEUED_SPINLOCKS=y | ||||||
|  | CONFIG_ARCH_WANT_IPC_PARSE_VERSION=y | ||||||
|  | CONFIG_BLK_MQ_PCI=y | ||||||
|  | CONFIG_BOARD_SCACHE=y | ||||||
|  | CONFIG_BOUNCE=y | ||||||
|  | CONFIG_CEVT_R4K=y | ||||||
|  | # CONFIG_CEVT_SYSTICK_QUIRK is not set | ||||||
|  | CONFIG_CLKDEV_LOOKUP=y | ||||||
|  | CONFIG_CLKSRC_MIPS_GIC=y | ||||||
|  | CONFIG_CLONE_BACKWARDS=y | ||||||
|  | CONFIG_CMDLINE="rootfstype=squashfs,jffs2" | ||||||
|  | CONFIG_CMDLINE_BOOL=y | ||||||
|  | # CONFIG_CMDLINE_OVERRIDE is not set | ||||||
|  | CONFIG_COMMON_CLK=y | ||||||
|  | # CONFIG_COMMON_CLK_BOSTON is not set | ||||||
|  | CONFIG_CPU_GENERIC_DUMP_TLB=y | ||||||
|  | CONFIG_CPU_HAS_PREFETCH=y | ||||||
|  | CONFIG_CPU_HAS_RIXI=y | ||||||
|  | CONFIG_CPU_HAS_SYNC=y | ||||||
|  | CONFIG_CPU_LITTLE_ENDIAN=y | ||||||
|  | CONFIG_CPU_MIPS32=y | ||||||
|  | # CONFIG_CPU_MIPS32_R1 is not set | ||||||
|  | CONFIG_CPU_MIPS32_R2=y | ||||||
|  | CONFIG_CPU_MIPSR2=y | ||||||
|  | CONFIG_CPU_MIPSR2_IRQ_EI=y | ||||||
|  | CONFIG_CPU_MIPSR2_IRQ_VI=y | ||||||
|  | CONFIG_CPU_NEEDS_NO_SMARTMIPS_OR_MICROMIPS=y | ||||||
|  | CONFIG_CPU_R4K_CACHE_TLB=y | ||||||
|  | CONFIG_CPU_R4K_FPU=y | ||||||
|  | CONFIG_CPU_RMAP=y | ||||||
|  | CONFIG_CPU_SUPPORTS_32BIT_KERNEL=y | ||||||
|  | CONFIG_CPU_SUPPORTS_HIGHMEM=y | ||||||
|  | CONFIG_CPU_SUPPORTS_MSA=y | ||||||
|  | CONFIG_CRC16=y | ||||||
|  | CONFIG_CRYPTO_ACOMP2=y | ||||||
|  | CONFIG_CRYPTO_AEAD=y | ||||||
|  | CONFIG_CRYPTO_AEAD2=y | ||||||
|  | CONFIG_CRYPTO_DEFLATE=y | ||||||
|  | CONFIG_CRYPTO_HASH2=y | ||||||
|  | CONFIG_CRYPTO_LZO=y | ||||||
|  | CONFIG_CRYPTO_MANAGER=y | ||||||
|  | CONFIG_CRYPTO_MANAGER2=y | ||||||
|  | CONFIG_CRYPTO_NULL2=y | ||||||
|  | CONFIG_CRYPTO_RNG2=y | ||||||
|  | CONFIG_CRYPTO_WORKQUEUE=y | ||||||
|  | CONFIG_CSRC_R4K=y | ||||||
|  | CONFIG_DEBUG_PINCTRL=y | ||||||
|  | CONFIG_DMA_NONCOHERENT=y | ||||||
|  | CONFIG_DTB_RT_NONE=y | ||||||
|  | CONFIG_DTC=y | ||||||
|  | CONFIG_EARLY_PRINTK=y | ||||||
|  | CONFIG_FIXED_PHY=y | ||||||
|  | CONFIG_GENERIC_ATOMIC64=y | ||||||
|  | CONFIG_GENERIC_CLOCKEVENTS=y | ||||||
|  | CONFIG_GENERIC_CLOCKEVENTS_BROADCAST=y | ||||||
|  | CONFIG_GENERIC_CMOS_UPDATE=y | ||||||
|  | CONFIG_GENERIC_CPU_AUTOPROBE=y | ||||||
|  | CONFIG_GENERIC_IO=y | ||||||
|  | CONFIG_GENERIC_IRQ_CHIP=y | ||||||
|  | CONFIG_GENERIC_IRQ_EFFECTIVE_AFF_MASK=y | ||||||
|  | CONFIG_GENERIC_IRQ_IPI=y | ||||||
|  | CONFIG_GENERIC_IRQ_SHOW=y | ||||||
|  | CONFIG_GENERIC_PCI_IOMAP=y | ||||||
|  | CONFIG_GENERIC_SCHED_CLOCK=y | ||||||
|  | CONFIG_GENERIC_SMP_IDLE_THREAD=y | ||||||
|  | CONFIG_GENERIC_TIME_VSYSCALL=y | ||||||
|  | CONFIG_GPIOLIB=y | ||||||
|  | CONFIG_GPIO_MT7621=y | ||||||
|  | # CONFIG_GPIO_RALINK is not set | ||||||
|  | CONFIG_GPIO_SYSFS=y | ||||||
|  | CONFIG_GPIO_WATCHDOG=y | ||||||
|  | # CONFIG_GPIO_WATCHDOG_ARCH_INITCALL is not set | ||||||
|  | # CONFIG_GRO_CELLS is not set | ||||||
|  | CONFIG_HANDLE_DOMAIN_IRQ=y | ||||||
|  | CONFIG_HARDWARE_WATCHPOINTS=y | ||||||
|  | CONFIG_HAS_DMA=y | ||||||
|  | CONFIG_HAS_IOMEM=y | ||||||
|  | CONFIG_HAS_IOPORT_MAP=y | ||||||
|  | # CONFIG_HAVE_64BIT_ALIGNED_ACCESS is not set | ||||||
|  | # CONFIG_HAVE_ARCH_BITREVERSE is not set | ||||||
|  | CONFIG_HAVE_ARCH_COMPILER_H=y | ||||||
|  | CONFIG_HAVE_ARCH_JUMP_LABEL=y | ||||||
|  | CONFIG_HAVE_ARCH_KGDB=y | ||||||
|  | CONFIG_HAVE_ARCH_SECCOMP_FILTER=y | ||||||
|  | CONFIG_HAVE_ARCH_TRACEHOOK=y | ||||||
|  | # CONFIG_HAVE_BOOTMEM_INFO_NODE is not set | ||||||
|  | CONFIG_HAVE_CBPF_JIT=y | ||||||
|  | CONFIG_HAVE_CC_STACKPROTECTOR=y | ||||||
|  | CONFIG_HAVE_CLK=y | ||||||
|  | CONFIG_HAVE_CLK_PREPARE=y | ||||||
|  | CONFIG_HAVE_CONTEXT_TRACKING=y | ||||||
|  | CONFIG_HAVE_COPY_THREAD_TLS=y | ||||||
|  | CONFIG_HAVE_C_RECORDMCOUNT=y | ||||||
|  | CONFIG_HAVE_DEBUG_KMEMLEAK=y | ||||||
|  | CONFIG_HAVE_DEBUG_STACKOVERFLOW=y | ||||||
|  | CONFIG_HAVE_DMA_API_DEBUG=y | ||||||
|  | CONFIG_HAVE_DMA_CONTIGUOUS=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_GENERIC_DMA_COHERENT=y | ||||||
|  | CONFIG_HAVE_IDE=y | ||||||
|  | CONFIG_HAVE_IRQ_EXIT_ON_IRQ_STACK=y | ||||||
|  | CONFIG_HAVE_IRQ_TIME_ACCOUNTING=y | ||||||
|  | CONFIG_HAVE_KVM=y | ||||||
|  | CONFIG_HAVE_LATENCYTOP_SUPPORT=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_HAVE_REGS_AND_STACK_ACCESS_API=y | ||||||
|  | CONFIG_HAVE_SYSCALL_TRACEPOINTS=y | ||||||
|  | CONFIG_HIGHMEM=y | ||||||
|  | CONFIG_HW_HAS_PCI=y | ||||||
|  | CONFIG_HZ_PERIODIC=y | ||||||
|  | CONFIG_I2C=y | ||||||
|  | CONFIG_I2C_BOARDINFO=y | ||||||
|  | CONFIG_I2C_MT7621=y | ||||||
|  | CONFIG_INITRAMFS_SOURCE="" | ||||||
|  | CONFIG_IRQCHIP=y | ||||||
|  | CONFIG_IRQ_DOMAIN=y | ||||||
|  | CONFIG_IRQ_DOMAIN_HIERARCHY=y | ||||||
|  | CONFIG_IRQ_FORCED_THREADING=y | ||||||
|  | CONFIG_IRQ_MIPS_CPU=y | ||||||
|  | CONFIG_IRQ_WORK=y | ||||||
|  | CONFIG_LIBFDT=y | ||||||
|  | CONFIG_LZO_COMPRESS=y | ||||||
|  | CONFIG_LZO_DECOMPRESS=y | ||||||
|  | CONFIG_MDIO_BUS=y | ||||||
|  | CONFIG_MDIO_DEVICE=y | ||||||
|  | CONFIG_MIGRATION=y | ||||||
|  | CONFIG_MIPS=y | ||||||
|  | CONFIG_MIPS_ASID_BITS=8 | ||||||
|  | CONFIG_MIPS_ASID_SHIFT=0 | ||||||
|  | CONFIG_MIPS_CBPF_JIT=y | ||||||
|  | CONFIG_MIPS_CLOCK_VSYSCALL=y | ||||||
|  | CONFIG_MIPS_CM=y | ||||||
|  | # CONFIG_MIPS_CMDLINE_BUILTIN_EXTEND is not set | ||||||
|  | # CONFIG_MIPS_CMDLINE_DTB_EXTEND is not set | ||||||
|  | # CONFIG_MIPS_CMDLINE_FROM_BOOTLOADER is not set | ||||||
|  | CONFIG_MIPS_CMDLINE_FROM_DTB=y | ||||||
|  | CONFIG_MIPS_CPC=y | ||||||
|  | CONFIG_MIPS_CPS=y | ||||||
|  | # CONFIG_MIPS_CPS_NS16550 is not set | ||||||
|  | CONFIG_MIPS_CPU_SCACHE=y | ||||||
|  | # CONFIG_MIPS_ELF_APPENDED_DTB is not set | ||||||
|  | CONFIG_MIPS_GIC=y | ||||||
|  | # CONFIG_MIPS_HUGE_TLB_SUPPORT is not set | ||||||
|  | CONFIG_MIPS_L1_CACHE_SHIFT=5 | ||||||
|  | # CONFIG_MIPS_MACHINE is not set | ||||||
|  | CONFIG_MIPS_MT=y | ||||||
|  | CONFIG_MIPS_MT_FPAFF=y | ||||||
|  | CONFIG_MIPS_MT_SMP=y | ||||||
|  | # CONFIG_MIPS_NO_APPENDED_DTB is not set | ||||||
|  | CONFIG_MIPS_PERF_SHARED_TC_COUNTERS=y | ||||||
|  | CONFIG_MIPS_RAW_APPENDED_DTB=y | ||||||
|  | CONFIG_MIPS_SPRAM=y | ||||||
|  | # CONFIG_MIPS_VPE_LOADER is not set | ||||||
|  | CONFIG_MODULES_USE_ELF_REL=y | ||||||
|  | CONFIG_MT7621_WDT=y | ||||||
|  | # CONFIG_MTD_CFI_INTELEXT is not set | ||||||
|  | CONFIG_MTD_CMDLINE_PARTS=y | ||||||
|  | CONFIG_MTD_M25P80=y | ||||||
|  | CONFIG_MTD_NAND=y | ||||||
|  | CONFIG_MTD_NAND_ECC=y | ||||||
|  | CONFIG_MTD_PHYSMAP=y | ||||||
|  | CONFIG_MTD_SPI_NOR=y | ||||||
|  | CONFIG_MTD_SPLIT_MINOR_FW=y | ||||||
|  | CONFIG_MTD_SPLIT_SEAMA_FW=y | ||||||
|  | CONFIG_MTD_SPLIT_TPLINK_FW=y | ||||||
|  | CONFIG_MTD_SPLIT_TRX_FW=y | ||||||
|  | CONFIG_MTD_SPLIT_UIMAGE_FW=y | ||||||
|  | CONFIG_MTD_UBI=y | ||||||
|  | CONFIG_MTD_UBI_BEB_LIMIT=20 | ||||||
|  | CONFIG_MTD_UBI_BLOCK=y | ||||||
|  | # CONFIG_MTD_UBI_FASTMAP is not set | ||||||
|  | # CONFIG_MTD_UBI_GLUEBI is not set | ||||||
|  | CONFIG_MTD_UBI_WL_THRESHOLD=4096 | ||||||
|  | CONFIG_MTK_MTD_NAND=y | ||||||
|  | CONFIG_NEED_DMA_MAP_STATE=y | ||||||
|  | CONFIG_NET_FLOW_LIMIT=y | ||||||
|  | CONFIG_NET_MEDIATEK_GSW_MT7621=y | ||||||
|  | CONFIG_NET_MEDIATEK_MDIO=y | ||||||
|  | CONFIG_NET_MEDIATEK_MDIO_MT7620=y | ||||||
|  | CONFIG_NET_MEDIATEK_MT7621=y | ||||||
|  | CONFIG_NET_MEDIATEK_OFFLOAD=y | ||||||
|  | CONFIG_NET_MEDIATEK_SOC=y | ||||||
|  | CONFIG_NET_VENDOR_MEDIATEK=y | ||||||
|  | CONFIG_NO_GENERIC_PCI_IOPORT_MAP=y | ||||||
|  | # CONFIG_NO_IOPORT_MAP is not set | ||||||
|  | CONFIG_NR_CPUS=4 | ||||||
|  | CONFIG_OF=y | ||||||
|  | CONFIG_OF_ADDRESS=y | ||||||
|  | CONFIG_OF_ADDRESS_PCI=y | ||||||
|  | CONFIG_OF_EARLY_FLATTREE=y | ||||||
|  | CONFIG_OF_FLATTREE=y | ||||||
|  | CONFIG_OF_GPIO=y | ||||||
|  | CONFIG_OF_IRQ=y | ||||||
|  | CONFIG_OF_MDIO=y | ||||||
|  | CONFIG_OF_NET=y | ||||||
|  | CONFIG_OF_PCI=y | ||||||
|  | CONFIG_OF_PCI_IRQ=y | ||||||
|  | CONFIG_PADATA=y | ||||||
|  | CONFIG_PCI=y | ||||||
|  | CONFIG_PCI_DISABLE_COMMON_QUIRKS=y | ||||||
|  | CONFIG_PCI_DOMAINS=y | ||||||
|  | CONFIG_PCI_DRIVERS_LEGACY=y | ||||||
|  | CONFIG_PERF_USE_VMALLOC=y | ||||||
|  | CONFIG_PGTABLE_LEVELS=2 | ||||||
|  | CONFIG_PHYLIB=y | ||||||
|  | # CONFIG_PHY_RALINK_USB is not set | ||||||
|  | CONFIG_PINCTRL=y | ||||||
|  | CONFIG_PINCTRL_RT2880=y | ||||||
|  | # CONFIG_PINCTRL_SINGLE is not set | ||||||
|  | CONFIG_POWER_RESET=y | ||||||
|  | CONFIG_POWER_RESET_GPIO=y | ||||||
|  | CONFIG_POWER_SUPPLY=y | ||||||
|  | CONFIG_QUEUED_RWLOCKS=y | ||||||
|  | CONFIG_QUEUED_SPINLOCKS=y | ||||||
|  | CONFIG_RALINK=y | ||||||
|  | # CONFIG_RALINK_WDT is not set | ||||||
|  | CONFIG_RATIONAL=y | ||||||
|  | CONFIG_RCU_NEED_SEGCBLIST=y | ||||||
|  | CONFIG_RCU_STALL_COMMON=y | ||||||
|  | CONFIG_REGMAP=y | ||||||
|  | CONFIG_REGMAP_I2C=y | ||||||
|  | CONFIG_REGMAP_SPI=y | ||||||
|  | CONFIG_REGULATOR=y | ||||||
|  | CONFIG_REGULATOR_FIXED_VOLTAGE=y | ||||||
|  | CONFIG_RESET_CONTROLLER=y | ||||||
|  | CONFIG_RFS_ACCEL=y | ||||||
|  | CONFIG_RPS=y | ||||||
|  | CONFIG_RTC_CLASS=y | ||||||
|  | CONFIG_RTC_DRV_BQ32K=y | ||||||
|  | CONFIG_RTC_DRV_PCF8563=y | ||||||
|  | CONFIG_RTC_I2C_AND_SPI=y | ||||||
|  | CONFIG_RTC_MC146818_LIB=y | ||||||
|  | # CONFIG_SCHED_INFO is not set | ||||||
|  | CONFIG_SCHED_SMT=y | ||||||
|  | # CONFIG_SCSI_DMA is not set | ||||||
|  | # CONFIG_SERIAL_8250_FSL is not set | ||||||
|  | CONFIG_SERIAL_8250_NR_UARTS=3 | ||||||
|  | CONFIG_SERIAL_8250_RUNTIME_UARTS=3 | ||||||
|  | CONFIG_SERIAL_OF_PLATFORM=y | ||||||
|  | CONFIG_SMP=y | ||||||
|  | CONFIG_SMP_UP=y | ||||||
|  | # CONFIG_SOC_MT7620 is not set | ||||||
|  | CONFIG_SOC_MT7621=y | ||||||
|  | # CONFIG_SOC_RT288X is not set | ||||||
|  | # CONFIG_SOC_RT305X is not set | ||||||
|  | # CONFIG_SOC_RT3883 is not set | ||||||
|  | CONFIG_SPI=y | ||||||
|  | CONFIG_SPI_MASTER=y | ||||||
|  | CONFIG_SPI_MT7621=y | ||||||
|  | # CONFIG_SPI_RT2880 is not set | ||||||
|  | CONFIG_SRCU=y | ||||||
|  | CONFIG_SWCONFIG=y | ||||||
|  | CONFIG_SWCONFIG_LEDS=y | ||||||
|  | CONFIG_SWPHY=y | ||||||
|  | CONFIG_SYNC_R4K=y | ||||||
|  | CONFIG_SYSCTL_EXCEPTION_TRACE=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_HIGHMEM=y | ||||||
|  | CONFIG_SYS_SUPPORTS_HOTPLUG_CPU=y | ||||||
|  | CONFIG_SYS_SUPPORTS_LITTLE_ENDIAN=y | ||||||
|  | CONFIG_SYS_SUPPORTS_MIPS16=y | ||||||
|  | CONFIG_SYS_SUPPORTS_MIPS_CPS=y | ||||||
|  | CONFIG_SYS_SUPPORTS_MULTITHREADING=y | ||||||
|  | CONFIG_SYS_SUPPORTS_SCHED_SMT=y | ||||||
|  | CONFIG_SYS_SUPPORTS_SMP=y | ||||||
|  | CONFIG_TICK_CPU_ACCOUNTING=y | ||||||
|  | CONFIG_TIMER_OF=y | ||||||
|  | CONFIG_TIMER_PROBE=y | ||||||
|  | CONFIG_TREE_RCU=y | ||||||
|  | CONFIG_TREE_SRCU=y | ||||||
|  | CONFIG_UBIFS_FS=y | ||||||
|  | CONFIG_UBIFS_FS_ADVANCED_COMPR=y | ||||||
|  | CONFIG_UBIFS_FS_LZO=y | ||||||
|  | CONFIG_UBIFS_FS_ZLIB=y | ||||||
|  | CONFIG_USB_SUPPORT=y | ||||||
|  | CONFIG_USE_OF=y | ||||||
|  | CONFIG_WATCHDOG_CORE=y | ||||||
|  | CONFIG_WEAK_ORDERING=y | ||||||
|  | CONFIG_WEAK_REORDERING_BEYOND_LLSC=y | ||||||
|  | CONFIG_XPS=y | ||||||
|  | CONFIG_ZLIB_DEFLATE=y | ||||||
|  | CONFIG_ZLIB_INFLATE=y | ||||||
| @@ -0,0 +1,45 @@ | |||||||
|  | From 35d017947401d9f449a7e55e52506744e0c62577 Mon Sep 17 00:00:00 2001 | ||||||
|  | From: Mathias Kresin <dev@kresin.me> | ||||||
|  | Date: Wed, 22 Aug 2018 22:38:06 +0200 | ||||||
|  | Subject: [PATCH] MIPS: ralink: Add rt3352 SPI_CS1 pinmux | ||||||
|  |  | ||||||
|  | The rt3352 has a pin that can be used as second spi chip select, | ||||||
|  | watchdog reset or GPIO. The pinmux setup was missing the definition of | ||||||
|  | said pin. | ||||||
|  |  | ||||||
|  | The pin is configured via the same bit on rt5350, so reuse the existing | ||||||
|  | macro. | ||||||
|  |  | ||||||
|  | Signed-off-by: Mathias Kresin <dev@kresin.me> | ||||||
|  | Signed-off-by: Paul Burton <paul.burton@mips.com> | ||||||
|  | Patchwork: https://patchwork.linux-mips.org/patch/20301/ | ||||||
|  | Cc: John Crispin <john@phrozen.org> | ||||||
|  | Cc: Ralf Baechle <ralf@linux-mips.org> | ||||||
|  | Cc: James Hogan <jhogan@kernel.org> | ||||||
|  | Cc: linux-mips@linux-mips.org | ||||||
|  | Cc: linux-kernel@vger.kernel.org | ||||||
|  | --- | ||||||
|  |  arch/mips/ralink/rt305x.c | 5 +++++ | ||||||
|  |  1 file changed, 5 insertions(+) | ||||||
|  |  | ||||||
|  | --- a/arch/mips/ralink/rt305x.c | ||||||
|  | +++ b/arch/mips/ralink/rt305x.c | ||||||
|  | @@ -49,6 +49,10 @@ static struct rt2880_pmx_func rgmii_func | ||||||
|  |  static struct rt2880_pmx_func rt3352_lna_func[] = { FUNC("lna", 0, 36, 2) }; | ||||||
|  |  static struct rt2880_pmx_func rt3352_pa_func[] = { FUNC("pa", 0, 38, 2) }; | ||||||
|  |  static struct rt2880_pmx_func rt3352_led_func[] = { FUNC("led", 0, 40, 5) }; | ||||||
|  | +static struct rt2880_pmx_func rt3352_cs1_func[] = { | ||||||
|  | +	FUNC("spi_cs1", 0, 45, 1), | ||||||
|  | +	FUNC("wdg_cs1", 1, 45, 1), | ||||||
|  | +}; | ||||||
|  |   | ||||||
|  |  static struct rt2880_pmx_group rt3050_pinmux_data[] = { | ||||||
|  |  	GRP("i2c", i2c_func, 1, RT305X_GPIO_MODE_I2C), | ||||||
|  | @@ -75,6 +79,7 @@ static struct rt2880_pmx_group rt3352_pi | ||||||
|  |  	GRP("lna", rt3352_lna_func, 1, RT3352_GPIO_MODE_LNA), | ||||||
|  |  	GRP("pa", rt3352_pa_func, 1, RT3352_GPIO_MODE_PA), | ||||||
|  |  	GRP("led", rt3352_led_func, 1, RT5350_GPIO_MODE_PHY_LED), | ||||||
|  | +	GRP("spi_cs1", rt3352_cs1_func, 2, RT5350_GPIO_MODE_SPI_CS1), | ||||||
|  |  	{ 0 } | ||||||
|  |  }; | ||||||
|  |   | ||||||
| @@ -0,0 +1,32 @@ | |||||||
|  | From 0eb1cfffd5433d8dce3e4163a5cd9accc6000856 Mon Sep 17 00:00:00 2001 | ||||||
|  | From: Tobias Wolf <dev-NTEO@vplace.de> | ||||||
|  | Date: Wed, 5 Sep 2018 08:51:26 +0200 | ||||||
|  | Subject: [PATCH] MIPS: pci-rt2880: set pci controller of_node | ||||||
|  |  | ||||||
|  | Set the PCI controller of_node such that PCI devices can be | ||||||
|  | instantiated via device tree. | ||||||
|  |  | ||||||
|  | Signed-off-by: Tobias Wolf <dev-NTEO@vplace.de> | ||||||
|  | Signed-off-by: Mathias Kresin <dev@kresin.me> | ||||||
|  | Acked-by: John Crispin <john@phrozen.org> | ||||||
|  | Signed-off-by: Paul Burton <paul.burton@mips.com> | ||||||
|  | Patchwork: https://patchwork.linux-mips.org/patch/20423/ | ||||||
|  | Cc: Ralf Baechle <ralf@linux-mips.org> | ||||||
|  | Cc: James Hogan <jhogan@kernel.org> | ||||||
|  | Cc: linux-mips@linux-mips.org | ||||||
|  | Cc: linux-kernel@vger.kernel.org | ||||||
|  | --- | ||||||
|  |  arch/mips/pci/pci-rt2880.c | 2 ++ | ||||||
|  |  1 file changed, 2 insertions(+) | ||||||
|  |  | ||||||
|  | --- a/arch/mips/pci/pci-rt2880.c | ||||||
|  | +++ b/arch/mips/pci/pci-rt2880.c | ||||||
|  | @@ -246,6 +246,8 @@ static int rt288x_pci_probe(struct platf | ||||||
|  |  	rt2880_pci_write_u32(PCI_BASE_ADDRESS_0, 0x08000000); | ||||||
|  |  	(void) rt2880_pci_read_u32(PCI_BASE_ADDRESS_0); | ||||||
|  |   | ||||||
|  | +	rt2880_pci_controller.of_node = pdev->dev.of_node; | ||||||
|  | + | ||||||
|  |  	register_pci_controller(&rt2880_pci_controller); | ||||||
|  |  	return 0; | ||||||
|  |  } | ||||||
| @@ -0,0 +1,45 @@ | |||||||
|  | From: Tobias Wolf <dev-NTEO@vplace.de> | ||||||
|  | Subject: [v2] MIPS: Fix memory reservation in bootmem_init for certain non-usermem setups | ||||||
|  |  | ||||||
|  | Commit 67a3ba25aa95 ("MIPS: Fix incorrect mem=X@Y handling") introduced a new | ||||||
|  | issue for rt288x where "PHYS_OFFSET" is 0x0 but the calculated "ramstart" is | ||||||
|  | not. As the prerequisite of custom memory map has been removed, this results | ||||||
|  | in the full memory range of 0x0 - 0x8000000 to be marked as reserved for this | ||||||
|  | platform. | ||||||
|  |  | ||||||
|  | v2: Correctly compare that usermem is not null. | ||||||
|  |  | ||||||
|  | This patch adds the originally intended prerequisite again. | ||||||
|  |  | ||||||
|  | Signed-off-by: Tobias Wolf <dev-NTEO@vplace.de> | ||||||
|  | --- | ||||||
|  |  | ||||||
|  | --- a/arch/mips/kernel/setup.c | ||||||
|  | +++ b/arch/mips/kernel/setup.c | ||||||
|  | @@ -369,6 +369,8 @@ static unsigned long __init bootmap_byte | ||||||
|  |  	return ALIGN(bytes, sizeof(long)); | ||||||
|  |  } | ||||||
|  |   | ||||||
|  | +static int usermem __initdata; | ||||||
|  | + | ||||||
|  |  static void __init bootmem_init(void) | ||||||
|  |  { | ||||||
|  |  	unsigned long reserved_end; | ||||||
|  | @@ -442,7 +444,7 @@ static void __init bootmem_init(void) | ||||||
|  |  	/* | ||||||
|  |  	 * Reserve any memory between the start of RAM and PHYS_OFFSET | ||||||
|  |  	 */ | ||||||
|  | -	if (ramstart > PHYS_OFFSET) | ||||||
|  | +	if (usermem && ramstart > PHYS_OFFSET) | ||||||
|  |  		add_memory_region(PHYS_OFFSET, ramstart - PHYS_OFFSET, | ||||||
|  |  				  BOOT_MEM_RESERVED); | ||||||
|  |   | ||||||
|  | @@ -652,8 +654,6 @@ static void __init bootmem_init(void) | ||||||
|  |   * initialization hook for anything else was introduced. | ||||||
|  |   */ | ||||||
|  |   | ||||||
|  | -static int usermem __initdata; | ||||||
|  | - | ||||||
|  |  static int __init early_parse_mem(char *p) | ||||||
|  |  { | ||||||
|  |  	phys_addr_t start, size; | ||||||
| @@ -0,0 +1,861 @@ | |||||||
|  | From fec11d4e8dc5cc79bcd7c8fd55038ac21ac39965 Mon Sep 17 00:00:00 2001 | ||||||
|  | From: John Crispin <blogic@openwrt.org> | ||||||
|  | Date: Sun, 16 Mar 2014 05:22:39 +0000 | ||||||
|  | Subject: [PATCH 04/53] MIPS: ralink: add MT7621 pcie driver | ||||||
|  |  | ||||||
|  | Signed-off-by: John Crispin <blogic@openwrt.org> | ||||||
|  | --- | ||||||
|  |  arch/mips/pci/Makefile     |    1 + | ||||||
|  |  arch/mips/pci/pci-mt7621.c |  813 ++++++++++++++++++++++++++++++++++++++++++++ | ||||||
|  |  2 files changed, 814 insertions(+) | ||||||
|  |  create mode 100644 arch/mips/pci/pci-mt7621.c | ||||||
|  |  | ||||||
|  | --- a/arch/mips/pci/Makefile | ||||||
|  | +++ b/arch/mips/pci/Makefile | ||||||
|  | @@ -47,6 +47,7 @@ obj-$(CONFIG_SNI_RM)		+= fixup-sni.o ops | ||||||
|  |  obj-$(CONFIG_LANTIQ)		+= fixup-lantiq.o | ||||||
|  |  obj-$(CONFIG_PCI_LANTIQ)	+= pci-lantiq.o ops-lantiq.o | ||||||
|  |  obj-$(CONFIG_SOC_MT7620)	+= pci-mt7620.o | ||||||
|  | +obj-$(CONFIG_SOC_MT7621)	+= pci-mt7621.o | ||||||
|  |  obj-$(CONFIG_SOC_RT288X)	+= pci-rt2880.o | ||||||
|  |  obj-$(CONFIG_SOC_RT3883)	+= pci-rt3883.o | ||||||
|  |  obj-$(CONFIG_TANBAC_TB0219)	+= fixup-tb0219.o | ||||||
|  | --- /dev/null | ||||||
|  | +++ b/arch/mips/pci/pci-mt7621.c | ||||||
|  | @@ -0,0 +1,836 @@ | ||||||
|  | +/************************************************************************** | ||||||
|  | + * | ||||||
|  | + *  BRIEF MODULE DESCRIPTION | ||||||
|  | + *     PCI init for Ralink RT2880 solution | ||||||
|  | + * | ||||||
|  | + *  Copyright 2007 Ralink Inc. (bruce_chang@ralinktech.com.tw) | ||||||
|  | + * | ||||||
|  | + *  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  SOFTWARE  IS PROVIDED   ``AS  IS'' AND   ANY  EXPRESS OR IMPLIED | ||||||
|  | + *  WARRANTIES,   INCLUDING, BUT NOT  LIMITED  TO, THE IMPLIED WARRANTIES OF | ||||||
|  | + *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN | ||||||
|  | + *  NO  EVENT  SHALL   THE AUTHOR  BE    LIABLE FOR ANY   DIRECT, INDIRECT, | ||||||
|  | + *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT | ||||||
|  | + *  NOT LIMITED   TO, PROCUREMENT OF  SUBSTITUTE GOODS  OR SERVICES; LOSS OF | ||||||
|  | + *  USE, DATA,  OR PROFITS; OR  BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON | ||||||
|  | + *  ANY THEORY OF LIABILITY, WHETHER IN  CONTRACT, STRICT LIABILITY, OR TORT | ||||||
|  | + *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF | ||||||
|  | + *  THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||||||
|  | + * | ||||||
|  | + *  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., | ||||||
|  | + *  675 Mass Ave, Cambridge, MA 02139, USA. | ||||||
|  | + * | ||||||
|  | + * | ||||||
|  | + ************************************************************************** | ||||||
|  | + * May 2007 Bruce Chang | ||||||
|  | + * Initial Release | ||||||
|  | + * | ||||||
|  | + * May 2009 Bruce Chang | ||||||
|  | + * support RT2880/RT3883 PCIe | ||||||
|  | + * | ||||||
|  | + * May 2011 Bruce Chang | ||||||
|  | + * support RT6855/MT7620 PCIe | ||||||
|  | + * | ||||||
|  | + ************************************************************************** | ||||||
|  | + */ | ||||||
|  | + | ||||||
|  | +#include <linux/types.h> | ||||||
|  | +#include <linux/pci.h> | ||||||
|  | +#include <linux/kernel.h> | ||||||
|  | +#include <linux/slab.h> | ||||||
|  | +#include <linux/version.h> | ||||||
|  | +#include <asm/pci.h> | ||||||
|  | +#include <asm/io.h> | ||||||
|  | +#include <asm/mips-cm.h> | ||||||
|  | +#include <linux/init.h> | ||||||
|  | +#include <linux/module.h> | ||||||
|  | +#include <linux/delay.h> | ||||||
|  | +#include <linux/of.h> | ||||||
|  | +#include <linux/of_pci.h> | ||||||
|  | +#include <linux/of_irq.h> | ||||||
|  | +#include <linux/platform_device.h> | ||||||
|  | + | ||||||
|  | +#include <ralink_regs.h> | ||||||
|  | + | ||||||
|  | +extern void pcie_phy_init(void); | ||||||
|  | +extern void chk_phy_pll(void); | ||||||
|  | + | ||||||
|  | +/* | ||||||
|  | + * These functions and structures provide the BIOS scan and mapping of the PCI | ||||||
|  | + * devices. | ||||||
|  | + */ | ||||||
|  | + | ||||||
|  | +#define CONFIG_PCIE_PORT0 | ||||||
|  | +#define CONFIG_PCIE_PORT1 | ||||||
|  | +#define CONFIG_PCIE_PORT2 | ||||||
|  | +#define RALINK_PCIE0_CLK_EN             (1<<24) | ||||||
|  | +#define RALINK_PCIE1_CLK_EN             (1<<25) | ||||||
|  | +#define RALINK_PCIE2_CLK_EN             (1<<26) | ||||||
|  | + | ||||||
|  | +#define RALINK_PCI_CONFIG_ADDR                         0x20 | ||||||
|  | +#define RALINK_PCI_CONFIG_DATA_VIRTUAL_REG     0x24 | ||||||
|  | +#define RALINK_INT_PCIE0         pcie_irq[0] | ||||||
|  | +#define RALINK_INT_PCIE1         pcie_irq[1] | ||||||
|  | +#define RALINK_INT_PCIE2         pcie_irq[2] | ||||||
|  | +#define RALINK_PCI_MEMBASE              *(volatile u32 *)(RALINK_PCI_BASE + 0x0028) | ||||||
|  | +#define RALINK_PCI_IOBASE               *(volatile u32 *)(RALINK_PCI_BASE + 0x002C) | ||||||
|  | +#define RALINK_PCIE0_RST                (1<<24) | ||||||
|  | +#define RALINK_PCIE1_RST                (1<<25) | ||||||
|  | +#define RALINK_PCIE2_RST                (1<<26) | ||||||
|  | +#define RALINK_SYSCTL_BASE              0xBE000000 | ||||||
|  | + | ||||||
|  | +#define RALINK_PCI_PCICFG_ADDR          *(volatile u32 *)(RALINK_PCI_BASE + 0x0000) | ||||||
|  | +#define RALINK_PCI_PCIMSK_ADDR          *(volatile u32 *)(RALINK_PCI_BASE + 0x000C) | ||||||
|  | +#define RALINK_PCI_BASE                 0xBE140000 | ||||||
|  | + | ||||||
|  | +#define RALINK_PCIEPHY_P0P1_CTL_OFFSET (RALINK_PCI_BASE + 0x9000) | ||||||
|  | +#define RT6855_PCIE0_OFFSET     0x2000 | ||||||
|  | +#define RT6855_PCIE1_OFFSET     0x3000 | ||||||
|  | +#define RT6855_PCIE2_OFFSET     0x4000 | ||||||
|  | + | ||||||
|  | +#define RALINK_PCI0_BAR0SETUP_ADDR      *(volatile u32 *)(RALINK_PCI_BASE + RT6855_PCIE0_OFFSET + 0x0010) | ||||||
|  | +#define RALINK_PCI0_IMBASEBAR0_ADDR     *(volatile u32 *)(RALINK_PCI_BASE + RT6855_PCIE0_OFFSET + 0x0018) | ||||||
|  | +#define RALINK_PCI0_ID                  *(volatile u32 *)(RALINK_PCI_BASE + RT6855_PCIE0_OFFSET + 0x0030) | ||||||
|  | +#define RALINK_PCI0_CLASS               *(volatile u32 *)(RALINK_PCI_BASE + RT6855_PCIE0_OFFSET + 0x0034) | ||||||
|  | +#define RALINK_PCI0_SUBID               *(volatile u32 *)(RALINK_PCI_BASE + RT6855_PCIE0_OFFSET + 0x0038) | ||||||
|  | +#define RALINK_PCI0_STATUS              *(volatile u32 *)(RALINK_PCI_BASE + RT6855_PCIE0_OFFSET + 0x0050) | ||||||
|  | +#define RALINK_PCI0_DERR                *(volatile u32 *)(RALINK_PCI_BASE + RT6855_PCIE0_OFFSET + 0x0060) | ||||||
|  | +#define RALINK_PCI0_ECRC                *(volatile u32 *)(RALINK_PCI_BASE + RT6855_PCIE0_OFFSET + 0x0064) | ||||||
|  | + | ||||||
|  | +#define RALINK_PCI1_BAR0SETUP_ADDR      *(volatile u32 *)(RALINK_PCI_BASE + RT6855_PCIE1_OFFSET + 0x0010) | ||||||
|  | +#define RALINK_PCI1_IMBASEBAR0_ADDR     *(volatile u32 *)(RALINK_PCI_BASE + RT6855_PCIE1_OFFSET + 0x0018) | ||||||
|  | +#define RALINK_PCI1_ID                  *(volatile u32 *)(RALINK_PCI_BASE + RT6855_PCIE1_OFFSET + 0x0030) | ||||||
|  | +#define RALINK_PCI1_CLASS               *(volatile u32 *)(RALINK_PCI_BASE + RT6855_PCIE1_OFFSET + 0x0034) | ||||||
|  | +#define RALINK_PCI1_SUBID               *(volatile u32 *)(RALINK_PCI_BASE + RT6855_PCIE1_OFFSET + 0x0038) | ||||||
|  | +#define RALINK_PCI1_STATUS              *(volatile u32 *)(RALINK_PCI_BASE + RT6855_PCIE1_OFFSET + 0x0050) | ||||||
|  | +#define RALINK_PCI1_DERR                *(volatile u32 *)(RALINK_PCI_BASE + RT6855_PCIE1_OFFSET + 0x0060) | ||||||
|  | +#define RALINK_PCI1_ECRC                *(volatile u32 *)(RALINK_PCI_BASE + RT6855_PCIE1_OFFSET + 0x0064) | ||||||
|  | + | ||||||
|  | +#define RALINK_PCI2_BAR0SETUP_ADDR      *(volatile u32 *)(RALINK_PCI_BASE + RT6855_PCIE2_OFFSET + 0x0010) | ||||||
|  | +#define RALINK_PCI2_IMBASEBAR0_ADDR     *(volatile u32 *)(RALINK_PCI_BASE + RT6855_PCIE2_OFFSET + 0x0018) | ||||||
|  | +#define RALINK_PCI2_ID                  *(volatile u32 *)(RALINK_PCI_BASE + RT6855_PCIE2_OFFSET + 0x0030) | ||||||
|  | +#define RALINK_PCI2_CLASS               *(volatile u32 *)(RALINK_PCI_BASE + RT6855_PCIE2_OFFSET + 0x0034) | ||||||
|  | +#define RALINK_PCI2_SUBID               *(volatile u32 *)(RALINK_PCI_BASE + RT6855_PCIE2_OFFSET + 0x0038) | ||||||
|  | +#define RALINK_PCI2_STATUS              *(volatile u32 *)(RALINK_PCI_BASE + RT6855_PCIE2_OFFSET + 0x0050) | ||||||
|  | +#define RALINK_PCI2_DERR                *(volatile u32 *)(RALINK_PCI_BASE + RT6855_PCIE2_OFFSET + 0x0060) | ||||||
|  | +#define RALINK_PCI2_ECRC                *(volatile u32 *)(RALINK_PCI_BASE + RT6855_PCIE2_OFFSET + 0x0064) | ||||||
|  | + | ||||||
|  | +#define RALINK_PCIEPHY_P0P1_CTL_OFFSET  (RALINK_PCI_BASE + 0x9000) | ||||||
|  | +#define RALINK_PCIEPHY_P2_CTL_OFFSET    (RALINK_PCI_BASE + 0xA000) | ||||||
|  | + | ||||||
|  | + | ||||||
|  | +#define MV_WRITE(ofs, data)  \ | ||||||
|  | +        *(volatile u32 *)(RALINK_PCI_BASE+(ofs)) = cpu_to_le32(data) | ||||||
|  | +#define MV_READ(ofs, data)   \ | ||||||
|  | +	        *(data) = le32_to_cpu(*(volatile u32 *)(RALINK_PCI_BASE+(ofs))) | ||||||
|  | +#define MV_READ_DATA(ofs)    \ | ||||||
|  | +		        le32_to_cpu(*(volatile u32 *)(RALINK_PCI_BASE+(ofs))) | ||||||
|  | + | ||||||
|  | +#define MV_WRITE_16(ofs, data)  \ | ||||||
|  | +        *(volatile u16 *)(RALINK_PCI_BASE+(ofs)) = cpu_to_le16(data) | ||||||
|  | +#define MV_READ_16(ofs, data)   \ | ||||||
|  | +	        *(data) = le16_to_cpu(*(volatile u16 *)(RALINK_PCI_BASE+(ofs))) | ||||||
|  | + | ||||||
|  | +#define MV_WRITE_8(ofs, data)  \ | ||||||
|  | +        *(volatile u8 *)(RALINK_PCI_BASE+(ofs)) = data | ||||||
|  | +#define MV_READ_8(ofs, data)   \ | ||||||
|  | +	        *(data) = *(volatile u8 *)(RALINK_PCI_BASE+(ofs)) | ||||||
|  | + | ||||||
|  | + | ||||||
|  | + | ||||||
|  | +#define RALINK_PCI_MM_MAP_BASE	0x60000000 | ||||||
|  | +#define RALINK_PCI_IO_MAP_BASE	0x1e160000 | ||||||
|  | + | ||||||
|  | +#define RALINK_SYSTEM_CONTROL_BASE	0xbe000000 | ||||||
|  | +#define GPIO_PERST | ||||||
|  | +#define ASSERT_SYSRST_PCIE(val)		do {	\ | ||||||
|  | +						if (*(unsigned int *)(0xbe00000c) == 0x00030101)	\ | ||||||
|  | +							RALINK_RSTCTRL |= val;	\ | ||||||
|  | +						else	\ | ||||||
|  | +							RALINK_RSTCTRL &= ~val;	\ | ||||||
|  | +					} while(0) | ||||||
|  | +#define DEASSERT_SYSRST_PCIE(val) 	do {	\ | ||||||
|  | +						if (*(unsigned int *)(0xbe00000c) == 0x00030101)	\ | ||||||
|  | +							RALINK_RSTCTRL &= ~val;	\ | ||||||
|  | +						else	\ | ||||||
|  | +							RALINK_RSTCTRL |= val;	\ | ||||||
|  | +					} while(0) | ||||||
|  | +#define RALINK_SYSCFG1			*(unsigned int *)(RALINK_SYSTEM_CONTROL_BASE + 0x14) | ||||||
|  | +#define RALINK_CLKCFG1			*(unsigned int *)(RALINK_SYSTEM_CONTROL_BASE + 0x30) | ||||||
|  | +#define RALINK_RSTCTRL			*(unsigned int *)(RALINK_SYSTEM_CONTROL_BASE + 0x34) | ||||||
|  | +#define RALINK_GPIOMODE			*(unsigned int *)(RALINK_SYSTEM_CONTROL_BASE + 0x60) | ||||||
|  | +#define RALINK_PCIE_CLK_GEN		*(unsigned int *)(RALINK_SYSTEM_CONTROL_BASE + 0x7c) | ||||||
|  | +#define RALINK_PCIE_CLK_GEN1		*(unsigned int *)(RALINK_SYSTEM_CONTROL_BASE + 0x80) | ||||||
|  | +#define PPLL_CFG1			*(unsigned int *)(RALINK_SYSTEM_CONTROL_BASE + 0x9c) | ||||||
|  | +#define PPLL_DRV			*(unsigned int *)(RALINK_SYSTEM_CONTROL_BASE + 0xa0) | ||||||
|  | +//RALINK_SYSCFG1 bit | ||||||
|  | +#define RALINK_PCI_HOST_MODE_EN		(1<<7) | ||||||
|  | +#define RALINK_PCIE_RC_MODE_EN		(1<<8) | ||||||
|  | +//RALINK_RSTCTRL bit | ||||||
|  | +#define RALINK_PCIE_RST			(1<<23) | ||||||
|  | +#define RALINK_PCI_RST			(1<<24) | ||||||
|  | +//RALINK_CLKCFG1 bit | ||||||
|  | +#define RALINK_PCI_CLK_EN		(1<<19) | ||||||
|  | +#define RALINK_PCIE_CLK_EN		(1<<21) | ||||||
|  | +//RALINK_GPIOMODE bit | ||||||
|  | +#define PCI_SLOTx2			(1<<11) | ||||||
|  | +#define PCI_SLOTx1			(2<<11) | ||||||
|  | +//MTK PCIE PLL bit | ||||||
|  | +#define PDRV_SW_SET			(1<<31) | ||||||
|  | +#define LC_CKDRVPD_			(1<<19) | ||||||
|  | + | ||||||
|  | +#define MEMORY_BASE 0x0 | ||||||
|  | +static int pcie_link_status = 0; | ||||||
|  | + | ||||||
|  | +#define PCI_ACCESS_READ_1  0 | ||||||
|  | +#define PCI_ACCESS_READ_2  1 | ||||||
|  | +#define PCI_ACCESS_READ_4  2 | ||||||
|  | +#define PCI_ACCESS_WRITE_1 3 | ||||||
|  | +#define PCI_ACCESS_WRITE_2 4 | ||||||
|  | +#define PCI_ACCESS_WRITE_4 5 | ||||||
|  | + | ||||||
|  | +static int pcie_irq[3]; | ||||||
|  | + | ||||||
|  | +static int config_access(unsigned char access_type, struct pci_bus *bus, | ||||||
|  | +			unsigned int devfn, unsigned int where, u32 * data) | ||||||
|  | +{ | ||||||
|  | +	unsigned int slot = PCI_SLOT(devfn); | ||||||
|  | +	u8 func = PCI_FUNC(devfn); | ||||||
|  | +	uint32_t address_reg, data_reg; | ||||||
|  | +	unsigned int address; | ||||||
|  | + | ||||||
|  | +	address_reg = RALINK_PCI_CONFIG_ADDR; | ||||||
|  | +	data_reg = RALINK_PCI_CONFIG_DATA_VIRTUAL_REG; | ||||||
|  | + | ||||||
|  | +	address = (((where&0xF00)>>8)<<24) |(bus->number << 16) | (slot << 11) | (func << 8) | (where & 0xfc) | 0x80000000; | ||||||
|  | +	MV_WRITE(address_reg, address); | ||||||
|  | + | ||||||
|  | +	switch(access_type) { | ||||||
|  | +	case PCI_ACCESS_WRITE_1: | ||||||
|  | +		MV_WRITE_8(data_reg+(where&0x3), *data); | ||||||
|  | +		break; | ||||||
|  | +	case PCI_ACCESS_WRITE_2: | ||||||
|  | +		MV_WRITE_16(data_reg+(where&0x3), *data); | ||||||
|  | +		break; | ||||||
|  | +	case PCI_ACCESS_WRITE_4: | ||||||
|  | +		MV_WRITE(data_reg, *data); | ||||||
|  | +		break; | ||||||
|  | +	case PCI_ACCESS_READ_1: | ||||||
|  | +		MV_READ_8( data_reg+(where&0x3), data); | ||||||
|  | +		break; | ||||||
|  | +	case PCI_ACCESS_READ_2: | ||||||
|  | +		MV_READ_16(data_reg+(where&0x3), data); | ||||||
|  | +		break; | ||||||
|  | +	case PCI_ACCESS_READ_4: | ||||||
|  | +		MV_READ(data_reg, data); | ||||||
|  | +		break; | ||||||
|  | +	default: | ||||||
|  | +		printk("no specify access type\n"); | ||||||
|  | +		break; | ||||||
|  | +	} | ||||||
|  | +	return 0; | ||||||
|  | +} | ||||||
|  | + | ||||||
|  | +static int | ||||||
|  | +read_config_byte(struct pci_bus *bus, unsigned int devfn, int where, u8 * val) | ||||||
|  | +{ | ||||||
|  | +	return config_access(PCI_ACCESS_READ_1, bus, devfn, (unsigned int)where, (u32 *)val); | ||||||
|  | +} | ||||||
|  | + | ||||||
|  | +static int | ||||||
|  | +read_config_word(struct pci_bus *bus, unsigned int devfn, int where, u16 * val) | ||||||
|  | +{ | ||||||
|  | +	return config_access(PCI_ACCESS_READ_2, bus, devfn, (unsigned int)where, (u32 *)val); | ||||||
|  | +} | ||||||
|  | + | ||||||
|  | +static int | ||||||
|  | +read_config_dword(struct pci_bus *bus, unsigned int devfn, int where, u32 * val) | ||||||
|  | +{ | ||||||
|  | +	return config_access(PCI_ACCESS_READ_4, bus, devfn, (unsigned int)where, (u32 *)val); | ||||||
|  | +} | ||||||
|  | + | ||||||
|  | +static int | ||||||
|  | +write_config_byte(struct pci_bus *bus, unsigned int devfn, int where, u8 val) | ||||||
|  | +{ | ||||||
|  | +	if (config_access(PCI_ACCESS_WRITE_1, bus, devfn, (unsigned int)where, (u32 *)&val)) | ||||||
|  | +		return -1; | ||||||
|  | + | ||||||
|  | +	return PCIBIOS_SUCCESSFUL; | ||||||
|  | +} | ||||||
|  | + | ||||||
|  | +static int | ||||||
|  | +write_config_word(struct pci_bus *bus, unsigned int devfn, int where, u16 val) | ||||||
|  | +{ | ||||||
|  | +	if (config_access(PCI_ACCESS_WRITE_2, bus, devfn, where, (u32 *)&val)) | ||||||
|  | +		return -1; | ||||||
|  | + | ||||||
|  | +	return PCIBIOS_SUCCESSFUL; | ||||||
|  | +} | ||||||
|  | + | ||||||
|  | +static int | ||||||
|  | +write_config_dword(struct pci_bus *bus, unsigned int devfn, int where, u32 val) | ||||||
|  | +{ | ||||||
|  | +	if (config_access(PCI_ACCESS_WRITE_4, bus, devfn, where, &val)) | ||||||
|  | +		return -1; | ||||||
|  | + | ||||||
|  | +	return PCIBIOS_SUCCESSFUL; | ||||||
|  | +} | ||||||
|  | + | ||||||
|  | + | ||||||
|  | +static int | ||||||
|  | +pci_config_read(struct pci_bus *bus, unsigned int devfn, int where, int size, u32 * val) | ||||||
|  | +{ | ||||||
|  | +	switch (size) { | ||||||
|  | +	case 1: | ||||||
|  | +		return read_config_byte(bus, devfn, where, (u8 *) val); | ||||||
|  | +	case 2: | ||||||
|  | +		return read_config_word(bus, devfn, where, (u16 *) val); | ||||||
|  | +	default: | ||||||
|  | +		return read_config_dword(bus, devfn, where, val); | ||||||
|  | +	} | ||||||
|  | +} | ||||||
|  | + | ||||||
|  | +static int | ||||||
|  | +pci_config_write(struct pci_bus *bus, unsigned int devfn, int where, int size, u32 val) | ||||||
|  | +{ | ||||||
|  | +	switch (size) { | ||||||
|  | +	case 1: | ||||||
|  | +		return write_config_byte(bus, devfn, where, (u8) val); | ||||||
|  | +	case 2: | ||||||
|  | +		return write_config_word(bus, devfn, where, (u16) val); | ||||||
|  | +	default: | ||||||
|  | +		return write_config_dword(bus, devfn, where, val); | ||||||
|  | +	} | ||||||
|  | +} | ||||||
|  | + | ||||||
|  | +struct pci_ops mt7621_pci_ops= { | ||||||
|  | +	.read		=  pci_config_read, | ||||||
|  | +	.write		= pci_config_write, | ||||||
|  | +}; | ||||||
|  | + | ||||||
|  | +static struct resource mt7621_res_pci_mem1 = { | ||||||
|  | +	.name		= "PCI MEM1", | ||||||
|  | +	.start		= RALINK_PCI_MM_MAP_BASE, | ||||||
|  | +	.end		= (u32)((RALINK_PCI_MM_MAP_BASE + (unsigned char *)0x0fffffff)), | ||||||
|  | +	.flags		= IORESOURCE_MEM, | ||||||
|  | +}; | ||||||
|  | +static struct resource mt7621_res_pci_io1 = { | ||||||
|  | +	.name		= "PCI I/O1", | ||||||
|  | +	.start		= RALINK_PCI_IO_MAP_BASE, | ||||||
|  | +	.end		= (u32)((RALINK_PCI_IO_MAP_BASE + (unsigned char *)0x0ffff)), | ||||||
|  | +	.flags		= IORESOURCE_IO, | ||||||
|  | +}; | ||||||
|  | + | ||||||
|  | +static struct pci_controller mt7621_controller = { | ||||||
|  | +	.pci_ops	= &mt7621_pci_ops, | ||||||
|  | +	.mem_resource	= &mt7621_res_pci_mem1, | ||||||
|  | +	.io_resource	= &mt7621_res_pci_io1, | ||||||
|  | +	.mem_offset	= 0x00000000UL, | ||||||
|  | +	.io_offset	= 0x00000000UL, | ||||||
|  | +	.io_map_base	= 0xa0000000, | ||||||
|  | +}; | ||||||
|  | + | ||||||
|  | +static void | ||||||
|  | +read_config(unsigned long bus, unsigned long dev, unsigned long func, unsigned long reg, unsigned long *val) | ||||||
|  | +{ | ||||||
|  | +	unsigned int address_reg, data_reg, address; | ||||||
|  | + | ||||||
|  | +	address_reg = RALINK_PCI_CONFIG_ADDR; | ||||||
|  | +        data_reg = RALINK_PCI_CONFIG_DATA_VIRTUAL_REG; | ||||||
|  | +	address = (((reg & 0xF00)>>8)<<24) | (bus << 16) | (dev << 11) | (func << 8) | (reg & 0xfc) | 0x80000000 ; | ||||||
|  | +        MV_WRITE(address_reg, address); | ||||||
|  | +        MV_READ(data_reg, val); | ||||||
|  | +	return; | ||||||
|  | +} | ||||||
|  | + | ||||||
|  | +static void | ||||||
|  | +write_config(unsigned long bus, unsigned long dev, unsigned long func, unsigned long reg, unsigned long val) | ||||||
|  | +{ | ||||||
|  | +	unsigned int address_reg, data_reg, address; | ||||||
|  | + | ||||||
|  | +	address_reg = RALINK_PCI_CONFIG_ADDR; | ||||||
|  | +	data_reg = RALINK_PCI_CONFIG_DATA_VIRTUAL_REG; | ||||||
|  | +	address = (((reg & 0xF00)>>8)<<24) | (bus << 16) | (dev << 11) | (func << 8) | (reg & 0xfc) | 0x80000000 ; | ||||||
|  | +	MV_WRITE(address_reg, address); | ||||||
|  | +	MV_WRITE(data_reg, val); | ||||||
|  | +	return; | ||||||
|  | +} | ||||||
|  | + | ||||||
|  | + | ||||||
|  | +int | ||||||
|  | +pcibios_map_irq(const struct pci_dev *dev, u8 slot, u8 pin) | ||||||
|  | +{ | ||||||
|  | +	u16 cmd; | ||||||
|  | +	u32 val; | ||||||
|  | +	int irq = 0; | ||||||
|  | + | ||||||
|  | +	if ((dev->bus->number == 0) && (slot == 0)) { | ||||||
|  | +		write_config(0, 0, 0, PCI_BASE_ADDRESS_0, MEMORY_BASE); | ||||||
|  | +		read_config(0, 0, 0, PCI_BASE_ADDRESS_0, (unsigned long *)&val); | ||||||
|  | +		printk("BAR0 at slot 0 = %x\n", val); | ||||||
|  | +		printk("bus=0x%x, slot = 0x%x\n",dev->bus->number, slot); | ||||||
|  | +	} else if((dev->bus->number == 0) && (slot == 0x1)) { | ||||||
|  | +		write_config(0, 1, 0, PCI_BASE_ADDRESS_0, MEMORY_BASE); | ||||||
|  | +		read_config(0, 1, 0, PCI_BASE_ADDRESS_0, (unsigned long *)&val); | ||||||
|  | +		printk("BAR0 at slot 1 = %x\n", val); | ||||||
|  | +		printk("bus=0x%x, slot = 0x%x\n",dev->bus->number, slot); | ||||||
|  | +	} else if((dev->bus->number == 0) && (slot == 0x2)) { | ||||||
|  | +		write_config(0, 2, 0, PCI_BASE_ADDRESS_0, MEMORY_BASE); | ||||||
|  | +		read_config(0, 2, 0, PCI_BASE_ADDRESS_0, (unsigned long *)&val); | ||||||
|  | +		printk("BAR0 at slot 2 = %x\n", val); | ||||||
|  | +		printk("bus=0x%x, slot = 0x%x\n",dev->bus->number, slot); | ||||||
|  | +	} else if ((dev->bus->number == 1) && (slot == 0x0)) { | ||||||
|  | +		switch (pcie_link_status) { | ||||||
|  | +		case 2: | ||||||
|  | +		case 6: | ||||||
|  | +			irq = RALINK_INT_PCIE1; | ||||||
|  | +			break; | ||||||
|  | +		case 4: | ||||||
|  | +			irq = RALINK_INT_PCIE2; | ||||||
|  | +			break; | ||||||
|  | +		default: | ||||||
|  | +			irq = RALINK_INT_PCIE0; | ||||||
|  | +		} | ||||||
|  | +		printk("bus=0x%x, slot = 0x%x, irq=0x%x\n",dev->bus->number, slot, dev->irq); | ||||||
|  | +	} else if ((dev->bus->number == 2) && (slot == 0x0)) { | ||||||
|  | +		switch (pcie_link_status) { | ||||||
|  | +		case 5: | ||||||
|  | +		case 6: | ||||||
|  | +			irq = RALINK_INT_PCIE2; | ||||||
|  | +			break; | ||||||
|  | +		default: | ||||||
|  | +			irq = RALINK_INT_PCIE1; | ||||||
|  | +		} | ||||||
|  | +		printk("bus=0x%x, slot = 0x%x, irq=0x%x\n",dev->bus->number, slot, dev->irq); | ||||||
|  | +	} else if ((dev->bus->number == 2) && (slot == 0x1)) { | ||||||
|  | +		switch (pcie_link_status) { | ||||||
|  | +		case 5: | ||||||
|  | +		case 6: | ||||||
|  | +			irq = RALINK_INT_PCIE2; | ||||||
|  | +			break; | ||||||
|  | +		default: | ||||||
|  | +			irq = RALINK_INT_PCIE1; | ||||||
|  | +		} | ||||||
|  | +		printk("bus=0x%x, slot = 0x%x, irq=0x%x\n",dev->bus->number, slot, dev->irq); | ||||||
|  | +	} else if ((dev->bus->number ==3) && (slot == 0x0)) { | ||||||
|  | +		irq = RALINK_INT_PCIE2; | ||||||
|  | +		printk("bus=0x%x, slot = 0x%x, irq=0x%x\n",dev->bus->number, slot, dev->irq); | ||||||
|  | +	} else if ((dev->bus->number ==3) && (slot == 0x1)) { | ||||||
|  | +		irq = RALINK_INT_PCIE2; | ||||||
|  | +		printk("bus=0x%x, slot = 0x%x, irq=0x%x\n",dev->bus->number, slot, dev->irq); | ||||||
|  | +	} else if ((dev->bus->number ==3) && (slot == 0x2)) { | ||||||
|  | +		irq = RALINK_INT_PCIE2; | ||||||
|  | +		printk("bus=0x%x, slot = 0x%x, irq=0x%x\n",dev->bus->number, slot, dev->irq); | ||||||
|  | +	} else { | ||||||
|  | +		printk("bus=0x%x, slot = 0x%x\n",dev->bus->number, slot); | ||||||
|  | +		return 0; | ||||||
|  | +	} | ||||||
|  | + | ||||||
|  | +	pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE, 0x14);  //configure cache line size 0x14 | ||||||
|  | +	pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0xFF);  //configure latency timer 0x10 | ||||||
|  | +	pci_read_config_word(dev, PCI_COMMAND, &cmd); | ||||||
|  | +	cmd = cmd | PCI_COMMAND_MASTER | PCI_COMMAND_IO | PCI_COMMAND_MEMORY; | ||||||
|  | +	pci_write_config_word(dev, PCI_COMMAND, cmd); | ||||||
|  | +	pci_write_config_byte(dev, PCI_INTERRUPT_LINE, irq); | ||||||
|  | +	return irq; | ||||||
|  | +} | ||||||
|  | + | ||||||
|  | +void | ||||||
|  | +set_pcie_phy(u32 *addr, int start_b, int bits, int val) | ||||||
|  | +{ | ||||||
|  | +//	printk("0x%p:", addr); | ||||||
|  | +//	printk(" %x", *addr); | ||||||
|  | +	*(unsigned int *)(addr) &= ~(((1<<bits) - 1)<<start_b); | ||||||
|  | +	*(unsigned int *)(addr) |= val << start_b; | ||||||
|  | +//	printk(" -> %x\n", *addr); | ||||||
|  | +} | ||||||
|  | + | ||||||
|  | +void | ||||||
|  | +bypass_pipe_rst(void) | ||||||
|  | +{ | ||||||
|  | +#if defined (CONFIG_PCIE_PORT0) | ||||||
|  | +	/* PCIe Port 0 */ | ||||||
|  | +	set_pcie_phy((u32 *)(RALINK_PCIEPHY_P0P1_CTL_OFFSET + 0x02c), 12, 1, 0x01);	// rg_pe1_pipe_rst_b | ||||||
|  | +	set_pcie_phy((u32 *)(RALINK_PCIEPHY_P0P1_CTL_OFFSET + 0x02c),  4, 1, 0x01);	// rg_pe1_pipe_cmd_frc[4] | ||||||
|  | +#endif | ||||||
|  | +#if defined (CONFIG_PCIE_PORT1) | ||||||
|  | +	/* PCIe Port 1 */ | ||||||
|  | +	set_pcie_phy((u32 *)(RALINK_PCIEPHY_P0P1_CTL_OFFSET + 0x12c), 12, 1, 0x01);	// rg_pe1_pipe_rst_b | ||||||
|  | +	set_pcie_phy((u32 *)(RALINK_PCIEPHY_P0P1_CTL_OFFSET + 0x12c),  4, 1, 0x01);	// rg_pe1_pipe_cmd_frc[4] | ||||||
|  | +#endif | ||||||
|  | +#if defined (CONFIG_PCIE_PORT2) | ||||||
|  | +	/* PCIe Port 2 */ | ||||||
|  | +	set_pcie_phy((u32 *)(RALINK_PCIEPHY_P2_CTL_OFFSET + 0x02c), 12, 1, 0x01);	// rg_pe1_pipe_rst_b | ||||||
|  | +	set_pcie_phy((u32 *)(RALINK_PCIEPHY_P2_CTL_OFFSET + 0x02c),  4, 1, 0x01);	// rg_pe1_pipe_cmd_frc[4] | ||||||
|  | +#endif | ||||||
|  | +} | ||||||
|  | + | ||||||
|  | +void | ||||||
|  | +set_phy_for_ssc(void) | ||||||
|  | +{ | ||||||
|  | +	unsigned long reg = (*(volatile u32 *)(RALINK_SYSCTL_BASE + 0x10)); | ||||||
|  | + | ||||||
|  | +	reg = (reg >> 6) & 0x7; | ||||||
|  | +#if defined (CONFIG_PCIE_PORT0) || defined (CONFIG_PCIE_PORT1) | ||||||
|  | +	/* Set PCIe Port0 & Port1 PHY to disable SSC */ | ||||||
|  | +	/* Debug Xtal Type */ | ||||||
|  | +	set_pcie_phy((u32 *)(RALINK_PCIEPHY_P0P1_CTL_OFFSET + 0x400),  8, 1, 0x01);	// rg_pe1_frc_h_xtal_type | ||||||
|  | +	set_pcie_phy((u32 *)(RALINK_PCIEPHY_P0P1_CTL_OFFSET + 0x400),  9, 2, 0x00);	// rg_pe1_h_xtal_type | ||||||
|  | +	set_pcie_phy((u32 *)(RALINK_PCIEPHY_P0P1_CTL_OFFSET + 0x000),  4, 1, 0x01);	// rg_pe1_frc_phy_en               //Force Port 0 enable control | ||||||
|  | +	set_pcie_phy((u32 *)(RALINK_PCIEPHY_P0P1_CTL_OFFSET + 0x100),  4, 1, 0x01);	// rg_pe1_frc_phy_en               //Force Port 1 enable control | ||||||
|  | +	set_pcie_phy((u32 *)(RALINK_PCIEPHY_P0P1_CTL_OFFSET + 0x000),  5, 1, 0x00);	// rg_pe1_phy_en                   //Port 0 disable | ||||||
|  | +	set_pcie_phy((u32 *)(RALINK_PCIEPHY_P0P1_CTL_OFFSET + 0x100),  5, 1, 0x00);	// rg_pe1_phy_en                   //Port 1 disable | ||||||
|  | +	if(reg <= 5 && reg >= 3) { 	// 40MHz Xtal | ||||||
|  | +		set_pcie_phy((u32 *)(RALINK_PCIEPHY_P0P1_CTL_OFFSET + 0x490),  6, 2, 0x01);	// RG_PE1_H_PLL_PREDIV             //Pre-divider ratio (for host mode) | ||||||
|  | +		printk("***** Xtal 40MHz *****\n"); | ||||||
|  | +	} else {			// 25MHz | 20MHz Xtal | ||||||
|  | +		set_pcie_phy((u32 *)(RALINK_PCIEPHY_P0P1_CTL_OFFSET + 0x490),  6, 2, 0x00);	// RG_PE1_H_PLL_PREDIV             //Pre-divider ratio (for host mode) | ||||||
|  | +		if (reg >= 6) { 	 | ||||||
|  | +			printk("***** Xtal 25MHz *****\n"); | ||||||
|  | +			set_pcie_phy((u32 *)(RALINK_PCIEPHY_P0P1_CTL_OFFSET + 0x4bc),  4, 2, 0x01);	// RG_PE1_H_PLL_FBKSEL             //Feedback clock select | ||||||
|  | +			set_pcie_phy((u32 *)(RALINK_PCIEPHY_P0P1_CTL_OFFSET + 0x49c),  0,31, 0x18000000);	// RG_PE1_H_LCDDS_PCW_NCPO         //DDS NCPO PCW (for host mode) | ||||||
|  | +			set_pcie_phy((u32 *)(RALINK_PCIEPHY_P0P1_CTL_OFFSET + 0x4a4),  0,16, 0x18d);	// RG_PE1_H_LCDDS_SSC_PRD          //DDS SSC dither period control | ||||||
|  | +			set_pcie_phy((u32 *)(RALINK_PCIEPHY_P0P1_CTL_OFFSET + 0x4a8),  0,12, 0x4a);	// RG_PE1_H_LCDDS_SSC_DELTA        //DDS SSC dither amplitude control | ||||||
|  | +			set_pcie_phy((u32 *)(RALINK_PCIEPHY_P0P1_CTL_OFFSET + 0x4a8), 16,12, 0x4a);	// RG_PE1_H_LCDDS_SSC_DELTA1       //DDS SSC dither amplitude control for initial | ||||||
|  | +		} else { | ||||||
|  | +			printk("***** Xtal 20MHz *****\n"); | ||||||
|  | +		} | ||||||
|  | +	} | ||||||
|  | +	set_pcie_phy((u32 *)(RALINK_PCIEPHY_P0P1_CTL_OFFSET + 0x4a0),  5, 1, 0x01);	// RG_PE1_LCDDS_CLK_PH_INV         //DDS clock inversion | ||||||
|  | +	set_pcie_phy((u32 *)(RALINK_PCIEPHY_P0P1_CTL_OFFSET + 0x490), 22, 2, 0x02);	// RG_PE1_H_PLL_BC                  | ||||||
|  | +	set_pcie_phy((u32 *)(RALINK_PCIEPHY_P0P1_CTL_OFFSET + 0x490), 18, 4, 0x06);	// RG_PE1_H_PLL_BP                  | ||||||
|  | +	set_pcie_phy((u32 *)(RALINK_PCIEPHY_P0P1_CTL_OFFSET + 0x490), 12, 4, 0x02);	// RG_PE1_H_PLL_IR                  | ||||||
|  | +	set_pcie_phy((u32 *)(RALINK_PCIEPHY_P0P1_CTL_OFFSET + 0x490),  8, 4, 0x01);	// RG_PE1_H_PLL_IC                  | ||||||
|  | +	set_pcie_phy((u32 *)(RALINK_PCIEPHY_P0P1_CTL_OFFSET + 0x4ac), 16, 3, 0x00);	// RG_PE1_H_PLL_BR                  | ||||||
|  | +	set_pcie_phy((u32 *)(RALINK_PCIEPHY_P0P1_CTL_OFFSET + 0x490),  1, 3, 0x02);	// RG_PE1_PLL_DIVEN                 | ||||||
|  | +	if(reg <= 5 && reg >= 3) { 	// 40MHz Xtal | ||||||
|  | +		set_pcie_phy((u32 *)(RALINK_PCIEPHY_P0P1_CTL_OFFSET + 0x414),  6, 2, 0x01);	// rg_pe1_mstckdiv		//value of da_pe1_mstckdiv when force mode enable | ||||||
|  | +		set_pcie_phy((u32 *)(RALINK_PCIEPHY_P0P1_CTL_OFFSET + 0x414),  5, 1, 0x01);	// rg_pe1_frc_mstckdiv          //force mode enable of da_pe1_mstckdiv       | ||||||
|  | +	} | ||||||
|  | +	/* Enable PHY and disable force mode */ | ||||||
|  | +	set_pcie_phy((u32 *)(RALINK_PCIEPHY_P0P1_CTL_OFFSET + 0x000),  5, 1, 0x01);	// rg_pe1_phy_en                   //Port 0 enable | ||||||
|  | +	set_pcie_phy((u32 *)(RALINK_PCIEPHY_P0P1_CTL_OFFSET + 0x100),  5, 1, 0x01);	// rg_pe1_phy_en                   //Port 1 enable | ||||||
|  | +	set_pcie_phy((u32 *)(RALINK_PCIEPHY_P0P1_CTL_OFFSET + 0x000),  4, 1, 0x00);	// rg_pe1_frc_phy_en               //Force Port 0 disable control | ||||||
|  | +	set_pcie_phy((u32 *)(RALINK_PCIEPHY_P0P1_CTL_OFFSET + 0x100),  4, 1, 0x00);	// rg_pe1_frc_phy_en               //Force Port 1 disable control | ||||||
|  | +#endif | ||||||
|  | +#if defined (CONFIG_PCIE_PORT2) | ||||||
|  | +	/* Set PCIe Port2 PHY to disable SSC */ | ||||||
|  | +	/* Debug Xtal Type */ | ||||||
|  | +	set_pcie_phy((u32 *)(RALINK_PCIEPHY_P2_CTL_OFFSET + 0x400),  8, 1, 0x01);	// rg_pe1_frc_h_xtal_type | ||||||
|  | +	set_pcie_phy((u32 *)(RALINK_PCIEPHY_P2_CTL_OFFSET + 0x400),  9, 2, 0x00);	// rg_pe1_h_xtal_type | ||||||
|  | +	set_pcie_phy((u32 *)(RALINK_PCIEPHY_P2_CTL_OFFSET + 0x000),  4, 1, 0x01);	// rg_pe1_frc_phy_en               //Force Port 0 enable control | ||||||
|  | +	set_pcie_phy((u32 *)(RALINK_PCIEPHY_P2_CTL_OFFSET + 0x000),  5, 1, 0x00);	// rg_pe1_phy_en                   //Port 0 disable | ||||||
|  | +	if(reg <= 5 && reg >= 3) { 	// 40MHz Xtal | ||||||
|  | +		set_pcie_phy((u32 *)(RALINK_PCIEPHY_P2_CTL_OFFSET + 0x490),  6, 2, 0x01);	// RG_PE1_H_PLL_PREDIV             //Pre-divider ratio (for host mode) | ||||||
|  | +	} else {			// 25MHz | 20MHz Xtal | ||||||
|  | +		set_pcie_phy((u32 *)(RALINK_PCIEPHY_P2_CTL_OFFSET + 0x490),  6, 2, 0x00);	// RG_PE1_H_PLL_PREDIV             //Pre-divider ratio (for host mode) | ||||||
|  | +		if (reg >= 6) { 	// 25MHz Xtal | ||||||
|  | +			set_pcie_phy((u32 *)(RALINK_PCIEPHY_P2_CTL_OFFSET + 0x4bc),  4, 2, 0x01);	// RG_PE1_H_PLL_FBKSEL             //Feedback clock select | ||||||
|  | +			set_pcie_phy((u32 *)(RALINK_PCIEPHY_P2_CTL_OFFSET + 0x49c),  0,31, 0x18000000);	// RG_PE1_H_LCDDS_PCW_NCPO         //DDS NCPO PCW (for host mode) | ||||||
|  | +			set_pcie_phy((u32 *)(RALINK_PCIEPHY_P2_CTL_OFFSET + 0x4a4),  0,16, 0x18d);	// RG_PE1_H_LCDDS_SSC_PRD          //DDS SSC dither period control | ||||||
|  | +			set_pcie_phy((u32 *)(RALINK_PCIEPHY_P2_CTL_OFFSET + 0x4a8),  0,12, 0x4a);	// RG_PE1_H_LCDDS_SSC_DELTA        //DDS SSC dither amplitude control | ||||||
|  | +			set_pcie_phy((u32 *)(RALINK_PCIEPHY_P2_CTL_OFFSET + 0x4a8), 16,12, 0x4a);	// RG_PE1_H_LCDDS_SSC_DELTA1       //DDS SSC dither amplitude control for initial | ||||||
|  | +		} | ||||||
|  | +	} | ||||||
|  | +	set_pcie_phy((u32 *)(RALINK_PCIEPHY_P2_CTL_OFFSET + 0x4a0),  5, 1, 0x01);	// RG_PE1_LCDDS_CLK_PH_INV         //DDS clock inversion | ||||||
|  | +	set_pcie_phy((u32 *)(RALINK_PCIEPHY_P2_CTL_OFFSET + 0x490), 22, 2, 0x02);	// RG_PE1_H_PLL_BC                  | ||||||
|  | +	set_pcie_phy((u32 *)(RALINK_PCIEPHY_P2_CTL_OFFSET + 0x490), 18, 4, 0x06);	// RG_PE1_H_PLL_BP                  | ||||||
|  | +	set_pcie_phy((u32 *)(RALINK_PCIEPHY_P2_CTL_OFFSET + 0x490), 12, 4, 0x02);	// RG_PE1_H_PLL_IR                  | ||||||
|  | +	set_pcie_phy((u32 *)(RALINK_PCIEPHY_P2_CTL_OFFSET + 0x490),  8, 4, 0x01);	// RG_PE1_H_PLL_IC                  | ||||||
|  | +	set_pcie_phy((u32 *)(RALINK_PCIEPHY_P2_CTL_OFFSET + 0x4ac), 16, 3, 0x00);	// RG_PE1_H_PLL_BR                  | ||||||
|  | +	set_pcie_phy((u32 *)(RALINK_PCIEPHY_P2_CTL_OFFSET + 0x490),  1, 3, 0x02);	// RG_PE1_PLL_DIVEN                 | ||||||
|  | +	if(reg <= 5 && reg >= 3) { 	// 40MHz Xtal | ||||||
|  | +		set_pcie_phy((u32 *)(RALINK_PCIEPHY_P2_CTL_OFFSET + 0x414),  6, 2, 0x01);	// rg_pe1_mstckdiv		//value of da_pe1_mstckdiv when force mode enable | ||||||
|  | +		set_pcie_phy((u32 *)(RALINK_PCIEPHY_P2_CTL_OFFSET + 0x414),  5, 1, 0x01);	// rg_pe1_frc_mstckdiv          //force mode enable of da_pe1_mstckdiv       | ||||||
|  | +	} | ||||||
|  | +	/* Enable PHY and disable force mode */ | ||||||
|  | +	set_pcie_phy((u32 *)(RALINK_PCIEPHY_P2_CTL_OFFSET + 0x000),  5, 1, 0x01);	// rg_pe1_phy_en                   //Port 0 enable | ||||||
|  | +	set_pcie_phy((u32 *)(RALINK_PCIEPHY_P2_CTL_OFFSET + 0x000),  4, 1, 0x00);	// rg_pe1_frc_phy_en               //Force Port 0 disable control | ||||||
|  | +#endif | ||||||
|  | +} | ||||||
|  | + | ||||||
|  | +void setup_cm_memory_region(struct resource *mem_resource) | ||||||
|  | +{ | ||||||
|  | +	resource_size_t mask; | ||||||
|  | +	if (mips_cps_numiocu(0)) { | ||||||
|  | +		/* FIXME: hardware doesn't accept mask values with 1s after | ||||||
|  | +		   0s (e.g. 0xffef), so it would be great to warn if that's | ||||||
|  | +		   about to happen */ | ||||||
|  | +		mask = ~(mem_resource->end - mem_resource->start); | ||||||
|  | + | ||||||
|  | +		write_gcr_reg1_base(mem_resource->start); | ||||||
|  | +		write_gcr_reg1_mask(mask | CM_GCR_REGn_MASK_CMTGT_IOCU0); | ||||||
|  | +		printk("PCI coherence region base: 0x%08lx, mask/settings: 0x%08lx\n", | ||||||
|  | +		       read_gcr_reg1_base(), | ||||||
|  | +		       read_gcr_reg1_mask()); | ||||||
|  | +	} | ||||||
|  | +} | ||||||
|  | + | ||||||
|  | +static int mt7621_pci_probe(struct platform_device *pdev) | ||||||
|  | +{ | ||||||
|  | +	unsigned long val = 0; | ||||||
|  | +	int i; | ||||||
|  | + | ||||||
|  | +	for (i = 0; i < 3; i++) | ||||||
|  | +		pcie_irq[i] = irq_of_parse_and_map(pdev->dev.of_node, i); | ||||||
|  | + | ||||||
|  | +	iomem_resource.start = 0; | ||||||
|  | +	iomem_resource.end= ~0; | ||||||
|  | +	ioport_resource.start= 0; | ||||||
|  | +	ioport_resource.end = ~0; | ||||||
|  | + | ||||||
|  | +#if defined (CONFIG_PCIE_PORT0) | ||||||
|  | +	val = RALINK_PCIE0_RST; | ||||||
|  | +#endif | ||||||
|  | +#if defined (CONFIG_PCIE_PORT1) | ||||||
|  | +	val |= RALINK_PCIE1_RST; | ||||||
|  | +#endif | ||||||
|  | +#if defined (CONFIG_PCIE_PORT2) | ||||||
|  | +	val |= RALINK_PCIE2_RST; | ||||||
|  | +#endif | ||||||
|  | +	ASSERT_SYSRST_PCIE(RALINK_PCIE0_RST | RALINK_PCIE1_RST | RALINK_PCIE2_RST); | ||||||
|  | +	printk("pull PCIe RST: RALINK_RSTCTRL = %x\n", RALINK_RSTCTRL); | ||||||
|  | +#if defined GPIO_PERST /* add GPIO control instead of PERST_N */ /*chhung*/ | ||||||
|  | +	*(unsigned int *)(0xbe000060) &= ~(0x3<<10 | 0x3<<3); | ||||||
|  | +	*(unsigned int *)(0xbe000060) |= 0x1<<10 | 0x1<<3; | ||||||
|  | +	mdelay(100); | ||||||
|  | +	*(unsigned int *)(0xbe000600) |= 0x1<<19 | 0x1<<8 | 0x1<<7; // use GPIO19/GPIO8/GPIO7 (PERST_N/UART_RXD3/UART_TXD3) | ||||||
|  | +	mdelay(100); | ||||||
|  | +	*(unsigned int *)(0xbe000620) &= ~(0x1<<19 | 0x1<<8 | 0x1<<7);		// clear DATA | ||||||
|  | + | ||||||
|  | +	mdelay(100); | ||||||
|  | +#else | ||||||
|  | +	*(unsigned int *)(0xbe000060) &= ~0x00000c00; | ||||||
|  | +#endif | ||||||
|  | +#if defined (CONFIG_PCIE_PORT0) | ||||||
|  | +	val = RALINK_PCIE0_RST; | ||||||
|  | +#endif | ||||||
|  | +#if defined (CONFIG_PCIE_PORT1) | ||||||
|  | +	val |= RALINK_PCIE1_RST; | ||||||
|  | +#endif | ||||||
|  | +#if defined (CONFIG_PCIE_PORT2) | ||||||
|  | +	val |= RALINK_PCIE2_RST; | ||||||
|  | +#endif | ||||||
|  | +	DEASSERT_SYSRST_PCIE(val); | ||||||
|  | +	printk("release PCIe RST: RALINK_RSTCTRL = %x\n", RALINK_RSTCTRL); | ||||||
|  | + | ||||||
|  | +	if ((*(unsigned int *)(0xbe00000c)&0xFFFF) == 0x0101) // MT7621 E2 | ||||||
|  | +		bypass_pipe_rst(); | ||||||
|  | +	set_phy_for_ssc(); | ||||||
|  | +	printk("release PCIe RST: RALINK_RSTCTRL = %x\n", RALINK_RSTCTRL); | ||||||
|  | + | ||||||
|  | +#if defined (CONFIG_PCIE_PORT0) | ||||||
|  | +	read_config(0, 0, 0, 0x70c, &val); | ||||||
|  | +	printk("Port 0 N_FTS = %x\n", (unsigned int)val); | ||||||
|  | +#endif | ||||||
|  | +#if defined (CONFIG_PCIE_PORT1) | ||||||
|  | +	read_config(0, 1, 0, 0x70c, &val); | ||||||
|  | +	printk("Port 1 N_FTS = %x\n", (unsigned int)val); | ||||||
|  | +#endif | ||||||
|  | +#if defined (CONFIG_PCIE_PORT2) | ||||||
|  | +	read_config(0, 2, 0, 0x70c, &val); | ||||||
|  | +	printk("Port 2 N_FTS = %x\n", (unsigned int)val); | ||||||
|  | +#endif | ||||||
|  | + | ||||||
|  | +	RALINK_RSTCTRL = (RALINK_RSTCTRL | RALINK_PCIE_RST); | ||||||
|  | +	RALINK_SYSCFG1 &= ~(0x30); | ||||||
|  | +	RALINK_SYSCFG1 |= (2<<4); | ||||||
|  | +	RALINK_PCIE_CLK_GEN &= 0x7fffffff; | ||||||
|  | +	RALINK_PCIE_CLK_GEN1 &= 0x80ffffff; | ||||||
|  | +	RALINK_PCIE_CLK_GEN1 |= 0xa << 24; | ||||||
|  | +	RALINK_PCIE_CLK_GEN |= 0x80000000; | ||||||
|  | +	mdelay(50); | ||||||
|  | +	RALINK_RSTCTRL = (RALINK_RSTCTRL & ~RALINK_PCIE_RST); | ||||||
|  | +	 | ||||||
|  | + | ||||||
|  | +#if defined GPIO_PERST /* add GPIO control instead of PERST_N */  /*chhung*/ | ||||||
|  | +	*(unsigned int *)(0xbe000620) |= 0x1<<19 | 0x1<<8 | 0x1<<7;		// set DATA | ||||||
|  | +	mdelay(100); | ||||||
|  | +#else | ||||||
|  | +	RALINK_PCI_PCICFG_ADDR &= ~(1<<1); //de-assert PERST | ||||||
|  | +#endif | ||||||
|  | +	mdelay(500); | ||||||
|  | + | ||||||
|  | + | ||||||
|  | +	mdelay(500); | ||||||
|  | +#if defined (CONFIG_PCIE_PORT0) | ||||||
|  | +	if(( RALINK_PCI0_STATUS & 0x1) == 0) | ||||||
|  | +	{ | ||||||
|  | +		printk("PCIE0 no card, disable it(RST&CLK)\n"); | ||||||
|  | +		ASSERT_SYSRST_PCIE(RALINK_PCIE0_RST); | ||||||
|  | +		RALINK_CLKCFG1 = (RALINK_CLKCFG1 & ~RALINK_PCIE0_CLK_EN); | ||||||
|  | +		pcie_link_status &= ~(1<<0); | ||||||
|  | +	} else { | ||||||
|  | +		pcie_link_status |= 1<<0; | ||||||
|  | +		RALINK_PCI_PCIMSK_ADDR |= (1<<20); // enable pcie1 interrupt | ||||||
|  | +	} | ||||||
|  | +#endif | ||||||
|  | +#if defined (CONFIG_PCIE_PORT1) | ||||||
|  | +	if(( RALINK_PCI1_STATUS & 0x1) == 0) | ||||||
|  | +	{ | ||||||
|  | +		printk("PCIE1 no card, disable it(RST&CLK)\n"); | ||||||
|  | +		ASSERT_SYSRST_PCIE(RALINK_PCIE1_RST); | ||||||
|  | +		RALINK_CLKCFG1 = (RALINK_CLKCFG1 & ~RALINK_PCIE1_CLK_EN); | ||||||
|  | +		pcie_link_status &= ~(1<<1); | ||||||
|  | +	} else { | ||||||
|  | +		pcie_link_status |= 1<<1; | ||||||
|  | +		RALINK_PCI_PCIMSK_ADDR |= (1<<21); // enable pcie1 interrupt | ||||||
|  | +	} | ||||||
|  | +#endif | ||||||
|  | +#if defined (CONFIG_PCIE_PORT2) | ||||||
|  | +	if (( RALINK_PCI2_STATUS & 0x1) == 0) { | ||||||
|  | +		printk("PCIE2 no card, disable it(RST&CLK)\n"); | ||||||
|  | +		ASSERT_SYSRST_PCIE(RALINK_PCIE2_RST); | ||||||
|  | +		RALINK_CLKCFG1 = (RALINK_CLKCFG1 & ~RALINK_PCIE2_CLK_EN); | ||||||
|  | +		pcie_link_status &= ~(1<<2); | ||||||
|  | +	} else { | ||||||
|  | +		pcie_link_status |= 1<<2; | ||||||
|  | +		RALINK_PCI_PCIMSK_ADDR |= (1<<22); // enable pcie2 interrupt | ||||||
|  | +	} | ||||||
|  | +#endif | ||||||
|  | +	if (pcie_link_status == 0) | ||||||
|  | +		return 0; | ||||||
|  | + | ||||||
|  | +/* | ||||||
|  | +pcie(2/1/0) link status	pcie2_num	pcie1_num	pcie0_num | ||||||
|  | +3'b000			x		x		x | ||||||
|  | +3'b001			x		x		0 | ||||||
|  | +3'b010			x		0		x | ||||||
|  | +3'b011			x		1		0 | ||||||
|  | +3'b100			0		x		x | ||||||
|  | +3'b101			1		x		0 | ||||||
|  | +3'b110			1		0		x | ||||||
|  | +3'b111			2		1		0 | ||||||
|  | +*/ | ||||||
|  | +	switch(pcie_link_status) { | ||||||
|  | +	case 2: | ||||||
|  | +		RALINK_PCI_PCICFG_ADDR &= ~0x00ff0000; | ||||||
|  | +		RALINK_PCI_PCICFG_ADDR |= 0x1 << 16;	//port0 | ||||||
|  | +		RALINK_PCI_PCICFG_ADDR |= 0x0 << 20;	//port1 | ||||||
|  | +		break; | ||||||
|  | +	case 4: | ||||||
|  | +		RALINK_PCI_PCICFG_ADDR &= ~0x0fff0000; | ||||||
|  | +		RALINK_PCI_PCICFG_ADDR |= 0x1 << 16;	//port0 | ||||||
|  | +		RALINK_PCI_PCICFG_ADDR |= 0x2 << 20;	//port1 | ||||||
|  | +		RALINK_PCI_PCICFG_ADDR |= 0x0 << 24;	//port2 | ||||||
|  | +		break; | ||||||
|  | +	case 5: | ||||||
|  | +		RALINK_PCI_PCICFG_ADDR &= ~0x0fff0000; | ||||||
|  | +		RALINK_PCI_PCICFG_ADDR |= 0x0 << 16;	//port0 | ||||||
|  | +		RALINK_PCI_PCICFG_ADDR |= 0x2 << 20;	//port1 | ||||||
|  | +		RALINK_PCI_PCICFG_ADDR |= 0x1 << 24;	//port2 | ||||||
|  | +		break; | ||||||
|  | +	case 6: | ||||||
|  | +		RALINK_PCI_PCICFG_ADDR &= ~0x0fff0000; | ||||||
|  | +		RALINK_PCI_PCICFG_ADDR |= 0x2 << 16;	//port0 | ||||||
|  | +		RALINK_PCI_PCICFG_ADDR |= 0x0 << 20;	//port1 | ||||||
|  | +		RALINK_PCI_PCICFG_ADDR |= 0x1 << 24;	//port2 | ||||||
|  | +		break; | ||||||
|  | +	} | ||||||
|  | +	printk(" -> %x\n", RALINK_PCI_PCICFG_ADDR); | ||||||
|  | +	//printk(" RALINK_PCI_ARBCTL = %x\n", RALINK_PCI_ARBCTL); | ||||||
|  | + | ||||||
|  | +/* | ||||||
|  | +	ioport_resource.start = mt7621_res_pci_io1.start; | ||||||
|  | +  	ioport_resource.end = mt7621_res_pci_io1.end; | ||||||
|  | +*/ | ||||||
|  | + | ||||||
|  | +	RALINK_PCI_MEMBASE = 0xffffffff; //RALINK_PCI_MM_MAP_BASE; | ||||||
|  | +	RALINK_PCI_IOBASE = RALINK_PCI_IO_MAP_BASE; | ||||||
|  | + | ||||||
|  | +#if defined (CONFIG_PCIE_PORT0) | ||||||
|  | +	//PCIe0 | ||||||
|  | +	if((pcie_link_status & 0x1) != 0) { | ||||||
|  | +		RALINK_PCI0_BAR0SETUP_ADDR = 0x7FFF0001;	//open 7FFF:2G; ENABLE | ||||||
|  | +		RALINK_PCI0_IMBASEBAR0_ADDR = MEMORY_BASE; | ||||||
|  | +		RALINK_PCI0_CLASS = 0x06040001; | ||||||
|  | +		printk("PCIE0 enabled\n"); | ||||||
|  | +	} | ||||||
|  | +#endif | ||||||
|  | +#if defined (CONFIG_PCIE_PORT1) | ||||||
|  | +	//PCIe1 | ||||||
|  | +	if ((pcie_link_status & 0x2) != 0) { | ||||||
|  | +		RALINK_PCI1_BAR0SETUP_ADDR = 0x7FFF0001;	//open 7FFF:2G; ENABLE | ||||||
|  | +		RALINK_PCI1_IMBASEBAR0_ADDR = MEMORY_BASE; | ||||||
|  | +		RALINK_PCI1_CLASS = 0x06040001; | ||||||
|  | +		printk("PCIE1 enabled\n"); | ||||||
|  | +	} | ||||||
|  | +#endif | ||||||
|  | +#if defined (CONFIG_PCIE_PORT2) | ||||||
|  | +	//PCIe2 | ||||||
|  | +	if ((pcie_link_status & 0x4) != 0) { | ||||||
|  | +		RALINK_PCI2_BAR0SETUP_ADDR = 0x7FFF0001;	//open 7FFF:2G; ENABLE | ||||||
|  | +		RALINK_PCI2_IMBASEBAR0_ADDR = MEMORY_BASE; | ||||||
|  | +		RALINK_PCI2_CLASS = 0x06040001; | ||||||
|  | +		printk("PCIE2 enabled\n"); | ||||||
|  | +	} | ||||||
|  | +#endif | ||||||
|  | + | ||||||
|  | + | ||||||
|  | +	switch(pcie_link_status) { | ||||||
|  | +	case 7: | ||||||
|  | +		read_config(0, 2, 0, 0x4, &val); | ||||||
|  | +		write_config(0, 2, 0, 0x4, val|0x4); | ||||||
|  | +		// write_config(0, 1, 0, 0x4, val|0x7); | ||||||
|  | +		read_config(0, 2, 0, 0x70c, &val); | ||||||
|  | +		val &= ~(0xff)<<8; | ||||||
|  | +		val |= 0x50<<8; | ||||||
|  | +		write_config(0, 2, 0, 0x70c, val); | ||||||
|  | +	case 3: | ||||||
|  | +	case 5: | ||||||
|  | +	case 6: | ||||||
|  | +		read_config(0, 1, 0, 0x4, &val); | ||||||
|  | +		write_config(0, 1, 0, 0x4, val|0x4); | ||||||
|  | +		// write_config(0, 1, 0, 0x4, val|0x7); | ||||||
|  | +		read_config(0, 1, 0, 0x70c, &val); | ||||||
|  | +		val &= ~(0xff)<<8; | ||||||
|  | +		val |= 0x50<<8; | ||||||
|  | +		write_config(0, 1, 0, 0x70c, val); | ||||||
|  | +	default: | ||||||
|  | +		read_config(0, 0, 0, 0x4, &val); | ||||||
|  | +		write_config(0, 0, 0, 0x4, val|0x4); //bus master enable | ||||||
|  | +		// write_config(0, 0, 0, 0x4, val|0x7); //bus master enable | ||||||
|  | +		read_config(0, 0, 0, 0x70c, &val); | ||||||
|  | +		val &= ~(0xff)<<8; | ||||||
|  | +		val |= 0x50<<8; | ||||||
|  | +		write_config(0, 0, 0, 0x70c, val); | ||||||
|  | +	} | ||||||
|  | + | ||||||
|  | +	pci_load_of_ranges(&mt7621_controller, pdev->dev.of_node); | ||||||
|  | +	setup_cm_memory_region(mt7621_controller.mem_resource); | ||||||
|  | +	register_pci_controller(&mt7621_controller); | ||||||
|  | +	return 0; | ||||||
|  | + | ||||||
|  | +} | ||||||
|  | + | ||||||
|  | +int pcibios_plat_dev_init(struct pci_dev *dev) | ||||||
|  | +{ | ||||||
|  | +	return 0; | ||||||
|  | +} | ||||||
|  | + | ||||||
|  | +static const struct of_device_id mt7621_pci_ids[] = { | ||||||
|  | +	{ .compatible = "mediatek,mt7621-pci" }, | ||||||
|  | +	{}, | ||||||
|  | +}; | ||||||
|  | +MODULE_DEVICE_TABLE(of, mt7621_pci_ids); | ||||||
|  | + | ||||||
|  | +static struct platform_driver mt7621_pci_driver = { | ||||||
|  | +	.probe = mt7621_pci_probe, | ||||||
|  | +	.driver = { | ||||||
|  | +		.name = "mt7621-pci", | ||||||
|  | +		.owner = THIS_MODULE, | ||||||
|  | +		.of_match_table = of_match_ptr(mt7621_pci_ids), | ||||||
|  | +	}, | ||||||
|  | +}; | ||||||
|  | + | ||||||
|  | +static int __init mt7621_pci_init(void) | ||||||
|  | +{ | ||||||
|  | +	return platform_driver_register(&mt7621_pci_driver); | ||||||
|  | +} | ||||||
|  | + | ||||||
|  | +arch_initcall(mt7621_pci_init); | ||||||
| @@ -0,0 +1,82 @@ | |||||||
|  | From ce3d4a4111a5f7e6b4e74bceae5faa6ce388e8ec Mon Sep 17 00:00:00 2001 | ||||||
|  | From: John Crispin <blogic@openwrt.org> | ||||||
|  | Date: Sun, 14 Jul 2013 23:08:11 +0200 | ||||||
|  | Subject: [PATCH 05/53] MIPS: use set_mode() to enable/disable the cevt-r4k | ||||||
|  |  irq | ||||||
|  |  | ||||||
|  | Signed-off-by: John Crispin <blogic@openwrt.org> | ||||||
|  | --- | ||||||
|  |  arch/mips/ralink/Kconfig |    5 +++++ | ||||||
|  |  1 file changed, 5 insertions(+) | ||||||
|  |  | ||||||
|  | --- a/arch/mips/ralink/Kconfig | ||||||
|  | +++ b/arch/mips/ralink/Kconfig | ||||||
|  | @@ -1,12 +1,17 @@ | ||||||
|  |  # SPDX-License-Identifier: GPL-2.0 | ||||||
|  |  if RALINK | ||||||
|  |   | ||||||
|  | +config CEVT_SYSTICK_QUIRK | ||||||
|  | +	bool | ||||||
|  | +	default n | ||||||
|  | + | ||||||
|  |  config CLKEVT_RT3352 | ||||||
|  |  	bool | ||||||
|  |  	depends on SOC_RT305X || SOC_MT7620 | ||||||
|  |  	default y | ||||||
|  |  	select TIMER_OF | ||||||
|  |  	select CLKSRC_MMIO | ||||||
|  | +	select CEVT_SYSTICK_QUIRK | ||||||
|  |   | ||||||
|  |  config RALINK_ILL_ACC | ||||||
|  |  	bool | ||||||
|  | --- a/arch/mips/kernel/cevt-r4k.c | ||||||
|  | +++ b/arch/mips/kernel/cevt-r4k.c | ||||||
|  | @@ -15,6 +15,26 @@ | ||||||
|  |  #include <asm/time.h> | ||||||
|  |  #include <asm/cevt-r4k.h> | ||||||
|  |   | ||||||
|  | +static int mips_state_oneshot(struct clock_event_device *evt) | ||||||
|  | +{ | ||||||
|  | +	if (!cp0_timer_irq_installed) { | ||||||
|  | +		cp0_timer_irq_installed = 1; | ||||||
|  | +		setup_irq(evt->irq, &c0_compare_irqaction); | ||||||
|  | +	} | ||||||
|  | + | ||||||
|  | +	return 0; | ||||||
|  | +} | ||||||
|  | + | ||||||
|  | +static int mips_state_shutdown(struct clock_event_device *evt) | ||||||
|  | +{ | ||||||
|  | +	if (cp0_timer_irq_installed) { | ||||||
|  | +		cp0_timer_irq_installed = 0; | ||||||
|  | +		remove_irq(evt->irq, &c0_compare_irqaction); | ||||||
|  | +	} | ||||||
|  | + | ||||||
|  | +	return 0; | ||||||
|  | +} | ||||||
|  | + | ||||||
|  |  static int mips_next_event(unsigned long delta, | ||||||
|  |  			   struct clock_event_device *evt) | ||||||
|  |  { | ||||||
|  | @@ -281,17 +301,21 @@ int r4k_clockevent_init(void) | ||||||
|  |  	cd->rating		= 300; | ||||||
|  |  	cd->irq			= irq; | ||||||
|  |  	cd->cpumask		= cpumask_of(cpu); | ||||||
|  | +	cd->set_state_shutdown	= mips_state_shutdown; | ||||||
|  | +	cd->set_state_oneshot	= mips_state_oneshot; | ||||||
|  |  	cd->set_next_event	= mips_next_event; | ||||||
|  |  	cd->event_handler	= mips_event_handler; | ||||||
|  |   | ||||||
|  |  	clockevents_config_and_register(cd, mips_hpt_frequency, min_delta, 0x7fffffff); | ||||||
|  |   | ||||||
|  | +#ifndef CONFIG_CEVT_SYSTICK_QUIRK | ||||||
|  |  	if (cp0_timer_irq_installed) | ||||||
|  |  		return 0; | ||||||
|  |   | ||||||
|  |  	cp0_timer_irq_installed = 1; | ||||||
|  |   | ||||||
|  |  	setup_irq(irq, &c0_compare_irqaction); | ||||||
|  | +#endif | ||||||
|  |   | ||||||
|  |  	return 0; | ||||||
|  |  } | ||||||
| @@ -0,0 +1,200 @@ | |||||||
|  | From bd30f19a006fb52bac80c6463c49dd2f4159f4ac Mon Sep 17 00:00:00 2001 | ||||||
|  | From: John Crispin <blogic@openwrt.org> | ||||||
|  | Date: Sun, 28 Jul 2013 16:26:41 +0200 | ||||||
|  | Subject: [PATCH 06/53] MIPS: ralink: add cpu frequency scaling | ||||||
|  |  | ||||||
|  | This feature will break udelay() and cause the delay loop to have longer delays | ||||||
|  | when the frequency is scaled causing a performance hit. | ||||||
|  |  | ||||||
|  | Signed-off-by: John Crispin <blogic@openwrt.org> | ||||||
|  | --- | ||||||
|  |  arch/mips/ralink/cevt-rt3352.c |   38 ++++++++++++++++++++++++++++++++++++++ | ||||||
|  |  1 file changed, 38 insertions(+) | ||||||
|  |  | ||||||
|  | --- a/arch/mips/ralink/cevt-rt3352.c | ||||||
|  | +++ b/arch/mips/ralink/cevt-rt3352.c | ||||||
|  | @@ -29,6 +29,10 @@ | ||||||
|  |  /* enable the counter */ | ||||||
|  |  #define CFG_CNT_EN		0x1 | ||||||
|  |   | ||||||
|  | +/* mt7620 frequency scaling defines */ | ||||||
|  | +#define CLK_LUT_CFG	0x40 | ||||||
|  | +#define SLEEP_EN	BIT(31) | ||||||
|  | + | ||||||
|  |  struct systick_device { | ||||||
|  |  	void __iomem *membase; | ||||||
|  |  	struct clock_event_device dev; | ||||||
|  | @@ -36,21 +40,53 @@ struct systick_device { | ||||||
|  |  	int freq_scale; | ||||||
|  |  }; | ||||||
|  |   | ||||||
|  | +static void (*systick_freq_scaling)(struct systick_device *sdev, int status); | ||||||
|  | + | ||||||
|  |  static int systick_set_oneshot(struct clock_event_device *evt); | ||||||
|  |  static int systick_shutdown(struct clock_event_device *evt); | ||||||
|  |   | ||||||
|  | +static inline void mt7620_freq_scaling(struct systick_device *sdev, int status) | ||||||
|  | +{ | ||||||
|  | +	if (sdev->freq_scale == status) | ||||||
|  | +		return; | ||||||
|  | + | ||||||
|  | +	sdev->freq_scale = status; | ||||||
|  | + | ||||||
|  | +	pr_info("%s: %s autosleep mode\n", sdev->dev.name, | ||||||
|  | +			(status) ? ("enable") : ("disable")); | ||||||
|  | +	if (status) | ||||||
|  | +		rt_sysc_w32(rt_sysc_r32(CLK_LUT_CFG) | SLEEP_EN, CLK_LUT_CFG); | ||||||
|  | +	else | ||||||
|  | +		rt_sysc_w32(rt_sysc_r32(CLK_LUT_CFG) & ~SLEEP_EN, CLK_LUT_CFG); | ||||||
|  | +} | ||||||
|  | + | ||||||
|  | +static inline unsigned int read_count(struct systick_device *sdev) | ||||||
|  | +{ | ||||||
|  | +	return ioread32(sdev->membase + SYSTICK_COUNT); | ||||||
|  | +} | ||||||
|  | + | ||||||
|  | +static inline unsigned int read_compare(struct systick_device *sdev) | ||||||
|  | +{ | ||||||
|  | +	return ioread32(sdev->membase + SYSTICK_COMPARE); | ||||||
|  | +} | ||||||
|  | + | ||||||
|  | +static inline void write_compare(struct systick_device *sdev, unsigned int val) | ||||||
|  | +{ | ||||||
|  | +	iowrite32(val, sdev->membase + SYSTICK_COMPARE); | ||||||
|  | +} | ||||||
|  | + | ||||||
|  |  static int systick_next_event(unsigned long delta, | ||||||
|  |  				struct clock_event_device *evt) | ||||||
|  |  { | ||||||
|  |  	struct systick_device *sdev; | ||||||
|  | -	u32 count; | ||||||
|  | +	int res; | ||||||
|  |   | ||||||
|  |  	sdev = container_of(evt, struct systick_device, dev); | ||||||
|  | -	count = ioread32(sdev->membase + SYSTICK_COUNT); | ||||||
|  | -	count = (count + delta) % SYSTICK_FREQ; | ||||||
|  | -	iowrite32(count, sdev->membase + SYSTICK_COMPARE); | ||||||
|  | +	delta += read_count(sdev); | ||||||
|  | +	write_compare(sdev, delta); | ||||||
|  | +	res = ((int)(read_count(sdev) - delta) >= 0) ? -ETIME : 0; | ||||||
|  |   | ||||||
|  | -	return 0; | ||||||
|  | +	return res; | ||||||
|  |  } | ||||||
|  |   | ||||||
|  |  static void systick_event_handler(struct clock_event_device *dev) | ||||||
|  | @@ -60,20 +96,25 @@ static void systick_event_handler(struct | ||||||
|  |   | ||||||
|  |  static irqreturn_t systick_interrupt(int irq, void *dev_id) | ||||||
|  |  { | ||||||
|  | -	struct clock_event_device *dev = (struct clock_event_device *) dev_id; | ||||||
|  | +	int ret = 0; | ||||||
|  | +	struct clock_event_device *cdev; | ||||||
|  | +	struct systick_device *sdev; | ||||||
|  |   | ||||||
|  | -	dev->event_handler(dev); | ||||||
|  | +	if (read_c0_cause() & STATUSF_IP7) { | ||||||
|  | +		cdev = (struct clock_event_device *) dev_id; | ||||||
|  | +		sdev = container_of(cdev, struct systick_device, dev); | ||||||
|  | + | ||||||
|  | +		/* Clear Count/Compare Interrupt */ | ||||||
|  | +		write_compare(sdev, read_compare(sdev)); | ||||||
|  | +		cdev->event_handler(cdev); | ||||||
|  | +		ret = 1; | ||||||
|  | +	} | ||||||
|  |   | ||||||
|  | -	return IRQ_HANDLED; | ||||||
|  | +	return IRQ_RETVAL(ret); | ||||||
|  |  } | ||||||
|  |   | ||||||
|  |  static struct systick_device systick = { | ||||||
|  |  	.dev = { | ||||||
|  | -		/* | ||||||
|  | -		 * cevt-r4k uses 300, make sure systick | ||||||
|  | -		 * gets used if available | ||||||
|  | -		 */ | ||||||
|  | -		.rating			= 310, | ||||||
|  |  		.features		= CLOCK_EVT_FEAT_ONESHOT, | ||||||
|  |  		.set_next_event		= systick_next_event, | ||||||
|  |  		.set_state_shutdown	= systick_shutdown, | ||||||
|  | @@ -95,9 +136,15 @@ static int systick_shutdown(struct clock | ||||||
|  |  	sdev = container_of(evt, struct systick_device, dev); | ||||||
|  |   | ||||||
|  |  	if (sdev->irq_requested) | ||||||
|  | -		free_irq(systick.dev.irq, &systick_irqaction); | ||||||
|  | +		remove_irq(systick.dev.irq, &systick_irqaction); | ||||||
|  |  	sdev->irq_requested = 0; | ||||||
|  | -	iowrite32(0, systick.membase + SYSTICK_CONFIG); | ||||||
|  | +	iowrite32(CFG_CNT_EN, systick.membase + SYSTICK_CONFIG); | ||||||
|  | + | ||||||
|  | +	if (systick_freq_scaling) | ||||||
|  | +		systick_freq_scaling(sdev, 0); | ||||||
|  | + | ||||||
|  | +	if (systick_freq_scaling) | ||||||
|  | +		systick_freq_scaling(sdev, 1); | ||||||
|  |   | ||||||
|  |  	return 0; | ||||||
|  |  } | ||||||
|  | @@ -117,34 +164,48 @@ static int systick_set_oneshot(struct cl | ||||||
|  |  	return 0; | ||||||
|  |  } | ||||||
|  |   | ||||||
|  | +static const struct of_device_id systick_match[] = { | ||||||
|  | +	{ .compatible = "ralink,mt7620a-systick", .data = mt7620_freq_scaling}, | ||||||
|  | +	{}, | ||||||
|  | +}; | ||||||
|  | + | ||||||
|  |  static int __init ralink_systick_init(struct device_node *np) | ||||||
|  |  { | ||||||
|  | +	const struct of_device_id *match; | ||||||
|  | +	int rating = 200; | ||||||
|  |  	int ret; | ||||||
|  |   | ||||||
|  |  	systick.membase = of_iomap(np, 0); | ||||||
|  |  	if (!systick.membase) | ||||||
|  |  		return -ENXIO; | ||||||
|  |   | ||||||
|  | -	systick_irqaction.name = np->name; | ||||||
|  | -	systick.dev.name = np->name; | ||||||
|  | -	clockevents_calc_mult_shift(&systick.dev, SYSTICK_FREQ, 60); | ||||||
|  | -	systick.dev.max_delta_ns = clockevent_delta2ns(0x7fff, &systick.dev); | ||||||
|  | -	systick.dev.max_delta_ticks = 0x7fff; | ||||||
|  | -	systick.dev.min_delta_ns = clockevent_delta2ns(0x3, &systick.dev); | ||||||
|  | -	systick.dev.min_delta_ticks = 0x3; | ||||||
|  | +	match = of_match_node(systick_match, np); | ||||||
|  | +	if (match) { | ||||||
|  | +		systick_freq_scaling = match->data; | ||||||
|  | +		/* | ||||||
|  | +		 * cevt-r4k uses 300, make sure systick | ||||||
|  | +		 * gets used if available | ||||||
|  | +		 */ | ||||||
|  | +		rating = 310; | ||||||
|  | +	} | ||||||
|  | + | ||||||
|  | +	/* enable counter than register clock source */ | ||||||
|  | +	iowrite32(CFG_CNT_EN, systick.membase + SYSTICK_CONFIG); | ||||||
|  | +	clocksource_mmio_init(systick.membase + SYSTICK_COUNT, np->name, | ||||||
|  | +			SYSTICK_FREQ, rating, 16, clocksource_mmio_readl_up); | ||||||
|  | + | ||||||
|  | +	/* register clock event */ | ||||||
|  |  	systick.dev.irq = irq_of_parse_and_map(np, 0); | ||||||
|  |  	if (!systick.dev.irq) { | ||||||
|  |  		pr_err("%s: request_irq failed", np->name); | ||||||
|  |  		return -EINVAL; | ||||||
|  |  	} | ||||||
|  |   | ||||||
|  | -	ret = clocksource_mmio_init(systick.membase + SYSTICK_COUNT, np->name, | ||||||
|  | -				    SYSTICK_FREQ, 301, 16, | ||||||
|  | -				    clocksource_mmio_readl_up); | ||||||
|  | -	if (ret) | ||||||
|  | -		return ret; | ||||||
|  | - | ||||||
|  | -	clockevents_register_device(&systick.dev); | ||||||
|  | +	systick_irqaction.name = np->name; | ||||||
|  | +	systick.dev.name = np->name; | ||||||
|  | +	systick.dev.rating = rating; | ||||||
|  | +	systick.dev.cpumask = cpumask_of(0); | ||||||
|  | +	clockevents_config_and_register(&systick.dev, SYSTICK_FREQ, 0x3, 0x7fff); | ||||||
|  |   | ||||||
|  |  	pr_info("%s: running - mult: %d, shift: %d\n", | ||||||
|  |  			np->name, systick.dev.mult, systick.dev.shift); | ||||||
| @@ -0,0 +1,21 @@ | |||||||
|  | From 67b7bff0fd364c194e653f69baa623ba2141bd4c Mon Sep 17 00:00:00 2001 | ||||||
|  | From: John Crispin <blogic@openwrt.org> | ||||||
|  | Date: Mon, 4 Aug 2014 18:46:02 +0200 | ||||||
|  | Subject: [PATCH 07/53] MIPS: ralink: copy the commandline from the devicetree | ||||||
|  |  | ||||||
|  | Signed-off-by: John Crispin <blogic@openwrt.org> | ||||||
|  | --- | ||||||
|  |  arch/mips/ralink/of.c |    2 ++ | ||||||
|  |  1 file changed, 2 insertions(+) | ||||||
|  |  | ||||||
|  | --- a/arch/mips/ralink/of.c | ||||||
|  | +++ b/arch/mips/ralink/of.c | ||||||
|  | @@ -82,6 +82,8 @@ void __init plat_mem_setup(void) | ||||||
|  |   | ||||||
|  |  	__dt_setup_arch(dtb); | ||||||
|  |   | ||||||
|  | +	strlcpy(arcs_cmdline, boot_command_line, COMMAND_LINE_SIZE); | ||||||
|  | + | ||||||
|  |  	of_scan_flat_dt(early_init_dt_find_memory, NULL); | ||||||
|  |  	if (memory_dtb) | ||||||
|  |  		of_scan_flat_dt(early_init_dt_scan_memory, NULL); | ||||||
| @@ -0,0 +1,28 @@ | |||||||
|  | From 7768798964eb0e4f95eaecffb93b5d0ca28a38af Mon Sep 17 00:00:00 2001 | ||||||
|  | From: Daniel Golle <daniel@makrotopia.org> | ||||||
|  | Date: Sat, 3 Jun 2017 20:00:03 +0200 | ||||||
|  | Subject: [PATCH] MIPS: pci-mt7620: enabled PCIe on MT7688 | ||||||
|  | To: linux-mips@linux-mips.org, | ||||||
|  |     John Crispin <john@phrozen.org> | ||||||
|  | Cc: Wei Yongjun <yongjun_wei@trendmicro.com.cn>, | ||||||
|  |     Ralf Baechle <ralf@linux-mips.org>, | ||||||
|  |     linux-mediatek@lists.infradead.org | ||||||
|  |  | ||||||
|  | Use PCIe support for MT7628AN also on MT7688. | ||||||
|  | Tested on WRTNODE2R. | ||||||
|  |  | ||||||
|  | Signed-off-by: Daniel Golle <daniel@makrotopia.org> | ||||||
|  | --- | ||||||
|  |  arch/mips/pci/pci-mt7620.c | 1 + | ||||||
|  |  1 file changed, 1 insertion(+) | ||||||
|  |  | ||||||
|  | --- a/arch/mips/pci/pci-mt7620.c | ||||||
|  | +++ b/arch/mips/pci/pci-mt7620.c | ||||||
|  | @@ -316,6 +316,7 @@ static int mt7620_pci_probe(struct platf | ||||||
|  |  		break; | ||||||
|  |   | ||||||
|  |  	case MT762X_SOC_MT7628AN: | ||||||
|  | +	case MT762X_SOC_MT7688: | ||||||
|  |  		if (mt7628_pci_hw_init(pdev)) | ||||||
|  |  			return -1; | ||||||
|  |  		break; | ||||||
| @@ -0,0 +1,28 @@ | |||||||
|  | From 5ede027f6c4a57ed25da872420508b7f1168b36b Mon Sep 17 00:00:00 2001 | ||||||
|  | From: John Crispin <blogic@openwrt.org> | ||||||
|  | Date: Mon, 7 Dec 2015 17:15:32 +0100 | ||||||
|  | Subject: [PATCH 13/53] owrt: hack: fix mt7688 cache issue | ||||||
|  |  | ||||||
|  | Signed-off-by: John Crispin <blogic@openwrt.org> | ||||||
|  | --- | ||||||
|  |  arch/mips/kernel/setup.c |    2 +- | ||||||
|  |  1 file changed, 1 insertion(+), 1 deletion(-) | ||||||
|  |  | ||||||
|  | --- a/arch/mips/kernel/setup.c | ||||||
|  | +++ b/arch/mips/kernel/setup.c | ||||||
|  | @@ -910,7 +910,6 @@ static void __init arch_mem_init(char ** | ||||||
|  |  				crashk_res.end - crashk_res.start + 1, | ||||||
|  |  				BOOTMEM_DEFAULT); | ||||||
|  |  #endif | ||||||
|  | -	device_tree_init(); | ||||||
|  |  	sparse_init(); | ||||||
|  |  	plat_swiotlb_setup(); | ||||||
|  |   | ||||||
|  | @@ -1026,6 +1025,7 @@ void __init setup_arch(char **cmdline_p) | ||||||
|  |   | ||||||
|  |  	cpu_cache_init(); | ||||||
|  |  	paging_init(); | ||||||
|  | +	device_tree_init(); | ||||||
|  |  } | ||||||
|  |   | ||||||
|  |  unsigned long kernelsp[NR_CPUS]; | ||||||
| @@ -0,0 +1,25 @@ | |||||||
|  | From 9e6ce539092a1dd605a20bf73c655a9de58d8641 Mon Sep 17 00:00:00 2001 | ||||||
|  | From: John Crispin <blogic@openwrt.org> | ||||||
|  | Date: Mon, 7 Dec 2015 17:18:05 +0100 | ||||||
|  | Subject: [PATCH 15/53] arch: mips: do not select illegal access driver by | ||||||
|  |  default | ||||||
|  |  | ||||||
|  | Signed-off-by: John Crispin <blogic@openwrt.org> | ||||||
|  | --- | ||||||
|  |  arch/mips/ralink/Kconfig |    4 ++-- | ||||||
|  |  1 file changed, 2 insertions(+), 2 deletions(-) | ||||||
|  |  | ||||||
|  | --- a/arch/mips/ralink/Kconfig | ||||||
|  | +++ b/arch/mips/ralink/Kconfig | ||||||
|  | @@ -14,9 +14,9 @@ config CLKEVT_RT3352 | ||||||
|  |  	select CEVT_SYSTICK_QUIRK | ||||||
|  |   | ||||||
|  |  config RALINK_ILL_ACC | ||||||
|  | -	bool | ||||||
|  | +	bool "illegal access irq" | ||||||
|  |  	depends on SOC_RT305X | ||||||
|  | -	default y | ||||||
|  | +	default n | ||||||
|  |   | ||||||
|  |  config IRQ_INTC | ||||||
|  |  	bool | ||||||
| @@ -0,0 +1,165 @@ | |||||||
|  | From 4267880319bc1a2270d352e0ded6d6386242a7ef Mon Sep 17 00:00:00 2001 | ||||||
|  | From: John Crispin <blogic@openwrt.org> | ||||||
|  | Date: Tue, 12 Aug 2014 20:49:27 +0200 | ||||||
|  | Subject: [PATCH 24/53] GPIO: add named gpio exports | ||||||
|  |  | ||||||
|  | Signed-off-by: John Crispin <blogic@openwrt.org> | ||||||
|  | --- | ||||||
|  |  drivers/gpio/gpiolib-of.c     |   68 +++++++++++++++++++++++++++++++++++++++++ | ||||||
|  |  drivers/gpio/gpiolib-sysfs.c  |   10 +++++- | ||||||
|  |  include/asm-generic/gpio.h    |    6 ++++ | ||||||
|  |  include/linux/gpio/consumer.h |    8 +++++ | ||||||
|  |  4 files changed, 91 insertions(+), 1 deletion(-) | ||||||
|  |  | ||||||
|  | --- 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" | ||||||
|  |   | ||||||
|  | @@ -513,3 +515,68 @@ 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 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 (!gpio_is_valid(gpio)) | ||||||
|  | +				return gpio; | ||||||
|  | + | ||||||
|  | +			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), | ||||||
|  | +	}, | ||||||
|  | +	.probe		= of_gpio_export_probe, | ||||||
|  | +}; | ||||||
|  | + | ||||||
|  | +module_platform_driver(gpio_export_driver); | ||||||
|  | --- a/drivers/gpio/gpiolib-sysfs.c | ||||||
|  | +++ b/drivers/gpio/gpiolib-sysfs.c | ||||||
|  | @@ -553,7 +553,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; | ||||||
|  |  	struct gpio_device	*gdev; | ||||||
|  | @@ -615,6 +615,8 @@ int gpiod_export(struct gpio_desc *desc, | ||||||
|  |  	offset = gpio_chip_hwgpio(desc); | ||||||
|  |  	if (chip->names && chip->names[offset]) | ||||||
|  |  		ioname = chip->names[offset]; | ||||||
|  | +	if (name) | ||||||
|  | +		ioname = name; | ||||||
|  |   | ||||||
|  |  	dev = device_create_with_groups(&gpio_class, &gdev->dev, | ||||||
|  |  					MKDEV(0, 0), data, gpio_groups, | ||||||
|  | @@ -636,6 +638,12 @@ err_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 *desc) | ||||||
|  | --- a/include/asm-generic/gpio.h | ||||||
|  | +++ b/include/asm-generic/gpio.h | ||||||
|  | @@ -127,6 +127,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 | ||||||
|  | @@ -451,6 +451,7 @@ struct gpio_desc *devm_fwnode_get_gpiod_ | ||||||
|  |   | ||||||
|  |  #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); | ||||||
|  | @@ -458,6 +459,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) | ||||||
|  |  { | ||||||
| @@ -0,0 +1,524 @@ | |||||||
|  | From 7adbe9a88c33c6e362a10b109d963b5500a21f00 Mon Sep 17 00:00:00 2001 | ||||||
|  | From: John Crispin <blogic@openwrt.org> | ||||||
|  | Date: Sun, 27 Jul 2014 09:34:05 +0100 | ||||||
|  | Subject: [PATCH 25/53] pinctrl: ralink: add pinctrl driver | ||||||
|  |  | ||||||
|  | Signed-off-by: John Crispin <blogic@openwrt.org> | ||||||
|  | --- | ||||||
|  |  arch/mips/Kconfig                |    2 + | ||||||
|  |  drivers/pinctrl/Kconfig          |    5 + | ||||||
|  |  drivers/pinctrl/Makefile         |    1 + | ||||||
|  |  drivers/pinctrl/pinctrl-rt2880.c |  474 ++++++++++++++++++++++++++++++++++++++ | ||||||
|  |  4 files changed, 482 insertions(+) | ||||||
|  |  create mode 100644 drivers/pinctrl/pinctrl-rt2880.c | ||||||
|  |  | ||||||
|  | --- a/arch/mips/Kconfig | ||||||
|  | +++ b/arch/mips/Kconfig | ||||||
|  | @@ -629,6 +629,8 @@ config RALINK | ||||||
|  |  	select CLKDEV_LOOKUP | ||||||
|  |  	select ARCH_HAS_RESET_CONTROLLER | ||||||
|  |  	select RESET_CONTROLLER | ||||||
|  | +	select PINCTRL | ||||||
|  | +	select PINCTRL_RT2880 | ||||||
|  |   | ||||||
|  |  config SGI_IP22 | ||||||
|  |  	bool "SGI IP22 (Indy/Indigo2)" | ||||||
|  | --- a/drivers/pinctrl/Kconfig | ||||||
|  | +++ b/drivers/pinctrl/Kconfig | ||||||
|  | @@ -143,6 +143,11 @@ config PINCTRL_LPC18XX | ||||||
|  |  	help | ||||||
|  |  	  Pinctrl driver for NXP LPC18xx/43xx System Control Unit (SCU). | ||||||
|  |   | ||||||
|  | +config PINCTRL_RT2880 | ||||||
|  | +	bool | ||||||
|  | +	depends on RALINK | ||||||
|  | +	select PINMUX | ||||||
|  | + | ||||||
|  |  config PINCTRL_FALCON | ||||||
|  |  	bool | ||||||
|  |  	depends on SOC_FALCON | ||||||
|  | --- a/drivers/pinctrl/Makefile | ||||||
|  | +++ b/drivers/pinctrl/Makefile | ||||||
|  | @@ -28,6 +28,7 @@ obj-$(CONFIG_PINCTRL_PALMAS)	+= pinctrl- | ||||||
|  |  obj-$(CONFIG_PINCTRL_PIC32)	+= pinctrl-pic32.o | ||||||
|  |  obj-$(CONFIG_PINCTRL_PISTACHIO)	+= pinctrl-pistachio.o | ||||||
|  |  obj-$(CONFIG_PINCTRL_ROCKCHIP)	+= pinctrl-rockchip.o | ||||||
|  | +obj-$(CONFIG_PINCTRL_RT2880)	+= pinctrl-rt2880.o | ||||||
|  |  obj-$(CONFIG_PINCTRL_RZA1)	+= pinctrl-rza1.o | ||||||
|  |  obj-$(CONFIG_PINCTRL_SINGLE)	+= pinctrl-single.o | ||||||
|  |  obj-$(CONFIG_PINCTRL_SIRF)	+= sirf/ | ||||||
|  | --- /dev/null | ||||||
|  | +++ b/drivers/pinctrl/pinctrl-rt2880.c | ||||||
|  | @@ -0,0 +1,472 @@ | ||||||
|  | +/* | ||||||
|  | + *  linux/drivers/pinctrl/pinctrl-rt2880.c | ||||||
|  | + * | ||||||
|  | + *  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 | ||||||
|  | + *  publishhed by the Free Software Foundation. | ||||||
|  | + * | ||||||
|  | + *  Copyright (C) 2013 John Crispin <blogic@openwrt.org> | ||||||
|  | + */ | ||||||
|  | + | ||||||
|  | +#include <linux/module.h> | ||||||
|  | +#include <linux/device.h> | ||||||
|  | +#include <linux/io.h> | ||||||
|  | +#include <linux/platform_device.h> | ||||||
|  | +#include <linux/slab.h> | ||||||
|  | +#include <linux/of.h> | ||||||
|  | +#include <linux/pinctrl/pinctrl.h> | ||||||
|  | +#include <linux/pinctrl/pinconf.h> | ||||||
|  | +#include <linux/pinctrl/pinmux.h> | ||||||
|  | +#include <linux/pinctrl/consumer.h> | ||||||
|  | +#include <linux/pinctrl/machine.h> | ||||||
|  | + | ||||||
|  | +#include <asm/mach-ralink/ralink_regs.h> | ||||||
|  | +#include <asm/mach-ralink/pinmux.h> | ||||||
|  | +#include <asm/mach-ralink/mt7620.h> | ||||||
|  | + | ||||||
|  | +#include "core.h" | ||||||
|  | + | ||||||
|  | +#define SYSC_REG_GPIO_MODE	0x60 | ||||||
|  | +#define SYSC_REG_GPIO_MODE2	0x64 | ||||||
|  | + | ||||||
|  | +struct rt2880_priv { | ||||||
|  | +	struct device *dev; | ||||||
|  | + | ||||||
|  | +	struct pinctrl_pin_desc *pads; | ||||||
|  | +	struct pinctrl_desc *desc; | ||||||
|  | + | ||||||
|  | +	struct rt2880_pmx_func **func; | ||||||
|  | +	int func_count; | ||||||
|  | + | ||||||
|  | +	struct rt2880_pmx_group *groups; | ||||||
|  | +	const char **group_names; | ||||||
|  | +	int group_count; | ||||||
|  | + | ||||||
|  | +	uint8_t *gpio; | ||||||
|  | +	int max_pins; | ||||||
|  | +}; | ||||||
|  | + | ||||||
|  | +static int rt2880_get_group_count(struct pinctrl_dev *pctrldev) | ||||||
|  | +{ | ||||||
|  | +	struct rt2880_priv *p = pinctrl_dev_get_drvdata(pctrldev); | ||||||
|  | + | ||||||
|  | +	return p->group_count; | ||||||
|  | +} | ||||||
|  | + | ||||||
|  | +static const char *rt2880_get_group_name(struct pinctrl_dev *pctrldev, | ||||||
|  | +					 unsigned group) | ||||||
|  | +{ | ||||||
|  | +	struct rt2880_priv *p = pinctrl_dev_get_drvdata(pctrldev); | ||||||
|  | + | ||||||
|  | +	if (group >= p->group_count) | ||||||
|  | +		return NULL; | ||||||
|  | + | ||||||
|  | +	return p->group_names[group]; | ||||||
|  | +} | ||||||
|  | + | ||||||
|  | +static int rt2880_get_group_pins(struct pinctrl_dev *pctrldev, | ||||||
|  | +				 unsigned group, | ||||||
|  | +				 const unsigned **pins, | ||||||
|  | +				 unsigned *num_pins) | ||||||
|  | +{ | ||||||
|  | +	struct rt2880_priv *p = pinctrl_dev_get_drvdata(pctrldev); | ||||||
|  | + | ||||||
|  | +	if (group >= p->group_count) | ||||||
|  | +		return -EINVAL; | ||||||
|  | + | ||||||
|  | +	*pins = p->groups[group].func[0].pins; | ||||||
|  | +	*num_pins = p->groups[group].func[0].pin_count; | ||||||
|  | + | ||||||
|  | +	return 0; | ||||||
|  | +} | ||||||
|  | + | ||||||
|  | +static void rt2880_pinctrl_dt_free_map(struct pinctrl_dev *pctrldev, | ||||||
|  | +				    struct pinctrl_map *map, unsigned num_maps) | ||||||
|  | +{ | ||||||
|  | +	int i; | ||||||
|  | + | ||||||
|  | +	for (i = 0; i < num_maps; i++) | ||||||
|  | +		if (map[i].type == PIN_MAP_TYPE_CONFIGS_PIN || | ||||||
|  | +		    map[i].type == PIN_MAP_TYPE_CONFIGS_GROUP) | ||||||
|  | +			kfree(map[i].data.configs.configs); | ||||||
|  | +	kfree(map); | ||||||
|  | +} | ||||||
|  | + | ||||||
|  | +static void rt2880_pinctrl_pin_dbg_show(struct pinctrl_dev *pctrldev, | ||||||
|  | +					struct seq_file *s, | ||||||
|  | +					unsigned offset) | ||||||
|  | +{ | ||||||
|  | +	seq_printf(s, "ralink pio"); | ||||||
|  | +} | ||||||
|  | + | ||||||
|  | +static void rt2880_pinctrl_dt_subnode_to_map(struct pinctrl_dev *pctrldev, | ||||||
|  | +				struct device_node *np, | ||||||
|  | +				struct pinctrl_map **map) | ||||||
|  | +{ | ||||||
|  | +        const char *function; | ||||||
|  | +	int func = of_property_read_string(np, "ralink,function", &function); | ||||||
|  | +	int grps = of_property_count_strings(np, "ralink,group"); | ||||||
|  | +	int i; | ||||||
|  | + | ||||||
|  | +	if (func || !grps) | ||||||
|  | +		return; | ||||||
|  | + | ||||||
|  | +	for (i = 0; i < grps; i++) { | ||||||
|  | +	        const char *group; | ||||||
|  | + | ||||||
|  | +		of_property_read_string_index(np, "ralink,group", i, &group); | ||||||
|  | + | ||||||
|  | +		(*map)->type = PIN_MAP_TYPE_MUX_GROUP; | ||||||
|  | +		(*map)->name = function; | ||||||
|  | +		(*map)->data.mux.group = group; | ||||||
|  | +		(*map)->data.mux.function = function; | ||||||
|  | +		(*map)++; | ||||||
|  | +	} | ||||||
|  | +} | ||||||
|  | + | ||||||
|  | +static int rt2880_pinctrl_dt_node_to_map(struct pinctrl_dev *pctrldev, | ||||||
|  | +				struct device_node *np_config, | ||||||
|  | +				struct pinctrl_map **map, | ||||||
|  | +				unsigned *num_maps) | ||||||
|  | +{ | ||||||
|  | +	int max_maps = 0; | ||||||
|  | +	struct pinctrl_map *tmp; | ||||||
|  | +	struct device_node *np; | ||||||
|  | + | ||||||
|  | +	for_each_child_of_node(np_config, np) { | ||||||
|  | +		int ret = of_property_count_strings(np, "ralink,group"); | ||||||
|  | + | ||||||
|  | +		if (ret >= 0) | ||||||
|  | +			max_maps += ret; | ||||||
|  | +	} | ||||||
|  | + | ||||||
|  | +	if (!max_maps) | ||||||
|  | +		return -EINVAL; | ||||||
|  | + | ||||||
|  | +	*map = kzalloc(max_maps * sizeof(struct pinctrl_map), GFP_KERNEL); | ||||||
|  | +	if (!*map) | ||||||
|  | +		return -ENOMEM; | ||||||
|  | + | ||||||
|  | +	tmp = *map; | ||||||
|  | + | ||||||
|  | +	for_each_child_of_node(np_config, np) | ||||||
|  | +		rt2880_pinctrl_dt_subnode_to_map(pctrldev, np, &tmp); | ||||||
|  | +	*num_maps = max_maps; | ||||||
|  | + | ||||||
|  | +	return 0; | ||||||
|  | +} | ||||||
|  | + | ||||||
|  | +static const struct pinctrl_ops rt2880_pctrl_ops = { | ||||||
|  | +	.get_groups_count	= rt2880_get_group_count, | ||||||
|  | +	.get_group_name		= rt2880_get_group_name, | ||||||
|  | +	.get_group_pins		= rt2880_get_group_pins, | ||||||
|  | +	.pin_dbg_show		= rt2880_pinctrl_pin_dbg_show, | ||||||
|  | +	.dt_node_to_map		= rt2880_pinctrl_dt_node_to_map, | ||||||
|  | +	.dt_free_map		= rt2880_pinctrl_dt_free_map, | ||||||
|  | +}; | ||||||
|  | + | ||||||
|  | +static int rt2880_pmx_func_count(struct pinctrl_dev *pctrldev) | ||||||
|  | +{ | ||||||
|  | +	struct rt2880_priv *p = pinctrl_dev_get_drvdata(pctrldev); | ||||||
|  | + | ||||||
|  | +	return p->func_count; | ||||||
|  | +} | ||||||
|  | + | ||||||
|  | +static const char *rt2880_pmx_func_name(struct pinctrl_dev *pctrldev, | ||||||
|  | +					 unsigned func) | ||||||
|  | +{ | ||||||
|  | +	struct rt2880_priv *p = pinctrl_dev_get_drvdata(pctrldev); | ||||||
|  | + | ||||||
|  | +	return p->func[func]->name; | ||||||
|  | +} | ||||||
|  | + | ||||||
|  | +static int rt2880_pmx_group_get_groups(struct pinctrl_dev *pctrldev, | ||||||
|  | +				unsigned func, | ||||||
|  | +				const char * const **groups, | ||||||
|  | +				unsigned * const num_groups) | ||||||
|  | +{ | ||||||
|  | +	struct rt2880_priv *p = pinctrl_dev_get_drvdata(pctrldev); | ||||||
|  | + | ||||||
|  | +	if (p->func[func]->group_count == 1) | ||||||
|  | +		*groups = &p->group_names[p->func[func]->groups[0]]; | ||||||
|  | +	else | ||||||
|  | +		*groups = p->group_names; | ||||||
|  | + | ||||||
|  | +	*num_groups = p->func[func]->group_count; | ||||||
|  | + | ||||||
|  | +	return 0; | ||||||
|  | +} | ||||||
|  | + | ||||||
|  | +static int rt2880_pmx_group_enable(struct pinctrl_dev *pctrldev, | ||||||
|  | +				unsigned func, | ||||||
|  | +				unsigned group) | ||||||
|  | +{ | ||||||
|  | +	struct rt2880_priv *p = pinctrl_dev_get_drvdata(pctrldev); | ||||||
|  | +        u32 mode = 0; | ||||||
|  | +	u32 reg = SYSC_REG_GPIO_MODE; | ||||||
|  | +	int i; | ||||||
|  | +	int shift; | ||||||
|  | + | ||||||
|  | +	/* dont allow double use */ | ||||||
|  | +	if (p->groups[group].enabled) { | ||||||
|  | +		dev_err(p->dev, "%s is already enabled\n", p->groups[group].name); | ||||||
|  | +		return -EBUSY; | ||||||
|  | +	} | ||||||
|  | + | ||||||
|  | +	p->groups[group].enabled = 1; | ||||||
|  | +	p->func[func]->enabled = 1; | ||||||
|  | + | ||||||
|  | +	shift = p->groups[group].shift; | ||||||
|  | +	if (shift >= 32) { | ||||||
|  | +		shift -= 32; | ||||||
|  | +		reg = SYSC_REG_GPIO_MODE2; | ||||||
|  | +	} | ||||||
|  | +	mode = rt_sysc_r32(reg); | ||||||
|  | +	mode &= ~(p->groups[group].mask << shift); | ||||||
|  | + | ||||||
|  | +	/* mark the pins as gpio */ | ||||||
|  | +	for (i = 0; i < p->groups[group].func[0].pin_count; i++) | ||||||
|  | +		p->gpio[p->groups[group].func[0].pins[i]] = 1; | ||||||
|  | + | ||||||
|  | +	/* function 0 is gpio and needs special handling */ | ||||||
|  | +	if (func == 0) { | ||||||
|  | +		mode |= p->groups[group].gpio << shift; | ||||||
|  | +	} else { | ||||||
|  | +		for (i = 0; i < p->func[func]->pin_count; i++) | ||||||
|  | +			p->gpio[p->func[func]->pins[i]] = 0; | ||||||
|  | +		mode |= p->func[func]->value << shift; | ||||||
|  | +	} | ||||||
|  | +	rt_sysc_w32(mode, reg); | ||||||
|  | + | ||||||
|  | +	return 0; | ||||||
|  | +} | ||||||
|  | + | ||||||
|  | +static int rt2880_pmx_group_gpio_request_enable(struct pinctrl_dev *pctrldev, | ||||||
|  | +				struct pinctrl_gpio_range *range, | ||||||
|  | +				unsigned pin) | ||||||
|  | +{ | ||||||
|  | +	struct rt2880_priv *p = pinctrl_dev_get_drvdata(pctrldev); | ||||||
|  | + | ||||||
|  | +	if (!p->gpio[pin]) { | ||||||
|  | +		dev_err(p->dev, "pin %d is not set to gpio mux\n", pin); | ||||||
|  | +		return -EINVAL; | ||||||
|  | +	} | ||||||
|  | + | ||||||
|  | +	return 0; | ||||||
|  | +} | ||||||
|  | + | ||||||
|  | +static const struct pinmux_ops rt2880_pmx_group_ops = { | ||||||
|  | +	.get_functions_count	= rt2880_pmx_func_count, | ||||||
|  | +	.get_function_name	= rt2880_pmx_func_name, | ||||||
|  | +	.get_function_groups	= rt2880_pmx_group_get_groups, | ||||||
|  | +	.set_mux		= rt2880_pmx_group_enable, | ||||||
|  | +	.gpio_request_enable	= rt2880_pmx_group_gpio_request_enable, | ||||||
|  | +}; | ||||||
|  | + | ||||||
|  | +static struct pinctrl_desc rt2880_pctrl_desc = { | ||||||
|  | +	.owner		= THIS_MODULE, | ||||||
|  | +	.name		= "rt2880-pinmux", | ||||||
|  | +	.pctlops	= &rt2880_pctrl_ops, | ||||||
|  | +	.pmxops		= &rt2880_pmx_group_ops, | ||||||
|  | +}; | ||||||
|  | + | ||||||
|  | +static struct rt2880_pmx_func gpio_func = { | ||||||
|  | +	.name = "gpio", | ||||||
|  | +}; | ||||||
|  | + | ||||||
|  | +static int rt2880_pinmux_index(struct rt2880_priv *p) | ||||||
|  | +{ | ||||||
|  | +	struct rt2880_pmx_func **f; | ||||||
|  | +	struct rt2880_pmx_group *mux = p->groups; | ||||||
|  | +	int i, j, c = 0; | ||||||
|  | + | ||||||
|  | +	/* count the mux functions */ | ||||||
|  | +	while (mux->name) { | ||||||
|  | +		p->group_count++; | ||||||
|  | +		mux++; | ||||||
|  | +	} | ||||||
|  | + | ||||||
|  | +	/* allocate the group names array needed by the gpio function */ | ||||||
|  | +	p->group_names = devm_kzalloc(p->dev, sizeof(char *) * p->group_count, GFP_KERNEL); | ||||||
|  | +	if (!p->group_names) | ||||||
|  | +		return -1; | ||||||
|  | + | ||||||
|  | +	for (i = 0; i < p->group_count; i++) { | ||||||
|  | +		p->group_names[i] = p->groups[i].name; | ||||||
|  | +		p->func_count += p->groups[i].func_count; | ||||||
|  | +	} | ||||||
|  | + | ||||||
|  | +	/* we have a dummy function[0] for gpio */ | ||||||
|  | +	p->func_count++; | ||||||
|  | + | ||||||
|  | +	/* allocate our function and group mapping index buffers */ | ||||||
|  | +	f = p->func = devm_kzalloc(p->dev, sizeof(struct rt2880_pmx_func) * p->func_count, GFP_KERNEL); | ||||||
|  | +	gpio_func.groups = devm_kzalloc(p->dev, sizeof(int) * p->group_count, GFP_KERNEL); | ||||||
|  | +	if (!f || !gpio_func.groups) | ||||||
|  | +		return -1; | ||||||
|  | + | ||||||
|  | +	/* add a backpointer to the function so it knows its group */ | ||||||
|  | +	gpio_func.group_count = p->group_count; | ||||||
|  | +	for (i = 0; i < gpio_func.group_count; i++) | ||||||
|  | +		gpio_func.groups[i] = i; | ||||||
|  | + | ||||||
|  | +	f[c] = &gpio_func; | ||||||
|  | +	c++; | ||||||
|  | + | ||||||
|  | +	/* add remaining functions */ | ||||||
|  | +	for (i = 0; i < p->group_count; i++) { | ||||||
|  | +		for (j = 0; j < p->groups[i].func_count; j++) { | ||||||
|  | +			f[c] = &p->groups[i].func[j]; | ||||||
|  | +			f[c]->groups = devm_kzalloc(p->dev, sizeof(int), GFP_KERNEL); | ||||||
|  | +			f[c]->groups[0] = i; | ||||||
|  | +			f[c]->group_count = 1; | ||||||
|  | +			c++; | ||||||
|  | +		} | ||||||
|  | +	} | ||||||
|  | +	return 0; | ||||||
|  | +} | ||||||
|  | + | ||||||
|  | +static int rt2880_pinmux_pins(struct rt2880_priv *p) | ||||||
|  | +{ | ||||||
|  | +	int i, j; | ||||||
|  | + | ||||||
|  | +	/* loop over the functions and initialize the pins array. also work out the highest pin used */ | ||||||
|  | +	for (i = 0; i < p->func_count; i++) { | ||||||
|  | +		int pin; | ||||||
|  | + | ||||||
|  | +		if (!p->func[i]->pin_count) | ||||||
|  | +			continue; | ||||||
|  | + | ||||||
|  | +		p->func[i]->pins = devm_kzalloc(p->dev, sizeof(int) * p->func[i]->pin_count, GFP_KERNEL); | ||||||
|  | +		for (j = 0; j < p->func[i]->pin_count; j++) | ||||||
|  | +			p->func[i]->pins[j] = p->func[i]->pin_first + j; | ||||||
|  | + | ||||||
|  | +		pin = p->func[i]->pin_first + p->func[i]->pin_count; | ||||||
|  | +		if (pin > p->max_pins) | ||||||
|  | +			p->max_pins = pin; | ||||||
|  | +	} | ||||||
|  | + | ||||||
|  | +	/* the buffer that tells us which pins are gpio */ | ||||||
|  | +	p->gpio = devm_kzalloc(p->dev,sizeof(uint8_t) * p->max_pins, | ||||||
|  | +		GFP_KERNEL); | ||||||
|  | +	/* the pads needed to tell pinctrl about our pins */ | ||||||
|  | +	p->pads = devm_kzalloc(p->dev, | ||||||
|  | +		sizeof(struct pinctrl_pin_desc) * p->max_pins, | ||||||
|  | +		GFP_KERNEL); | ||||||
|  | +	if (!p->pads || !p->gpio ) { | ||||||
|  | +		dev_err(p->dev, "Failed to allocate gpio data\n"); | ||||||
|  | +		return -ENOMEM; | ||||||
|  | +	} | ||||||
|  | + | ||||||
|  | +	memset(p->gpio, 1, sizeof(uint8_t) * p->max_pins); | ||||||
|  | +	for (i = 0; i < p->func_count; i++) { | ||||||
|  | +		if (!p->func[i]->pin_count) | ||||||
|  | +			continue; | ||||||
|  | + | ||||||
|  | +		for (j = 0; j < p->func[i]->pin_count; j++) | ||||||
|  | +			p->gpio[p->func[i]->pins[j]] = 0; | ||||||
|  | +	} | ||||||
|  | + | ||||||
|  | +	/* pin 0 is always a gpio */ | ||||||
|  | +	p->gpio[0] = 1; | ||||||
|  | + | ||||||
|  | +	/* set the pads */ | ||||||
|  | +	for (i = 0; i < p->max_pins; i++) { | ||||||
|  | +		/* strlen("ioXY") + 1 = 5 */ | ||||||
|  | +		char *name = devm_kzalloc(p->dev, 5, GFP_KERNEL); | ||||||
|  | + | ||||||
|  | +		if (!name) { | ||||||
|  | +			dev_err(p->dev, "Failed to allocate pad name\n"); | ||||||
|  | +			return -ENOMEM; | ||||||
|  | +		} | ||||||
|  | +		snprintf(name, 5, "io%d", i); | ||||||
|  | +		p->pads[i].number = i; | ||||||
|  | +		p->pads[i].name = name; | ||||||
|  | +	} | ||||||
|  | +	p->desc->pins = p->pads; | ||||||
|  | +	p->desc->npins = p->max_pins; | ||||||
|  | + | ||||||
|  | +	return 0; | ||||||
|  | +} | ||||||
|  | + | ||||||
|  | +static int rt2880_pinmux_probe(struct platform_device *pdev) | ||||||
|  | +{ | ||||||
|  | +	struct rt2880_priv *p; | ||||||
|  | +	struct pinctrl_dev *dev; | ||||||
|  | +	struct device_node *np; | ||||||
|  | + | ||||||
|  | +	if (!rt2880_pinmux_data) | ||||||
|  | +		return -ENOSYS; | ||||||
|  | + | ||||||
|  | +	/* setup the private data */ | ||||||
|  | +	p = devm_kzalloc(&pdev->dev, sizeof(struct rt2880_priv), GFP_KERNEL); | ||||||
|  | +	if (!p) | ||||||
|  | +		return -ENOMEM; | ||||||
|  | + | ||||||
|  | +	p->dev = &pdev->dev; | ||||||
|  | +	p->desc = &rt2880_pctrl_desc; | ||||||
|  | +	p->groups = rt2880_pinmux_data; | ||||||
|  | +	platform_set_drvdata(pdev, p); | ||||||
|  | + | ||||||
|  | +	/* init the device */ | ||||||
|  | +	if (rt2880_pinmux_index(p)) { | ||||||
|  | +		dev_err(&pdev->dev, "failed to load index\n"); | ||||||
|  | +		return -EINVAL; | ||||||
|  | +	} | ||||||
|  | +	if (rt2880_pinmux_pins(p)) { | ||||||
|  | +		dev_err(&pdev->dev, "failed to load pins\n"); | ||||||
|  | +		return -EINVAL; | ||||||
|  | +	} | ||||||
|  | +	dev = pinctrl_register(p->desc, &pdev->dev, p); | ||||||
|  | +	if (IS_ERR(dev)) | ||||||
|  | +		return PTR_ERR(dev); | ||||||
|  | + | ||||||
|  | +	/* finalize by adding gpio ranges for enables gpio controllers */ | ||||||
|  | +	for_each_compatible_node(np, NULL, "ralink,rt2880-gpio") { | ||||||
|  | +		const __be32 *ngpio, *gpiobase; | ||||||
|  | +		struct pinctrl_gpio_range *range; | ||||||
|  | +		char *name; | ||||||
|  | + | ||||||
|  | +		if (!of_device_is_available(np)) | ||||||
|  | +			continue; | ||||||
|  | + | ||||||
|  | +		ngpio = of_get_property(np, "ralink,nr-gpio", NULL); | ||||||
|  | +		gpiobase = of_get_property(np, "ralink,gpio-base", NULL); | ||||||
|  | +		if (!ngpio || !gpiobase) { | ||||||
|  | +			dev_err(&pdev->dev, "failed to load chip info\n"); | ||||||
|  | +			return -EINVAL; | ||||||
|  | +		} | ||||||
|  | + | ||||||
|  | +		range = devm_kzalloc(p->dev, sizeof(struct pinctrl_gpio_range) + 4, GFP_KERNEL); | ||||||
|  | +		range->name = name = (char *) &range[1]; | ||||||
|  | +		sprintf(name, "pio"); | ||||||
|  | +		range->npins = __be32_to_cpu(*ngpio); | ||||||
|  | +		range->base = __be32_to_cpu(*gpiobase); | ||||||
|  | +		range->pin_base = range->base; | ||||||
|  | +		pinctrl_add_gpio_range(dev, range); | ||||||
|  | +	} | ||||||
|  | + | ||||||
|  | +	return 0; | ||||||
|  | +} | ||||||
|  | + | ||||||
|  | +static const struct of_device_id rt2880_pinmux_match[] = { | ||||||
|  | +	{ .compatible = "ralink,rt2880-pinmux" }, | ||||||
|  | +	{}, | ||||||
|  | +}; | ||||||
|  | +MODULE_DEVICE_TABLE(of, rt2880_pinmux_match); | ||||||
|  | + | ||||||
|  | +static struct platform_driver rt2880_pinmux_driver = { | ||||||
|  | +	.probe = rt2880_pinmux_probe, | ||||||
|  | +	.driver = { | ||||||
|  | +		.name = "rt2880-pinmux", | ||||||
|  | +		.owner = THIS_MODULE, | ||||||
|  | +		.of_match_table = rt2880_pinmux_match, | ||||||
|  | +	}, | ||||||
|  | +}; | ||||||
|  | + | ||||||
|  | +int __init rt2880_pinmux_init(void) | ||||||
|  | +{ | ||||||
|  | +	return platform_driver_register(&rt2880_pinmux_driver); | ||||||
|  | +} | ||||||
|  | + | ||||||
|  | +core_initcall_sync(rt2880_pinmux_init); | ||||||
| @@ -0,0 +1,59 @@ | |||||||
|  | From d410e5478c622c01fcf31427533df5f433df9146 Mon Sep 17 00:00:00 2001 | ||||||
|  | From: John Crispin <blogic@openwrt.org> | ||||||
|  | Date: Sun, 28 Jul 2013 19:45:30 +0200 | ||||||
|  | Subject: [PATCH 26/53] DT: Add documentation for gpio-ralink | ||||||
|  |  | ||||||
|  | Describe gpio-ralink binding. | ||||||
|  |  | ||||||
|  | Signed-off-by: John Crispin <blogic@openwrt.org> | ||||||
|  | Cc: linux-mips@linux-mips.org | ||||||
|  | Cc: devicetree@vger.kernel.org | ||||||
|  | Cc: linux-gpio@vger.kernel.org | ||||||
|  | --- | ||||||
|  |  .../devicetree/bindings/gpio/gpio-ralink.txt       |   40 ++++++++++++++++++++ | ||||||
|  |  1 file changed, 40 insertions(+) | ||||||
|  |  create mode 100644 Documentation/devicetree/bindings/gpio/gpio-ralink.txt | ||||||
|  |  | ||||||
|  | --- /dev/null | ||||||
|  | +++ b/Documentation/devicetree/bindings/gpio/gpio-ralink.txt | ||||||
|  | @@ -0,0 +1,40 @@ | ||||||
|  | +Ralink SoC GPIO controller bindings | ||||||
|  | + | ||||||
|  | +Required properties: | ||||||
|  | +- compatible: | ||||||
|  | +  - "ralink,rt2880-gpio" for Ralink controllers | ||||||
|  | +- #gpio-cells : Should be two. | ||||||
|  | +  - first cell is the pin number | ||||||
|  | +  - second cell is used to specify optional parameters (unused) | ||||||
|  | +- gpio-controller : Marks the device node as a GPIO controller | ||||||
|  | +- reg : Physical base address and length of the controller's registers | ||||||
|  | +- interrupt-parent: phandle to the INTC device node | ||||||
|  | +- interrupts : Specify the INTC interrupt number | ||||||
|  | +- ralink,nr-gpio : Specify the number of GPIOs | ||||||
|  | +- ralink,register-map : The register layout depends on the GPIO bank and actual | ||||||
|  | +		SoC type. Register offsets need to be in this order. | ||||||
|  | +		[ INT, EDGE, RENA, FENA, DATA, DIR, POL, SET, RESET, TOGGLE ] | ||||||
|  | + | ||||||
|  | +Optional properties: | ||||||
|  | +- ralink,gpio-base : Specify the GPIO chips base number | ||||||
|  | + | ||||||
|  | +Example: | ||||||
|  | + | ||||||
|  | +	gpio0: gpio@600 { | ||||||
|  | +		compatible = "ralink,rt5350-gpio", "ralink,rt2880-gpio"; | ||||||
|  | + | ||||||
|  | +		#gpio-cells = <2>; | ||||||
|  | +		gpio-controller; | ||||||
|  | + | ||||||
|  | +		reg = <0x600 0x34>; | ||||||
|  | + | ||||||
|  | +		interrupt-parent = <&intc>; | ||||||
|  | +		interrupts = <6>; | ||||||
|  | + | ||||||
|  | +		ralink,gpio-base = <0>; | ||||||
|  | +		ralink,nr-gpio = <24>; | ||||||
|  | +		ralink,register-map = [ 00 04 08 0c | ||||||
|  | +				20 24 28 2c | ||||||
|  | +				30 34 ]; | ||||||
|  | + | ||||||
|  | +	}; | ||||||
| @@ -0,0 +1,430 @@ | |||||||
|  | From 69fdd2c4f937796b934e89c33acde9d082e27bfd Mon Sep 17 00:00:00 2001 | ||||||
|  | From: John Crispin <blogic@openwrt.org> | ||||||
|  | Date: Mon, 4 Aug 2014 20:36:29 +0200 | ||||||
|  | Subject: [PATCH 27/53] GPIO: MIPS: ralink: add gpio driver for ralink SoC | ||||||
|  |  | ||||||
|  | Add gpio driver for Ralink SoC. This driver makes the gpio core on | ||||||
|  | RT2880, RT305x, rt3352, rt3662, rt3883, rt5350 and mt7620 work. | ||||||
|  |  | ||||||
|  | Signed-off-by: John Crispin <blogic@openwrt.org> | ||||||
|  | Cc: linux-mips@linux-mips.org | ||||||
|  | Cc: linux-gpio@vger.kernel.org | ||||||
|  | --- | ||||||
|  |  arch/mips/include/asm/mach-ralink/gpio.h |   24 ++ | ||||||
|  |  drivers/gpio/Kconfig                     |    6 + | ||||||
|  |  drivers/gpio/Makefile                    |    1 + | ||||||
|  |  drivers/gpio/gpio-ralink.c               |  355 ++++++++++++++++++++++++++++++ | ||||||
|  |  4 files changed, 386 insertions(+) | ||||||
|  |  create mode 100644 arch/mips/include/asm/mach-ralink/gpio.h | ||||||
|  |  create mode 100644 drivers/gpio/gpio-ralink.c | ||||||
|  |  | ||||||
|  | --- /dev/null | ||||||
|  | +++ b/arch/mips/include/asm/mach-ralink/gpio.h | ||||||
|  | @@ -0,0 +1,24 @@ | ||||||
|  | +/* | ||||||
|  | + *  Ralink SoC GPIO API support | ||||||
|  | + * | ||||||
|  | + *  Copyright (C) 2008-2009 Gabor Juhos <juhosg@openwrt.org> | ||||||
|  | + *  Copyright (C) 2008 Imre Kaloz <kaloz@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. | ||||||
|  | + * | ||||||
|  | + */ | ||||||
|  | + | ||||||
|  | +#ifndef __ASM_MACH_RALINK_GPIO_H | ||||||
|  | +#define __ASM_MACH_RALINK_GPIO_H | ||||||
|  | + | ||||||
|  | +#define ARCH_NR_GPIOS	128 | ||||||
|  | +#include <asm-generic/gpio.h> | ||||||
|  | + | ||||||
|  | +#define gpio_get_value	__gpio_get_value | ||||||
|  | +#define gpio_set_value	__gpio_set_value | ||||||
|  | +#define gpio_cansleep	__gpio_cansleep | ||||||
|  | +#define gpio_to_irq	__gpio_to_irq | ||||||
|  | + | ||||||
|  | +#endif /* __ASM_MACH_RALINK_GPIO_H */ | ||||||
|  | --- a/drivers/gpio/Kconfig | ||||||
|  | +++ b/drivers/gpio/Kconfig | ||||||
|  | @@ -398,6 +398,12 @@ config GPIO_REG | ||||||
|  |  	  A 32-bit single register GPIO fixed in/out implementation.  This | ||||||
|  |  	  can be used to represent any register as a set of GPIO signals. | ||||||
|  |   | ||||||
|  | +config GPIO_RALINK | ||||||
|  | +	bool "Ralink GPIO Support" | ||||||
|  | +	depends on RALINK | ||||||
|  | +	help | ||||||
|  | +	  Say yes here to support the Ralink SoC GPIO device | ||||||
|  | + | ||||||
|  |  config GPIO_SPEAR_SPICS | ||||||
|  |  	bool "ST SPEAr13xx SPI Chip Select as GPIO support" | ||||||
|  |  	depends on PLAT_SPEAR | ||||||
|  | --- a/drivers/gpio/Makefile | ||||||
|  | +++ b/drivers/gpio/Makefile | ||||||
|  | @@ -98,6 +98,7 @@ obj-$(CONFIG_GPIO_PCI_IDIO_16)	+= gpio-p | ||||||
|  |  obj-$(CONFIG_GPIO_PISOSR)	+= gpio-pisosr.o | ||||||
|  |  obj-$(CONFIG_GPIO_PL061)	+= gpio-pl061.o | ||||||
|  |  obj-$(CONFIG_GPIO_PXA)		+= gpio-pxa.o | ||||||
|  | +obj-$(CONFIG_GPIO_RALINK)	+= gpio-ralink.o | ||||||
|  |  obj-$(CONFIG_GPIO_RC5T583)	+= gpio-rc5t583.o | ||||||
|  |  obj-$(CONFIG_GPIO_RDC321X)	+= gpio-rdc321x.o | ||||||
|  |  obj-$(CONFIG_GPIO_RCAR)		+= gpio-rcar.o | ||||||
|  | --- /dev/null | ||||||
|  | +++ b/drivers/gpio/gpio-ralink.c | ||||||
|  | @@ -0,0 +1,355 @@ | ||||||
|  | +/* | ||||||
|  | + * 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. | ||||||
|  | + * | ||||||
|  | + * Copyright (C) 2009-2011 Gabor Juhos <juhosg@openwrt.org> | ||||||
|  | + * Copyright (C) 2013 John Crispin <blogic@openwrt.org> | ||||||
|  | + */ | ||||||
|  | + | ||||||
|  | +#include <linux/module.h> | ||||||
|  | +#include <linux/io.h> | ||||||
|  | +#include <linux/gpio.h> | ||||||
|  | +#include <linux/spinlock.h> | ||||||
|  | +#include <linux/platform_device.h> | ||||||
|  | +#include <linux/of_irq.h> | ||||||
|  | +#include <linux/irqdomain.h> | ||||||
|  | +#include <linux/interrupt.h> | ||||||
|  | + | ||||||
|  | +enum ralink_gpio_reg { | ||||||
|  | +	GPIO_REG_INT = 0, | ||||||
|  | +	GPIO_REG_EDGE, | ||||||
|  | +	GPIO_REG_RENA, | ||||||
|  | +	GPIO_REG_FENA, | ||||||
|  | +	GPIO_REG_DATA, | ||||||
|  | +	GPIO_REG_DIR, | ||||||
|  | +	GPIO_REG_POL, | ||||||
|  | +	GPIO_REG_SET, | ||||||
|  | +	GPIO_REG_RESET, | ||||||
|  | +	GPIO_REG_TOGGLE, | ||||||
|  | +	GPIO_REG_MAX | ||||||
|  | +}; | ||||||
|  | + | ||||||
|  | +struct ralink_gpio_chip { | ||||||
|  | +	struct gpio_chip chip; | ||||||
|  | +	u8 regs[GPIO_REG_MAX]; | ||||||
|  | + | ||||||
|  | +	spinlock_t lock; | ||||||
|  | +	void __iomem *membase; | ||||||
|  | +	struct irq_domain *domain; | ||||||
|  | +	int irq; | ||||||
|  | + | ||||||
|  | +	u32 rising; | ||||||
|  | +	u32 falling; | ||||||
|  | +}; | ||||||
|  | + | ||||||
|  | +#define MAP_MAX	4 | ||||||
|  | +static struct irq_domain *irq_map[MAP_MAX]; | ||||||
|  | +static int irq_map_count; | ||||||
|  | +static atomic_t irq_refcount = ATOMIC_INIT(0); | ||||||
|  | + | ||||||
|  | +static inline struct ralink_gpio_chip *to_ralink_gpio(struct gpio_chip *chip) | ||||||
|  | +{ | ||||||
|  | +	struct ralink_gpio_chip *rg; | ||||||
|  | + | ||||||
|  | +	rg = container_of(chip, struct ralink_gpio_chip, chip); | ||||||
|  | + | ||||||
|  | +	return rg; | ||||||
|  | +} | ||||||
|  | + | ||||||
|  | +static inline void rt_gpio_w32(struct ralink_gpio_chip *rg, u8 reg, u32 val) | ||||||
|  | +{ | ||||||
|  | +	iowrite32(val, rg->membase + rg->regs[reg]); | ||||||
|  | +} | ||||||
|  | + | ||||||
|  | +static inline u32 rt_gpio_r32(struct ralink_gpio_chip *rg, u8 reg) | ||||||
|  | +{ | ||||||
|  | +	return ioread32(rg->membase + rg->regs[reg]); | ||||||
|  | +} | ||||||
|  | + | ||||||
|  | +static void ralink_gpio_set(struct gpio_chip *chip, unsigned offset, int value) | ||||||
|  | +{ | ||||||
|  | +	struct ralink_gpio_chip *rg = to_ralink_gpio(chip); | ||||||
|  | + | ||||||
|  | +	rt_gpio_w32(rg, (value) ? GPIO_REG_SET : GPIO_REG_RESET, BIT(offset)); | ||||||
|  | +} | ||||||
|  | + | ||||||
|  | +static int ralink_gpio_get(struct gpio_chip *chip, unsigned offset) | ||||||
|  | +{ | ||||||
|  | +	struct ralink_gpio_chip *rg = to_ralink_gpio(chip); | ||||||
|  | + | ||||||
|  | +	return !!(rt_gpio_r32(rg, GPIO_REG_DATA) & BIT(offset)); | ||||||
|  | +} | ||||||
|  | + | ||||||
|  | +static int ralink_gpio_direction_input(struct gpio_chip *chip, unsigned offset) | ||||||
|  | +{ | ||||||
|  | +	struct ralink_gpio_chip *rg = to_ralink_gpio(chip); | ||||||
|  | +	unsigned long flags; | ||||||
|  | +	u32 t; | ||||||
|  | + | ||||||
|  | +	spin_lock_irqsave(&rg->lock, flags); | ||||||
|  | +	t = rt_gpio_r32(rg, GPIO_REG_DIR); | ||||||
|  | +	t &= ~BIT(offset); | ||||||
|  | +	rt_gpio_w32(rg, GPIO_REG_DIR, t); | ||||||
|  | +	spin_unlock_irqrestore(&rg->lock, flags); | ||||||
|  | + | ||||||
|  | +	return 0; | ||||||
|  | +} | ||||||
|  | + | ||||||
|  | +static int ralink_gpio_direction_output(struct gpio_chip *chip, | ||||||
|  | +					unsigned offset, int value) | ||||||
|  | +{ | ||||||
|  | +	struct ralink_gpio_chip *rg = to_ralink_gpio(chip); | ||||||
|  | +	unsigned long flags; | ||||||
|  | +	u32 t; | ||||||
|  | + | ||||||
|  | +	spin_lock_irqsave(&rg->lock, flags); | ||||||
|  | +	ralink_gpio_set(chip, offset, value); | ||||||
|  | +	t = rt_gpio_r32(rg, GPIO_REG_DIR); | ||||||
|  | +	t |= BIT(offset); | ||||||
|  | +	rt_gpio_w32(rg, GPIO_REG_DIR, t); | ||||||
|  | +	spin_unlock_irqrestore(&rg->lock, flags); | ||||||
|  | + | ||||||
|  | +	return 0; | ||||||
|  | +} | ||||||
|  | + | ||||||
|  | +static int ralink_gpio_to_irq(struct gpio_chip *chip, unsigned pin) | ||||||
|  | +{ | ||||||
|  | +	struct ralink_gpio_chip *rg = to_ralink_gpio(chip); | ||||||
|  | + | ||||||
|  | +	if (rg->irq < 1) | ||||||
|  | +		return -1; | ||||||
|  | + | ||||||
|  | +	return irq_create_mapping(rg->domain, pin); | ||||||
|  | +} | ||||||
|  | + | ||||||
|  | +static void ralink_gpio_irq_handler(struct irq_desc *desc) | ||||||
|  | +{ | ||||||
|  | +	int i; | ||||||
|  | + | ||||||
|  | +	for (i = 0; i < irq_map_count; i++) { | ||||||
|  | +		struct irq_domain *domain = irq_map[i]; | ||||||
|  | +		struct ralink_gpio_chip *rg; | ||||||
|  | +		unsigned long pending; | ||||||
|  | +		int bit; | ||||||
|  | + | ||||||
|  | +		rg = (struct ralink_gpio_chip *) domain->host_data; | ||||||
|  | +		pending = rt_gpio_r32(rg, GPIO_REG_INT); | ||||||
|  | + | ||||||
|  | +		for_each_set_bit(bit, &pending, rg->chip.ngpio) { | ||||||
|  | +			u32 map = irq_find_mapping(domain, bit); | ||||||
|  | +			generic_handle_irq(map); | ||||||
|  | +			rt_gpio_w32(rg, GPIO_REG_INT, BIT(bit)); | ||||||
|  | +		} | ||||||
|  | +	} | ||||||
|  | +} | ||||||
|  | + | ||||||
|  | +static void ralink_gpio_irq_unmask(struct irq_data *d) | ||||||
|  | +{ | ||||||
|  | +	struct ralink_gpio_chip *rg; | ||||||
|  | +	unsigned long flags; | ||||||
|  | +	u32 rise, fall; | ||||||
|  | + | ||||||
|  | +	rg = (struct ralink_gpio_chip *) d->domain->host_data; | ||||||
|  | +	rise = rt_gpio_r32(rg, GPIO_REG_RENA); | ||||||
|  | +	fall = rt_gpio_r32(rg, GPIO_REG_FENA); | ||||||
|  | + | ||||||
|  | +	spin_lock_irqsave(&rg->lock, flags); | ||||||
|  | +	rt_gpio_w32(rg, GPIO_REG_RENA, rise | (BIT(d->hwirq) & rg->rising)); | ||||||
|  | +	rt_gpio_w32(rg, GPIO_REG_FENA, fall | (BIT(d->hwirq) & rg->falling)); | ||||||
|  | +	spin_unlock_irqrestore(&rg->lock, flags); | ||||||
|  | +} | ||||||
|  | + | ||||||
|  | +static void ralink_gpio_irq_mask(struct irq_data *d) | ||||||
|  | +{ | ||||||
|  | +	struct ralink_gpio_chip *rg; | ||||||
|  | +	unsigned long flags; | ||||||
|  | +	u32 rise, fall; | ||||||
|  | + | ||||||
|  | +	rg = (struct ralink_gpio_chip *) d->domain->host_data; | ||||||
|  | +	rise = rt_gpio_r32(rg, GPIO_REG_RENA); | ||||||
|  | +	fall = rt_gpio_r32(rg, GPIO_REG_FENA); | ||||||
|  | + | ||||||
|  | +	spin_lock_irqsave(&rg->lock, flags); | ||||||
|  | +	rt_gpio_w32(rg, GPIO_REG_FENA, fall & ~BIT(d->hwirq)); | ||||||
|  | +	rt_gpio_w32(rg, GPIO_REG_RENA, rise & ~BIT(d->hwirq)); | ||||||
|  | +	spin_unlock_irqrestore(&rg->lock, flags); | ||||||
|  | +} | ||||||
|  | + | ||||||
|  | +static int ralink_gpio_irq_type(struct irq_data *d, unsigned int type) | ||||||
|  | +{ | ||||||
|  | +	struct ralink_gpio_chip *rg; | ||||||
|  | +	u32 mask = BIT(d->hwirq); | ||||||
|  | + | ||||||
|  | +	rg = (struct ralink_gpio_chip *) d->domain->host_data; | ||||||
|  | + | ||||||
|  | +	if (type == IRQ_TYPE_PROBE) { | ||||||
|  | +		if ((rg->rising | rg->falling) & mask) | ||||||
|  | +			return 0; | ||||||
|  | + | ||||||
|  | +		type = IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING; | ||||||
|  | +	} | ||||||
|  | + | ||||||
|  | +	if (type & IRQ_TYPE_EDGE_RISING) | ||||||
|  | +		rg->rising |= mask; | ||||||
|  | +	else | ||||||
|  | +		rg->rising &= ~mask; | ||||||
|  | + | ||||||
|  | +	if (type & IRQ_TYPE_EDGE_FALLING) | ||||||
|  | +		rg->falling |= mask; | ||||||
|  | +	else | ||||||
|  | +		rg->falling &= ~mask; | ||||||
|  | + | ||||||
|  | +	return 0; | ||||||
|  | +} | ||||||
|  | + | ||||||
|  | +static struct irq_chip ralink_gpio_irq_chip = { | ||||||
|  | +	.name		= "GPIO", | ||||||
|  | +	.irq_unmask	= ralink_gpio_irq_unmask, | ||||||
|  | +	.irq_mask	= ralink_gpio_irq_mask, | ||||||
|  | +	.irq_mask_ack	= ralink_gpio_irq_mask, | ||||||
|  | +	.irq_set_type	= ralink_gpio_irq_type, | ||||||
|  | +}; | ||||||
|  | + | ||||||
|  | +static int gpio_map(struct irq_domain *d, unsigned int irq, irq_hw_number_t hw) | ||||||
|  | +{ | ||||||
|  | +	irq_set_chip_and_handler(irq, &ralink_gpio_irq_chip, handle_level_irq); | ||||||
|  | +	irq_set_handler_data(irq, d); | ||||||
|  | + | ||||||
|  | +	return 0; | ||||||
|  | +} | ||||||
|  | + | ||||||
|  | +static const struct irq_domain_ops irq_domain_ops = { | ||||||
|  | +	.xlate = irq_domain_xlate_onecell, | ||||||
|  | +	.map = gpio_map, | ||||||
|  | +}; | ||||||
|  | + | ||||||
|  | +static void ralink_gpio_irq_init(struct device_node *np, | ||||||
|  | +				 struct ralink_gpio_chip *rg) | ||||||
|  | +{ | ||||||
|  | +	if (irq_map_count >= MAP_MAX) | ||||||
|  | +		return; | ||||||
|  | + | ||||||
|  | +	rg->irq = irq_of_parse_and_map(np, 0); | ||||||
|  | +	if (!rg->irq) | ||||||
|  | +		return; | ||||||
|  | + | ||||||
|  | +	rg->domain = irq_domain_add_linear(np, rg->chip.ngpio, | ||||||
|  | +					   &irq_domain_ops, rg); | ||||||
|  | +	if (!rg->domain) { | ||||||
|  | +		dev_err(rg->chip.parent, "irq_domain_add_linear failed\n"); | ||||||
|  | +		return; | ||||||
|  | +	} | ||||||
|  | + | ||||||
|  | +	irq_map[irq_map_count++] = rg->domain; | ||||||
|  | + | ||||||
|  | +	rt_gpio_w32(rg, GPIO_REG_RENA, 0x0); | ||||||
|  | +	rt_gpio_w32(rg, GPIO_REG_FENA, 0x0); | ||||||
|  | + | ||||||
|  | +	if (!atomic_read(&irq_refcount)) | ||||||
|  | +		irq_set_chained_handler(rg->irq, ralink_gpio_irq_handler); | ||||||
|  | +	atomic_inc(&irq_refcount); | ||||||
|  | + | ||||||
|  | +	dev_info(rg->chip.parent, "registering %d irq handlers\n", rg->chip.ngpio); | ||||||
|  | +} | ||||||
|  | + | ||||||
|  | +static int ralink_gpio_request(struct gpio_chip *chip, unsigned offset) | ||||||
|  | +{ | ||||||
|  | +	int gpio = chip->base + offset; | ||||||
|  | + | ||||||
|  | +	return pinctrl_request_gpio(gpio); | ||||||
|  | +} | ||||||
|  | + | ||||||
|  | +static void ralink_gpio_free(struct gpio_chip *chip, unsigned offset) | ||||||
|  | +{ | ||||||
|  | +	int gpio = chip->base + offset; | ||||||
|  | + | ||||||
|  | +	pinctrl_free_gpio(gpio); | ||||||
|  | +} | ||||||
|  | + | ||||||
|  | +static int ralink_gpio_probe(struct platform_device *pdev) | ||||||
|  | +{ | ||||||
|  | +	struct device_node *np = pdev->dev.of_node; | ||||||
|  | +	struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||||||
|  | +	struct ralink_gpio_chip *rg; | ||||||
|  | +	const __be32 *ngpio, *gpiobase; | ||||||
|  | + | ||||||
|  | +	if (!res) { | ||||||
|  | +		dev_err(&pdev->dev, "failed to find resource\n"); | ||||||
|  | +		return -ENOMEM; | ||||||
|  | +	} | ||||||
|  | + | ||||||
|  | +	rg = devm_kzalloc(&pdev->dev, | ||||||
|  | +			sizeof(struct ralink_gpio_chip), GFP_KERNEL); | ||||||
|  | +	if (!rg) | ||||||
|  | +		return -ENOMEM; | ||||||
|  | + | ||||||
|  | +	rg->membase = devm_ioremap_resource(&pdev->dev, res); | ||||||
|  | +	if (!rg->membase) { | ||||||
|  | +		dev_err(&pdev->dev, "cannot remap I/O memory region\n"); | ||||||
|  | +		return -ENOMEM; | ||||||
|  | +	} | ||||||
|  | + | ||||||
|  | +	if (of_property_read_u8_array(np, "ralink,register-map", | ||||||
|  | +			rg->regs, GPIO_REG_MAX)) { | ||||||
|  | +		dev_err(&pdev->dev, "failed to read register definition\n"); | ||||||
|  | +		return -EINVAL; | ||||||
|  | +	} | ||||||
|  | + | ||||||
|  | +	ngpio = of_get_property(np, "ralink,nr-gpio", NULL); | ||||||
|  | +	if (!ngpio) { | ||||||
|  | +		dev_err(&pdev->dev, "failed to read number of pins\n"); | ||||||
|  | +		return -EINVAL; | ||||||
|  | +	} | ||||||
|  | + | ||||||
|  | +	gpiobase = of_get_property(np, "ralink,gpio-base", NULL); | ||||||
|  | +	if (gpiobase) | ||||||
|  | +		rg->chip.base = be32_to_cpu(*gpiobase); | ||||||
|  | +	else | ||||||
|  | +		rg->chip.base = -1; | ||||||
|  | + | ||||||
|  | +	spin_lock_init(&rg->lock); | ||||||
|  | + | ||||||
|  | +	rg->chip.parent = &pdev->dev; | ||||||
|  | +	rg->chip.label = dev_name(&pdev->dev); | ||||||
|  | +	rg->chip.of_node = np; | ||||||
|  | +	rg->chip.ngpio = be32_to_cpu(*ngpio); | ||||||
|  | +	rg->chip.direction_input = ralink_gpio_direction_input; | ||||||
|  | +	rg->chip.direction_output = ralink_gpio_direction_output; | ||||||
|  | +	rg->chip.get = ralink_gpio_get; | ||||||
|  | +	rg->chip.set = ralink_gpio_set; | ||||||
|  | +	rg->chip.request = ralink_gpio_request; | ||||||
|  | +	rg->chip.to_irq = ralink_gpio_to_irq; | ||||||
|  | +	rg->chip.free = ralink_gpio_free; | ||||||
|  | + | ||||||
|  | +	/* set polarity to low for all lines */ | ||||||
|  | +	rt_gpio_w32(rg, GPIO_REG_POL, 0); | ||||||
|  | + | ||||||
|  | +	dev_info(&pdev->dev, "registering %d gpios\n", rg->chip.ngpio); | ||||||
|  | + | ||||||
|  | +	ralink_gpio_irq_init(np, rg); | ||||||
|  | + | ||||||
|  | +	return gpiochip_add(&rg->chip); | ||||||
|  | +} | ||||||
|  | + | ||||||
|  | +static const struct of_device_id ralink_gpio_match[] = { | ||||||
|  | +	{ .compatible = "ralink,rt2880-gpio" }, | ||||||
|  | +	{}, | ||||||
|  | +}; | ||||||
|  | +MODULE_DEVICE_TABLE(of, ralink_gpio_match); | ||||||
|  | + | ||||||
|  | +static struct platform_driver ralink_gpio_driver = { | ||||||
|  | +	.probe = ralink_gpio_probe, | ||||||
|  | +	.driver = { | ||||||
|  | +		.name = "rt2880_gpio", | ||||||
|  | +		.owner = THIS_MODULE, | ||||||
|  | +		.of_match_table = ralink_gpio_match, | ||||||
|  | +	}, | ||||||
|  | +}; | ||||||
|  | + | ||||||
|  | +static int __init ralink_gpio_init(void) | ||||||
|  | +{ | ||||||
|  | +	return platform_driver_register(&ralink_gpio_driver); | ||||||
|  | +} | ||||||
|  | + | ||||||
|  | +subsys_initcall(ralink_gpio_init); | ||||||
| @@ -0,0 +1,405 @@ | |||||||
|  | From 61ac7d9b4228de8c332900902c2b93189b042eab Mon Sep 17 00:00:00 2001 | ||||||
|  | From: John Crispin <blogic@openwrt.org> | ||||||
|  | Date: Sun, 27 Jul 2014 11:00:32 +0100 | ||||||
|  | Subject: [PATCH 28/53] GPIO: ralink: add mt7621 gpio controller | ||||||
|  |  | ||||||
|  | Signed-off-by: John Crispin <blogic@openwrt.org> | ||||||
|  | --- | ||||||
|  |  arch/mips/Kconfig          |    3 + | ||||||
|  |  drivers/gpio/Kconfig       |    6 + | ||||||
|  |  drivers/gpio/Makefile      |    1 + | ||||||
|  |  drivers/gpio/gpio-mt7621.c |  354 ++++++++++++++++++++++++++++++++++++++++++++ | ||||||
|  |  4 files changed, 364 insertions(+) | ||||||
|  |  create mode 100644 drivers/gpio/gpio-mt7621.c | ||||||
|  |  | ||||||
|  | --- a/arch/mips/Kconfig | ||||||
|  | +++ b/arch/mips/Kconfig | ||||||
|  | @@ -631,6 +631,9 @@ config RALINK | ||||||
|  |  	select RESET_CONTROLLER | ||||||
|  |  	select PINCTRL | ||||||
|  |  	select PINCTRL_RT2880 | ||||||
|  | +	select ARCH_HAS_RESET_CONTROLLER | ||||||
|  | +	select RESET_CONTROLLER | ||||||
|  | +	select ARCH_REQUIRE_GPIOLIB | ||||||
|  |   | ||||||
|  |  config SGI_IP22 | ||||||
|  |  	bool "SGI IP22 (Indy/Indigo2)" | ||||||
|  | --- a/drivers/gpio/Kconfig | ||||||
|  | +++ b/drivers/gpio/Kconfig | ||||||
|  | @@ -298,6 +298,12 @@ config GPIO_MENZ127 | ||||||
|  |  	help | ||||||
|  |  	 Say yes here to support the MEN 16Z127 GPIO Controller | ||||||
|  |   | ||||||
|  | +config GPIO_MT7621 | ||||||
|  | +	bool "Mediatek GPIO Support" | ||||||
|  | +	depends on SOC_MT7620 || SOC_MT7621 | ||||||
|  | +	help | ||||||
|  | +	  Say yes here to support the Mediatek SoC GPIO device | ||||||
|  | + | ||||||
|  |  config GPIO_MM_LANTIQ | ||||||
|  |  	bool "Lantiq Memory mapped GPIOs" | ||||||
|  |  	depends on LANTIQ && SOC_XWAY | ||||||
|  | --- a/drivers/gpio/Makefile | ||||||
|  | +++ b/drivers/gpio/Makefile | ||||||
|  | @@ -152,3 +152,4 @@ obj-$(CONFIG_GPIO_ZEVIO)	+= gpio-zevio.o | ||||||
|  |  obj-$(CONFIG_GPIO_ZYNQ)		+= gpio-zynq.o | ||||||
|  |  obj-$(CONFIG_GPIO_ZX)		+= gpio-zx.o | ||||||
|  |  obj-$(CONFIG_GPIO_LOONGSON1)	+= gpio-loongson1.o | ||||||
|  | +obj-$(CONFIG_GPIO_MT7621)	+= gpio-mt7621.o | ||||||
|  | --- /dev/null | ||||||
|  | +++ b/drivers/gpio/gpio-mt7621.c | ||||||
|  | @@ -0,0 +1,354 @@ | ||||||
|  | +/* | ||||||
|  | + * 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. | ||||||
|  | + * | ||||||
|  | + * Copyright (C) 2009-2011 Gabor Juhos <juhosg@openwrt.org> | ||||||
|  | + * Copyright (C) 2013 John Crispin <blogic@openwrt.org> | ||||||
|  | + */ | ||||||
|  | + | ||||||
|  | +#include <linux/io.h> | ||||||
|  | +#include <linux/err.h> | ||||||
|  | +#include <linux/gpio.h> | ||||||
|  | +#include <linux/module.h> | ||||||
|  | +#include <linux/of_irq.h> | ||||||
|  | +#include <linux/spinlock.h> | ||||||
|  | +#include <linux/irqdomain.h> | ||||||
|  | +#include <linux/interrupt.h> | ||||||
|  | +#include <linux/platform_device.h> | ||||||
|  | + | ||||||
|  | +#define MTK_MAX_BANK		3 | ||||||
|  | +#define MTK_BANK_WIDTH		32 | ||||||
|  | + | ||||||
|  | +enum mediatek_gpio_reg { | ||||||
|  | +	GPIO_REG_CTRL = 0, | ||||||
|  | +	GPIO_REG_POL, | ||||||
|  | +	GPIO_REG_DATA, | ||||||
|  | +	GPIO_REG_DSET, | ||||||
|  | +	GPIO_REG_DCLR, | ||||||
|  | +	GPIO_REG_REDGE, | ||||||
|  | +	GPIO_REG_FEDGE, | ||||||
|  | +	GPIO_REG_HLVL, | ||||||
|  | +	GPIO_REG_LLVL, | ||||||
|  | +	GPIO_REG_STAT, | ||||||
|  | +	GPIO_REG_EDGE, | ||||||
|  | +}; | ||||||
|  | + | ||||||
|  | +static void __iomem *mediatek_gpio_membase; | ||||||
|  | +static int mediatek_gpio_irq; | ||||||
|  | +static struct irq_domain *mediatek_gpio_irq_domain; | ||||||
|  | +static atomic_t irq_refcount = ATOMIC_INIT(0); | ||||||
|  | + | ||||||
|  | +struct mtk_gc { | ||||||
|  | +	struct gpio_chip chip; | ||||||
|  | +	spinlock_t lock; | ||||||
|  | +	int bank; | ||||||
|  | +	u32 rising; | ||||||
|  | +	u32 falling; | ||||||
|  | +} *gc_map[MTK_MAX_BANK]; | ||||||
|  | + | ||||||
|  | +static inline struct mtk_gc | ||||||
|  | +*to_mediatek_gpio(struct gpio_chip *chip) | ||||||
|  | +{ | ||||||
|  | +	struct mtk_gc *mgc; | ||||||
|  | + | ||||||
|  | +	mgc = container_of(chip, struct mtk_gc, chip); | ||||||
|  | + | ||||||
|  | +	return mgc; | ||||||
|  | +} | ||||||
|  | + | ||||||
|  | +static inline void | ||||||
|  | +mtk_gpio_w32(struct mtk_gc *rg, u8 reg, u32 val) | ||||||
|  | +{ | ||||||
|  | +	iowrite32(val, mediatek_gpio_membase + (reg * 0x10) + (rg->bank * 0x4)); | ||||||
|  | +} | ||||||
|  | + | ||||||
|  | +static inline u32 | ||||||
|  | +mtk_gpio_r32(struct mtk_gc *rg, u8 reg) | ||||||
|  | +{ | ||||||
|  | +	return ioread32(mediatek_gpio_membase + (reg * 0x10) + (rg->bank * 0x4)); | ||||||
|  | +} | ||||||
|  | + | ||||||
|  | +static void | ||||||
|  | +mediatek_gpio_set(struct gpio_chip *chip, unsigned offset, int value) | ||||||
|  | +{ | ||||||
|  | +	struct mtk_gc *rg = to_mediatek_gpio(chip); | ||||||
|  | + | ||||||
|  | +	mtk_gpio_w32(rg, (value) ? GPIO_REG_DSET : GPIO_REG_DCLR, BIT(offset)); | ||||||
|  | +} | ||||||
|  | + | ||||||
|  | +static int | ||||||
|  | +mediatek_gpio_get(struct gpio_chip *chip, unsigned offset) | ||||||
|  | +{ | ||||||
|  | +	struct mtk_gc *rg = to_mediatek_gpio(chip); | ||||||
|  | + | ||||||
|  | +	return !!(mtk_gpio_r32(rg, GPIO_REG_DATA) & BIT(offset)); | ||||||
|  | +} | ||||||
|  | + | ||||||
|  | +static int | ||||||
|  | +mediatek_gpio_direction_input(struct gpio_chip *chip, unsigned offset) | ||||||
|  | +{ | ||||||
|  | +	struct mtk_gc *rg = to_mediatek_gpio(chip); | ||||||
|  | +	unsigned long flags; | ||||||
|  | +	u32 t; | ||||||
|  | + | ||||||
|  | +	spin_lock_irqsave(&rg->lock, flags); | ||||||
|  | +	t = mtk_gpio_r32(rg, GPIO_REG_CTRL); | ||||||
|  | +	t &= ~BIT(offset); | ||||||
|  | +	mtk_gpio_w32(rg, GPIO_REG_CTRL, t); | ||||||
|  | +	spin_unlock_irqrestore(&rg->lock, flags); | ||||||
|  | + | ||||||
|  | +	return 0; | ||||||
|  | +} | ||||||
|  | + | ||||||
|  | +static int | ||||||
|  | +mediatek_gpio_direction_output(struct gpio_chip *chip, | ||||||
|  | +					unsigned offset, int value) | ||||||
|  | +{ | ||||||
|  | +	struct mtk_gc *rg = to_mediatek_gpio(chip); | ||||||
|  | +	unsigned long flags; | ||||||
|  | +	u32 t; | ||||||
|  | + | ||||||
|  | +	spin_lock_irqsave(&rg->lock, flags); | ||||||
|  | +	t = mtk_gpio_r32(rg, GPIO_REG_CTRL); | ||||||
|  | +	t |= BIT(offset); | ||||||
|  | +	mtk_gpio_w32(rg, GPIO_REG_CTRL, t); | ||||||
|  | +	mediatek_gpio_set(chip, offset, value); | ||||||
|  | +	spin_unlock_irqrestore(&rg->lock, flags); | ||||||
|  | + | ||||||
|  | +	return 0; | ||||||
|  | +} | ||||||
|  | + | ||||||
|  | +static int | ||||||
|  | +mediatek_gpio_get_direction(struct gpio_chip *chip, unsigned offset) | ||||||
|  | +{ | ||||||
|  | +	struct mtk_gc *rg = to_mediatek_gpio(chip); | ||||||
|  | +	unsigned long flags; | ||||||
|  | +	u32 t; | ||||||
|  | + | ||||||
|  | +	spin_lock_irqsave(&rg->lock, flags); | ||||||
|  | +	t = mtk_gpio_r32(rg, GPIO_REG_CTRL); | ||||||
|  | +	spin_unlock_irqrestore(&rg->lock, flags); | ||||||
|  | + | ||||||
|  | +	if (t & BIT(offset)) | ||||||
|  | +		return 0; | ||||||
|  | + | ||||||
|  | +	return 1; | ||||||
|  | +} | ||||||
|  | + | ||||||
|  | +static int | ||||||
|  | +mediatek_gpio_to_irq(struct gpio_chip *chip, unsigned pin) | ||||||
|  | +{ | ||||||
|  | +	struct mtk_gc *rg = to_mediatek_gpio(chip); | ||||||
|  | + | ||||||
|  | +	return irq_create_mapping(mediatek_gpio_irq_domain, pin + (rg->bank * MTK_BANK_WIDTH)); | ||||||
|  | +} | ||||||
|  | + | ||||||
|  | +static int | ||||||
|  | +mediatek_gpio_bank_probe(struct platform_device *pdev, struct device_node *bank) | ||||||
|  | +{ | ||||||
|  | +	const __be32 *id = of_get_property(bank, "reg", NULL); | ||||||
|  | +	struct mtk_gc *rg = devm_kzalloc(&pdev->dev, | ||||||
|  | +				sizeof(struct mtk_gc), GFP_KERNEL); | ||||||
|  | + | ||||||
|  | +	if (!rg || !id || be32_to_cpu(*id) > MTK_MAX_BANK) | ||||||
|  | +		return -ENOMEM; | ||||||
|  | + | ||||||
|  | +	gc_map[be32_to_cpu(*id)] = rg; | ||||||
|  | + | ||||||
|  | +	memset(rg, 0, sizeof(struct mtk_gc)); | ||||||
|  | + | ||||||
|  | +	spin_lock_init(&rg->lock); | ||||||
|  | + | ||||||
|  | +	rg->chip.parent = &pdev->dev; | ||||||
|  | +	rg->chip.label = dev_name(&pdev->dev); | ||||||
|  | +	rg->chip.of_node = bank; | ||||||
|  | +	rg->chip.base = MTK_BANK_WIDTH * be32_to_cpu(*id); | ||||||
|  | +	rg->chip.ngpio = MTK_BANK_WIDTH; | ||||||
|  | +	rg->chip.direction_input = mediatek_gpio_direction_input; | ||||||
|  | +	rg->chip.direction_output = mediatek_gpio_direction_output; | ||||||
|  | +	rg->chip.get_direction = mediatek_gpio_get_direction; | ||||||
|  | +	rg->chip.get = mediatek_gpio_get; | ||||||
|  | +	rg->chip.set = mediatek_gpio_set; | ||||||
|  | +	if (mediatek_gpio_irq_domain) | ||||||
|  | +		rg->chip.to_irq = mediatek_gpio_to_irq; | ||||||
|  | +	rg->bank = be32_to_cpu(*id); | ||||||
|  | + | ||||||
|  | +	/* set polarity to low for all gpios */ | ||||||
|  | +	mtk_gpio_w32(rg, GPIO_REG_POL, 0); | ||||||
|  | + | ||||||
|  | +	dev_info(&pdev->dev, "registering %d gpios\n", rg->chip.ngpio); | ||||||
|  | + | ||||||
|  | +	return gpiochip_add(&rg->chip); | ||||||
|  | +} | ||||||
|  | + | ||||||
|  | +static void | ||||||
|  | +mediatek_gpio_irq_handler(struct irq_desc *desc) | ||||||
|  | +{ | ||||||
|  | +	int i; | ||||||
|  | + | ||||||
|  | +	for (i = 0; i < MTK_MAX_BANK; i++) { | ||||||
|  | +		struct mtk_gc *rg = gc_map[i]; | ||||||
|  | +		unsigned long pending; | ||||||
|  | +		int bit; | ||||||
|  | + | ||||||
|  | +		if (!rg) | ||||||
|  | +			continue; | ||||||
|  | + | ||||||
|  | +		pending = mtk_gpio_r32(rg, GPIO_REG_STAT); | ||||||
|  | + | ||||||
|  | +		for_each_set_bit(bit, &pending, MTK_BANK_WIDTH) { | ||||||
|  | +			u32 map = irq_find_mapping(mediatek_gpio_irq_domain, (MTK_BANK_WIDTH * i) + bit); | ||||||
|  | + | ||||||
|  | +			generic_handle_irq(map); | ||||||
|  | +			mtk_gpio_w32(rg, GPIO_REG_STAT, BIT(bit)); | ||||||
|  | +		} | ||||||
|  | +	} | ||||||
|  | +} | ||||||
|  | + | ||||||
|  | +static void | ||||||
|  | +mediatek_gpio_irq_unmask(struct irq_data *d) | ||||||
|  | +{ | ||||||
|  | +	int pin = d->hwirq; | ||||||
|  | +	int bank = pin / 32; | ||||||
|  | +	struct mtk_gc *rg = gc_map[bank]; | ||||||
|  | +	unsigned long flags; | ||||||
|  | +	u32 rise, fall; | ||||||
|  | + | ||||||
|  | +	if (!rg) | ||||||
|  | +		return; | ||||||
|  | + | ||||||
|  | +	rise = mtk_gpio_r32(rg, GPIO_REG_REDGE); | ||||||
|  | +	fall = mtk_gpio_r32(rg, GPIO_REG_FEDGE); | ||||||
|  | + | ||||||
|  | +	spin_lock_irqsave(&rg->lock, flags); | ||||||
|  | +	mtk_gpio_w32(rg, GPIO_REG_REDGE, rise | (BIT(d->hwirq) & rg->rising)); | ||||||
|  | +	mtk_gpio_w32(rg, GPIO_REG_FEDGE, fall | (BIT(d->hwirq) & rg->falling)); | ||||||
|  | +	spin_unlock_irqrestore(&rg->lock, flags); | ||||||
|  | +} | ||||||
|  | + | ||||||
|  | +static void | ||||||
|  | +mediatek_gpio_irq_mask(struct irq_data *d) | ||||||
|  | +{ | ||||||
|  | +	int pin = d->hwirq; | ||||||
|  | +	int bank = pin / 32; | ||||||
|  | +	struct mtk_gc *rg = gc_map[bank]; | ||||||
|  | +	unsigned long flags; | ||||||
|  | +	u32 rise, fall; | ||||||
|  | + | ||||||
|  | +	if (!rg) | ||||||
|  | +		return; | ||||||
|  | + | ||||||
|  | +	rise = mtk_gpio_r32(rg, GPIO_REG_REDGE); | ||||||
|  | +	fall = mtk_gpio_r32(rg, GPIO_REG_FEDGE); | ||||||
|  | + | ||||||
|  | +	spin_lock_irqsave(&rg->lock, flags); | ||||||
|  | +	mtk_gpio_w32(rg, GPIO_REG_FEDGE, fall & ~BIT(d->hwirq)); | ||||||
|  | +	mtk_gpio_w32(rg, GPIO_REG_REDGE, rise & ~BIT(d->hwirq)); | ||||||
|  | +	spin_unlock_irqrestore(&rg->lock, flags); | ||||||
|  | +} | ||||||
|  | + | ||||||
|  | +static int | ||||||
|  | +mediatek_gpio_irq_type(struct irq_data *d, unsigned int type) | ||||||
|  | +{ | ||||||
|  | +	int pin = d->hwirq; | ||||||
|  | +	int bank = pin / 32; | ||||||
|  | +	struct mtk_gc *rg = gc_map[bank]; | ||||||
|  | +	u32 mask = BIT(d->hwirq); | ||||||
|  | + | ||||||
|  | +	if (!rg) | ||||||
|  | +		return -1; | ||||||
|  | + | ||||||
|  | +	if (type == IRQ_TYPE_PROBE) { | ||||||
|  | +		if ((rg->rising | rg->falling) & mask) | ||||||
|  | +			return 0; | ||||||
|  | + | ||||||
|  | +		type = IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING; | ||||||
|  | +	} | ||||||
|  | + | ||||||
|  | +	if (type & IRQ_TYPE_EDGE_RISING) | ||||||
|  | +		rg->rising |= mask; | ||||||
|  | +	else | ||||||
|  | +		rg->rising &= ~mask; | ||||||
|  | + | ||||||
|  | +	if (type & IRQ_TYPE_EDGE_FALLING) | ||||||
|  | +		rg->falling |= mask; | ||||||
|  | +	else | ||||||
|  | +		rg->falling &= ~mask; | ||||||
|  | + | ||||||
|  | +	return 0; | ||||||
|  | +} | ||||||
|  | + | ||||||
|  | +static struct irq_chip mediatek_gpio_irq_chip = { | ||||||
|  | +	.name		= "GPIO", | ||||||
|  | +	.irq_unmask	= mediatek_gpio_irq_unmask, | ||||||
|  | +	.irq_mask	= mediatek_gpio_irq_mask, | ||||||
|  | +	.irq_mask_ack	= mediatek_gpio_irq_mask, | ||||||
|  | +	.irq_set_type	= mediatek_gpio_irq_type, | ||||||
|  | +}; | ||||||
|  | + | ||||||
|  | +static int | ||||||
|  | +mediatek_gpio_gpio_map(struct irq_domain *d, unsigned int irq, irq_hw_number_t hw) | ||||||
|  | +{ | ||||||
|  | +	irq_set_chip_and_handler(irq, &mediatek_gpio_irq_chip, handle_level_irq); | ||||||
|  | +	irq_set_handler_data(irq, d); | ||||||
|  | + | ||||||
|  | +	return 0; | ||||||
|  | +} | ||||||
|  | + | ||||||
|  | +static const struct irq_domain_ops irq_domain_ops = { | ||||||
|  | +	.xlate = irq_domain_xlate_onecell, | ||||||
|  | +	.map = mediatek_gpio_gpio_map, | ||||||
|  | +}; | ||||||
|  | + | ||||||
|  | +static int | ||||||
|  | +mediatek_gpio_probe(struct platform_device *pdev) | ||||||
|  | +{ | ||||||
|  | +	struct device_node *bank, *np = pdev->dev.of_node; | ||||||
|  | +	struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||||||
|  | + | ||||||
|  | +	mediatek_gpio_membase = devm_ioremap_resource(&pdev->dev, res); | ||||||
|  | +	if (IS_ERR(mediatek_gpio_membase)) | ||||||
|  | +		return PTR_ERR(mediatek_gpio_membase); | ||||||
|  | + | ||||||
|  | +	mediatek_gpio_irq = irq_of_parse_and_map(np, 0); | ||||||
|  | +	if (mediatek_gpio_irq) { | ||||||
|  | +		mediatek_gpio_irq_domain = irq_domain_add_linear(np, | ||||||
|  | +			MTK_MAX_BANK * MTK_BANK_WIDTH, | ||||||
|  | +			&irq_domain_ops, NULL); | ||||||
|  | +		if (!mediatek_gpio_irq_domain) | ||||||
|  | +			dev_err(&pdev->dev, "irq_domain_add_linear failed\n"); | ||||||
|  | +	} | ||||||
|  | + | ||||||
|  | +	for_each_child_of_node(np, bank) | ||||||
|  | +		if (of_device_is_compatible(bank, "mtk,mt7621-gpio-bank")) | ||||||
|  | +			mediatek_gpio_bank_probe(pdev, bank); | ||||||
|  | + | ||||||
|  | +	if (mediatek_gpio_irq_domain) | ||||||
|  | +		irq_set_chained_handler(mediatek_gpio_irq, mediatek_gpio_irq_handler); | ||||||
|  | + | ||||||
|  | +	return 0; | ||||||
|  | +} | ||||||
|  | + | ||||||
|  | +static const struct of_device_id mediatek_gpio_match[] = { | ||||||
|  | +	{ .compatible = "mtk,mt7621-gpio" }, | ||||||
|  | +	{}, | ||||||
|  | +}; | ||||||
|  | +MODULE_DEVICE_TABLE(of, mediatek_gpio_match); | ||||||
|  | + | ||||||
|  | +static struct platform_driver mediatek_gpio_driver = { | ||||||
|  | +	.probe = mediatek_gpio_probe, | ||||||
|  | +	.driver = { | ||||||
|  | +		.name = "mt7621_gpio", | ||||||
|  | +		.owner = THIS_MODULE, | ||||||
|  | +		.of_match_table = mediatek_gpio_match, | ||||||
|  | +	}, | ||||||
|  | +}; | ||||||
|  | + | ||||||
|  | +static int __init | ||||||
|  | +mediatek_gpio_init(void) | ||||||
|  | +{ | ||||||
|  | +	return platform_driver_register(&mediatek_gpio_driver); | ||||||
|  | +} | ||||||
|  | + | ||||||
|  | +subsys_initcall(mediatek_gpio_init); | ||||||
| @@ -0,0 +1,44 @@ | |||||||
|  | From 57fa7f2f4ef6f78ce1d30509c0d111aa3791b524 Mon Sep 17 00:00:00 2001 | ||||||
|  | From: Daniel Santos <daniel.santos@pobox.com> | ||||||
|  | Date: Sun, 4 Nov 2018 20:24:32 -0600 | ||||||
|  | Subject: gpio-ralink: Add support for GPIO as interrupt-controller | ||||||
|  |  | ||||||
|  | Signed-off-by: Daniel Santos <daniel.santos@pobox.com> | ||||||
|  | --- | ||||||
|  |  Documentation/devicetree/bindings/gpio/gpio-ralink.txt | 6 ++++++ | ||||||
|  |  drivers/gpio/gpio-ralink.c                             | 2 +- | ||||||
|  |  2 files changed, 7 insertions(+), 1 deletion(-) | ||||||
|  |  | ||||||
|  | --- a/Documentation/devicetree/bindings/gpio/gpio-ralink.txt | ||||||
|  | +++ b/Documentation/devicetree/bindings/gpio/gpio-ralink.txt | ||||||
|  | @@ -17,6 +17,9 @@ Required properties: | ||||||
|  |   | ||||||
|  |  Optional properties: | ||||||
|  |  - ralink,gpio-base : Specify the GPIO chips base number | ||||||
|  | +- interrupt-controller : marks this as an interrupt controller | ||||||
|  | +- #interrupt-cells : a standard two-cell interrupt flag, see | ||||||
|  | +  interrupt-controller/interrupts.txt | ||||||
|  |   | ||||||
|  |  Example: | ||||||
|  |   | ||||||
|  | @@ -28,6 +31,9 @@ Example: | ||||||
|  |   | ||||||
|  |  		reg = <0x600 0x34>; | ||||||
|  |   | ||||||
|  | +		interrupt-controller; | ||||||
|  | +		#interrupt-cells = <2>; | ||||||
|  | + | ||||||
|  |  		interrupt-parent = <&intc>; | ||||||
|  |  		interrupts = <6>; | ||||||
|  |   | ||||||
|  | --- a/drivers/gpio/gpio-ralink.c | ||||||
|  | +++ b/drivers/gpio/gpio-ralink.c | ||||||
|  | @@ -220,7 +220,7 @@ static int gpio_map(struct irq_domain *d | ||||||
|  |  } | ||||||
|  |   | ||||||
|  |  static const struct irq_domain_ops irq_domain_ops = { | ||||||
|  | -	.xlate = irq_domain_xlate_onecell, | ||||||
|  | +	.xlate = irq_domain_xlate_twocell, | ||||||
|  |  	.map = gpio_map, | ||||||
|  |  }; | ||||||
|  |   | ||||||
| @@ -0,0 +1,246 @@ | |||||||
|  | From 975e76214cd2516eb6cfff4c3eec581872645e88 Mon Sep 17 00:00:00 2001 | ||||||
|  | From: John Crispin <blogic@openwrt.org> | ||||||
|  | Date: Thu, 19 Sep 2013 01:50:59 +0200 | ||||||
|  | Subject: [PATCH 31/53] uvc: add iPassion iP2970 support | ||||||
|  |  | ||||||
|  | Signed-off-by: John Crispin <blogic@openwrt.org> | ||||||
|  | --- | ||||||
|  |  drivers/media/usb/uvc/uvc_driver.c |   12 +++ | ||||||
|  |  drivers/media/usb/uvc/uvc_status.c |    2 + | ||||||
|  |  drivers/media/usb/uvc/uvc_video.c  |  147 ++++++++++++++++++++++++++++++++++++ | ||||||
|  |  drivers/media/usb/uvc/uvcvideo.h   |    5 +- | ||||||
|  |  4 files changed, 165 insertions(+), 1 deletion(-) | ||||||
|  |  | ||||||
|  | --- a/drivers/media/usb/uvc/uvc_driver.c | ||||||
|  | +++ b/drivers/media/usb/uvc/uvc_driver.c | ||||||
|  | @@ -2749,6 +2749,18 @@ static const struct usb_device_id uvc_id | ||||||
|  |  	  .bInterfaceSubClass	= 1, | ||||||
|  |  	  .bInterfaceProtocol	= 0, | ||||||
|  |  	  .driver_info		= UVC_QUIRK_FORCE_Y8 }, | ||||||
|  | +	/* iPassion iP2970 */ | ||||||
|  | +	{ .match_flags          = USB_DEVICE_ID_MATCH_DEVICE | ||||||
|  | +				| USB_DEVICE_ID_MATCH_INT_INFO, | ||||||
|  | +	 .idVendor		= 0x1B3B, | ||||||
|  | +	 .idProduct		= 0x2970, | ||||||
|  | +	 .bInterfaceClass	= USB_CLASS_VIDEO, | ||||||
|  | +	 .bInterfaceSubClass	= 1, | ||||||
|  | +	 .bInterfaceProtocol	= 0, | ||||||
|  | +	 .driver_info		= UVC_QUIRK_PROBE_MINMAX | ||||||
|  | +				| UVC_QUIRK_STREAM_NO_FID | ||||||
|  | +				| UVC_QUIRK_MOTION | ||||||
|  | +				| UVC_QUIRK_SINGLE_ISO }, | ||||||
|  |  	/* Generic USB Video Class */ | ||||||
|  |  	{ USB_INTERFACE_INFO(USB_CLASS_VIDEO, 1, UVC_PC_PROTOCOL_UNDEFINED) }, | ||||||
|  |  	{ USB_INTERFACE_INFO(USB_CLASS_VIDEO, 1, UVC_PC_PROTOCOL_15) }, | ||||||
|  | --- a/drivers/media/usb/uvc/uvc_status.c | ||||||
|  | +++ b/drivers/media/usb/uvc/uvc_status.c | ||||||
|  | @@ -139,6 +139,7 @@ static void uvc_status_complete(struct u | ||||||
|  |  		switch (dev->status[0] & 0x0f) { | ||||||
|  |  		case UVC_STATUS_TYPE_CONTROL: | ||||||
|  |  			uvc_event_control(dev, dev->status, len); | ||||||
|  | +			dev->motion = 1; | ||||||
|  |  			break; | ||||||
|  |   | ||||||
|  |  		case UVC_STATUS_TYPE_STREAMING: | ||||||
|  | @@ -182,6 +183,7 @@ int uvc_status_init(struct uvc_device *d | ||||||
|  |  	} | ||||||
|  |   | ||||||
|  |  	pipe = usb_rcvintpipe(dev->udev, ep->desc.bEndpointAddress); | ||||||
|  | +	dev->motion = 0; | ||||||
|  |   | ||||||
|  |  	/* For high-speed interrupt endpoints, the bInterval value is used as | ||||||
|  |  	 * an exponent of two. Some developers forgot about it. | ||||||
|  | --- a/drivers/media/usb/uvc/uvc_video.c | ||||||
|  | +++ b/drivers/media/usb/uvc/uvc_video.c | ||||||
|  | @@ -21,6 +21,11 @@ | ||||||
|  |  #include <linux/wait.h> | ||||||
|  |  #include <linux/atomic.h> | ||||||
|  |  #include <asm/unaligned.h> | ||||||
|  | +#include <linux/skbuff.h> | ||||||
|  | +#include <linux/kobject.h> | ||||||
|  | +#include <linux/netlink.h> | ||||||
|  | +#include <linux/kobject.h> | ||||||
|  | +#include <linux/workqueue.h> | ||||||
|  |   | ||||||
|  |  #include <media/v4l2-common.h> | ||||||
|  |   | ||||||
|  | @@ -1101,9 +1106,149 @@ static void uvc_video_decode_data(struct | ||||||
|  |  	} | ||||||
|  |  } | ||||||
|  |   | ||||||
|  | +struct bh_priv { | ||||||
|  | +	unsigned long	seen; | ||||||
|  | +}; | ||||||
|  | + | ||||||
|  | +struct bh_event { | ||||||
|  | +	const char		*name; | ||||||
|  | +	struct sk_buff		*skb; | ||||||
|  | +	struct work_struct	work; | ||||||
|  | +}; | ||||||
|  | + | ||||||
|  | +#define BH_ERR(fmt, args...) printk(KERN_ERR "%s: " fmt, "webcam", ##args ) | ||||||
|  | +#define BH_DBG(fmt, args...) do {} while (0) | ||||||
|  | +#define BH_SKB_SIZE     2048 | ||||||
|  | + | ||||||
|  | +extern u64 uevent_next_seqnum(void); | ||||||
|  | +static int seen = 0; | ||||||
|  | + | ||||||
|  | +static int bh_event_add_var(struct bh_event *event, int argv, | ||||||
|  | +		const char *format, ...) | ||||||
|  | +{ | ||||||
|  | +	static char buf[128]; | ||||||
|  | +	char *s; | ||||||
|  | +	va_list args; | ||||||
|  | +	int len; | ||||||
|  | + | ||||||
|  | +	if (argv) | ||||||
|  | +		return 0; | ||||||
|  | + | ||||||
|  | +	va_start(args, format); | ||||||
|  | +	len = vsnprintf(buf, sizeof(buf), format, args); | ||||||
|  | +	va_end(args); | ||||||
|  | + | ||||||
|  | +	if (len >= sizeof(buf)) { | ||||||
|  | +		BH_ERR("buffer size too small\n"); | ||||||
|  | +		WARN_ON(1); | ||||||
|  | +		return -ENOMEM; | ||||||
|  | +	} | ||||||
|  | + | ||||||
|  | +	s = skb_put(event->skb, len + 1); | ||||||
|  | +	strcpy(s, buf); | ||||||
|  | + | ||||||
|  | +	BH_DBG("added variable '%s'\n", s); | ||||||
|  | + | ||||||
|  | +	return 0; | ||||||
|  | +} | ||||||
|  | + | ||||||
|  | +static int motion_hotplug_fill_event(struct bh_event *event) | ||||||
|  | +{ | ||||||
|  | +	int s = jiffies; | ||||||
|  | +	int ret; | ||||||
|  | + | ||||||
|  | +	if (!seen) | ||||||
|  | +		seen = jiffies; | ||||||
|  | + | ||||||
|  | +	ret = bh_event_add_var(event, 0, "HOME=%s", "/"); | ||||||
|  | +	if (ret) | ||||||
|  | +		return ret; | ||||||
|  | + | ||||||
|  | +	ret = bh_event_add_var(event, 0, "PATH=%s", | ||||||
|  | +		"/sbin:/bin:/usr/sbin:/usr/bin"); | ||||||
|  | +	if (ret) | ||||||
|  | +		return ret; | ||||||
|  | + | ||||||
|  | +	ret = bh_event_add_var(event, 0, "SUBSYSTEM=usb"); | ||||||
|  | +	if (ret) | ||||||
|  | +		return ret; | ||||||
|  | + | ||||||
|  | +	ret = bh_event_add_var(event, 0, "ACTION=motion"); | ||||||
|  | +	if (ret) | ||||||
|  | +		return ret; | ||||||
|  | + | ||||||
|  | +	ret = bh_event_add_var(event, 0, "SEEN=%d", s - seen); | ||||||
|  | +	if (ret) | ||||||
|  | +		return ret; | ||||||
|  | +	seen = s; | ||||||
|  | + | ||||||
|  | +	ret = bh_event_add_var(event, 0, "SEQNUM=%llu", uevent_next_seqnum()); | ||||||
|  | + | ||||||
|  | +	return ret; | ||||||
|  | +} | ||||||
|  | + | ||||||
|  | +static void motion_hotplug_work(struct work_struct *work) | ||||||
|  | +{ | ||||||
|  | +	struct bh_event *event = container_of(work, struct bh_event, work); | ||||||
|  | +	int ret = 0; | ||||||
|  | + | ||||||
|  | +	event->skb = alloc_skb(BH_SKB_SIZE, GFP_KERNEL); | ||||||
|  | +	if (!event->skb) | ||||||
|  | +		goto out_free_event; | ||||||
|  | + | ||||||
|  | +	ret = bh_event_add_var(event, 0, "%s@", "add"); | ||||||
|  | +	if (ret) | ||||||
|  | +		goto out_free_skb; | ||||||
|  | + | ||||||
|  | +	ret = motion_hotplug_fill_event(event); | ||||||
|  | +	if (ret) | ||||||
|  | +		goto out_free_skb; | ||||||
|  | + | ||||||
|  | +	NETLINK_CB(event->skb).dst_group = 1; | ||||||
|  | +	broadcast_uevent(event->skb, 0, 1, GFP_KERNEL); | ||||||
|  | + | ||||||
|  | +out_free_skb: | ||||||
|  | +	if (ret) { | ||||||
|  | +		BH_ERR("work error %d\n", ret); | ||||||
|  | +		kfree_skb(event->skb); | ||||||
|  | +	} | ||||||
|  | +out_free_event: | ||||||
|  | +	kfree(event); | ||||||
|  | +} | ||||||
|  | + | ||||||
|  | +static int motion_hotplug_create_event(void) | ||||||
|  | +{ | ||||||
|  | +	struct bh_event *event; | ||||||
|  | + | ||||||
|  | +	event = kzalloc(sizeof(*event), GFP_KERNEL); | ||||||
|  | +	if (!event) | ||||||
|  | +		return -ENOMEM; | ||||||
|  | + | ||||||
|  | +	event->name = "motion"; | ||||||
|  | + | ||||||
|  | +	INIT_WORK(&event->work, (void *)(void *)motion_hotplug_work); | ||||||
|  | +	schedule_work(&event->work); | ||||||
|  | + | ||||||
|  | +	return 0; | ||||||
|  | +} | ||||||
|  | + | ||||||
|  | +#define MOTION_FLAG_OFFSET	4 | ||||||
|  |  static void uvc_video_decode_end(struct uvc_streaming *stream, | ||||||
|  |  		struct uvc_buffer *buf, const __u8 *data, int len) | ||||||
|  |  { | ||||||
|  | +	if ((stream->dev->quirks & UVC_QUIRK_MOTION) && | ||||||
|  | +			(data[len - 2] == 0xff) && (data[len - 1] == 0xd9)) { | ||||||
|  | +		u8 *mem; | ||||||
|  | +		buf->state = UVC_BUF_STATE_READY; | ||||||
|  | +		mem = (u8 *) (buf->mem + MOTION_FLAG_OFFSET); | ||||||
|  | +		if ( stream->dev->motion ) { | ||||||
|  | +			stream->dev->motion = 0; | ||||||
|  | +			motion_hotplug_create_event(); | ||||||
|  | +		} else { | ||||||
|  | +			*mem &= 0x7f; | ||||||
|  | +		} | ||||||
|  | +	} | ||||||
|  | + | ||||||
|  |  	/* Mark the buffer as done if the EOF marker is set. */ | ||||||
|  |  	if (data[1] & UVC_STREAM_EOF && buf->bytesused != 0) { | ||||||
|  |  		uvc_trace(UVC_TRACE_FRAME, "Frame complete (EOF found).\n"); | ||||||
|  | @@ -1518,6 +1663,8 @@ static int uvc_init_video_isoc(struct uv | ||||||
|  |  	if (npackets == 0) | ||||||
|  |  		return -ENOMEM; | ||||||
|  |   | ||||||
|  | +	if (stream->dev->quirks & UVC_QUIRK_SINGLE_ISO) | ||||||
|  | +		npackets = 1; | ||||||
|  |  	size = npackets * psize; | ||||||
|  |   | ||||||
|  |  	for (i = 0; i < UVC_URBS; ++i) { | ||||||
|  | --- a/drivers/media/usb/uvc/uvcvideo.h | ||||||
|  | +++ b/drivers/media/usb/uvc/uvcvideo.h | ||||||
|  | @@ -186,7 +186,9 @@ | ||||||
|  |  #define UVC_QUIRK_RESTRICT_FRAME_RATE	0x00000200 | ||||||
|  |  #define UVC_QUIRK_RESTORE_CTRLS_ON_INIT	0x00000400 | ||||||
|  |  #define UVC_QUIRK_FORCE_Y8		0x00000800 | ||||||
|  | - | ||||||
|  | +#define UVC_QUIRK_MOTION		0x00001000 | ||||||
|  | +#define UVC_QUIRK_SINGLE_ISO		0x00002000 | ||||||
|  | +  | ||||||
|  |  /* Format flags */ | ||||||
|  |  #define UVC_FMT_FLAG_COMPRESSED		0x00000001 | ||||||
|  |  #define UVC_FMT_FLAG_STREAM		0x00000002 | ||||||
|  | @@ -584,6 +586,7 @@ struct uvc_device { | ||||||
|  |  	__u8 *status; | ||||||
|  |  	struct input_dev *input; | ||||||
|  |  	char input_phys[64]; | ||||||
|  | +	int motion; | ||||||
|  |  }; | ||||||
|  |   | ||||||
|  |  enum uvc_handle_state { | ||||||
| @@ -0,0 +1,29 @@ | |||||||
|  | From a758e0870c6d1e4b0272f6e7f9efa9face5534bb Mon Sep 17 00:00:00 2001 | ||||||
|  | From: John Crispin <blogic@openwrt.org> | ||||||
|  | Date: Sun, 27 Jul 2014 09:49:07 +0100 | ||||||
|  | Subject: [PATCH 32/53] USB: dwc2: add device_reset() | ||||||
|  |  | ||||||
|  | Signed-off-by: John Crispin <blogic@openwrt.org> | ||||||
|  | --- | ||||||
|  |  drivers/usb/dwc2/hcd.c |    3 +++ | ||||||
|  |  1 file changed, 3 insertions(+) | ||||||
|  |  | ||||||
|  | --- a/drivers/usb/dwc2/hcd.c | ||||||
|  | +++ b/drivers/usb/dwc2/hcd.c | ||||||
|  | @@ -48,6 +48,7 @@ | ||||||
|  |  #include <linux/io.h> | ||||||
|  |  #include <linux/slab.h> | ||||||
|  |  #include <linux/usb.h> | ||||||
|  | +#include <linux/reset.h> | ||||||
|  |   | ||||||
|  |  #include <linux/usb/hcd.h> | ||||||
|  |  #include <linux/usb/ch11.h> | ||||||
|  | @@ -5215,6 +5216,8 @@ int dwc2_hcd_init(struct dwc2_hsotg *hso | ||||||
|  |   | ||||||
|  |  	retval = -ENOMEM; | ||||||
|  |   | ||||||
|  | +	device_reset(hsotg->dev); | ||||||
|  | + | ||||||
|  |  	hcfg = dwc2_readl(hsotg->regs + HCFG); | ||||||
|  |  	dev_dbg(hsotg->dev, "hcfg=%08x\n", hcfg); | ||||||
|  |   | ||||||
| @@ -0,0 +1,59 @@ | |||||||
|  | From 0b6eb1e68290243d439ee330ea8d0b239a5aec69 Mon Sep 17 00:00:00 2001 | ||||||
|  | From: John Crispin <blogic@openwrt.org> | ||||||
|  | Date: Sun, 27 Jul 2014 09:38:50 +0100 | ||||||
|  | Subject: [PATCH 34/53] 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 | ||||||
|  | @@ -913,7 +913,10 @@ 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; | ||||||
|  | -			phy_link_down(phydev, true); | ||||||
|  | +			if (!phydev->no_auto_carrier_off) | ||||||
|  | +				phy_link_down(phydev, true); | ||||||
|  | +			else | ||||||
|  | +				phy_link_down(phydev, false); | ||||||
|  |  			break; | ||||||
|  |  		} | ||||||
|  |   | ||||||
|  | @@ -1000,7 +1003,10 @@ void phy_state_machine(struct work_struc | ||||||
|  |  			phy_link_up(phydev); | ||||||
|  |  		} else { | ||||||
|  |  			phydev->state = PHY_NOLINK; | ||||||
|  | -			phy_link_down(phydev, true); | ||||||
|  | +			if (!phydev->no_auto_carrier_off) | ||||||
|  | +				phy_link_down(phydev, true); | ||||||
|  | +			else | ||||||
|  | +				phy_link_down(phydev, false); | ||||||
|  |  		} | ||||||
|  |   | ||||||
|  |  		if (phy_interrupt_is_valid(phydev)) | ||||||
|  | @@ -1010,7 +1016,10 @@ void phy_state_machine(struct work_struc | ||||||
|  |  	case PHY_HALTED: | ||||||
|  |  		if (phydev->link) { | ||||||
|  |  			phydev->link = 0; | ||||||
|  | -			phy_link_down(phydev, true); | ||||||
|  | +			if (!phydev->no_auto_carrier_off) | ||||||
|  | +				phy_link_down(phydev, true); | ||||||
|  | +			else | ||||||
|  | +				phy_link_down(phydev, false); | ||||||
|  |  			do_suspend = true; | ||||||
|  |  		} | ||||||
|  |  		break; | ||||||
|  | --- a/include/linux/phy.h | ||||||
|  | +++ b/include/linux/phy.h | ||||||
|  | @@ -412,6 +412,7 @@ struct phy_device { | ||||||
|  |  	bool suspended; | ||||||
|  |  	bool sysfs_links; | ||||||
|  |  	bool loopback_enabled; | ||||||
|  | +	bool no_auto_carrier_off; | ||||||
|  |   | ||||||
|  |  	enum phy_state state; | ||||||
|  |   | ||||||
| @@ -0,0 +1,70 @@ | |||||||
|  | From ee9081b2726a5ca8cde5497afdc5425e21ff8f8b Mon Sep 17 00:00:00 2001 | ||||||
|  | From: John Crispin <blogic@openwrt.org> | ||||||
|  | Date: Mon, 15 Jul 2013 00:39:21 +0200 | ||||||
|  | Subject: [PATCH 37/53] mtd: cfi cmdset 0002 force word write | ||||||
|  |  | ||||||
|  | --- | ||||||
|  |  drivers/mtd/chips/cfi_cmdset_0002.c |    9 +++++++-- | ||||||
|  |  1 file changed, 7 insertions(+), 2 deletions(-) | ||||||
|  |  | ||||||
|  | --- a/drivers/mtd/chips/cfi_cmdset_0002.c | ||||||
|  | +++ b/drivers/mtd/chips/cfi_cmdset_0002.c | ||||||
|  | @@ -40,7 +40,7 @@ | ||||||
|  |  #include <linux/mtd/xip.h> | ||||||
|  |   | ||||||
|  |  #define AMD_BOOTLOC_BUG | ||||||
|  | -#define FORCE_WORD_WRITE 0 | ||||||
|  | +#define FORCE_WORD_WRITE 1 | ||||||
|  |   | ||||||
|  |  #define MAX_RETRIES 3 | ||||||
|  |   | ||||||
|  | @@ -51,7 +51,9 @@ | ||||||
|  |   | ||||||
|  |  static int cfi_amdstd_read (struct mtd_info *, loff_t, size_t, size_t *, u_char *); | ||||||
|  |  static int cfi_amdstd_write_words(struct mtd_info *, loff_t, size_t, size_t *, const u_char *); | ||||||
|  | +#if !FORCE_WORD_WRITE | ||||||
|  |  static int cfi_amdstd_write_buffers(struct mtd_info *, loff_t, size_t, size_t *, const u_char *); | ||||||
|  | +#endif | ||||||
|  |  static int cfi_amdstd_erase_chip(struct mtd_info *, struct erase_info *); | ||||||
|  |  static int cfi_amdstd_erase_varsize(struct mtd_info *, struct erase_info *); | ||||||
|  |  static void cfi_amdstd_sync (struct mtd_info *); | ||||||
|  | @@ -202,6 +204,7 @@ static void fixup_amd_bootblock(struct m | ||||||
|  |  } | ||||||
|  |  #endif | ||||||
|  |   | ||||||
|  | +#if !FORCE_WORD_WRITE | ||||||
|  |  static void fixup_use_write_buffers(struct mtd_info *mtd) | ||||||
|  |  { | ||||||
|  |  	struct map_info *map = mtd->priv; | ||||||
|  | @@ -211,6 +214,7 @@ static void fixup_use_write_buffers(stru | ||||||
|  |  		mtd->_write = cfi_amdstd_write_buffers; | ||||||
|  |  	} | ||||||
|  |  } | ||||||
|  | +#endif /* !FORCE_WORD_WRITE */ | ||||||
|  |   | ||||||
|  |  /* Atmel chips don't use the same PRI format as AMD chips */ | ||||||
|  |  static void fixup_convert_atmel_pri(struct mtd_info *mtd) | ||||||
|  | @@ -1798,6 +1802,7 @@ static int cfi_amdstd_write_words(struct | ||||||
|  |  /* | ||||||
|  |   * FIXME: interleaved mode not tested, and probably not supported! | ||||||
|  |   */ | ||||||
|  | +#if !FORCE_WORD_WRITE | ||||||
|  |  static int __xipram do_write_buffer(struct map_info *map, struct flchip *chip, | ||||||
|  |  				    unsigned long adr, const u_char *buf, | ||||||
|  |  				    int len) | ||||||
|  | @@ -1926,7 +1931,6 @@ static int __xipram do_write_buffer(stru | ||||||
|  |  	return ret; | ||||||
|  |  } | ||||||
|  |   | ||||||
|  | - | ||||||
|  |  static int cfi_amdstd_write_buffers(struct mtd_info *mtd, loff_t to, size_t len, | ||||||
|  |  				    size_t *retlen, const u_char *buf) | ||||||
|  |  { | ||||||
|  | @@ -2001,6 +2005,7 @@ static int cfi_amdstd_write_buffers(stru | ||||||
|  |   | ||||||
|  |  	return 0; | ||||||
|  |  } | ||||||
|  | +#endif /* !FORCE_WORD_WRITE */ | ||||||
|  |   | ||||||
|  |  /* | ||||||
|  |   * Wait for the flash chip to become ready to write data | ||||||
| @@ -0,0 +1,67 @@ | |||||||
|  | From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <rafal@milecki.pl> | ||||||
|  | Subject: [PATCH] Revert "mtd: nand: Remove unused chip->write_page() hook" | ||||||
|  | MIME-Version: 1.0 | ||||||
|  | Content-Type: text/plain; charset=UTF-8 | ||||||
|  | Content-Transfer-Encoding: 8bit | ||||||
|  |  | ||||||
|  | This reverts commit f107d7a43923a83d837b3ea3c7b7de58cd014bbd. | ||||||
|  |  | ||||||
|  | OpenWrt's downstream driver mtk_nand2 still uses that callback. | ||||||
|  |  | ||||||
|  | Signed-off-by: Rafał Miłecki <rafal@milecki.pl> | ||||||
|  | --- | ||||||
|  |  | ||||||
|  | --- a/drivers/mtd/nand/nand_base.c | ||||||
|  | +++ b/drivers/mtd/nand/nand_base.c | ||||||
|  | @@ -2577,7 +2577,7 @@ static int nand_write_page_syndrome(stru | ||||||
|  |  } | ||||||
|  |   | ||||||
|  |  /** | ||||||
|  | - * nand_write_page - write one page | ||||||
|  | + * nand_write_page - [REPLACEABLE] write one page | ||||||
|  |   * @mtd: MTD device structure | ||||||
|  |   * @chip: NAND chip descriptor | ||||||
|  |   * @offset: address offset within the page | ||||||
|  | @@ -2761,9 +2761,9 @@ static int nand_do_write_ops(struct mtd_ | ||||||
|  |  			memset(chip->oob_poi, 0xff, mtd->oobsize); | ||||||
|  |  		} | ||||||
|  |   | ||||||
|  | -		ret = nand_write_page(mtd, chip, column, bytes, wbuf, | ||||||
|  | -				      oob_required, page, | ||||||
|  | -				      (ops->mode == MTD_OPS_RAW)); | ||||||
|  | +		ret = chip->write_page(mtd, chip, column, bytes, wbuf, | ||||||
|  | +					oob_required, page, | ||||||
|  | +					(ops->mode == MTD_OPS_RAW)); | ||||||
|  |  		if (ret) | ||||||
|  |  			break; | ||||||
|  |   | ||||||
|  | @@ -4719,6 +4719,9 @@ int nand_scan_tail(struct mtd_info *mtd) | ||||||
|  |  		} | ||||||
|  |  	} | ||||||
|  |   | ||||||
|  | +	if (!chip->write_page) | ||||||
|  | +		chip->write_page = nand_write_page; | ||||||
|  | + | ||||||
|  |  	/* | ||||||
|  |  	 * Check ECC mode, default to software if 3byte/512byte hardware ECC is | ||||||
|  |  	 * selected and we have 256 byte pagesize fallback to software ECC | ||||||
|  | --- a/include/linux/mtd/rawnand.h | ||||||
|  | +++ b/include/linux/mtd/rawnand.h | ||||||
|  | @@ -862,6 +862,7 @@ struct nand_manufacturer_ops { | ||||||
|  |   *			structure which is shared among multiple independent | ||||||
|  |   *			devices. | ||||||
|  |   * @priv:		[OPTIONAL] pointer to private chip data | ||||||
|  | + * @write_page:		[REPLACEABLE] High-level page write function | ||||||
|  |   * @manufacturer:	[INTERN] Contains manufacturer information | ||||||
|  |   */ | ||||||
|  |   | ||||||
|  | @@ -885,6 +886,9 @@ struct nand_chip { | ||||||
|  |  	int(*waitfunc)(struct mtd_info *mtd, struct nand_chip *this); | ||||||
|  |  	int (*erase)(struct mtd_info *mtd, int page); | ||||||
|  |  	int (*scan_bbt)(struct mtd_info *mtd); | ||||||
|  | +	int (*write_page)(struct mtd_info *mtd, struct nand_chip *chip, | ||||||
|  | +			uint32_t offset, int data_len, const uint8_t *buf, | ||||||
|  | +			int oob_required, int page, int raw); | ||||||
|  |  	int (*onfi_set_features)(struct mtd_info *mtd, struct nand_chip *chip, | ||||||
|  |  			int feature_addr, uint8_t *subfeature_para); | ||||||
|  |  	int (*onfi_get_features)(struct mtd_info *mtd, struct nand_chip *chip, | ||||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										32
									
								
								target/linux/ramips/patches-5.4/0040-nand-hack.patch
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										32
									
								
								target/linux/ramips/patches-5.4/0040-nand-hack.patch
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,32 @@ | |||||||
|  | --- a/drivers/mtd/nand/nand_base.c | ||||||
|  | +++ b/drivers/mtd/nand/nand_base.c | ||||||
|  | @@ -1908,6 +1908,9 @@ static int nand_do_read_ops(struct mtd_i | ||||||
|  |  						 __func__, buf); | ||||||
|  |   | ||||||
|  |  read_retry: | ||||||
|  | +#ifdef CONFIG_MTK_MTD_NAND | ||||||
|  | +			ret = chip->read_page(mtd, chip, bufpoi, page); | ||||||
|  | +#else | ||||||
|  |  			if (nand_standard_page_accessors(&chip->ecc)) | ||||||
|  |  				chip->cmdfunc(mtd, NAND_CMD_READ0, 0x00, page); | ||||||
|  |   | ||||||
|  | @@ -1927,6 +1930,7 @@ read_retry: | ||||||
|  |  			else | ||||||
|  |  				ret = chip->ecc.read_page(mtd, chip, bufpoi, | ||||||
|  |  							  oob_required, page); | ||||||
|  | +#endif | ||||||
|  |  			if (ret < 0) { | ||||||
|  |  				if (use_bufpoi) | ||||||
|  |  					/* Invalidate page cache */ | ||||||
|  | --- a/include/linux/mtd/rawnand.h | ||||||
|  | +++ b/include/linux/mtd/rawnand.h | ||||||
|  | @@ -897,6 +897,9 @@ struct nand_chip { | ||||||
|  |  	int (*setup_data_interface)(struct mtd_info *mtd, int chipnr, | ||||||
|  |  				    const struct nand_data_interface *conf); | ||||||
|  |   | ||||||
|  | +#ifdef CONFIG_MTK_MTD_NAND | ||||||
|  | +	int (*read_page)(struct mtd_info *mtd, struct nand_chip *chip, u8 *buf, int page); | ||||||
|  | +#endif /* CONFIG_MTK_MTD_NAND */ | ||||||
|  |   | ||||||
|  |  	int chip_delay; | ||||||
|  |  	unsigned int options; | ||||||
| @@ -0,0 +1,44 @@ | |||||||
|  | From da6015e7f19d749f135f7ac55c4ec47b06faa868 Mon Sep 17 00:00:00 2001 | ||||||
|  | From: John Crispin <blogic@openwrt.org> | ||||||
|  | Date: Fri, 9 Aug 2013 20:12:59 +0200 | ||||||
|  | Subject: [PATCH 41/53] DT: Add documentation for spi-rt2880 | ||||||
|  |  | ||||||
|  | Describe the SPI master found on the MIPS based Ralink RT2880 SoC. | ||||||
|  |  | ||||||
|  | Signed-off-by: John Crispin <blogic@openwrt.org> | ||||||
|  | --- | ||||||
|  |  .../devicetree/bindings/spi/spi-rt2880.txt         |   28 ++++++++++++++++++++ | ||||||
|  |  1 file changed, 28 insertions(+) | ||||||
|  |  create mode 100644 Documentation/devicetree/bindings/spi/spi-rt2880.txt | ||||||
|  |  | ||||||
|  | --- /dev/null | ||||||
|  | +++ b/Documentation/devicetree/bindings/spi/spi-rt2880.txt | ||||||
|  | @@ -0,0 +1,28 @@ | ||||||
|  | +Ralink SoC RT2880 SPI master controller. | ||||||
|  | + | ||||||
|  | +This SPI controller is found on most wireless SoCs made by ralink. | ||||||
|  | + | ||||||
|  | +Required properties: | ||||||
|  | +- compatible : "ralink,rt2880-spi" | ||||||
|  | +- reg : The register base for the controller. | ||||||
|  | +- #address-cells : <1>, as required by generic SPI binding. | ||||||
|  | +- #size-cells : <0>, also as required by generic SPI binding. | ||||||
|  | + | ||||||
|  | +Child nodes as per the generic SPI binding. | ||||||
|  | + | ||||||
|  | +Example: | ||||||
|  | + | ||||||
|  | +	spi@b00 { | ||||||
|  | +		compatible = "ralink,rt2880-spi"; | ||||||
|  | +		reg = <0xb00 0x100>; | ||||||
|  | + | ||||||
|  | +		#address-cells = <1>; | ||||||
|  | +		#size-cells = <0>; | ||||||
|  | + | ||||||
|  | +		m25p80@0 { | ||||||
|  | +			compatible = "m25p80"; | ||||||
|  | +			reg = <0>; | ||||||
|  | +			spi-max-frequency = <10000000>; | ||||||
|  | +		}; | ||||||
|  | +	}; | ||||||
|  | + | ||||||
| @@ -0,0 +1,574 @@ | |||||||
|  | From 683af4ebb91a1600df1946ac4769d916b8a1be65 Mon Sep 17 00:00:00 2001 | ||||||
|  | From: John Crispin <blogic@openwrt.org> | ||||||
|  | Date: Sun, 27 Jul 2014 11:15:12 +0100 | ||||||
|  | Subject: [PATCH 42/53] SPI: ralink: add Ralink SoC spi driver | ||||||
|  |  | ||||||
|  | Add the driver needed to make SPI work on Ralink SoC. | ||||||
|  |  | ||||||
|  | Signed-off-by: Gabor Juhos <juhosg@openwrt.org> | ||||||
|  | Acked-by: John Crispin <blogic@openwrt.org> | ||||||
|  | --- | ||||||
|  |  drivers/spi/Kconfig      |    6 + | ||||||
|  |  drivers/spi/Makefile     |    1 + | ||||||
|  |  drivers/spi/spi-rt2880.c |  530 ++++++++++++++++++++++++++++++++++++++++++++++ | ||||||
|  |  3 files changed, 537 insertions(+) | ||||||
|  |  create mode 100644 drivers/spi/spi-rt2880.c | ||||||
|  |  | ||||||
|  | --- a/drivers/spi/Kconfig | ||||||
|  | +++ b/drivers/spi/Kconfig | ||||||
|  | @@ -563,6 +563,12 @@ config SPI_QUP | ||||||
|  |  	  This driver can also be built as a module.  If so, the module | ||||||
|  |  	  will be called spi_qup. | ||||||
|  |   | ||||||
|  | +config SPI_RT2880 | ||||||
|  | +	tristate "Ralink RT288x SPI Controller" | ||||||
|  | +	depends on RALINK | ||||||
|  | +	help | ||||||
|  | +	  This selects a driver for the Ralink RT288x/RT305x SPI Controller. | ||||||
|  | + | ||||||
|  |  config SPI_S3C24XX | ||||||
|  |  	tristate "Samsung S3C24XX series SPI" | ||||||
|  |  	depends on ARCH_S3C24XX | ||||||
|  | --- a/drivers/spi/Makefile | ||||||
|  | +++ b/drivers/spi/Makefile | ||||||
|  | @@ -81,6 +81,7 @@ obj-$(CONFIG_SPI_QUP)			+= spi-qup.o | ||||||
|  |  obj-$(CONFIG_SPI_ROCKCHIP)		+= spi-rockchip.o | ||||||
|  |  obj-$(CONFIG_SPI_RB4XX)			+= spi-rb4xx.o | ||||||
|  |  obj-$(CONFIG_SPI_RSPI)			+= spi-rspi.o | ||||||
|  | +obj-$(CONFIG_SPI_RT2880)		+= spi-rt2880.o | ||||||
|  |  obj-$(CONFIG_SPI_S3C24XX)		+= spi-s3c24xx-hw.o | ||||||
|  |  spi-s3c24xx-hw-y			:= spi-s3c24xx.o | ||||||
|  |  spi-s3c24xx-hw-$(CONFIG_SPI_S3C24XX_FIQ) += spi-s3c24xx-fiq.o | ||||||
|  | --- /dev/null | ||||||
|  | +++ b/drivers/spi/spi-rt2880.c | ||||||
|  | @@ -0,0 +1,530 @@ | ||||||
|  | +/* | ||||||
|  | + * spi-rt2880.c -- Ralink RT288x/RT305x SPI controller driver | ||||||
|  | + * | ||||||
|  | + * Copyright (C) 2011 Sergiy <piratfm@gmail.com> | ||||||
|  | + * Copyright (C) 2011-2013 Gabor Juhos <juhosg@openwrt.org> | ||||||
|  | + * | ||||||
|  | + * Some parts are based on spi-orion.c: | ||||||
|  | + *   Author: Shadi Ammouri <shadi@marvell.com> | ||||||
|  | + *   Copyright (C) 2007-2008 Marvell Ltd. | ||||||
|  | + * | ||||||
|  | + * 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/clk.h> | ||||||
|  | +#include <linux/err.h> | ||||||
|  | +#include <linux/delay.h> | ||||||
|  | +#include <linux/io.h> | ||||||
|  | +#include <linux/reset.h> | ||||||
|  | +#include <linux/spi/spi.h> | ||||||
|  | +#include <linux/platform_device.h> | ||||||
|  | +#include <linux/gpio.h> | ||||||
|  | + | ||||||
|  | +#define DRIVER_NAME			"spi-rt2880" | ||||||
|  | + | ||||||
|  | +#define RAMIPS_SPI_STAT			0x00 | ||||||
|  | +#define RAMIPS_SPI_CFG			0x10 | ||||||
|  | +#define RAMIPS_SPI_CTL			0x14 | ||||||
|  | +#define RAMIPS_SPI_DATA			0x20 | ||||||
|  | +#define RAMIPS_SPI_ADDR			0x24 | ||||||
|  | +#define RAMIPS_SPI_BS			0x28 | ||||||
|  | +#define RAMIPS_SPI_USER			0x2C | ||||||
|  | +#define RAMIPS_SPI_TXFIFO		0x30 | ||||||
|  | +#define RAMIPS_SPI_RXFIFO		0x34 | ||||||
|  | +#define RAMIPS_SPI_FIFO_STAT		0x38 | ||||||
|  | +#define RAMIPS_SPI_MODE			0x3C | ||||||
|  | +#define RAMIPS_SPI_DEV_OFFSET		0x40 | ||||||
|  | +#define RAMIPS_SPI_DMA			0x80 | ||||||
|  | +#define RAMIPS_SPI_DMASTAT		0x84 | ||||||
|  | +#define RAMIPS_SPI_ARBITER		0xF0 | ||||||
|  | + | ||||||
|  | +/* SPISTAT register bit field */ | ||||||
|  | +#define SPISTAT_BUSY			BIT(0) | ||||||
|  | + | ||||||
|  | +/* SPICFG register bit field */ | ||||||
|  | +#define SPICFG_ADDRMODE			BIT(12) | ||||||
|  | +#define SPICFG_RXENVDIS			BIT(11) | ||||||
|  | +#define SPICFG_RXCAP			BIT(10) | ||||||
|  | +#define SPICFG_SPIENMODE		BIT(9) | ||||||
|  | +#define SPICFG_MSBFIRST			BIT(8) | ||||||
|  | +#define SPICFG_SPICLKPOL		BIT(6) | ||||||
|  | +#define SPICFG_RXCLKEDGE_FALLING	BIT(5) | ||||||
|  | +#define SPICFG_TXCLKEDGE_FALLING	BIT(4) | ||||||
|  | +#define SPICFG_HIZSPI			BIT(3) | ||||||
|  | +#define SPICFG_SPICLK_PRESCALE_MASK	0x7 | ||||||
|  | +#define SPICFG_SPICLK_DIV2		0 | ||||||
|  | +#define SPICFG_SPICLK_DIV4		1 | ||||||
|  | +#define SPICFG_SPICLK_DIV8		2 | ||||||
|  | +#define SPICFG_SPICLK_DIV16		3 | ||||||
|  | +#define SPICFG_SPICLK_DIV32		4 | ||||||
|  | +#define SPICFG_SPICLK_DIV64		5 | ||||||
|  | +#define SPICFG_SPICLK_DIV128		6 | ||||||
|  | +#define SPICFG_SPICLK_DISABLE		7 | ||||||
|  | + | ||||||
|  | +/* SPICTL register bit field */ | ||||||
|  | +#define SPICTL_START			BIT(4) | ||||||
|  | +#define SPICTL_HIZSDO			BIT(3) | ||||||
|  | +#define SPICTL_STARTWR			BIT(2) | ||||||
|  | +#define SPICTL_STARTRD			BIT(1) | ||||||
|  | +#define SPICTL_SPIENA			BIT(0) | ||||||
|  | + | ||||||
|  | +/* SPIUSER register bit field */ | ||||||
|  | +#define SPIUSER_USERMODE		BIT(21) | ||||||
|  | +#define SPIUSER_INSTR_PHASE		BIT(20) | ||||||
|  | +#define SPIUSER_ADDR_PHASE_MASK		0x7 | ||||||
|  | +#define SPIUSER_ADDR_PHASE_OFFSET	17 | ||||||
|  | +#define SPIUSER_MODE_PHASE		BIT(16) | ||||||
|  | +#define SPIUSER_DUMMY_PHASE_MASK	0x3 | ||||||
|  | +#define SPIUSER_DUMMY_PHASE_OFFSET	14 | ||||||
|  | +#define SPIUSER_DATA_PHASE_MASK		0x3 | ||||||
|  | +#define SPIUSER_DATA_PHASE_OFFSET	12 | ||||||
|  | +#define SPIUSER_DATA_READ		(BIT(0) << SPIUSER_DATA_PHASE_OFFSET) | ||||||
|  | +#define SPIUSER_DATA_WRITE		(BIT(1) << SPIUSER_DATA_PHASE_OFFSET) | ||||||
|  | +#define SPIUSER_ADDR_TYPE_OFFSET	9 | ||||||
|  | +#define SPIUSER_MODE_TYPE_OFFSET	6 | ||||||
|  | +#define SPIUSER_DUMMY_TYPE_OFFSET	3 | ||||||
|  | +#define SPIUSER_DATA_TYPE_OFFSET	0 | ||||||
|  | +#define SPIUSER_TRANSFER_MASK		0x7 | ||||||
|  | +#define SPIUSER_TRANSFER_SINGLE		BIT(0) | ||||||
|  | +#define SPIUSER_TRANSFER_DUAL		BIT(1) | ||||||
|  | +#define SPIUSER_TRANSFER_QUAD		BIT(2) | ||||||
|  | + | ||||||
|  | +#define SPIUSER_TRANSFER_TYPE(type) ( \ | ||||||
|  | +	(type << SPIUSER_ADDR_TYPE_OFFSET) | \ | ||||||
|  | +	(type << SPIUSER_MODE_TYPE_OFFSET) | \ | ||||||
|  | +	(type << SPIUSER_DUMMY_TYPE_OFFSET) | \ | ||||||
|  | +	(type << SPIUSER_DATA_TYPE_OFFSET) \ | ||||||
|  | +) | ||||||
|  | + | ||||||
|  | +/* SPIFIFOSTAT register bit field */ | ||||||
|  | +#define SPIFIFOSTAT_TXEMPTY		BIT(19) | ||||||
|  | +#define SPIFIFOSTAT_RXEMPTY		BIT(18) | ||||||
|  | +#define SPIFIFOSTAT_TXFULL		BIT(17) | ||||||
|  | +#define SPIFIFOSTAT_RXFULL		BIT(16) | ||||||
|  | +#define SPIFIFOSTAT_FIFO_MASK		0xff | ||||||
|  | +#define SPIFIFOSTAT_TX_OFFSET		8 | ||||||
|  | +#define SPIFIFOSTAT_RX_OFFSET		0 | ||||||
|  | + | ||||||
|  | +#define SPI_FIFO_DEPTH			16 | ||||||
|  | + | ||||||
|  | +/* SPIMODE register bit field */ | ||||||
|  | +#define SPIMODE_MODE_OFFSET		24 | ||||||
|  | +#define SPIMODE_DUMMY_OFFSET		0 | ||||||
|  | + | ||||||
|  | +/* SPIARB register bit field */ | ||||||
|  | +#define SPICTL_ARB_EN			BIT(31) | ||||||
|  | +#define SPICTL_CSCTL1			BIT(16) | ||||||
|  | +#define SPI1_POR			BIT(1) | ||||||
|  | +#define SPI0_POR			BIT(0) | ||||||
|  | + | ||||||
|  | +#define RT2880_SPI_MODE_BITS	(SPI_CPOL | SPI_CPHA | SPI_LSB_FIRST | \ | ||||||
|  | +		SPI_CS_HIGH) | ||||||
|  | + | ||||||
|  | +static atomic_t hw_reset_count = ATOMIC_INIT(0); | ||||||
|  | + | ||||||
|  | +struct rt2880_spi { | ||||||
|  | +	struct spi_master	*master; | ||||||
|  | +	void __iomem		*base; | ||||||
|  | +	u32			speed; | ||||||
|  | +	u16			wait_loops; | ||||||
|  | +	u16			mode; | ||||||
|  | +	struct clk		*clk; | ||||||
|  | +}; | ||||||
|  | + | ||||||
|  | +static inline struct rt2880_spi *spidev_to_rt2880_spi(struct spi_device *spi) | ||||||
|  | +{ | ||||||
|  | +	return spi_master_get_devdata(spi->master); | ||||||
|  | +} | ||||||
|  | + | ||||||
|  | +static inline u32 rt2880_spi_read(struct rt2880_spi *rs, u32 reg) | ||||||
|  | +{ | ||||||
|  | +	return ioread32(rs->base + reg); | ||||||
|  | +} | ||||||
|  | + | ||||||
|  | +static inline void rt2880_spi_write(struct rt2880_spi *rs, u32 reg, | ||||||
|  | +		const u32 val) | ||||||
|  | +{ | ||||||
|  | +	iowrite32(val, rs->base + reg); | ||||||
|  | +} | ||||||
|  | + | ||||||
|  | +static inline void rt2880_spi_setbits(struct rt2880_spi *rs, u32 reg, u32 mask) | ||||||
|  | +{ | ||||||
|  | +	void __iomem *addr = rs->base + reg; | ||||||
|  | + | ||||||
|  | +	iowrite32((ioread32(addr) | mask), addr); | ||||||
|  | +} | ||||||
|  | + | ||||||
|  | +static inline void rt2880_spi_clrbits(struct rt2880_spi *rs, u32 reg, u32 mask) | ||||||
|  | +{ | ||||||
|  | +	void __iomem *addr = rs->base + reg; | ||||||
|  | + | ||||||
|  | +	iowrite32((ioread32(addr) & ~mask), addr); | ||||||
|  | +} | ||||||
|  | + | ||||||
|  | +static u32 rt2880_spi_baudrate_get(struct spi_device *spi, unsigned int speed) | ||||||
|  | +{ | ||||||
|  | +	struct rt2880_spi *rs = spidev_to_rt2880_spi(spi); | ||||||
|  | +	u32 rate; | ||||||
|  | +	u32 prescale; | ||||||
|  | + | ||||||
|  | +	/* | ||||||
|  | +	 * the supported rates are: 2, 4, 8, ... 128 | ||||||
|  | +	 * round up as we look for equal or less speed | ||||||
|  | +	 */ | ||||||
|  | +	rate = DIV_ROUND_UP(clk_get_rate(rs->clk), speed); | ||||||
|  | +	rate = roundup_pow_of_two(rate); | ||||||
|  | + | ||||||
|  | +	/* Convert the rate to SPI clock divisor value.	*/ | ||||||
|  | +	prescale = ilog2(rate / 2); | ||||||
|  | + | ||||||
|  | +	/* some tolerance. double and add 100 */ | ||||||
|  | +	rs->wait_loops = (8 * HZ * loops_per_jiffy) / | ||||||
|  | +		(clk_get_rate(rs->clk) / rate); | ||||||
|  | +	rs->wait_loops = (rs->wait_loops << 1) + 100; | ||||||
|  | +	rs->speed = speed; | ||||||
|  | + | ||||||
|  | +	dev_dbg(&spi->dev, "speed: %lu/%u, rate: %u, prescal: %u, loops: %hu\n", | ||||||
|  | +			clk_get_rate(rs->clk) / rate, speed, rate, prescale, | ||||||
|  | +			rs->wait_loops); | ||||||
|  | + | ||||||
|  | +	return prescale; | ||||||
|  | +} | ||||||
|  | + | ||||||
|  | +static u32 get_arbiter_offset(struct spi_master *master) | ||||||
|  | +{ | ||||||
|  | +	u32 offset; | ||||||
|  | + | ||||||
|  | +	offset = RAMIPS_SPI_ARBITER; | ||||||
|  | +	if (master->bus_num == 1) | ||||||
|  | +		offset -= RAMIPS_SPI_DEV_OFFSET; | ||||||
|  | + | ||||||
|  | +	return offset; | ||||||
|  | +} | ||||||
|  | + | ||||||
|  | +static void rt2880_spi_set_cs(struct spi_device *spi, bool enable) | ||||||
|  | +{ | ||||||
|  | +	struct rt2880_spi *rs = spidev_to_rt2880_spi(spi); | ||||||
|  | + | ||||||
|  | +	if (enable) | ||||||
|  | +		rt2880_spi_setbits(rs, RAMIPS_SPI_CTL, SPICTL_SPIENA); | ||||||
|  | +	else | ||||||
|  | +		rt2880_spi_clrbits(rs, RAMIPS_SPI_CTL, SPICTL_SPIENA); | ||||||
|  | +} | ||||||
|  | + | ||||||
|  | +static int rt2880_spi_wait_ready(struct rt2880_spi *rs, int len) | ||||||
|  | +{ | ||||||
|  | +	int loop = rs->wait_loops * len; | ||||||
|  | + | ||||||
|  | +	while ((rt2880_spi_read(rs, RAMIPS_SPI_STAT) & SPISTAT_BUSY) && --loop) | ||||||
|  | +		cpu_relax(); | ||||||
|  | + | ||||||
|  | +	if (loop) | ||||||
|  | +		return 0; | ||||||
|  | + | ||||||
|  | +	return -ETIMEDOUT; | ||||||
|  | +} | ||||||
|  | + | ||||||
|  | +static void rt2880_dump_reg(struct spi_master *master) | ||||||
|  | +{ | ||||||
|  | +	struct rt2880_spi *rs = spi_master_get_devdata(master); | ||||||
|  | + | ||||||
|  | +	dev_dbg(&master->dev, "stat: %08x, cfg: %08x, ctl: %08x, " \ | ||||||
|  | +			"data: %08x, arb: %08x\n", | ||||||
|  | +			rt2880_spi_read(rs, RAMIPS_SPI_STAT), | ||||||
|  | +			rt2880_spi_read(rs, RAMIPS_SPI_CFG), | ||||||
|  | +			rt2880_spi_read(rs, RAMIPS_SPI_CTL), | ||||||
|  | +			rt2880_spi_read(rs, RAMIPS_SPI_DATA), | ||||||
|  | +			rt2880_spi_read(rs, get_arbiter_offset(master))); | ||||||
|  | +} | ||||||
|  | + | ||||||
|  | +static int rt2880_spi_transfer_one(struct spi_master *master, | ||||||
|  | +		struct spi_device *spi, struct spi_transfer *xfer) | ||||||
|  | +{ | ||||||
|  | +	struct rt2880_spi *rs = spi_master_get_devdata(master); | ||||||
|  | +	unsigned len; | ||||||
|  | +	const u8 *tx = xfer->tx_buf; | ||||||
|  | +	u8 *rx = xfer->rx_buf; | ||||||
|  | +	int err = 0; | ||||||
|  | + | ||||||
|  | +	/* change clock speed  */ | ||||||
|  | +	if (unlikely(rs->speed != xfer->speed_hz)) { | ||||||
|  | +		u32 reg; | ||||||
|  | +		reg = rt2880_spi_read(rs, RAMIPS_SPI_CFG); | ||||||
|  | +		reg &= ~SPICFG_SPICLK_PRESCALE_MASK; | ||||||
|  | +		reg |= rt2880_spi_baudrate_get(spi, xfer->speed_hz); | ||||||
|  | +		rt2880_spi_write(rs, RAMIPS_SPI_CFG, reg); | ||||||
|  | +	} | ||||||
|  | + | ||||||
|  | +	if (tx) { | ||||||
|  | +		len = xfer->len; | ||||||
|  | +		while (len-- > 0) { | ||||||
|  | +			rt2880_spi_write(rs, RAMIPS_SPI_DATA, *tx++); | ||||||
|  | +			rt2880_spi_setbits(rs, RAMIPS_SPI_CTL, SPICTL_STARTWR); | ||||||
|  | +			err = rt2880_spi_wait_ready(rs, 1); | ||||||
|  | +			if (err) { | ||||||
|  | +				dev_err(&spi->dev, "TX failed, err=%d\n", err); | ||||||
|  | +				goto out; | ||||||
|  | +			} | ||||||
|  | +		} | ||||||
|  | +	} | ||||||
|  | + | ||||||
|  | +	if (rx) { | ||||||
|  | +		len = xfer->len; | ||||||
|  | +		while (len-- > 0) { | ||||||
|  | +			rt2880_spi_setbits(rs, RAMIPS_SPI_CTL, SPICTL_STARTRD); | ||||||
|  | +			err = rt2880_spi_wait_ready(rs, 1); | ||||||
|  | +			if (err) { | ||||||
|  | +				dev_err(&spi->dev, "RX failed, err=%d\n", err); | ||||||
|  | +				goto out; | ||||||
|  | +			} | ||||||
|  | +			*rx++ = (u8) rt2880_spi_read(rs, RAMIPS_SPI_DATA); | ||||||
|  | +		} | ||||||
|  | +	} | ||||||
|  | + | ||||||
|  | +out: | ||||||
|  | +	return err; | ||||||
|  | +} | ||||||
|  | + | ||||||
|  | +/* copy from spi.c */ | ||||||
|  | +static void spi_set_cs(struct spi_device *spi, bool enable) | ||||||
|  | +{ | ||||||
|  | +	if (spi->mode & SPI_CS_HIGH) | ||||||
|  | +		enable = !enable; | ||||||
|  | + | ||||||
|  | +	if (spi->cs_gpio >= 0) | ||||||
|  | +		gpio_set_value(spi->cs_gpio, !enable); | ||||||
|  | +	else if (spi->master->set_cs) | ||||||
|  | +		spi->master->set_cs(spi, !enable); | ||||||
|  | +} | ||||||
|  | + | ||||||
|  | +static int rt2880_spi_setup(struct spi_device *spi) | ||||||
|  | +{ | ||||||
|  | +	struct spi_master *master = spi->master; | ||||||
|  | +	struct rt2880_spi *rs = spi_master_get_devdata(master); | ||||||
|  | +	u32 reg, old_reg, arbit_off; | ||||||
|  | + | ||||||
|  | +	if ((spi->max_speed_hz > master->max_speed_hz) || | ||||||
|  | +			(spi->max_speed_hz < master->min_speed_hz)) { | ||||||
|  | +		dev_err(&spi->dev, "invalide requested speed %d Hz\n", | ||||||
|  | +				spi->max_speed_hz); | ||||||
|  | +		return -EINVAL; | ||||||
|  | +	} | ||||||
|  | + | ||||||
|  | +	if (!(master->bits_per_word_mask & | ||||||
|  | +				BIT(spi->bits_per_word - 1))) { | ||||||
|  | +		dev_err(&spi->dev, "invalide bits_per_word %d\n", | ||||||
|  | +				spi->bits_per_word); | ||||||
|  | +		return -EINVAL; | ||||||
|  | +	} | ||||||
|  | + | ||||||
|  | +	/* the hardware seems can't work on mode0 force it to mode3 */ | ||||||
|  | +	if ((spi->mode & (SPI_CPOL | SPI_CPHA)) == SPI_MODE_0) { | ||||||
|  | +		dev_warn(&spi->dev, "force spi mode3\n"); | ||||||
|  | +		spi->mode |= SPI_MODE_3; | ||||||
|  | +	} | ||||||
|  | + | ||||||
|  | +	/* chip polarity */ | ||||||
|  | +	arbit_off = get_arbiter_offset(master); | ||||||
|  | +	reg = old_reg = rt2880_spi_read(rs, arbit_off); | ||||||
|  | +	if (spi->mode & SPI_CS_HIGH) { | ||||||
|  | +		switch (master->bus_num) { | ||||||
|  | +		case 1: | ||||||
|  | +			reg |= SPI1_POR; | ||||||
|  | +			break; | ||||||
|  | +		default: | ||||||
|  | +			reg |= SPI0_POR; | ||||||
|  | +			break; | ||||||
|  | +		} | ||||||
|  | +	} else { | ||||||
|  | +		switch (master->bus_num) { | ||||||
|  | +		case 1: | ||||||
|  | +			reg &= ~SPI1_POR; | ||||||
|  | +			break; | ||||||
|  | +		default: | ||||||
|  | +			reg &= ~SPI0_POR; | ||||||
|  | +			break; | ||||||
|  | +		} | ||||||
|  | +	} | ||||||
|  | + | ||||||
|  | +	/* enable spi1 */ | ||||||
|  | +	if (master->bus_num == 1) | ||||||
|  | +		reg |= SPICTL_ARB_EN; | ||||||
|  | + | ||||||
|  | +	if (reg != old_reg) | ||||||
|  | +		rt2880_spi_write(rs, arbit_off, reg); | ||||||
|  | + | ||||||
|  | +	/* deselected the spi device */ | ||||||
|  | +	spi_set_cs(spi, false); | ||||||
|  | + | ||||||
|  | +	rt2880_dump_reg(master); | ||||||
|  | + | ||||||
|  | +	return 0; | ||||||
|  | +} | ||||||
|  | + | ||||||
|  | +static int rt2880_spi_prepare_message(struct spi_master *master, | ||||||
|  | +		struct spi_message *msg) | ||||||
|  | +{ | ||||||
|  | +	struct rt2880_spi *rs = spi_master_get_devdata(master); | ||||||
|  | +	struct spi_device *spi = msg->spi; | ||||||
|  | +	u32 reg; | ||||||
|  | + | ||||||
|  | +	if ((rs->mode == spi->mode) && (rs->speed == spi->max_speed_hz)) | ||||||
|  | +		return 0; | ||||||
|  | + | ||||||
|  | +#if 0 | ||||||
|  | +	/* set spido to tri-state */ | ||||||
|  | +	rt2880_spi_setbits(rs, RAMIPS_SPI_CTL, SPICTL_HIZSDO); | ||||||
|  | +#endif | ||||||
|  | + | ||||||
|  | +	reg = rt2880_spi_read(rs, RAMIPS_SPI_CFG); | ||||||
|  | + | ||||||
|  | +	reg &= ~(SPICFG_MSBFIRST | SPICFG_SPICLKPOL | | ||||||
|  | +			SPICFG_RXCLKEDGE_FALLING | | ||||||
|  | +			SPICFG_TXCLKEDGE_FALLING | | ||||||
|  | +			SPICFG_SPICLK_PRESCALE_MASK); | ||||||
|  | + | ||||||
|  | +	/* MSB */ | ||||||
|  | +	if (!(spi->mode & SPI_LSB_FIRST)) | ||||||
|  | +		reg |= SPICFG_MSBFIRST; | ||||||
|  | + | ||||||
|  | +	/* spi mode */ | ||||||
|  | +	switch (spi->mode & (SPI_CPOL | SPI_CPHA)) { | ||||||
|  | +	case SPI_MODE_0: | ||||||
|  | +		reg |= SPICFG_TXCLKEDGE_FALLING; | ||||||
|  | +		break; | ||||||
|  | +	case SPI_MODE_1: | ||||||
|  | +		reg |= SPICFG_RXCLKEDGE_FALLING; | ||||||
|  | +		break; | ||||||
|  | +	case SPI_MODE_2: | ||||||
|  | +		reg |= SPICFG_SPICLKPOL | SPICFG_RXCLKEDGE_FALLING; | ||||||
|  | +		break; | ||||||
|  | +	case SPI_MODE_3: | ||||||
|  | +		reg |= SPICFG_SPICLKPOL | SPICFG_TXCLKEDGE_FALLING; | ||||||
|  | +		break; | ||||||
|  | +	} | ||||||
|  | +	rs->mode = spi->mode; | ||||||
|  | + | ||||||
|  | +#if 0 | ||||||
|  | +	/* set spiclk and spiena to tri-state */ | ||||||
|  | +	reg |= SPICFG_HIZSPI; | ||||||
|  | +#endif | ||||||
|  | + | ||||||
|  | +	/* clock divide */ | ||||||
|  | +	reg |= rt2880_spi_baudrate_get(spi, spi->max_speed_hz); | ||||||
|  | + | ||||||
|  | +	rt2880_spi_write(rs, RAMIPS_SPI_CFG, reg); | ||||||
|  | + | ||||||
|  | +	return 0; | ||||||
|  | +} | ||||||
|  | + | ||||||
|  | +static int rt2880_spi_probe(struct platform_device *pdev) | ||||||
|  | +{ | ||||||
|  | +	struct spi_master *master; | ||||||
|  | +	struct rt2880_spi *rs; | ||||||
|  | +	void __iomem *base; | ||||||
|  | +	struct resource *r; | ||||||
|  | +	struct clk *clk; | ||||||
|  | +	int ret; | ||||||
|  | + | ||||||
|  | +	r = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||||||
|  | +	base = devm_ioremap_resource(&pdev->dev, r); | ||||||
|  | +	if (IS_ERR(base)) | ||||||
|  | +		return PTR_ERR(base); | ||||||
|  | + | ||||||
|  | +	clk = devm_clk_get(&pdev->dev, NULL); | ||||||
|  | +	if (IS_ERR(clk)) { | ||||||
|  | +		dev_err(&pdev->dev, "unable to get SYS clock\n"); | ||||||
|  | +		return PTR_ERR(clk); | ||||||
|  | +	} | ||||||
|  | + | ||||||
|  | +	ret = clk_prepare_enable(clk); | ||||||
|  | +	if (ret) | ||||||
|  | +		goto err_clk; | ||||||
|  | + | ||||||
|  | +	master = spi_alloc_master(&pdev->dev, sizeof(*rs)); | ||||||
|  | +	if (master == NULL) { | ||||||
|  | +		dev_dbg(&pdev->dev, "master allocation failed\n"); | ||||||
|  | +		ret = -ENOMEM; | ||||||
|  | +		goto err_clk; | ||||||
|  | +	} | ||||||
|  | + | ||||||
|  | +	master->dev.of_node = pdev->dev.of_node; | ||||||
|  | +	master->mode_bits = RT2880_SPI_MODE_BITS; | ||||||
|  | +	master->bits_per_word_mask = SPI_BPW_MASK(8); | ||||||
|  | +	master->min_speed_hz = clk_get_rate(clk) / 128; | ||||||
|  | +	master->max_speed_hz = clk_get_rate(clk) / 2; | ||||||
|  | +	master->flags = SPI_MASTER_HALF_DUPLEX; | ||||||
|  | +	master->setup = rt2880_spi_setup; | ||||||
|  | +	master->prepare_message = rt2880_spi_prepare_message; | ||||||
|  | +	master->set_cs = rt2880_spi_set_cs; | ||||||
|  | +	master->transfer_one = rt2880_spi_transfer_one, | ||||||
|  | + | ||||||
|  | +	dev_set_drvdata(&pdev->dev, master); | ||||||
|  | + | ||||||
|  | +	rs = spi_master_get_devdata(master); | ||||||
|  | +	rs->master = master; | ||||||
|  | +	rs->base = base; | ||||||
|  | +	rs->clk = clk; | ||||||
|  | + | ||||||
|  | +	if (atomic_inc_return(&hw_reset_count) == 1) | ||||||
|  | +		device_reset(&pdev->dev); | ||||||
|  | + | ||||||
|  | +	ret = devm_spi_register_master(&pdev->dev, master); | ||||||
|  | +	if (ret < 0) { | ||||||
|  | +		dev_err(&pdev->dev, "devm_spi_register_master error.\n"); | ||||||
|  | +		goto err_master; | ||||||
|  | +	} | ||||||
|  | + | ||||||
|  | +	return ret; | ||||||
|  | + | ||||||
|  | +err_master: | ||||||
|  | +	spi_master_put(master); | ||||||
|  | +	kfree(master); | ||||||
|  | +err_clk: | ||||||
|  | +	clk_disable_unprepare(clk); | ||||||
|  | + | ||||||
|  | +	return ret; | ||||||
|  | +} | ||||||
|  | + | ||||||
|  | +static int rt2880_spi_remove(struct platform_device *pdev) | ||||||
|  | +{ | ||||||
|  | +	struct spi_master *master; | ||||||
|  | +	struct rt2880_spi *rs; | ||||||
|  | + | ||||||
|  | +	master = dev_get_drvdata(&pdev->dev); | ||||||
|  | +	rs = spi_master_get_devdata(master); | ||||||
|  | + | ||||||
|  | +	clk_disable_unprepare(rs->clk); | ||||||
|  | +	atomic_dec(&hw_reset_count); | ||||||
|  | + | ||||||
|  | +	return 0; | ||||||
|  | +} | ||||||
|  | + | ||||||
|  | +MODULE_ALIAS("platform:" DRIVER_NAME); | ||||||
|  | + | ||||||
|  | +static const struct of_device_id rt2880_spi_match[] = { | ||||||
|  | +	{ .compatible = "ralink,rt2880-spi" }, | ||||||
|  | +	{}, | ||||||
|  | +}; | ||||||
|  | +MODULE_DEVICE_TABLE(of, rt2880_spi_match); | ||||||
|  | + | ||||||
|  | +static struct platform_driver rt2880_spi_driver = { | ||||||
|  | +	.driver = { | ||||||
|  | +		.name = DRIVER_NAME, | ||||||
|  | +		.owner = THIS_MODULE, | ||||||
|  | +		.of_match_table = rt2880_spi_match, | ||||||
|  | +	}, | ||||||
|  | +	.probe = rt2880_spi_probe, | ||||||
|  | +	.remove = rt2880_spi_remove, | ||||||
|  | +}; | ||||||
|  | + | ||||||
|  | +module_platform_driver(rt2880_spi_driver); | ||||||
|  | + | ||||||
|  | +MODULE_DESCRIPTION("Ralink SPI driver"); | ||||||
|  | +MODULE_AUTHOR("Sergiy <piratfm@gmail.com>"); | ||||||
|  | +MODULE_AUTHOR("Gabor Juhos <juhosg@openwrt.org>"); | ||||||
|  | +MODULE_LICENSE("GPL"); | ||||||
| @@ -0,0 +1,487 @@ | |||||||
|  | From cbd66c626e16743b05af807ad48012c0a097b9fb Mon Sep 17 00:00:00 2001 | ||||||
|  | From: Stefan Roese <sr@denx.de> | ||||||
|  | Date: Mon, 25 Mar 2019 09:29:25 +0100 | ||||||
|  | Subject: [PATCH] spi: mt7621: Move SPI driver out of staging | ||||||
|  |  | ||||||
|  | This patch moves the MT7621 SPI driver, which is used on some Ralink / | ||||||
|  | MediaTek MT76xx MIPS SoC's, out of the staging directory. No changes to | ||||||
|  | the source code are done in this patch. | ||||||
|  |  | ||||||
|  | This driver version was tested successfully on an MT7688 based platform | ||||||
|  | with an SPI NOR on CS0 and an SPI NAND on CS1 without any issues (so | ||||||
|  | far). | ||||||
|  |  | ||||||
|  | This patch also documents the devicetree bindings for the MT7621 SPI | ||||||
|  | device driver. | ||||||
|  |  | ||||||
|  | Signed-off-by: Stefan Roese <sr@denx.de> | ||||||
|  | Cc: Rob Herring <robh@kernel.org> | ||||||
|  | Cc: Mark Brown <broonie@kernel.org> | ||||||
|  | Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org> | ||||||
|  | Cc: NeilBrown <neil@brown.name> | ||||||
|  | Cc: Sankalp Negi <sankalpnegi2310@gmail.com> | ||||||
|  | Cc: Chuanhong Guo <gch981213@gmail.com> | ||||||
|  | Cc: John Crispin <john@phrozen.org> | ||||||
|  | Cc: Armando Miraglia <arma2ff0@gmail.com> | ||||||
|  | Signed-off-by: Mark Brown <broonie@kernel.org> | ||||||
|  | --- | ||||||
|  |  .../devicetree/bindings/spi/spi-mt7621.txt    | 26 ++++++ | ||||||
|  |  drivers/spi/Kconfig                           |  6 ++ | ||||||
|  |  drivers/spi/Makefile                          |  1 + | ||||||
|  |  .../{staging/mt7621-spi => spi}/spi-mt7621.c  | 83 +++++++++---------- | ||||||
|  |  drivers/staging/Kconfig                       |  2 - | ||||||
|  |  drivers/staging/Makefile                      |  1 - | ||||||
|  |  drivers/staging/mt7621-spi/Kconfig            |  6 -- | ||||||
|  |  drivers/staging/mt7621-spi/Makefile           |  1 - | ||||||
|  |  drivers/staging/mt7621-spi/TODO               |  5 -- | ||||||
|  |  9 files changed, 74 insertions(+), 57 deletions(-) | ||||||
|  |  create mode 100644 Documentation/devicetree/bindings/spi/spi-mt7621.txt | ||||||
|  |  rename drivers/{staging/mt7621-spi => spi}/spi-mt7621.c (88%) | ||||||
|  |  delete mode 100644 drivers/staging/mt7621-spi/Kconfig | ||||||
|  |  delete mode 100644 drivers/staging/mt7621-spi/Makefile | ||||||
|  |  delete mode 100644 drivers/staging/mt7621-spi/TODO | ||||||
|  |  | ||||||
|  | --- a/drivers/spi/Kconfig | ||||||
|  | +++ b/drivers/spi/Kconfig | ||||||
|  | @@ -569,6 +569,12 @@ config SPI_RT2880 | ||||||
|  |  	help | ||||||
|  |  	  This selects a driver for the Ralink RT288x/RT305x SPI Controller. | ||||||
|  |   | ||||||
|  | +config SPI_MT7621 | ||||||
|  | +	tristate "MediaTek MT7621 SPI Controller" | ||||||
|  | +	depends on RALINK | ||||||
|  | +	help | ||||||
|  | +	  This selects a driver for the MediaTek MT7621 SPI Controller. | ||||||
|  | + | ||||||
|  |  config SPI_S3C24XX | ||||||
|  |  	tristate "Samsung S3C24XX series SPI" | ||||||
|  |  	depends on ARCH_S3C24XX | ||||||
|  | --- a/drivers/spi/Makefile | ||||||
|  | +++ b/drivers/spi/Makefile | ||||||
|  | @@ -60,6 +60,7 @@ obj-$(CONFIG_SPI_MPC512x_PSC)		+= spi-mp | ||||||
|  |  obj-$(CONFIG_SPI_MPC52xx_PSC)		+= spi-mpc52xx-psc.o | ||||||
|  |  obj-$(CONFIG_SPI_MPC52xx)		+= spi-mpc52xx.o | ||||||
|  |  obj-$(CONFIG_SPI_MT65XX)                += spi-mt65xx.o | ||||||
|  | +obj-$(CONFIG_SPI_MT7621)		+= spi-mt7621.o | ||||||
|  |  obj-$(CONFIG_SPI_MXS)			+= spi-mxs.o | ||||||
|  |  obj-$(CONFIG_SPI_NUC900)		+= spi-nuc900.o | ||||||
|  |  obj-$(CONFIG_SPI_OC_TINY)		+= spi-oc-tiny.o | ||||||
|  | --- /dev/null | ||||||
|  | +++ b/drivers/spi/spi-mt7621.c | ||||||
|  | @@ -0,0 +1,416 @@ | ||||||
|  | +// SPDX-License-Identifier: GPL-2.0 | ||||||
|  | +// | ||||||
|  | +// spi-mt7621.c -- MediaTek MT7621 SPI controller driver | ||||||
|  | +// | ||||||
|  | +// Copyright (C) 2011 Sergiy <piratfm@gmail.com> | ||||||
|  | +// Copyright (C) 2011-2013 Gabor Juhos <juhosg@openwrt.org> | ||||||
|  | +// Copyright (C) 2014-2015 Felix Fietkau <nbd@nbd.name> | ||||||
|  | +// | ||||||
|  | +// Some parts are based on spi-orion.c: | ||||||
|  | +//   Author: Shadi Ammouri <shadi@marvell.com> | ||||||
|  | +//   Copyright (C) 2007-2008 Marvell Ltd. | ||||||
|  | + | ||||||
|  | +#include <linux/clk.h> | ||||||
|  | +#include <linux/delay.h> | ||||||
|  | +#include <linux/io.h> | ||||||
|  | +#include <linux/module.h> | ||||||
|  | +#include <linux/of_device.h> | ||||||
|  | +#include <linux/reset.h> | ||||||
|  | +#include <linux/spi/spi.h> | ||||||
|  | + | ||||||
|  | +#define DRIVER_NAME		"spi-mt7621" | ||||||
|  | + | ||||||
|  | +/* in usec */ | ||||||
|  | +#define RALINK_SPI_WAIT_MAX_LOOP 2000 | ||||||
|  | + | ||||||
|  | +/* SPISTAT register bit field */ | ||||||
|  | +#define SPISTAT_BUSY		BIT(0) | ||||||
|  | + | ||||||
|  | +#define MT7621_SPI_TRANS	0x00 | ||||||
|  | +#define SPITRANS_BUSY		BIT(16) | ||||||
|  | + | ||||||
|  | +#define MT7621_SPI_OPCODE	0x04 | ||||||
|  | +#define MT7621_SPI_DATA0	0x08 | ||||||
|  | +#define MT7621_SPI_DATA4	0x18 | ||||||
|  | +#define SPI_CTL_TX_RX_CNT_MASK	0xff | ||||||
|  | +#define SPI_CTL_START		BIT(8) | ||||||
|  | + | ||||||
|  | +#define MT7621_SPI_MASTER	0x28 | ||||||
|  | +#define MASTER_MORE_BUFMODE	BIT(2) | ||||||
|  | +#define MASTER_FULL_DUPLEX	BIT(10) | ||||||
|  | +#define MASTER_RS_CLK_SEL	GENMASK(27, 16) | ||||||
|  | +#define MASTER_RS_CLK_SEL_SHIFT	16 | ||||||
|  | +#define MASTER_RS_SLAVE_SEL	GENMASK(31, 29) | ||||||
|  | + | ||||||
|  | +#define MT7621_SPI_MOREBUF	0x2c | ||||||
|  | +#define MT7621_SPI_POLAR	0x38 | ||||||
|  | +#define MT7621_SPI_SPACE	0x3c | ||||||
|  | + | ||||||
|  | +#define MT7621_CPHA		BIT(5) | ||||||
|  | +#define MT7621_CPOL		BIT(4) | ||||||
|  | +#define MT7621_LSB_FIRST	BIT(3) | ||||||
|  | + | ||||||
|  | +struct mt7621_spi { | ||||||
|  | +	struct spi_controller	*master; | ||||||
|  | +	void __iomem		*base; | ||||||
|  | +	unsigned int		sys_freq; | ||||||
|  | +	unsigned int		speed; | ||||||
|  | +	struct clk		*clk; | ||||||
|  | +	int			pending_write; | ||||||
|  | +}; | ||||||
|  | + | ||||||
|  | +static inline struct mt7621_spi *spidev_to_mt7621_spi(struct spi_device *spi) | ||||||
|  | +{ | ||||||
|  | +	return spi_controller_get_devdata(spi->master); | ||||||
|  | +} | ||||||
|  | + | ||||||
|  | +static inline u32 mt7621_spi_read(struct mt7621_spi *rs, u32 reg) | ||||||
|  | +{ | ||||||
|  | +	return ioread32(rs->base + reg); | ||||||
|  | +} | ||||||
|  | + | ||||||
|  | +static inline void mt7621_spi_write(struct mt7621_spi *rs, u32 reg, u32 val) | ||||||
|  | +{ | ||||||
|  | +	iowrite32(val, rs->base + reg); | ||||||
|  | +} | ||||||
|  | + | ||||||
|  | +static void mt7621_spi_set_cs(struct spi_device *spi, int enable) | ||||||
|  | +{ | ||||||
|  | +	struct mt7621_spi *rs = spidev_to_mt7621_spi(spi); | ||||||
|  | +	int cs = spi->chip_select; | ||||||
|  | +	u32 polar = 0; | ||||||
|  | +	u32 master; | ||||||
|  | + | ||||||
|  | +	/* | ||||||
|  | +	 * Select SPI device 7, enable "more buffer mode" and disable | ||||||
|  | +	 * full-duplex (only half-duplex really works on this chip | ||||||
|  | +	 * reliably) | ||||||
|  | +	 */ | ||||||
|  | +	master = mt7621_spi_read(rs, MT7621_SPI_MASTER); | ||||||
|  | +	master |= MASTER_RS_SLAVE_SEL | MASTER_MORE_BUFMODE; | ||||||
|  | +	master &= ~MASTER_FULL_DUPLEX; | ||||||
|  | +	mt7621_spi_write(rs, MT7621_SPI_MASTER, master); | ||||||
|  | + | ||||||
|  | +	rs->pending_write = 0; | ||||||
|  | + | ||||||
|  | +	if (enable) | ||||||
|  | +		polar = BIT(cs); | ||||||
|  | +	mt7621_spi_write(rs, MT7621_SPI_POLAR, polar); | ||||||
|  | +} | ||||||
|  | + | ||||||
|  | +static int mt7621_spi_prepare(struct spi_device *spi, unsigned int speed) | ||||||
|  | +{ | ||||||
|  | +	struct mt7621_spi *rs = spidev_to_mt7621_spi(spi); | ||||||
|  | +	u32 rate; | ||||||
|  | +	u32 reg; | ||||||
|  | + | ||||||
|  | +	dev_dbg(&spi->dev, "speed:%u\n", speed); | ||||||
|  | + | ||||||
|  | +	rate = DIV_ROUND_UP(rs->sys_freq, speed); | ||||||
|  | +	dev_dbg(&spi->dev, "rate-1:%u\n", rate); | ||||||
|  | + | ||||||
|  | +	if (rate > 4097) | ||||||
|  | +		return -EINVAL; | ||||||
|  | + | ||||||
|  | +	if (rate < 2) | ||||||
|  | +		rate = 2; | ||||||
|  | + | ||||||
|  | +	reg = mt7621_spi_read(rs, MT7621_SPI_MASTER); | ||||||
|  | +	reg &= ~MASTER_RS_CLK_SEL; | ||||||
|  | +	reg |= (rate - 2) << MASTER_RS_CLK_SEL_SHIFT; | ||||||
|  | +	rs->speed = speed; | ||||||
|  | + | ||||||
|  | +	reg &= ~MT7621_LSB_FIRST; | ||||||
|  | +	if (spi->mode & SPI_LSB_FIRST) | ||||||
|  | +		reg |= MT7621_LSB_FIRST; | ||||||
|  | + | ||||||
|  | +	/* | ||||||
|  | +	 * This SPI controller seems to be tested on SPI flash only and some | ||||||
|  | +	 * bits are swizzled under other SPI modes probably due to incorrect | ||||||
|  | +	 * wiring inside the silicon. Only mode 0 works correctly. | ||||||
|  | +	 */ | ||||||
|  | +	reg &= ~(MT7621_CPHA | MT7621_CPOL); | ||||||
|  | + | ||||||
|  | +	mt7621_spi_write(rs, MT7621_SPI_MASTER, reg); | ||||||
|  | + | ||||||
|  | +	return 0; | ||||||
|  | +} | ||||||
|  | + | ||||||
|  | +static inline int mt7621_spi_wait_till_ready(struct mt7621_spi *rs) | ||||||
|  | +{ | ||||||
|  | +	int i; | ||||||
|  | + | ||||||
|  | +	for (i = 0; i < RALINK_SPI_WAIT_MAX_LOOP; i++) { | ||||||
|  | +		u32 status; | ||||||
|  | + | ||||||
|  | +		status = mt7621_spi_read(rs, MT7621_SPI_TRANS); | ||||||
|  | +		if ((status & SPITRANS_BUSY) == 0) | ||||||
|  | +			return 0; | ||||||
|  | +		cpu_relax(); | ||||||
|  | +		udelay(1); | ||||||
|  | +	} | ||||||
|  | + | ||||||
|  | +	return -ETIMEDOUT; | ||||||
|  | +} | ||||||
|  | + | ||||||
|  | +static void mt7621_spi_read_half_duplex(struct mt7621_spi *rs, | ||||||
|  | +					int rx_len, u8 *buf) | ||||||
|  | +{ | ||||||
|  | +	int tx_len; | ||||||
|  | + | ||||||
|  | +	/* | ||||||
|  | +	 * Combine with any pending write, and perform one or more half-duplex | ||||||
|  | +	 * transactions reading 'len' bytes. Data to be written is already in | ||||||
|  | +	 * MT7621_SPI_DATA. | ||||||
|  | +	 */ | ||||||
|  | +	tx_len = rs->pending_write; | ||||||
|  | +	rs->pending_write = 0; | ||||||
|  | + | ||||||
|  | +	while (rx_len || tx_len) { | ||||||
|  | +		int i; | ||||||
|  | +		u32 val = (min(tx_len, 4) * 8) << 24; | ||||||
|  | +		int rx = min(rx_len, 32); | ||||||
|  | + | ||||||
|  | +		if (tx_len > 4) | ||||||
|  | +			val |= (tx_len - 4) * 8; | ||||||
|  | +		val |= (rx * 8) << 12; | ||||||
|  | +		mt7621_spi_write(rs, MT7621_SPI_MOREBUF, val); | ||||||
|  | + | ||||||
|  | +		tx_len = 0; | ||||||
|  | + | ||||||
|  | +		val = mt7621_spi_read(rs, MT7621_SPI_TRANS); | ||||||
|  | +		val |= SPI_CTL_START; | ||||||
|  | +		mt7621_spi_write(rs, MT7621_SPI_TRANS, val); | ||||||
|  | + | ||||||
|  | +		mt7621_spi_wait_till_ready(rs); | ||||||
|  | + | ||||||
|  | +		for (i = 0; i < rx; i++) { | ||||||
|  | +			if ((i % 4) == 0) | ||||||
|  | +				val = mt7621_spi_read(rs, MT7621_SPI_DATA0 + i); | ||||||
|  | +			*buf++ = val & 0xff; | ||||||
|  | +			val >>= 8; | ||||||
|  | +		} | ||||||
|  | + | ||||||
|  | +		rx_len -= i; | ||||||
|  | +	} | ||||||
|  | +} | ||||||
|  | + | ||||||
|  | +static inline void mt7621_spi_flush(struct mt7621_spi *rs) | ||||||
|  | +{ | ||||||
|  | +	mt7621_spi_read_half_duplex(rs, 0, NULL); | ||||||
|  | +} | ||||||
|  | + | ||||||
|  | +static void mt7621_spi_write_half_duplex(struct mt7621_spi *rs, | ||||||
|  | +					 int tx_len, const u8 *buf) | ||||||
|  | +{ | ||||||
|  | +	int len = rs->pending_write; | ||||||
|  | +	int val = 0; | ||||||
|  | + | ||||||
|  | +	if (len & 3) { | ||||||
|  | +		val = mt7621_spi_read(rs, MT7621_SPI_OPCODE + (len & ~3)); | ||||||
|  | +		if (len < 4) { | ||||||
|  | +			val <<= (4 - len) * 8; | ||||||
|  | +			val = swab32(val); | ||||||
|  | +		} | ||||||
|  | +	} | ||||||
|  | + | ||||||
|  | +	while (tx_len > 0) { | ||||||
|  | +		if (len >= 36) { | ||||||
|  | +			rs->pending_write = len; | ||||||
|  | +			mt7621_spi_flush(rs); | ||||||
|  | +			len = 0; | ||||||
|  | +		} | ||||||
|  | + | ||||||
|  | +		val |= *buf++ << (8 * (len & 3)); | ||||||
|  | +		len++; | ||||||
|  | +		if ((len & 3) == 0) { | ||||||
|  | +			if (len == 4) | ||||||
|  | +				/* The byte-order of the opcode is weird! */ | ||||||
|  | +				val = swab32(val); | ||||||
|  | +			mt7621_spi_write(rs, MT7621_SPI_OPCODE + len - 4, val); | ||||||
|  | +			val = 0; | ||||||
|  | +		} | ||||||
|  | +		tx_len -= 1; | ||||||
|  | +	} | ||||||
|  | + | ||||||
|  | +	if (len & 3) { | ||||||
|  | +		if (len < 4) { | ||||||
|  | +			val = swab32(val); | ||||||
|  | +			val >>= (4 - len) * 8; | ||||||
|  | +		} | ||||||
|  | +		mt7621_spi_write(rs, MT7621_SPI_OPCODE + (len & ~3), val); | ||||||
|  | +	} | ||||||
|  | + | ||||||
|  | +	rs->pending_write = len; | ||||||
|  | +} | ||||||
|  | + | ||||||
|  | +static int mt7621_spi_transfer_one_message(struct spi_controller *master, | ||||||
|  | +					   struct spi_message *m) | ||||||
|  | +{ | ||||||
|  | +	struct mt7621_spi *rs = spi_controller_get_devdata(master); | ||||||
|  | +	struct spi_device *spi = m->spi; | ||||||
|  | +	unsigned int speed = spi->max_speed_hz; | ||||||
|  | +	struct spi_transfer *t = NULL; | ||||||
|  | +	int status = 0; | ||||||
|  | + | ||||||
|  | +	mt7621_spi_wait_till_ready(rs); | ||||||
|  | + | ||||||
|  | +	list_for_each_entry(t, &m->transfers, transfer_list) | ||||||
|  | +		if (t->speed_hz < speed) | ||||||
|  | +			speed = t->speed_hz; | ||||||
|  | + | ||||||
|  | +	if (mt7621_spi_prepare(spi, speed)) { | ||||||
|  | +		status = -EIO; | ||||||
|  | +		goto msg_done; | ||||||
|  | +	} | ||||||
|  | + | ||||||
|  | +	/* Assert CS */ | ||||||
|  | +	mt7621_spi_set_cs(spi, 1); | ||||||
|  | + | ||||||
|  | +	m->actual_length = 0; | ||||||
|  | +	list_for_each_entry(t, &m->transfers, transfer_list) { | ||||||
|  | +		if ((t->rx_buf) && (t->tx_buf)) { | ||||||
|  | +			/* | ||||||
|  | +			 * This controller will shift some extra data out | ||||||
|  | +			 * of spi_opcode if (mosi_bit_cnt > 0) && | ||||||
|  | +			 * (cmd_bit_cnt == 0). So the claimed full-duplex | ||||||
|  | +			 * support is broken since we have no way to read | ||||||
|  | +			 * the MISO value during that bit. | ||||||
|  | +			 */ | ||||||
|  | +			status = -EIO; | ||||||
|  | +			goto msg_done; | ||||||
|  | +		} else if (t->rx_buf) { | ||||||
|  | +			mt7621_spi_read_half_duplex(rs, t->len, t->rx_buf); | ||||||
|  | +		} else if (t->tx_buf) { | ||||||
|  | +			mt7621_spi_write_half_duplex(rs, t->len, t->tx_buf); | ||||||
|  | +		} | ||||||
|  | +		m->actual_length += t->len; | ||||||
|  | +	} | ||||||
|  | + | ||||||
|  | +	/* Flush data and deassert CS */ | ||||||
|  | +	mt7621_spi_flush(rs); | ||||||
|  | +	mt7621_spi_set_cs(spi, 0); | ||||||
|  | + | ||||||
|  | +msg_done: | ||||||
|  | +	m->status = status; | ||||||
|  | +	spi_finalize_current_message(master); | ||||||
|  | + | ||||||
|  | +	return 0; | ||||||
|  | +} | ||||||
|  | + | ||||||
|  | +static int mt7621_spi_setup(struct spi_device *spi) | ||||||
|  | +{ | ||||||
|  | +	struct mt7621_spi *rs = spidev_to_mt7621_spi(spi); | ||||||
|  | + | ||||||
|  | +	if ((spi->max_speed_hz == 0) || | ||||||
|  | +	    (spi->max_speed_hz > (rs->sys_freq / 2))) | ||||||
|  | +		spi->max_speed_hz = (rs->sys_freq / 2); | ||||||
|  | + | ||||||
|  | +	if (spi->max_speed_hz < (rs->sys_freq / 4097)) { | ||||||
|  | +		dev_err(&spi->dev, "setup: requested speed is too low %d Hz\n", | ||||||
|  | +			spi->max_speed_hz); | ||||||
|  | +		return -EINVAL; | ||||||
|  | +	} | ||||||
|  | + | ||||||
|  | +	return 0; | ||||||
|  | +} | ||||||
|  | + | ||||||
|  | +static const struct of_device_id mt7621_spi_match[] = { | ||||||
|  | +	{ .compatible = "ralink,mt7621-spi" }, | ||||||
|  | +	{}, | ||||||
|  | +}; | ||||||
|  | +MODULE_DEVICE_TABLE(of, mt7621_spi_match); | ||||||
|  | + | ||||||
|  | +static int mt7621_spi_probe(struct platform_device *pdev) | ||||||
|  | +{ | ||||||
|  | +	const struct of_device_id *match; | ||||||
|  | +	struct spi_controller *master; | ||||||
|  | +	struct mt7621_spi *rs; | ||||||
|  | +	void __iomem *base; | ||||||
|  | +	struct resource *r; | ||||||
|  | +	int status = 0; | ||||||
|  | +	struct clk *clk; | ||||||
|  | +	int ret; | ||||||
|  | + | ||||||
|  | +	match = of_match_device(mt7621_spi_match, &pdev->dev); | ||||||
|  | +	if (!match) | ||||||
|  | +		return -EINVAL; | ||||||
|  | + | ||||||
|  | +	r = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||||||
|  | +	base = devm_ioremap_resource(&pdev->dev, r); | ||||||
|  | +	if (IS_ERR(base)) | ||||||
|  | +		return PTR_ERR(base); | ||||||
|  | + | ||||||
|  | +	clk = devm_clk_get(&pdev->dev, NULL); | ||||||
|  | +	if (IS_ERR(clk)) { | ||||||
|  | +		dev_err(&pdev->dev, "unable to get SYS clock, err=%d\n", | ||||||
|  | +			status); | ||||||
|  | +		return PTR_ERR(clk); | ||||||
|  | +	} | ||||||
|  | + | ||||||
|  | +	status = clk_prepare_enable(clk); | ||||||
|  | +	if (status) | ||||||
|  | +		return status; | ||||||
|  | + | ||||||
|  | +	master = spi_alloc_master(&pdev->dev, sizeof(*rs)); | ||||||
|  | +	if (!master) { | ||||||
|  | +		dev_info(&pdev->dev, "master allocation failed\n"); | ||||||
|  | +		return -ENOMEM; | ||||||
|  | +	} | ||||||
|  | + | ||||||
|  | +	master->mode_bits = SPI_LSB_FIRST; | ||||||
|  | +	master->flags = SPI_CONTROLLER_HALF_DUPLEX; | ||||||
|  | +	master->setup = mt7621_spi_setup; | ||||||
|  | +	master->transfer_one_message = mt7621_spi_transfer_one_message; | ||||||
|  | +	master->bits_per_word_mask = SPI_BPW_MASK(8); | ||||||
|  | +	master->dev.of_node = pdev->dev.of_node; | ||||||
|  | +	master->num_chipselect = 2; | ||||||
|  | + | ||||||
|  | +	dev_set_drvdata(&pdev->dev, master); | ||||||
|  | + | ||||||
|  | +	rs = spi_controller_get_devdata(master); | ||||||
|  | +	rs->base = base; | ||||||
|  | +	rs->clk = clk; | ||||||
|  | +	rs->master = master; | ||||||
|  | +	rs->sys_freq = clk_get_rate(rs->clk); | ||||||
|  | +	rs->pending_write = 0; | ||||||
|  | +	dev_info(&pdev->dev, "sys_freq: %u\n", rs->sys_freq); | ||||||
|  | + | ||||||
|  | +	ret = device_reset(&pdev->dev); | ||||||
|  | +	if (ret) { | ||||||
|  | +		dev_err(&pdev->dev, "SPI reset failed!\n"); | ||||||
|  | +		return ret; | ||||||
|  | +	} | ||||||
|  | + | ||||||
|  | +	return devm_spi_register_controller(&pdev->dev, master); | ||||||
|  | +} | ||||||
|  | + | ||||||
|  | +static int mt7621_spi_remove(struct platform_device *pdev) | ||||||
|  | +{ | ||||||
|  | +	struct spi_controller *master; | ||||||
|  | +	struct mt7621_spi *rs; | ||||||
|  | + | ||||||
|  | +	master = dev_get_drvdata(&pdev->dev); | ||||||
|  | +	rs = spi_controller_get_devdata(master); | ||||||
|  | + | ||||||
|  | +	clk_disable_unprepare(rs->clk); | ||||||
|  | + | ||||||
|  | +	return 0; | ||||||
|  | +} | ||||||
|  | + | ||||||
|  | +MODULE_ALIAS("platform:" DRIVER_NAME); | ||||||
|  | + | ||||||
|  | +static struct platform_driver mt7621_spi_driver = { | ||||||
|  | +	.driver = { | ||||||
|  | +		.name = DRIVER_NAME, | ||||||
|  | +		.of_match_table = mt7621_spi_match, | ||||||
|  | +	}, | ||||||
|  | +	.probe = mt7621_spi_probe, | ||||||
|  | +	.remove = mt7621_spi_remove, | ||||||
|  | +}; | ||||||
|  | + | ||||||
|  | +module_platform_driver(mt7621_spi_driver); | ||||||
|  | + | ||||||
|  | +MODULE_DESCRIPTION("MT7621 SPI driver"); | ||||||
|  | +MODULE_AUTHOR("Felix Fietkau <nbd@nbd.name>"); | ||||||
|  | +MODULE_LICENSE("GPL"); | ||||||
| @@ -0,0 +1,507 @@ | |||||||
|  | From 723b8beaabf3c3c4b1ce69480141f1e926f3f3b2 Mon Sep 17 00:00:00 2001 | ||||||
|  | From: John Crispin <blogic@openwrt.org> | ||||||
|  | Date: Sun, 27 Jul 2014 09:52:56 +0100 | ||||||
|  | Subject: [PATCH 44/53] i2c: MIPS: adds ralink I2C driver | ||||||
|  |  | ||||||
|  | Signed-off-by: John Crispin <blogic@openwrt.org> | ||||||
|  | --- | ||||||
|  |  .../devicetree/bindings/i2c/i2c-ralink.txt         |   27 ++ | ||||||
|  |  drivers/i2c/busses/Kconfig                         |    4 + | ||||||
|  |  drivers/i2c/busses/Makefile                        |    1 + | ||||||
|  |  drivers/i2c/busses/i2c-ralink.c                    |  327 ++++++++++++++++++++ | ||||||
|  |  4 files changed, 359 insertions(+) | ||||||
|  |  create mode 100644 Documentation/devicetree/bindings/i2c/i2c-ralink.txt | ||||||
|  |  create mode 100644 drivers/i2c/busses/i2c-ralink.c | ||||||
|  |  | ||||||
|  | --- /dev/null | ||||||
|  | +++ b/Documentation/devicetree/bindings/i2c/i2c-ralink.txt | ||||||
|  | @@ -0,0 +1,27 @@ | ||||||
|  | +I2C for Ralink platforms | ||||||
|  | + | ||||||
|  | +Required properties : | ||||||
|  | +- compatible : Must be "link,rt3052-i2c" | ||||||
|  | +- reg: physical base address of the controller and length of memory mapped | ||||||
|  | +     region. | ||||||
|  | +- #address-cells = <1>; | ||||||
|  | +- #size-cells = <0>; | ||||||
|  | + | ||||||
|  | +Optional properties: | ||||||
|  | +- Child nodes conforming to i2c bus binding | ||||||
|  | + | ||||||
|  | +Example : | ||||||
|  | + | ||||||
|  | +palmbus@10000000 { | ||||||
|  | +	i2c@900 { | ||||||
|  | +		compatible = "link,rt3052-i2c"; | ||||||
|  | +		reg = <0x900 0x100>; | ||||||
|  | +		#address-cells = <1>; | ||||||
|  | +		#size-cells = <0>; | ||||||
|  | + | ||||||
|  | +		hwmon@4b { | ||||||
|  | +			compatible = "national,lm92"; | ||||||
|  | +			reg = <0x4b>; | ||||||
|  | +		}; | ||||||
|  | +	}; | ||||||
|  | +}; | ||||||
|  | --- a/drivers/i2c/busses/Kconfig | ||||||
|  | +++ b/drivers/i2c/busses/Kconfig | ||||||
|  | @@ -864,6 +864,11 @@ config I2C_RK3X | ||||||
|  |  	  This driver can also be built as a module. If so, the module will | ||||||
|  |  	  be called i2c-rk3x. | ||||||
|  |   | ||||||
|  | +config I2C_RALINK | ||||||
|  | +	tristate "Ralink I2C Controller" | ||||||
|  | +	depends on RALINK && !SOC_MT7621 | ||||||
|  | +	select OF_I2C | ||||||
|  | + | ||||||
|  |  config HAVE_S3C2410_I2C | ||||||
|  |  	bool | ||||||
|  |  	help | ||||||
|  | --- a/drivers/i2c/busses/Makefile | ||||||
|  | +++ b/drivers/i2c/busses/Makefile | ||||||
|  | @@ -84,6 +84,7 @@ obj-$(CONFIG_I2C_PNX)		+= i2c-pnx.o | ||||||
|  |  obj-$(CONFIG_I2C_PUV3)		+= i2c-puv3.o | ||||||
|  |  obj-$(CONFIG_I2C_PXA)		+= i2c-pxa.o | ||||||
|  |  obj-$(CONFIG_I2C_PXA_PCI)	+= i2c-pxa-pci.o | ||||||
|  | +obj-$(CONFIG_I2C_RALINK)	+= i2c-ralink.o | ||||||
|  |  obj-$(CONFIG_I2C_QUP)		+= i2c-qup.o | ||||||
|  |  obj-$(CONFIG_I2C_RIIC)		+= i2c-riic.o | ||||||
|  |  obj-$(CONFIG_I2C_RK3X)		+= i2c-rk3x.o | ||||||
|  | --- /dev/null | ||||||
|  | +++ b/drivers/i2c/busses/i2c-ralink.c | ||||||
|  | @@ -0,0 +1,435 @@ | ||||||
|  | +/* | ||||||
|  | + * drivers/i2c/busses/i2c-ralink.c | ||||||
|  | + * | ||||||
|  | + * Copyright (C) 2013 Steven Liu <steven_liu@mediatek.com> | ||||||
|  | + * Copyright (C) 2016 Michael Lee <igvtee@gmail.com> | ||||||
|  | + * | ||||||
|  | + * Improve driver for i2cdetect from i2c-tools to detect i2c devices on the bus. | ||||||
|  | + * (C) 2014 Sittisak <sittisaks@hotmail.com> | ||||||
|  | + * | ||||||
|  | + * This software is licensed under the terms of the GNU General Public | ||||||
|  | + * License version 2, as published by the Free Software Foundation, and | ||||||
|  | + * may be copied, distributed, and modified under those terms. | ||||||
|  | + * | ||||||
|  | + * 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. | ||||||
|  | + * | ||||||
|  | + */ | ||||||
|  | + | ||||||
|  | +#include <linux/interrupt.h> | ||||||
|  | +#include <linux/kernel.h> | ||||||
|  | +#include <linux/module.h> | ||||||
|  | +#include <linux/reset.h> | ||||||
|  | +#include <linux/delay.h> | ||||||
|  | +#include <linux/slab.h> | ||||||
|  | +#include <linux/init.h> | ||||||
|  | +#include <linux/errno.h> | ||||||
|  | +#include <linux/platform_device.h> | ||||||
|  | +#include <linux/of_platform.h> | ||||||
|  | +#include <linux/i2c.h> | ||||||
|  | +#include <linux/io.h> | ||||||
|  | +#include <linux/err.h> | ||||||
|  | +#include <linux/clk.h> | ||||||
|  | + | ||||||
|  | +#define REG_CONFIG_REG		0x00 | ||||||
|  | +#define REG_CLKDIV_REG		0x04 | ||||||
|  | +#define REG_DEVADDR_REG		0x08 | ||||||
|  | +#define REG_ADDR_REG		0x0C | ||||||
|  | +#define REG_DATAOUT_REG		0x10 | ||||||
|  | +#define REG_DATAIN_REG		0x14 | ||||||
|  | +#define REG_STATUS_REG		0x18 | ||||||
|  | +#define REG_STARTXFR_REG	0x1C | ||||||
|  | +#define REG_BYTECNT_REG		0x20 | ||||||
|  | + | ||||||
|  | +/* REG_CONFIG_REG */ | ||||||
|  | +#define I2C_ADDRLEN_OFFSET	5 | ||||||
|  | +#define I2C_DEVADLEN_OFFSET	2 | ||||||
|  | +#define I2C_ADDRLEN_MASK	0x3 | ||||||
|  | +#define I2C_ADDR_DIS		BIT(1) | ||||||
|  | +#define I2C_DEVADDR_DIS		BIT(0) | ||||||
|  | +#define I2C_ADDRLEN_8		(7 << I2C_ADDRLEN_OFFSET) | ||||||
|  | +#define I2C_DEVADLEN_7		(6 << I2C_DEVADLEN_OFFSET) | ||||||
|  | +#define I2C_CONF_DEFAULT	(I2C_ADDRLEN_8 | I2C_DEVADLEN_7) | ||||||
|  | + | ||||||
|  | +/* REG_CLKDIV_REG */ | ||||||
|  | +#define I2C_CLKDIV_MASK		0xffff | ||||||
|  | + | ||||||
|  | +/* REG_DEVADDR_REG */ | ||||||
|  | +#define I2C_DEVADDR_MASK	0x7f | ||||||
|  | + | ||||||
|  | +/* REG_ADDR_REG */ | ||||||
|  | +#define I2C_ADDR_MASK		0xff | ||||||
|  | + | ||||||
|  | +/* REG_STATUS_REG */ | ||||||
|  | +#define I2C_STARTERR		BIT(4) | ||||||
|  | +#define I2C_ACKERR		BIT(3) | ||||||
|  | +#define I2C_DATARDY		BIT(2) | ||||||
|  | +#define I2C_SDOEMPTY		BIT(1) | ||||||
|  | +#define I2C_BUSY		BIT(0) | ||||||
|  | + | ||||||
|  | +/* REG_STARTXFR_REG */ | ||||||
|  | +#define NOSTOP_CMD		BIT(2) | ||||||
|  | +#define NODATA_CMD		BIT(1) | ||||||
|  | +#define READ_CMD		BIT(0) | ||||||
|  | + | ||||||
|  | +/* REG_BYTECNT_REG */ | ||||||
|  | +#define BYTECNT_MAX		64 | ||||||
|  | +#define SET_BYTECNT(x)		(x - 1) | ||||||
|  | + | ||||||
|  | +/* timeout waiting for I2C devices to respond (clock streching) */ | ||||||
|  | +#define TIMEOUT_MS              1000 | ||||||
|  | +#define DELAY_INTERVAL_US       100 | ||||||
|  | + | ||||||
|  | +struct rt_i2c { | ||||||
|  | +	void __iomem *base; | ||||||
|  | +	struct clk *clk; | ||||||
|  | +	struct device *dev; | ||||||
|  | +	struct i2c_adapter adap; | ||||||
|  | +	u32 cur_clk; | ||||||
|  | +	u32 clk_div; | ||||||
|  | +	u32 flags; | ||||||
|  | +}; | ||||||
|  | + | ||||||
|  | +static void rt_i2c_w32(struct rt_i2c *i2c, u32 val, unsigned reg) | ||||||
|  | +{ | ||||||
|  | +	iowrite32(val, i2c->base + reg); | ||||||
|  | +} | ||||||
|  | + | ||||||
|  | +static u32 rt_i2c_r32(struct rt_i2c *i2c, unsigned reg) | ||||||
|  | +{ | ||||||
|  | +	return ioread32(i2c->base + reg); | ||||||
|  | +} | ||||||
|  | + | ||||||
|  | +static int poll_down_timeout(void __iomem *addr, u32 mask) | ||||||
|  | +{ | ||||||
|  | +	unsigned long timeout = jiffies + msecs_to_jiffies(TIMEOUT_MS); | ||||||
|  | + | ||||||
|  | +	do { | ||||||
|  | +		if (!(readl_relaxed(addr) & mask)) | ||||||
|  | +			return 0; | ||||||
|  | + | ||||||
|  | +		usleep_range(DELAY_INTERVAL_US, DELAY_INTERVAL_US + 50); | ||||||
|  | +	} while (time_before(jiffies, timeout)); | ||||||
|  | + | ||||||
|  | +	return (readl_relaxed(addr) & mask) ? -EAGAIN : 0; | ||||||
|  | +} | ||||||
|  | + | ||||||
|  | +static int rt_i2c_wait_idle(struct rt_i2c *i2c) | ||||||
|  | +{ | ||||||
|  | +	int ret; | ||||||
|  | + | ||||||
|  | +	ret = poll_down_timeout(i2c->base + REG_STATUS_REG, I2C_BUSY); | ||||||
|  | +	if (ret < 0) | ||||||
|  | +		dev_dbg(i2c->dev, "idle err(%d)\n", ret); | ||||||
|  | + | ||||||
|  | +	return ret; | ||||||
|  | +} | ||||||
|  | + | ||||||
|  | +static int poll_up_timeout(void __iomem *addr, u32 mask) | ||||||
|  | +{ | ||||||
|  | +	unsigned long timeout = jiffies + msecs_to_jiffies(TIMEOUT_MS); | ||||||
|  | +	u32 status; | ||||||
|  | + | ||||||
|  | +	do { | ||||||
|  | +		status = readl_relaxed(addr); | ||||||
|  | + | ||||||
|  | +		/* check error status */ | ||||||
|  | +		if (status & I2C_STARTERR) | ||||||
|  | +			return -EAGAIN; | ||||||
|  | +		else if (status & I2C_ACKERR) | ||||||
|  | +			return -ENXIO; | ||||||
|  | +		else if (status & mask) | ||||||
|  | +			return 0; | ||||||
|  | + | ||||||
|  | +		usleep_range(DELAY_INTERVAL_US, DELAY_INTERVAL_US + 50); | ||||||
|  | +	} while (time_before(jiffies, timeout)); | ||||||
|  | + | ||||||
|  | +	return -ETIMEDOUT; | ||||||
|  | +} | ||||||
|  | + | ||||||
|  | +static int rt_i2c_wait_rx_done(struct rt_i2c *i2c) | ||||||
|  | +{ | ||||||
|  | +	int ret; | ||||||
|  | + | ||||||
|  | +	ret = poll_up_timeout(i2c->base + REG_STATUS_REG, I2C_DATARDY); | ||||||
|  | +	if (ret < 0) | ||||||
|  | +		dev_dbg(i2c->dev, "rx err(%d)\n", ret); | ||||||
|  | + | ||||||
|  | +	return ret; | ||||||
|  | +} | ||||||
|  | + | ||||||
|  | +static int rt_i2c_wait_tx_done(struct rt_i2c *i2c) | ||||||
|  | +{ | ||||||
|  | +	int ret; | ||||||
|  | + | ||||||
|  | +	ret = poll_up_timeout(i2c->base + REG_STATUS_REG, I2C_SDOEMPTY); | ||||||
|  | +	if (ret < 0) | ||||||
|  | +		dev_dbg(i2c->dev, "tx err(%d)\n", ret); | ||||||
|  | + | ||||||
|  | +	return ret; | ||||||
|  | +} | ||||||
|  | + | ||||||
|  | +static void rt_i2c_reset(struct rt_i2c *i2c) | ||||||
|  | +{ | ||||||
|  | +	device_reset(i2c->adap.dev.parent); | ||||||
|  | +	barrier(); | ||||||
|  | +	rt_i2c_w32(i2c, i2c->clk_div, REG_CLKDIV_REG); | ||||||
|  | +} | ||||||
|  | + | ||||||
|  | +static void rt_i2c_dump_reg(struct rt_i2c *i2c) | ||||||
|  | +{ | ||||||
|  | +	dev_dbg(i2c->dev, "conf %08x, clkdiv %08x, devaddr %08x, " \ | ||||||
|  | +			"addr %08x, dataout %08x, datain %08x, " \ | ||||||
|  | +			"status %08x, startxfr %08x, bytecnt %08x\n", | ||||||
|  | +			rt_i2c_r32(i2c, REG_CONFIG_REG), | ||||||
|  | +			rt_i2c_r32(i2c, REG_CLKDIV_REG), | ||||||
|  | +			rt_i2c_r32(i2c, REG_DEVADDR_REG), | ||||||
|  | +			rt_i2c_r32(i2c, REG_ADDR_REG), | ||||||
|  | +			rt_i2c_r32(i2c, REG_DATAOUT_REG), | ||||||
|  | +			rt_i2c_r32(i2c, REG_DATAIN_REG), | ||||||
|  | +			rt_i2c_r32(i2c, REG_STATUS_REG), | ||||||
|  | +			rt_i2c_r32(i2c, REG_STARTXFR_REG), | ||||||
|  | +			rt_i2c_r32(i2c, REG_BYTECNT_REG)); | ||||||
|  | +} | ||||||
|  | + | ||||||
|  | +static int rt_i2c_master_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, | ||||||
|  | +		int num) | ||||||
|  | +{ | ||||||
|  | +	struct rt_i2c *i2c; | ||||||
|  | +	struct i2c_msg *pmsg; | ||||||
|  | +	unsigned char addr; | ||||||
|  | +	int i, j, ret; | ||||||
|  | +	u32 cmd; | ||||||
|  | + | ||||||
|  | +	i2c = i2c_get_adapdata(adap); | ||||||
|  | + | ||||||
|  | +	for (i = 0; i < num; i++) { | ||||||
|  | +		pmsg = &msgs[i]; | ||||||
|  | +		if (i == (num - 1)) | ||||||
|  | +			cmd = 0; | ||||||
|  | +		else | ||||||
|  | +			cmd = NOSTOP_CMD; | ||||||
|  | + | ||||||
|  | +		dev_dbg(i2c->dev, "addr: 0x%x, len: %d, flags: 0x%x, stop: %d\n", | ||||||
|  | +				pmsg->addr, pmsg->len, pmsg->flags, | ||||||
|  | +				(cmd == 0)? 1 : 0); | ||||||
|  | + | ||||||
|  | +		/* wait hardware idle */ | ||||||
|  | +		if ((ret = rt_i2c_wait_idle(i2c))) | ||||||
|  | +			goto err_timeout; | ||||||
|  | + | ||||||
|  | +		if (pmsg->flags & I2C_M_TEN) { | ||||||
|  | +			rt_i2c_w32(i2c, I2C_CONF_DEFAULT, REG_CONFIG_REG); | ||||||
|  | +			/* 10 bits address */ | ||||||
|  | +			addr = 0x78 | ((pmsg->addr >> 8) & 0x03); | ||||||
|  | +			rt_i2c_w32(i2c, addr & I2C_DEVADDR_MASK, | ||||||
|  | +					REG_DEVADDR_REG); | ||||||
|  | +			rt_i2c_w32(i2c, pmsg->addr & I2C_ADDR_MASK, | ||||||
|  | +					REG_ADDR_REG); | ||||||
|  | +		} else { | ||||||
|  | +			rt_i2c_w32(i2c, I2C_CONF_DEFAULT | I2C_ADDR_DIS, | ||||||
|  | +					REG_CONFIG_REG); | ||||||
|  | +			/* 7 bits address */ | ||||||
|  | +			rt_i2c_w32(i2c, pmsg->addr & I2C_DEVADDR_MASK, | ||||||
|  | +					REG_DEVADDR_REG); | ||||||
|  | +		} | ||||||
|  | + | ||||||
|  | +		/* buffer length */ | ||||||
|  | +		if (pmsg->len == 0) | ||||||
|  | +			cmd |= NODATA_CMD; | ||||||
|  | +		else | ||||||
|  | +			rt_i2c_w32(i2c, SET_BYTECNT(pmsg->len), | ||||||
|  | +					REG_BYTECNT_REG); | ||||||
|  | + | ||||||
|  | +		j = 0; | ||||||
|  | +		if (pmsg->flags & I2C_M_RD) { | ||||||
|  | +			cmd |= READ_CMD; | ||||||
|  | +			/* start transfer */ | ||||||
|  | +			barrier(); | ||||||
|  | +			rt_i2c_w32(i2c, cmd, REG_STARTXFR_REG); | ||||||
|  | +			do { | ||||||
|  | +				/* wait */ | ||||||
|  | +				if ((ret = rt_i2c_wait_rx_done(i2c))) | ||||||
|  | +					goto err_timeout; | ||||||
|  | +				/* read data */ | ||||||
|  | +				if (pmsg->len) | ||||||
|  | +					pmsg->buf[j] = rt_i2c_r32(i2c, | ||||||
|  | +							REG_DATAIN_REG); | ||||||
|  | +				j++; | ||||||
|  | +			} while (j < pmsg->len); | ||||||
|  | +		} else { | ||||||
|  | +			do { | ||||||
|  | +				/* write data */ | ||||||
|  | +				if (pmsg->len) | ||||||
|  | +					rt_i2c_w32(i2c, pmsg->buf[j], | ||||||
|  | +							REG_DATAOUT_REG); | ||||||
|  | +				/* start transfer */ | ||||||
|  | +				if (j == 0) { | ||||||
|  | +					barrier(); | ||||||
|  | +					rt_i2c_w32(i2c, cmd, REG_STARTXFR_REG); | ||||||
|  | +				} | ||||||
|  | +				/* wait */ | ||||||
|  | +				if ((ret = rt_i2c_wait_tx_done(i2c))) | ||||||
|  | +					goto err_timeout; | ||||||
|  | +				j++; | ||||||
|  | +			} while (j < pmsg->len); | ||||||
|  | +		} | ||||||
|  | +	} | ||||||
|  | +	/* the return value is number of executed messages */ | ||||||
|  | +	ret = i; | ||||||
|  | + | ||||||
|  | +	return ret; | ||||||
|  | + | ||||||
|  | +err_timeout: | ||||||
|  | +	rt_i2c_dump_reg(i2c); | ||||||
|  | +	rt_i2c_reset(i2c); | ||||||
|  | +	return ret; | ||||||
|  | +} | ||||||
|  | + | ||||||
|  | +static u32 rt_i2c_func(struct i2c_adapter *a) | ||||||
|  | +{ | ||||||
|  | +	return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL; | ||||||
|  | +} | ||||||
|  | + | ||||||
|  | +static const struct i2c_algorithm rt_i2c_algo = { | ||||||
|  | +	.master_xfer	= rt_i2c_master_xfer, | ||||||
|  | +	.functionality	= rt_i2c_func, | ||||||
|  | +}; | ||||||
|  | + | ||||||
|  | +static const struct of_device_id i2c_rt_dt_ids[] = { | ||||||
|  | +	{ .compatible = "ralink,rt2880-i2c" }, | ||||||
|  | +	{ /* sentinel */ } | ||||||
|  | +}; | ||||||
|  | + | ||||||
|  | +MODULE_DEVICE_TABLE(of, i2c_rt_dt_ids); | ||||||
|  | + | ||||||
|  | +static struct i2c_adapter_quirks rt_i2c_quirks = { | ||||||
|  | +        .max_write_len = BYTECNT_MAX, | ||||||
|  | +        .max_read_len = BYTECNT_MAX, | ||||||
|  | +}; | ||||||
|  | + | ||||||
|  | +static int rt_i2c_init(struct rt_i2c *i2c) | ||||||
|  | +{ | ||||||
|  | +	u32 reg; | ||||||
|  | + | ||||||
|  | +	/* i2c_sclk = periph_clk / ((2 * clk_div) + 5) */ | ||||||
|  | +	i2c->clk_div = (clk_get_rate(i2c->clk) - (5 * i2c->cur_clk)) / | ||||||
|  | +		(2 * i2c->cur_clk); | ||||||
|  | +	if (i2c->clk_div < 8) | ||||||
|  | +		i2c->clk_div = 8; | ||||||
|  | +	if (i2c->clk_div > I2C_CLKDIV_MASK) | ||||||
|  | +		i2c->clk_div = I2C_CLKDIV_MASK; | ||||||
|  | + | ||||||
|  | +	/* check support combinde/repeated start message */ | ||||||
|  | +	rt_i2c_w32(i2c, NOSTOP_CMD, REG_STARTXFR_REG); | ||||||
|  | +	reg = rt_i2c_r32(i2c, REG_STARTXFR_REG) & NOSTOP_CMD; | ||||||
|  | + | ||||||
|  | +	rt_i2c_reset(i2c); | ||||||
|  | + | ||||||
|  | +	return reg; | ||||||
|  | +} | ||||||
|  | + | ||||||
|  | +static int rt_i2c_probe(struct platform_device *pdev) | ||||||
|  | +{ | ||||||
|  | +	struct resource *res; | ||||||
|  | +	struct rt_i2c *i2c; | ||||||
|  | +	struct i2c_adapter *adap; | ||||||
|  | +	const struct of_device_id *match; | ||||||
|  | +	int ret, restart; | ||||||
|  | + | ||||||
|  | +	match = of_match_device(i2c_rt_dt_ids, &pdev->dev); | ||||||
|  | + | ||||||
|  | +	res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||||||
|  | +	if (!res) { | ||||||
|  | +		dev_err(&pdev->dev, "no memory resource found\n"); | ||||||
|  | +		return -ENODEV; | ||||||
|  | +	} | ||||||
|  | + | ||||||
|  | +	i2c = devm_kzalloc(&pdev->dev, sizeof(struct rt_i2c), GFP_KERNEL); | ||||||
|  | +	if (!i2c) { | ||||||
|  | +		dev_err(&pdev->dev, "failed to allocate i2c_adapter\n"); | ||||||
|  | +		return -ENOMEM; | ||||||
|  | +	} | ||||||
|  | + | ||||||
|  | +	i2c->base = devm_ioremap_resource(&pdev->dev, res); | ||||||
|  | +	if (IS_ERR(i2c->base)) | ||||||
|  | +		return PTR_ERR(i2c->base); | ||||||
|  | + | ||||||
|  | +	i2c->clk = devm_clk_get(&pdev->dev, NULL); | ||||||
|  | +	if (IS_ERR(i2c->clk)) { | ||||||
|  | +		dev_err(&pdev->dev, "no clock defined\n"); | ||||||
|  | +		return -ENODEV; | ||||||
|  | +	} | ||||||
|  | +	clk_prepare_enable(i2c->clk); | ||||||
|  | +	i2c->dev = &pdev->dev; | ||||||
|  | + | ||||||
|  | +	if (of_property_read_u32(pdev->dev.of_node, | ||||||
|  | +				"clock-frequency", &i2c->cur_clk)) | ||||||
|  | +		i2c->cur_clk = 100000; | ||||||
|  | + | ||||||
|  | +	adap = &i2c->adap; | ||||||
|  | +	adap->owner = THIS_MODULE; | ||||||
|  | +	adap->class = I2C_CLASS_HWMON | I2C_CLASS_SPD; | ||||||
|  | +	adap->algo = &rt_i2c_algo; | ||||||
|  | +	adap->retries = 3; | ||||||
|  | +	adap->dev.parent = &pdev->dev; | ||||||
|  | +	i2c_set_adapdata(adap, i2c); | ||||||
|  | +	adap->dev.of_node = pdev->dev.of_node; | ||||||
|  | +	strlcpy(adap->name, dev_name(&pdev->dev), sizeof(adap->name)); | ||||||
|  | +	adap->quirks = &rt_i2c_quirks; | ||||||
|  | + | ||||||
|  | +	platform_set_drvdata(pdev, i2c); | ||||||
|  | + | ||||||
|  | +	restart = rt_i2c_init(i2c); | ||||||
|  | + | ||||||
|  | +	ret = i2c_add_adapter(adap); | ||||||
|  | +	if (ret < 0) { | ||||||
|  | +		dev_err(&pdev->dev, "failed to add adapter\n"); | ||||||
|  | +		clk_disable_unprepare(i2c->clk); | ||||||
|  | +		return ret; | ||||||
|  | +	} | ||||||
|  | + | ||||||
|  | +	dev_info(&pdev->dev, "clock %uKHz, re-start %ssupport\n", | ||||||
|  | +			i2c->cur_clk/1000, restart ? "" : "not "); | ||||||
|  | + | ||||||
|  | +	return ret; | ||||||
|  | +} | ||||||
|  | + | ||||||
|  | +static int rt_i2c_remove(struct platform_device *pdev) | ||||||
|  | +{ | ||||||
|  | +	struct rt_i2c *i2c = platform_get_drvdata(pdev); | ||||||
|  | + | ||||||
|  | +	i2c_del_adapter(&i2c->adap); | ||||||
|  | +	clk_disable_unprepare(i2c->clk); | ||||||
|  | + | ||||||
|  | +	return 0; | ||||||
|  | +} | ||||||
|  | + | ||||||
|  | +static struct platform_driver rt_i2c_driver = { | ||||||
|  | +	.probe		= rt_i2c_probe, | ||||||
|  | +	.remove		= rt_i2c_remove, | ||||||
|  | +	.driver		= { | ||||||
|  | +		.owner	= THIS_MODULE, | ||||||
|  | +		.name	= "i2c-ralink", | ||||||
|  | +		.of_match_table = i2c_rt_dt_ids, | ||||||
|  | +	}, | ||||||
|  | +}; | ||||||
|  | + | ||||||
|  | +static int __init i2c_rt_init (void) | ||||||
|  | +{ | ||||||
|  | +	return platform_driver_register(&rt_i2c_driver); | ||||||
|  | +} | ||||||
|  | +subsys_initcall(i2c_rt_init); | ||||||
|  | + | ||||||
|  | +static void __exit i2c_rt_exit (void) | ||||||
|  | +{ | ||||||
|  | +	platform_driver_unregister(&rt_i2c_driver); | ||||||
|  | +} | ||||||
|  | +module_exit(i2c_rt_exit); | ||||||
|  | + | ||||||
|  | +MODULE_AUTHOR("Steven Liu <steven_liu@mediatek.com>"); | ||||||
|  | +MODULE_DESCRIPTION("Ralink I2c host driver"); | ||||||
|  | +MODULE_LICENSE("GPL"); | ||||||
|  | +MODULE_ALIAS("platform:Ralink-I2C"); | ||||||
							
								
								
									
										473
									
								
								target/linux/ramips/patches-5.4/0045-i2c-add-mt7621-driver.patch
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										473
									
								
								target/linux/ramips/patches-5.4/0045-i2c-add-mt7621-driver.patch
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,473 @@ | |||||||
|  | From d5c54ff3d1db0a4348fa04d8e78f3bf6063e3afc Mon Sep 17 00:00:00 2001 | ||||||
|  | From: John Crispin <blogic@openwrt.org> | ||||||
|  | Date: Mon, 7 Dec 2015 17:21:27 +0100 | ||||||
|  | Subject: [PATCH 45/53] i2c: add mt7621 driver | ||||||
|  |  | ||||||
|  | Signed-off-by: John Crispin <blogic@openwrt.org> | ||||||
|  | --- | ||||||
|  |  drivers/i2c/busses/Kconfig      |    4 + | ||||||
|  |  drivers/i2c/busses/Makefile     |    1 + | ||||||
|  |  drivers/i2c/busses/i2c-mt7621.c |  303 +++++++++++++++++++++++++++++++++++++++ | ||||||
|  |  3 files changed, 308 insertions(+) | ||||||
|  |  create mode 100644 drivers/i2c/busses/i2c-mt7621.c | ||||||
|  |  | ||||||
|  | --- a/drivers/i2c/busses/Kconfig | ||||||
|  | +++ b/drivers/i2c/busses/Kconfig | ||||||
|  | @@ -869,6 +869,11 @@ config I2C_RALINK | ||||||
|  |  	depends on RALINK && !SOC_MT7621 | ||||||
|  |  	select OF_I2C | ||||||
|  |   | ||||||
|  | +config I2C_MT7621 | ||||||
|  | +	tristate "MT7621/MT7628 I2C Controller" | ||||||
|  | +	depends on RALINK && (SOC_MT7620 || SOC_MT7621) | ||||||
|  | +	select OF_I2C | ||||||
|  | + | ||||||
|  |  config HAVE_S3C2410_I2C | ||||||
|  |  	bool | ||||||
|  |  	help | ||||||
|  | --- a/drivers/i2c/busses/Makefile | ||||||
|  | +++ b/drivers/i2c/busses/Makefile | ||||||
|  | @@ -85,6 +85,7 @@ obj-$(CONFIG_I2C_PUV3)		+= i2c-puv3.o | ||||||
|  |  obj-$(CONFIG_I2C_PXA)		+= i2c-pxa.o | ||||||
|  |  obj-$(CONFIG_I2C_PXA_PCI)	+= i2c-pxa-pci.o | ||||||
|  |  obj-$(CONFIG_I2C_RALINK)	+= i2c-ralink.o | ||||||
|  | +obj-$(CONFIG_I2C_MT7621)	+= i2c-mt7621.o | ||||||
|  |  obj-$(CONFIG_I2C_QUP)		+= i2c-qup.o | ||||||
|  |  obj-$(CONFIG_I2C_RIIC)		+= i2c-riic.o | ||||||
|  |  obj-$(CONFIG_I2C_RK3X)		+= i2c-rk3x.o | ||||||
|  | --- /dev/null | ||||||
|  | +++ b/drivers/i2c/busses/i2c-mt7621.c | ||||||
|  | @@ -0,0 +1,433 @@ | ||||||
|  | +/* | ||||||
|  | + * drivers/i2c/busses/i2c-mt7621.c | ||||||
|  | + * | ||||||
|  | + * Copyright (C) 2013 Steven Liu <steven_liu@mediatek.com> | ||||||
|  | + * Copyright (C) 2016 Michael Lee <igvtee@gmail.com> | ||||||
|  | + * | ||||||
|  | + * Improve driver for i2cdetect from i2c-tools to detect i2c devices on the bus. | ||||||
|  | + * (C) 2014 Sittisak <sittisaks@hotmail.com> | ||||||
|  | + * | ||||||
|  | + * This software is licensed under the terms of the GNU General Public | ||||||
|  | + * License version 2, as published by the Free Software Foundation, and | ||||||
|  | + * may be copied, distributed, and modified under those terms. | ||||||
|  | + * | ||||||
|  | + * 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. | ||||||
|  | + * | ||||||
|  | + */ | ||||||
|  | + | ||||||
|  | +#include <linux/interrupt.h> | ||||||
|  | +#include <linux/kernel.h> | ||||||
|  | +#include <linux/module.h> | ||||||
|  | +#include <linux/reset.h> | ||||||
|  | +#include <linux/delay.h> | ||||||
|  | +#include <linux/slab.h> | ||||||
|  | +#include <linux/init.h> | ||||||
|  | +#include <linux/errno.h> | ||||||
|  | +#include <linux/platform_device.h> | ||||||
|  | +#include <linux/of_platform.h> | ||||||
|  | +#include <linux/i2c.h> | ||||||
|  | +#include <linux/io.h> | ||||||
|  | +#include <linux/err.h> | ||||||
|  | +#include <linux/clk.h> | ||||||
|  | + | ||||||
|  | +#define REG_SM0CFG0		0x08 | ||||||
|  | +#define REG_SM0DOUT		0x10 | ||||||
|  | +#define REG_SM0DIN		0x14 | ||||||
|  | +#define REG_SM0ST		0x18 | ||||||
|  | +#define REG_SM0AUTO		0x1C | ||||||
|  | +#define REG_SM0CFG1		0x20 | ||||||
|  | +#define REG_SM0CFG2		0x28 | ||||||
|  | +#define REG_SM0CTL0		0x40 | ||||||
|  | +#define REG_SM0CTL1		0x44 | ||||||
|  | +#define REG_SM0D0		0x50 | ||||||
|  | +#define REG_SM0D1		0x54 | ||||||
|  | +#define REG_PINTEN		0x5C | ||||||
|  | +#define REG_PINTST		0x60 | ||||||
|  | +#define REG_PINTCL		0x64 | ||||||
|  | + | ||||||
|  | +/* REG_SM0CFG0 */ | ||||||
|  | +#define I2C_DEVADDR_MASK	0x7f | ||||||
|  | + | ||||||
|  | +/* REG_SM0ST */ | ||||||
|  | +#define I2C_DATARDY		BIT(2) | ||||||
|  | +#define I2C_SDOEMPTY		BIT(1) | ||||||
|  | +#define I2C_BUSY		BIT(0) | ||||||
|  | + | ||||||
|  | +/* REG_SM0AUTO */ | ||||||
|  | +#define READ_CMD		BIT(0) | ||||||
|  | + | ||||||
|  | +/* REG_SM0CFG1 */ | ||||||
|  | +#define BYTECNT_MAX		64 | ||||||
|  | +#define SET_BYTECNT(x)		(x - 1) | ||||||
|  | + | ||||||
|  | +/* REG_SM0CFG2 */ | ||||||
|  | +#define AUTOMODE_EN		BIT(0) | ||||||
|  | + | ||||||
|  | +/* REG_SM0CTL0 */ | ||||||
|  | +#define ODRAIN_HIGH_SM0		BIT(31) | ||||||
|  | +#define VSYNC_SHIFT		28 | ||||||
|  | +#define VSYNC_MASK		0x3 | ||||||
|  | +#define VSYNC_PULSE		(0x1 << VSYNC_SHIFT) | ||||||
|  | +#define VSYNC_RISING		(0x2 << VSYNC_SHIFT) | ||||||
|  | +#define CLK_DIV_SHIFT		16 | ||||||
|  | +#define CLK_DIV_MASK		0xfff | ||||||
|  | +#define DEG_CNT_SHIFT		8 | ||||||
|  | +#define DEG_CNT_MASK		0xff | ||||||
|  | +#define WAIT_HIGH		BIT(6) | ||||||
|  | +#define DEG_EN			BIT(5) | ||||||
|  | +#define CS_STATUA		BIT(4) | ||||||
|  | +#define SCL_STATUS		BIT(3) | ||||||
|  | +#define SDA_STATUS		BIT(2) | ||||||
|  | +#define SM0_EN			BIT(1) | ||||||
|  | +#define SCL_STRECH		BIT(0) | ||||||
|  | + | ||||||
|  | +/* REG_SM0CTL1 */ | ||||||
|  | +#define ACK_SHIFT		16 | ||||||
|  | +#define ACK_MASK		0xff | ||||||
|  | +#define PGLEN_SHIFT		8 | ||||||
|  | +#define PGLEN_MASK		0x7 | ||||||
|  | +#define SM0_MODE_SHIFT		4 | ||||||
|  | +#define SM0_MODE_MASK		0x7 | ||||||
|  | +#define SM0_MODE_START		0x1 | ||||||
|  | +#define SM0_MODE_WRITE		0x2 | ||||||
|  | +#define SM0_MODE_STOP		0x3 | ||||||
|  | +#define SM0_MODE_READ_NACK	0x4 | ||||||
|  | +#define SM0_MODE_READ_ACK	0x5 | ||||||
|  | +#define SM0_TRI_BUSY		BIT(0) | ||||||
|  | + | ||||||
|  | +/* timeout waiting for I2C devices to respond (clock streching) */ | ||||||
|  | +#define TIMEOUT_MS              1000 | ||||||
|  | +#define DELAY_INTERVAL_US       100 | ||||||
|  | + | ||||||
|  | +struct mtk_i2c { | ||||||
|  | +	void __iomem *base; | ||||||
|  | +	struct clk *clk; | ||||||
|  | +	struct device *dev; | ||||||
|  | +	struct i2c_adapter adap; | ||||||
|  | +	u32 cur_clk; | ||||||
|  | +	u32 clk_div; | ||||||
|  | +	u32 flags; | ||||||
|  | +}; | ||||||
|  | + | ||||||
|  | +static void mtk_i2c_w32(struct mtk_i2c *i2c, u32 val, unsigned reg) | ||||||
|  | +{ | ||||||
|  | +	iowrite32(val, i2c->base + reg); | ||||||
|  | +} | ||||||
|  | + | ||||||
|  | +static u32 mtk_i2c_r32(struct mtk_i2c *i2c, unsigned reg) | ||||||
|  | +{ | ||||||
|  | +	return ioread32(i2c->base + reg); | ||||||
|  | +} | ||||||
|  | + | ||||||
|  | +static int poll_down_timeout(void __iomem *addr, u32 mask) | ||||||
|  | +{ | ||||||
|  | +	unsigned long timeout = jiffies + msecs_to_jiffies(TIMEOUT_MS); | ||||||
|  | + | ||||||
|  | +	do { | ||||||
|  | +		if (!(readl_relaxed(addr) & mask)) | ||||||
|  | +			return 0; | ||||||
|  | + | ||||||
|  | +		usleep_range(DELAY_INTERVAL_US, DELAY_INTERVAL_US + 50); | ||||||
|  | +	} while (time_before(jiffies, timeout)); | ||||||
|  | + | ||||||
|  | +	return (readl_relaxed(addr) & mask) ? -EAGAIN : 0; | ||||||
|  | +} | ||||||
|  | + | ||||||
|  | +static int mtk_i2c_wait_idle(struct mtk_i2c *i2c) | ||||||
|  | +{ | ||||||
|  | +	int ret; | ||||||
|  | + | ||||||
|  | +	ret = poll_down_timeout(i2c->base + REG_SM0ST, I2C_BUSY); | ||||||
|  | +	if (ret < 0) | ||||||
|  | +		dev_dbg(i2c->dev, "idle err(%d)\n", ret); | ||||||
|  | + | ||||||
|  | +	return ret; | ||||||
|  | +} | ||||||
|  | + | ||||||
|  | +static int poll_up_timeout(void __iomem *addr, u32 mask) | ||||||
|  | +{ | ||||||
|  | +	unsigned long timeout = jiffies + msecs_to_jiffies(TIMEOUT_MS); | ||||||
|  | +	u32 status; | ||||||
|  | + | ||||||
|  | +	do { | ||||||
|  | +		status = readl_relaxed(addr); | ||||||
|  | +		if (status & mask) | ||||||
|  | +			return 0; | ||||||
|  | +		usleep_range(DELAY_INTERVAL_US, DELAY_INTERVAL_US + 50); | ||||||
|  | +	} while (time_before(jiffies, timeout)); | ||||||
|  | + | ||||||
|  | +	return -ETIMEDOUT; | ||||||
|  | +} | ||||||
|  | + | ||||||
|  | +static int mtk_i2c_wait_rx_done(struct mtk_i2c *i2c) | ||||||
|  | +{ | ||||||
|  | +	int ret; | ||||||
|  | + | ||||||
|  | +	ret = poll_up_timeout(i2c->base + REG_SM0ST, I2C_DATARDY); | ||||||
|  | +	if (ret < 0) | ||||||
|  | +		dev_dbg(i2c->dev, "rx err(%d)\n", ret); | ||||||
|  | + | ||||||
|  | +	return ret; | ||||||
|  | +} | ||||||
|  | + | ||||||
|  | +static int mtk_i2c_wait_tx_done(struct mtk_i2c *i2c) | ||||||
|  | +{ | ||||||
|  | +	int ret; | ||||||
|  | + | ||||||
|  | +	ret = poll_up_timeout(i2c->base + REG_SM0ST, I2C_SDOEMPTY); | ||||||
|  | +	if (ret < 0) | ||||||
|  | +		dev_dbg(i2c->dev, "tx err(%d)\n", ret); | ||||||
|  | + | ||||||
|  | +	return ret; | ||||||
|  | +} | ||||||
|  | + | ||||||
|  | +static void mtk_i2c_reset(struct mtk_i2c *i2c) | ||||||
|  | +{ | ||||||
|  | +	u32 reg; | ||||||
|  | +	device_reset(i2c->adap.dev.parent); | ||||||
|  | +	barrier(); | ||||||
|  | + | ||||||
|  | +	/* ctrl0 */ | ||||||
|  | +	reg = ODRAIN_HIGH_SM0 | VSYNC_PULSE | (i2c->clk_div << CLK_DIV_SHIFT) | | ||||||
|  | +		WAIT_HIGH | SM0_EN; | ||||||
|  | +	mtk_i2c_w32(i2c, reg, REG_SM0CTL0); | ||||||
|  | + | ||||||
|  | +	/* auto mode */ | ||||||
|  | +	mtk_i2c_w32(i2c, AUTOMODE_EN, REG_SM0CFG2); | ||||||
|  | +} | ||||||
|  | + | ||||||
|  | +static void mtk_i2c_dump_reg(struct mtk_i2c *i2c) | ||||||
|  | +{ | ||||||
|  | +	dev_dbg(i2c->dev, "cfg0 %08x, dout %08x, din %08x, " \ | ||||||
|  | +			"status %08x, auto %08x, cfg1 %08x, " \ | ||||||
|  | +			"cfg2 %08x, ctl0 %08x, ctl1 %08x\n", | ||||||
|  | +			mtk_i2c_r32(i2c, REG_SM0CFG0), | ||||||
|  | +			mtk_i2c_r32(i2c, REG_SM0DOUT), | ||||||
|  | +			mtk_i2c_r32(i2c, REG_SM0DIN), | ||||||
|  | +			mtk_i2c_r32(i2c, REG_SM0ST), | ||||||
|  | +			mtk_i2c_r32(i2c, REG_SM0AUTO), | ||||||
|  | +			mtk_i2c_r32(i2c, REG_SM0CFG1), | ||||||
|  | +			mtk_i2c_r32(i2c, REG_SM0CFG2), | ||||||
|  | +			mtk_i2c_r32(i2c, REG_SM0CTL0), | ||||||
|  | +			mtk_i2c_r32(i2c, REG_SM0CTL1)); | ||||||
|  | +} | ||||||
|  | + | ||||||
|  | +static int mtk_i2c_master_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, | ||||||
|  | +		int num) | ||||||
|  | +{ | ||||||
|  | +	struct mtk_i2c *i2c; | ||||||
|  | +	struct i2c_msg *pmsg; | ||||||
|  | +	int i, j, ret; | ||||||
|  | +	u32 cmd; | ||||||
|  | + | ||||||
|  | +	i2c = i2c_get_adapdata(adap); | ||||||
|  | + | ||||||
|  | +	for (i = 0; i < num; i++) { | ||||||
|  | +		pmsg = &msgs[i]; | ||||||
|  | +		cmd = 0; | ||||||
|  | + | ||||||
|  | +		dev_dbg(i2c->dev, "addr: 0x%x, len: %d, flags: 0x%x\n", | ||||||
|  | +				pmsg->addr, pmsg->len, pmsg->flags); | ||||||
|  | + | ||||||
|  | +		/* wait hardware idle */ | ||||||
|  | +		if ((ret = mtk_i2c_wait_idle(i2c))) | ||||||
|  | +			goto err_timeout; | ||||||
|  | + | ||||||
|  | +		if (pmsg->flags & I2C_M_TEN) { | ||||||
|  | +			dev_dbg(i2c->dev, "10 bits addr not supported\n"); | ||||||
|  | +			return -EINVAL; | ||||||
|  | +		} else { | ||||||
|  | +			/* 7 bits address */ | ||||||
|  | +			mtk_i2c_w32(i2c, pmsg->addr & I2C_DEVADDR_MASK, | ||||||
|  | +					REG_SM0CFG0); | ||||||
|  | +		} | ||||||
|  | + | ||||||
|  | +		/* buffer length */ | ||||||
|  | +		if (pmsg->len == 0) { | ||||||
|  | +			dev_dbg(i2c->dev, "length is 0\n"); | ||||||
|  | +			return -EINVAL; | ||||||
|  | +		} else | ||||||
|  | +			mtk_i2c_w32(i2c, SET_BYTECNT(pmsg->len), | ||||||
|  | +					REG_SM0CFG1); | ||||||
|  | + | ||||||
|  | +		j = 0; | ||||||
|  | +		if (pmsg->flags & I2C_M_RD) { | ||||||
|  | +			cmd |= READ_CMD; | ||||||
|  | +			/* start transfer */ | ||||||
|  | +			barrier(); | ||||||
|  | +			mtk_i2c_w32(i2c, cmd, REG_SM0AUTO); | ||||||
|  | +			do { | ||||||
|  | +				/* wait */ | ||||||
|  | +				if ((ret = mtk_i2c_wait_rx_done(i2c))) | ||||||
|  | +					goto err_timeout; | ||||||
|  | +				/* read data */ | ||||||
|  | +				if (pmsg->len) | ||||||
|  | +					pmsg->buf[j] = mtk_i2c_r32(i2c, | ||||||
|  | +							REG_SM0DIN); | ||||||
|  | +				j++; | ||||||
|  | +			} while (j < pmsg->len); | ||||||
|  | +		} else { | ||||||
|  | +			do { | ||||||
|  | +				/* write data */ | ||||||
|  | +				if (pmsg->len) | ||||||
|  | +					mtk_i2c_w32(i2c, pmsg->buf[j], | ||||||
|  | +							REG_SM0DOUT); | ||||||
|  | +				/* start transfer */ | ||||||
|  | +				if (j == 0) { | ||||||
|  | +					barrier(); | ||||||
|  | +					mtk_i2c_w32(i2c, cmd, REG_SM0AUTO); | ||||||
|  | +				} | ||||||
|  | +				/* wait */ | ||||||
|  | +				if ((ret = mtk_i2c_wait_tx_done(i2c))) | ||||||
|  | +					goto err_timeout; | ||||||
|  | +				j++; | ||||||
|  | +			} while (j < pmsg->len); | ||||||
|  | +		} | ||||||
|  | +	} | ||||||
|  | +	/* the return value is number of executed messages */ | ||||||
|  | +	ret = i; | ||||||
|  | + | ||||||
|  | +	return ret; | ||||||
|  | + | ||||||
|  | +err_timeout: | ||||||
|  | +	mtk_i2c_dump_reg(i2c); | ||||||
|  | +	mtk_i2c_reset(i2c); | ||||||
|  | +	return ret; | ||||||
|  | +} | ||||||
|  | + | ||||||
|  | +static u32 mtk_i2c_func(struct i2c_adapter *a) | ||||||
|  | +{ | ||||||
|  | +	return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL; | ||||||
|  | +} | ||||||
|  | + | ||||||
|  | +static const struct i2c_algorithm mtk_i2c_algo = { | ||||||
|  | +	.master_xfer	= mtk_i2c_master_xfer, | ||||||
|  | +	.functionality	= mtk_i2c_func, | ||||||
|  | +}; | ||||||
|  | + | ||||||
|  | +static const struct of_device_id i2c_mtk_dt_ids[] = { | ||||||
|  | +	{ .compatible = "mediatek,mt7621-i2c" }, | ||||||
|  | +	{ /* sentinel */ } | ||||||
|  | +}; | ||||||
|  | + | ||||||
|  | +MODULE_DEVICE_TABLE(of, i2c_mtk_dt_ids); | ||||||
|  | + | ||||||
|  | +static struct i2c_adapter_quirks mtk_i2c_quirks = { | ||||||
|  | +        .max_write_len = BYTECNT_MAX, | ||||||
|  | +        .max_read_len = BYTECNT_MAX, | ||||||
|  | +}; | ||||||
|  | + | ||||||
|  | +static void mtk_i2c_init(struct mtk_i2c *i2c) | ||||||
|  | +{ | ||||||
|  | +	i2c->clk_div = clk_get_rate(i2c->clk) / i2c->cur_clk; | ||||||
|  | +	if (i2c->clk_div > CLK_DIV_MASK) | ||||||
|  | +		i2c->clk_div = CLK_DIV_MASK; | ||||||
|  | + | ||||||
|  | +	mtk_i2c_reset(i2c); | ||||||
|  | +} | ||||||
|  | + | ||||||
|  | +static int mtk_i2c_probe(struct platform_device *pdev) | ||||||
|  | +{ | ||||||
|  | +	struct resource *res; | ||||||
|  | +	struct mtk_i2c *i2c; | ||||||
|  | +	struct i2c_adapter *adap; | ||||||
|  | +	const struct of_device_id *match; | ||||||
|  | +	int ret; | ||||||
|  | + | ||||||
|  | +	match = of_match_device(i2c_mtk_dt_ids, &pdev->dev); | ||||||
|  | + | ||||||
|  | +	res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||||||
|  | +	if (!res) { | ||||||
|  | +		dev_err(&pdev->dev, "no memory resource found\n"); | ||||||
|  | +		return -ENODEV; | ||||||
|  | +	} | ||||||
|  | + | ||||||
|  | +	i2c = devm_kzalloc(&pdev->dev, sizeof(struct mtk_i2c), GFP_KERNEL); | ||||||
|  | +	if (!i2c) { | ||||||
|  | +		dev_err(&pdev->dev, "failed to allocate i2c_adapter\n"); | ||||||
|  | +		return -ENOMEM; | ||||||
|  | +	} | ||||||
|  | + | ||||||
|  | +	i2c->base = devm_ioremap_resource(&pdev->dev, res); | ||||||
|  | +	if (IS_ERR(i2c->base)) | ||||||
|  | +		return PTR_ERR(i2c->base); | ||||||
|  | + | ||||||
|  | +	i2c->clk = devm_clk_get(&pdev->dev, NULL); | ||||||
|  | +	if (IS_ERR(i2c->clk)) { | ||||||
|  | +		dev_err(&pdev->dev, "no clock defined\n"); | ||||||
|  | +		return -ENODEV; | ||||||
|  | +	} | ||||||
|  | +	clk_prepare_enable(i2c->clk); | ||||||
|  | +	i2c->dev = &pdev->dev; | ||||||
|  | + | ||||||
|  | +	if (of_property_read_u32(pdev->dev.of_node, | ||||||
|  | +				"clock-frequency", &i2c->cur_clk)) | ||||||
|  | +		i2c->cur_clk = 100000; | ||||||
|  | + | ||||||
|  | +	adap = &i2c->adap; | ||||||
|  | +	adap->owner = THIS_MODULE; | ||||||
|  | +	adap->class = I2C_CLASS_HWMON | I2C_CLASS_SPD; | ||||||
|  | +	adap->algo = &mtk_i2c_algo; | ||||||
|  | +	adap->retries = 3; | ||||||
|  | +	adap->dev.parent = &pdev->dev; | ||||||
|  | +	i2c_set_adapdata(adap, i2c); | ||||||
|  | +	adap->dev.of_node = pdev->dev.of_node; | ||||||
|  | +	strlcpy(adap->name, dev_name(&pdev->dev), sizeof(adap->name)); | ||||||
|  | +	adap->quirks = &mtk_i2c_quirks; | ||||||
|  | + | ||||||
|  | +	platform_set_drvdata(pdev, i2c); | ||||||
|  | + | ||||||
|  | +	mtk_i2c_init(i2c); | ||||||
|  | + | ||||||
|  | +	ret = i2c_add_adapter(adap); | ||||||
|  | +	if (ret < 0) { | ||||||
|  | +		dev_err(&pdev->dev, "failed to add adapter\n"); | ||||||
|  | +		clk_disable_unprepare(i2c->clk); | ||||||
|  | +		return ret; | ||||||
|  | +	} | ||||||
|  | + | ||||||
|  | +	dev_info(&pdev->dev, "clock %uKHz, re-start not support\n", | ||||||
|  | +			i2c->cur_clk/1000); | ||||||
|  | + | ||||||
|  | +	return ret; | ||||||
|  | +} | ||||||
|  | + | ||||||
|  | +static int mtk_i2c_remove(struct platform_device *pdev) | ||||||
|  | +{ | ||||||
|  | +	struct mtk_i2c *i2c = platform_get_drvdata(pdev); | ||||||
|  | + | ||||||
|  | +	i2c_del_adapter(&i2c->adap); | ||||||
|  | +	clk_disable_unprepare(i2c->clk); | ||||||
|  | + | ||||||
|  | +	return 0; | ||||||
|  | +} | ||||||
|  | + | ||||||
|  | +static struct platform_driver mtk_i2c_driver = { | ||||||
|  | +	.probe		= mtk_i2c_probe, | ||||||
|  | +	.remove		= mtk_i2c_remove, | ||||||
|  | +	.driver		= { | ||||||
|  | +		.owner	= THIS_MODULE, | ||||||
|  | +		.name	= "i2c-mt7621", | ||||||
|  | +		.of_match_table = i2c_mtk_dt_ids, | ||||||
|  | +	}, | ||||||
|  | +}; | ||||||
|  | + | ||||||
|  | +static int __init i2c_mtk_init (void) | ||||||
|  | +{ | ||||||
|  | +	return platform_driver_register(&mtk_i2c_driver); | ||||||
|  | +} | ||||||
|  | +subsys_initcall(i2c_mtk_init); | ||||||
|  | + | ||||||
|  | +static void __exit i2c_mtk_exit (void) | ||||||
|  | +{ | ||||||
|  | +	platform_driver_unregister(&mtk_i2c_driver); | ||||||
|  | +} | ||||||
|  | +module_exit(i2c_mtk_exit); | ||||||
|  | + | ||||||
|  | +MODULE_AUTHOR("Steven Liu <steven_liu@mediatek.com>"); | ||||||
|  | +MODULE_DESCRIPTION("MT7621 I2c host driver"); | ||||||
|  | +MODULE_LICENSE("GPL"); | ||||||
|  | +MODULE_ALIAS("platform:MT7621-I2C"); | ||||||
| @@ -0,0 +1,43 @@ | |||||||
|  | From 23147af14531cbdada194b94120ef8774f46292d Mon Sep 17 00:00:00 2001 | ||||||
|  | From: John Crispin <blogic@openwrt.org> | ||||||
|  | Date: Thu, 13 Nov 2014 19:08:40 +0100 | ||||||
|  | Subject: [PATCH 46/53] mmc: MIPS: ralink: add sdhci for mt7620a SoC | ||||||
|  |  | ||||||
|  | Signed-off-by: John Crispin <blogic@openwrt.org> | ||||||
|  | --- | ||||||
|  |  drivers/mmc/host/Kconfig             |    2 + | ||||||
|  |  drivers/mmc/host/Makefile            |    1 + | ||||||
|  |  drivers/mmc/host/mtk-mmc/Kconfig     |   16 + | ||||||
|  |  drivers/mmc/host/mtk-mmc/Makefile    |   42 + | ||||||
|  |  drivers/mmc/host/mtk-mmc/board.h     |  137 ++ | ||||||
|  |  drivers/mmc/host/mtk-mmc/dbg.c       |  347 ++++ | ||||||
|  |  drivers/mmc/host/mtk-mmc/dbg.h       |  156 ++ | ||||||
|  |  drivers/mmc/host/mtk-mmc/mt6575_sd.h | 1001 +++++++++++ | ||||||
|  |  drivers/mmc/host/mtk-mmc/sd.c        | 3060 ++++++++++++++++++++++++++++++++++ | ||||||
|  |  9 files changed, 4762 insertions(+) | ||||||
|  |  create mode 100644 drivers/mmc/host/mtk-mmc/Kconfig | ||||||
|  |  create mode 100644 drivers/mmc/host/mtk-mmc/Makefile | ||||||
|  |  create mode 100644 drivers/mmc/host/mtk-mmc/board.h | ||||||
|  |  create mode 100644 drivers/mmc/host/mtk-mmc/dbg.c | ||||||
|  |  create mode 100644 drivers/mmc/host/mtk-mmc/dbg.h | ||||||
|  |  create mode 100644 drivers/mmc/host/mtk-mmc/mt6575_sd.h | ||||||
|  |  create mode 100644 drivers/mmc/host/mtk-mmc/sd.c | ||||||
|  |  | ||||||
|  | --- a/drivers/mmc/host/Kconfig | ||||||
|  | +++ b/drivers/mmc/host/Kconfig | ||||||
|  | @@ -901,3 +901,5 @@ config MMC_SDHCI_XENON | ||||||
|  |  	  This selects Marvell Xenon eMMC/SD/SDIO SDHCI. | ||||||
|  |  	  If you have a controller with this interface, say Y or M here. | ||||||
|  |  	  If unsure, say N. | ||||||
|  | + | ||||||
|  | +source "drivers/mmc/host/mtk-mmc/Kconfig" | ||||||
|  | --- a/drivers/mmc/host/Makefile | ||||||
|  | +++ b/drivers/mmc/host/Makefile | ||||||
|  | @@ -3,6 +3,7 @@ | ||||||
|  |  # Makefile for MMC/SD host controller drivers | ||||||
|  |  # | ||||||
|  |   | ||||||
|  | +obj-$(CONFIG_MTK_MMC) 		+= mtk-mmc/ | ||||||
|  |  obj-$(CONFIG_MMC_ARMMMCI) += armmmci.o | ||||||
|  |  armmmci-y := mmci.o | ||||||
|  |  armmmci-$(CONFIG_MMC_QCOM_DML) += mmci_qcom_dml.o | ||||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										1046
									
								
								target/linux/ramips/patches-5.4/0048-asoc-add-mt7620-support.patch
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1046
									
								
								target/linux/ramips/patches-5.4/0048-asoc-add-mt7620-support.patch
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @@ -0,0 +1,22 @@ | |||||||
|  | From a7eb46e0ea4a11e4dfb56ab129bf816d1059a6c5 Mon Sep 17 00:00:00 2001 | ||||||
|  | From: John Crispin <blogic@openwrt.org> | ||||||
|  | Date: Mon, 7 Dec 2015 17:31:08 +0100 | ||||||
|  | Subject: [PATCH 51/53] serial: add ugly custom baud rate hack | ||||||
|  |  | ||||||
|  | Signed-off-by: John Crispin <blogic@openwrt.org> | ||||||
|  | --- | ||||||
|  |  drivers/tty/serial/serial_core.c |    3 +++ | ||||||
|  |  1 file changed, 3 insertions(+) | ||||||
|  |  | ||||||
|  | --- a/drivers/tty/serial/serial_core.c | ||||||
|  | +++ b/drivers/tty/serial/serial_core.c | ||||||
|  | @@ -428,6 +428,9 @@ uart_get_baud_rate(struct uart_port *por | ||||||
|  |  		break; | ||||||
|  |  	} | ||||||
|  |   | ||||||
|  | +	if (tty_termios_baud_rate(termios) == 2500000) | ||||||
|  | +		return 250000; | ||||||
|  | + | ||||||
|  |  	for (try = 0; try < 2; try++) { | ||||||
|  |  		baud = tty_termios_baud_rate(termios); | ||||||
|  |   | ||||||
| @@ -0,0 +1,217 @@ | |||||||
|  | From fc8f96309c21c1bc3276427309cd7d361347d66e Mon Sep 17 00:00:00 2001 | ||||||
|  | From: John Crispin <blogic@openwrt.org> | ||||||
|  | Date: Mon, 7 Dec 2015 17:16:50 +0100 | ||||||
|  | Subject: [PATCH 52/53] pwm: add mediatek support | ||||||
|  |  | ||||||
|  | Signed-off-by: John Crispin <blogic@openwrt.org> | ||||||
|  | --- | ||||||
|  |  drivers/pwm/Kconfig        |    9 +++ | ||||||
|  |  drivers/pwm/Makefile       |    1 + | ||||||
|  |  drivers/pwm/pwm-mediatek.c |  173 ++++++++++++++++++++++++++++++++++++++++++++ | ||||||
|  |  3 files changed, 183 insertions(+) | ||||||
|  |  create mode 100644 drivers/pwm/pwm-mediatek.c | ||||||
|  |  | ||||||
|  | --- a/drivers/pwm/Kconfig | ||||||
|  | +++ b/drivers/pwm/Kconfig | ||||||
|  | @@ -302,6 +302,15 @@ config PWM_MEDIATEK | ||||||
|  |  	  To compile this driver as a module, choose M here: the module | ||||||
|  |  	  will be called pwm-mediatek. | ||||||
|  |   | ||||||
|  | +config PWM_MEDIATEK_RAMIPS | ||||||
|  | +	tristate "Mediatek PWM support" | ||||||
|  | +	depends on RALINK && OF | ||||||
|  | +	help | ||||||
|  | +	  Generic PWM framework driver for Mediatek ARM SoC. | ||||||
|  | + | ||||||
|  | +	  To compile this driver as a module, choose M here: the module | ||||||
|  | +	  will be called pwm-mxs. | ||||||
|  | + | ||||||
|  |  config PWM_MXS | ||||||
|  |  	tristate "Freescale MXS PWM support" | ||||||
|  |  	depends on ARCH_MXS && OF | ||||||
|  | --- a/drivers/pwm/Makefile | ||||||
|  | +++ b/drivers/pwm/Makefile | ||||||
|  | @@ -28,6 +28,7 @@ obj-$(CONFIG_PWM_LPSS_PCI)	+= pwm-lpss-p | ||||||
|  |  obj-$(CONFIG_PWM_LPSS_PLATFORM)	+= pwm-lpss-platform.o | ||||||
|  |  obj-$(CONFIG_PWM_MESON)		+= pwm-meson.o | ||||||
|  |  obj-$(CONFIG_PWM_MEDIATEK)	+= pwm-mediatek.o | ||||||
|  | +obj-$(CONFIG_PWM_MEDIATEK_RAMIPS)	+= pwm-mediatek-ramips.o | ||||||
|  |  obj-$(CONFIG_PWM_MTK_DISP)	+= pwm-mtk-disp.o | ||||||
|  |  obj-$(CONFIG_PWM_MXS)		+= pwm-mxs.o | ||||||
|  |  obj-$(CONFIG_PWM_OMAP_DMTIMER)	+= pwm-omap-dmtimer.o | ||||||
|  | --- /dev/null | ||||||
|  | +++ b/drivers/pwm/pwm-mediatek-ramips.c | ||||||
|  | @@ -0,0 +1,173 @@ | ||||||
|  | +/* | ||||||
|  | + * Mediatek Pulse Width Modulator driver | ||||||
|  | + * | ||||||
|  | + * Copyright (C) 2015 John Crispin <blogic@openwrt.org> | ||||||
|  | + * | ||||||
|  | + * This file is licensed under the terms of the GNU General Public | ||||||
|  | + * License version 2. This program is licensed "as is" without any | ||||||
|  | + * warranty of any kind, whether express or implied. | ||||||
|  | + */ | ||||||
|  | + | ||||||
|  | +#include <linux/err.h> | ||||||
|  | +#include <linux/io.h> | ||||||
|  | +#include <linux/ioport.h> | ||||||
|  | +#include <linux/kernel.h> | ||||||
|  | +#include <linux/module.h> | ||||||
|  | +#include <linux/of.h> | ||||||
|  | +#include <linux/platform_device.h> | ||||||
|  | +#include <linux/pwm.h> | ||||||
|  | +#include <linux/slab.h> | ||||||
|  | +#include <linux/types.h> | ||||||
|  | + | ||||||
|  | +#define NUM_PWM		4 | ||||||
|  | + | ||||||
|  | +/* PWM registers and bits definitions */ | ||||||
|  | +#define PWMCON			0x00 | ||||||
|  | +#define PWMHDUR			0x04 | ||||||
|  | +#define PWMLDUR			0x08 | ||||||
|  | +#define PWMGDUR			0x0c | ||||||
|  | +#define PWMWAVENUM		0x28 | ||||||
|  | +#define PWMDWIDTH		0x2c | ||||||
|  | +#define PWMTHRES		0x30 | ||||||
|  | + | ||||||
|  | +/** | ||||||
|  | + * struct mtk_pwm_chip - struct representing pwm chip | ||||||
|  | + * | ||||||
|  | + * @mmio_base: base address of pwm chip | ||||||
|  | + * @chip: linux pwm chip representation | ||||||
|  | + */ | ||||||
|  | +struct mtk_pwm_chip { | ||||||
|  | +	void __iomem *mmio_base; | ||||||
|  | +	struct pwm_chip chip; | ||||||
|  | +}; | ||||||
|  | + | ||||||
|  | +static inline struct mtk_pwm_chip *to_mtk_pwm_chip(struct pwm_chip *chip) | ||||||
|  | +{ | ||||||
|  | +	return container_of(chip, struct mtk_pwm_chip, chip); | ||||||
|  | +} | ||||||
|  | + | ||||||
|  | +static inline u32 mtk_pwm_readl(struct mtk_pwm_chip *chip, unsigned int num, | ||||||
|  | +				  unsigned long offset) | ||||||
|  | +{ | ||||||
|  | +	return ioread32(chip->mmio_base + 0x10 + (num * 0x40) + offset); | ||||||
|  | +} | ||||||
|  | + | ||||||
|  | +static inline void mtk_pwm_writel(struct mtk_pwm_chip *chip, | ||||||
|  | +				    unsigned int num, unsigned long offset, | ||||||
|  | +				    unsigned long val) | ||||||
|  | +{ | ||||||
|  | +	iowrite32(val, chip->mmio_base + 0x10 + (num * 0x40) + offset); | ||||||
|  | +} | ||||||
|  | + | ||||||
|  | +static int mtk_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm, | ||||||
|  | +			    int duty_ns, int period_ns) | ||||||
|  | +{ | ||||||
|  | +	struct mtk_pwm_chip *pc = to_mtk_pwm_chip(chip); | ||||||
|  | +	u32 resolution = 100 / 4; | ||||||
|  | +	u32 clkdiv = 0; | ||||||
|  | + | ||||||
|  | +	while (period_ns / resolution  > 8191) { | ||||||
|  | +		clkdiv++; | ||||||
|  | +		resolution *= 2; | ||||||
|  | +	} | ||||||
|  | + | ||||||
|  | +	if (clkdiv > 7) | ||||||
|  | +		return -1; | ||||||
|  | + | ||||||
|  | +	mtk_pwm_writel(pc, pwm->hwpwm, PWMCON, BIT(15) | BIT(3) | clkdiv); | ||||||
|  | +	mtk_pwm_writel(pc, pwm->hwpwm, PWMDWIDTH, period_ns / resolution); | ||||||
|  | +	mtk_pwm_writel(pc, pwm->hwpwm, PWMTHRES, duty_ns / resolution); | ||||||
|  | +	return 0; | ||||||
|  | +} | ||||||
|  | + | ||||||
|  | +static int mtk_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm) | ||||||
|  | +{ | ||||||
|  | +	struct mtk_pwm_chip *pc = to_mtk_pwm_chip(chip); | ||||||
|  | +	u32 val; | ||||||
|  | + | ||||||
|  | +	val = ioread32(pc->mmio_base); | ||||||
|  | +	val |= BIT(pwm->hwpwm); | ||||||
|  | +	iowrite32(val, pc->mmio_base); | ||||||
|  | + | ||||||
|  | +	return 0; | ||||||
|  | +} | ||||||
|  | + | ||||||
|  | +static void mtk_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm) | ||||||
|  | +{ | ||||||
|  | +	struct mtk_pwm_chip *pc = to_mtk_pwm_chip(chip); | ||||||
|  | +	u32 val; | ||||||
|  | + | ||||||
|  | +	val = ioread32(pc->mmio_base); | ||||||
|  | +	val &= ~BIT(pwm->hwpwm); | ||||||
|  | +	iowrite32(val, pc->mmio_base); | ||||||
|  | +} | ||||||
|  | + | ||||||
|  | +static const struct pwm_ops mtk_pwm_ops = { | ||||||
|  | +	.config = mtk_pwm_config, | ||||||
|  | +	.enable = mtk_pwm_enable, | ||||||
|  | +	.disable = mtk_pwm_disable, | ||||||
|  | +	.owner = THIS_MODULE, | ||||||
|  | +}; | ||||||
|  | + | ||||||
|  | +static int mtk_pwm_probe(struct platform_device *pdev) | ||||||
|  | +{ | ||||||
|  | +	struct mtk_pwm_chip *pc; | ||||||
|  | +	struct resource *r; | ||||||
|  | +	int ret; | ||||||
|  | + | ||||||
|  | +	pc = devm_kzalloc(&pdev->dev, sizeof(*pc), GFP_KERNEL); | ||||||
|  | +	if (!pc) | ||||||
|  | +		return -ENOMEM; | ||||||
|  | + | ||||||
|  | +	r = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||||||
|  | +	pc->mmio_base = devm_ioremap_resource(&pdev->dev, r); | ||||||
|  | +	if (IS_ERR(pc->mmio_base)) | ||||||
|  | +		return PTR_ERR(pc->mmio_base); | ||||||
|  | + | ||||||
|  | +	platform_set_drvdata(pdev, pc); | ||||||
|  | + | ||||||
|  | +	pc->chip.dev = &pdev->dev; | ||||||
|  | +	pc->chip.ops = &mtk_pwm_ops; | ||||||
|  | +	pc->chip.base = -1; | ||||||
|  | +	pc->chip.npwm = NUM_PWM; | ||||||
|  | + | ||||||
|  | +	ret = pwmchip_add(&pc->chip); | ||||||
|  | +	if (ret < 0) | ||||||
|  | +		dev_err(&pdev->dev, "pwmchip_add() failed: %d\n", ret); | ||||||
|  | + | ||||||
|  | +	return ret; | ||||||
|  | +} | ||||||
|  | + | ||||||
|  | +static int mtk_pwm_remove(struct platform_device *pdev) | ||||||
|  | +{ | ||||||
|  | +	struct mtk_pwm_chip *pc = platform_get_drvdata(pdev); | ||||||
|  | +	int i; | ||||||
|  | + | ||||||
|  | +	for (i = 0; i < NUM_PWM; i++) | ||||||
|  | +		pwm_disable(&pc->chip.pwms[i]); | ||||||
|  | + | ||||||
|  | +	return pwmchip_remove(&pc->chip); | ||||||
|  | +} | ||||||
|  | + | ||||||
|  | +static const struct of_device_id mtk_pwm_of_match[] = { | ||||||
|  | +	{ .compatible = "mediatek,mt7628-pwm" }, | ||||||
|  | +	{ } | ||||||
|  | +}; | ||||||
|  | + | ||||||
|  | +MODULE_DEVICE_TABLE(of, mtk_pwm_of_match); | ||||||
|  | + | ||||||
|  | +static struct platform_driver mtk_pwm_driver = { | ||||||
|  | +	.driver = { | ||||||
|  | +		.name = "mtk-pwm", | ||||||
|  | +		.owner = THIS_MODULE, | ||||||
|  | +		.of_match_table = mtk_pwm_of_match, | ||||||
|  | +	}, | ||||||
|  | +	.probe = mtk_pwm_probe, | ||||||
|  | +	.remove = mtk_pwm_remove, | ||||||
|  | +}; | ||||||
|  | + | ||||||
|  | +module_platform_driver(mtk_pwm_driver); | ||||||
|  | + | ||||||
|  | +MODULE_LICENSE("GPL"); | ||||||
|  | +MODULE_AUTHOR("John Crispin <blogic@openwrt.org>"); | ||||||
|  | +MODULE_ALIAS("platform:mtk-pwm"); | ||||||
| @@ -0,0 +1,214 @@ | |||||||
|  | mtd: spi-nor: add support for switching between 3-byte and 4-byte addressing on w25q256 flash | ||||||
|  |  | ||||||
|  | On some devices the flash chip needs to be in 3-byte addressing mode during | ||||||
|  | reboot, otherwise the boot loader will fail to start. | ||||||
|  | This mode however does not allow regular reads/writes onto the upper 16M | ||||||
|  | half. W25Q256 has separate read commands for reading from >16M, however | ||||||
|  | it does not have any separate write commands. | ||||||
|  | This patch changes the code to leave the chip in 3-byte mode most of the | ||||||
|  | time and only switch during erase/write cycles that go to >16M | ||||||
|  | addresses. | ||||||
|  |  | ||||||
|  | Signed-off-by: Felix Fietkau <nbd@nbd.name> | ||||||
|  | --- | ||||||
|  | --- a/drivers/mtd/spi-nor/spi-nor.c | ||||||
|  | +++ b/drivers/mtd/spi-nor/spi-nor.c | ||||||
|  | @@ -89,6 +89,10 @@ struct flash_info { | ||||||
|  |  #define NO_CHIP_ERASE		BIT(12) /* Chip does not support chip erase */ | ||||||
|  |  #define SPI_NOR_SKIP_SFDP	BIT(13)	/* Skip parsing of SFDP tables */ | ||||||
|  |  #define USE_CLSR		BIT(14)	/* use CLSR command */ | ||||||
|  | +#define SPI_NOR_4B_READ_OP	BIT(15)	/* | ||||||
|  | +					 * Like SPI_NOR_4B_OPCODES, but for read | ||||||
|  | +					 * op code only. | ||||||
|  | +					 */ | ||||||
|  |  }; | ||||||
|  |   | ||||||
|  |  #define JEDEC_MFR(info)	((info)->id[0]) | ||||||
|  | @@ -240,6 +244,15 @@ static inline u8 spi_nor_convert_3to4_er | ||||||
|  |  				      ARRAY_SIZE(spi_nor_3to4_erase)); | ||||||
|  |  } | ||||||
|  |   | ||||||
|  | +static void spi_nor_set_4byte_read(struct spi_nor *nor, | ||||||
|  | +				   const struct flash_info *info) | ||||||
|  | +{ | ||||||
|  | +	nor->addr_width = 3; | ||||||
|  | +	nor->ext_addr = 0; | ||||||
|  | +	nor->read_opcode = spi_nor_convert_3to4_read(nor->read_opcode); | ||||||
|  | +	nor->flags |= SNOR_F_4B_EXT_ADDR; | ||||||
|  | +} | ||||||
|  | + | ||||||
|  |  static void spi_nor_set_4byte_opcodes(struct spi_nor *nor, | ||||||
|  |  				      const struct flash_info *info) | ||||||
|  |  { | ||||||
|  | @@ -467,6 +480,36 @@ static int spi_nor_erase_sector(struct s | ||||||
|  |  	return nor->write_reg(nor, nor->erase_opcode, buf, nor->addr_width); | ||||||
|  |  } | ||||||
|  |   | ||||||
|  | +static int spi_nor_check_ext_addr(struct spi_nor *nor, u32 addr) | ||||||
|  | +{ | ||||||
|  | +	bool ext_addr; | ||||||
|  | +	int ret; | ||||||
|  | +	u8 cmd; | ||||||
|  | + | ||||||
|  | +	if (!(nor->flags & SNOR_F_4B_EXT_ADDR)) | ||||||
|  | +		return 0; | ||||||
|  | + | ||||||
|  | +	ext_addr = !!(addr & 0xff000000); | ||||||
|  | +	if (nor->ext_addr == ext_addr) | ||||||
|  | +		return 0; | ||||||
|  | + | ||||||
|  | +	cmd = ext_addr ? SPINOR_OP_EN4B : SPINOR_OP_EX4B; | ||||||
|  | +	write_enable(nor); | ||||||
|  | +	ret = nor->write_reg(nor, cmd, NULL, 0); | ||||||
|  | +	if (ret) | ||||||
|  | +		return ret; | ||||||
|  | + | ||||||
|  | +	cmd = 0; | ||||||
|  | +	ret = nor->write_reg(nor, SPINOR_OP_WREAR, &cmd, 1); | ||||||
|  | +	if (ret) | ||||||
|  | +		return ret; | ||||||
|  | + | ||||||
|  | +	nor->addr_width = 3 + ext_addr; | ||||||
|  | +	nor->ext_addr = ext_addr; | ||||||
|  | +	write_disable(nor); | ||||||
|  | +	return 0; | ||||||
|  | +} | ||||||
|  | + | ||||||
|  |  /* | ||||||
|  |   * Erase an address range on the nor chip.  The address range may extend | ||||||
|  |   * one or more erase sectors.  Return an error is there is a problem erasing. | ||||||
|  | @@ -492,6 +535,10 @@ static int spi_nor_erase(struct mtd_info | ||||||
|  |  	if (ret) | ||||||
|  |  		return ret; | ||||||
|  |   | ||||||
|  | +	ret = spi_nor_check_ext_addr(nor, addr + len); | ||||||
|  | +	if (ret) | ||||||
|  | +		return ret; | ||||||
|  | + | ||||||
|  |  	/* whole-chip erase? */ | ||||||
|  |  	if (len == mtd->size && !(nor->flags & SNOR_F_NO_OP_CHIP_ERASE)) { | ||||||
|  |  		unsigned long timeout; | ||||||
|  | @@ -542,6 +589,7 @@ static int spi_nor_erase(struct mtd_info | ||||||
|  |  	write_disable(nor); | ||||||
|  |   | ||||||
|  |  erase_err: | ||||||
|  | +	spi_nor_check_ext_addr(nor, 0); | ||||||
|  |  	spi_nor_unlock_and_unprep(nor, SPI_NOR_OPS_ERASE); | ||||||
|  |   | ||||||
|  |  	instr->state = ret ? MTD_ERASE_FAILED : MTD_ERASE_DONE; | ||||||
|  | @@ -834,7 +882,9 @@ static int spi_nor_lock(struct mtd_info | ||||||
|  |  	if (ret) | ||||||
|  |  		return ret; | ||||||
|  |   | ||||||
|  | +	spi_nor_check_ext_addr(nor, ofs + len); | ||||||
|  |  	ret = nor->flash_lock(nor, ofs, len); | ||||||
|  | +	spi_nor_check_ext_addr(nor, 0); | ||||||
|  |   | ||||||
|  |  	spi_nor_unlock_and_unprep(nor, SPI_NOR_OPS_UNLOCK); | ||||||
|  |  	return ret; | ||||||
|  | @@ -849,7 +899,9 @@ static int spi_nor_unlock(struct mtd_inf | ||||||
|  |  	if (ret) | ||||||
|  |  		return ret; | ||||||
|  |   | ||||||
|  | +	spi_nor_check_ext_addr(nor, ofs + len); | ||||||
|  |  	ret = nor->flash_unlock(nor, ofs, len); | ||||||
|  | +	spi_nor_check_ext_addr(nor, 0); | ||||||
|  |   | ||||||
|  |  	spi_nor_unlock_and_unprep(nor, SPI_NOR_OPS_LOCK); | ||||||
|  |  	return ret; | ||||||
|  | @@ -1182,7 +1234,7 @@ static const struct flash_info spi_nor_i | ||||||
|  |  	{ "w25q80", INFO(0xef5014, 0, 64 * 1024,  16, SECT_4K) }, | ||||||
|  |  	{ "w25q80bl", INFO(0xef4014, 0, 64 * 1024,  16, SECT_4K) }, | ||||||
|  |  	{ "w25q128", INFO(0xef4018, 0, 64 * 1024, 256, SECT_4K) }, | ||||||
|  | -	{ "w25q256", INFO(0xef4019, 0, 64 * 1024, 512, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, | ||||||
|  | +	{ "w25q256", INFO(0xef4019, 0, 64 * 1024, 512, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_4B_READ_OP) }, | ||||||
|  |  	{ "w25m512jv", INFO(0xef7119, 0, 64 * 1024, 1024, | ||||||
|  |  			SECT_4K | SPI_NOR_QUAD_READ | SPI_NOR_DUAL_READ) }, | ||||||
|  |   | ||||||
|  | @@ -1245,6 +1297,9 @@ static int spi_nor_read(struct mtd_info | ||||||
|  |  	if (ret) | ||||||
|  |  		return ret; | ||||||
|  |   | ||||||
|  | +	if (nor->flags & SNOR_F_4B_EXT_ADDR) | ||||||
|  | +		nor->addr_width = 4; | ||||||
|  | + | ||||||
|  |  	while (len) { | ||||||
|  |  		loff_t addr = from; | ||||||
|  |   | ||||||
|  | @@ -1269,6 +1324,18 @@ static int spi_nor_read(struct mtd_info | ||||||
|  |  	ret = 0; | ||||||
|  |   | ||||||
|  |  read_err: | ||||||
|  | +	if (nor->flags & SNOR_F_4B_EXT_ADDR) { | ||||||
|  | +		u8 val = 0; | ||||||
|  | + | ||||||
|  | +		if ((from + len) & 0xff000000) { | ||||||
|  | +			write_enable(nor); | ||||||
|  | +			nor->write_reg(nor, SPINOR_OP_WREAR, &val, 1); | ||||||
|  | +			write_disable(nor); | ||||||
|  | +		} | ||||||
|  | + | ||||||
|  | +		nor->addr_width = 3; | ||||||
|  | +	} | ||||||
|  | + | ||||||
|  |  	spi_nor_unlock_and_unprep(nor, SPI_NOR_OPS_READ); | ||||||
|  |  	return ret; | ||||||
|  |  } | ||||||
|  | @@ -1370,6 +1437,10 @@ static int spi_nor_write(struct mtd_info | ||||||
|  |  	if (ret) | ||||||
|  |  		return ret; | ||||||
|  |   | ||||||
|  | +	ret = spi_nor_check_ext_addr(nor, to + len); | ||||||
|  | +	if (ret < 0) | ||||||
|  | +		return ret; | ||||||
|  | + | ||||||
|  |  	for (i = 0; i < len; ) { | ||||||
|  |  		ssize_t written; | ||||||
|  |  		loff_t addr = to + i; | ||||||
|  | @@ -1410,6 +1481,7 @@ static int spi_nor_write(struct mtd_info | ||||||
|  |  	} | ||||||
|  |   | ||||||
|  |  write_err: | ||||||
|  | +	spi_nor_check_ext_addr(nor, 0); | ||||||
|  |  	spi_nor_unlock_and_unprep(nor, SPI_NOR_OPS_WRITE); | ||||||
|  |  	return ret; | ||||||
|  |  } | ||||||
|  | @@ -2826,8 +2898,10 @@ int spi_nor_scan(struct spi_nor *nor, co | ||||||
|  |  	} else if (mtd->size > 0x1000000) { | ||||||
|  |  		/* enable 4-byte addressing if the device exceeds 16MiB */ | ||||||
|  |  		nor->addr_width = 4; | ||||||
|  | -		if (JEDEC_MFR(info) == SNOR_MFR_SPANSION || | ||||||
|  | -		    info->flags & SPI_NOR_4B_OPCODES) | ||||||
|  | +		if (info->flags & SPI_NOR_4B_READ_OP) | ||||||
|  | +			spi_nor_set_4byte_read(nor, info); | ||||||
|  | +		else if (JEDEC_MFR(info) == SNOR_MFR_SPANSION || | ||||||
|  | +			 info->flags & SPI_NOR_4B_OPCODES) | ||||||
|  |  			spi_nor_set_4byte_opcodes(nor, info); | ||||||
|  |  		else | ||||||
|  |  			set_4byte(nor, info, 1); | ||||||
|  | --- a/include/linux/mtd/spi-nor.h | ||||||
|  | +++ b/include/linux/mtd/spi-nor.h | ||||||
|  | @@ -102,6 +102,7 @@ | ||||||
|  |  /* Used for Macronix and Winbond flashes. */ | ||||||
|  |  #define SPINOR_OP_EN4B		0xb7	/* Enter 4-byte mode */ | ||||||
|  |  #define SPINOR_OP_EX4B		0xe9	/* Exit 4-byte mode */ | ||||||
|  | +#define SPINOR_OP_WREAR		0xc5	/* Write extended address register */ | ||||||
|  |   | ||||||
|  |  /* Used for Spansion flashes only. */ | ||||||
|  |  #define SPINOR_OP_BRWR		0x17	/* Bank register write */ | ||||||
|  | @@ -229,6 +230,7 @@ enum spi_nor_option_flags { | ||||||
|  |  	SNOR_F_S3AN_ADDR_DEFAULT = BIT(3), | ||||||
|  |  	SNOR_F_READY_XSR_RDY	= BIT(4), | ||||||
|  |  	SNOR_F_USE_CLSR		= BIT(5), | ||||||
|  | +	SNOR_F_4B_EXT_ADDR	= BIT(6), | ||||||
|  |  }; | ||||||
|  |   | ||||||
|  |  /** | ||||||
|  | @@ -280,6 +282,7 @@ struct spi_nor { | ||||||
|  |  	enum spi_nor_protocol	reg_proto; | ||||||
|  |  	bool			sst_write_second; | ||||||
|  |  	u32			flags; | ||||||
|  | +	u8			ext_addr; | ||||||
|  |  	u8			cmd_buf[SPI_NOR_MAX_CMD_SIZE]; | ||||||
|  |   | ||||||
|  |  	int (*prepare)(struct spi_nor *nor, enum spi_nor_ops ops); | ||||||
| @@ -0,0 +1,73 @@ | |||||||
|  | --- a/drivers/mtd/spi-nor/spi-nor.c | ||||||
|  | +++ b/drivers/mtd/spi-nor/spi-nor.c | ||||||
|  | @@ -142,20 +142,29 @@ static int read_fsr(struct spi_nor *nor) | ||||||
|  |   * location. Return the configuration register value. | ||||||
|  |   * Returns negative if error occurred. | ||||||
|  |   */ | ||||||
|  | -static int read_cr(struct spi_nor *nor) | ||||||
|  | +static int _read_cr(struct spi_nor *nor, u8 reg) | ||||||
|  |  { | ||||||
|  |  	int ret; | ||||||
|  |  	u8 val; | ||||||
|  |   | ||||||
|  | -	ret = nor->read_reg(nor, SPINOR_OP_RDCR, &val, 1); | ||||||
|  | +	ret = nor->read_reg(nor, reg, &val, 1); | ||||||
|  |  	if (ret < 0) { | ||||||
|  | -		dev_err(nor->dev, "error %d reading CR\n", ret); | ||||||
|  | +		dev_err(nor->dev, "error %d reading %s\n", ret, | ||||||
|  | +			(reg==SPINOR_OP_RDCR)?"CR":"XCR"); | ||||||
|  |  		return ret; | ||||||
|  |  	} | ||||||
|  |   | ||||||
|  |  	return val; | ||||||
|  |  } | ||||||
|  |   | ||||||
|  | +static inline int read_cr(struct spi_nor *nor) { | ||||||
|  | +	return _read_cr(nor, SPINOR_OP_RDCR); | ||||||
|  | +} | ||||||
|  | + | ||||||
|  | +static inline int read_xcr(struct spi_nor *nor) { | ||||||
|  | +	return _read_cr(nor, SPINOR_OP_RDXCR); | ||||||
|  | +} | ||||||
|  | + | ||||||
|  |  /* | ||||||
|  |   * Write status register 1 byte | ||||||
|  |   * Returns negative if error occurred. | ||||||
|  | @@ -2898,9 +2907,16 @@ int spi_nor_scan(struct spi_nor *nor, co | ||||||
|  |  	} else if (mtd->size > 0x1000000) { | ||||||
|  |  		/* enable 4-byte addressing if the device exceeds 16MiB */ | ||||||
|  |  		nor->addr_width = 4; | ||||||
|  | -		if (info->flags & SPI_NOR_4B_READ_OP) | ||||||
|  | -			spi_nor_set_4byte_read(nor, info); | ||||||
|  | -		else if (JEDEC_MFR(info) == SNOR_MFR_SPANSION || | ||||||
|  | +		if (info->flags & SPI_NOR_4B_READ_OP) { | ||||||
|  | +			if (JEDEC_MFR(info) == SNOR_MFR_WINBOND) { | ||||||
|  | +				ret = read_xcr(nor); | ||||||
|  | +				if (!(ret > 0 && (ret & XCR_DEF_4B_ADDR_MODE))) | ||||||
|  | +					spi_nor_set_4byte_read(nor, info); | ||||||
|  | +				else | ||||||
|  | +					set_4byte(nor, info, 1); | ||||||
|  | +			} else | ||||||
|  | +				spi_nor_set_4byte_read(nor, info); | ||||||
|  | +		} else if (JEDEC_MFR(info) == SNOR_MFR_SPANSION || | ||||||
|  |  			 info->flags & SPI_NOR_4B_OPCODES) | ||||||
|  |  			spi_nor_set_4byte_opcodes(nor, info); | ||||||
|  |  		else | ||||||
|  | --- a/include/linux/mtd/spi-nor.h | ||||||
|  | +++ b/include/linux/mtd/spi-nor.h | ||||||
|  | @@ -103,6 +103,7 @@ | ||||||
|  |  #define SPINOR_OP_EN4B		0xb7	/* Enter 4-byte mode */ | ||||||
|  |  #define SPINOR_OP_EX4B		0xe9	/* Exit 4-byte mode */ | ||||||
|  |  #define SPINOR_OP_WREAR		0xc5	/* Write extended address register */ | ||||||
|  | +#define SPINOR_OP_RDXCR		0x15	/* Read extended configuration register */ | ||||||
|  |   | ||||||
|  |  /* Used for Spansion flashes only. */ | ||||||
|  |  #define SPINOR_OP_BRWR		0x17	/* Bank register write */ | ||||||
|  | @@ -135,6 +136,7 @@ | ||||||
|  |   | ||||||
|  |  /* Configuration Register bits. */ | ||||||
|  |  #define CR_QUAD_EN_SPAN		BIT(1)	/* Spansion Quad I/O */ | ||||||
|  | +#define XCR_DEF_4B_ADDR_MODE	BIT(1)	/* Winbond 4B mode default */ | ||||||
|  |   | ||||||
|  |  /* Status Register 2 bits. */ | ||||||
|  |  #define SR2_QUAD_EN_BIT7	BIT(7) | ||||||
| @@ -0,0 +1,15 @@ | |||||||
|  | --- a/drivers/usb/dwc2/platform.c | ||||||
|  | +++ b/drivers/usb/dwc2/platform.c | ||||||
|  | @@ -406,6 +406,12 @@ static int dwc2_driver_probe(struct plat | ||||||
|  |  	if (retval) | ||||||
|  |  		return retval; | ||||||
|  |   | ||||||
|  | +	/* Enable USB port before any regs access */ | ||||||
|  | +	if (dwc2_readl(hsotg->regs + PCGCTL) & 0x0f) { | ||||||
|  | +		dwc2_writel(0x00, hsotg->regs + PCGCTL); | ||||||
|  | +		/* TODO: mdelay(25) here? vendor driver don't use it */ | ||||||
|  | +	} | ||||||
|  | + | ||||||
|  |  	retval = dwc2_get_dr_mode(hsotg); | ||||||
|  |  	if (retval) | ||||||
|  |  		goto error; | ||||||
							
								
								
									
										10
									
								
								target/linux/ramips/patches-5.4/0070-weak_reordering.patch
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								target/linux/ramips/patches-5.4/0070-weak_reordering.patch
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,10 @@ | |||||||
|  | --- a/arch/mips/ralink/Kconfig | ||||||
|  | +++ b/arch/mips/ralink/Kconfig | ||||||
|  | @@ -58,6 +58,7 @@ choice | ||||||
|  |  		select COMMON_CLK | ||||||
|  |  		select CLKSRC_MIPS_GIC | ||||||
|  |  		select HW_HAS_PCI | ||||||
|  | +		select WEAK_REORDERING_BEYOND_LLSC | ||||||
|  |  endchoice | ||||||
|  |   | ||||||
|  |  choice | ||||||
							
								
								
									
										19
									
								
								target/linux/ramips/patches-5.4/0098-disable_cm.patch
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								target/linux/ramips/patches-5.4/0098-disable_cm.patch
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,19 @@ | |||||||
|  | --- a/arch/mips/kernel/mips-cm.c | ||||||
|  | +++ b/arch/mips/kernel/mips-cm.c | ||||||
|  | @@ -237,6 +237,7 @@ int mips_cm_probe(void) | ||||||
|  |   | ||||||
|  |  	/* disable CM regions */ | ||||||
|  |  	write_gcr_reg0_base(CM_GCR_REGn_BASE_BASEADDR); | ||||||
|  | +	/* | ||||||
|  |  	write_gcr_reg0_mask(CM_GCR_REGn_MASK_ADDRMASK); | ||||||
|  |  	write_gcr_reg1_base(CM_GCR_REGn_BASE_BASEADDR); | ||||||
|  |  	write_gcr_reg1_mask(CM_GCR_REGn_MASK_ADDRMASK); | ||||||
|  | @@ -244,7 +245,7 @@ int mips_cm_probe(void) | ||||||
|  |  	write_gcr_reg2_mask(CM_GCR_REGn_MASK_ADDRMASK); | ||||||
|  |  	write_gcr_reg3_base(CM_GCR_REGn_BASE_BASEADDR); | ||||||
|  |  	write_gcr_reg3_mask(CM_GCR_REGn_MASK_ADDRMASK); | ||||||
|  | - | ||||||
|  | +*/ | ||||||
|  |  	/* probe for an L2-only sync region */ | ||||||
|  |  	mips_cm_probe_l2sync(); | ||||||
|  |   | ||||||
							
								
								
									
										10
									
								
								target/linux/ramips/patches-5.4/0099-pci-mt7620.patch
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								target/linux/ramips/patches-5.4/0099-pci-mt7620.patch
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,10 @@ | |||||||
|  | --- a/arch/mips/pci/pci-mt7620.c | ||||||
|  | +++ b/arch/mips/pci/pci-mt7620.c | ||||||
|  | @@ -33,7 +33,6 @@ | ||||||
|  |  #define RALINK_GPIOMODE			0x60 | ||||||
|  |   | ||||||
|  |  #define PPLL_CFG1			0x9c | ||||||
|  | -#define PDRV_SW_SET			BIT(23) | ||||||
|  |   | ||||||
|  |  #define PPLL_DRV			0xa0 | ||||||
|  |  #define PDRV_SW_SET			(1<<31) | ||||||
							
								
								
									
										97
									
								
								target/linux/ramips/patches-5.4/0200-linkit_bootstrap.patch
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										97
									
								
								target/linux/ramips/patches-5.4/0200-linkit_bootstrap.patch
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,97 @@ | |||||||
|  | --- a/drivers/misc/Makefile | ||||||
|  | +++ b/drivers/misc/Makefile | ||||||
|  | @@ -56,6 +56,7 @@ obj-$(CONFIG_CXL_BASE)		+= cxl/ | ||||||
|  |  obj-$(CONFIG_ASPEED_LPC_CTRL)	+= aspeed-lpc-ctrl.o | ||||||
|  |  obj-$(CONFIG_ASPEED_LPC_SNOOP)	+= aspeed-lpc-snoop.o | ||||||
|  |  obj-$(CONFIG_PCI_ENDPOINT_TEST)	+= pci_endpoint_test.o | ||||||
|  | +obj-$(CONFIG_SOC_MT7620)	+= linkit.o | ||||||
|  |   | ||||||
|  |  lkdtm-$(CONFIG_LKDTM)		+= lkdtm_core.o | ||||||
|  |  lkdtm-$(CONFIG_LKDTM)		+= lkdtm_bugs.o | ||||||
|  | --- /dev/null | ||||||
|  | +++ b/drivers/misc/linkit.c | ||||||
|  | @@ -0,0 +1,84 @@ | ||||||
|  | +/* | ||||||
|  | + *  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 | ||||||
|  | + *  publishhed by the Free Software Foundation. | ||||||
|  | + * | ||||||
|  | + *  Copyright (C) 2015 John Crispin <blogic@openwrt.org> | ||||||
|  | + */ | ||||||
|  | + | ||||||
|  | +#include <linux/module.h> | ||||||
|  | +#include <linux/platform_device.h> | ||||||
|  | +#include <linux/of.h> | ||||||
|  | +#include <linux/mtd/mtd.h> | ||||||
|  | +#include <linux/gpio.h> | ||||||
|  | + | ||||||
|  | +#define LINKIT_LATCH_GPIO	11 | ||||||
|  | + | ||||||
|  | +struct linkit_hw_data { | ||||||
|  | +	char board[16]; | ||||||
|  | +	char rev[16]; | ||||||
|  | +}; | ||||||
|  | + | ||||||
|  | +static void sanify_string(char *s) | ||||||
|  | +{ | ||||||
|  | +	int i; | ||||||
|  | + | ||||||
|  | +	for (i = 0; i < 15; i++) | ||||||
|  | +		if (s[i] <= 0x20) | ||||||
|  | +			s[i] = '\0'; | ||||||
|  | +	s[15] = '\0'; | ||||||
|  | +} | ||||||
|  | + | ||||||
|  | +static int linkit_probe(struct platform_device *pdev) | ||||||
|  | +{ | ||||||
|  | +	struct linkit_hw_data hw; | ||||||
|  | +	struct mtd_info *mtd; | ||||||
|  | +	size_t retlen; | ||||||
|  | +	int ret; | ||||||
|  | + | ||||||
|  | +	mtd = get_mtd_device_nm("factory"); | ||||||
|  | +	if (IS_ERR(mtd)) | ||||||
|  | +		return PTR_ERR(mtd); | ||||||
|  | + | ||||||
|  | +	ret = mtd_read(mtd, 0x400, sizeof(hw), &retlen, (u_char *) &hw); | ||||||
|  | +	put_mtd_device(mtd); | ||||||
|  | + | ||||||
|  | +	sanify_string(hw.board); | ||||||
|  | +	sanify_string(hw.rev); | ||||||
|  | + | ||||||
|  | +	dev_info(&pdev->dev, "Version  : %s\n", hw.board); | ||||||
|  | +	dev_info(&pdev->dev, "Revision : %s\n", hw.rev); | ||||||
|  | + | ||||||
|  | +	if (!strcmp(hw.board, "LINKITS7688")) { | ||||||
|  | +		dev_info(&pdev->dev, "setting up bootstrap latch\n"); | ||||||
|  | + | ||||||
|  | +		if (devm_gpio_request(&pdev->dev, LINKIT_LATCH_GPIO, "bootstrap")) { | ||||||
|  | +			dev_err(&pdev->dev, "failed to setup bootstrap gpio\n"); | ||||||
|  | +			return -1; | ||||||
|  | +		} | ||||||
|  | +		gpio_direction_output(LINKIT_LATCH_GPIO, 0); | ||||||
|  | +	} | ||||||
|  | + | ||||||
|  | +	return 0; | ||||||
|  | +} | ||||||
|  | + | ||||||
|  | +static const struct of_device_id linkit_match[] = { | ||||||
|  | +	{ .compatible = "mediatek,linkit" }, | ||||||
|  | +	{}, | ||||||
|  | +}; | ||||||
|  | +MODULE_DEVICE_TABLE(of, linkit_match); | ||||||
|  | + | ||||||
|  | +static struct platform_driver linkit_driver = { | ||||||
|  | +	.probe = linkit_probe, | ||||||
|  | +	.driver = { | ||||||
|  | +		.name = "mtk-linkit", | ||||||
|  | +		.owner = THIS_MODULE, | ||||||
|  | +		.of_match_table = linkit_match, | ||||||
|  | +	}, | ||||||
|  | +}; | ||||||
|  | + | ||||||
|  | +int __init linkit_init(void) | ||||||
|  | +{ | ||||||
|  | +	return platform_driver_register(&linkit_driver); | ||||||
|  | +} | ||||||
|  | +late_initcall_sync(linkit_init); | ||||||
| @@ -0,0 +1,61 @@ | |||||||
|  | There is a variant of MT7621 which contains only one CPU core instead of 2. | ||||||
|  | This is not reflected in the config register, so the kernel detects more | ||||||
|  | physical cores, which leads to a hang on SMP bringup. | ||||||
|  | Add a hack to detect missing cores. | ||||||
|  |  | ||||||
|  | Signed-off-by: Felix Fietkau <nbd@nbd.name> | ||||||
|  |  | ||||||
|  | --- a/arch/mips/kernel/smp-cps.c | ||||||
|  | +++ b/arch/mips/kernel/smp-cps.c | ||||||
|  | @@ -47,6 +47,11 @@ static unsigned core_vpe_count(unsigned | ||||||
|  |  	return mips_cps_numvps(cluster, core); | ||||||
|  |  } | ||||||
|  |   | ||||||
|  | +bool __weak plat_cpu_core_present(int core) | ||||||
|  | +{ | ||||||
|  | +	return true; | ||||||
|  | +} | ||||||
|  | + | ||||||
|  |  static void __init cps_smp_setup(void) | ||||||
|  |  { | ||||||
|  |  	unsigned int nclusters, ncores, nvpes, core_vpes; | ||||||
|  | @@ -64,6 +69,8 @@ static void __init cps_smp_setup(void) | ||||||
|  |   | ||||||
|  |  		ncores = mips_cps_numcores(cl); | ||||||
|  |  		for (c = 0; c < ncores; c++) { | ||||||
|  | +			if (!plat_cpu_core_present(c)) | ||||||
|  | +				continue; | ||||||
|  |  			core_vpes = core_vpe_count(cl, c); | ||||||
|  |   | ||||||
|  |  			if (c > 0) | ||||||
|  | --- a/arch/mips/ralink/mt7621.c | ||||||
|  | +++ b/arch/mips/ralink/mt7621.c | ||||||
|  | @@ -15,6 +15,7 @@ | ||||||
|  |  #include <asm/mips-cps.h> | ||||||
|  |  #include <asm/mach-ralink/ralink_regs.h> | ||||||
|  |  #include <asm/mach-ralink/mt7621.h> | ||||||
|  | +#include <asm/mips-boards/launch.h> | ||||||
|  |   | ||||||
|  |  #include <pinmux.h> | ||||||
|  |   | ||||||
|  | @@ -162,6 +163,20 @@ void __init ralink_of_remap(void) | ||||||
|  |  		panic("Failed to remap core resources"); | ||||||
|  |  } | ||||||
|  |   | ||||||
|  | +bool plat_cpu_core_present(int core) | ||||||
|  | +{ | ||||||
|  | +	struct cpulaunch *launch = (struct cpulaunch *)CKSEG0ADDR(CPULAUNCH); | ||||||
|  | + | ||||||
|  | +	if (!core) | ||||||
|  | +		return true; | ||||||
|  | +	launch += core * 2; /* 2 VPEs per core */ | ||||||
|  | +	if (!(launch->flags & LAUNCH_FREADY)) | ||||||
|  | +		return false; | ||||||
|  | +	if (launch->flags & (LAUNCH_FGO | LAUNCH_FGONE)) | ||||||
|  | +		return false; | ||||||
|  | +	return true; | ||||||
|  | +} | ||||||
|  | + | ||||||
|  |  void prom_soc_init(struct ralink_soc_info *soc_info) | ||||||
|  |  { | ||||||
|  |  	void __iomem *sysc = (void __iomem *) KSEG1ADDR(MT7621_SYSC_BASE); | ||||||
							
								
								
									
										87
									
								
								target/linux/ramips/patches-5.4/101-mt7621-timer.patch
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										87
									
								
								target/linux/ramips/patches-5.4/101-mt7621-timer.patch
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,87 @@ | |||||||
|  | --- a/arch/mips/ralink/mt7621.c | ||||||
|  | +++ b/arch/mips/ralink/mt7621.c | ||||||
|  | @@ -9,6 +9,7 @@ | ||||||
|  |   | ||||||
|  |  #include <linux/kernel.h> | ||||||
|  |  #include <linux/init.h> | ||||||
|  | +#include <linux/jiffies.h> | ||||||
|  |   | ||||||
|  |  #include <asm/mipsregs.h> | ||||||
|  |  #include <asm/smp-ops.h> | ||||||
|  | @@ -16,6 +17,7 @@ | ||||||
|  |  #include <asm/mach-ralink/ralink_regs.h> | ||||||
|  |  #include <asm/mach-ralink/mt7621.h> | ||||||
|  |  #include <asm/mips-boards/launch.h> | ||||||
|  | +#include <asm/delay.h> | ||||||
|  |   | ||||||
|  |  #include <pinmux.h> | ||||||
|  |   | ||||||
|  | @@ -177,6 +179,58 @@ bool plat_cpu_core_present(int core) | ||||||
|  |  	return true; | ||||||
|  |  } | ||||||
|  |   | ||||||
|  | +#define LPS_PREC 8 | ||||||
|  | +/* | ||||||
|  | +*  Re-calibration lpj(loop-per-jiffy). | ||||||
|  | +*  (derived from kernel/calibrate.c) | ||||||
|  | +*/ | ||||||
|  | +static int udelay_recal(void) | ||||||
|  | +{ | ||||||
|  | +	unsigned int i, lpj = 0; | ||||||
|  | +	unsigned long ticks, loopbit; | ||||||
|  | +	int lps_precision = LPS_PREC; | ||||||
|  | + | ||||||
|  | +	lpj = (1<<12); | ||||||
|  | + | ||||||
|  | +	while ((lpj <<= 1) != 0) { | ||||||
|  | +		/* wait for "start of" clock tick */ | ||||||
|  | +		ticks = jiffies; | ||||||
|  | +		while (ticks == jiffies) | ||||||
|  | +			/* nothing */; | ||||||
|  | + | ||||||
|  | +		/* Go .. */ | ||||||
|  | +		ticks = jiffies; | ||||||
|  | +		__delay(lpj); | ||||||
|  | +		ticks = jiffies - ticks; | ||||||
|  | +		if (ticks) | ||||||
|  | +			break; | ||||||
|  | +	} | ||||||
|  | + | ||||||
|  | +	/* | ||||||
|  | +	 * Do a binary approximation to get lpj set to | ||||||
|  | +	 * equal one clock (up to lps_precision bits) | ||||||
|  | +	 */ | ||||||
|  | +	lpj >>= 1; | ||||||
|  | +	loopbit = lpj; | ||||||
|  | +	while (lps_precision-- && (loopbit >>= 1)) { | ||||||
|  | +		lpj |= loopbit; | ||||||
|  | +		ticks = jiffies; | ||||||
|  | +		while (ticks == jiffies) | ||||||
|  | +			/* nothing */; | ||||||
|  | +		ticks = jiffies; | ||||||
|  | +		__delay(lpj); | ||||||
|  | +		if (jiffies != ticks)   /* longer than 1 tick */ | ||||||
|  | +			lpj &= ~loopbit; | ||||||
|  | +	} | ||||||
|  | +	printk(KERN_INFO "%d CPUs re-calibrate udelay(lpj = %d)\n", NR_CPUS, lpj); | ||||||
|  | + | ||||||
|  | +	for(i=0; i< NR_CPUS; i++) | ||||||
|  | +		cpu_data[i].udelay_val = lpj; | ||||||
|  | + | ||||||
|  | +	return 0; | ||||||
|  | +} | ||||||
|  | +device_initcall(udelay_recal); | ||||||
|  | + | ||||||
|  |  void prom_soc_init(struct ralink_soc_info *soc_info) | ||||||
|  |  { | ||||||
|  |  	void __iomem *sysc = (void __iomem *) KSEG1ADDR(MT7621_SYSC_BASE); | ||||||
|  | --- a/arch/mips/ralink/Kconfig | ||||||
|  | +++ b/arch/mips/ralink/Kconfig | ||||||
|  | @@ -59,6 +59,7 @@ choice | ||||||
|  |  		select CLKSRC_MIPS_GIC | ||||||
|  |  		select HW_HAS_PCI | ||||||
|  |  		select WEAK_REORDERING_BEYOND_LLSC | ||||||
|  | +		select GENERIC_CLOCKEVENTS_BROADCAST | ||||||
|  |  endchoice | ||||||
|  |   | ||||||
|  |  choice | ||||||
| @@ -0,0 +1,224 @@ | |||||||
|  | --- a/arch/mips/include/asm/mach-ralink/mt7621.h | ||||||
|  | +++ b/arch/mips/include/asm/mach-ralink/mt7621.h | ||||||
|  | @@ -19,6 +19,10 @@ | ||||||
|  |  #define SYSC_REG_CHIP_REV		0x0c | ||||||
|  |  #define SYSC_REG_SYSTEM_CONFIG0		0x10 | ||||||
|  |  #define SYSC_REG_SYSTEM_CONFIG1		0x14 | ||||||
|  | +#define SYSC_REG_CLKCFG0		0x2c | ||||||
|  | +#define SYSC_REG_CUR_CLK_STS		0x44 | ||||||
|  | + | ||||||
|  | +#define MEMC_REG_CPU_PLL		0x648 | ||||||
|  |   | ||||||
|  |  #define CHIP_REV_PKG_MASK		0x1 | ||||||
|  |  #define CHIP_REV_PKG_SHIFT		16 | ||||||
|  | @@ -26,6 +30,22 @@ | ||||||
|  |  #define CHIP_REV_VER_SHIFT		8 | ||||||
|  |  #define CHIP_REV_ECO_MASK		0xf | ||||||
|  |   | ||||||
|  | +#define XTAL_MODE_SEL_MASK		0x7 | ||||||
|  | +#define XTAL_MODE_SEL_SHIFT		6 | ||||||
|  | + | ||||||
|  | +#define CPU_CLK_SEL_MASK		0x3 | ||||||
|  | +#define CPU_CLK_SEL_SHIFT		30 | ||||||
|  | + | ||||||
|  | +#define CUR_CPU_FDIV_MASK		0x1f | ||||||
|  | +#define CUR_CPU_FDIV_SHIFT		8 | ||||||
|  | +#define CUR_CPU_FFRAC_MASK		0x1f | ||||||
|  | +#define CUR_CPU_FFRAC_SHIFT		0 | ||||||
|  | + | ||||||
|  | +#define CPU_PLL_PREDIV_MASK		0x3 | ||||||
|  | +#define CPU_PLL_PREDIV_SHIFT		12 | ||||||
|  | +#define CPU_PLL_FBDIV_MASK		0x7f | ||||||
|  | +#define CPU_PLL_FBDIV_SHIFT		4 | ||||||
|  | + | ||||||
|  |  #define MT7621_DRAM_BASE                0x0 | ||||||
|  |  #define MT7621_DDR2_SIZE_MIN		32 | ||||||
|  |  #define MT7621_DDR2_SIZE_MAX		256 | ||||||
|  | --- a/arch/mips/ralink/mt7621.c | ||||||
|  | +++ b/arch/mips/ralink/mt7621.c | ||||||
|  | @@ -10,6 +10,10 @@ | ||||||
|  |  #include <linux/kernel.h> | ||||||
|  |  #include <linux/init.h> | ||||||
|  |  #include <linux/jiffies.h> | ||||||
|  | +#include <linux/clk.h> | ||||||
|  | +#include <linux/clkdev.h> | ||||||
|  | +#include <linux/clk-provider.h> | ||||||
|  | +#include <dt-bindings/clock/mt7621-clk.h> | ||||||
|  |   | ||||||
|  |  #include <asm/mipsregs.h> | ||||||
|  |  #include <asm/smp-ops.h> | ||||||
|  | @@ -18,16 +22,12 @@ | ||||||
|  |  #include <asm/mach-ralink/mt7621.h> | ||||||
|  |  #include <asm/mips-boards/launch.h> | ||||||
|  |  #include <asm/delay.h> | ||||||
|  | +#include <asm/time.h> | ||||||
|  |   | ||||||
|  |  #include <pinmux.h> | ||||||
|  |   | ||||||
|  |  #include "common.h" | ||||||
|  |   | ||||||
|  | -#define SYSC_REG_SYSCFG		0x10 | ||||||
|  | -#define SYSC_REG_CPLL_CLKCFG0	0x2c | ||||||
|  | -#define SYSC_REG_CUR_CLK_STS	0x44 | ||||||
|  | -#define CPU_CLK_SEL		(BIT(30) | BIT(31)) | ||||||
|  | - | ||||||
|  |  #define MT7621_GPIO_MODE_UART1		1 | ||||||
|  |  #define MT7621_GPIO_MODE_I2C		2 | ||||||
|  |  #define MT7621_GPIO_MODE_UART3_MASK	0x3 | ||||||
|  | @@ -113,49 +113,89 @@ static struct rt2880_pmx_group mt7621_pi | ||||||
|  |  	{ 0 } | ||||||
|  |  }; | ||||||
|  |   | ||||||
|  | +static struct clk *clks[MT7621_CLK_MAX]; | ||||||
|  | +static struct clk_onecell_data clk_data = { | ||||||
|  | +	.clks = clks, | ||||||
|  | +	.clk_num = ARRAY_SIZE(clks), | ||||||
|  | +}; | ||||||
|  | + | ||||||
|  |  phys_addr_t mips_cpc_default_phys_base(void) | ||||||
|  |  { | ||||||
|  |  	panic("Cannot detect cpc address"); | ||||||
|  |  } | ||||||
|  |   | ||||||
|  | -void __init ralink_clk_init(void) | ||||||
|  | +static struct clk *__init mt7621_add_sys_clkdev( | ||||||
|  | +	const char *id, unsigned long rate) | ||||||
|  |  { | ||||||
|  | -	int cpu_fdiv = 0; | ||||||
|  | -	int cpu_ffrac = 0; | ||||||
|  | -	int fbdiv = 0; | ||||||
|  | -	u32 clk_sts, syscfg; | ||||||
|  | -	u8 clk_sel = 0, xtal_mode; | ||||||
|  | -	u32 cpu_clk; | ||||||
|  | +	struct clk *clk; | ||||||
|  | +	int err; | ||||||
|  | + | ||||||
|  | +	clk = clk_register_fixed_rate(NULL, id, NULL, 0, rate); | ||||||
|  | +	if (IS_ERR(clk)) | ||||||
|  | +		panic("failed to allocate %s clock structure", id); | ||||||
|  | + | ||||||
|  | +	err = clk_register_clkdev(clk, id, NULL); | ||||||
|  | +	if (err) | ||||||
|  | +		panic("unable to register %s clock device", id); | ||||||
|  |   | ||||||
|  | -	if ((rt_sysc_r32(SYSC_REG_CPLL_CLKCFG0) & CPU_CLK_SEL) != 0) | ||||||
|  | -		clk_sel = 1; | ||||||
|  | +	return clk; | ||||||
|  | +} | ||||||
|  | + | ||||||
|  | +void __init ralink_clk_init(void) | ||||||
|  | +{ | ||||||
|  | +	u32 syscfg, xtal_sel, clkcfg, clk_sel, curclk, ffiv, ffrac; | ||||||
|  | +	u32 pll, prediv, fbdiv; | ||||||
|  | +	u32 xtal_clk, cpu_clk, bus_clk; | ||||||
|  | +	const static u32 prediv_tbl[] = {0, 1, 2, 2}; | ||||||
|  | + | ||||||
|  | +	syscfg = rt_sysc_r32(SYSC_REG_SYSTEM_CONFIG0); | ||||||
|  | +	xtal_sel = (syscfg >> XTAL_MODE_SEL_SHIFT) & XTAL_MODE_SEL_MASK; | ||||||
|  | + | ||||||
|  | +	clkcfg = rt_sysc_r32(SYSC_REG_CLKCFG0); | ||||||
|  | +	clk_sel = (clkcfg >> CPU_CLK_SEL_SHIFT) & CPU_CLK_SEL_MASK; | ||||||
|  | + | ||||||
|  | +	curclk = rt_sysc_r32(SYSC_REG_CUR_CLK_STS); | ||||||
|  | +	ffiv = (curclk >> CUR_CPU_FDIV_SHIFT) & CUR_CPU_FDIV_MASK; | ||||||
|  | +	ffrac = (curclk >> CUR_CPU_FFRAC_SHIFT) & CUR_CPU_FFRAC_MASK; | ||||||
|  | + | ||||||
|  | +	if (xtal_sel <= 2) | ||||||
|  | +		xtal_clk = 20 * 1000 * 1000; | ||||||
|  | +	else if (xtal_sel <= 5) | ||||||
|  | +		xtal_clk = 40 * 1000 * 1000; | ||||||
|  | +	else | ||||||
|  | +		xtal_clk = 25 * 1000 * 1000; | ||||||
|  |   | ||||||
|  |  	switch (clk_sel) { | ||||||
|  |  	case 0: | ||||||
|  | -		clk_sts = rt_sysc_r32(SYSC_REG_CUR_CLK_STS); | ||||||
|  | -		cpu_fdiv = ((clk_sts >> 8) & 0x1F); | ||||||
|  | -		cpu_ffrac = (clk_sts & 0x1F); | ||||||
|  | -		cpu_clk = (500 * cpu_ffrac / cpu_fdiv) * 1000 * 1000; | ||||||
|  | +		cpu_clk = 500 * 1000 * 1000; | ||||||
|  |  		break; | ||||||
|  | - | ||||||
|  |  	case 1: | ||||||
|  | -		fbdiv = ((rt_sysc_r32(0x648) >> 4) & 0x7F) + 1; | ||||||
|  | -		syscfg = rt_sysc_r32(SYSC_REG_SYSCFG); | ||||||
|  | -		xtal_mode = (syscfg >> 6) & 0x7; | ||||||
|  | -		if (xtal_mode >= 6) { | ||||||
|  | -			/* 25Mhz Xtal */ | ||||||
|  | -			cpu_clk = 25 * fbdiv * 1000 * 1000; | ||||||
|  | -		} else if (xtal_mode >= 3) { | ||||||
|  | -			/* 40Mhz Xtal */ | ||||||
|  | -			cpu_clk = 40 * fbdiv * 1000 * 1000; | ||||||
|  | -		} else { | ||||||
|  | -			/* 20Mhz Xtal */ | ||||||
|  | -			cpu_clk = 20 * fbdiv * 1000 * 1000; | ||||||
|  | -		} | ||||||
|  | +		pll = rt_memc_r32(MEMC_REG_CPU_PLL); | ||||||
|  | +		fbdiv = (pll >> CPU_PLL_FBDIV_SHIFT) & CPU_PLL_FBDIV_MASK; | ||||||
|  | +		prediv = (pll >> CPU_PLL_PREDIV_SHIFT) & CPU_PLL_PREDIV_MASK; | ||||||
|  | +		cpu_clk = ((fbdiv + 1) * xtal_clk) >> prediv_tbl[prediv]; | ||||||
|  |  		break; | ||||||
|  | +	default: | ||||||
|  | +		cpu_clk = xtal_clk; | ||||||
|  |  	} | ||||||
|  | + | ||||||
|  | +	cpu_clk = cpu_clk / ffiv * ffrac; | ||||||
|  | +	bus_clk = cpu_clk / 4; | ||||||
|  | + | ||||||
|  | +	clks[MT7621_CLK_CPU] = mt7621_add_sys_clkdev("cpu", cpu_clk); | ||||||
|  | +	clks[MT7621_CLK_BUS] = mt7621_add_sys_clkdev("bus", bus_clk); | ||||||
|  | + | ||||||
|  | +	pr_info("CPU Clock: %dMHz\n", cpu_clk / 1000000); | ||||||
|  | +	mips_hpt_frequency = cpu_clk / 2; | ||||||
|  |  } | ||||||
|  |   | ||||||
|  | +static void __init mt7621_clocks_init_dt(struct device_node *np) | ||||||
|  | +{ | ||||||
|  | +	of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data); | ||||||
|  | +} | ||||||
|  | + | ||||||
|  | +CLK_OF_DECLARE(ar7100, "mediatek,mt7621-pll", mt7621_clocks_init_dt); | ||||||
|  | + | ||||||
|  |  void __init ralink_of_remap(void) | ||||||
|  |  { | ||||||
|  |  	rt_sysc_membase = plat_of_remap_node("mtk,mt7621-sysc"); | ||||||
|  | --- a/arch/mips/ralink/timer-gic.c | ||||||
|  | +++ b/arch/mips/ralink/timer-gic.c | ||||||
|  | @@ -11,14 +11,14 @@ | ||||||
|  |   | ||||||
|  |  #include <linux/of.h> | ||||||
|  |  #include <linux/clk-provider.h> | ||||||
|  | -#include <linux/clocksource.h> | ||||||
|  | +#include <asm/time.h> | ||||||
|  |   | ||||||
|  |  #include "common.h" | ||||||
|  |   | ||||||
|  |  void __init plat_time_init(void) | ||||||
|  |  { | ||||||
|  |  	ralink_of_remap(); | ||||||
|  | - | ||||||
|  | +	ralink_clk_init(); | ||||||
|  |  	of_clk_init(NULL); | ||||||
|  |  	timer_probe(); | ||||||
|  |  } | ||||||
|  | --- /dev/null | ||||||
|  | +++ b/include/dt-bindings/clock/mt7621-clk.h | ||||||
|  | @@ -0,0 +1,18 @@ | ||||||
|  | +/* | ||||||
|  | + * Copyright (C) 2018 Weijie Gao <hackpascal@gmail.com> | ||||||
|  | + * | ||||||
|  | + * 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. | ||||||
|  | + * | ||||||
|  | + */ | ||||||
|  | + | ||||||
|  | +#ifndef __DT_BINDINGS_MT7621_CLK_H | ||||||
|  | +#define __DT_BINDINGS_MT7621_CLK_H | ||||||
|  | + | ||||||
|  | +#define MT7621_CLK_CPU		0 | ||||||
|  | +#define MT7621_CLK_BUS		1 | ||||||
|  | + | ||||||
|  | +#define MT7621_CLK_MAX		2 | ||||||
|  | + | ||||||
|  | +#endif /* __DT_BINDINGS_MT7621_CLK_H */ | ||||||
							
								
								
									
										125
									
								
								target/linux/ramips/patches-5.4/105-mt7621-memory-detect.patch
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										125
									
								
								target/linux/ramips/patches-5.4/105-mt7621-memory-detect.patch
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,125 @@ | |||||||
|  | From b5a52351a66f3c2a7a207548aa87d78ff2d336c0 Mon Sep 17 00:00:00 2001 | ||||||
|  | From: Chuanhong Guo <gch981213@gmail.com> | ||||||
|  | Date: Wed, 10 Jul 2019 00:24:48 +0800 | ||||||
|  | Subject: [PATCH] MIPS: ralink: mt7621: add memory detection support | ||||||
|  |  | ||||||
|  | mt7621 has the following memory map: | ||||||
|  | 0x0-0x1c000000: lower 448m memory | ||||||
|  | 0x1c000000-0x2000000: peripheral registers | ||||||
|  | 0x20000000-0x2400000: higher 64m memory | ||||||
|  |  | ||||||
|  | detect_memory_region in arch/mips/kernel/setup.c only add the first | ||||||
|  | memory region and isn't suitable for 512m memory detection because | ||||||
|  | it may accidentally read the memory area for peripheral registers. | ||||||
|  |  | ||||||
|  | This commit adds memory detection capability for mt7621: | ||||||
|  | 1. add the highmem area when 512m is detected. | ||||||
|  | 2. guard memcmp from accessing peripheral registers: | ||||||
|  |      This only happens when some weird user decided to change | ||||||
|  |      kernel load address to 256m or higher address. Since this | ||||||
|  |      is a quite unusual case, we just skip 512m testing and return | ||||||
|  |      256m as memory size. | ||||||
|  |  | ||||||
|  | Signed-off-by: Chuanhong Guo <gch981213@gmail.com> | ||||||
|  | --- | ||||||
|  |  arch/mips/include/asm/mach-ralink/mt7621.h |  7 ++--- | ||||||
|  |  arch/mips/ralink/mt7621.c                  | 30 +++++++++++++++++++--- | ||||||
|  |  2 files changed, 30 insertions(+), 7 deletions(-) | ||||||
|  |  | ||||||
|  | --- a/arch/mips/include/asm/mach-ralink/mt7621.h | ||||||
|  | +++ b/arch/mips/include/asm/mach-ralink/mt7621.h | ||||||
|  | @@ -46,9 +46,10 @@ | ||||||
|  |  #define CPU_PLL_FBDIV_MASK		0x7f | ||||||
|  |  #define CPU_PLL_FBDIV_SHIFT		4 | ||||||
|  |   | ||||||
|  | -#define MT7621_DRAM_BASE                0x0 | ||||||
|  | -#define MT7621_DDR2_SIZE_MIN		32 | ||||||
|  | -#define MT7621_DDR2_SIZE_MAX		256 | ||||||
|  | +#define MT7621_LOWMEM_BASE		0x0 | ||||||
|  | +#define MT7621_LOWMEM_MAX_SIZE		0x1C000000 | ||||||
|  | +#define MT7621_HIGHMEM_BASE		0x20000000 | ||||||
|  | +#define MT7621_HIGHMEM_SIZE		0x4000000 | ||||||
|  |   | ||||||
|  |  #define MT7621_CHIP_NAME0		0x3637544D | ||||||
|  |  #define MT7621_CHIP_NAME1		0x20203132 | ||||||
|  | --- a/arch/mips/ralink/mt7621.c | ||||||
|  | +++ b/arch/mips/ralink/mt7621.c | ||||||
|  | @@ -15,6 +15,7 @@ | ||||||
|  |  #include <linux/clk-provider.h> | ||||||
|  |  #include <dt-bindings/clock/mt7621-clk.h> | ||||||
|  |   | ||||||
|  | +#include <asm/bootinfo.h> | ||||||
|  |  #include <asm/mipsregs.h> | ||||||
|  |  #include <asm/smp-ops.h> | ||||||
|  |  #include <asm/mips-cps.h> | ||||||
|  | @@ -57,6 +58,8 @@ | ||||||
|  |  #define MT7621_GPIO_MODE_SDHCI_SHIFT	18 | ||||||
|  |  #define MT7621_GPIO_MODE_SDHCI_GPIO	1 | ||||||
|  |   | ||||||
|  | +static void *detect_magic __initdata = detect_memory_region; | ||||||
|  | + | ||||||
|  |  static struct rt2880_pmx_func uart1_grp[] =  { FUNC("uart1", 0, 1, 2) }; | ||||||
|  |  static struct rt2880_pmx_func i2c_grp[] =  { FUNC("i2c", 0, 3, 2) }; | ||||||
|  |  static struct rt2880_pmx_func uart3_grp[] = { | ||||||
|  | @@ -141,6 +144,28 @@ static struct clk *__init mt7621_add_sys | ||||||
|  |  	return clk; | ||||||
|  |  } | ||||||
|  |   | ||||||
|  | +void __init mt7621_memory_detect(void) | ||||||
|  | +{ | ||||||
|  | +	void *dm = &detect_magic; | ||||||
|  | +	phys_addr_t size; | ||||||
|  | + | ||||||
|  | +	for (size = 32 * SZ_1M; size < 256 * SZ_1M; size <<= 1) { | ||||||
|  | +		if (!memcmp(dm, dm + size, sizeof(detect_magic))) | ||||||
|  | +			break; | ||||||
|  | +	} | ||||||
|  | + | ||||||
|  | +	if ((size == 256 * SZ_1M) && | ||||||
|  | +	    (CPHYSADDR(dm + size) < MT7621_LOWMEM_MAX_SIZE) && | ||||||
|  | +	    memcmp(dm, dm + size, sizeof(detect_magic))) { | ||||||
|  | +		add_memory_region(MT7621_LOWMEM_BASE, MT7621_LOWMEM_MAX_SIZE, | ||||||
|  | +				  BOOT_MEM_RAM); | ||||||
|  | +		add_memory_region(MT7621_HIGHMEM_BASE, MT7621_HIGHMEM_SIZE, | ||||||
|  | +				  BOOT_MEM_RAM); | ||||||
|  | +	} else { | ||||||
|  | +		add_memory_region(MT7621_LOWMEM_BASE, size, BOOT_MEM_RAM); | ||||||
|  | +	} | ||||||
|  | +} | ||||||
|  | + | ||||||
|  |  void __init ralink_clk_init(void) | ||||||
|  |  { | ||||||
|  |  	u32 syscfg, xtal_sel, clkcfg, clk_sel, curclk, ffiv, ffrac; | ||||||
|  | @@ -319,10 +344,7 @@ void prom_soc_init(struct ralink_soc_inf | ||||||
|  |  		(rev >> CHIP_REV_VER_SHIFT) & CHIP_REV_VER_MASK, | ||||||
|  |  		(rev & CHIP_REV_ECO_MASK)); | ||||||
|  |   | ||||||
|  | -	soc_info->mem_size_min = MT7621_DDR2_SIZE_MIN; | ||||||
|  | -	soc_info->mem_size_max = MT7621_DDR2_SIZE_MAX; | ||||||
|  | -	soc_info->mem_base = MT7621_DRAM_BASE; | ||||||
|  | - | ||||||
|  | +	soc_info->mem_detect = mt7621_memory_detect; | ||||||
|  |  	rt2880_pinmux_data = mt7621_pinmux_data; | ||||||
|  |   | ||||||
|  |   | ||||||
|  | --- a/arch/mips/ralink/common.h | ||||||
|  | +++ b/arch/mips/ralink/common.h | ||||||
|  | @@ -19,6 +19,7 @@ struct ralink_soc_info { | ||||||
|  |  	unsigned long mem_size; | ||||||
|  |  	unsigned long mem_size_min; | ||||||
|  |  	unsigned long mem_size_max; | ||||||
|  | +	void (*mem_detect)(void); | ||||||
|  |  }; | ||||||
|  |  extern struct ralink_soc_info soc_info; | ||||||
|  |   | ||||||
|  | --- a/arch/mips/ralink/of.c | ||||||
|  | +++ b/arch/mips/ralink/of.c | ||||||
|  | @@ -89,6 +89,8 @@ void __init plat_mem_setup(void) | ||||||
|  |  	of_scan_flat_dt(early_init_dt_find_memory, NULL); | ||||||
|  |  	if (memory_dtb) | ||||||
|  |  		of_scan_flat_dt(early_init_dt_scan_memory, NULL); | ||||||
|  | +	else if (soc_info.mem_detect) | ||||||
|  | +		soc_info.mem_detect(); | ||||||
|  |  	else if (soc_info.mem_size) | ||||||
|  |  		add_memory_region(soc_info.mem_base, soc_info.mem_size * SZ_1M, | ||||||
|  |  				  BOOT_MEM_RAM); | ||||||
							
								
								
									
										15
									
								
								target/linux/ramips/patches-5.4/110-mt7621-perfctr-fix.patch
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								target/linux/ramips/patches-5.4/110-mt7621-perfctr-fix.patch
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,15 @@ | |||||||
|  | --- a/arch/mips/ralink/irq-gic.c | ||||||
|  | +++ b/arch/mips/ralink/irq-gic.c | ||||||
|  | @@ -15,6 +15,12 @@ | ||||||
|  |   | ||||||
|  |  int get_c0_perfcount_int(void) | ||||||
|  |  { | ||||||
|  | +	/* | ||||||
|  | +	 * Performance counter events are routed through GIC. | ||||||
|  | +	 * Prevent them from firing on CPU IRQ7 as well | ||||||
|  | +	 */ | ||||||
|  | +	clear_c0_status(IE_SW0 << 7); | ||||||
|  | + | ||||||
|  |  	return gic_get_c0_perfcount_int(); | ||||||
|  |  } | ||||||
|  |  EXPORT_SYMBOL_GPL(get_c0_perfcount_int); | ||||||
| @@ -0,0 +1,19 @@ | |||||||
|  | --- a/arch/mips/include/asm/mach-ralink/mt7620.h | ||||||
|  | +++ b/arch/mips/include/asm/mach-ralink/mt7620.h | ||||||
|  | @@ -137,4 +137,16 @@ static inline int mt7620_get_eco(void) | ||||||
|  |  	return rt_sysc_r32(SYSC_REG_CHIP_REV) & CHIP_REV_ECO_MASK; | ||||||
|  |  } | ||||||
|  |   | ||||||
|  | +static inline int mt7620_get_chipver(void) | ||||||
|  | +{ | ||||||
|  | +	return (rt_sysc_r32(SYSC_REG_CHIP_REV) >> CHIP_REV_VER_SHIFT) & | ||||||
|  | +		CHIP_REV_VER_MASK; | ||||||
|  | +} | ||||||
|  | + | ||||||
|  | +static inline int mt7620_get_pkg(void) | ||||||
|  | +{ | ||||||
|  | +	return (rt_sysc_r32(SYSC_REG_CHIP_REV) >> CHIP_REV_PKG_SHIFT) & | ||||||
|  | +		CHIP_REV_PKG_MASK; | ||||||
|  | +} | ||||||
|  | + | ||||||
|  |  #endif | ||||||
| @@ -0,0 +1,14 @@ | |||||||
|  | --- a/drivers/mtd/spi-nor/spi-nor.c | ||||||
|  | +++ b/drivers/mtd/spi-nor/spi-nor.c | ||||||
|  | @@ -1066,6 +1066,11 @@ static const struct flash_info spi_nor_i | ||||||
|  |  			SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | | ||||||
|  |  			SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB) | ||||||
|  |  	}, | ||||||
|  | +	{ | ||||||
|  | +		"gd25q512", INFO(0xc84020, 0, 64 * 1024, 1024, | ||||||
|  | +			SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | | ||||||
|  | +			SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB | SPI_NOR_4B_OPCODES) | ||||||
|  | +	}, | ||||||
|  |   | ||||||
|  |  	/* Intel/Numonyx -- xxxs33b */ | ||||||
|  |  	{ "160s33b",  INFO(0x898911, 0, 64 * 1024,  32, 0) }, | ||||||
| @@ -0,0 +1,72 @@ | |||||||
|  | This hack can be dropped after the next stable release from | ||||||
|  | v5.x-tree. | ||||||
|  |  | ||||||
|  | The problem was fixed upstream by | ||||||
|  |  | ||||||
|  | commit 2bffa65da43e ("mtd: spi-nor: Add a post BFPT fixup for MX25L25635E") | ||||||
|  |  | ||||||
|  | For reference see: | ||||||
|  | <https://github.com/openwrt/openwrt/pull/1743> | ||||||
|  |  | ||||||
|  | --- a/drivers/mtd/spi-nor/spi-nor.c | ||||||
|  | +++ b/drivers/mtd/spi-nor/spi-nor.c | ||||||
|  | @@ -1103,6 +1103,7 @@ static const struct flash_info spi_nor_i | ||||||
|  |  	{ "mx25l12805d", INFO(0xc22018, 0, 64 * 1024, 256, 0) }, | ||||||
|  |  	{ "mx25l12855e", INFO(0xc22618, 0, 64 * 1024, 256, 0) }, | ||||||
|  |  	{ "mx25l25635e", INFO(0xc22019, 0, 64 * 1024, 512, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, | ||||||
|  | +	{ "mx25l25635f", INFO(0xc22019, 0, 64 * 1024, 512, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES) }, | ||||||
|  |  	{ "mx25u25635f", INFO(0xc22539, 0, 64 * 1024, 512, SECT_4K | SPI_NOR_4B_OPCODES) }, | ||||||
|  |  	{ "mx25l25655e", INFO(0xc22619, 0, 64 * 1024, 512, 0) }, | ||||||
|  |  	{ "mx66l51235l", INFO(0xc2201a, 0, 64 * 1024, 1024, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES) }, | ||||||
|  | @@ -1275,11 +1276,12 @@ static const struct flash_info spi_nor_i | ||||||
|  |  	{ }, | ||||||
|  |  }; | ||||||
|  |   | ||||||
|  | -static const struct flash_info *spi_nor_read_id(struct spi_nor *nor) | ||||||
|  | +static const struct flash_info *spi_nor_read_id(struct spi_nor *nor, | ||||||
|  | +						const char *name) | ||||||
|  |  { | ||||||
|  |  	int			tmp; | ||||||
|  |  	u8			id[SPI_NOR_MAX_ID_LEN]; | ||||||
|  | -	const struct flash_info	*info; | ||||||
|  | +	const struct flash_info	*info, *first_match = NULL; | ||||||
|  |   | ||||||
|  |  	tmp = nor->read_reg(nor, SPINOR_OP_RDID, id, SPI_NOR_MAX_ID_LEN); | ||||||
|  |  	if (tmp < 0) { | ||||||
|  | @@ -1290,10 +1292,16 @@ static const struct flash_info *spi_nor_ | ||||||
|  |  	for (tmp = 0; tmp < ARRAY_SIZE(spi_nor_ids) - 1; tmp++) { | ||||||
|  |  		info = &spi_nor_ids[tmp]; | ||||||
|  |  		if (info->id_len) { | ||||||
|  | -			if (!memcmp(info->id, id, info->id_len)) | ||||||
|  | -				return &spi_nor_ids[tmp]; | ||||||
|  | +			if (!memcmp(info->id, id, info->id_len)) { | ||||||
|  | +				if (!name || !strcmp(name, info->name)) | ||||||
|  | +					return info; | ||||||
|  | +				if (!first_match) | ||||||
|  | +					first_match = info; | ||||||
|  | +			} | ||||||
|  |  		} | ||||||
|  |  	} | ||||||
|  | +	if (first_match) | ||||||
|  | +		return first_match; | ||||||
|  |  	dev_err(nor->dev, "unrecognized JEDEC id bytes: %02x, %02x, %02x\n", | ||||||
|  |  		id[0], id[1], id[2]); | ||||||
|  |  	return ERR_PTR(-ENODEV); | ||||||
|  | @@ -2773,7 +2781,7 @@ int spi_nor_scan(struct spi_nor *nor, co | ||||||
|  |  		info = spi_nor_match_id(name); | ||||||
|  |  	/* Try to auto-detect if chip name wasn't specified or not found */ | ||||||
|  |  	if (!info) | ||||||
|  | -		info = spi_nor_read_id(nor); | ||||||
|  | +		info = spi_nor_read_id(nor, NULL); | ||||||
|  |  	if (IS_ERR_OR_NULL(info)) | ||||||
|  |  		return -ENOENT; | ||||||
|  |   | ||||||
|  | @@ -2784,7 +2792,7 @@ int spi_nor_scan(struct spi_nor *nor, co | ||||||
|  |  	if (name && info->id_len) { | ||||||
|  |  		const struct flash_info *jinfo; | ||||||
|  |   | ||||||
|  | -		jinfo = spi_nor_read_id(nor); | ||||||
|  | +		jinfo = spi_nor_read_id(nor, name); | ||||||
|  |  		if (IS_ERR(jinfo)) { | ||||||
|  |  			return PTR_ERR(jinfo); | ||||||
|  |  		} else if (jinfo != info) { | ||||||
| @@ -0,0 +1,21 @@ | |||||||
|  | --- a/arch/mips/pci/pci-mt7620.c | ||||||
|  | +++ b/arch/mips/pci/pci-mt7620.c | ||||||
|  | @@ -35,6 +35,7 @@ | ||||||
|  |  #define PPLL_CFG1			0x9c | ||||||
|  |   | ||||||
|  |  #define PPLL_DRV			0xa0 | ||||||
|  | +#define PPLL_LD			(1<<23) | ||||||
|  |  #define PDRV_SW_SET			(1<<31) | ||||||
|  |  #define LC_CKDRVPD			(1<<19) | ||||||
|  |  #define LC_CKDRVOHZ			(1<<18) | ||||||
|  | @@ -242,8 +243,8 @@ static int mt7620_pci_hw_init(struct pla | ||||||
|  |  	rt_sysc_m32(0, RALINK_PCIE0_CLK_EN, RALINK_CLKCFG1); | ||||||
|  |  	mdelay(100); | ||||||
|  |   | ||||||
|  | -	if (!(rt_sysc_r32(PPLL_CFG1) & PDRV_SW_SET)) { | ||||||
|  | -		dev_err(&pdev->dev, "MT7620 PPLL unlock\n"); | ||||||
|  | +	if (!(rt_sysc_r32(PPLL_CFG1) & PPLL_LD)) { | ||||||
|  | +		dev_err(&pdev->dev, "MT7620 PPLL is unlocked, aborting init\n"); | ||||||
|  |  		reset_control_assert(rstpcie0); | ||||||
|  |  		rt_sysc_m32(RALINK_PCIE0_CLK_EN, 0, RALINK_CLKCFG1); | ||||||
|  |  		return -1; | ||||||
		Reference in New Issue
	
	Block a user