All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 00/16] MIPS: support for the Atheros AR231X SoCs
@ 2014-09-28 18:32 Sergey Ryazanov
  2014-09-28 18:33 ` [PATCH 01/16] MIPS: ar231x: add common parts Sergey Ryazanov
                   ` (15 more replies)
  0 siblings, 16 replies; 37+ messages in thread
From: Sergey Ryazanov @ 2014-09-28 18:32 UTC (permalink / raw)
  To: Ralf Baechle; +Cc: Linux MIPS

This patch set contains initial support for the following Atheros SoCs: AR5312,
AR2312, AR2313, AR2315, AR2316, AR2317, AR2318.

- Patches 1 through 14 and patch 16 add support for different parts of AR231x
  SoCs.
- Patch 11 provided only for reference, since it should be rewritten to use
  spi-nor framework.
- Patch 15 updates ath5k dependecies

The code was successfully tested with AR2313, AR2315 and AR2317 SoCs.

This code has been written by OpenWRT developers and it resided in OpenWRT's
tree for a long time. My work was to cleanup the code and its rebase on the
latest linux-mips tree.

Changes since RFC:
  - use dynamic IRQ numbers allocation
  - group ath5 related changes in one patch
  - group devices registration in separate patch

Sergey Ryazanov (16):
  MIPS: ar231x: add common parts
  MIPS: ar231x: add basic AR5312 SoC support
  MIPS: ar231x: add basic AR2315 SoC support
  MIPS: ar231x: add interrupts handling routines
  MIPS: ar231x: add early printk support
  MIPS: ar231x: add UART support
  MIPS: ar231x: add board configuration detection
  MIPS: ar231x: add SoC type detection
  gpio: add driver for Atheros AR5312 SoC GPIO controller
  gpio: add driver for Atheros AR2315 SoC GPIO controller
  mtd: add Atheros AR2315 SPI Flash driver
  watchdog: add Atheros AR2315 watchdog driver
  MIPS: ar231x: register various chip devices
  MIPS: ar231x: add AR2315 PCI host controller driver
  ath5k: update dependencies
  MIPS: ar231x: add Wireless device support

 arch/mips/Kbuild.platforms                         |   1 +
 arch/mips/Kconfig                                  |  15 +
 arch/mips/ar231x/Kconfig                           |  18 +
 arch/mips/ar231x/Makefile                          |  16 +
 arch/mips/ar231x/Platform                          |   6 +
 arch/mips/ar231x/ar2315.c                          | 385 ++++++++++++++
 arch/mips/ar231x/ar2315.h                          |  24 +
 arch/mips/ar231x/ar5312.c                          | 392 ++++++++++++++
 arch/mips/ar231x/ar5312.h                          |  24 +
 arch/mips/ar231x/board.c                           | 222 ++++++++
 arch/mips/ar231x/devices.c                         | 120 +++++
 arch/mips/ar231x/devices.h                         |  39 ++
 arch/mips/ar231x/early_printk.c                    |  45 ++
 arch/mips/ar231x/prom.c                            |  31 ++
 arch/mips/include/asm/mach-ar231x/ar2315_regs.h    | 580 +++++++++++++++++++++
 arch/mips/include/asm/mach-ar231x/ar231x.h         |  31 ++
 .../mips/include/asm/mach-ar231x/ar231x_platform.h |  73 +++
 arch/mips/include/asm/mach-ar231x/ar5312_regs.h    | 215 ++++++++
 .../asm/mach-ar231x/cpu-feature-overrides.h        |  84 +++
 arch/mips/include/asm/mach-ar231x/dma-coherence.h  |  76 +++
 arch/mips/include/asm/mach-ar231x/gpio.h           |  16 +
 arch/mips/include/asm/mach-ar231x/war.h            |  25 +
 arch/mips/pci/Makefile                             |   1 +
 arch/mips/pci/pci-ar2315.c                         | 353 +++++++++++++
 drivers/gpio/Kconfig                               |  14 +
 drivers/gpio/Makefile                              |   2 +
 drivers/gpio/gpio-ar2315.c                         | 232 +++++++++
 drivers/gpio/gpio-ar5312.c                         | 121 +++++
 drivers/mtd/devices/Kconfig                        |   5 +
 drivers/mtd/devices/Makefile                       |   1 +
 drivers/mtd/devices/ar2315.c                       | 459 ++++++++++++++++
 drivers/mtd/devices/ar2315_spiflash.h              | 106 ++++
 drivers/net/wireless/ath/ath5k/Kconfig             |  10 +-
 drivers/net/wireless/ath/ath5k/ath5k.h             |   2 +-
 drivers/net/wireless/ath/ath5k/base.c              |   4 +-
 drivers/net/wireless/ath/ath5k/led.c               |   4 +-
 drivers/watchdog/Kconfig                           |   8 +
 drivers/watchdog/Makefile                          |   1 +
 drivers/watchdog/ar2315-wtd.c                      | 167 ++++++
 39 files changed, 3918 insertions(+), 10 deletions(-)
 create mode 100644 arch/mips/ar231x/Kconfig
 create mode 100644 arch/mips/ar231x/Makefile
 create mode 100644 arch/mips/ar231x/Platform
 create mode 100644 arch/mips/ar231x/ar2315.c
 create mode 100644 arch/mips/ar231x/ar2315.h
 create mode 100644 arch/mips/ar231x/ar5312.c
 create mode 100644 arch/mips/ar231x/ar5312.h
 create mode 100644 arch/mips/ar231x/board.c
 create mode 100644 arch/mips/ar231x/devices.c
 create mode 100644 arch/mips/ar231x/devices.h
 create mode 100644 arch/mips/ar231x/early_printk.c
 create mode 100644 arch/mips/ar231x/prom.c
 create mode 100644 arch/mips/include/asm/mach-ar231x/ar2315_regs.h
 create mode 100644 arch/mips/include/asm/mach-ar231x/ar231x.h
 create mode 100644 arch/mips/include/asm/mach-ar231x/ar231x_platform.h
 create mode 100644 arch/mips/include/asm/mach-ar231x/ar5312_regs.h
 create mode 100644 arch/mips/include/asm/mach-ar231x/cpu-feature-overrides.h
 create mode 100644 arch/mips/include/asm/mach-ar231x/dma-coherence.h
 create mode 100644 arch/mips/include/asm/mach-ar231x/gpio.h
 create mode 100644 arch/mips/include/asm/mach-ar231x/war.h
 create mode 100644 arch/mips/pci/pci-ar2315.c
 create mode 100644 drivers/gpio/gpio-ar2315.c
 create mode 100644 drivers/gpio/gpio-ar5312.c
 create mode 100644 drivers/mtd/devices/ar2315.c
 create mode 100644 drivers/mtd/devices/ar2315_spiflash.h
 create mode 100644 drivers/watchdog/ar2315-wtd.c

-- 
1.8.5.5

^ permalink raw reply	[flat|nested] 37+ messages in thread

* [PATCH 01/16] MIPS: ar231x: add common parts
  2014-09-28 18:32 [PATCH 00/16] MIPS: support for the Atheros AR231X SoCs Sergey Ryazanov
@ 2014-09-28 18:33 ` Sergey Ryazanov
  2014-09-29  9:30   ` Jonas Gorski
  2014-09-28 18:33 ` [PATCH 02/16] MIPS: ar231x: add basic AR5312 SoC support Sergey Ryazanov
                   ` (14 subsequent siblings)
  15 siblings, 1 reply; 37+ messages in thread
From: Sergey Ryazanov @ 2014-09-28 18:33 UTC (permalink / raw)
  To: Ralf Baechle; +Cc: Linux MIPS

Add common code for Atheros AR5312 and Atheros AR2315 SoCs families.

Signed-off-by: Sergey Ryazanov <ryazanov.s.a@gmail.com>
---
 arch/mips/Kbuild.platforms                         |  1 +
 arch/mips/Kconfig                                  | 13 ++++
 arch/mips/ar231x/Makefile                          | 11 ++++
 arch/mips/ar231x/Platform                          |  6 ++
 arch/mips/ar231x/board.c                           | 53 +++++++++++++++
 arch/mips/ar231x/devices.c                         | 20 ++++++
 arch/mips/ar231x/devices.h                         | 22 +++++++
 arch/mips/ar231x/prom.c                            | 26 ++++++++
 arch/mips/include/asm/mach-ar231x/ar231x.h         | 29 +++++++++
 .../asm/mach-ar231x/cpu-feature-overrides.h        | 76 ++++++++++++++++++++++
 arch/mips/include/asm/mach-ar231x/dma-coherence.h  | 64 ++++++++++++++++++
 arch/mips/include/asm/mach-ar231x/gpio.h           | 16 +++++
 arch/mips/include/asm/mach-ar231x/war.h            | 25 +++++++
 13 files changed, 362 insertions(+)
 create mode 100644 arch/mips/ar231x/Makefile
 create mode 100644 arch/mips/ar231x/Platform
 create mode 100644 arch/mips/ar231x/board.c
 create mode 100644 arch/mips/ar231x/devices.c
 create mode 100644 arch/mips/ar231x/devices.h
 create mode 100644 arch/mips/ar231x/prom.c
 create mode 100644 arch/mips/include/asm/mach-ar231x/ar231x.h
 create mode 100644 arch/mips/include/asm/mach-ar231x/cpu-feature-overrides.h
 create mode 100644 arch/mips/include/asm/mach-ar231x/dma-coherence.h
 create mode 100644 arch/mips/include/asm/mach-ar231x/gpio.h
 create mode 100644 arch/mips/include/asm/mach-ar231x/war.h

diff --git a/arch/mips/Kbuild.platforms b/arch/mips/Kbuild.platforms
index f5e18bf..ee1940a 100644
--- a/arch/mips/Kbuild.platforms
+++ b/arch/mips/Kbuild.platforms
@@ -1,6 +1,7 @@
 # All platforms listed in alphabetic order
 
 platforms += alchemy
+platforms += ar231x
 platforms += ar7
 platforms += ath79
 platforms += bcm47xx
diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig
index 01c0389..6adae4c 100644
--- a/arch/mips/Kconfig
+++ b/arch/mips/Kconfig
@@ -73,6 +73,19 @@ config MIPS_ALCHEMY
 	select SYS_SUPPORTS_ZBOOT
 	select COMMON_CLK
 
+config AR231X
+	bool "Atheros AR231x/AR531x SoC support"
+	select CEVT_R4K
+	select CSRC_R4K
+	select DMA_NONCOHERENT
+	select IRQ_CPU
+	select SYS_HAS_CPU_MIPS32_R1
+	select SYS_SUPPORTS_BIG_ENDIAN
+	select SYS_SUPPORTS_32BIT_KERNEL
+	select ARCH_REQUIRE_GPIOLIB
+	help
+	  Support for Atheros AR231x and Atheros AR531x based boards
+
 config AR7
 	bool "Texas Instruments AR7"
 	select BOOT_ELF32
diff --git a/arch/mips/ar231x/Makefile b/arch/mips/ar231x/Makefile
new file mode 100644
index 0000000..9199fa1
--- /dev/null
+++ b/arch/mips/ar231x/Makefile
@@ -0,0 +1,11 @@
+#
+# This file is subject to the terms and conditions of the GNU General Public
+# License.  See the file "COPYING" in the main directory of this archive
+# for more details.
+#
+# Copyright (C) 2006 FON Technology, SL.
+# Copyright (C) 2006 Imre Kaloz <kaloz@openwrt.org>
+# Copyright (C) 2006-2009 Felix Fietkau <nbd@openwrt.org>
+#
+
+obj-y += board.o prom.o devices.o
diff --git a/arch/mips/ar231x/Platform b/arch/mips/ar231x/Platform
new file mode 100644
index 0000000..c924fd1
--- /dev/null
+++ b/arch/mips/ar231x/Platform
@@ -0,0 +1,6 @@
+#
+# Atheros AR531X/AR231X WiSoC
+#
+platform-$(CONFIG_AR231X)	+= ar231x/
+cflags-$(CONFIG_AR231X)		+= -I$(srctree)/arch/mips/include/asm/mach-ar231x
+load-$(CONFIG_AR231X)		+= 0xffffffff80041000
diff --git a/arch/mips/ar231x/board.c b/arch/mips/ar231x/board.c
new file mode 100644
index 0000000..9cde045
--- /dev/null
+++ b/arch/mips/ar231x/board.c
@@ -0,0 +1,53 @@
+/*
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 2003 Atheros Communications, Inc.,  All Rights Reserved.
+ * Copyright (C) 2006 FON Technology, SL.
+ * Copyright (C) 2006 Imre Kaloz <kaloz@openwrt.org>
+ * Copyright (C) 2006-2009 Felix Fietkau <nbd@openwrt.org>
+ */
+
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <asm/irq_cpu.h>
+#include <asm/reboot.h>
+#include <asm/bootinfo.h>
+#include <asm/time.h>
+
+static void ar231x_halt(void)
+{
+	local_irq_disable();
+	while (1)
+		;
+}
+
+void __init plat_mem_setup(void)
+{
+	_machine_halt = ar231x_halt;
+	pm_power_off = ar231x_halt;
+
+	/* Disable data watchpoints */
+	write_c0_watchlo0(0);
+}
+
+asmlinkage void plat_irq_dispatch(void)
+{
+}
+
+void __init plat_time_init(void)
+{
+}
+
+unsigned int __cpuinit get_c0_compare_int(void)
+{
+	return CP0_LEGACY_COMPARE_IRQ;
+}
+
+void __init arch_init_irq(void)
+{
+	clear_c0_status(ST0_IM);
+	mips_cpu_irq_init();
+}
+
diff --git a/arch/mips/ar231x/devices.c b/arch/mips/ar231x/devices.c
new file mode 100644
index 0000000..f71a643
--- /dev/null
+++ b/arch/mips/ar231x/devices.c
@@ -0,0 +1,20 @@
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <asm/bootinfo.h>
+
+#include "devices.h"
+
+int ar231x_devtype = DEV_TYPE_UNKNOWN;
+
+static const char * const devtype_strings[] = {
+	[DEV_TYPE_UNKNOWN] = "Atheros (unknown)",
+};
+
+const char *get_system_type(void)
+{
+	if ((ar231x_devtype >= ARRAY_SIZE(devtype_strings)) ||
+	    !devtype_strings[ar231x_devtype])
+		return devtype_strings[DEV_TYPE_UNKNOWN];
+	return devtype_strings[ar231x_devtype];
+}
+
diff --git a/arch/mips/ar231x/devices.h b/arch/mips/ar231x/devices.h
new file mode 100644
index 0000000..1590577
--- /dev/null
+++ b/arch/mips/ar231x/devices.h
@@ -0,0 +1,22 @@
+#ifndef __AR231X_DEVICES_H
+#define __AR231X_DEVICES_H
+
+#include <linux/cpu.h>
+
+enum {
+	DEV_TYPE_UNKNOWN
+};
+
+extern int ar231x_devtype;
+
+static inline bool is_2315(void)
+{
+	return (current_cpu_data.cputype == CPU_4KEC);
+}
+
+static inline bool is_5312(void)
+{
+	return !is_2315();
+}
+
+#endif
diff --git a/arch/mips/ar231x/prom.c b/arch/mips/ar231x/prom.c
new file mode 100644
index 0000000..522357f
--- /dev/null
+++ b/arch/mips/ar231x/prom.c
@@ -0,0 +1,26 @@
+/*
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright MontaVista Software Inc
+ * Copyright (C) 2003 Atheros Communications, Inc.,  All Rights Reserved.
+ * Copyright (C) 2006 FON Technology, SL.
+ * Copyright (C) 2006 Imre Kaloz <kaloz@openwrt.org>
+ * Copyright (C) 2006 Felix Fietkau <nbd@openwrt.org>
+ */
+
+/*
+ * Prom setup file for ar231x
+ */
+
+#include <linux/init.h>
+#include <asm/bootinfo.h>
+
+void __init prom_init(void)
+{
+}
+
+void __init prom_free_prom_memory(void)
+{
+}
diff --git a/arch/mips/include/asm/mach-ar231x/ar231x.h b/arch/mips/include/asm/mach-ar231x/ar231x.h
new file mode 100644
index 0000000..b830723
--- /dev/null
+++ b/arch/mips/include/asm/mach-ar231x/ar231x.h
@@ -0,0 +1,29 @@
+#ifndef __ASM_MACH_AR231X_H
+#define __ASM_MACH_AR231X_H
+
+#include <linux/io.h>
+
+#define AR231X_REG_MS(_val, _field)	(((_val) & _field##_M) >> _field##_S)
+
+static inline u32 ar231x_read_reg(u32 reg)
+{
+	return __raw_readl((void __iomem *)KSEG1ADDR(reg));
+}
+
+static inline void ar231x_write_reg(u32 reg, u32 val)
+{
+	__raw_writel(val, (void __iomem *)KSEG1ADDR(reg));
+}
+
+static inline u32 ar231x_mask_reg(u32 reg, u32 mask, u32 val)
+{
+	u32 ret = ar231x_read_reg(reg);
+
+	ret &= ~mask;
+	ret |= val;
+	ar231x_write_reg(reg, ret);
+
+	return ret;
+}
+
+#endif	/* __ASM_MACH_AR231X_H */
diff --git a/arch/mips/include/asm/mach-ar231x/cpu-feature-overrides.h b/arch/mips/include/asm/mach-ar231x/cpu-feature-overrides.h
new file mode 100644
index 0000000..337fe3e
--- /dev/null
+++ b/arch/mips/include/asm/mach-ar231x/cpu-feature-overrides.h
@@ -0,0 +1,76 @@
+/*
+ *  Atheros AR231x/AR531x SoC specific CPU feature overrides
+ *
+ *  Copyright (C) 2008 Gabor Juhos <juhosg@openwrt.org>
+ *
+ *  This file was derived from: include/asm-mips/cpu-features.h
+ *	Copyright (C) 2003, 2004 Ralf Baechle
+ *	Copyright (C) 2004 Maciej W. Rozycki
+ *
+ *  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_AR231X_CPU_FEATURE_OVERRIDES_H
+#define __ASM_MACH_AR231X_CPU_FEATURE_OVERRIDES_H
+
+/*
+ * The Atheros AR531x/AR231x SoCs have MIPS 4Kc/4KEc core.
+ */
+#define cpu_has_tlb			1
+#define cpu_has_4kex			1
+#define cpu_has_3k_cache		0
+#define cpu_has_4k_cache		1
+#define cpu_has_tx39_cache		0
+#define cpu_has_sb1_cache		0
+#define cpu_has_fpu			0
+#define cpu_has_32fpr			0
+#define cpu_has_counter			1
+/* #define cpu_has_watch		? */
+/* #define cpu_has_divec		? */
+/* #define cpu_has_vce			? */
+/* #define cpu_has_cache_cdex_p		? */
+/* #define cpu_has_cache_cdex_s		? */
+/* #define cpu_has_prefetch		? */
+/* #define cpu_has_mcheck		? */
+#define cpu_has_ejtag			1
+
+/*
+ * The MIPS 4Kc V0.9 core in the AR5312/AR2312 have problems with the
+ * ll/sc instructions.
+ */
+#define cpu_has_llsc			0
+
+#define cpu_has_mips16			0
+#define cpu_has_mdmx			0
+#define cpu_has_mips3d			0
+#define cpu_has_smartmips		0
+
+/* #define cpu_has_vtag_icache		? */
+/* #define cpu_has_dc_aliases		? */
+/* #define cpu_has_ic_fills_f_dc	? */
+/* #define cpu_has_pindexed_dcache	? */
+
+/* #define cpu_icache_snoops_remote_store	? */
+
+#define cpu_has_mips32r1		1
+
+#define cpu_has_mips64r1		0
+#define cpu_has_mips64r2		0
+
+#define cpu_has_dsp			0
+#define cpu_has_mipsmt			0
+
+/* #define cpu_has_nofpuex		? */
+#define cpu_has_64bits			0
+#define cpu_has_64bit_zero_reg		0
+#define cpu_has_64bit_gp_regs		0
+#define cpu_has_64bit_addresses		0
+
+/* #define cpu_has_inclusive_pcaches	? */
+
+/* #define cpu_dcache_line_size()	? */
+/* #define cpu_icache_line_size()	? */
+
+#endif /* __ASM_MACH_AR231X_CPU_FEATURE_OVERRIDES_H */
diff --git a/arch/mips/include/asm/mach-ar231x/dma-coherence.h b/arch/mips/include/asm/mach-ar231x/dma-coherence.h
new file mode 100644
index 0000000..ed32240
--- /dev/null
+++ b/arch/mips/include/asm/mach-ar231x/dma-coherence.h
@@ -0,0 +1,64 @@
+/*
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 2006  Ralf Baechle <ralf@linux-mips.org>
+ * Copyright (C) 2007  Felix Fietkau <nbd@openwrt.org>
+ *
+ */
+#ifndef __ASM_MACH_AR231X_DMA_COHERENCE_H
+#define __ASM_MACH_AR231X_DMA_COHERENCE_H
+
+#include <linux/device.h>
+
+static inline dma_addr_t
+plat_map_dma_mem(struct device *dev, void *addr, size_t size)
+{
+	return virt_to_phys(addr);
+}
+
+static inline dma_addr_t
+plat_map_dma_mem_page(struct device *dev, struct page *page)
+{
+	return page_to_phys(page);
+}
+
+static inline unsigned long
+plat_dma_addr_to_phys(struct device *dev, dma_addr_t dma_addr)
+{
+	return dma_addr;
+}
+
+static inline void
+plat_unmap_dma_mem(struct device *dev, dma_addr_t dma_addr, size_t size,
+		   enum dma_data_direction direction)
+{
+}
+
+static inline int plat_dma_supported(struct device *dev, u64 mask)
+{
+	return 1;
+}
+
+static inline void plat_extra_sync_for_device(struct device *dev)
+{
+}
+
+static inline int plat_dma_mapping_error(struct device *dev,
+					 dma_addr_t dma_addr)
+{
+	return 0;
+}
+
+static inline int plat_device_is_coherent(struct device *dev)
+{
+#ifdef CONFIG_DMA_COHERENT
+	return 1;
+#endif
+#ifdef CONFIG_DMA_NONCOHERENT
+	return 0;
+#endif
+}
+
+#endif /* __ASM_MACH_AR231X_DMA_COHERENCE_H */
diff --git a/arch/mips/include/asm/mach-ar231x/gpio.h b/arch/mips/include/asm/mach-ar231x/gpio.h
new file mode 100644
index 0000000..89d29f1
--- /dev/null
+++ b/arch/mips/include/asm/mach-ar231x/gpio.h
@@ -0,0 +1,16 @@
+#ifndef __ASM_MACH_AR231X_GPIO_H
+#define __ASM_MACH_AR231X_GPIO_H
+
+#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
+
+static inline int irq_to_gpio(unsigned irq)
+{
+	return -EINVAL;
+}
+
+#endif	/* __ASM_MACH_AR231X_GPIO_H */
diff --git a/arch/mips/include/asm/mach-ar231x/war.h b/arch/mips/include/asm/mach-ar231x/war.h
new file mode 100644
index 0000000..5faf9da
--- /dev/null
+++ b/arch/mips/include/asm/mach-ar231x/war.h
@@ -0,0 +1,25 @@
+/*
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 2008 Felix Fietkau <nbd@openwrt.org>
+ */
+#ifndef __ASM_MACH_AR231X_WAR_H
+#define __ASM_MACH_AR231X_WAR_H
+
+#define R4600_V1_INDEX_ICACHEOP_WAR	0
+#define R4600_V1_HIT_CACHEOP_WAR	0
+#define R4600_V2_HIT_CACHEOP_WAR	0
+#define R5432_CP0_INTERRUPT_WAR		0
+#define BCM1250_M3_WAR			0
+#define SIBYTE_1956_WAR			0
+#define MIPS4K_ICACHE_REFILL_WAR	0
+#define MIPS_CACHE_SYNC_WAR		0
+#define TX49XX_ICACHE_INDEX_INV_WAR	0
+#define RM9000_CDEX_SMP_WAR		0
+#define ICACHE_REFILLS_WORKAROUND_WAR	0
+#define R10000_LLSC_WAR			0
+#define MIPS34K_MISSED_ITLB_WAR		0
+
+#endif /* __ASM_MACH_AR231X_WAR_H */
-- 
1.8.5.5

^ permalink raw reply related	[flat|nested] 37+ messages in thread

* [PATCH 02/16] MIPS: ar231x: add basic AR5312 SoC support
  2014-09-28 18:32 [PATCH 00/16] MIPS: support for the Atheros AR231X SoCs Sergey Ryazanov
  2014-09-28 18:33 ` [PATCH 01/16] MIPS: ar231x: add common parts Sergey Ryazanov
@ 2014-09-28 18:33 ` Sergey Ryazanov
  2014-09-29  9:35   ` Jonas Gorski
  2014-09-28 18:33 ` [PATCH 03/16] MIPS: ar231x: add basic AR2315 " Sergey Ryazanov
                   ` (13 subsequent siblings)
  15 siblings, 1 reply; 37+ messages in thread
From: Sergey Ryazanov @ 2014-09-28 18:33 UTC (permalink / raw)
  To: Ralf Baechle; +Cc: Linux MIPS

Add basic support for Atheros AR5312/AR2312 SoCs: registers definition
file and initial setup code.

Signed-off-by: Sergey Ryazanov <ryazanov.s.a@gmail.com>
---
 arch/mips/Kconfig                               |   1 +
 arch/mips/ar231x/Kconfig                        |   4 +
 arch/mips/ar231x/Makefile                       |   2 +
 arch/mips/ar231x/ar5312.c                       | 143 ++++++++++++++++++
 arch/mips/ar231x/ar5312.h                       |  18 +++
 arch/mips/ar231x/board.c                        |   5 +
 arch/mips/ar231x/prom.c                         |   3 +
 arch/mips/include/asm/mach-ar231x/ar5312_regs.h | 190 ++++++++++++++++++++++++
 8 files changed, 366 insertions(+)
 create mode 100644 arch/mips/ar231x/Kconfig
 create mode 100644 arch/mips/ar231x/ar5312.c
 create mode 100644 arch/mips/ar231x/ar5312.h
 create mode 100644 arch/mips/include/asm/mach-ar231x/ar5312_regs.h

diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig
index 6adae4c..bd81f7a 100644
--- a/arch/mips/Kconfig
+++ b/arch/mips/Kconfig
@@ -845,6 +845,7 @@ config MIPS_PARAVIRT
 endchoice
 
 source "arch/mips/alchemy/Kconfig"
+source "arch/mips/ar231x/Kconfig"
 source "arch/mips/ath79/Kconfig"
 source "arch/mips/bcm47xx/Kconfig"
 source "arch/mips/bcm63xx/Kconfig"
diff --git a/arch/mips/ar231x/Kconfig b/arch/mips/ar231x/Kconfig
new file mode 100644
index 0000000..7634a64
--- /dev/null
+++ b/arch/mips/ar231x/Kconfig
@@ -0,0 +1,4 @@
+config SOC_AR5312
+	bool "Atheros AR5312/AR2312+ SoC support"
+	depends on AR231X
+	default y
diff --git a/arch/mips/ar231x/Makefile b/arch/mips/ar231x/Makefile
index 9199fa1..3361619 100644
--- a/arch/mips/ar231x/Makefile
+++ b/arch/mips/ar231x/Makefile
@@ -9,3 +9,5 @@
 #
 
 obj-y += board.o prom.o devices.o
+
+obj-$(CONFIG_SOC_AR5312) += ar5312.o
diff --git a/arch/mips/ar231x/ar5312.c b/arch/mips/ar231x/ar5312.c
new file mode 100644
index 0000000..909bee0
--- /dev/null
+++ b/arch/mips/ar231x/ar5312.c
@@ -0,0 +1,143 @@
+/*
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 2003 Atheros Communications, Inc.,  All Rights Reserved.
+ * Copyright (C) 2006 FON Technology, SL.
+ * Copyright (C) 2006 Imre Kaloz <kaloz@openwrt.org>
+ * Copyright (C) 2006-2009 Felix Fietkau <nbd@openwrt.org>
+ * Copyright (C) 2012 Alexandros C. Couloumbis <alex@ozo.com>
+ */
+
+/*
+ * Platform devices for Atheros AR5312 SoCs
+ */
+
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/reboot.h>
+#include <asm/bootinfo.h>
+#include <asm/reboot.h>
+#include <asm/time.h>
+
+#include <ar5312_regs.h>
+#include <ar231x.h>
+
+#include "devices.h"
+#include "ar5312.h"
+
+static void ar5312_restart(char *command)
+{
+	/* reset the system */
+	local_irq_disable();
+	while (1)
+		ar231x_write_reg(AR5312_RESET, AR5312_RESET_SYSTEM);
+}
+
+/*
+ * This table is indexed by bits 5..4 of the CLOCKCTL1 register
+ * to determine the predevisor value.
+ */
+static unsigned clockctl1_predivide_table[4] __initdata = { 1, 2, 4, 5 };
+
+static unsigned __init ar5312_cpu_frequency(void)
+{
+	u32 scratch, devid, clock_ctl1;
+	u32 predivide_mask, multiplier_mask, doubler_mask;
+	unsigned predivide_shift, multiplier_shift;
+	unsigned predivide_select, predivisor, multiplier;
+
+	/* Trust the bootrom's idea of cpu frequency. */
+	scratch = ar231x_read_reg(AR5312_SCRATCH);
+	if (scratch)
+		return scratch;
+
+	devid = ar231x_read_reg(AR5312_REV);
+	devid = (devid & AR5312_REV_MAJ) >> AR5312_REV_MAJ_S;
+	if (devid == AR5312_REV_MAJ_AR2313) {
+		predivide_mask = AR2313_CLOCKCTL1_PREDIVIDE_MASK;
+		predivide_shift = AR2313_CLOCKCTL1_PREDIVIDE_SHIFT;
+		multiplier_mask = AR2313_CLOCKCTL1_MULTIPLIER_MASK;
+		multiplier_shift = AR2313_CLOCKCTL1_MULTIPLIER_SHIFT;
+		doubler_mask = AR2313_CLOCKCTL1_DOUBLER_MASK;
+	} else { /* AR5312 and AR2312 */
+		predivide_mask = AR5312_CLOCKCTL1_PREDIVIDE_MASK;
+		predivide_shift = AR5312_CLOCKCTL1_PREDIVIDE_SHIFT;
+		multiplier_mask = AR5312_CLOCKCTL1_MULTIPLIER_MASK;
+		multiplier_shift = AR5312_CLOCKCTL1_MULTIPLIER_SHIFT;
+		doubler_mask = AR5312_CLOCKCTL1_DOUBLER_MASK;
+	}
+
+	/*
+	 * Clocking is derived from a fixed 40MHz input clock.
+	 *
+	 *  cpu_freq = input_clock * MULT (where MULT is PLL multiplier)
+	 *  sys_freq = cpu_freq / 4	  (used for APB clock, serial,
+	 *				   flash, Timer, Watchdog Timer)
+	 *
+	 *  cnt_freq = cpu_freq / 2	  (use for CPU count/compare)
+	 *
+	 * So, for example, with a PLL multiplier of 5, we have
+	 *
+	 *  cpu_freq = 200MHz
+	 *  sys_freq = 50MHz
+	 *  cnt_freq = 100MHz
+	 *
+	 * We compute the CPU frequency, based on PLL settings.
+	 */
+
+	clock_ctl1 = ar231x_read_reg(AR5312_CLOCKCTL1);
+	predivide_select = (clock_ctl1 & predivide_mask) >> predivide_shift;
+	predivisor = clockctl1_predivide_table[predivide_select];
+	multiplier = (clock_ctl1 & multiplier_mask) >> multiplier_shift;
+
+	if (clock_ctl1 & doubler_mask)
+		multiplier <<= 1;
+
+	return (40000000 / predivisor) * multiplier;
+}
+
+static inline unsigned ar5312_sys_frequency(void)
+{
+	return ar5312_cpu_frequency() / 4;
+}
+
+void __init ar5312_plat_time_init(void)
+{
+	if (!is_5312())
+		return;
+
+	mips_hpt_frequency = ar5312_cpu_frequency() / 2;
+}
+
+void __init ar5312_plat_mem_setup(void)
+{
+	if (!is_5312())
+		return;
+
+	/* Clear any lingering AHB errors */
+	ar231x_read_reg(AR5312_PROCADDR);
+	ar231x_read_reg(AR5312_DMAADDR);
+	ar231x_write_reg(AR5312_WD_CTRL, AR5312_WD_CTRL_IGNORE_EXPIRATION);
+
+	_machine_restart = ar5312_restart;
+}
+
+void __init ar5312_prom_init(void)
+{
+	u32 memsize, memcfg, bank0_ac, bank1_ac;
+
+	if (!is_5312())
+		return;
+
+	/* Detect memory size */
+	memcfg = ar231x_read_reg(AR5312_MEM_CFG1);
+	bank0_ac = AR231X_REG_MS(memcfg, AR5312_MEM_CFG1_AC0);
+	bank1_ac = AR231X_REG_MS(memcfg, AR5312_MEM_CFG1_AC1);
+	memsize = (bank0_ac ? (1 << (bank0_ac + 1)) : 0) +
+		  (bank1_ac ? (1 << (bank1_ac + 1)) : 0);
+	memsize <<= 20;
+	add_memory_region(0, memsize, BOOT_MEM_RAM);
+}
+
diff --git a/arch/mips/ar231x/ar5312.h b/arch/mips/ar231x/ar5312.h
new file mode 100644
index 0000000..339b28e
--- /dev/null
+++ b/arch/mips/ar231x/ar5312.h
@@ -0,0 +1,18 @@
+#ifndef __AR5312_H
+#define __AR5312_H
+
+#ifdef CONFIG_SOC_AR5312
+
+void ar5312_plat_time_init(void);
+void ar5312_plat_mem_setup(void);
+void ar5312_prom_init(void);
+
+#else
+
+static inline void ar5312_plat_time_init(void) {}
+static inline void ar5312_plat_mem_setup(void) {}
+static inline void ar5312_prom_init(void) {}
+
+#endif
+
+#endif	/* __AR5312_H */
diff --git a/arch/mips/ar231x/board.c b/arch/mips/ar231x/board.c
index 9cde045..0014967 100644
--- a/arch/mips/ar231x/board.c
+++ b/arch/mips/ar231x/board.c
@@ -16,6 +16,8 @@
 #include <asm/bootinfo.h>
 #include <asm/time.h>
 
+#include "ar5312.h"
+
 static void ar231x_halt(void)
 {
 	local_irq_disable();
@@ -28,6 +30,8 @@ void __init plat_mem_setup(void)
 	_machine_halt = ar231x_halt;
 	pm_power_off = ar231x_halt;
 
+	ar5312_plat_mem_setup();
+
 	/* Disable data watchpoints */
 	write_c0_watchlo0(0);
 }
@@ -38,6 +42,7 @@ asmlinkage void plat_irq_dispatch(void)
 
 void __init plat_time_init(void)
 {
+	ar5312_plat_time_init();
 }
 
 unsigned int __cpuinit get_c0_compare_int(void)
diff --git a/arch/mips/ar231x/prom.c b/arch/mips/ar231x/prom.c
index 522357f..d3efdd8 100644
--- a/arch/mips/ar231x/prom.c
+++ b/arch/mips/ar231x/prom.c
@@ -17,8 +17,11 @@
 #include <linux/init.h>
 #include <asm/bootinfo.h>
 
+#include "ar5312.h"
+
 void __init prom_init(void)
 {
+	ar5312_prom_init();
 }
 
 void __init prom_free_prom_memory(void)
diff --git a/arch/mips/include/asm/mach-ar231x/ar5312_regs.h b/arch/mips/include/asm/mach-ar231x/ar5312_regs.h
new file mode 100644
index 0000000..5eb22fd
--- /dev/null
+++ b/arch/mips/include/asm/mach-ar231x/ar5312_regs.h
@@ -0,0 +1,190 @@
+/*
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 2003 Atheros Communications, Inc.,  All Rights Reserved.
+ * Copyright (C) 2006 Imre Kaloz <kaloz@openwrt.org>
+ * Copyright (C) 2006 Felix Fietkau <nbd@openwrt.org>
+ */
+
+#ifndef __ASM_MACH_AR231X_AR5312_REGS_H
+#define __ASM_MACH_AR231X_AR5312_REGS_H
+
+/*
+ * Address Map
+ *
+ * The AR5312 supports 2 enet MACS, even though many reference boards only
+ * actually use 1 of them (i.e. Only MAC 0 is actually connected to an enet
+ * PHY or PHY switch. The AR2312 supports 1 enet MAC.
+ */
+#define AR5312_WLAN0		0x18000000
+#define AR5312_WLAN1		0x18500000
+#define AR5312_ENET0		0x18100000
+#define AR5312_ENET1		0x18200000
+#define AR5312_SDRAMCTL		0x18300000
+#define AR5312_FLASHCTL		0x18400000
+#define AR5312_APBBASE		0x1c000000
+#define AR5312_UART0		0x1c000000	/* UART MMR */
+#define AR5312_FLASH		0x1e000000
+
+/*
+ * Need these defines to determine true number of ethernet MACs
+ */
+#define AR5312_AR5312_REV2	0x0052		/* AR5312 WMAC (AP31) */
+#define AR5312_AR5312_REV7	0x0057		/* AR5312 WMAC (AP30-040) */
+#define AR5312_AR2313_REV8	0x0058		/* AR2313 WMAC (AP43-030) */
+
+/* Reset/Timer Block Address Map */
+#define AR5312_RESETTMR		(AR5312_APBBASE  + 0x3000)
+#define AR5312_TIMER		(AR5312_RESETTMR + 0x0000) /* countdown timer */
+#define AR5312_WD_CTRL		(AR5312_RESETTMR + 0x0008) /* watchdog cntrl */
+#define AR5312_WD_TIMER		(AR5312_RESETTMR + 0x000c) /* watchdog timer */
+#define AR5312_ISR		(AR5312_RESETTMR + 0x0010) /* Intr Status Reg */
+#define AR5312_IMR		(AR5312_RESETTMR + 0x0014) /* Intr Mask Reg */
+#define AR5312_RESET		(AR5312_RESETTMR + 0x0020)
+#define AR5312_CLOCKCTL1	(AR5312_RESETTMR + 0x0064)
+#define AR5312_SCRATCH		(AR5312_RESETTMR + 0x006c)
+#define AR5312_PROCADDR		(AR5312_RESETTMR + 0x0070)
+#define AR5312_PROC1		(AR5312_RESETTMR + 0x0074)
+#define AR5312_DMAADDR		(AR5312_RESETTMR + 0x0078)
+#define AR5312_DMA1		(AR5312_RESETTMR + 0x007c)
+#define AR5312_ENABLE		(AR5312_RESETTMR + 0x0080) /* interface enb */
+#define AR5312_REV		(AR5312_RESETTMR + 0x0090) /* revision */
+
+/* AR5312_WD_CTRL register bit field definitions */
+#define AR5312_WD_CTRL_IGNORE_EXPIRATION	0x0000
+#define AR5312_WD_CTRL_NMI			0x0001
+#define AR5312_WD_CTRL_RESET			0x0002
+
+/* AR5312_ISR register bit field definitions */
+#define AR5312_ISR_TIMER	0x0001
+#define AR5312_ISR_AHBPROC	0x0002
+#define AR5312_ISR_AHBDMA	0x0004
+#define AR5312_ISR_GPIO		0x0008
+#define AR5312_ISR_UART0	0x0010
+#define AR5312_ISR_UART0DMA	0x0020
+#define AR5312_ISR_WD		0x0040
+#define AR5312_ISR_LOCAL	0x0080
+
+/* AR5312_RESET register bit field definitions */
+#define AR5312_RESET_SYSTEM		0x00000001  /* cold reset full system */
+#define AR5312_RESET_PROC		0x00000002  /* cold reset MIPS core */
+#define AR5312_RESET_WLAN0		0x00000004  /* cold reset WLAN MAC/BB */
+#define AR5312_RESET_EPHY0		0x00000008  /* cold reset ENET0 phy */
+#define AR5312_RESET_EPHY1		0x00000010  /* cold reset ENET1 phy */
+#define AR5312_RESET_ENET0		0x00000020  /* cold reset ENET0 MAC */
+#define AR5312_RESET_ENET1		0x00000040  /* cold reset ENET1 MAC */
+#define AR5312_RESET_UART0		0x00000100  /* cold reset UART0 */
+#define AR5312_RESET_WLAN1		0x00000200  /* cold reset WLAN MAC/BB */
+#define AR5312_RESET_APB		0x00000400  /* cold reset APB ar5312 */
+#define AR5312_RESET_WARM_PROC		0x00001000  /* warm reset MIPS core */
+#define AR5312_RESET_WARM_WLAN0_MAC	0x00002000  /* warm reset WLAN0 MAC */
+#define AR5312_RESET_WARM_WLAN0_BB	0x00004000  /* warm reset WLAN0 BB */
+#define AR5312_RESET_NMI		0x00010000  /* send an NMI to the CPU */
+#define AR5312_RESET_WARM_WLAN1_MAC	0x00020000  /* warm reset WLAN1 MAC */
+#define AR5312_RESET_WARM_WLAN1_BB	0x00040000  /* warm reset WLAN1 BB */
+#define AR5312_RESET_LOCAL_BUS		0x00080000  /* reset local bus */
+#define AR5312_RESET_WDOG		0x00100000  /* last reset was a wdt */
+
+#define AR5312_RESET_WMAC0_BITS		(AR5312_RESET_WLAN0 |\
+					 AR5312_RESET_WARM_WLAN0_MAC |\
+					 AR5312_RESET_WARM_WLAN0_BB)
+
+#define AR5312_RESET_WMAC1_BITS		(AR5312_RESET_WLAN1 |\
+					 AR5312_RESET_WARM_WLAN1_MAC |\
+					 AR5312_RESET_WARM_WLAN1_BB)
+
+/* AR5312_CLOCKCTL1 register bit field definitions */
+#define AR5312_CLOCKCTL1_PREDIVIDE_MASK		0x00000030
+#define AR5312_CLOCKCTL1_PREDIVIDE_SHIFT	4
+#define AR5312_CLOCKCTL1_MULTIPLIER_MASK	0x00001f00
+#define AR5312_CLOCKCTL1_MULTIPLIER_SHIFT	8
+#define AR5312_CLOCKCTL1_DOUBLER_MASK		0x00010000
+
+/* Valid for AR5312 and AR2312 */
+#define AR5312_CLOCKCTL1_PREDIVIDE_MASK		0x00000030
+#define AR5312_CLOCKCTL1_PREDIVIDE_SHIFT	4
+#define AR5312_CLOCKCTL1_MULTIPLIER_MASK	0x00001f00
+#define AR5312_CLOCKCTL1_MULTIPLIER_SHIFT	8
+#define AR5312_CLOCKCTL1_DOUBLER_MASK		0x00010000
+
+/* Valid for AR2313 */
+#define AR2313_CLOCKCTL1_PREDIVIDE_MASK		0x00003000
+#define AR2313_CLOCKCTL1_PREDIVIDE_SHIFT	12
+#define AR2313_CLOCKCTL1_MULTIPLIER_MASK	0x001f0000
+#define AR2313_CLOCKCTL1_MULTIPLIER_SHIFT	16
+#define AR2313_CLOCKCTL1_DOUBLER_MASK		0x00000000
+
+/* AR5312_ENABLE register bit field definitions */
+#define AR5312_ENABLE_WLAN0			0x0001
+#define AR5312_ENABLE_ENET0			0x0002
+#define AR5312_ENABLE_ENET1			0x0004
+#define AR5312_ENABLE_UART_AND_WLAN1_PIO	0x0008   /* UART & WLAN1 PIOs */
+#define AR5312_ENABLE_WLAN1_DMA			0x0010   /* WLAN1 DMAs */
+#define AR5312_ENABLE_WLAN1		(AR5312_ENABLE_UART_AND_WLAN1_PIO |\
+					 AR5312_ENABLE_WLAN1_DMA)
+
+/* AR5312_REV register bit field definitions */
+#define AR5312_REV_WMAC_MAJ	0xf000
+#define AR5312_REV_WMAC_MAJ_S	12
+#define AR5312_REV_WMAC_MIN	0x0f00
+#define AR5312_REV_WMAC_MIN_S	8
+#define AR5312_REV_MAJ		0x00f0
+#define AR5312_REV_MAJ_S	4
+#define AR5312_REV_MIN		0x000f
+#define AR5312_REV_MIN_S	0
+#define AR5312_REV_CHIP		(AR5312_REV_MAJ|AR5312_REV_MIN)
+
+/* Major revision numbers, bits 7..4 of Revision ID register */
+#define AR5312_REV_MAJ_AR5312		0x4
+#define AR5312_REV_MAJ_AR2313		0x5
+
+/* Minor revision numbers, bits 3..0 of Revision ID register */
+#define AR5312_REV_MIN_DUAL		0x0	/* Dual WLAN version */
+#define AR5312_REV_MIN_SINGLE		0x1	/* Single WLAN version */
+
+/* AR5312_FLASHCTL register bit field definitions */
+#define AR5312_FLASHCTL_IDCY	0x0000000f	/* Idle cycle turnaround time */
+#define AR5312_FLASHCTL_IDCY_S	0
+#define AR5312_FLASHCTL_WST1	0x000003e0	/* Wait state 1 */
+#define AR5312_FLASHCTL_WST1_S	5
+#define AR5312_FLASHCTL_RBLE	0x00000400	/* Read byte lane enable */
+#define AR5312_FLASHCTL_WST2	0x0000f800	/* Wait state 2 */
+#define AR5312_FLASHCTL_WST2_S	11
+#define AR5312_FLASHCTL_AC	0x00070000	/* Flash addr check (added) */
+#define AR5312_FLASHCTL_AC_S	16
+#define AR5312_FLASHCTL_AC_128K	0x00000000
+#define AR5312_FLASHCTL_AC_256K	0x00010000
+#define AR5312_FLASHCTL_AC_512K	0x00020000
+#define AR5312_FLASHCTL_AC_1M	0x00030000
+#define AR5312_FLASHCTL_AC_2M	0x00040000
+#define AR5312_FLASHCTL_AC_4M	0x00050000
+#define AR5312_FLASHCTL_AC_8M	0x00060000
+#define AR5312_FLASHCTL_AC_RES	0x00070000	/* 16MB is not supported */
+#define AR5312_FLASHCTL_E	0x00080000	/* Flash bank enable (added) */
+#define AR5312_FLASHCTL_BUSERR	0x01000000	/* Bus transfer error flag */
+#define AR5312_FLASHCTL_WPERR	0x02000000	/* Write protect error flag */
+#define AR5312_FLASHCTL_WP	0x04000000	/* Write protect */
+#define AR5312_FLASHCTL_BM	0x08000000	/* Burst mode */
+#define AR5312_FLASHCTL_MW	0x30000000	/* Mem width */
+#define AR5312_FLASHCTL_MW8	0x00000000	/* Mem width x8 */
+#define AR5312_FLASHCTL_MW16	0x10000000	/* Mem width x16 */
+#define AR5312_FLASHCTL_MW32	0x20000000	/* Mem width x32 (not supp) */
+#define AR5312_FLASHCTL_ATNR	0x00000000	/* Access == no retry */
+#define AR5312_FLASHCTL_ATR	0x80000000	/* Access == retry every */
+#define AR5312_FLASHCTL_ATR4	0xc0000000	/* Access == retry every 4 */
+
+/* ARM Flash Controller -- 3 flash banks with either x8 or x16 devices.  */
+#define AR5312_FLASHCTL0	(AR5312_FLASHCTL + 0x00)
+#define AR5312_FLASHCTL1	(AR5312_FLASHCTL + 0x04)
+#define AR5312_FLASHCTL2	(AR5312_FLASHCTL + 0x08)
+
+/* ARM SDRAM Controller -- just enough to determine memory size */
+#define AR5312_MEM_CFG1		(AR5312_SDRAMCTL + 0x04)
+#define AR5312_MEM_CFG1_AC0_M	0x00000700	/* bank 0: SDRAM addr check */
+#define AR5312_MEM_CFG1_AC0_S	8
+#define AR5312_MEM_CFG1_AC1_M	0x00007000	/* bank 1: SDRAM addr check */
+#define AR5312_MEM_CFG1_AC1_S	12
+
+#endif	/* __ASM_MACH_AR231X_AR5312_REGS_H */
-- 
1.8.5.5

^ permalink raw reply related	[flat|nested] 37+ messages in thread

* [PATCH 03/16] MIPS: ar231x: add basic AR2315 SoC support
  2014-09-28 18:32 [PATCH 00/16] MIPS: support for the Atheros AR231X SoCs Sergey Ryazanov
  2014-09-28 18:33 ` [PATCH 01/16] MIPS: ar231x: add common parts Sergey Ryazanov
  2014-09-28 18:33 ` [PATCH 02/16] MIPS: ar231x: add basic AR5312 SoC support Sergey Ryazanov
@ 2014-09-28 18:33 ` Sergey Ryazanov
  2014-09-29  9:50   ` Jonas Gorski
  2014-09-28 18:33 ` [PATCH 04/16] MIPS: ar231x: add interrupts handling routines Sergey Ryazanov
                   ` (12 subsequent siblings)
  15 siblings, 1 reply; 37+ messages in thread
From: Sergey Ryazanov @ 2014-09-28 18:33 UTC (permalink / raw)
  To: Ralf Baechle; +Cc: Linux MIPS

Add basic support for Atheros AR2315+ SoCs: registers definition file
and initial setup code.

Signed-off-by: Sergey Ryazanov <ryazanov.s.a@gmail.com>
---
 arch/mips/ar231x/Kconfig                           |   5 +
 arch/mips/ar231x/Makefile                          |   1 +
 arch/mips/ar231x/ar2315.c                          | 136 ++++++
 arch/mips/ar231x/ar2315.h                          |  18 +
 arch/mips/ar231x/board.c                           |   3 +
 arch/mips/ar231x/prom.c                            |   2 +
 arch/mips/include/asm/mach-ar231x/ar2315_regs.h    | 529 +++++++++++++++++++++
 .../asm/mach-ar231x/cpu-feature-overrides.h        |  10 +-
 8 files changed, 703 insertions(+), 1 deletion(-)
 create mode 100644 arch/mips/ar231x/ar2315.c
 create mode 100644 arch/mips/ar231x/ar2315.h
 create mode 100644 arch/mips/include/asm/mach-ar231x/ar2315_regs.h

diff --git a/arch/mips/ar231x/Kconfig b/arch/mips/ar231x/Kconfig
index 7634a64..aa0fceb 100644
--- a/arch/mips/ar231x/Kconfig
+++ b/arch/mips/ar231x/Kconfig
@@ -2,3 +2,8 @@ config SOC_AR5312
 	bool "Atheros AR5312/AR2312+ SoC support"
 	depends on AR231X
 	default y
+
+config SOC_AR2315
+	bool "Atheros AR2315+ SoC support"
+	depends on AR231X
+	default y
diff --git a/arch/mips/ar231x/Makefile b/arch/mips/ar231x/Makefile
index 3361619..201b7d4 100644
--- a/arch/mips/ar231x/Makefile
+++ b/arch/mips/ar231x/Makefile
@@ -11,3 +11,4 @@
 obj-y += board.o prom.o devices.o
 
 obj-$(CONFIG_SOC_AR5312) += ar5312.o
+obj-$(CONFIG_SOC_AR2315) += ar2315.o
diff --git a/arch/mips/ar231x/ar2315.c b/arch/mips/ar231x/ar2315.c
new file mode 100644
index 0000000..5f8b7c4
--- /dev/null
+++ b/arch/mips/ar231x/ar2315.c
@@ -0,0 +1,136 @@
+/*
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 2003 Atheros Communications, Inc.,  All Rights Reserved.
+ * Copyright (C) 2006 FON Technology, SL.
+ * Copyright (C) 2006 Imre Kaloz <kaloz@openwrt.org>
+ * Copyright (C) 2006 Felix Fietkau <nbd@openwrt.org>
+ * Copyright (C) 2012 Alexandros C. Couloumbis <alex@ozo.com>
+ */
+
+/*
+ * Platform devices for Atheros AR2315 SoCs
+ */
+
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/reboot.h>
+#include <asm/bootinfo.h>
+#include <asm/reboot.h>
+#include <asm/time.h>
+
+#include <ar2315_regs.h>
+#include <ar231x.h>
+
+#include "devices.h"
+#include "ar2315.h"
+
+static void ar2315_restart(char *command)
+{
+	void (*mips_reset_vec)(void) = (void *)0xbfc00000;
+
+	local_irq_disable();
+
+	/* try reset the system via reset control */
+	ar231x_write_reg(AR2315_COLD_RESET, AR2317_RESET_SYSTEM);
+
+	/* Attempt to jump to the mips reset location - the boot loader
+	 * itself might be able to recover the system */
+	mips_reset_vec();
+}
+
+/*
+ * This table is indexed by bits 5..4 of the CLOCKCTL1 register
+ * to determine the predevisor value.
+ */
+static int clockctl1_predivide_table[4] __initdata = { 1, 2, 4, 5 };
+static int pllc_divide_table[5] __initdata = { 2, 3, 4, 6, 3 };
+
+static unsigned __init ar2315_sys_clk(u32 clock_ctl)
+{
+	unsigned int pllc_ctrl, cpu_div;
+	unsigned int pllc_out, refdiv, fdiv, divby2;
+	unsigned int clk_div;
+
+	pllc_ctrl = ar231x_read_reg(AR2315_PLLC_CTL);
+	refdiv = AR231X_REG_MS(pllc_ctrl, AR2315_PLLC_REF_DIV);
+	refdiv = clockctl1_predivide_table[refdiv];
+	fdiv = AR231X_REG_MS(pllc_ctrl, AR2315_PLLC_FDBACK_DIV);
+	divby2 = AR231X_REG_MS(pllc_ctrl, AR2315_PLLC_ADD_FDBACK_DIV) + 1;
+	pllc_out = (40000000 / refdiv) * (2 * divby2) * fdiv;
+
+	/* clkm input selected */
+	switch (clock_ctl & AR2315_CPUCLK_CLK_SEL_M) {
+	case 0:
+	case 1:
+		clk_div = AR231X_REG_MS(pllc_ctrl, AR2315_PLLC_CLKM_DIV);
+		clk_div = pllc_divide_table[clk_div];
+		break;
+	case 2:
+		clk_div = AR231X_REG_MS(pllc_ctrl, AR2315_PLLC_CLKC_DIV);
+		clk_div = pllc_divide_table[clk_div];
+		break;
+	default:
+		pllc_out = 40000000;
+		clk_div = 1;
+		break;
+	}
+
+	cpu_div = AR231X_REG_MS(clock_ctl, AR2315_CPUCLK_CLK_DIV);
+	cpu_div = cpu_div * 2 ?: 1;
+
+	return pllc_out / (clk_div * cpu_div);
+}
+
+static inline unsigned ar2315_cpu_frequency(void)
+{
+	return ar2315_sys_clk(ar231x_read_reg(AR2315_CPUCLK));
+}
+
+static inline unsigned ar2315_apb_frequency(void)
+{
+	return ar2315_sys_clk(ar231x_read_reg(AR2315_AMBACLK));
+}
+
+void __init ar2315_plat_time_init(void)
+{
+	if (!is_2315())
+		return;
+
+	mips_hpt_frequency = ar2315_cpu_frequency() / 2;
+}
+
+void __init ar2315_plat_mem_setup(void)
+{
+	u32 config;
+
+	if (!is_2315())
+		return;
+
+	/* Clear any lingering AHB errors */
+	config = read_c0_config();
+	write_c0_config(config & ~0x3);
+	ar231x_write_reg(AR2315_AHB_ERR0, AR2315_AHB_ERROR_DET);
+	ar231x_read_reg(AR2315_AHB_ERR1);
+	ar231x_write_reg(AR2315_WDC, AR2315_WDC_IGNORE_EXPIRATION);
+
+	_machine_restart = ar2315_restart;
+}
+
+void __init ar2315_prom_init(void)
+{
+	u32 memsize, memcfg;
+
+	if (!is_2315())
+		return;
+
+	memcfg = ar231x_read_reg(AR2315_MEM_CFG);
+	memsize   = 1 + AR231X_REG_MS(memcfg, AR2315_MEM_CFG_DATA_WIDTH);
+	memsize <<= 1 + AR231X_REG_MS(memcfg, AR2315_MEM_CFG_COL_WIDTH);
+	memsize <<= 1 + AR231X_REG_MS(memcfg, AR2315_MEM_CFG_ROW_WIDTH);
+	memsize <<= 3;
+	add_memory_region(0, memsize, BOOT_MEM_RAM);
+}
+
diff --git a/arch/mips/ar231x/ar2315.h b/arch/mips/ar231x/ar2315.h
new file mode 100644
index 0000000..98d32b2
--- /dev/null
+++ b/arch/mips/ar231x/ar2315.h
@@ -0,0 +1,18 @@
+#ifndef __AR2315_H
+#define __AR2315_H
+
+#ifdef CONFIG_SOC_AR2315
+
+void ar2315_plat_time_init(void);
+void ar2315_plat_mem_setup(void);
+void ar2315_prom_init(void);
+
+#else
+
+static inline void ar2315_plat_time_init(void) {}
+static inline void ar2315_plat_mem_setup(void) {}
+static inline void ar2315_prom_init(void) {}
+
+#endif
+
+#endif	/* __AR2315_H */
diff --git a/arch/mips/ar231x/board.c b/arch/mips/ar231x/board.c
index 0014967..f50a7cf 100644
--- a/arch/mips/ar231x/board.c
+++ b/arch/mips/ar231x/board.c
@@ -17,6 +17,7 @@
 #include <asm/time.h>
 
 #include "ar5312.h"
+#include "ar2315.h"
 
 static void ar231x_halt(void)
 {
@@ -31,6 +32,7 @@ void __init plat_mem_setup(void)
 	pm_power_off = ar231x_halt;
 
 	ar5312_plat_mem_setup();
+	ar2315_plat_mem_setup();
 
 	/* Disable data watchpoints */
 	write_c0_watchlo0(0);
@@ -43,6 +45,7 @@ asmlinkage void plat_irq_dispatch(void)
 void __init plat_time_init(void)
 {
 	ar5312_plat_time_init();
+	ar2315_plat_time_init();
 }
 
 unsigned int __cpuinit get_c0_compare_int(void)
diff --git a/arch/mips/ar231x/prom.c b/arch/mips/ar231x/prom.c
index d3efdd8..d8a2c23 100644
--- a/arch/mips/ar231x/prom.c
+++ b/arch/mips/ar231x/prom.c
@@ -18,10 +18,12 @@
 #include <asm/bootinfo.h>
 
 #include "ar5312.h"
+#include "ar2315.h"
 
 void __init prom_init(void)
 {
 	ar5312_prom_init();
+	ar2315_prom_init();
 }
 
 void __init prom_free_prom_memory(void)
diff --git a/arch/mips/include/asm/mach-ar231x/ar2315_regs.h b/arch/mips/include/asm/mach-ar231x/ar2315_regs.h
new file mode 100644
index 0000000..91197b6
--- /dev/null
+++ b/arch/mips/include/asm/mach-ar231x/ar2315_regs.h
@@ -0,0 +1,529 @@
+/*
+ * Register definitions for AR2315+
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 2003 Atheros Communications, Inc.,  All Rights Reserved.
+ * Copyright (C) 2006 FON Technology, SL.
+ * Copyright (C) 2006 Imre Kaloz <kaloz@openwrt.org>
+ * Copyright (C) 2006-2008 Felix Fietkau <nbd@openwrt.org>
+ */
+
+#ifndef __ASM_MACH_AR231X_AR2315_REGS_H
+#define __ASM_MACH_AR231X_AR2315_REGS_H
+
+/*
+ * Address map
+ */
+#define AR2315_SPI_READ		0x08000000	/* SPI flash */
+#define AR2315_WLAN0		0x10000000	/* Wireless MMR */
+#define AR2315_PCI		0x10100000	/* PCI MMR */
+#define AR2315_SDRAMCTL		0x10300000	/* SDRAM MMR */
+#define AR2315_LOCAL		0x10400000	/* Local bus MMR */
+#define AR2315_ENET0		0x10500000	/* Ethernet MMR */
+#define AR2315_DSLBASE		0x11000000	/* Reset control MMR */
+#define AR2315_UART0		0x11100000	/* UART MMR */
+#define AR2315_SPI_MMR		0x11300000	/* SPI flash MMR */
+#define AR2315_PCIEXT		0x80000000	/* PCI external */
+#define AR2315_PCIEXT_SZ	0x40000000
+
+/*
+ * Cold reset register
+ */
+#define AR2315_COLD_RESET		(AR2315_DSLBASE + 0x0000)
+
+#define AR2315_RESET_COLD_AHB		0x00000001
+#define AR2315_RESET_COLD_APB		0x00000002
+#define AR2315_RESET_COLD_CPU		0x00000004
+#define AR2315_RESET_COLD_CPUWARM	0x00000008
+#define AR2315_RESET_SYSTEM		(RESET_COLD_CPU |\
+					 RESET_COLD_APB |\
+					 RESET_COLD_AHB)  /* full system */
+#define AR2317_RESET_SYSTEM		0x00000010
+
+/*
+ * Reset register
+ */
+#define AR2315_RESET			(AR2315_DSLBASE + 0x0004)
+
+#define AR2315_RESET_WARM_WLAN0_MAC	0x00000001  /* warm reset WLAN0 MAC */
+#define AR2315_RESET_WARM_WLAN0_BB	0x00000002  /* warm reset WLAN0 BB */
+#define AR2315_RESET_MPEGTS_RSVD	0x00000004  /* warm reset MPEG-TS */
+#define AR2315_RESET_PCIDMA		0x00000008  /* warm reset PCI ahb/dma */
+#define AR2315_RESET_MEMCTL		0x00000010  /* warm reset mem control */
+#define AR2315_RESET_LOCAL		0x00000020  /* warm reset local bus */
+#define AR2315_RESET_I2C_RSVD		0x00000040  /* warm reset I2C bus */
+#define AR2315_RESET_SPI		0x00000080  /* warm reset SPI iface */
+#define AR2315_RESET_UART0		0x00000100  /* warm reset UART0 */
+#define AR2315_RESET_IR_RSVD		0x00000200  /* warm reset IR iface */
+#define AR2315_RESET_EPHY0		0x00000400  /* cold reset ENET0 phy */
+#define AR2315_RESET_ENET0		0x00000800  /* cold reset ENET0 MAC */
+
+/*
+ * AHB master arbitration control
+ */
+#define AR2315_AHB_ARB_CTL		(AR2315_DSLBASE + 0x0008)
+
+#define AR2315_ARB_CPU			0x00000001  /* CPU, default */
+#define AR2315_ARB_WLAN			0x00000002  /* WLAN */
+#define AR2315_ARB_MPEGTS_RSVD		0x00000004  /* MPEG-TS */
+#define AR2315_ARB_LOCAL		0x00000008  /* Local bus */
+#define AR2315_ARB_PCI			0x00000010  /* PCI bus */
+#define AR2315_ARB_ETHERNET		0x00000020  /* Ethernet */
+#define AR2315_ARB_RETRY		0x00000100  /* Retry policy (debug) */
+
+/*
+ * Config Register
+ */
+#define AR2315_ENDIAN_CTL		(AR2315_DSLBASE + 0x000c)
+
+#define AR2315_CONFIG_AHB		0x00000001  /* EC-AHB bridge endian */
+#define AR2315_CONFIG_WLAN		0x00000002  /* WLAN byteswap */
+#define AR2315_CONFIG_MPEGTS_RSVD	0x00000004  /* MPEG-TS byteswap */
+#define AR2315_CONFIG_PCI		0x00000008  /* PCI byteswap */
+#define AR2315_CONFIG_MEMCTL		0x00000010  /* Mem controller endian */
+#define AR2315_CONFIG_LOCAL		0x00000020  /* Local bus byteswap */
+#define AR2315_CONFIG_ETHERNET		0x00000040  /* Ethernet byteswap */
+#define AR2315_CONFIG_MERGE		0x00000200  /* CPU write buffer merge */
+#define AR2315_CONFIG_CPU		0x00000400  /* CPU big endian */
+#define AR2315_CONFIG_BIG		0x00000400
+#define AR2315_CONFIG_PCIAHB		0x00000800
+#define AR2315_CONFIG_PCIAHB_BRIDGE	0x00001000
+#define AR2315_CONFIG_SPI		0x00008000  /* SPI byteswap */
+#define AR2315_CONFIG_CPU_DRAM		0x00010000
+#define AR2315_CONFIG_CPU_PCI		0x00020000
+#define AR2315_CONFIG_CPU_MMR		0x00040000
+
+/*
+ * NMI control
+ */
+#define AR2315_NMI_CTL			(AR2315_DSLBASE + 0x0010)
+
+#define AR2315_NMI_EN			1
+
+/*
+ * Revision Register - Initial value is 0x3010 (WMAC 3.0, AR231X 1.0).
+ */
+#define AR2315_SREV			(AR2315_DSLBASE + 0x0014)
+
+#define AR2315_REV_MAJ			0x00f0
+#define AR2315_REV_MAJ_S		4
+#define AR2315_REV_MIN			0x000f
+#define AR2315_REV_MIN_S		0
+#define AR2315_REV_CHIP			(AR2315_REV_MAJ | AR2315_REV_MIN)
+
+/*
+ * Interface Enable
+ */
+#define AR2315_IF_CTL			(AR2315_DSLBASE + 0x0018)
+
+#define AR2315_IF_MASK			0x00000007
+#define AR2315_IF_DISABLED		0		/* Disable all */
+#define AR2315_IF_PCI			1		/* PCI */
+#define AR2315_IF_TS_LOCAL		2		/* Local bus */
+#define AR2315_IF_ALL			3		/* Emulation only */
+#define AR2315_IF_LOCAL_HOST		0x00000008
+#define AR2315_IF_PCI_HOST		0x00000010
+#define AR2315_IF_PCI_INTR		0x00000020
+#define AR2315_IF_PCI_CLK_MASK		0x00030000
+#define AR2315_IF_PCI_CLK_INPUT		0
+#define AR2315_IF_PCI_CLK_OUTPUT_LOW	1
+#define AR2315_IF_PCI_CLK_OUTPUT_CLK	2
+#define AR2315_IF_PCI_CLK_OUTPUT_HIGH	3
+#define AR2315_IF_PCI_CLK_SHIFT		16
+
+/*
+ * APB Interrupt control
+ */
+
+#define AR2315_ISR			(AR2315_DSLBASE + 0x0020)
+#define AR2315_IMR			(AR2315_DSLBASE + 0x0024)
+#define AR2315_GISR			(AR2315_DSLBASE + 0x0028)
+
+#define AR2315_ISR_UART0	0x0001		/* high speed UART */
+#define AR2315_ISR_I2C_RSVD	0x0002		/* I2C bus */
+#define AR2315_ISR_SPI		0x0004		/* SPI bus */
+#define AR2315_ISR_AHB		0x0008		/* AHB error */
+#define AR2315_ISR_APB		0x0010		/* APB error */
+#define AR2315_ISR_TIMER	0x0020		/* Timer */
+#define AR2315_ISR_GPIO		0x0040		/* GPIO */
+#define AR2315_ISR_WD		0x0080		/* Watchdog */
+#define AR2315_ISR_IR_RSVD	0x0100		/* IR */
+
+#define AR2315_GISR_MISC	0x0001		/* Misc */
+#define AR2315_GISR_WLAN0	0x0002		/* WLAN0 */
+#define AR2315_GISR_MPEGTS_RSVD	0x0004		/* MPEG-TS */
+#define AR2315_GISR_LOCALPCI	0x0008		/* Local/PCI bus */
+#define AR2315_GISR_WMACPOLL	0x0010
+#define AR2315_GISR_TIMER	0x0020
+#define AR2315_GISR_ETHERNET	0x0040		/* Ethernet */
+
+/*
+ * Timers
+ */
+#define AR2315_TIMER			(AR2315_DSLBASE + 0x0030)
+#define AR2315_RELOAD			(AR2315_DSLBASE + 0x0034)
+#define AR2315_WD			(AR2315_DSLBASE + 0x0038)
+#define AR2315_WDC			(AR2315_DSLBASE + 0x003c)
+
+#define AR2315_WDC_IGNORE_EXPIRATION	0x00000000
+#define AR2315_WDC_NMI			0x00000001	/* NMI on watchdog */
+#define AR2315_WDC_RESET		0x00000002	/* reset on watchdog */
+
+/*
+ * CPU Performance Counters
+ */
+#define AR2315_PERFCNT0			(AR2315_DSLBASE + 0x0048)
+#define AR2315_PERFCNT1			(AR2315_DSLBASE + 0x004c)
+
+#define AR2315_PERF0_DATAHIT	0x0001  /* Count Data Cache Hits */
+#define AR2315_PERF0_DATAMISS	0x0002  /* Count Data Cache Misses */
+#define AR2315_PERF0_INSTHIT	0x0004  /* Count Instruction Cache Hits */
+#define AR2315_PERF0_INSTMISS	0x0008  /* Count Instruction Cache Misses */
+#define AR2315_PERF0_ACTIVE	0x0010  /* Count Active Processor Cycles */
+#define AR2315_PERF0_WBHIT	0x0020  /* Count CPU Write Buffer Hits */
+#define AR2315_PERF0_WBMISS	0x0040  /* Count CPU Write Buffer Misses */
+
+#define AR2315_PERF1_EB_ARDY	0x0001  /* Count EB_ARdy signal */
+#define AR2315_PERF1_EB_AVALID	0x0002  /* Count EB_AValid signal */
+#define AR2315_PERF1_EB_WDRDY	0x0004  /* Count EB_WDRdy signal */
+#define AR2315_PERF1_EB_RDVAL	0x0008  /* Count EB_RdVal signal */
+#define AR2315_PERF1_VRADDR	0x0010  /* Count valid read address cycles */
+#define AR2315_PERF1_VWADDR	0x0020  /* Count valid write address cycles */
+#define AR2315_PERF1_VWDATA	0x0040  /* Count valid write data cycles */
+
+/*
+ * AHB Error Reporting.
+ */
+#define AR2315_AHB_ERR0			(AR2315_DSLBASE + 0x0050)  /* error  */
+#define AR2315_AHB_ERR1			(AR2315_DSLBASE + 0x0054)  /* haddr  */
+#define AR2315_AHB_ERR2			(AR2315_DSLBASE + 0x0058)  /* hwdata */
+#define AR2315_AHB_ERR3			(AR2315_DSLBASE + 0x005c)  /* hrdata */
+#define AR2315_AHB_ERR4			(AR2315_DSLBASE + 0x0060)  /* status */
+
+#define AR2315_AHB_ERROR_DET	1 /* AHB Error has been detected,          */
+				  /* write 1 to clear all bits in ERR0     */
+#define AR2315_AHB_ERROR_OVR	2 /* AHB Error overflow has been detected  */
+#define AR2315_AHB_ERROR_WDT	4 /* AHB Error due to wdt instead of hresp */
+
+#define AR2315_PROCERR_HMAST		0x0000000f
+#define AR2315_PROCERR_HMAST_DFLT	0
+#define AR2315_PROCERR_HMAST_WMAC	1
+#define AR2315_PROCERR_HMAST_ENET	2
+#define AR2315_PROCERR_HMAST_PCIENDPT	3
+#define AR2315_PROCERR_HMAST_LOCAL	4
+#define AR2315_PROCERR_HMAST_CPU	5
+#define AR2315_PROCERR_HMAST_PCITGT	6
+#define AR2315_PROCERR_HMAST_S		0
+#define AR2315_PROCERR_HWRITE		0x00000010
+#define AR2315_PROCERR_HSIZE		0x00000060
+#define AR2315_PROCERR_HSIZE_S		5
+#define AR2315_PROCERR_HTRANS		0x00000180
+#define AR2315_PROCERR_HTRANS_S		7
+#define AR2315_PROCERR_HBURST		0x00000e00
+#define AR2315_PROCERR_HBURST_S		9
+
+/*
+ * Clock Control
+ */
+#define AR2315_PLLC_CTL			(AR2315_DSLBASE + 0x0064)
+#define AR2315_PLLV_CTL			(AR2315_DSLBASE + 0x0068)
+#define AR2315_CPUCLK			(AR2315_DSLBASE + 0x006c)
+#define AR2315_AMBACLK			(AR2315_DSLBASE + 0x0070)
+#define AR2315_SYNCCLK			(AR2315_DSLBASE + 0x0074)
+#define AR2315_DSL_SLEEP_CTL		(AR2315_DSLBASE + 0x0080)
+#define AR2315_DSL_SLEEP_DUR		(AR2315_DSLBASE + 0x0084)
+
+/* PLLc Control fields */
+#define AR2315_PLLC_REF_DIV_M		0x00000003
+#define AR2315_PLLC_REF_DIV_S		0
+#define AR2315_PLLC_FDBACK_DIV_M	0x0000007C
+#define AR2315_PLLC_FDBACK_DIV_S	2
+#define AR2315_PLLC_ADD_FDBACK_DIV_M	0x00000080
+#define AR2315_PLLC_ADD_FDBACK_DIV_S	7
+#define AR2315_PLLC_CLKC_DIV_M		0x0001c000
+#define AR2315_PLLC_CLKC_DIV_S		14
+#define AR2315_PLLC_CLKM_DIV_M		0x00700000
+#define AR2315_PLLC_CLKM_DIV_S		20
+
+/* CPU CLK Control fields */
+#define AR2315_CPUCLK_CLK_SEL_M		0x00000003
+#define AR2315_CPUCLK_CLK_SEL_S		0
+#define AR2315_CPUCLK_CLK_DIV_M		0x0000000c
+#define AR2315_CPUCLK_CLK_DIV_S		2
+
+/* AMBA CLK Control fields */
+#define AR2315_AMBACLK_CLK_SEL_M	0x00000003
+#define AR2315_AMBACLK_CLK_SEL_S	0
+#define AR2315_AMBACLK_CLK_DIV_M	0x0000000c
+#define AR2315_AMBACLK_CLK_DIV_S	2
+
+/*
+ *  PCI Clock Control
+ */
+#define AR2315_PCICLK			(AR2315_DSLBASE + 0x00a4)
+
+#define AR2315_PCICLK_INPUT_M		0x3
+#define AR2315_PCICLK_INPUT_S		0
+#define AR2315_PCICLK_PLLC_CLKM		0
+#define AR2315_PCICLK_PLLC_CLKM1	1
+#define AR2315_PCICLK_PLLC_CLKC		2
+#define AR2315_PCICLK_REF_CLK		3
+#define AR2315_PCICLK_DIV_M		0xc
+#define AR2315_PCICLK_DIV_S		2
+#define AR2315_PCICLK_IN_FREQ		0
+#define AR2315_PCICLK_IN_FREQ_DIV_6	1
+#define AR2315_PCICLK_IN_FREQ_DIV_8	2
+#define AR2315_PCICLK_IN_FREQ_DIV_10	3
+
+/*
+ * Observation Control Register
+ */
+#define AR2315_OCR			(AR2315_DSLBASE + 0x00b0)
+
+#define AR2315_OCR_GPIO0_IRIN		0x0040
+#define AR2315_OCR_GPIO1_IROUT		0x0080
+#define AR2315_OCR_GPIO3_RXCLR		0x0200
+
+/*
+ *  General Clock Control
+ */
+
+#define AR2315_MISCCLK			(AR2315_DSLBASE + 0x00b4)
+
+#define AR2315_MISCCLK_PLLBYPASS_EN	0x00000001
+#define AR2315_MISCCLK_PROCREFCLK	0x00000002
+
+/*
+ * SDRAM Controller
+ *   - No read or write buffers are included.
+ */
+#define AR2315_MEM_CFG			(AR2315_SDRAMCTL + 0x00)
+#define AR2315_MEM_CTRL			(AR2315_SDRAMCTL + 0x0c)
+#define AR2315_MEM_REF			(AR2315_SDRAMCTL + 0x10)
+
+#define AR2315_MEM_CFG_DATA_WIDTH_M	0x00006000
+#define AR2315_MEM_CFG_DATA_WIDTH_S	13
+#define AR2315_MEM_CFG_COL_WIDTH_M	0x00001E00
+#define AR2315_MEM_CFG_COL_WIDTH_S	9
+#define AR2315_MEM_CFG_ROW_WIDTH_M	0x000001E0
+#define AR2315_MEM_CFG_ROW_WIDTH_S	5
+#define AR2315_MEM_CFG_BANKADDR_BITS_M	0x00000018
+#define AR2315_MEM_CFG_BANKADDR_BITS_S	3
+
+/*
+ * PCI Bus Interface Registers
+ */
+#define AR2315_PCI_1MS_REG		(AR2315_PCI + 0x0008)
+
+#define AR2315_PCI_1MS_MASK		0x3FFFF	/* # of AHB clk cycles in 1ms */
+
+#define AR2315_PCI_MISC_CONFIG		(AR2315_PCI + 0x000c)
+
+#define AR2315_PCIMISC_TXD_EN	0x00000001	/* Enable TXD for fragments */
+#define AR2315_PCIMISC_CFG_SEL	0x00000002	/* Mem or Config cycles */
+#define AR2315_PCIMISC_GIG_MASK	0x0000000C	/* bits 31-30 for pci req */
+#define AR2315_PCIMISC_RST_MODE	0x00000030
+#define AR2315_PCIRST_INPUT	0x00000000	/* 4:5=0 rst is input */
+#define AR2315_PCIRST_LOW	0x00000010	/* 4:5=1 rst to GND */
+#define AR2315_PCIRST_HIGH	0x00000020	/* 4:5=2 rst to VDD */
+#define AR2315_PCIGRANT_EN	0x00000000	/* 6:7=0 early grant en */
+#define AR2315_PCIGRANT_FRAME	0x00000040	/* 6:7=1 grant waits 4 frame */
+#define AR2315_PCIGRANT_IDLE	0x00000080	/* 6:7=2 grant waits 4 idle */
+#define AR2315_PCIGRANT_GAP	0x00000000	/* 6:7=2 grant waits 4 idle */
+#define AR2315_PCICACHE_DIS	0x00001000	/* PCI external access cache
+						 * disable */
+
+#define AR2315_PCI_OUT_TSTAMP		(AR2315_PCI + 0x0010)
+
+#define AR2315_PCI_UNCACHE_CFG		(AR2315_PCI + 0x0014)
+
+#define AR2315_PCI_IN_EN		(AR2315_PCI + 0x0100)
+
+#define AR2315_PCI_IN_EN0	0x01	/* Enable chain 0 */
+#define AR2315_PCI_IN_EN1	0x02	/* Enable chain 1 */
+#define AR2315_PCI_IN_EN2	0x04	/* Enable chain 2 */
+#define AR2315_PCI_IN_EN3	0x08	/* Enable chain 3 */
+
+#define AR2315_PCI_IN_DIS		(AR2315_PCI + 0x0104)
+
+#define AR2315_PCI_IN_DIS0	0x01	/* Disable chain 0 */
+#define AR2315_PCI_IN_DIS1	0x02	/* Disable chain 1 */
+#define AR2315_PCI_IN_DIS2	0x04	/* Disable chain 2 */
+#define AR2315_PCI_IN_DIS3	0x08	/* Disable chain 3 */
+
+#define AR2315_PCI_IN_PTR		(AR2315_PCI + 0x0200)
+
+#define AR2315_PCI_OUT_EN		(AR2315_PCI + 0x0400)
+
+#define AR2315_PCI_OUT_EN0	0x01	/* Enable chain 0 */
+
+#define AR2315_PCI_OUT_DIS		(AR2315_PCI + 0x0404)
+
+#define AR2315_PCI_OUT_DIS0	0x01	/* Disable chain 0 */
+
+#define AR2315_PCI_OUT_PTR		(AR2315_PCI + 0x0408)
+
+/*
+ * PCI interrupt status
+ * Write one to clear
+ */
+#define AR2315_PCI_ISR			(AR2315_PCI + 0x0500)
+
+#define AR2315_PCI_INT_TX	0x00000001	/* Desc In Completed */
+#define AR2315_PCI_INT_TXOK	0x00000002	/* Desc In OK */
+#define AR2315_PCI_INT_TXERR	0x00000004	/* Desc In ERR */
+#define AR2315_PCI_INT_TXEOL	0x00000008	/* Desc In End-of-List */
+#define AR2315_PCI_INT_RX	0x00000010	/* Desc Out Completed */
+#define AR2315_PCI_INT_RXOK	0x00000020	/* Desc Out OK */
+#define AR2315_PCI_INT_RXERR	0x00000040	/* Desc Out ERR */
+#define AR2315_PCI_INT_RXEOL	0x00000080	/* Desc Out EOL */
+#define AR2315_PCI_INT_TXOOD	0x00000200	/* Desc In Out-of-Desc */
+#define AR2315_PCI_INT_DESCMASK	0x0000FFFF	/* Desc Mask */
+#define AR2315_PCI_INT_EXT	0x02000000	/* Extern PCI INTA */
+#define AR2315_PCI_INT_ABORT	0x04000000	/* PCI bus abort event */
+
+/* PCI interrupt mask */
+#define AR2315_PCI_IMR			(AR2315_PCI + 0x0504)
+
+/* Global PCI interrupt enable */
+#define AR2315_PCI_IER			(AR2315_PCI + 0x0508)
+
+#define AR2315_PCI_IER_DISABLE		0x00	/* disable pci interrupts */
+#define AR2315_PCI_IER_ENABLE		0x01	/* enable pci interrupts */
+
+#define AR2315_PCI_HOST_IN_EN		(AR2315_PCI + 0x0800)
+#define AR2315_PCI_HOST_IN_DIS		(AR2315_PCI + 0x0804)
+#define AR2315_PCI_HOST_IN_PTR		(AR2315_PCI + 0x0810)
+#define AR2315_PCI_HOST_OUT_EN		(AR2315_PCI + 0x0900)
+#define AR2315_PCI_HOST_OUT_DIS		(AR2315_PCI + 0x0904)
+#define AR2315_PCI_HOST_OUT_PTR		(AR2315_PCI + 0x0908)
+
+/*
+ * Local Bus Interface Registers
+ */
+#define AR2315_LB_CONFIG		(AR2315_LOCAL + 0x0000)
+
+#define AR2315_LBCONF_OE	0x00000001	/* =1 OE is low-true */
+#define AR2315_LBCONF_CS0	0x00000002	/* =1 first CS is low-true */
+#define AR2315_LBCONF_CS1	0x00000004	/* =1 2nd CS is low-true */
+#define AR2315_LBCONF_RDY	0x00000008	/* =1 RDY is low-true */
+#define AR2315_LBCONF_WE	0x00000010	/* =1 Write En is low-true */
+#define AR2315_LBCONF_WAIT	0x00000020	/* =1 WAIT is low-true */
+#define AR2315_LBCONF_ADS	0x00000040	/* =1 Adr Strobe is low-true */
+#define AR2315_LBCONF_MOT	0x00000080	/* =0 Intel, =1 Motorola */
+#define AR2315_LBCONF_8CS	0x00000100	/* =1 8 bits CS, 0= 16bits */
+#define AR2315_LBCONF_8DS	0x00000200	/* =1 8 bits Data S, 0=16bits */
+#define AR2315_LBCONF_ADS_EN	0x00000400	/* =1 Enable ADS */
+#define AR2315_LBCONF_ADR_OE	0x00000800	/* =1 Adr cap on OE, WE or DS */
+#define AR2315_LBCONF_ADDT_MUX	0x00001000	/* =1 Adr and Data share bus */
+#define AR2315_LBCONF_DATA_OE	0x00002000	/* =1 Data cap on OE, WE, DS */
+#define AR2315_LBCONF_16DATA	0x00004000	/* =1 Data is 16 bits wide */
+#define AR2315_LBCONF_SWAPDT	0x00008000	/* =1 Byte swap data */
+#define AR2315_LBCONF_SYNC	0x00010000	/* =1 Bus synchronous to clk */
+#define AR2315_LBCONF_INT	0x00020000	/* =1 Intr is low true */
+#define AR2315_LBCONF_INT_CTR0	0x00000000	/* GND high-Z, Vdd is high-Z */
+#define AR2315_LBCONF_INT_CTR1	0x00040000	/* GND drive, Vdd is high-Z */
+#define AR2315_LBCONF_INT_CTR2	0x00080000	/* GND high-Z, Vdd drive */
+#define AR2315_LBCONF_INT_CTR3	0x000C0000	/* GND drive, Vdd drive */
+#define AR2315_LBCONF_RDY_WAIT	0x00100000	/* =1 RDY is negative of WAIT */
+#define AR2315_LBCONF_INT_PULSE	0x00200000	/* =1 Interrupt is a pulse */
+#define AR2315_LBCONF_ENABLE	0x00400000	/* =1 Falcon respond to LB */
+
+#define AR2315_LB_CLKSEL		(AR2315_LOCAL + 0x0004)
+
+#define AR2315_LBCLK_EXT	0x0001		/* use external clk for lb */
+
+#define AR2315_LB_1MS			(AR2315_LOCAL + 0x0008)
+
+#define AR2315_LB1MS_MASK	0x3FFFF		/* # of AHB clk cycles in 1ms */
+
+#define AR2315_LB_MISCCFG		(AR2315_LOCAL + 0x000C)
+
+#define AR2315_LBM_TXD_EN	0x00000001	/* Enable TXD for fragments */
+#define AR2315_LBM_RX_INTEN	0x00000002	/* Enable LB ints on RX ready */
+#define AR2315_LBM_MBOXWR_INTEN	0x00000004	/* Enable LB ints on mbox wr */
+#define AR2315_LBM_MBOXRD_INTEN	0x00000008	/* Enable LB ints on mbox rd */
+#define AR2315_LMB_DESCSWAP_EN	0x00000010	/* Byte swap desc enable */
+#define AR2315_LBM_TIMEOUT_M	0x00FFFF80
+#define AR2315_LBM_TIMEOUT_S	7
+#define AR2315_LBM_PORTMUX	0x07000000
+
+#define AR2315_LB_RXTSOFF		(AR2315_LOCAL + 0x0010)
+
+#define AR2315_LB_TX_CHAIN_EN		(AR2315_LOCAL + 0x0100)
+
+#define AR2315_LB_TXEN_0	0x01
+#define AR2315_LB_TXEN_1	0x02
+#define AR2315_LB_TXEN_2	0x04
+#define AR2315_LB_TXEN_3	0x08
+
+#define AR2315_LB_TX_CHAIN_DIS		(AR2315_LOCAL + 0x0104)
+#define AR2315_LB_TX_DESC_PTR		(AR2315_LOCAL + 0x0200)
+
+#define AR2315_LB_RX_CHAIN_EN		(AR2315_LOCAL + 0x0400)
+
+#define AR2315_LB_RXEN		0x01
+
+#define AR2315_LB_RX_CHAIN_DIS		(AR2315_LOCAL + 0x0404)
+#define AR2315_LB_RX_DESC_PTR		(AR2315_LOCAL + 0x0408)
+
+#define AR2315_LB_INT_STATUS		(AR2315_LOCAL + 0x0500)
+
+#define AR2315_INT_TX_DESC	0x0001
+#define AR2315_INT_TX_OK	0x0002
+#define AR2315_INT_TX_ERR	0x0004
+#define AR2315_INT_TX_EOF	0x0008
+#define AR2315_INT_RX_DESC	0x0010
+#define AR2315_INT_RX_OK	0x0020
+#define AR2315_INT_RX_ERR	0x0040
+#define AR2315_INT_RX_EOF	0x0080
+#define AR2315_INT_TX_TRUNC	0x0100
+#define AR2315_INT_TX_STARVE	0x0200
+#define AR2315_INT_LB_TIMEOUT	0x0400
+#define AR2315_INT_LB_ERR	0x0800
+#define AR2315_INT_MBOX_WR	0x1000
+#define AR2315_INT_MBOX_RD	0x2000
+
+/* Bit definitions for INT MASK are the same as INT_STATUS */
+#define AR2315_LB_INT_MASK		(AR2315_LOCAL + 0x0504)
+
+#define AR2315_LB_INT_EN		(AR2315_LOCAL + 0x0508)
+#define AR2315_LB_MBOX			(AR2315_LOCAL + 0x0600)
+
+/*
+ * IR Interface Registers
+ */
+#define AR2315_IR_PKTDATA		(AR2315_IR + 0x0000)
+
+#define AR2315_IR_PKTLEN		(AR2315_IR + 0x07fc) /* 0 - 63 */
+
+#define AR2315_IR_CONTROL		(AR2315_IR + 0x0800)
+
+#define AR2315_IRCTL_TX			0x00000000  /* use as tranmitter */
+#define AR2315_IRCTL_RX			0x00000001  /* use as receiver   */
+#define AR2315_IRCTL_SAMPLECLK_M	0x00003ffe  /* Sample clk divisor */
+#define AR2315_IRCTL_SAMPLECLK_S	1
+#define AR2315_IRCTL_OUTPUTCLK_M	0x03ffc000  /* Output clk div */
+#define AR2315_IRCTL_OUTPUTCLK_S	14
+
+#define AR2315_IR_STATUS		(AR2315_IR + 0x0804)
+
+#define AR2315_IRSTS_RX			0x00000001  /* receive in progress */
+#define AR2315_IRSTS_TX			0x00000002  /* transmit in progress */
+
+#define AR2315_IR_CONFIG		(AR2315_IR + 0x0808)
+
+#define AR2315_IRCFG_INVIN		0x00000001  /* invert in polarity */
+#define AR2315_IRCFG_INVOUT		0x00000002  /* invert out polarity */
+#define AR2315_IRCFG_SEQ_START_WIN_SEL	0x00000004  /* 1 => 28, 0 => 7 */
+#define AR2315_IRCFG_SEQ_START_THRESH	0x000000f0
+#define AR2315_IRCFG_SEQ_END_UNIT_SEL	0x00000100
+#define AR2315_IRCFG_SEQ_END_UNIT_THRESH 0x00007e00
+#define AR2315_IRCFG_SEQ_END_WIN_SEL	0x00008000
+#define AR2315_IRCFG_SEQ_END_WIN_THRESH	0x001f0000
+#define AR2315_IRCFG_NUM_BACKOFF_WORDS	0x01e00000
+
+#endif /* __ASM_MACH_AR231X_AR2315_REGS_H */
diff --git a/arch/mips/include/asm/mach-ar231x/cpu-feature-overrides.h b/arch/mips/include/asm/mach-ar231x/cpu-feature-overrides.h
index 337fe3e..5b7cee6 100644
--- a/arch/mips/include/asm/mach-ar231x/cpu-feature-overrides.h
+++ b/arch/mips/include/asm/mach-ar231x/cpu-feature-overrides.h
@@ -36,11 +36,15 @@
 /* #define cpu_has_mcheck		? */
 #define cpu_has_ejtag			1
 
+#if !defined(CONFIG_SOC_AR5312)
+#  define cpu_has_llsc			1
+#else
 /*
  * The MIPS 4Kc V0.9 core in the AR5312/AR2312 have problems with the
  * ll/sc instructions.
  */
-#define cpu_has_llsc			0
+#  define cpu_has_llsc			0
+#endif
 
 #define cpu_has_mips16			0
 #define cpu_has_mdmx			0
@@ -56,6 +60,10 @@
 
 #define cpu_has_mips32r1		1
 
+#if !defined(CONFIG_SOC_AR5312)
+#  define cpu_has_mips32r2		1
+#endif
+
 #define cpu_has_mips64r1		0
 #define cpu_has_mips64r2		0
 
-- 
1.8.5.5

^ permalink raw reply related	[flat|nested] 37+ messages in thread

* [PATCH 04/16] MIPS: ar231x: add interrupts handling routines
  2014-09-28 18:32 [PATCH 00/16] MIPS: support for the Atheros AR231X SoCs Sergey Ryazanov
                   ` (2 preceding siblings ...)
  2014-09-28 18:33 ` [PATCH 03/16] MIPS: ar231x: add basic AR2315 " Sergey Ryazanov
@ 2014-09-28 18:33 ` Sergey Ryazanov
  2014-09-28 18:33 ` [PATCH 05/16] MIPS: ar231x: add early printk support Sergey Ryazanov
                   ` (11 subsequent siblings)
  15 siblings, 0 replies; 37+ messages in thread
From: Sergey Ryazanov @ 2014-09-28 18:33 UTC (permalink / raw)
  To: Ralf Baechle; +Cc: Linux MIPS

Add interrupts initialization and handling routines, also add AHB bus
error interrupt handlers for both SoCs families.

Signed-off-by: Sergey Ryazanov <ryazanov.s.a@gmail.com>
---

Changes since RFC:
  - add all interrupts
  - use dynamic IRQ numbers allocation

 arch/mips/ar231x/ar2315.c                       | 111 ++++++++++++++++++++++++
 arch/mips/ar231x/ar2315.h                       |   2 +
 arch/mips/ar231x/ar5312.c                       | 106 ++++++++++++++++++++++
 arch/mips/ar231x/ar5312.h                       |   2 +
 arch/mips/ar231x/board.c                        |   8 ++
 arch/mips/ar231x/devices.h                      |   1 +
 arch/mips/include/asm/mach-ar231x/ar2315_regs.h |  23 +++++
 arch/mips/include/asm/mach-ar231x/ar231x.h      |   2 +
 arch/mips/include/asm/mach-ar231x/ar5312_regs.h |  23 +++++
 9 files changed, 278 insertions(+)

diff --git a/arch/mips/ar231x/ar2315.c b/arch/mips/ar231x/ar2315.c
index 5f8b7c4..320893a 100644
--- a/arch/mips/ar231x/ar2315.c
+++ b/arch/mips/ar231x/ar2315.c
@@ -27,6 +27,117 @@
 #include "devices.h"
 #include "ar2315.h"
 
+static unsigned ar2315_misc_irq_base;
+
+static irqreturn_t ar2315_ahb_err_handler(int cpl, void *dev_id)
+{
+	ar231x_write_reg(AR2315_AHB_ERR0, AR2315_AHB_ERROR_DET);
+	ar231x_read_reg(AR2315_AHB_ERR1);
+
+	pr_emerg("AHB fatal error\n");
+	machine_restart("AHB error"); /* Catastrophic failure */
+
+	return IRQ_HANDLED;
+}
+
+static struct irqaction ar2315_ahb_err_interrupt  = {
+	.handler	= ar2315_ahb_err_handler,
+	.name		= "ar2315-ahb-error",
+};
+
+static void ar2315_misc_irq_handler(unsigned irq, struct irq_desc *desc)
+{
+	u32 pending = ar231x_read_reg(AR2315_ISR) & ar231x_read_reg(AR2315_IMR);
+	unsigned base = ar2315_misc_irq_base;
+
+	if (pending & AR2315_ISR_SPI)
+		generic_handle_irq(base + AR2315_MISC_IRQ_SPI);
+	else if (pending & AR2315_ISR_TIMER)
+		generic_handle_irq(base + AR2315_MISC_IRQ_TIMER);
+	else if (pending & AR2315_ISR_AHB)
+		generic_handle_irq(base + AR2315_MISC_IRQ_AHB);
+	else if (pending & AR2315_ISR_GPIO) {
+		ar231x_write_reg(AR2315_ISR, AR2315_ISR_GPIO);
+		generic_handle_irq(base + AR2315_MISC_IRQ_GPIO);
+	} else if (pending & AR2315_ISR_UART0)
+		generic_handle_irq(base + AR2315_MISC_IRQ_UART0);
+	else if (pending & AR2315_ISR_WD) {
+		ar231x_write_reg(AR2315_ISR, AR2315_ISR_WD);
+		generic_handle_irq(base + AR2315_MISC_IRQ_WATCHDOG);
+	} else
+		spurious_interrupt();
+}
+
+static void ar2315_misc_irq_unmask(struct irq_data *d)
+{
+	u32 imr = ar231x_read_reg(AR2315_IMR);
+
+	imr |= 1 << (d->irq - ar2315_misc_irq_base);
+	ar231x_write_reg(AR2315_IMR, imr);
+}
+
+static void ar2315_misc_irq_mask(struct irq_data *d)
+{
+	u32 imr = ar231x_read_reg(AR2315_IMR);
+
+	imr &= ~(1 << (d->irq - ar2315_misc_irq_base));
+	ar231x_write_reg(AR2315_IMR, imr);
+}
+
+static struct irq_chip ar2315_misc_irq_chip = {
+	.name		= "ar2315-misc",
+	.irq_unmask	= ar2315_misc_irq_unmask,
+	.irq_mask	= ar2315_misc_irq_mask,
+};
+
+/*
+ * Called when an interrupt is received, this function
+ * determines exactly which interrupt it was, and it
+ * invokes the appropriate handler.
+ *
+ * Implicitly, we also define interrupt priority by
+ * choosing which to dispatch first.
+ */
+static void ar2315_irq_dispatch(void)
+{
+	u32 pending = read_c0_status() & read_c0_cause();
+
+	if (pending & CAUSEF_IP3)
+		do_IRQ(AR2315_IRQ_WLAN0);
+	else if (pending & CAUSEF_IP2)
+		do_IRQ(AR2315_IRQ_MISC);
+	else if (pending & CAUSEF_IP7)
+		do_IRQ(AR231X_IRQ_CPU_CLOCK);
+	else
+		spurious_interrupt();
+}
+
+void __init ar2315_arch_init_irq(void)
+{
+	unsigned i;
+	int res;
+
+	if (!is_2315())
+		return;
+
+	ar231x_irq_dispatch = ar2315_irq_dispatch;
+
+	res = irq_alloc_descs(-1, 0, AR2315_MISC_IRQ_COUNT, 0);
+	if (res < 0)
+		pr_emerg("Failed to allocate misc IRQ numbers\n");
+	ar2315_misc_irq_base = res;
+
+	for (i = 0; i < AR2315_MISC_IRQ_COUNT; i++) {
+		unsigned irq = ar2315_misc_irq_base + i;
+
+		irq_set_chip_and_handler(irq, &ar2315_misc_irq_chip,
+					 handle_level_irq);
+	}
+	setup_irq(ar2315_misc_irq_base + AR2315_MISC_IRQ_AHB,
+		  &ar2315_ahb_err_interrupt);
+	irq_set_chained_handler(AR2315_IRQ_MISC, ar2315_misc_irq_handler);
+}
+
 static void ar2315_restart(char *command)
 {
 	void (*mips_reset_vec)(void) = (void *)0xbfc00000;
diff --git a/arch/mips/ar231x/ar2315.h b/arch/mips/ar231x/ar2315.h
index 98d32b2..2a57858 100644
--- a/arch/mips/ar231x/ar2315.h
+++ b/arch/mips/ar231x/ar2315.h
@@ -3,12 +3,14 @@
 
 #ifdef CONFIG_SOC_AR2315
 
+void ar2315_arch_init_irq(void);
 void ar2315_plat_time_init(void);
 void ar2315_plat_mem_setup(void);
 void ar2315_prom_init(void);
 
 #else
 
+static inline void ar2315_arch_init_irq(void) {}
 static inline void ar2315_plat_time_init(void) {}
 static inline void ar2315_plat_mem_setup(void) {}
 static inline void ar2315_prom_init(void) {}
diff --git a/arch/mips/ar231x/ar5312.c b/arch/mips/ar231x/ar5312.c
index 909bee0..3f81d33 100644
--- a/arch/mips/ar231x/ar5312.c
+++ b/arch/mips/ar231x/ar5312.c
@@ -27,6 +27,112 @@
 #include "devices.h"
 #include "ar5312.h"
 
+static unsigned ar5312_misc_irq_base;
+
+static irqreturn_t ar5312_ahb_err_handler(int cpl, void *dev_id)
+{
+	u32 proc1 = ar231x_read_reg(AR5312_PROC1);
+	u32 proc_addr = ar231x_read_reg(AR5312_PROCADDR); /* clears error */
+	u32 dma1 = ar231x_read_reg(AR5312_DMA1);
+	u32 dma_addr = ar231x_read_reg(AR5312_DMAADDR);   /* clears error */
+
+	pr_emerg("AHB interrupt: PROCADDR=0x%8.8x PROC1=0x%8.8x DMAADDR=0x%8.8x DMA1=0x%8.8x\n",
+		 proc_addr, proc1, dma_addr, dma1);
+
+	machine_restart("AHB error"); /* Catastrophic failure */
+	return IRQ_HANDLED;
+}
+
+static struct irqaction ar5312_ahb_err_interrupt  = {
+	.handler = ar5312_ahb_err_handler,
+	.name    = "ar5312-ahb-error",
+};
+
+static void ar5312_misc_irq_handler(unsigned irq, struct irq_desc *desc)
+{
+	u32 pending = ar231x_read_reg(AR5312_ISR) & ar231x_read_reg(AR5312_IMR);
+	unsigned base = ar5312_misc_irq_base;
+
+	if (pending & AR5312_ISR_TIMER) {
+		generic_handle_irq(base + AR5312_MISC_IRQ_TIMER);
+		(void)ar231x_read_reg(AR5312_TIMER);
+	} else if (pending & AR5312_ISR_AHBPROC)
+		generic_handle_irq(base + AR5312_MISC_IRQ_AHB_PROC);
+	else if (pending & AR5312_ISR_UART0)
+		generic_handle_irq(base + AR5312_MISC_IRQ_UART0);
+	else if (pending & AR5312_ISR_WD)
+		generic_handle_irq(base + AR5312_MISC_IRQ_WATCHDOG);
+	else
+		spurious_interrupt();
+}
+
+/* Enable the specified AR5312_MISC_IRQ interrupt */
+static void ar5312_misc_irq_unmask(struct irq_data *d)
+{
+	u32 imr = ar231x_read_reg(AR5312_IMR);
+
+	imr |= 1 << (d->irq - ar5312_misc_irq_base);
+	ar231x_write_reg(AR5312_IMR, imr);
+}
+
+/* Disable the specified AR5312_MISC_IRQ interrupt */
+static void ar5312_misc_irq_mask(struct irq_data *d)
+{
+	u32 imr = ar231x_read_reg(AR5312_IMR);
+
+	imr &= ~(1 << (d->irq - ar5312_misc_irq_base));
+	ar231x_write_reg(AR5312_IMR, imr);
+	ar231x_read_reg(AR5312_IMR); /* flush write buffer */
+}
+
+static struct irq_chip ar5312_misc_irq_chip = {
+	.name		= "ar5312-misc",
+	.irq_unmask	= ar5312_misc_irq_unmask,
+	.irq_mask	= ar5312_misc_irq_mask,
+};
+
+static void ar5312_irq_dispatch(void)
+{
+	u32 pending = read_c0_status() & read_c0_cause();
+
+	if (pending & CAUSEF_IP2)
+		do_IRQ(AR5312_IRQ_WLAN0);
+	else if (pending & CAUSEF_IP5)
+		do_IRQ(AR5312_IRQ_WLAN1);
+	else if (pending & CAUSEF_IP6)
+		do_IRQ(AR5312_IRQ_MISC);
+	else if (pending & CAUSEF_IP7)
+		do_IRQ(AR231X_IRQ_CPU_CLOCK);
+	else
+		spurious_interrupt();
+}
+
+void __init ar5312_arch_init_irq(void)
+{
+	unsigned i;
+	int res;
+
+	if (!is_5312())
+		return;
+
+	ar231x_irq_dispatch = ar5312_irq_dispatch;
+
+	res = irq_alloc_descs(-1, 0, AR5312_MISC_IRQ_COUNT, 0);
+	if (res < 0)
+		pr_emerg("Failed to allocate misc IRQ numbers\n");
+	ar5312_misc_irq_base = res;
+
+	for (i = 0; i < AR5312_MISC_IRQ_COUNT; i++) {
+		unsigned irq = ar5312_misc_irq_base + i;
+
+		irq_set_chip_and_handler(irq, &ar5312_misc_irq_chip,
+					 handle_level_irq);
+	}
+	setup_irq(ar5312_misc_irq_base + AR5312_MISC_IRQ_AHB_PROC,
+		  &ar5312_ahb_err_interrupt);
+	irq_set_chained_handler(AR5312_IRQ_MISC, ar5312_misc_irq_handler);
+}
+
 static void ar5312_restart(char *command)
 {
 	/* reset the system */
diff --git a/arch/mips/ar231x/ar5312.h b/arch/mips/ar231x/ar5312.h
index 339b28e..b60ad38 100644
--- a/arch/mips/ar231x/ar5312.h
+++ b/arch/mips/ar231x/ar5312.h
@@ -3,12 +3,14 @@
 
 #ifdef CONFIG_SOC_AR5312
 
+void ar5312_arch_init_irq(void);
 void ar5312_plat_time_init(void);
 void ar5312_plat_mem_setup(void);
 void ar5312_prom_init(void);
 
 #else
 
+static inline void ar5312_arch_init_irq(void) {}
 static inline void ar5312_plat_time_init(void) {}
 static inline void ar5312_plat_mem_setup(void) {}
 static inline void ar5312_prom_init(void) {}
diff --git a/arch/mips/ar231x/board.c b/arch/mips/ar231x/board.c
index f50a7cf..24a00b4 100644
--- a/arch/mips/ar231x/board.c
+++ b/arch/mips/ar231x/board.c
@@ -16,9 +16,12 @@
 #include <asm/bootinfo.h>
 #include <asm/time.h>
 
+#include "devices.h"
 #include "ar5312.h"
 #include "ar2315.h"
 
+void (*ar231x_irq_dispatch)(void);
+
 static void ar231x_halt(void)
 {
 	local_irq_disable();
@@ -40,6 +43,7 @@ void __init plat_mem_setup(void)
 
 asmlinkage void plat_irq_dispatch(void)
 {
+	ar231x_irq_dispatch();
 }
 
 void __init plat_time_init(void)
@@ -57,5 +61,9 @@ void __init arch_init_irq(void)
 {
 	clear_c0_status(ST0_IM);
 	mips_cpu_irq_init();
+
+	/* Initialize interrupt controllers */
+	ar5312_arch_init_irq();
+	ar2315_arch_init_irq();
 }
 
diff --git a/arch/mips/ar231x/devices.h b/arch/mips/ar231x/devices.h
index 1590577..82fa6fb 100644
--- a/arch/mips/ar231x/devices.h
+++ b/arch/mips/ar231x/devices.h
@@ -8,6 +8,7 @@ enum {
 };
 
 extern int ar231x_devtype;
+extern void (*ar231x_irq_dispatch)(void);
 
 static inline bool is_2315(void)
 {
diff --git a/arch/mips/include/asm/mach-ar231x/ar2315_regs.h b/arch/mips/include/asm/mach-ar231x/ar2315_regs.h
index 91197b6..a65d578 100644
--- a/arch/mips/include/asm/mach-ar231x/ar2315_regs.h
+++ b/arch/mips/include/asm/mach-ar231x/ar2315_regs.h
@@ -15,6 +15,29 @@
 #define __ASM_MACH_AR231X_AR2315_REGS_H
 
 /*
+ * IRQs
+ */
+#define AR2315_IRQ_MISC		(MIPS_CPU_IRQ_BASE + 2)	/* C0_CAUSE: 0x0400 */
+#define AR2315_IRQ_WLAN0	(MIPS_CPU_IRQ_BASE + 3)	/* C0_CAUSE: 0x0800 */
+#define AR2315_IRQ_ENET0	(MIPS_CPU_IRQ_BASE + 4)	/* C0_CAUSE: 0x1000 */
+#define AR2315_IRQ_LCBUS_PCI	(MIPS_CPU_IRQ_BASE + 5)	/* C0_CAUSE: 0x2000 */
+#define AR2315_IRQ_WLAN0_POLL	(MIPS_CPU_IRQ_BASE + 6)	/* C0_CAUSE: 0x4000 */
+
+/*
+ * Miscellaneous interrupts, which share IP2.
+ */
+#define AR2315_MISC_IRQ_UART0		0
+#define AR2315_MISC_IRQ_I2C_RSVD	1
+#define AR2315_MISC_IRQ_SPI		2
+#define AR2315_MISC_IRQ_AHB		3
+#define AR2315_MISC_IRQ_APB		4
+#define AR2315_MISC_IRQ_TIMER		5
+#define AR2315_MISC_IRQ_GPIO		6
+#define AR2315_MISC_IRQ_WATCHDOG	7
+#define AR2315_MISC_IRQ_IR_RSVD		8
+#define AR2315_MISC_IRQ_COUNT		9
+
+/*
  * Address map
  */
 #define AR2315_SPI_READ		0x08000000	/* SPI flash */
diff --git a/arch/mips/include/asm/mach-ar231x/ar231x.h b/arch/mips/include/asm/mach-ar231x/ar231x.h
index b830723..a9f05aa 100644
--- a/arch/mips/include/asm/mach-ar231x/ar231x.h
+++ b/arch/mips/include/asm/mach-ar231x/ar231x.h
@@ -3,6 +3,8 @@
 
 #include <linux/io.h>
 
+#define AR231X_IRQ_CPU_CLOCK	(MIPS_CPU_IRQ_BASE + 7)	/* C0_CAUSE: 0x8000 */
+
 #define AR231X_REG_MS(_val, _field)	(((_val) & _field##_M) >> _field##_S)
 
 static inline u32 ar231x_read_reg(u32 reg)
diff --git a/arch/mips/include/asm/mach-ar231x/ar5312_regs.h b/arch/mips/include/asm/mach-ar231x/ar5312_regs.h
index 5eb22fd..c7055e32 100644
--- a/arch/mips/include/asm/mach-ar231x/ar5312_regs.h
+++ b/arch/mips/include/asm/mach-ar231x/ar5312_regs.h
@@ -12,6 +12,29 @@
 #define __ASM_MACH_AR231X_AR5312_REGS_H
 
 /*
+ * IRQs
+ */
+#define AR5312_IRQ_WLAN0	(MIPS_CPU_IRQ_BASE + 2)	/* C0_CAUSE: 0x0400 */
+#define AR5312_IRQ_ENET0	(MIPS_CPU_IRQ_BASE + 3)	/* C0_CAUSE: 0x0800 */
+#define AR5312_IRQ_ENET1	(MIPS_CPU_IRQ_BASE + 4)	/* C0_CAUSE: 0x1000 */
+#define AR5312_IRQ_WLAN1	(MIPS_CPU_IRQ_BASE + 5)	/* C0_CAUSE: 0x2000 */
+#define AR5312_IRQ_MISC		(MIPS_CPU_IRQ_BASE + 6)	/* C0_CAUSE: 0x4000 */
+
+/*
+ * Miscellaneous interrupts, which share IP6.
+ */
+#define AR5312_MISC_IRQ_TIMER		0
+#define AR5312_MISC_IRQ_AHB_PROC	1
+#define AR5312_MISC_IRQ_AHB_DMA		2
+#define AR5312_MISC_IRQ_GPIO		3
+#define AR5312_MISC_IRQ_UART0		4
+#define AR5312_MISC_IRQ_UART0_DMA	5
+#define AR5312_MISC_IRQ_WATCHDOG	6
+#define AR5312_MISC_IRQ_LOCAL		7
+#define AR5312_MISC_IRQ_SPI		8
+#define AR5312_MISC_IRQ_COUNT		9
+
+/*
  * Address Map
  *
  * The AR5312 supports 2 enet MACS, even though many reference boards only
-- 
1.8.5.5

^ permalink raw reply related	[flat|nested] 37+ messages in thread

* [PATCH 05/16] MIPS: ar231x: add early printk support
  2014-09-28 18:32 [PATCH 00/16] MIPS: support for the Atheros AR231X SoCs Sergey Ryazanov
                   ` (3 preceding siblings ...)
  2014-09-28 18:33 ` [PATCH 04/16] MIPS: ar231x: add interrupts handling routines Sergey Ryazanov
@ 2014-09-28 18:33 ` Sergey Ryazanov
  2014-09-29 12:47   ` Jonas Gorski
  2014-09-28 18:33 ` [PATCH 06/16] MIPS: ar231x: add UART support Sergey Ryazanov
                   ` (10 subsequent siblings)
  15 siblings, 1 reply; 37+ messages in thread
From: Sergey Ryazanov @ 2014-09-28 18:33 UTC (permalink / raw)
  To: Ralf Baechle; +Cc: Linux MIPS

Signed-off-by: Sergey Ryazanov <ryazanov.s.a@gmail.com>
---
 arch/mips/Kconfig               |  1 +
 arch/mips/ar231x/Makefile       |  2 ++
 arch/mips/ar231x/early_printk.c | 45 +++++++++++++++++++++++++++++++++++++++++
 3 files changed, 48 insertions(+)
 create mode 100644 arch/mips/ar231x/early_printk.c

diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig
index bd81f7a..b89bfdf 100644
--- a/arch/mips/Kconfig
+++ b/arch/mips/Kconfig
@@ -83,6 +83,7 @@ config AR231X
 	select SYS_SUPPORTS_BIG_ENDIAN
 	select SYS_SUPPORTS_32BIT_KERNEL
 	select ARCH_REQUIRE_GPIOLIB
+	select SYS_HAS_EARLY_PRINTK
 	help
 	  Support for Atheros AR231x and Atheros AR531x based boards
 
diff --git a/arch/mips/ar231x/Makefile b/arch/mips/ar231x/Makefile
index 201b7d4..eabad7d 100644
--- a/arch/mips/ar231x/Makefile
+++ b/arch/mips/ar231x/Makefile
@@ -10,5 +10,7 @@
 
 obj-y += board.o prom.o devices.o
 
+obj-$(CONFIG_EARLY_PRINTK) += early_printk.o
+
 obj-$(CONFIG_SOC_AR5312) += ar5312.o
 obj-$(CONFIG_SOC_AR2315) += ar2315.o
diff --git a/arch/mips/ar231x/early_printk.c b/arch/mips/ar231x/early_printk.c
new file mode 100644
index 0000000..393c5ab
--- /dev/null
+++ b/arch/mips/ar231x/early_printk.c
@@ -0,0 +1,45 @@
+/*
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 2010 Gabor Juhos <juhosg@openwrt.org>
+ */
+
+#include <linux/mm.h>
+#include <linux/io.h>
+#include <linux/serial_reg.h>
+
+#include <ar2315_regs.h>
+#include <ar5312_regs.h>
+#include "devices.h"
+
+static inline void prom_uart_wr(void __iomem *base, unsigned reg,
+				unsigned char ch)
+{
+	__raw_writel(ch, base + 4 * reg);
+}
+
+static inline unsigned char prom_uart_rr(void __iomem *base, unsigned reg)
+{
+	return __raw_readl(base + 4 * reg);
+}
+
+void prom_putchar(unsigned char ch)
+{
+	static void __iomem *base;
+
+	if (unlikely(base == NULL)) {
+		if (is_2315())
+			base = (void __iomem *)(KSEG1ADDR(AR2315_UART0));
+		else
+			base = (void __iomem *)(KSEG1ADDR(AR5312_UART0));
+	}
+
+	while ((prom_uart_rr(base, UART_LSR) & UART_LSR_THRE) == 0)
+		;
+	prom_uart_wr(base, UART_TX, ch);
+	while ((prom_uart_rr(base, UART_LSR) & UART_LSR_THRE) == 0)
+		;
+}
+
-- 
1.8.5.5

^ permalink raw reply related	[flat|nested] 37+ messages in thread

* [PATCH 06/16] MIPS: ar231x: add UART support
  2014-09-28 18:32 [PATCH 00/16] MIPS: support for the Atheros AR231X SoCs Sergey Ryazanov
                   ` (4 preceding siblings ...)
  2014-09-28 18:33 ` [PATCH 05/16] MIPS: ar231x: add early printk support Sergey Ryazanov
@ 2014-09-28 18:33 ` Sergey Ryazanov
  2014-09-28 18:33 ` [PATCH 07/16] MIPS: ar231x: add board configuration detection Sergey Ryazanov
                   ` (9 subsequent siblings)
  15 siblings, 0 replies; 37+ messages in thread
From: Sergey Ryazanov @ 2014-09-28 18:33 UTC (permalink / raw)
  To: Ralf Baechle; +Cc: Linux MIPS

Signed-off-by: Sergey Ryazanov <ryazanov.s.a@gmail.com>
---

Changes since RFC:
  - register UART during arch initialization

 arch/mips/ar231x/ar2315.c  |  9 +++++++++
 arch/mips/ar231x/ar2315.h  |  2 ++
 arch/mips/ar231x/ar5312.c  |  9 +++++++++
 arch/mips/ar231x/ar5312.h  |  2 ++
 arch/mips/ar231x/devices.c | 25 +++++++++++++++++++++++++
 arch/mips/ar231x/devices.h |  2 ++
 6 files changed, 49 insertions(+)

diff --git a/arch/mips/ar231x/ar2315.c b/arch/mips/ar231x/ar2315.c
index 320893a..3d21a25a 100644
--- a/arch/mips/ar231x/ar2315.c
+++ b/arch/mips/ar231x/ar2315.c
@@ -245,3 +245,12 @@ void __init ar2315_prom_init(void)
 	add_memory_region(0, memsize, BOOT_MEM_RAM);
 }
 
+void __init ar2315_arch_init(void)
+{
+	if (!is_2315())
+		return;
+
+	ar231x_serial_setup(AR2315_UART0, ar2315_misc_irq_base +
+			    AR2315_MISC_IRQ_UART0, ar2315_apb_frequency());
+}
+
diff --git a/arch/mips/ar231x/ar2315.h b/arch/mips/ar231x/ar2315.h
index 2a57858..9af22db 100644
--- a/arch/mips/ar231x/ar2315.h
+++ b/arch/mips/ar231x/ar2315.h
@@ -7,6 +7,7 @@ void ar2315_arch_init_irq(void);
 void ar2315_plat_time_init(void);
 void ar2315_plat_mem_setup(void);
 void ar2315_prom_init(void);
+void ar2315_arch_init(void);
 
 #else
 
@@ -14,6 +15,7 @@ static inline void ar2315_arch_init_irq(void) {}
 static inline void ar2315_plat_time_init(void) {}
 static inline void ar2315_plat_mem_setup(void) {}
 static inline void ar2315_prom_init(void) {}
+static inline void ar2315_arch_init(void) {}
 
 #endif
 
diff --git a/arch/mips/ar231x/ar5312.c b/arch/mips/ar231x/ar5312.c
index 3f81d33..138d7e1 100644
--- a/arch/mips/ar231x/ar5312.c
+++ b/arch/mips/ar231x/ar5312.c
@@ -247,3 +247,12 @@ void __init ar5312_prom_init(void)
 	add_memory_region(0, memsize, BOOT_MEM_RAM);
 }
 
+void __init ar5312_arch_init(void)
+{
+	if (!is_5312())
+		return;
+
+	ar231x_serial_setup(AR5312_UART0, ar5312_misc_irq_base +
+			    AR5312_MISC_IRQ_UART0, ar5312_sys_frequency());
+}
+
diff --git a/arch/mips/ar231x/ar5312.h b/arch/mips/ar231x/ar5312.h
index b60ad38..d04a33d 100644
--- a/arch/mips/ar231x/ar5312.h
+++ b/arch/mips/ar231x/ar5312.h
@@ -7,6 +7,7 @@ void ar5312_arch_init_irq(void);
 void ar5312_plat_time_init(void);
 void ar5312_plat_mem_setup(void);
 void ar5312_prom_init(void);
+void ar5312_arch_init(void);
 
 #else
 
@@ -14,6 +15,7 @@ static inline void ar5312_arch_init_irq(void) {}
 static inline void ar5312_plat_time_init(void) {}
 static inline void ar5312_plat_mem_setup(void) {}
 static inline void ar5312_prom_init(void) {}
+static inline void ar5312_arch_init(void) {}
 
 #endif
 
diff --git a/arch/mips/ar231x/devices.c b/arch/mips/ar231x/devices.c
index f71a643..85caae4 100644
--- a/arch/mips/ar231x/devices.c
+++ b/arch/mips/ar231x/devices.c
@@ -1,5 +1,6 @@
 #include <linux/kernel.h>
 #include <linux/init.h>
+#include <linux/serial_8250.h>
 #include <asm/bootinfo.h>
 
 #include "devices.h"
@@ -18,3 +19,27 @@ const char *get_system_type(void)
 	return devtype_strings[ar231x_devtype];
 }
 
+void __init ar231x_serial_setup(u32 mapbase, int irq, unsigned int uartclk)
+{
+	struct uart_port s;
+
+	memset(&s, 0, sizeof(s));
+
+	s.flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST | UPF_IOREMAP;
+	s.iotype = UPIO_MEM32;
+	s.irq = irq;
+	s.regshift = 2;
+	s.mapbase = mapbase;
+	s.uartclk = uartclk;
+
+	early_serial_setup(&s);
+}
+
+static int __init ar231x_arch_init(void)
+{
+	ar5312_arch_init();
+	ar2315_arch_init();
+	return 0;
+}
+
+arch_initcall(ar231x_arch_init);
diff --git a/arch/mips/ar231x/devices.h b/arch/mips/ar231x/devices.h
index 82fa6fb..9f83150 100644
--- a/arch/mips/ar231x/devices.h
+++ b/arch/mips/ar231x/devices.h
@@ -10,6 +10,8 @@ enum {
 extern int ar231x_devtype;
 extern void (*ar231x_irq_dispatch)(void);
 
+void ar231x_serial_setup(u32 mapbase, int irq, unsigned int uartclk);
+
 static inline bool is_2315(void)
 {
 	return (current_cpu_data.cputype == CPU_4KEC);
-- 
1.8.5.5

^ permalink raw reply related	[flat|nested] 37+ messages in thread

* [PATCH 07/16] MIPS: ar231x: add board configuration detection
  2014-09-28 18:32 [PATCH 00/16] MIPS: support for the Atheros AR231X SoCs Sergey Ryazanov
                   ` (5 preceding siblings ...)
  2014-09-28 18:33 ` [PATCH 06/16] MIPS: ar231x: add UART support Sergey Ryazanov
@ 2014-09-28 18:33 ` Sergey Ryazanov
  2014-09-28 18:33 ` [PATCH 08/16] MIPS: ar231x: add SoC type detection Sergey Ryazanov
                   ` (8 subsequent siblings)
  15 siblings, 0 replies; 37+ messages in thread
From: Sergey Ryazanov @ 2014-09-28 18:33 UTC (permalink / raw)
  To: Ralf Baechle; +Cc: Linux MIPS

All boards based on AR5312/AR2315 SoC have a special structure located
at the end of flash. This structure contains board-specific data such as
Ethernet and Wireless MAC addresses. The flash is mapped to the memmory
at predefined location.

Signed-off-by: Sergey Ryazanov <ryazanov.s.a@gmail.com>
---
 arch/mips/ar231x/ar2315.c                          |  17 +++
 arch/mips/ar231x/ar2315.h                          |   2 +
 arch/mips/ar231x/ar5312.c                          |  41 ++++++
 arch/mips/ar231x/ar5312.h                          |   2 +
 arch/mips/ar231x/board.c                           | 153 +++++++++++++++++++++
 arch/mips/ar231x/devices.c                         |  14 ++
 arch/mips/ar231x/devices.h                         |   2 +
 .../mips/include/asm/mach-ar231x/ar231x_platform.h |  73 ++++++++++
 8 files changed, 304 insertions(+)
 create mode 100644 arch/mips/include/asm/mach-ar231x/ar231x_platform.h

diff --git a/arch/mips/ar231x/ar2315.c b/arch/mips/ar231x/ar2315.c
index 3d21a25a..0b973eb 100644
--- a/arch/mips/ar231x/ar2315.c
+++ b/arch/mips/ar231x/ar2315.c
@@ -138,6 +138,23 @@ void __init ar2315_arch_init_irq(void)
 	irq_set_chained_handler(AR2315_IRQ_MISC, ar2315_misc_irq_handler);
 }
 
+/*
+ * NB: We use mapping size that is larger than the actual flash size,
+ * but this shouldn't be a problem here, because the flash will simply
+ * be mapped multiple times.
+ */
+static const u8 * const __initconst
+ar2315_flash_limit = (u8 *)KSEG1ADDR(AR2315_SPI_READ + 0x1000000);
+
+void __init ar2315_init_devices(void)
+{
+	if (!is_2315())
+		return;
+
+	/* Find board configuration */
+	ar231x_find_config(ar2315_flash_limit);
+}
+
 static void ar2315_restart(char *command)
 {
 	void (*mips_reset_vec)(void) = (void *)0xbfc00000;
diff --git a/arch/mips/ar231x/ar2315.h b/arch/mips/ar231x/ar2315.h
index 9af22db..308379a 100644
--- a/arch/mips/ar231x/ar2315.h
+++ b/arch/mips/ar231x/ar2315.h
@@ -4,6 +4,7 @@
 #ifdef CONFIG_SOC_AR2315
 
 void ar2315_arch_init_irq(void);
+void ar2315_init_devices(void);
 void ar2315_plat_time_init(void);
 void ar2315_plat_mem_setup(void);
 void ar2315_prom_init(void);
@@ -12,6 +13,7 @@ void ar2315_arch_init(void);
 #else
 
 static inline void ar2315_arch_init_irq(void) {}
+static inline void ar2315_init_devices(void) {}
 static inline void ar2315_plat_time_init(void) {}
 static inline void ar2315_plat_mem_setup(void) {}
 static inline void ar2315_prom_init(void) {}
diff --git a/arch/mips/ar231x/ar5312.c b/arch/mips/ar231x/ar5312.c
index 138d7e1..576c790 100644
--- a/arch/mips/ar231x/ar5312.c
+++ b/arch/mips/ar231x/ar5312.c
@@ -133,6 +133,47 @@ void __init ar5312_arch_init_irq(void)
 	irq_set_chained_handler(AR5312_IRQ_MISC, ar5312_misc_irq_handler);
 }
 
+static void __init ar5312_flash_init(void)
+{
+	u32 ctl;
+
+	/*
+	 * Configure flash bank 0.
+	 * Assume 8M window size. Flash will be aliased if it's smaller
+	 */
+	ctl = ar231x_read_reg(AR5312_FLASHCTL0) & AR5312_FLASHCTL_MW;
+	ctl |= AR5312_FLASHCTL_E | AR5312_FLASHCTL_AC_8M | AR5312_FLASHCTL_RBLE;
+	ctl |= 0x01 << AR5312_FLASHCTL_IDCY_S;
+	ctl |= 0x07 << AR5312_FLASHCTL_WST1_S;
+	ctl |= 0x07 << AR5312_FLASHCTL_WST2_S;
+	ar231x_write_reg(AR5312_FLASHCTL0, ctl);
+
+	/* Disable other flash banks */
+	ar231x_mask_reg(AR5312_FLASHCTL1, AR5312_FLASHCTL_E |
+					  AR5312_FLASHCTL_AC, 0);
+	ar231x_mask_reg(AR5312_FLASHCTL2, AR5312_FLASHCTL_E |
+					  AR5312_FLASHCTL_AC, 0);
+}
+
+/*
+ * NB: This mapping size is larger than the actual flash size,
+ * but this shouldn't be a problem here, because the flash
+ * will simply be mapped multiple times.
+ */
+static const u8 * const __initconst
+ar5312_flash_limit = (u8 *)KSEG1ADDR(AR5312_FLASH + 0x800000);
+
+void __init ar5312_init_devices(void)
+{
+	if (!is_5312())
+		return;
+
+	ar5312_flash_init();
+
+	/* Locate board/radio config data */
+	ar231x_find_config(ar5312_flash_limit);
+}
+
 static void ar5312_restart(char *command)
 {
 	/* reset the system */
diff --git a/arch/mips/ar231x/ar5312.h b/arch/mips/ar231x/ar5312.h
index d04a33d..211992f 100644
--- a/arch/mips/ar231x/ar5312.h
+++ b/arch/mips/ar231x/ar5312.h
@@ -4,6 +4,7 @@
 #ifdef CONFIG_SOC_AR5312
 
 void ar5312_arch_init_irq(void);
+void ar5312_init_devices(void);
 void ar5312_plat_time_init(void);
 void ar5312_plat_mem_setup(void);
 void ar5312_prom_init(void);
@@ -12,6 +13,7 @@ void ar5312_arch_init(void);
 #else
 
 static inline void ar5312_arch_init_irq(void) {}
+static inline void ar5312_init_devices(void) {}
 static inline void ar5312_plat_time_init(void) {}
 static inline void ar5312_plat_mem_setup(void) {}
 static inline void ar5312_prom_init(void) {}
diff --git a/arch/mips/ar231x/board.c b/arch/mips/ar231x/board.c
index 24a00b4..f1e5d8f 100644
--- a/arch/mips/ar231x/board.c
+++ b/arch/mips/ar231x/board.c
@@ -16,12 +16,165 @@
 #include <asm/bootinfo.h>
 #include <asm/time.h>
 
+#include <ar231x_platform.h>
 #include "devices.h"
 #include "ar5312.h"
 #include "ar2315.h"
 
 void (*ar231x_irq_dispatch)(void);
 
+static inline bool check_radio_magic(const u8 *addr)
+{
+	addr += 0x7a; /* offset for flash magic */
+	return (addr[0] == 0x5a) && (addr[1] == 0xa5);
+}
+
+static inline bool check_notempty(const u8 *addr)
+{
+	return *(u32 *)addr != 0xffffffff;
+}
+
+static inline bool check_board_data(const u8 *flash_limit, const u8 *addr,
+				    bool broken)
+{
+	/* config magic found */
+	if (*((u32 *)addr) == AR231X_BD_MAGIC)
+		return true;
+
+	if (!broken)
+		return false;
+
+	if (check_radio_magic(addr + 0xf8))
+		ar231x_board.radio = addr + 0xf8;
+	if ((addr < flash_limit + 0x10000) &&
+	    check_radio_magic(addr + 0x10000))
+		ar231x_board.radio = addr + 0x10000;
+
+	if (ar231x_board.radio) {
+		/* broken board data detected, use radio data to find the
+		 * offset, user will fix this */
+		return true;
+	}
+
+	return false;
+}
+
+static const u8 * __init find_board_config(const u8 *flash_limit, bool broken)
+{
+	const u8 *addr;
+	const u8 *begin = flash_limit - 0x1000;
+	const u8 *end = flash_limit - 0x30000;
+
+	for (addr = begin; addr >= end; addr -= 0x1000)
+		if (check_board_data(flash_limit, addr, broken))
+			return addr;
+
+	return NULL;
+}
+
+static const u8 * __init find_radio_config(const u8 *flash_limit,
+					   const u8 *bcfg)
+{
+	const u8 *rcfg, *begin, *end;
+
+	/*
+	 * Now find the start of Radio Configuration data, using heuristics:
+	 * Search forward from Board Configuration data by 0x1000 bytes
+	 * at a time until we find non-0xffffffff.
+	 */
+	begin = bcfg + 0x1000;
+	end = flash_limit;
+	for (rcfg = begin; rcfg < end; rcfg += 0x1000)
+		if (check_notempty(rcfg) && check_radio_magic(rcfg))
+			return rcfg;
+
+	/* AR2316 relocates radio config to new location */
+	begin = bcfg + 0xf8;
+	end = flash_limit - 0x1000 + 0xf8;
+	for (rcfg = begin; rcfg < end; rcfg += 0x1000)
+		if (check_notempty(rcfg) && check_radio_magic(rcfg))
+			return rcfg;
+
+	pr_warn("WARNING: Could not find Radio Configuration data\n");
+
+	return NULL;
+}
+
+int __init ar231x_find_config(const u8 *flash_limit)
+{
+	struct ar231x_boarddata *config;
+	unsigned int rcfg_size;
+	int broken_boarddata = 0;
+	const u8 *bcfg, *rcfg;
+	u8 *board_data;
+	u8 *radio_data;
+	u8 *mac_addr;
+	u32 offset;
+
+	ar231x_board.config = NULL;
+	ar231x_board.radio = NULL;
+	/* Copy the board and radio data to RAM, because accessing the mapped
+	 * memory of the flash directly after booting is not safe */
+
+	/* Try to find valid board and radio data */
+	bcfg = find_board_config(flash_limit, false);
+
+	/* If that fails, try to at least find valid radio data */
+	if (!bcfg) {
+		bcfg = find_board_config(flash_limit, true);
+		broken_boarddata = 1;
+	}
+
+	if (!bcfg) {
+		pr_warn("WARNING: No board configuration data found!\n");
+		return -ENODEV;
+	}
+
+	board_data = kzalloc(BOARD_CONFIG_BUFSZ, GFP_KERNEL);
+	ar231x_board.config = (struct ar231x_boarddata *)board_data;
+	memcpy(board_data, bcfg, 0x100);
+	if (broken_boarddata) {
+		pr_warn("WARNING: broken board data detected\n");
+		config = ar231x_board.config;
+		if (is_zero_ether_addr(config->enet0_mac)) {
+			pr_info("Fixing up empty mac addresses\n");
+			config->reset_config_gpio = 0xffff;
+			config->sys_led_gpio = 0xffff;
+			random_ether_addr(config->wlan0_mac);
+			config->wlan0_mac[0] &= ~0x06;
+			random_ether_addr(config->enet0_mac);
+			random_ether_addr(config->enet1_mac);
+		}
+	}
+
+	/* Radio config starts 0x100 bytes after board config, regardless
+	 * of what the physical layout on the flash chip looks like */
+
+	if (ar231x_board.radio)
+		rcfg = (u8 *)ar231x_board.radio;
+	else
+		rcfg = find_radio_config(flash_limit, bcfg);
+
+	if (!rcfg)
+		return -ENODEV;
+
+	radio_data = board_data + 0x100 + ((rcfg - bcfg) & 0xfff);
+	ar231x_board.radio = radio_data;
+	offset = radio_data - board_data;
+	pr_info("Radio config found at offset 0x%x (0x%x)\n", rcfg - bcfg,
+		offset);
+	rcfg_size = BOARD_CONFIG_BUFSZ - offset;
+	memcpy(radio_data, rcfg, rcfg_size);
+
+	mac_addr = &radio_data[0x1d * 2];
+	if (is_broadcast_ether_addr(mac_addr)) {
+		pr_info("Radio MAC is blank; using board-data\n");
+		ether_addr_copy(mac_addr, ar231x_board.config->wlan0_mac);
+	}
+
+	return 0;
+}
+
 static void ar231x_halt(void)
 {
 	local_irq_disable();
diff --git a/arch/mips/ar231x/devices.c b/arch/mips/ar231x/devices.c
index 85caae4..0b7d42b 100644
--- a/arch/mips/ar231x/devices.c
+++ b/arch/mips/ar231x/devices.c
@@ -3,8 +3,12 @@
 #include <linux/serial_8250.h>
 #include <asm/bootinfo.h>
 
+#include <ar231x_platform.h>
 #include "devices.h"
+#include "ar5312.h"
+#include "ar2315.h"
 
+struct ar231x_board_config ar231x_board;
 int ar231x_devtype = DEV_TYPE_UNKNOWN;
 
 static const char * const devtype_strings[] = {
@@ -35,6 +39,16 @@ void __init ar231x_serial_setup(u32 mapbase, int irq, unsigned int uartclk)
 	early_serial_setup(&s);
 }
 
+static int __init ar231x_register_devices(void)
+{
+	ar5312_init_devices();
+	ar2315_init_devices();
+
+	return 0;
+}
+
+device_initcall(ar231x_register_devices);
+
 static int __init ar231x_arch_init(void)
 {
 	ar5312_arch_init();
diff --git a/arch/mips/ar231x/devices.h b/arch/mips/ar231x/devices.h
index 9f83150..ef50bd0 100644
--- a/arch/mips/ar231x/devices.h
+++ b/arch/mips/ar231x/devices.h
@@ -8,8 +8,10 @@ enum {
 };
 
 extern int ar231x_devtype;
+extern struct ar231x_board_config ar231x_board;
 extern void (*ar231x_irq_dispatch)(void);
 
+int ar231x_find_config(const u8 *flash_limit);
 void ar231x_serial_setup(u32 mapbase, int irq, unsigned int uartclk);
 
 static inline bool is_2315(void)
diff --git a/arch/mips/include/asm/mach-ar231x/ar231x_platform.h b/arch/mips/include/asm/mach-ar231x/ar231x_platform.h
new file mode 100644
index 0000000..a726a81
--- /dev/null
+++ b/arch/mips/include/asm/mach-ar231x/ar231x_platform.h
@@ -0,0 +1,73 @@
+#ifndef __ASM_MACH_AR231X_PLATFORM_H
+#define __ASM_MACH_AR231X_PLATFORM_H
+
+#include <linux/etherdevice.h>
+
+/*
+ * This is board-specific data that is stored in a "fixed" location in flash.
+ * It is shared across operating systems, so it should not be changed lightly.
+ * The main reason we need it is in order to extract the ethernet MAC
+ * address(es).
+ */
+struct ar231x_boarddata {
+	u32 magic;                   /* board data is valid */
+#define AR231X_BD_MAGIC 0x35333131   /* "5311", for all 531x/231x platforms */
+	u16 cksum;                   /* checksum (starting with BD_REV 2) */
+	u16 rev;                     /* revision of this struct */
+#define BD_REV 4
+	char board_name[64];         /* Name of board */
+	u16 major;                   /* Board major number */
+	u16 minor;                   /* Board minor number */
+	u32 flags;                   /* Board configuration */
+#define BD_ENET0        0x00000001   /* ENET0 is stuffed */
+#define BD_ENET1        0x00000002   /* ENET1 is stuffed */
+#define BD_UART1        0x00000004   /* UART1 is stuffed */
+#define BD_UART0        0x00000008   /* UART0 is stuffed (dma) */
+#define BD_RSTFACTORY   0x00000010   /* Reset factory defaults stuffed */
+#define BD_SYSLED       0x00000020   /* System LED stuffed */
+#define BD_EXTUARTCLK   0x00000040   /* External UART clock */
+#define BD_CPUFREQ      0x00000080   /* cpu freq is valid in nvram */
+#define BD_SYSFREQ      0x00000100   /* sys freq is set in nvram */
+#define BD_WLAN0        0x00000200   /* Enable WLAN0 */
+#define BD_MEMCAP       0x00000400   /* CAP SDRAM @ mem_cap for testing */
+#define BD_DISWATCHDOG  0x00000800   /* disable system watchdog */
+#define BD_WLAN1        0x00001000   /* Enable WLAN1 (ar5212) */
+#define BD_ISCASPER     0x00002000   /* FLAG for AR2312 */
+#define BD_WLAN0_2G_EN  0x00004000   /* FLAG for radio0_2G */
+#define BD_WLAN0_5G_EN  0x00008000   /* FLAG for radio0_2G */
+#define BD_WLAN1_2G_EN  0x00020000   /* FLAG for radio0_2G */
+#define BD_WLAN1_5G_EN  0x00040000   /* FLAG for radio0_2G */
+	u16 reset_config_gpio;       /* Reset factory GPIO pin */
+	u16 sys_led_gpio;            /* System LED GPIO pin */
+
+	u32 cpu_freq;                /* CPU core frequency in Hz */
+	u32 sys_freq;                /* System frequency in Hz */
+	u32 cnt_freq;                /* Calculated C0_COUNT frequency */
+
+	u8  wlan0_mac[ETH_ALEN];
+	u8  enet0_mac[ETH_ALEN];
+	u8  enet1_mac[ETH_ALEN];
+
+	u16 pci_id;                  /* Pseudo PCIID for common code */
+	u16 mem_cap;                 /* cap bank1 in MB */
+
+	/* version 3 */
+	u8  wlan1_mac[ETH_ALEN];     /* (ar5212) */
+};
+
+#define BOARD_CONFIG_BUFSZ		0x1000
+
+/*
+ * Platform device information for the Wireless MAC
+ */
+struct ar231x_board_config {
+	u16 devid;
+
+	/* board config data */
+	struct ar231x_boarddata *config;
+
+	/* radio calibration data */
+	const char *radio;
+};
+
+#endif /* __ASM_MACH_AR231X_PLATFORM_H */
-- 
1.8.5.5

^ permalink raw reply related	[flat|nested] 37+ messages in thread

* [PATCH 08/16] MIPS: ar231x: add SoC type detection
  2014-09-28 18:32 [PATCH 00/16] MIPS: support for the Atheros AR231X SoCs Sergey Ryazanov
                   ` (6 preceding siblings ...)
  2014-09-28 18:33 ` [PATCH 07/16] MIPS: ar231x: add board configuration detection Sergey Ryazanov
@ 2014-09-28 18:33 ` Sergey Ryazanov
  2014-09-28 18:33 ` [PATCH 09/16] gpio: add driver for Atheros AR5312 SoC GPIO controller Sergey Ryazanov
                   ` (7 subsequent siblings)
  15 siblings, 0 replies; 37+ messages in thread
From: Sergey Ryazanov @ 2014-09-28 18:33 UTC (permalink / raw)
  To: Ralf Baechle; +Cc: Linux MIPS

Detect SoC type based on device ID and board configuration data.

Signed-off-by: Sergey Ryazanov <ryazanov.s.a@gmail.com>
---
 arch/mips/ar231x/ar2315.c  | 22 +++++++++++++++++++++-
 arch/mips/ar231x/ar5312.c  | 22 ++++++++++++++++++++++
 arch/mips/ar231x/devices.c |  7 +++++++
 arch/mips/ar231x/devices.h | 11 +++++++++++
 4 files changed, 61 insertions(+), 1 deletion(-)

diff --git a/arch/mips/ar231x/ar2315.c b/arch/mips/ar231x/ar2315.c
index 0b973eb..7791637 100644
--- a/arch/mips/ar231x/ar2315.c
+++ b/arch/mips/ar231x/ar2315.c
@@ -21,6 +21,7 @@
 #include <asm/reboot.h>
 #include <asm/time.h>
 
+#include <ar231x_platform.h>
 #include <ar2315_regs.h>
 #include <ar231x.h>
 
@@ -249,7 +250,7 @@ void __init ar2315_plat_mem_setup(void)
 
 void __init ar2315_prom_init(void)
 {
-	u32 memsize, memcfg;
+	u32 memsize, memcfg, devid;
 
 	if (!is_2315())
 		return;
@@ -260,6 +261,25 @@ void __init ar2315_prom_init(void)
 	memsize <<= 1 + AR231X_REG_MS(memcfg, AR2315_MEM_CFG_ROW_WIDTH);
 	memsize <<= 3;
 	add_memory_region(0, memsize, BOOT_MEM_RAM);
+
+	/* Detect the hardware based on the device ID */
+	devid = ar231x_read_reg(AR2315_SREV) & AR2315_REV_CHIP;
+	switch (devid) {
+	case 0x91:	/* Need to check */
+		ar231x_devtype = DEV_TYPE_AR2318;
+		break;
+	case 0x90:
+		ar231x_devtype = DEV_TYPE_AR2317;
+		break;
+	case 0x87:
+		ar231x_devtype = DEV_TYPE_AR2316;
+		break;
+	case 0x86:
+	default:
+		ar231x_devtype = DEV_TYPE_AR2315;
+		break;
+	}
+	ar231x_board.devid = devid;
 }
 
 void __init ar2315_arch_init(void)
diff --git a/arch/mips/ar231x/ar5312.c b/arch/mips/ar231x/ar5312.c
index 576c790..f207d14 100644
--- a/arch/mips/ar231x/ar5312.c
+++ b/arch/mips/ar231x/ar5312.c
@@ -21,6 +21,7 @@
 #include <asm/reboot.h>
 #include <asm/time.h>
 
+#include <ar231x_platform.h>
 #include <ar5312_regs.h>
 #include <ar231x.h>
 
@@ -165,6 +166,8 @@ ar5312_flash_limit = (u8 *)KSEG1ADDR(AR5312_FLASH + 0x800000);
 
 void __init ar5312_init_devices(void)
 {
+	struct ar231x_boarddata *config;
+
 	if (!is_5312())
 		return;
 
@@ -172,6 +175,19 @@ void __init ar5312_init_devices(void)
 
 	/* Locate board/radio config data */
 	ar231x_find_config(ar5312_flash_limit);
+	config = ar231x_board.config;
+
+	/* AR2313 has CPU minor rev. 10 */
+	if ((current_cpu_data.processor_id & 0xff) == 0x0a)
+		ar231x_devtype = DEV_TYPE_AR2313;
+
+	/* AR2312 shares the same Silicon ID as AR5312 */
+	else if (config->flags & BD_ISCASPER)
+		ar231x_devtype = DEV_TYPE_AR2312;
+
+	/* Everything else is probably AR5312 or compatible */
+	else
+		ar231x_devtype = DEV_TYPE_AR5312;
 }
 
 static void ar5312_restart(char *command)
@@ -274,6 +290,7 @@ void __init ar5312_plat_mem_setup(void)
 void __init ar5312_prom_init(void)
 {
 	u32 memsize, memcfg, bank0_ac, bank1_ac;
+	u32 devid;
 
 	if (!is_5312())
 		return;
@@ -286,6 +303,11 @@ void __init ar5312_prom_init(void)
 		  (bank1_ac ? (1 << (bank1_ac + 1)) : 0);
 	memsize <<= 20;
 	add_memory_region(0, memsize, BOOT_MEM_RAM);
+
+	devid = ar231x_read_reg(AR5312_REV);
+	devid >>= AR5312_REV_WMAC_MIN_S;
+	devid &= AR5312_REV_CHIP;
+	ar231x_board.devid = (u16)devid;
 }
 
 void __init ar5312_arch_init(void)
diff --git a/arch/mips/ar231x/devices.c b/arch/mips/ar231x/devices.c
index 0b7d42b..21f90f2 100644
--- a/arch/mips/ar231x/devices.c
+++ b/arch/mips/ar231x/devices.c
@@ -12,6 +12,13 @@ struct ar231x_board_config ar231x_board;
 int ar231x_devtype = DEV_TYPE_UNKNOWN;
 
 static const char * const devtype_strings[] = {
+	[DEV_TYPE_AR5312] = "Atheros AR5312",
+	[DEV_TYPE_AR2312] = "Atheros AR2312",
+	[DEV_TYPE_AR2313] = "Atheros AR2313",
+	[DEV_TYPE_AR2315] = "Atheros AR2315",
+	[DEV_TYPE_AR2316] = "Atheros AR2316",
+	[DEV_TYPE_AR2317] = "Atheros AR2317",
+	[DEV_TYPE_AR2318] = "Atheros AR2318",
 	[DEV_TYPE_UNKNOWN] = "Atheros (unknown)",
 };
 
diff --git a/arch/mips/ar231x/devices.h b/arch/mips/ar231x/devices.h
index ef50bd0..5ffa091 100644
--- a/arch/mips/ar231x/devices.h
+++ b/arch/mips/ar231x/devices.h
@@ -4,6 +4,17 @@
 #include <linux/cpu.h>
 
 enum {
+	/* handled by ar5312.c */
+	DEV_TYPE_AR2312,
+	DEV_TYPE_AR2313,
+	DEV_TYPE_AR5312,
+
+	/* handled by ar2315.c */
+	DEV_TYPE_AR2315,
+	DEV_TYPE_AR2316,
+	DEV_TYPE_AR2317,
+	DEV_TYPE_AR2318,
+
 	DEV_TYPE_UNKNOWN
 };
 
-- 
1.8.5.5

^ permalink raw reply related	[flat|nested] 37+ messages in thread

* [PATCH 09/16] gpio: add driver for Atheros AR5312 SoC GPIO controller
  2014-09-28 18:32 [PATCH 00/16] MIPS: support for the Atheros AR231X SoCs Sergey Ryazanov
                   ` (7 preceding siblings ...)
  2014-09-28 18:33 ` [PATCH 08/16] MIPS: ar231x: add SoC type detection Sergey Ryazanov
@ 2014-09-28 18:33 ` Sergey Ryazanov
  2014-10-15  7:33   ` Linus Walleij
  2014-09-28 18:33 ` [PATCH 10/16] gpio: add driver for Atheros AR2315 " Sergey Ryazanov
                   ` (6 subsequent siblings)
  15 siblings, 1 reply; 37+ messages in thread
From: Sergey Ryazanov @ 2014-09-28 18:33 UTC (permalink / raw)
  To: Ralf Baechle; +Cc: Linux MIPS, Linus Walleij, Alexandre Courbot, linux-gpio

Atheros AR5312 SoC have a builtin GPIO controller, which could be accessed
via memory mapped registers. This patch adds new driver for them.

Signed-off-by: Sergey Ryazanov <ryazanov.s.a@gmail.com>
Cc: Linus Walleij <linus.walleij@linaro.org>
Cc: Alexandre Courbot <gnurou@gmail.com>
Cc: linux-gpio@vger.kernel.org
---

Changes since RFC:
  - move device registration to separate patch

 drivers/gpio/Kconfig       |   7 +++
 drivers/gpio/Makefile      |   1 +
 drivers/gpio/gpio-ar5312.c | 121 +++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 129 insertions(+)
 create mode 100644 drivers/gpio/gpio-ar5312.c

diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig
index 9de1515..7ce411b 100644
--- a/drivers/gpio/Kconfig
+++ b/drivers/gpio/Kconfig
@@ -112,6 +112,13 @@ config GPIO_MAX730X
 
 comment "Memory mapped GPIO drivers:"
 
+config GPIO_AR5312
+	bool "AR5312 SoC GPIO support"
+	default y if SOC_AR5312
+	depends on SOC_AR5312
+	help
+	  Say yes here to enable GPIO support for Atheros AR5312/AR2312+ SoCs.
+
 config GPIO_CLPS711X
 	tristate "CLPS711X GPIO support"
 	depends on ARCH_CLPS711X || COMPILE_TEST
diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile
index 5d024e3..fae00f4 100644
--- a/drivers/gpio/Makefile
+++ b/drivers/gpio/Makefile
@@ -17,6 +17,7 @@ obj-$(CONFIG_GPIO_ADNP)		+= gpio-adnp.o
 obj-$(CONFIG_GPIO_ADP5520)	+= gpio-adp5520.o
 obj-$(CONFIG_GPIO_ADP5588)	+= gpio-adp5588.o
 obj-$(CONFIG_GPIO_AMD8111)	+= gpio-amd8111.o
+obj-$(CONFIG_GPIO_AR5312)	+= gpio-ar5312.o
 obj-$(CONFIG_GPIO_ARIZONA)	+= gpio-arizona.o
 obj-$(CONFIG_GPIO_BCM_KONA)	+= gpio-bcm-kona.o
 obj-$(CONFIG_GPIO_BT8XX)	+= gpio-bt8xx.o
diff --git a/drivers/gpio/gpio-ar5312.c b/drivers/gpio/gpio-ar5312.c
new file mode 100644
index 0000000..27adb61
--- /dev/null
+++ b/drivers/gpio/gpio-ar5312.c
@@ -0,0 +1,121 @@
+/*
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 2003 Atheros Communications, Inc.,  All Rights Reserved.
+ * Copyright (C) 2006 FON Technology, SL.
+ * Copyright (C) 2006 Imre Kaloz <kaloz@openwrt.org>
+ * Copyright (C) 2006-2009 Felix Fietkau <nbd@openwrt.org>
+ * Copyright (C) 2012 Alexandros C. Couloumbis <alex@ozo.com>
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/gpio.h>
+
+#define DRIVER_NAME	"ar5312-gpio"
+
+#define AR5312_GPIO_DO		0x00		/* output register */
+#define AR5312_GPIO_DI		0x04		/* intput register */
+#define AR5312_GPIO_CR		0x08		/* control register */
+
+#define AR5312_GPIO_CR_M(x)	(1 << (x))	/* mask for i/o */
+#define AR5312_GPIO_CR_O(x)	(0 << (x))	/* mask for output */
+#define AR5312_GPIO_CR_I(x)	(1 << (x))	/* mask for input */
+#define AR5312_GPIO_CR_INT(x)	(1 << ((x)+8))	/* mask for interrupt */
+#define AR5312_GPIO_CR_UART(x)	(1 << ((x)+16))	/* uart multiplex */
+
+#define AR5312_GPIO_NUM		8
+
+static void __iomem *ar5312_mem;
+
+static inline u32 ar5312_gpio_reg_read(unsigned reg)
+{
+	return __raw_readl(ar5312_mem + reg);
+}
+
+static inline void ar5312_gpio_reg_write(unsigned reg, u32 val)
+{
+	__raw_writel(val, ar5312_mem + reg);
+}
+
+static inline void ar5312_gpio_reg_mask(unsigned reg, u32 mask, u32 val)
+{
+	ar5312_gpio_reg_write(reg, (ar5312_gpio_reg_read(reg) & ~mask) | val);
+}
+
+static int ar5312_gpio_get_val(struct gpio_chip *chip, unsigned gpio)
+{
+	return (ar5312_gpio_reg_read(AR5312_GPIO_DI) >> gpio) & 1;
+}
+
+static void ar5312_gpio_set_val(struct gpio_chip *chip, unsigned gpio, int val)
+{
+	u32 reg = ar5312_gpio_reg_read(AR5312_GPIO_DO);
+
+	reg = val ? reg | (1 << gpio) : reg & ~(1 << gpio);
+	ar5312_gpio_reg_write(AR5312_GPIO_DO, reg);
+}
+
+static int ar5312_gpio_dir_in(struct gpio_chip *chip, unsigned gpio)
+{
+	ar5312_gpio_reg_mask(AR5312_GPIO_CR, 0, 1 << gpio);
+	return 0;
+}
+
+static int ar5312_gpio_dir_out(struct gpio_chip *chip, unsigned gpio, int val)
+{
+	ar5312_gpio_reg_mask(AR5312_GPIO_CR, 1 << gpio, 0);
+	ar5312_gpio_set_val(chip, gpio, val);
+	return 0;
+}
+
+static struct gpio_chip ar5312_gpio_chip = {
+	.label			= DRIVER_NAME,
+	.direction_input	= ar5312_gpio_dir_in,
+	.direction_output	= ar5312_gpio_dir_out,
+	.set			= ar5312_gpio_set_val,
+	.get			= ar5312_gpio_get_val,
+	.base			= 0,
+	.ngpio			= AR5312_GPIO_NUM,
+};
+
+static int ar5312_gpio_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct resource *res;
+	int ret;
+
+	if (ar5312_mem)
+		return -EBUSY;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	ar5312_mem = devm_ioremap_resource(dev, res);
+	if (IS_ERR(ar5312_mem))
+		return PTR_ERR(ar5312_mem);
+
+	ar5312_gpio_chip.dev = dev;
+	ret = gpiochip_add(&ar5312_gpio_chip);
+	if (ret) {
+		dev_err(dev, "failed to add gpiochip\n");
+		return ret;
+	}
+
+	return 0;
+}
+
+static struct platform_driver ar5312_gpio_driver = {
+	.probe = ar5312_gpio_probe,
+	.driver = {
+		.name = DRIVER_NAME,
+		.owner = THIS_MODULE,
+	}
+};
+
+static int __init ar5312_gpio_init(void)
+{
+	return platform_driver_register(&ar5312_gpio_driver);
+}
+subsys_initcall(ar5312_gpio_init);
-- 
1.8.5.5


^ permalink raw reply related	[flat|nested] 37+ messages in thread

* [PATCH 10/16] gpio: add driver for Atheros AR2315 SoC GPIO controller
  2014-09-28 18:32 [PATCH 00/16] MIPS: support for the Atheros AR231X SoCs Sergey Ryazanov
                   ` (8 preceding siblings ...)
  2014-09-28 18:33 ` [PATCH 09/16] gpio: add driver for Atheros AR5312 SoC GPIO controller Sergey Ryazanov
@ 2014-09-28 18:33 ` Sergey Ryazanov
  2014-10-15  8:58   ` Linus Walleij
  2014-09-28 18:33   ` Sergey Ryazanov
                   ` (5 subsequent siblings)
  15 siblings, 1 reply; 37+ messages in thread
From: Sergey Ryazanov @ 2014-09-28 18:33 UTC (permalink / raw)
  To: Ralf Baechle; +Cc: Linux MIPS, Linus Walleij, Alexandre Courbot, linux-gpio

Atheros AR2315 SoC have a builtin GPIO controller, which could be
accessed via memory mapped registers. This patch adds new driver
for them.

Signed-off-by: Sergey Ryazanov <ryazanov.s.a@gmail.com>
Cc: Linus Walleij <linus.walleij@linaro.org>
Cc: Alexandre Courbot <gnurou@gmail.com>
Cc: linux-gpio@vger.kernel.org
---

Changes since RFC:
  - fix chip name, this patch adds AR2315 GPIO controller driver
  - use dynamic IRQ numbers allocation
  - move device registration to separate patch

 drivers/gpio/Kconfig       |   7 ++
 drivers/gpio/Makefile      |   1 +
 drivers/gpio/gpio-ar2315.c | 232 +++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 240 insertions(+)
 create mode 100644 drivers/gpio/gpio-ar2315.c

diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig
index 7ce411b..0ceb4ba 100644
--- a/drivers/gpio/Kconfig
+++ b/drivers/gpio/Kconfig
@@ -112,6 +112,13 @@ config GPIO_MAX730X
 
 comment "Memory mapped GPIO drivers:"
 
+config GPIO_AR2315
+	bool "AR2315 SoC GPIO support"
+	default y if SOC_AR2315
+	depends on SOC_AR2315
+	help
+	  Say yes here to enable GPIO support for Atheros AR2315+ SoCs.
+
 config GPIO_AR5312
 	bool "AR5312 SoC GPIO support"
 	default y if SOC_AR5312
diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile
index fae00f4..9a3a136 100644
--- a/drivers/gpio/Makefile
+++ b/drivers/gpio/Makefile
@@ -17,6 +17,7 @@ obj-$(CONFIG_GPIO_ADNP)		+= gpio-adnp.o
 obj-$(CONFIG_GPIO_ADP5520)	+= gpio-adp5520.o
 obj-$(CONFIG_GPIO_ADP5588)	+= gpio-adp5588.o
 obj-$(CONFIG_GPIO_AMD8111)	+= gpio-amd8111.o
+obj-$(CONFIG_GPIO_AR2315)	+= gpio-ar2315.o
 obj-$(CONFIG_GPIO_AR5312)	+= gpio-ar5312.o
 obj-$(CONFIG_GPIO_ARIZONA)	+= gpio-arizona.o
 obj-$(CONFIG_GPIO_BCM_KONA)	+= gpio-bcm-kona.o
diff --git a/drivers/gpio/gpio-ar2315.c b/drivers/gpio/gpio-ar2315.c
new file mode 100644
index 0000000..2a6caaf
--- /dev/null
+++ b/drivers/gpio/gpio-ar2315.c
@@ -0,0 +1,232 @@
+/*
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 2003 Atheros Communications, Inc.,  All Rights Reserved.
+ * Copyright (C) 2006 FON Technology, SL.
+ * Copyright (C) 2006 Imre Kaloz <kaloz@openwrt.org>
+ * Copyright (C) 2006 Felix Fietkau <nbd@openwrt.org>
+ * Copyright (C) 2012 Alexandros C. Couloumbis <alex@ozo.com>
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/gpio.h>
+#include <linux/irq.h>
+
+#define DRIVER_NAME	"ar2315-gpio"
+
+#define AR2315_GPIO_DI			0x0000
+#define AR2315_GPIO_DO			0x0008
+#define AR2315_GPIO_DIR			0x0010
+#define AR2315_GPIO_INT			0x0018
+
+#define AR2315_GPIO_DIR_M(x)		(1 << (x))	/* mask for i/o */
+#define AR2315_GPIO_DIR_O(x)		(1 << (x))	/* output */
+#define AR2315_GPIO_DIR_I(x)		(0)		/* input */
+
+#define AR2315_GPIO_INT_NUM_M		0x3F		/* mask for GPIO num */
+#define AR2315_GPIO_INT_TRIG(x)		((x) << 6)	/* interrupt trigger */
+#define AR2315_GPIO_INT_TRIG_M		(0x3 << 6)	/* mask for int trig */
+
+#define AR2315_GPIO_INT_TRIG_OFF	0	/* Triggerring off */
+#define AR2315_GPIO_INT_TRIG_LOW	1	/* Low Level Triggered */
+#define AR2315_GPIO_INT_TRIG_HIGH	2	/* High Level Triggered */
+#define AR2315_GPIO_INT_TRIG_EDGE	3	/* Edge Triggered */
+
+#define AR2315_GPIO_NUM		22
+
+static u32 ar2315_gpio_intmask;
+static u32 ar2315_gpio_intval;
+static unsigned ar2315_gpio_irq_base;
+static void __iomem *ar2315_mem;
+
+static inline u32 ar2315_gpio_reg_read(unsigned reg)
+{
+	return __raw_readl(ar2315_mem + reg);
+}
+
+static inline void ar2315_gpio_reg_write(unsigned reg, u32 val)
+{
+	__raw_writel(val, ar2315_mem + reg);
+}
+
+static inline void ar2315_gpio_reg_mask(unsigned reg, u32 mask, u32 val)
+{
+	ar2315_gpio_reg_write(reg, (ar2315_gpio_reg_read(reg) & ~mask) | val);
+}
+
+static void ar2315_gpio_irq_handler(unsigned irq, struct irq_desc *desc)
+{
+	u32 pend;
+	int bit = -1;
+
+	/* only do one gpio interrupt at a time */
+	pend = ar2315_gpio_reg_read(AR2315_GPIO_DI);
+	pend ^= ar2315_gpio_intval;
+	pend &= ar2315_gpio_intmask;
+
+	if (pend) {
+		bit = fls(pend) - 1;
+		pend &= ~(1 << bit);
+		ar2315_gpio_intval ^= (1 << bit);
+	}
+
+	/* Enable interrupt with edge detection */
+	if ((ar2315_gpio_reg_read(AR2315_GPIO_DIR) & AR2315_GPIO_DIR_M(bit)) !=
+	    AR2315_GPIO_DIR_I(bit))
+		return;
+
+	if (bit >= 0)
+		generic_handle_irq(ar2315_gpio_irq_base + bit);
+}
+
+static void ar2315_gpio_int_setup(unsigned gpio, int trig)
+{
+	u32 reg = ar2315_gpio_reg_read(AR2315_GPIO_INT);
+
+	reg &= ~(AR2315_GPIO_INT_NUM_M | AR2315_GPIO_INT_TRIG_M);
+	reg |= gpio | AR2315_GPIO_INT_TRIG(trig);
+	ar2315_gpio_reg_write(AR2315_GPIO_INT, reg);
+}
+
+static void ar2315_gpio_irq_unmask(struct irq_data *d)
+{
+	unsigned gpio = d->irq - ar2315_gpio_irq_base;
+	u32 dir = ar2315_gpio_reg_read(AR2315_GPIO_DIR);
+
+	/* Enable interrupt with edge detection */
+	if ((dir & AR2315_GPIO_DIR_M(gpio)) != AR2315_GPIO_DIR_I(gpio))
+		return;
+
+	ar2315_gpio_intmask |= (1 << gpio);
+	ar2315_gpio_int_setup(gpio, AR2315_GPIO_INT_TRIG_EDGE);
+}
+
+static void ar2315_gpio_irq_mask(struct irq_data *d)
+{
+	unsigned gpio = d->irq - ar2315_gpio_irq_base;
+
+	/* Disable interrupt */
+	ar2315_gpio_intmask &= ~(1 << gpio);
+	ar2315_gpio_int_setup(gpio, AR2315_GPIO_INT_TRIG_OFF);
+}
+
+static struct irq_chip ar2315_gpio_irq_chip = {
+	.name		= DRIVER_NAME,
+	.irq_unmask	= ar2315_gpio_irq_unmask,
+	.irq_mask	= ar2315_gpio_irq_mask,
+};
+
+static void ar2315_gpio_irq_init(unsigned irq)
+{
+	unsigned i;
+
+	ar2315_gpio_intval = ar2315_gpio_reg_read(AR2315_GPIO_DI);
+	for (i = 0; i < AR2315_GPIO_NUM; i++) {
+		unsigned _irq = ar2315_gpio_irq_base + i;
+
+		irq_set_chip_and_handler(_irq, &ar2315_gpio_irq_chip,
+					 handle_level_irq);
+	}
+	irq_set_chained_handler(irq, ar2315_gpio_irq_handler);
+}
+
+static int ar2315_gpio_get_val(struct gpio_chip *chip, unsigned gpio)
+{
+	return (ar2315_gpio_reg_read(AR2315_GPIO_DI) >> gpio) & 1;
+}
+
+static void ar2315_gpio_set_val(struct gpio_chip *chip, unsigned gpio, int val)
+{
+	u32 reg = ar2315_gpio_reg_read(AR2315_GPIO_DO);
+
+	reg = val ? reg | (1 << gpio) : reg & ~(1 << gpio);
+	ar2315_gpio_reg_write(AR2315_GPIO_DO, reg);
+}
+
+static int ar2315_gpio_dir_in(struct gpio_chip *chip, unsigned gpio)
+{
+	ar2315_gpio_reg_mask(AR2315_GPIO_DIR, 1 << gpio, 0);
+	return 0;
+}
+
+static int ar2315_gpio_dir_out(struct gpio_chip *chip, unsigned gpio, int val)
+{
+	ar2315_gpio_reg_mask(AR2315_GPIO_DIR, 0, 1 << gpio);
+	ar2315_gpio_set_val(chip, gpio, val);
+	return 0;
+}
+
+static int ar2315_gpio_to_irq(struct gpio_chip *chip, unsigned gpio)
+{
+	return ar2315_gpio_irq_base + gpio;
+}
+
+static struct gpio_chip ar2315_gpio_chip = {
+	.label			= DRIVER_NAME,
+	.direction_input	= ar2315_gpio_dir_in,
+	.direction_output	= ar2315_gpio_dir_out,
+	.set			= ar2315_gpio_set_val,
+	.get			= ar2315_gpio_get_val,
+	.to_irq			= ar2315_gpio_to_irq,
+	.base			= 0,
+	.ngpio			= AR2315_GPIO_NUM,
+};
+
+static int ar2315_gpio_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct resource *res;
+	unsigned irq;
+	int ret;
+
+	if (ar2315_mem)
+		return -EBUSY;
+
+	res = platform_get_resource_byname(pdev, IORESOURCE_IRQ, DRIVER_NAME);
+	if (!res) {
+		dev_err(dev, "not found IRQ number\n");
+		return -ENXIO;
+	}
+	irq = res->start;
+
+	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, DRIVER_NAME);
+	ar2315_mem = devm_ioremap_resource(dev, res);
+	if (IS_ERR(ar2315_mem))
+		return PTR_ERR(ar2315_mem);
+
+	ar2315_gpio_chip.dev = dev;
+	ret = gpiochip_add(&ar2315_gpio_chip);
+	if (ret) {
+		dev_err(dev, "failed to add gpiochip\n");
+		return ret;
+	}
+
+	ret = irq_alloc_descs(-1, 0, AR2315_GPIO_NUM, 0);
+	if (ret < 0) {
+		dev_err(dev, "failed to allocate IRQ numbers\n");
+		return ret;
+	}
+	ar2315_gpio_irq_base = ret;
+
+	ar2315_gpio_irq_init(irq);
+
+	return 0;
+}
+
+static struct platform_driver ar2315_gpio_driver = {
+	.probe = ar2315_gpio_probe,
+	.driver = {
+		.name = DRIVER_NAME,
+		.owner = THIS_MODULE,
+	}
+};
+
+static int __init ar2315_gpio_init(void)
+{
+	return platform_driver_register(&ar2315_gpio_driver);
+}
+subsys_initcall(ar2315_gpio_init);
-- 
1.8.5.5


^ permalink raw reply related	[flat|nested] 37+ messages in thread

* [PATCH 11/16] mtd: add Atheros AR2315 SPI Flash driver
  2014-09-28 18:32 [PATCH 00/16] MIPS: support for the Atheros AR231X SoCs Sergey Ryazanov
@ 2014-09-28 18:33   ` Sergey Ryazanov
  2014-09-28 18:33 ` [PATCH 02/16] MIPS: ar231x: add basic AR5312 SoC support Sergey Ryazanov
                     ` (14 subsequent siblings)
  15 siblings, 0 replies; 37+ messages in thread
From: Sergey Ryazanov @ 2014-09-28 18:33 UTC (permalink / raw)
  To: Ralf Baechle; +Cc: Linux MIPS, David Woodhouse, Brian Norris, linux-mtd

Atheros AR2315 SoC have a SPI Flash unit with hybrid flash access: flash
read is performed via memory mapping, on the other hand flash write is
performed by explicitly issued SPI command.

Signed-off-by: Sergey Ryazanov <ryazanov.s.a@gmail.com>
Cc: David Woodhouse <dwmw2@infradead.org>
Cc: Brian Norris <computersforpeace@gmail.com>
Cc: linux-mtd@lists.infradead.org
---
This driver is not ready for merging since it should be rewrited using
spi-nor framework.

Changes since RFC:
  - move device registration to separate patch

 drivers/mtd/devices/Kconfig           |   5 +
 drivers/mtd/devices/Makefile          |   1 +
 drivers/mtd/devices/ar2315.c          | 459 ++++++++++++++++++++++++++++++++++
 drivers/mtd/devices/ar2315_spiflash.h | 106 ++++++++
 4 files changed, 571 insertions(+)
 create mode 100644 drivers/mtd/devices/ar2315.c
 create mode 100644 drivers/mtd/devices/ar2315_spiflash.h

diff --git a/drivers/mtd/devices/Kconfig b/drivers/mtd/devices/Kconfig
index c49d0b1..9533867 100644
--- a/drivers/mtd/devices/Kconfig
+++ b/drivers/mtd/devices/Kconfig
@@ -112,6 +112,11 @@ config MTD_SST25L
 	  Set up your spi devices with the right board-specific platform data,
 	  if you want to specify device partitioning.
 
+config MTD_AR2315
+	tristate "Atheros AR2315+ SPI Flash support"
+	depends on SOC_AR2315
+	default y
+
 config MTD_BCM47XXSFLASH
 	tristate "R/O support for serial flash on BCMA bus"
 	depends on BCMA_SFLASH
diff --git a/drivers/mtd/devices/Makefile b/drivers/mtd/devices/Makefile
index c68868f..eaec8fb 100644
--- a/drivers/mtd/devices/Makefile
+++ b/drivers/mtd/devices/Makefile
@@ -15,6 +15,7 @@ obj-$(CONFIG_MTD_M25P80)	+= m25p80.o
 obj-$(CONFIG_MTD_NAND_OMAP_BCH)	+= elm.o
 obj-$(CONFIG_MTD_SPEAR_SMI)	+= spear_smi.o
 obj-$(CONFIG_MTD_SST25L)	+= sst25l.o
+obj-$(CONFIG_MTD_AR2315)	+= ar2315.o
 obj-$(CONFIG_MTD_BCM47XXSFLASH)	+= bcm47xxsflash.o
 obj-$(CONFIG_MTD_ST_SPI_FSM)    += st_spi_fsm.o
 
diff --git a/drivers/mtd/devices/ar2315.c b/drivers/mtd/devices/ar2315.c
new file mode 100644
index 0000000..f2a5e28
--- /dev/null
+++ b/drivers/mtd/devices/ar2315.c
@@ -0,0 +1,459 @@
+
+/*
+ * MTD driver for the SPI Flash Memory support on Atheros AR2315
+ *
+ * Copyright (c) 2005-2006 Atheros Communications Inc.
+ * Copyright (C) 2006-2007 FON Technology, SL.
+ * Copyright (C) 2006-2007 Imre Kaloz <kaloz@openwrt.org>
+ * Copyright (C) 2006-2009 Felix Fietkau <nbd@openwrt.org>
+ * Copyright (C) 2012 Alexandros C. Couloumbis <alex@ozo.com>
+ *
+ * This code 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/kernel.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/slab.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/partitions.h>
+#include <linux/platform_device.h>
+#include <linux/sched.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/mutex.h>
+
+#include "ar2315_spiflash.h"
+
+#define DRIVER_NAME "ar2315-spiflash"
+
+#define busy_wait(_priv, _condition, _wait) do { \
+	while (_condition) { \
+		if (_wait > 1) \
+			msleep(_wait); \
+		else if ((_wait == 1) && need_resched()) \
+			schedule(); \
+		else \
+			udelay(1); \
+	} \
+} while (0)
+
+enum {
+	FLASH_NONE,
+	FLASH_1MB,
+	FLASH_2MB,
+	FLASH_4MB,
+	FLASH_8MB,
+	FLASH_16MB,
+};
+
+/* Flash configuration table */
+struct flashconfig {
+	u32 byte_cnt;
+	u32 sector_cnt;
+	u32 sector_size;
+};
+
+static const struct flashconfig flashconfig_tbl[] = {
+	[FLASH_NONE] = { 0, 0, 0},
+	[FLASH_1MB]  = { STM_1MB_BYTE_COUNT, STM_1MB_SECTOR_COUNT,
+			 STM_1MB_SECTOR_SIZE},
+	[FLASH_2MB]  = { STM_2MB_BYTE_COUNT, STM_2MB_SECTOR_COUNT,
+			 STM_2MB_SECTOR_SIZE},
+	[FLASH_4MB]  = { STM_4MB_BYTE_COUNT, STM_4MB_SECTOR_COUNT,
+			 STM_4MB_SECTOR_SIZE},
+	[FLASH_8MB]  = { STM_8MB_BYTE_COUNT, STM_8MB_SECTOR_COUNT,
+			 STM_8MB_SECTOR_SIZE},
+	[FLASH_16MB] = { STM_16MB_BYTE_COUNT, STM_16MB_SECTOR_COUNT,
+			 STM_16MB_SECTOR_SIZE}
+};
+
+/* Mapping of generic opcodes to STM serial flash opcodes */
+enum {
+	SPI_WRITE_ENABLE,
+	SPI_WRITE_DISABLE,
+	SPI_RD_STATUS,
+	SPI_WR_STATUS,
+	SPI_RD_DATA,
+	SPI_FAST_RD_DATA,
+	SPI_PAGE_PROGRAM,
+	SPI_SECTOR_ERASE,
+	SPI_BULK_ERASE,
+	SPI_DEEP_PWRDOWN,
+	SPI_RD_SIG,
+};
+
+struct opcodes {
+	__u16 code;
+	__s8 tx_cnt;
+	__s8 rx_cnt;
+};
+
+static const struct opcodes stm_opcodes[] = {
+	[SPI_WRITE_ENABLE] = {STM_OP_WR_ENABLE, 1, 0},
+	[SPI_WRITE_DISABLE] = {STM_OP_WR_DISABLE, 1, 0},
+	[SPI_RD_STATUS] = {STM_OP_RD_STATUS, 1, 1},
+	[SPI_WR_STATUS] = {STM_OP_WR_STATUS, 1, 0},
+	[SPI_RD_DATA] = {STM_OP_RD_DATA, 4, 4},
+	[SPI_FAST_RD_DATA] = {STM_OP_FAST_RD_DATA, 5, 0},
+	[SPI_PAGE_PROGRAM] = {STM_OP_PAGE_PGRM, 8, 0},
+	[SPI_SECTOR_ERASE] = {STM_OP_SECTOR_ERASE, 4, 0},
+	[SPI_BULK_ERASE] = {STM_OP_BULK_ERASE, 1, 0},
+	[SPI_DEEP_PWRDOWN] = {STM_OP_DEEP_PWRDOWN, 1, 0},
+	[SPI_RD_SIG] = {STM_OP_RD_SIG, 4, 1},
+};
+
+/* Driver private data structure */
+struct spiflash_priv {
+	struct mtd_info mtd;
+	void __iomem *readaddr; /* memory mapped data for read  */
+	void __iomem *mmraddr;  /* memory mapped register space */
+	struct mutex lock;	/* serialize registers access */
+};
+
+#define to_spiflash(_mtd) container_of(_mtd, struct spiflash_priv, mtd)
+
+enum {
+	FL_READY,
+	FL_READING,
+	FL_ERASING,
+	FL_WRITING
+};
+
+/*****************************************************************************/
+
+static u32
+spiflash_read_reg(struct spiflash_priv *priv, int reg)
+{
+	return ioread32(priv->mmraddr + reg);
+}
+
+static void
+spiflash_write_reg(struct spiflash_priv *priv, int reg, u32 data)
+{
+	iowrite32(data, priv->mmraddr + reg);
+}
+
+static u32
+spiflash_wait_busy(struct spiflash_priv *priv)
+{
+	u32 reg;
+
+	busy_wait(priv, (reg = spiflash_read_reg(priv, SPI_FLASH_CTL)) &
+		SPI_CTL_BUSY, 0);
+	return reg;
+}
+
+static u32
+spiflash_sendcmd(struct spiflash_priv *priv, int opcode, u32 addr)
+{
+	const struct opcodes *op;
+	u32 reg, mask;
+
+	op = &stm_opcodes[opcode];
+	reg = spiflash_wait_busy(priv);
+	spiflash_write_reg(priv, SPI_FLASH_OPCODE,
+			   ((u32)op->code) | (addr << 8));
+
+	reg &= ~SPI_CTL_TX_RX_CNT_MASK;
+	reg |= SPI_CTL_START | op->tx_cnt | (op->rx_cnt << 4);
+
+	spiflash_write_reg(priv, SPI_FLASH_CTL, reg);
+	spiflash_wait_busy(priv);
+
+	if (!op->rx_cnt)
+		return 0;
+
+	reg = spiflash_read_reg(priv, SPI_FLASH_DATA);
+
+	switch (op->rx_cnt) {
+	case 1:
+		mask = 0x000000ff;
+		break;
+	case 2:
+		mask = 0x0000ffff;
+		break;
+	case 3:
+		mask = 0x00ffffff;
+		break;
+	default:
+		mask = 0xffffffff;
+		break;
+	}
+	reg &= mask;
+
+	return reg;
+}
+
+/*
+ * Probe SPI flash device
+ * Function returns 0 for failure.
+ * and flashconfig_tbl array index for success.
+ */
+static int
+spiflash_probe_chip(struct platform_device *pdev, struct spiflash_priv *priv)
+{
+	u32 sig = spiflash_sendcmd(priv, SPI_RD_SIG, 0);
+	int flash_size;
+
+	switch (sig) {
+	case STM_8MBIT_SIGNATURE:
+		flash_size = FLASH_1MB;
+		break;
+	case STM_16MBIT_SIGNATURE:
+		flash_size = FLASH_2MB;
+		break;
+	case STM_32MBIT_SIGNATURE:
+		flash_size = FLASH_4MB;
+		break;
+	case STM_64MBIT_SIGNATURE:
+		flash_size = FLASH_8MB;
+		break;
+	case STM_128MBIT_SIGNATURE:
+		flash_size = FLASH_16MB;
+		break;
+	default:
+		dev_warn(&pdev->dev, "read of flash device signature failed!\n");
+		return 0;
+	}
+
+	return flash_size;
+}
+
+static void
+spiflash_wait_complete(struct spiflash_priv *priv, unsigned int timeout)
+{
+	busy_wait(priv, spiflash_sendcmd(priv, SPI_RD_STATUS, 0) &
+		SPI_STATUS_WIP, timeout);
+}
+
+static int
+spiflash_erase(struct mtd_info *mtd, struct erase_info *instr)
+{
+	struct spiflash_priv *priv = to_spiflash(mtd);
+	const struct opcodes *op;
+	u32 temp, reg;
+
+	if (instr->addr + instr->len > mtd->size)
+		return -EINVAL;
+
+	mutex_lock(&priv->lock);
+
+	spiflash_sendcmd(priv, SPI_WRITE_ENABLE, 0);
+	reg = spiflash_wait_busy(priv);
+
+	op = &stm_opcodes[SPI_SECTOR_ERASE];
+	temp = ((u32)instr->addr << 8) | (u32)(op->code);
+	spiflash_write_reg(priv, SPI_FLASH_OPCODE, temp);
+
+	reg &= ~SPI_CTL_TX_RX_CNT_MASK;
+	reg |= op->tx_cnt | SPI_CTL_START;
+	spiflash_write_reg(priv, SPI_FLASH_CTL, reg);
+
+	spiflash_wait_complete(priv, 20);
+
+	mutex_unlock(&priv->lock);
+
+	instr->state = MTD_ERASE_DONE;
+	mtd_erase_callback(instr);
+
+	return 0;
+}
+
+static int
+spiflash_read(struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen,
+	      u_char *buf)
+{
+	struct spiflash_priv *priv = to_spiflash(mtd);
+
+	if (!len)
+		return 0;
+
+	if (from + len > mtd->size)
+		return -EINVAL;
+
+	*retlen = len;
+
+	mutex_lock(&priv->lock);
+
+	memcpy_fromio(buf, priv->readaddr + from, len);
+
+	mutex_unlock(&priv->lock);
+
+	return 0;
+}
+
+static int
+spiflash_write(struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen,
+	       const u8 *buf)
+{
+	struct spiflash_priv *priv = to_spiflash(mtd);
+	u32 opcode, bytes_left;
+
+	*retlen = 0;
+
+	if (!len)
+		return 0;
+
+	if (to + len > mtd->size)
+		return -EINVAL;
+
+	bytes_left = len;
+
+	do {
+		u32 read_len, reg, page_offset, spi_data = 0;
+
+		read_len = min(bytes_left, sizeof(u32));
+
+		/* 32-bit writes cannot span across a page boundary
+		 * (256 bytes). This types of writes require two page
+		 * program operations to handle it correctly. The STM part
+		 * will write the overflow data to the beginning of the
+		 * current page as opposed to the subsequent page.
+		 */
+		page_offset = (to & (STM_PAGE_SIZE - 1)) + read_len;
+
+		if (page_offset > STM_PAGE_SIZE)
+			read_len -= (page_offset - STM_PAGE_SIZE);
+
+		mutex_lock(&priv->lock);
+
+		spiflash_sendcmd(priv, SPI_WRITE_ENABLE, 0);
+		spi_data = 0;
+		switch (read_len) {
+		case 4:
+			spi_data |= buf[3] << 24;
+			/* fall through */
+		case 3:
+			spi_data |= buf[2] << 16;
+			/* fall through */
+		case 2:
+			spi_data |= buf[1] << 8;
+			/* fall through */
+		case 1:
+			spi_data |= buf[0] & 0xff;
+			break;
+		default:
+			break;
+		}
+
+		spiflash_write_reg(priv, SPI_FLASH_DATA, spi_data);
+		opcode = stm_opcodes[SPI_PAGE_PROGRAM].code |
+			(to & 0x00ffffff) << 8;
+		spiflash_write_reg(priv, SPI_FLASH_OPCODE, opcode);
+
+		reg = spiflash_read_reg(priv, SPI_FLASH_CTL);
+		reg &= ~SPI_CTL_TX_RX_CNT_MASK;
+		reg |= (read_len + 4) | SPI_CTL_START;
+		spiflash_write_reg(priv, SPI_FLASH_CTL, reg);
+
+		spiflash_wait_complete(priv, 1);
+
+		mutex_unlock(&priv->lock);
+
+		bytes_left -= read_len;
+		to += read_len;
+		buf += read_len;
+
+		*retlen += read_len;
+	} while (bytes_left != 0);
+
+	return 0;
+}
+
+#if defined CONFIG_MTD_REDBOOT_PARTS || CONFIG_MTD_MYLOADER_PARTS
+static const char * const part_probe_types[] = {
+	"cmdlinepart", "RedBoot", "MyLoader", NULL
+};
+#endif
+
+static int
+spiflash_probe(struct platform_device *pdev)
+{
+	struct spiflash_priv *priv;
+	struct mtd_info *mtd;
+	struct resource *res;
+	int index;
+	int result = 0;
+
+	priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
+	if (!priv)
+		return -ENOMEM;
+
+	mutex_init(&priv->lock);
+	mtd = &priv->mtd;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+	priv->mmraddr = devm_ioremap_resource(&pdev->dev, res);
+	if (IS_ERR(priv->mmraddr)) {
+		dev_warn(&pdev->dev, "failed to map flash MMR\n");
+		return PTR_ERR(priv->mmraddr);
+	}
+
+	index = spiflash_probe_chip(pdev, priv);
+	if (!index) {
+		dev_warn(&pdev->dev, "found no flash device\n");
+		return -ENODEV;
+	}
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	priv->readaddr = devm_ioremap_resource(&pdev->dev, res);
+	if (IS_ERR(priv->readaddr)) {
+		dev_warn(&pdev->dev, "failed to map flash read mem\n");
+		return PTR_ERR(priv->readaddr);
+	}
+
+	platform_set_drvdata(pdev, priv);
+	mtd->name = "spiflash";
+	mtd->type = MTD_NORFLASH;
+	mtd->flags = (MTD_CAP_NORFLASH|MTD_WRITEABLE);
+	mtd->size = flashconfig_tbl[index].byte_cnt;
+	mtd->erasesize = flashconfig_tbl[index].sector_size;
+	mtd->writesize = 1;
+	mtd->numeraseregions = 0;
+	mtd->eraseregions = NULL;
+	mtd->_erase = spiflash_erase;
+	mtd->_read = spiflash_read;
+	mtd->_write = spiflash_write;
+	mtd->owner = THIS_MODULE;
+
+	dev_info(&pdev->dev, "%lld Kbytes flash detected\n", mtd->size >> 10);
+
+#if defined CONFIG_MTD_REDBOOT_PARTS || CONFIG_MTD_MYLOADER_PARTS
+	/* parse redboot partitions */
+
+	result = mtd_device_parse_register(mtd, part_probe_types,
+					   NULL, NULL, 0);
+#endif
+
+	return result;
+}
+
+static int
+spiflash_remove(struct platform_device *pdev)
+{
+	struct spiflash_priv *priv = platform_get_drvdata(pdev);
+
+	mtd_device_unregister(&priv->mtd);
+
+	return 0;
+}
+
+static struct platform_driver spiflash_driver = {
+	.driver.name = DRIVER_NAME,
+	.probe = spiflash_probe,
+	.remove = spiflash_remove,
+};
+
+module_platform_driver(spiflash_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("OpenWrt.org");
+MODULE_AUTHOR("Atheros Communications Inc");
+MODULE_DESCRIPTION("MTD driver for SPI Flash on Atheros AR2315+ SOC");
+MODULE_ALIAS("platform:" DRIVER_NAME);
+
diff --git a/drivers/mtd/devices/ar2315_spiflash.h b/drivers/mtd/devices/ar2315_spiflash.h
new file mode 100644
index 0000000..17b0903
--- /dev/null
+++ b/drivers/mtd/devices/ar2315_spiflash.h
@@ -0,0 +1,106 @@
+/*
+ * Atheros AR2315 SPI Flash Memory support header file.
+ *
+ * Copyright (c) 2005, Atheros Communications Inc.
+ * Copyright (C) 2006 FON Technology, SL.
+ * Copyright (C) 2006 Imre Kaloz <kaloz@openwrt.org>
+ * Copyright (C) 2006-2009 Felix Fietkau <nbd@openwrt.org>
+ *
+ * This code 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 __AR2315_SPIFLASH_H
+#define __AR2315_SPIFLASH_H
+
+#define STM_PAGE_SIZE           256
+
+#define SFI_WRITE_BUFFER_SIZE   4
+#define SFI_FLASH_ADDR_MASK     0x00ffffff
+
+#define STM_8MBIT_SIGNATURE     0x13
+#define STM_M25P80_BYTE_COUNT   1048576
+#define STM_M25P80_SECTOR_COUNT 16
+#define STM_M25P80_SECTOR_SIZE  0x10000
+
+#define STM_16MBIT_SIGNATURE    0x14
+#define STM_M25P16_BYTE_COUNT   2097152
+#define STM_M25P16_SECTOR_COUNT 32
+#define STM_M25P16_SECTOR_SIZE  0x10000
+
+#define STM_32MBIT_SIGNATURE    0x15
+#define STM_M25P32_BYTE_COUNT   4194304
+#define STM_M25P32_SECTOR_COUNT 64
+#define STM_M25P32_SECTOR_SIZE  0x10000
+
+#define STM_64MBIT_SIGNATURE    0x16
+#define STM_M25P64_BYTE_COUNT   8388608
+#define STM_M25P64_SECTOR_COUNT 128
+#define STM_M25P64_SECTOR_SIZE  0x10000
+
+#define STM_128MBIT_SIGNATURE   0x17
+#define STM_M25P128_BYTE_COUNT   16777216
+#define STM_M25P128_SECTOR_COUNT 256
+#define STM_M25P128_SECTOR_SIZE  0x10000
+
+#define STM_1MB_BYTE_COUNT   STM_M25P80_BYTE_COUNT
+#define STM_1MB_SECTOR_COUNT STM_M25P80_SECTOR_COUNT
+#define STM_1MB_SECTOR_SIZE  STM_M25P80_SECTOR_SIZE
+#define STM_2MB_BYTE_COUNT   STM_M25P16_BYTE_COUNT
+#define STM_2MB_SECTOR_COUNT STM_M25P16_SECTOR_COUNT
+#define STM_2MB_SECTOR_SIZE  STM_M25P16_SECTOR_SIZE
+#define STM_4MB_BYTE_COUNT   STM_M25P32_BYTE_COUNT
+#define STM_4MB_SECTOR_COUNT STM_M25P32_SECTOR_COUNT
+#define STM_4MB_SECTOR_SIZE  STM_M25P32_SECTOR_SIZE
+#define STM_8MB_BYTE_COUNT   STM_M25P64_BYTE_COUNT
+#define STM_8MB_SECTOR_COUNT STM_M25P64_SECTOR_COUNT
+#define STM_8MB_SECTOR_SIZE  STM_M25P64_SECTOR_SIZE
+#define STM_16MB_BYTE_COUNT   STM_M25P128_BYTE_COUNT
+#define STM_16MB_SECTOR_COUNT STM_M25P128_SECTOR_COUNT
+#define STM_16MB_SECTOR_SIZE  STM_M25P128_SECTOR_SIZE
+
+/*
+ * ST Microelectronics Opcodes for Serial Flash
+ */
+
+#define STM_OP_WR_ENABLE       0x06     /* Write Enable */
+#define STM_OP_WR_DISABLE      0x04     /* Write Disable */
+#define STM_OP_RD_STATUS       0x05     /* Read Status */
+#define STM_OP_WR_STATUS       0x01     /* Write Status */
+#define STM_OP_RD_DATA         0x03     /* Read Data */
+#define STM_OP_FAST_RD_DATA    0x0b     /* Fast Read Data */
+#define STM_OP_PAGE_PGRM       0x02     /* Page Program */
+#define STM_OP_SECTOR_ERASE    0xd8     /* Sector Erase */
+#define STM_OP_BULK_ERASE      0xc7     /* Bulk Erase */
+#define STM_OP_DEEP_PWRDOWN    0xb9     /* Deep Power-Down Mode */
+#define STM_OP_RD_SIG          0xab     /* Read Electronic Signature */
+
+#define STM_STATUS_WIP       0x01       /* Write-In-Progress */
+#define STM_STATUS_WEL       0x02       /* Write Enable Latch */
+#define STM_STATUS_BP0       0x04       /* Block Protect 0 */
+#define STM_STATUS_BP1       0x08       /* Block Protect 1 */
+#define STM_STATUS_BP2       0x10       /* Block Protect 2 */
+#define STM_STATUS_SRWD      0x80       /* Status Register Write Disable */
+
+/*
+ * SPI Flash Interface Registers
+ */
+
+#define SPI_FLASH_CTL           0x00
+#define SPI_FLASH_OPCODE        0x04
+#define SPI_FLASH_DATA          0x08
+
+#define SPI_CTL_START           0x00000100
+#define SPI_CTL_BUSY            0x00010000
+#define SPI_CTL_TXCNT_MASK      0x0000000f
+#define SPI_CTL_RXCNT_MASK      0x000000f0
+#define SPI_CTL_TX_RX_CNT_MASK  0x000000ff
+#define SPI_CTL_SIZE_MASK       0x00060000
+
+#define SPI_CTL_CLK_SEL_MASK    0x03000000
+#define SPI_OPCODE_MASK         0x000000ff
+
+#define SPI_STATUS_WIP		STM_STATUS_WIP
+
+#endif
-- 
1.8.5.5

^ permalink raw reply related	[flat|nested] 37+ messages in thread

* [PATCH 11/16] mtd: add Atheros AR2315 SPI Flash driver
@ 2014-09-28 18:33   ` Sergey Ryazanov
  0 siblings, 0 replies; 37+ messages in thread
From: Sergey Ryazanov @ 2014-09-28 18:33 UTC (permalink / raw)
  To: Ralf Baechle; +Cc: Linux MIPS, Brian Norris, David Woodhouse, linux-mtd

Atheros AR2315 SoC have a SPI Flash unit with hybrid flash access: flash
read is performed via memory mapping, on the other hand flash write is
performed by explicitly issued SPI command.

Signed-off-by: Sergey Ryazanov <ryazanov.s.a@gmail.com>
Cc: David Woodhouse <dwmw2@infradead.org>
Cc: Brian Norris <computersforpeace@gmail.com>
Cc: linux-mtd@lists.infradead.org
---
This driver is not ready for merging since it should be rewrited using
spi-nor framework.

Changes since RFC:
  - move device registration to separate patch

 drivers/mtd/devices/Kconfig           |   5 +
 drivers/mtd/devices/Makefile          |   1 +
 drivers/mtd/devices/ar2315.c          | 459 ++++++++++++++++++++++++++++++++++
 drivers/mtd/devices/ar2315_spiflash.h | 106 ++++++++
 4 files changed, 571 insertions(+)
 create mode 100644 drivers/mtd/devices/ar2315.c
 create mode 100644 drivers/mtd/devices/ar2315_spiflash.h

diff --git a/drivers/mtd/devices/Kconfig b/drivers/mtd/devices/Kconfig
index c49d0b1..9533867 100644
--- a/drivers/mtd/devices/Kconfig
+++ b/drivers/mtd/devices/Kconfig
@@ -112,6 +112,11 @@ config MTD_SST25L
 	  Set up your spi devices with the right board-specific platform data,
 	  if you want to specify device partitioning.
 
+config MTD_AR2315
+	tristate "Atheros AR2315+ SPI Flash support"
+	depends on SOC_AR2315
+	default y
+
 config MTD_BCM47XXSFLASH
 	tristate "R/O support for serial flash on BCMA bus"
 	depends on BCMA_SFLASH
diff --git a/drivers/mtd/devices/Makefile b/drivers/mtd/devices/Makefile
index c68868f..eaec8fb 100644
--- a/drivers/mtd/devices/Makefile
+++ b/drivers/mtd/devices/Makefile
@@ -15,6 +15,7 @@ obj-$(CONFIG_MTD_M25P80)	+= m25p80.o
 obj-$(CONFIG_MTD_NAND_OMAP_BCH)	+= elm.o
 obj-$(CONFIG_MTD_SPEAR_SMI)	+= spear_smi.o
 obj-$(CONFIG_MTD_SST25L)	+= sst25l.o
+obj-$(CONFIG_MTD_AR2315)	+= ar2315.o
 obj-$(CONFIG_MTD_BCM47XXSFLASH)	+= bcm47xxsflash.o
 obj-$(CONFIG_MTD_ST_SPI_FSM)    += st_spi_fsm.o
 
diff --git a/drivers/mtd/devices/ar2315.c b/drivers/mtd/devices/ar2315.c
new file mode 100644
index 0000000..f2a5e28
--- /dev/null
+++ b/drivers/mtd/devices/ar2315.c
@@ -0,0 +1,459 @@
+
+/*
+ * MTD driver for the SPI Flash Memory support on Atheros AR2315
+ *
+ * Copyright (c) 2005-2006 Atheros Communications Inc.
+ * Copyright (C) 2006-2007 FON Technology, SL.
+ * Copyright (C) 2006-2007 Imre Kaloz <kaloz@openwrt.org>
+ * Copyright (C) 2006-2009 Felix Fietkau <nbd@openwrt.org>
+ * Copyright (C) 2012 Alexandros C. Couloumbis <alex@ozo.com>
+ *
+ * This code 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/kernel.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/slab.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/partitions.h>
+#include <linux/platform_device.h>
+#include <linux/sched.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/mutex.h>
+
+#include "ar2315_spiflash.h"
+
+#define DRIVER_NAME "ar2315-spiflash"
+
+#define busy_wait(_priv, _condition, _wait) do { \
+	while (_condition) { \
+		if (_wait > 1) \
+			msleep(_wait); \
+		else if ((_wait == 1) && need_resched()) \
+			schedule(); \
+		else \
+			udelay(1); \
+	} \
+} while (0)
+
+enum {
+	FLASH_NONE,
+	FLASH_1MB,
+	FLASH_2MB,
+	FLASH_4MB,
+	FLASH_8MB,
+	FLASH_16MB,
+};
+
+/* Flash configuration table */
+struct flashconfig {
+	u32 byte_cnt;
+	u32 sector_cnt;
+	u32 sector_size;
+};
+
+static const struct flashconfig flashconfig_tbl[] = {
+	[FLASH_NONE] = { 0, 0, 0},
+	[FLASH_1MB]  = { STM_1MB_BYTE_COUNT, STM_1MB_SECTOR_COUNT,
+			 STM_1MB_SECTOR_SIZE},
+	[FLASH_2MB]  = { STM_2MB_BYTE_COUNT, STM_2MB_SECTOR_COUNT,
+			 STM_2MB_SECTOR_SIZE},
+	[FLASH_4MB]  = { STM_4MB_BYTE_COUNT, STM_4MB_SECTOR_COUNT,
+			 STM_4MB_SECTOR_SIZE},
+	[FLASH_8MB]  = { STM_8MB_BYTE_COUNT, STM_8MB_SECTOR_COUNT,
+			 STM_8MB_SECTOR_SIZE},
+	[FLASH_16MB] = { STM_16MB_BYTE_COUNT, STM_16MB_SECTOR_COUNT,
+			 STM_16MB_SECTOR_SIZE}
+};
+
+/* Mapping of generic opcodes to STM serial flash opcodes */
+enum {
+	SPI_WRITE_ENABLE,
+	SPI_WRITE_DISABLE,
+	SPI_RD_STATUS,
+	SPI_WR_STATUS,
+	SPI_RD_DATA,
+	SPI_FAST_RD_DATA,
+	SPI_PAGE_PROGRAM,
+	SPI_SECTOR_ERASE,
+	SPI_BULK_ERASE,
+	SPI_DEEP_PWRDOWN,
+	SPI_RD_SIG,
+};
+
+struct opcodes {
+	__u16 code;
+	__s8 tx_cnt;
+	__s8 rx_cnt;
+};
+
+static const struct opcodes stm_opcodes[] = {
+	[SPI_WRITE_ENABLE] = {STM_OP_WR_ENABLE, 1, 0},
+	[SPI_WRITE_DISABLE] = {STM_OP_WR_DISABLE, 1, 0},
+	[SPI_RD_STATUS] = {STM_OP_RD_STATUS, 1, 1},
+	[SPI_WR_STATUS] = {STM_OP_WR_STATUS, 1, 0},
+	[SPI_RD_DATA] = {STM_OP_RD_DATA, 4, 4},
+	[SPI_FAST_RD_DATA] = {STM_OP_FAST_RD_DATA, 5, 0},
+	[SPI_PAGE_PROGRAM] = {STM_OP_PAGE_PGRM, 8, 0},
+	[SPI_SECTOR_ERASE] = {STM_OP_SECTOR_ERASE, 4, 0},
+	[SPI_BULK_ERASE] = {STM_OP_BULK_ERASE, 1, 0},
+	[SPI_DEEP_PWRDOWN] = {STM_OP_DEEP_PWRDOWN, 1, 0},
+	[SPI_RD_SIG] = {STM_OP_RD_SIG, 4, 1},
+};
+
+/* Driver private data structure */
+struct spiflash_priv {
+	struct mtd_info mtd;
+	void __iomem *readaddr; /* memory mapped data for read  */
+	void __iomem *mmraddr;  /* memory mapped register space */
+	struct mutex lock;	/* serialize registers access */
+};
+
+#define to_spiflash(_mtd) container_of(_mtd, struct spiflash_priv, mtd)
+
+enum {
+	FL_READY,
+	FL_READING,
+	FL_ERASING,
+	FL_WRITING
+};
+
+/*****************************************************************************/
+
+static u32
+spiflash_read_reg(struct spiflash_priv *priv, int reg)
+{
+	return ioread32(priv->mmraddr + reg);
+}
+
+static void
+spiflash_write_reg(struct spiflash_priv *priv, int reg, u32 data)
+{
+	iowrite32(data, priv->mmraddr + reg);
+}
+
+static u32
+spiflash_wait_busy(struct spiflash_priv *priv)
+{
+	u32 reg;
+
+	busy_wait(priv, (reg = spiflash_read_reg(priv, SPI_FLASH_CTL)) &
+		SPI_CTL_BUSY, 0);
+	return reg;
+}
+
+static u32
+spiflash_sendcmd(struct spiflash_priv *priv, int opcode, u32 addr)
+{
+	const struct opcodes *op;
+	u32 reg, mask;
+
+	op = &stm_opcodes[opcode];
+	reg = spiflash_wait_busy(priv);
+	spiflash_write_reg(priv, SPI_FLASH_OPCODE,
+			   ((u32)op->code) | (addr << 8));
+
+	reg &= ~SPI_CTL_TX_RX_CNT_MASK;
+	reg |= SPI_CTL_START | op->tx_cnt | (op->rx_cnt << 4);
+
+	spiflash_write_reg(priv, SPI_FLASH_CTL, reg);
+	spiflash_wait_busy(priv);
+
+	if (!op->rx_cnt)
+		return 0;
+
+	reg = spiflash_read_reg(priv, SPI_FLASH_DATA);
+
+	switch (op->rx_cnt) {
+	case 1:
+		mask = 0x000000ff;
+		break;
+	case 2:
+		mask = 0x0000ffff;
+		break;
+	case 3:
+		mask = 0x00ffffff;
+		break;
+	default:
+		mask = 0xffffffff;
+		break;
+	}
+	reg &= mask;
+
+	return reg;
+}
+
+/*
+ * Probe SPI flash device
+ * Function returns 0 for failure.
+ * and flashconfig_tbl array index for success.
+ */
+static int
+spiflash_probe_chip(struct platform_device *pdev, struct spiflash_priv *priv)
+{
+	u32 sig = spiflash_sendcmd(priv, SPI_RD_SIG, 0);
+	int flash_size;
+
+	switch (sig) {
+	case STM_8MBIT_SIGNATURE:
+		flash_size = FLASH_1MB;
+		break;
+	case STM_16MBIT_SIGNATURE:
+		flash_size = FLASH_2MB;
+		break;
+	case STM_32MBIT_SIGNATURE:
+		flash_size = FLASH_4MB;
+		break;
+	case STM_64MBIT_SIGNATURE:
+		flash_size = FLASH_8MB;
+		break;
+	case STM_128MBIT_SIGNATURE:
+		flash_size = FLASH_16MB;
+		break;
+	default:
+		dev_warn(&pdev->dev, "read of flash device signature failed!\n");
+		return 0;
+	}
+
+	return flash_size;
+}
+
+static void
+spiflash_wait_complete(struct spiflash_priv *priv, unsigned int timeout)
+{
+	busy_wait(priv, spiflash_sendcmd(priv, SPI_RD_STATUS, 0) &
+		SPI_STATUS_WIP, timeout);
+}
+
+static int
+spiflash_erase(struct mtd_info *mtd, struct erase_info *instr)
+{
+	struct spiflash_priv *priv = to_spiflash(mtd);
+	const struct opcodes *op;
+	u32 temp, reg;
+
+	if (instr->addr + instr->len > mtd->size)
+		return -EINVAL;
+
+	mutex_lock(&priv->lock);
+
+	spiflash_sendcmd(priv, SPI_WRITE_ENABLE, 0);
+	reg = spiflash_wait_busy(priv);
+
+	op = &stm_opcodes[SPI_SECTOR_ERASE];
+	temp = ((u32)instr->addr << 8) | (u32)(op->code);
+	spiflash_write_reg(priv, SPI_FLASH_OPCODE, temp);
+
+	reg &= ~SPI_CTL_TX_RX_CNT_MASK;
+	reg |= op->tx_cnt | SPI_CTL_START;
+	spiflash_write_reg(priv, SPI_FLASH_CTL, reg);
+
+	spiflash_wait_complete(priv, 20);
+
+	mutex_unlock(&priv->lock);
+
+	instr->state = MTD_ERASE_DONE;
+	mtd_erase_callback(instr);
+
+	return 0;
+}
+
+static int
+spiflash_read(struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen,
+	      u_char *buf)
+{
+	struct spiflash_priv *priv = to_spiflash(mtd);
+
+	if (!len)
+		return 0;
+
+	if (from + len > mtd->size)
+		return -EINVAL;
+
+	*retlen = len;
+
+	mutex_lock(&priv->lock);
+
+	memcpy_fromio(buf, priv->readaddr + from, len);
+
+	mutex_unlock(&priv->lock);
+
+	return 0;
+}
+
+static int
+spiflash_write(struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen,
+	       const u8 *buf)
+{
+	struct spiflash_priv *priv = to_spiflash(mtd);
+	u32 opcode, bytes_left;
+
+	*retlen = 0;
+
+	if (!len)
+		return 0;
+
+	if (to + len > mtd->size)
+		return -EINVAL;
+
+	bytes_left = len;
+
+	do {
+		u32 read_len, reg, page_offset, spi_data = 0;
+
+		read_len = min(bytes_left, sizeof(u32));
+
+		/* 32-bit writes cannot span across a page boundary
+		 * (256 bytes). This types of writes require two page
+		 * program operations to handle it correctly. The STM part
+		 * will write the overflow data to the beginning of the
+		 * current page as opposed to the subsequent page.
+		 */
+		page_offset = (to & (STM_PAGE_SIZE - 1)) + read_len;
+
+		if (page_offset > STM_PAGE_SIZE)
+			read_len -= (page_offset - STM_PAGE_SIZE);
+
+		mutex_lock(&priv->lock);
+
+		spiflash_sendcmd(priv, SPI_WRITE_ENABLE, 0);
+		spi_data = 0;
+		switch (read_len) {
+		case 4:
+			spi_data |= buf[3] << 24;
+			/* fall through */
+		case 3:
+			spi_data |= buf[2] << 16;
+			/* fall through */
+		case 2:
+			spi_data |= buf[1] << 8;
+			/* fall through */
+		case 1:
+			spi_data |= buf[0] & 0xff;
+			break;
+		default:
+			break;
+		}
+
+		spiflash_write_reg(priv, SPI_FLASH_DATA, spi_data);
+		opcode = stm_opcodes[SPI_PAGE_PROGRAM].code |
+			(to & 0x00ffffff) << 8;
+		spiflash_write_reg(priv, SPI_FLASH_OPCODE, opcode);
+
+		reg = spiflash_read_reg(priv, SPI_FLASH_CTL);
+		reg &= ~SPI_CTL_TX_RX_CNT_MASK;
+		reg |= (read_len + 4) | SPI_CTL_START;
+		spiflash_write_reg(priv, SPI_FLASH_CTL, reg);
+
+		spiflash_wait_complete(priv, 1);
+
+		mutex_unlock(&priv->lock);
+
+		bytes_left -= read_len;
+		to += read_len;
+		buf += read_len;
+
+		*retlen += read_len;
+	} while (bytes_left != 0);
+
+	return 0;
+}
+
+#if defined CONFIG_MTD_REDBOOT_PARTS || CONFIG_MTD_MYLOADER_PARTS
+static const char * const part_probe_types[] = {
+	"cmdlinepart", "RedBoot", "MyLoader", NULL
+};
+#endif
+
+static int
+spiflash_probe(struct platform_device *pdev)
+{
+	struct spiflash_priv *priv;
+	struct mtd_info *mtd;
+	struct resource *res;
+	int index;
+	int result = 0;
+
+	priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
+	if (!priv)
+		return -ENOMEM;
+
+	mutex_init(&priv->lock);
+	mtd = &priv->mtd;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+	priv->mmraddr = devm_ioremap_resource(&pdev->dev, res);
+	if (IS_ERR(priv->mmraddr)) {
+		dev_warn(&pdev->dev, "failed to map flash MMR\n");
+		return PTR_ERR(priv->mmraddr);
+	}
+
+	index = spiflash_probe_chip(pdev, priv);
+	if (!index) {
+		dev_warn(&pdev->dev, "found no flash device\n");
+		return -ENODEV;
+	}
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	priv->readaddr = devm_ioremap_resource(&pdev->dev, res);
+	if (IS_ERR(priv->readaddr)) {
+		dev_warn(&pdev->dev, "failed to map flash read mem\n");
+		return PTR_ERR(priv->readaddr);
+	}
+
+	platform_set_drvdata(pdev, priv);
+	mtd->name = "spiflash";
+	mtd->type = MTD_NORFLASH;
+	mtd->flags = (MTD_CAP_NORFLASH|MTD_WRITEABLE);
+	mtd->size = flashconfig_tbl[index].byte_cnt;
+	mtd->erasesize = flashconfig_tbl[index].sector_size;
+	mtd->writesize = 1;
+	mtd->numeraseregions = 0;
+	mtd->eraseregions = NULL;
+	mtd->_erase = spiflash_erase;
+	mtd->_read = spiflash_read;
+	mtd->_write = spiflash_write;
+	mtd->owner = THIS_MODULE;
+
+	dev_info(&pdev->dev, "%lld Kbytes flash detected\n", mtd->size >> 10);
+
+#if defined CONFIG_MTD_REDBOOT_PARTS || CONFIG_MTD_MYLOADER_PARTS
+	/* parse redboot partitions */
+
+	result = mtd_device_parse_register(mtd, part_probe_types,
+					   NULL, NULL, 0);
+#endif
+
+	return result;
+}
+
+static int
+spiflash_remove(struct platform_device *pdev)
+{
+	struct spiflash_priv *priv = platform_get_drvdata(pdev);
+
+	mtd_device_unregister(&priv->mtd);
+
+	return 0;
+}
+
+static struct platform_driver spiflash_driver = {
+	.driver.name = DRIVER_NAME,
+	.probe = spiflash_probe,
+	.remove = spiflash_remove,
+};
+
+module_platform_driver(spiflash_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("OpenWrt.org");
+MODULE_AUTHOR("Atheros Communications Inc");
+MODULE_DESCRIPTION("MTD driver for SPI Flash on Atheros AR2315+ SOC");
+MODULE_ALIAS("platform:" DRIVER_NAME);
+
diff --git a/drivers/mtd/devices/ar2315_spiflash.h b/drivers/mtd/devices/ar2315_spiflash.h
new file mode 100644
index 0000000..17b0903
--- /dev/null
+++ b/drivers/mtd/devices/ar2315_spiflash.h
@@ -0,0 +1,106 @@
+/*
+ * Atheros AR2315 SPI Flash Memory support header file.
+ *
+ * Copyright (c) 2005, Atheros Communications Inc.
+ * Copyright (C) 2006 FON Technology, SL.
+ * Copyright (C) 2006 Imre Kaloz <kaloz@openwrt.org>
+ * Copyright (C) 2006-2009 Felix Fietkau <nbd@openwrt.org>
+ *
+ * This code 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 __AR2315_SPIFLASH_H
+#define __AR2315_SPIFLASH_H
+
+#define STM_PAGE_SIZE           256
+
+#define SFI_WRITE_BUFFER_SIZE   4
+#define SFI_FLASH_ADDR_MASK     0x00ffffff
+
+#define STM_8MBIT_SIGNATURE     0x13
+#define STM_M25P80_BYTE_COUNT   1048576
+#define STM_M25P80_SECTOR_COUNT 16
+#define STM_M25P80_SECTOR_SIZE  0x10000
+
+#define STM_16MBIT_SIGNATURE    0x14
+#define STM_M25P16_BYTE_COUNT   2097152
+#define STM_M25P16_SECTOR_COUNT 32
+#define STM_M25P16_SECTOR_SIZE  0x10000
+
+#define STM_32MBIT_SIGNATURE    0x15
+#define STM_M25P32_BYTE_COUNT   4194304
+#define STM_M25P32_SECTOR_COUNT 64
+#define STM_M25P32_SECTOR_SIZE  0x10000
+
+#define STM_64MBIT_SIGNATURE    0x16
+#define STM_M25P64_BYTE_COUNT   8388608
+#define STM_M25P64_SECTOR_COUNT 128
+#define STM_M25P64_SECTOR_SIZE  0x10000
+
+#define STM_128MBIT_SIGNATURE   0x17
+#define STM_M25P128_BYTE_COUNT   16777216
+#define STM_M25P128_SECTOR_COUNT 256
+#define STM_M25P128_SECTOR_SIZE  0x10000
+
+#define STM_1MB_BYTE_COUNT   STM_M25P80_BYTE_COUNT
+#define STM_1MB_SECTOR_COUNT STM_M25P80_SECTOR_COUNT
+#define STM_1MB_SECTOR_SIZE  STM_M25P80_SECTOR_SIZE
+#define STM_2MB_BYTE_COUNT   STM_M25P16_BYTE_COUNT
+#define STM_2MB_SECTOR_COUNT STM_M25P16_SECTOR_COUNT
+#define STM_2MB_SECTOR_SIZE  STM_M25P16_SECTOR_SIZE
+#define STM_4MB_BYTE_COUNT   STM_M25P32_BYTE_COUNT
+#define STM_4MB_SECTOR_COUNT STM_M25P32_SECTOR_COUNT
+#define STM_4MB_SECTOR_SIZE  STM_M25P32_SECTOR_SIZE
+#define STM_8MB_BYTE_COUNT   STM_M25P64_BYTE_COUNT
+#define STM_8MB_SECTOR_COUNT STM_M25P64_SECTOR_COUNT
+#define STM_8MB_SECTOR_SIZE  STM_M25P64_SECTOR_SIZE
+#define STM_16MB_BYTE_COUNT   STM_M25P128_BYTE_COUNT
+#define STM_16MB_SECTOR_COUNT STM_M25P128_SECTOR_COUNT
+#define STM_16MB_SECTOR_SIZE  STM_M25P128_SECTOR_SIZE
+
+/*
+ * ST Microelectronics Opcodes for Serial Flash
+ */
+
+#define STM_OP_WR_ENABLE       0x06     /* Write Enable */
+#define STM_OP_WR_DISABLE      0x04     /* Write Disable */
+#define STM_OP_RD_STATUS       0x05     /* Read Status */
+#define STM_OP_WR_STATUS       0x01     /* Write Status */
+#define STM_OP_RD_DATA         0x03     /* Read Data */
+#define STM_OP_FAST_RD_DATA    0x0b     /* Fast Read Data */
+#define STM_OP_PAGE_PGRM       0x02     /* Page Program */
+#define STM_OP_SECTOR_ERASE    0xd8     /* Sector Erase */
+#define STM_OP_BULK_ERASE      0xc7     /* Bulk Erase */
+#define STM_OP_DEEP_PWRDOWN    0xb9     /* Deep Power-Down Mode */
+#define STM_OP_RD_SIG          0xab     /* Read Electronic Signature */
+
+#define STM_STATUS_WIP       0x01       /* Write-In-Progress */
+#define STM_STATUS_WEL       0x02       /* Write Enable Latch */
+#define STM_STATUS_BP0       0x04       /* Block Protect 0 */
+#define STM_STATUS_BP1       0x08       /* Block Protect 1 */
+#define STM_STATUS_BP2       0x10       /* Block Protect 2 */
+#define STM_STATUS_SRWD      0x80       /* Status Register Write Disable */
+
+/*
+ * SPI Flash Interface Registers
+ */
+
+#define SPI_FLASH_CTL           0x00
+#define SPI_FLASH_OPCODE        0x04
+#define SPI_FLASH_DATA          0x08
+
+#define SPI_CTL_START           0x00000100
+#define SPI_CTL_BUSY            0x00010000
+#define SPI_CTL_TXCNT_MASK      0x0000000f
+#define SPI_CTL_RXCNT_MASK      0x000000f0
+#define SPI_CTL_TX_RX_CNT_MASK  0x000000ff
+#define SPI_CTL_SIZE_MASK       0x00060000
+
+#define SPI_CTL_CLK_SEL_MASK    0x03000000
+#define SPI_OPCODE_MASK         0x000000ff
+
+#define SPI_STATUS_WIP		STM_STATUS_WIP
+
+#endif
-- 
1.8.5.5

^ permalink raw reply related	[flat|nested] 37+ messages in thread

* [PATCH 12/16] watchdog: add Atheros AR2315 watchdog driver
  2014-09-28 18:32 [PATCH 00/16] MIPS: support for the Atheros AR231X SoCs Sergey Ryazanov
                   ` (10 preceding siblings ...)
  2014-09-28 18:33   ` Sergey Ryazanov
@ 2014-09-28 18:33 ` Sergey Ryazanov
  2014-09-28 21:35   ` Guenter Roeck
  2014-09-28 18:33 ` [PATCH 13/16] MIPS: ar231x: register various chip devices Sergey Ryazanov
                   ` (3 subsequent siblings)
  15 siblings, 1 reply; 37+ messages in thread
From: Sergey Ryazanov @ 2014-09-28 18:33 UTC (permalink / raw)
  To: Ralf Baechle; +Cc: Linux MIPS, Wim Van Sebroeck, linux-watchdog

Signed-off-by: Sergey Ryazanov <ryazanov.s.a@gmail.com>
Cc: Wim Van Sebroeck <wim@iguana.be>
Cc: linux-watchdog@vger.kernel.org
---

Changes since RFC:
  - use watchdog infrastructure
  - remove deprecated IRQF_DISABLED flag
  - move device registration to separate patch

 drivers/watchdog/Kconfig      |   8 ++
 drivers/watchdog/Makefile     |   1 +
 drivers/watchdog/ar2315-wtd.c | 167 ++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 176 insertions(+)
 create mode 100644 drivers/watchdog/ar2315-wtd.c

diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig
index f57312f..dbace99 100644
--- a/drivers/watchdog/Kconfig
+++ b/drivers/watchdog/Kconfig
@@ -1186,6 +1186,14 @@ config RALINK_WDT
 	help
 	  Hardware driver for the Ralink SoC Watchdog Timer.
 
+config AR2315_WDT
+	tristate "Atheros AR2315+ WiSoCs Watchdog Timer"
+	select WATCHDOG_CORE
+	depends on SOC_AR2315
+	help
+	  Hardware driver for the built-in watchdog timer on the Atheros
+	  AR2315/AR2316 WiSoCs.
+
 # PARISC Architecture
 
 # POWERPC Architecture
diff --git a/drivers/watchdog/Makefile b/drivers/watchdog/Makefile
index 468c320..ef7f83b 100644
--- a/drivers/watchdog/Makefile
+++ b/drivers/watchdog/Makefile
@@ -133,6 +133,7 @@ obj-$(CONFIG_WDT_MTX1) += mtx-1_wdt.o
 obj-$(CONFIG_PNX833X_WDT) += pnx833x_wdt.o
 obj-$(CONFIG_SIBYTE_WDOG) += sb_wdog.o
 obj-$(CONFIG_AR7_WDT) += ar7_wdt.o
+obj-$(CONFIG_AR2315_WDT) += ar2315-wtd.o
 obj-$(CONFIG_TXX9_WDT) += txx9wdt.o
 obj-$(CONFIG_OCTEON_WDT) += octeon-wdt.o
 octeon-wdt-y := octeon-wdt-main.o octeon-wdt-nmi.o
diff --git a/drivers/watchdog/ar2315-wtd.c b/drivers/watchdog/ar2315-wtd.c
new file mode 100644
index 0000000..4fd34d2
--- /dev/null
+++ b/drivers/watchdog/ar2315-wtd.c
@@ -0,0 +1,167 @@
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ *
+ * Copyright (C) 2008 John Crispin <blogic@openwrt.org>
+ * Based on EP93xx and ifxmips wdt driver
+ */
+
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/watchdog.h>
+#include <linux/reboot.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+
+#define DRIVER_NAME	"ar2315-wdt"
+
+#define CLOCK_RATE 40000000
+
+#define WDT_REG_TIMER		0x00
+#define WDT_REG_CTRL		0x04
+
+#define WDT_CTRL_ACT_NONE	0x00000000	/* No action */
+#define WDT_CTRL_ACT_NMI	0x00000001	/* NMI on watchdog */
+#define WDT_CTRL_ACT_RESET	0x00000002	/* reset on watchdog */
+
+static int started;
+static void __iomem *wdt_base;
+
+static inline void ar2315_wdt_wr(unsigned reg, u32 val)
+{
+	iowrite32(val, wdt_base + reg);
+}
+
+static void ar2315_wdt_enable(struct watchdog_device *wdd)
+{
+	ar2315_wdt_wr(WDT_REG_TIMER, wdd->timeout * CLOCK_RATE);
+}
+
+static int ar2315_wdt_start(struct watchdog_device *wdd)
+{
+	ar2315_wdt_enable(wdd);
+	started = 1;
+	return 0;
+}
+
+static int ar2315_wdt_stop(struct watchdog_device *wdd)
+{
+	return 0;
+}
+
+static int ar2315_wdt_ping(struct watchdog_device *wdd)
+{
+	ar2315_wdt_enable(wdd);
+	return 0;
+}
+
+static int ar2315_wdt_set_timeout(struct watchdog_device *wdd, unsigned val)
+{
+	wdd->timeout = val;
+	return 0;
+}
+
+static irqreturn_t ar2315_wdt_interrupt(int irq, void *dev)
+{
+	struct platform_device *pdev = (struct platform_device *)dev;
+
+	if (started) {
+		dev_crit(&pdev->dev, "watchdog expired, rebooting system\n");
+		emergency_restart();
+	} else {
+		ar2315_wdt_wr(WDT_REG_CTRL, 0);
+		ar2315_wdt_wr(WDT_REG_TIMER, 0);
+	}
+	return IRQ_HANDLED;
+}
+
+static const struct watchdog_info ar2315_wdt_info = {
+	.identity = "ar2315 Watchdog",
+	.options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING,
+};
+
+static const struct watchdog_ops ar2315_wdt_ops = {
+	.owner = THIS_MODULE,
+	.start = ar2315_wdt_start,
+	.stop = ar2315_wdt_stop,
+	.ping = ar2315_wdt_ping,
+	.set_timeout = ar2315_wdt_set_timeout,
+};
+
+static struct watchdog_device ar2315_wdt_dev = {
+	.info = &ar2315_wdt_info,
+	.ops = &ar2315_wdt_ops,
+	.min_timeout = 1,
+	.max_timeout = 90,
+	.timeout = 20,
+};
+
+static int ar2315_wdt_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct resource *res;
+	int ret = 0;
+
+	if (wdt_base)
+		return -EBUSY;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	wdt_base = devm_ioremap_resource(dev, res);
+	if (IS_ERR(wdt_base))
+		return PTR_ERR(wdt_base);
+
+	res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+	if (!res) {
+		dev_err(dev, "no IRQ resource\n");
+		return -ENOENT;
+	}
+
+	ret = devm_request_irq(dev, res->start, ar2315_wdt_interrupt, 0,
+			       DRIVER_NAME, pdev);
+	if (ret) {
+		dev_err(dev, "failed to register inetrrupt\n");
+		return ret;
+	}
+
+	ar2315_wdt_dev.parent = dev;
+	ret = watchdog_register_device(&ar2315_wdt_dev);
+	if (ret) {
+		dev_err(dev, "failed to register watchdog device\n");
+		return ret;
+	}
+
+	return 0;
+}
+
+static int ar2315_wdt_remove(struct platform_device *pdev)
+{
+	watchdog_unregister_device(&ar2315_wdt_dev);
+	return 0;
+}
+
+static struct platform_driver ar2315_wdt_driver = {
+	.probe = ar2315_wdt_probe,
+	.remove = ar2315_wdt_remove,
+	.driver = {
+		.name = DRIVER_NAME,
+		.owner = THIS_MODULE,
+	},
+};
+
+module_platform_driver(ar2315_wdt_driver);
+
+MODULE_DESCRIPTION("Atheros AR2315 hardware watchdog driver");
+MODULE_AUTHOR("John Crispin <blogic@openwrt.org>");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:" DRIVER_NAME);
-- 
1.8.5.5


^ permalink raw reply related	[flat|nested] 37+ messages in thread

* [PATCH 13/16] MIPS: ar231x: register various chip devices
  2014-09-28 18:32 [PATCH 00/16] MIPS: support for the Atheros AR231X SoCs Sergey Ryazanov
                   ` (11 preceding siblings ...)
  2014-09-28 18:33 ` [PATCH 12/16] watchdog: add Atheros AR2315 watchdog driver Sergey Ryazanov
@ 2014-09-28 18:33 ` Sergey Ryazanov
  2014-09-28 18:33 ` [PATCH 14/16] MIPS: ar231x: add AR2315 PCI host controller driver Sergey Ryazanov
                   ` (2 subsequent siblings)
  15 siblings, 0 replies; 37+ messages in thread
From: Sergey Ryazanov @ 2014-09-28 18:33 UTC (permalink / raw)
  To: Ralf Baechle; +Cc: Linux MIPS

Register GPIO, watchdog and flash devices.

Signed-off-by: Sergey Ryazanov <ryazanov.s.a@gmail.com>
---
 arch/mips/ar231x/Kconfig                        |  2 +
 arch/mips/ar231x/ar2315.c                       | 86 ++++++++++++++++++++++++-
 arch/mips/ar231x/ar5312.c                       | 53 ++++++++++++++-
 arch/mips/include/asm/mach-ar231x/ar2315_regs.h |  5 ++
 arch/mips/include/asm/mach-ar231x/ar5312_regs.h |  2 +
 5 files changed, 144 insertions(+), 4 deletions(-)

diff --git a/arch/mips/ar231x/Kconfig b/arch/mips/ar231x/Kconfig
index aa0fceb..88ca061 100644
--- a/arch/mips/ar231x/Kconfig
+++ b/arch/mips/ar231x/Kconfig
@@ -1,9 +1,11 @@
 config SOC_AR5312
 	bool "Atheros AR5312/AR2312+ SoC support"
 	depends on AR231X
+	select GPIO_AR5312
 	default y
 
 config SOC_AR2315
 	bool "Atheros AR2315+ SoC support"
 	depends on AR231X
+	select GPIO_AR2315
 	default y
diff --git a/arch/mips/ar231x/ar2315.c b/arch/mips/ar231x/ar2315.c
index 7791637..dab9992 100644
--- a/arch/mips/ar231x/ar2315.c
+++ b/arch/mips/ar231x/ar2315.c
@@ -16,7 +16,10 @@
 
 #include <linux/init.h>
 #include <linux/kernel.h>
+#include <linux/platform_device.h>
 #include <linux/reboot.h>
+#include <linux/delay.h>
+#include <linux/gpio.h>
 #include <asm/bootinfo.h>
 #include <asm/reboot.h>
 #include <asm/time.h>
@@ -139,6 +142,66 @@ void __init ar2315_arch_init_irq(void)
 	irq_set_chained_handler(AR2315_IRQ_MISC, ar2315_misc_irq_handler);
 }
 
+static struct resource ar2315_spiflash_res[] = {
+	{
+		.name = "spiflash_read",
+		.flags = IORESOURCE_MEM,
+		.start = AR2315_SPI_READ,
+		.end = AR2315_SPI_READ + 0x1000000 - 1,
+	},
+	{
+		.name = "spiflash_mmr",
+		.flags = IORESOURCE_MEM,
+		.start = AR2315_SPI_MMR,
+		.end = AR2315_SPI_MMR + 12 - 1,
+	},
+};
+
+static struct platform_device ar2315_spiflash = {
+	.id = -1,
+	.name = "ar2315-spiflash",
+	.resource = ar2315_spiflash_res,
+	.num_resources = ARRAY_SIZE(ar2315_spiflash_res)
+};
+
+static struct resource ar2315_wdt_res[] = {
+	{
+		.flags = IORESOURCE_MEM,
+		.start = AR2315_WD,
+		.end = AR2315_WD + 8 - 1,
+	},
+	{
+		.flags = IORESOURCE_IRQ,
+	}
+};
+
+static struct platform_device ar2315_wdt = {
+	.id = -1,
+	.name = "ar2315-wdt",
+	.resource = ar2315_wdt_res,
+	.num_resources = ARRAY_SIZE(ar2315_wdt_res)
+};
+
+static struct resource ar2315_gpio_res[] = {
+	{
+		.name = "ar2315-gpio",
+		.flags = IORESOURCE_MEM,
+		.start = AR2315_GPIO,
+		.end = AR2315_GPIO + 0x10 - 1,
+	},
+	{
+		.name = "ar2315-gpio",
+		.flags = IORESOURCE_IRQ,
+	},
+};
+
+static struct platform_device ar2315_gpio = {
+	.id = -1,
+	.name = "ar2315-gpio",
+	.resource = ar2315_gpio_res,
+	.num_resources = ARRAY_SIZE(ar2315_gpio_res)
+};
+
 /*
  * NB: We use mapping size that is larger than the actual flash size,
  * but this shouldn't be a problem here, because the flash will simply
@@ -149,11 +212,23 @@ ar2315_flash_limit = (u8 *)KSEG1ADDR(AR2315_SPI_READ + 0x1000000);
 
 void __init ar2315_init_devices(void)
 {
+	struct resource *res;
+
 	if (!is_2315())
 		return;
 
 	/* Find board configuration */
 	ar231x_find_config(ar2315_flash_limit);
+
+	res = &ar2315_gpio_res[1];
+	res->start = ar2315_misc_irq_base + AR2315_MISC_IRQ_GPIO;
+	res->end = res->start;
+	platform_device_register(&ar2315_gpio);
+	res = &ar2315_wdt_res[1];
+	res->start = ar2315_misc_irq_base + AR2315_MISC_IRQ_WATCHDOG;
+	res->end = res->start;
+	platform_device_register(&ar2315_wdt);
+	platform_device_register(&ar2315_spiflash);
 }
 
 static void ar2315_restart(char *command)
@@ -165,8 +240,15 @@ static void ar2315_restart(char *command)
 	/* try reset the system via reset control */
 	ar231x_write_reg(AR2315_COLD_RESET, AR2317_RESET_SYSTEM);
 
-	/* Attempt to jump to the mips reset location - the boot loader
-	 * itself might be able to recover the system */
+	/* Cold reset does not work on the AR2315/6, use the GPIO reset bits
+	 * a workaround. Give it some time to attempt a gpio based hardware
+	 * reset (atheros reference design workaround) */
+	gpio_request_one(AR2315_RESET_GPIO, GPIOF_OUT_INIT_LOW, "Reset");
+	mdelay(100);
+
+	/* Some boards (e.g. Senao EOC-2610) don't implement the reset logic
+	 * workaround. Attempt to jump to the mips reset location -
+	 * the boot loader itself might be able to recover the system */
 	mips_reset_vec();
 }
 
diff --git a/arch/mips/ar231x/ar5312.c b/arch/mips/ar231x/ar5312.c
index f207d14..5efbe00 100644
--- a/arch/mips/ar231x/ar5312.c
+++ b/arch/mips/ar231x/ar5312.c
@@ -16,6 +16,8 @@
 
 #include <linux/init.h>
 #include <linux/kernel.h>
+#include <linux/platform_device.h>
+#include <linux/mtd/physmap.h>
 #include <linux/reboot.h>
 #include <asm/bootinfo.h>
 #include <asm/reboot.h>
@@ -134,15 +136,59 @@ void __init ar5312_arch_init_irq(void)
 	irq_set_chained_handler(AR5312_IRQ_MISC, ar5312_misc_irq_handler);
 }
 
+static struct physmap_flash_data ar5312_flash_data = {
+	.width = 2,
+};
+
+static struct resource ar5312_flash_resource = {
+	.start = AR5312_FLASH,
+	.end = AR5312_FLASH + 0x800000 - 1,
+	.flags = IORESOURCE_MEM,
+};
+
+static struct platform_device ar5312_physmap_flash = {
+	.name = "physmap-flash",
+	.id = 0,
+	.dev.platform_data = &ar5312_flash_data,
+	.resource = &ar5312_flash_resource,
+	.num_resources = 1,
+};
+
+static struct resource ar5312_gpio_res[] = {
+	{
+		.name = "ar5312-gpio",
+		.flags = IORESOURCE_MEM,
+		.start = AR5312_GPIO,
+		.end = AR5312_GPIO + 0x0c - 1,
+	},
+};
+
+static struct platform_device ar5312_gpio = {
+	.name = "ar5312-gpio",
+	.id = -1,
+	.resource = ar5312_gpio_res,
+	.num_resources = ARRAY_SIZE(ar5312_gpio_res),
+};
+
 static void __init ar5312_flash_init(void)
 {
-	u32 ctl;
+	u32 ctl = ar231x_read_reg(AR5312_FLASHCTL0) & AR5312_FLASHCTL_MW;
+
+	/* fixup flash width */
+	switch (ctl) {
+	case AR5312_FLASHCTL_MW16:
+		ar5312_flash_data.width = 2;
+		break;
+	case AR5312_FLASHCTL_MW8:
+	default:
+		ar5312_flash_data.width = 1;
+		break;
+	}
 
 	/*
 	 * Configure flash bank 0.
 	 * Assume 8M window size. Flash will be aliased if it's smaller
 	 */
-	ctl = ar231x_read_reg(AR5312_FLASHCTL0) & AR5312_FLASHCTL_MW;
 	ctl |= AR5312_FLASHCTL_E | AR5312_FLASHCTL_AC_8M | AR5312_FLASHCTL_RBLE;
 	ctl |= 0x01 << AR5312_FLASHCTL_IDCY_S;
 	ctl |= 0x07 << AR5312_FLASHCTL_WST1_S;
@@ -188,6 +234,9 @@ void __init ar5312_init_devices(void)
 	/* Everything else is probably AR5312 or compatible */
 	else
 		ar231x_devtype = DEV_TYPE_AR5312;
+
+	platform_device_register(&ar5312_physmap_flash);
+	platform_device_register(&ar5312_gpio);
 }
 
 static void ar5312_restart(char *command)
diff --git a/arch/mips/include/asm/mach-ar231x/ar2315_regs.h b/arch/mips/include/asm/mach-ar231x/ar2315_regs.h
index a65d578..ab64560 100644
--- a/arch/mips/include/asm/mach-ar231x/ar2315_regs.h
+++ b/arch/mips/include/asm/mach-ar231x/ar2315_regs.h
@@ -283,6 +283,11 @@
 #define AR2315_AMBACLK_CLK_DIV_M	0x0000000c
 #define AR2315_AMBACLK_CLK_DIV_S	2
 
+/* GPIO MMR base address */
+#define AR2315_GPIO			(AR2315_DSLBASE + 0x0088)
+
+#define AR2315_RESET_GPIO	5
+
 /*
  *  PCI Clock Control
  */
diff --git a/arch/mips/include/asm/mach-ar231x/ar5312_regs.h b/arch/mips/include/asm/mach-ar231x/ar5312_regs.h
index c7055e32..fccdb4d 100644
--- a/arch/mips/include/asm/mach-ar231x/ar5312_regs.h
+++ b/arch/mips/include/asm/mach-ar231x/ar5312_regs.h
@@ -210,4 +210,6 @@
 #define AR5312_MEM_CFG1_AC1_M	0x00007000	/* bank 1: SDRAM addr check */
 #define AR5312_MEM_CFG1_AC1_S	12
 
+#define AR5312_GPIO		(AR5312_APBBASE  + 0x2000)
+
 #endif	/* __ASM_MACH_AR231X_AR5312_REGS_H */
-- 
1.8.5.5

^ permalink raw reply related	[flat|nested] 37+ messages in thread

* [PATCH 14/16] MIPS: ar231x: add AR2315 PCI host controller driver
  2014-09-28 18:32 [PATCH 00/16] MIPS: support for the Atheros AR231X SoCs Sergey Ryazanov
                   ` (12 preceding siblings ...)
  2014-09-28 18:33 ` [PATCH 13/16] MIPS: ar231x: register various chip devices Sergey Ryazanov
@ 2014-09-28 18:33 ` Sergey Ryazanov
  2014-09-28 18:33 ` [PATCH 15/16] ath5k: update dependencies Sergey Ryazanov
  2014-09-28 18:33 ` [PATCH 16/16] MIPS: ar231x: add Wireless device support Sergey Ryazanov
  15 siblings, 0 replies; 37+ messages in thread
From: Sergey Ryazanov @ 2014-09-28 18:33 UTC (permalink / raw)
  To: Ralf Baechle; +Cc: Linux MIPS

Add PCI host controller driver and DMA address calculation hook.

Signed-off-by: Sergey Ryazanov <ryazanov.s.a@gmail.com>
---

Changes since RFC:
  - use dynamic IRQ numbers allocation

 arch/mips/ar231x/Kconfig                          |   7 +
 arch/mips/ar231x/ar2315.c                         |   9 +
 arch/mips/include/asm/mach-ar231x/ar2315_regs.h   |  23 ++
 arch/mips/include/asm/mach-ar231x/dma-coherence.h |  18 +-
 arch/mips/pci/Makefile                            |   1 +
 arch/mips/pci/pci-ar2315.c                        | 353 ++++++++++++++++++++++
 6 files changed, 408 insertions(+), 3 deletions(-)
 create mode 100644 arch/mips/pci/pci-ar2315.c

diff --git a/arch/mips/ar231x/Kconfig b/arch/mips/ar231x/Kconfig
index 88ca061..f4bf354 100644
--- a/arch/mips/ar231x/Kconfig
+++ b/arch/mips/ar231x/Kconfig
@@ -9,3 +9,10 @@ config SOC_AR2315
 	depends on AR231X
 	select GPIO_AR2315
 	default y
+
+config PCI_AR2315
+	bool "Atheros AR2315 PCI controller support"
+	depends on SOC_AR2315
+	select HW_HAS_PCI
+	select PCI
+	default y
diff --git a/arch/mips/ar231x/ar2315.c b/arch/mips/ar231x/ar2315.c
index dab9992..0d50718 100644
--- a/arch/mips/ar231x/ar2315.c
+++ b/arch/mips/ar231x/ar2315.c
@@ -108,6 +108,10 @@ static void ar2315_irq_dispatch(void)
 
 	if (pending & CAUSEF_IP3)
 		do_IRQ(AR2315_IRQ_WLAN0);
+#ifdef CONFIG_PCI_AR2315
+	else if (pending & CAUSEF_IP5)
+		do_IRQ(AR2315_IRQ_LCBUS_PCI);
+#endif
 	else if (pending & CAUSEF_IP2)
 		do_IRQ(AR2315_IRQ_MISC);
 	else if (pending & CAUSEF_IP7)
@@ -371,5 +375,10 @@ void __init ar2315_arch_init(void)
 
 	ar231x_serial_setup(AR2315_UART0, ar2315_misc_irq_base +
 			    AR2315_MISC_IRQ_UART0, ar2315_apb_frequency());
+
+#ifdef CONFIG_PCI_AR2315
+	if (ar231x_devtype == DEV_TYPE_AR2315)
+		platform_device_register_simple("ar2315-pci", -1, NULL, 0);
+#endif
 }
 
diff --git a/arch/mips/include/asm/mach-ar231x/ar2315_regs.h b/arch/mips/include/asm/mach-ar231x/ar2315_regs.h
index ab64560..b620ec4 100644
--- a/arch/mips/include/asm/mach-ar231x/ar2315_regs.h
+++ b/arch/mips/include/asm/mach-ar231x/ar2315_regs.h
@@ -38,6 +38,15 @@
 #define AR2315_MISC_IRQ_COUNT		9
 
 /*
+ * PCI interrupts, which share IP5
+ * Keep ordered according to AR2315_PCI_INT_XXX bits
+ */
+#define AR2315_PCI_IRQ_EXT		0
+#define AR2315_PCI_IRQ_ABORT		1
+#define AR2315_PCI_IRQ_COUNT		2
+#define AR2315_PCI_IRQ_SHIFT		25	/* in AR2315_PCI_INT_STATUS */
+
+/*
  * Address map
  */
 #define AR2315_SPI_READ		0x08000000	/* SPI flash */
@@ -554,4 +563,18 @@
 #define AR2315_IRCFG_SEQ_END_WIN_THRESH	0x001f0000
 #define AR2315_IRCFG_NUM_BACKOFF_WORDS	0x01e00000
 
+/*
+ * We need some arbitrary non-zero value to be programmed to the BAR1 register
+ * of PCI host controller to enable DMA. The same value should be used as the
+ * offset to calculate the physical address of DMA buffer for PCI devices.
+ */
+#define AR2315_PCI_HOST_SDRAM_BASEADDR	0x20000000
+
+/* ??? access BAR */
+#define AR2315_PCI_HOST_MBAR0		0x10000000
+/* RAM access BAR */
+#define AR2315_PCI_HOST_MBAR1		AR2315_PCI_HOST_SDRAM_BASEADDR
+/* ??? access BAR */
+#define AR2315_PCI_HOST_MBAR2		0x30000000
+
 #endif /* __ASM_MACH_AR231X_AR2315_REGS_H */
diff --git a/arch/mips/include/asm/mach-ar231x/dma-coherence.h b/arch/mips/include/asm/mach-ar231x/dma-coherence.h
index ed32240..90065c1 100644
--- a/arch/mips/include/asm/mach-ar231x/dma-coherence.h
+++ b/arch/mips/include/asm/mach-ar231x/dma-coherence.h
@@ -11,23 +11,35 @@
 #define __ASM_MACH_AR231X_DMA_COHERENCE_H
 
 #include <linux/device.h>
+#include <ar2315_regs.h>
+
+static inline dma_addr_t ar231x_dev_offset(struct device *dev)
+{
+#ifdef CONFIG_PCI
+	extern struct bus_type pci_bus_type;
+
+	if (dev && dev->bus == &pci_bus_type)
+		return AR2315_PCI_HOST_SDRAM_BASEADDR;
+#endif
+	return 0;
+}
 
 static inline dma_addr_t
 plat_map_dma_mem(struct device *dev, void *addr, size_t size)
 {
-	return virt_to_phys(addr);
+	return virt_to_phys(addr) + ar231x_dev_offset(dev);
 }
 
 static inline dma_addr_t
 plat_map_dma_mem_page(struct device *dev, struct page *page)
 {
-	return page_to_phys(page);
+	return page_to_phys(page) + ar231x_dev_offset(dev);
 }
 
 static inline unsigned long
 plat_dma_addr_to_phys(struct device *dev, dma_addr_t dma_addr)
 {
-	return dma_addr;
+	return dma_addr - ar231x_dev_offset(dev);
 }
 
 static inline void
diff --git a/arch/mips/pci/Makefile b/arch/mips/pci/Makefile
index 6523d55..ab6c857 100644
--- a/arch/mips/pci/Makefile
+++ b/arch/mips/pci/Makefile
@@ -19,6 +19,7 @@ obj-$(CONFIG_BCM47XX)		+= pci-bcm47xx.o
 obj-$(CONFIG_BCM63XX)		+= pci-bcm63xx.o fixup-bcm63xx.o \
 					ops-bcm63xx.o
 obj-$(CONFIG_MIPS_ALCHEMY)	+= pci-alchemy.o
+obj-$(CONFIG_PCI_AR2315)	+= pci-ar2315.o
 obj-$(CONFIG_SOC_AR71XX)	+= pci-ar71xx.o
 obj-$(CONFIG_PCI_AR724X)	+= pci-ar724x.o
 obj-$(CONFIG_MIPS_PCI_VIRTIO)	+= pci-virtio-guest.o
diff --git a/arch/mips/pci/pci-ar2315.c b/arch/mips/pci/pci-ar2315.c
new file mode 100644
index 0000000..cfbb7a1
--- /dev/null
+++ b/arch/mips/pci/pci-ar2315.c
@@ -0,0 +1,353 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+/**
+ * Both AR2315 and AR2316 chips have PCI interface unit, which supports DMA
+ * and interrupt. PCI interface supports MMIO access method, but does not
+ * seem to support I/O ports.
+ *
+ * Read/write operation in the region 0x80000000-0xBFFFFFFF causes
+ * a memory read/write command on the PCI bus. 30 LSBs of address on
+ * the bus are taken from memory read/write request and 2 MSBs are
+ * determined by PCI unit configuration.
+ *
+ * To work with the configuration space instead of memory is necessary set
+ * the CFG_SEL bit in the PCI_MISC_CONFIG register.
+ *
+ * Devices on the bus can perform DMA requests via chip BAR1. PCI host
+ * controller BARs are programmend as if an external device is programmed.
+ * Which means that during configuration, IDSEL pin of the chip should be
+ * asserted.
+ *
+ * We know (and support) only one board that uses the PCI interface -
+ * Fonera 2.0g (FON2202). It has a USB EHCI controller connected to the
+ * AR2315 PCI bus. IDSEL pin of USB controller is connected to AD[13] line
+ * and IDSEL pin of AR125 is connected to AD[16] line.
+ */
+
+#include <linux/types.h>
+#include <linux/pci.h>
+#include <linux/platform_device.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/mm.h>
+#include <linux/delay.h>
+#include <linux/irq.h>
+#include <linux/io.h>
+#include <asm/paccess.h>
+#include <ar231x_platform.h>
+#include <ar231x.h>
+#include <ar2315_regs.h>
+
+/* Arbitrary size of memory region to access the configuration space */
+#define AR2315_PCI_CFG_SIZE	0x00100000
+
+#define AR2315_PCI_HOST_SLOT	3
+#define AR2315_PCI_HOST_DEVID	((0xff18 << 16) | PCI_VENDOR_ID_ATHEROS)
+
+static void __iomem *ar2315_pci_cfg_mem;
+static unsigned ar2315_pci_irq_base;
+
+static int ar2315_pci_cfg_access(int devfn, int where, int size, u32 *ptr,
+				 bool write)
+{
+	int func = PCI_FUNC(devfn);
+	int dev = PCI_SLOT(devfn);
+	u32 addr = (1 << (13 + dev)) | (func << 8) | (where & ~3);
+	u32 mask = 0xffffffff >> 8 * (4 - size);
+	u32 sh = (where & 3) * 8;
+	u32 value, isr;
+
+	/* Prevent access past the remapped area */
+	if (addr >= AR2315_PCI_CFG_SIZE || dev > 18)
+		return PCIBIOS_DEVICE_NOT_FOUND;
+
+	/* Clear pending errors */
+	ar231x_write_reg(AR2315_PCI_ISR, AR2315_PCI_INT_ABORT);
+	/* Select Configuration access */
+	ar231x_mask_reg(AR2315_PCI_MISC_CONFIG, 0, AR2315_PCIMISC_CFG_SEL);
+
+	mb();	/* PCI must see space change before we begin */
+
+	value = __raw_readl(ar2315_pci_cfg_mem + addr);
+
+	isr = ar231x_read_reg(AR2315_PCI_ISR);
+	if (isr & AR2315_PCI_INT_ABORT)
+		goto exit_err;
+
+	if (write) {
+		value = (value & ~(mask << sh)) | *ptr << sh;
+		__raw_writel(value, ar2315_pci_cfg_mem + addr);
+		isr = ar231x_read_reg(AR2315_PCI_ISR);
+		if (isr & AR2315_PCI_INT_ABORT)
+			goto exit_err;
+	} else {
+		*ptr = (value >> sh) & mask;
+	}
+
+	goto exit;
+
+exit_err:
+	ar231x_write_reg(AR2315_PCI_ISR, AR2315_PCI_INT_ABORT);
+	if (!write)
+		*ptr = 0xffffffff;
+
+exit:
+	/* Select Memory access */
+	ar231x_mask_reg(AR2315_PCI_MISC_CONFIG, AR2315_PCIMISC_CFG_SEL, 0);
+
+	return isr & AR2315_PCI_INT_ABORT ? PCIBIOS_DEVICE_NOT_FOUND :
+					    PCIBIOS_SUCCESSFUL;
+}
+
+static inline int ar2315_pci_local_cfg_rd(unsigned devfn, int where, u32 *val)
+{
+	return ar2315_pci_cfg_access(devfn, where, sizeof(u32), val, false);
+}
+
+static inline int ar2315_pci_local_cfg_wr(unsigned devfn, int where, u32 val)
+{
+	return ar2315_pci_cfg_access(devfn, where, sizeof(u32), &val, true);
+}
+
+static int ar2315_pci_cfg_read(struct pci_bus *bus, unsigned int devfn,
+			       int where, int size, u32 *value)
+{
+	if (PCI_SLOT(devfn) == AR2315_PCI_HOST_SLOT)
+		return PCIBIOS_DEVICE_NOT_FOUND;
+
+	return ar2315_pci_cfg_access(devfn, where, size, value, 0);
+}
+
+static int ar2315_pci_cfg_write(struct pci_bus *bus, unsigned int devfn,
+				int where, int size, u32 value)
+{
+	if (PCI_SLOT(devfn) == AR2315_PCI_HOST_SLOT)
+		return PCIBIOS_DEVICE_NOT_FOUND;
+
+	return ar2315_pci_cfg_access(devfn, where, size, &value, 1);
+}
+
+static struct pci_ops ar2315_pci_ops = {
+	.read	= ar2315_pci_cfg_read,
+	.write	= ar2315_pci_cfg_write,
+};
+
+static struct resource ar2315_mem_resource = {
+	.name	= "ar2315-pci-mem",
+	.start	= AR2315_PCIEXT,
+	.end	= AR2315_PCIEXT + AR2315_PCIEXT_SZ - 1,
+	.flags	= IORESOURCE_MEM,
+};
+
+/* PCI controller does not support I/O ports */
+static struct resource ar2315_io_resource = {
+	.name	= "ar2315-pci-io",
+	.start	= 0,
+	.end	= 0,
+	.flags	= IORESOURCE_IO,
+};
+
+static struct pci_controller ar2315_pci_controller = {
+	.pci_ops	= &ar2315_pci_ops,
+	.mem_resource	= &ar2315_mem_resource,
+	.io_resource	= &ar2315_io_resource,
+	.mem_offset     = 0x00000000UL,
+	.io_offset      = 0x00000000UL,
+};
+
+static int ar2315_pci_host_setup(void)
+{
+	unsigned devfn = PCI_DEVFN(AR2315_PCI_HOST_SLOT, 0);
+	int res;
+	u32 id;
+
+	res = ar2315_pci_local_cfg_rd(devfn, PCI_VENDOR_ID, &id);
+	if (res != PCIBIOS_SUCCESSFUL || id != AR2315_PCI_HOST_DEVID)
+		return -ENODEV;
+
+	/* Program MBARs */
+	ar2315_pci_local_cfg_wr(devfn, PCI_BASE_ADDRESS_0,
+				AR2315_PCI_HOST_MBAR0);
+	ar2315_pci_local_cfg_wr(devfn, PCI_BASE_ADDRESS_1,
+				AR2315_PCI_HOST_MBAR1);
+	ar2315_pci_local_cfg_wr(devfn, PCI_BASE_ADDRESS_2,
+				AR2315_PCI_HOST_MBAR2);
+
+	/* Run */
+	ar2315_pci_local_cfg_wr(devfn, PCI_COMMAND, PCI_COMMAND_MEMORY |
+				PCI_COMMAND_MASTER | PCI_COMMAND_SPECIAL |
+				PCI_COMMAND_INVALIDATE | PCI_COMMAND_PARITY |
+				PCI_COMMAND_SERR | PCI_COMMAND_FAST_BACK);
+
+	return 0;
+}
+
+static void ar2315_pci_irq_handler(unsigned irq, struct irq_desc *desc)
+{
+	u32 pending = ar231x_read_reg(AR2315_PCI_ISR) &
+		      ar231x_read_reg(AR2315_PCI_IMR);
+
+	if (pending & AR2315_PCI_INT_EXT)
+		generic_handle_irq(ar2315_pci_irq_base + AR2315_PCI_IRQ_EXT);
+	else if (pending & AR2315_PCI_INT_ABORT)
+		generic_handle_irq(ar2315_pci_irq_base + AR2315_PCI_IRQ_ABORT);
+	else
+		spurious_interrupt();
+}
+
+static void ar2315_pci_irq_mask(struct irq_data *d)
+{
+	u32 m = 1 << (d->irq - ar2315_pci_irq_base + AR2315_PCI_IRQ_SHIFT);
+
+	ar231x_mask_reg(AR2315_PCI_IMR, m, 0);
+}
+
+static void ar2315_pci_irq_mask_ack(struct irq_data *d)
+{
+	u32 m = 1 << (d->irq - ar2315_pci_irq_base + AR2315_PCI_IRQ_SHIFT);
+
+	ar231x_mask_reg(AR2315_PCI_IMR, m, 0);
+	ar231x_write_reg(AR2315_PCI_ISR, m);
+}
+
+static void ar2315_pci_irq_unmask(struct irq_data *d)
+{
+	u32 m = 1 << (d->irq - ar2315_pci_irq_base + AR2315_PCI_IRQ_SHIFT);
+
+	ar231x_mask_reg(AR2315_PCI_IMR, 0, m);
+}
+
+static struct irq_chip ar2315_pci_irq_chip = {
+	.name = "AR2315-PCI",
+	.irq_mask = ar2315_pci_irq_mask,
+	.irq_mask_ack = ar2315_pci_irq_mask_ack,
+	.irq_unmask = ar2315_pci_irq_unmask,
+};
+
+static void ar2315_pci_irq_init(void)
+{
+	unsigned i;
+
+	ar231x_mask_reg(AR2315_PCI_IER, AR2315_PCI_IER_ENABLE, 0);
+	ar231x_mask_reg(AR2315_PCI_IMR, (AR2315_PCI_INT_ABORT |
+			 AR2315_PCI_INT_EXT), 0);
+
+	for (i = 0; i < AR2315_PCI_IRQ_COUNT; ++i) {
+		unsigned irq = ar2315_pci_irq_base + i;
+
+		irq_set_chip_and_handler(irq, &ar2315_pci_irq_chip,
+					 handle_level_irq);
+	}
+
+	irq_set_chained_handler(AR2315_IRQ_LCBUS_PCI, ar2315_pci_irq_handler);
+
+	/* Clear any pending Abort or external Interrupts
+	 * and enable interrupt processing */
+	ar231x_write_reg(AR2315_PCI_ISR, (AR2315_PCI_INT_ABORT |
+			 AR2315_PCI_INT_EXT));
+	ar231x_mask_reg(AR2315_PCI_IER, 0, AR2315_PCI_IER_ENABLE);
+}
+
+static int ar2315_pci_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	u32 reg;
+	int res;
+
+	/* Remap PCI config space */
+	ar2315_pci_cfg_mem = devm_ioremap_nocache(dev, AR2315_PCIEXT,
+						  AR2315_PCI_CFG_SIZE);
+	if (!ar2315_pci_cfg_mem) {
+		dev_err(dev, "failed to remap PCI config space\n");
+		return -ENOMEM;
+	}
+
+	/* Reset PCI DMA logic */
+	reg = ar231x_mask_reg(AR2315_RESET, 0, AR2315_RESET_PCIDMA);
+	msleep(20);
+	reg &= ~AR2315_RESET_PCIDMA;
+	ar231x_write_reg(AR2315_RESET, reg);
+	msleep(20);
+
+	ar231x_mask_reg(AR2315_ENDIAN_CTL, 0,
+			AR2315_CONFIG_PCIAHB | AR2315_CONFIG_PCIAHB_BRIDGE);
+
+	ar231x_write_reg(AR2315_PCICLK, AR2315_PCICLK_PLLC_CLKM |
+			 (AR2315_PCICLK_IN_FREQ_DIV_6 << AR2315_PCICLK_DIV_S));
+	ar231x_mask_reg(AR2315_AHB_ARB_CTL, 0, AR2315_ARB_PCI);
+	ar231x_mask_reg(AR2315_IF_CTL, AR2315_IF_PCI_CLK_MASK | AR2315_IF_MASK,
+			AR2315_IF_PCI | AR2315_IF_PCI_HOST |
+			AR2315_IF_PCI_INTR | (AR2315_IF_PCI_CLK_OUTPUT_CLK <<
+					      AR2315_IF_PCI_CLK_SHIFT));
+
+	/* Reset the PCI bus by setting bits 5-4 in PCI_MCFG */
+	ar231x_mask_reg(AR2315_PCI_MISC_CONFIG, AR2315_PCIMISC_RST_MODE,
+			AR2315_PCIRST_LOW);
+	msleep(100);
+
+	/* Bring the PCI out of reset */
+	ar231x_mask_reg(AR2315_PCI_MISC_CONFIG, AR2315_PCIMISC_RST_MODE,
+			AR2315_PCIRST_HIGH | AR2315_PCICACHE_DIS | 0x8);
+
+	ar231x_write_reg(AR2315_PCI_UNCACHE_CFG,
+			 0x1E | /* 1GB uncached */
+			 (1 << 5) | /* Enable uncached */
+			 (0x2 << 30) /* Base: 0x80000000 */);
+	ar231x_read_reg(AR2315_PCI_UNCACHE_CFG);
+
+	msleep(500);
+
+	res = ar2315_pci_host_setup();
+	if (res)
+		return res;
+
+	res = irq_alloc_descs(-1, 0, AR2315_PCI_IRQ_COUNT, 0);
+	if (res < 0) {
+		dev_err(dev, "failed to allocate PCI IRQ numbers\n");
+		return res;
+	}
+	ar2315_pci_irq_base = res;
+
+	ar2315_pci_irq_init();
+
+	register_pci_controller(&ar2315_pci_controller);
+
+	return 0;
+}
+
+static struct platform_driver ar2315_pci_driver = {
+	.probe = ar2315_pci_probe,
+	.driver = {
+		.name = "ar2315-pci",
+		.owner = THIS_MODULE,
+	},
+};
+
+static int __init ar2315_pci_init(void)
+{
+	return platform_driver_register(&ar2315_pci_driver);
+}
+arch_initcall(ar2315_pci_init);
+
+int pcibios_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
+{
+	return ar2315_pci_irq_base + AR2315_PCI_IRQ_EXT;
+}
+
+int pcibios_plat_dev_init(struct pci_dev *dev)
+{
+	return 0;
+}
-- 
1.8.5.5

^ permalink raw reply related	[flat|nested] 37+ messages in thread

* [PATCH 15/16] ath5k: update dependencies
  2014-09-28 18:32 [PATCH 00/16] MIPS: support for the Atheros AR231X SoCs Sergey Ryazanov
                   ` (13 preceding siblings ...)
  2014-09-28 18:33 ` [PATCH 14/16] MIPS: ar231x: add AR2315 PCI host controller driver Sergey Ryazanov
@ 2014-09-28 18:33 ` Sergey Ryazanov
  2014-09-30 17:20   ` John W. Linville
  2014-09-28 18:33 ` [PATCH 16/16] MIPS: ar231x: add Wireless device support Sergey Ryazanov
  15 siblings, 1 reply; 37+ messages in thread
From: Sergey Ryazanov @ 2014-09-28 18:33 UTC (permalink / raw)
  To: Ralf Baechle
  Cc: Linux MIPS, Jiri Slaby, Nick Kossifidis, Luis R. Rodriguez,
	linux-wireless, ath5k-devel

- Use config symbol defined in the driver instead of arch specific one for
  conditional compilation.
- Rename the ATHEROS_AR231X config symbol to AR231X.
- Some of AR231x SoCs (e.g. AR2315) have PCI bus support, so remove !PCI
  dependency, which block AHB support build.

Signed-off-by: Sergey Ryazanov <ryazanov.s.a@gmail.com>
Cc: Jiri Slaby <jirislaby@gmail.com>
Cc: Nick Kossifidis <mickflemm@gmail.com>
Cc: "Luis R. Rodriguez" <mcgrof@do-not-panic.com>
Cc: linux-wireless@vger.kernel.org
Cc: ath5k-devel@lists.ath5k.org
---

Changes since RFC:
  - merge together patches that update ath5k dependencies

 drivers/net/wireless/ath/ath5k/Kconfig | 10 +++++-----
 drivers/net/wireless/ath/ath5k/ath5k.h |  2 +-
 drivers/net/wireless/ath/ath5k/base.c  |  4 ++--
 drivers/net/wireless/ath/ath5k/led.c   |  4 ++--
 4 files changed, 10 insertions(+), 10 deletions(-)

diff --git a/drivers/net/wireless/ath/ath5k/Kconfig b/drivers/net/wireless/ath/ath5k/Kconfig
index c9f81a3..2b2a399 100644
--- a/drivers/net/wireless/ath/ath5k/Kconfig
+++ b/drivers/net/wireless/ath/ath5k/Kconfig
@@ -1,13 +1,13 @@
 config ATH5K
 	tristate "Atheros 5xxx wireless cards support"
-	depends on (PCI || ATHEROS_AR231X) && MAC80211
+	depends on (PCI || AR231X) && MAC80211
 	select ATH_COMMON
 	select MAC80211_LEDS
 	select LEDS_CLASS
 	select NEW_LEDS
 	select AVERAGE
-	select ATH5K_AHB if (ATHEROS_AR231X && !PCI)
-	select ATH5K_PCI if (!ATHEROS_AR231X && PCI)
+	select ATH5K_AHB if AR231X
+	select ATH5K_PCI if !AR231X
 	---help---
 	  This module adds support for wireless adapters based on
 	  Atheros 5xxx chipset.
@@ -54,14 +54,14 @@ config ATH5K_TRACER
 
 config ATH5K_AHB
 	bool "Atheros 5xxx AHB bus support"
-	depends on (ATHEROS_AR231X && !PCI)
+	depends on AR231X
 	---help---
 	  This adds support for WiSoC type chipsets of the 5xxx Atheros
 	  family.
 
 config ATH5K_PCI
 	bool "Atheros 5xxx PCI bus support"
-	depends on (!ATHEROS_AR231X && PCI)
+	depends on (!AR231X && PCI)
 	---help---
 	  This adds support for PCI type chipsets of the 5xxx Atheros
 	  family.
diff --git a/drivers/net/wireless/ath/ath5k/ath5k.h b/drivers/net/wireless/ath/ath5k/ath5k.h
index 85316bb..1ed7a88 100644
--- a/drivers/net/wireless/ath/ath5k/ath5k.h
+++ b/drivers/net/wireless/ath/ath5k/ath5k.h
@@ -1647,7 +1647,7 @@ static inline struct ath_regulatory *ath5k_hw_regulatory(struct ath5k_hw *ah)
 	return &(ath5k_hw_common(ah)->regulatory);
 }
 
-#ifdef CONFIG_ATHEROS_AR231X
+#ifdef CONFIG_ATH5K_AHB
 #define AR5K_AR2315_PCI_BASE	((void __iomem *)0xb0100000)
 
 static inline void __iomem *ath5k_ahb_reg(struct ath5k_hw *ah, u16 reg)
diff --git a/drivers/net/wireless/ath/ath5k/base.c b/drivers/net/wireless/ath/ath5k/base.c
index 8ad2550..dd42487 100644
--- a/drivers/net/wireless/ath/ath5k/base.c
+++ b/drivers/net/wireless/ath/ath5k/base.c
@@ -99,7 +99,7 @@ static int ath5k_reset(struct ath5k_hw *ah, struct ieee80211_channel *chan,
 
 /* Known SREVs */
 static const struct ath5k_srev_name srev_names[] = {
-#ifdef CONFIG_ATHEROS_AR231X
+#ifdef CONFIG_ATH5K_AHB
 	{ "5312",	AR5K_VERSION_MAC,	AR5K_SREV_AR5312_R2 },
 	{ "5312",	AR5K_VERSION_MAC,	AR5K_SREV_AR5312_R7 },
 	{ "2313",	AR5K_VERSION_MAC,	AR5K_SREV_AR2313_R8 },
@@ -142,7 +142,7 @@ static const struct ath5k_srev_name srev_names[] = {
 	{ "5413",	AR5K_VERSION_RAD,	AR5K_SREV_RAD_5413 },
 	{ "5424",	AR5K_VERSION_RAD,	AR5K_SREV_RAD_5424 },
 	{ "5133",	AR5K_VERSION_RAD,	AR5K_SREV_RAD_5133 },
-#ifdef CONFIG_ATHEROS_AR231X
+#ifdef CONFIG_ATH5K_AHB
 	{ "2316",	AR5K_VERSION_RAD,	AR5K_SREV_RAD_2316 },
 	{ "2317",	AR5K_VERSION_RAD,	AR5K_SREV_RAD_2317 },
 #endif
diff --git a/drivers/net/wireless/ath/ath5k/led.c b/drivers/net/wireless/ath/ath5k/led.c
index 48a6a69b..c730677 100644
--- a/drivers/net/wireless/ath/ath5k/led.c
+++ b/drivers/net/wireless/ath/ath5k/led.c
@@ -162,7 +162,7 @@ int ath5k_init_leds(struct ath5k_hw *ah)
 {
 	int ret = 0;
 	struct ieee80211_hw *hw = ah->hw;
-#ifndef CONFIG_ATHEROS_AR231X
+#ifndef CONFIG_ATH5K_AHB
 	struct pci_dev *pdev = ah->pdev;
 #endif
 	char name[ATH5K_LED_MAX_NAME_LEN + 1];
@@ -171,7 +171,7 @@ int ath5k_init_leds(struct ath5k_hw *ah)
 	if (!ah->pdev)
 		return 0;
 
-#ifdef CONFIG_ATHEROS_AR231X
+#ifdef CONFIG_ATH5K_AHB
 	match = NULL;
 #else
 	match = pci_match_id(&ath5k_led_devices[0], pdev);
-- 
1.8.5.5


^ permalink raw reply related	[flat|nested] 37+ messages in thread

* [PATCH 16/16] MIPS: ar231x: add Wireless device support
  2014-09-28 18:32 [PATCH 00/16] MIPS: support for the Atheros AR231X SoCs Sergey Ryazanov
                   ` (14 preceding siblings ...)
  2014-09-28 18:33 ` [PATCH 15/16] ath5k: update dependencies Sergey Ryazanov
@ 2014-09-28 18:33 ` Sergey Ryazanov
  15 siblings, 0 replies; 37+ messages in thread
From: Sergey Ryazanov @ 2014-09-28 18:33 UTC (permalink / raw)
  To: Ralf Baechle; +Cc: Linux MIPS

Atheros AR5312 and AR2315 both have a builtin wireless device, this
patch add helper code and register platform device for all supported
WiSoCs.

Signed-off-by: Sergey Ryazanov <ryazanov.s.a@gmail.com>
---
 arch/mips/ar231x/ar2315.c  |  1 +
 arch/mips/ar231x/ar5312.c  | 22 +++++++++++++++++++
 arch/mips/ar231x/devices.c | 54 ++++++++++++++++++++++++++++++++++++++++++++++
 arch/mips/ar231x/devices.h |  1 +
 4 files changed, 78 insertions(+)

diff --git a/arch/mips/ar231x/ar2315.c b/arch/mips/ar231x/ar2315.c
index 0d50718..837fcad 100644
--- a/arch/mips/ar231x/ar2315.c
+++ b/arch/mips/ar231x/ar2315.c
@@ -233,6 +233,7 @@ void __init ar2315_init_devices(void)
 	res->end = res->start;
 	platform_device_register(&ar2315_wdt);
 	platform_device_register(&ar2315_spiflash);
+	ar231x_add_wmac(0, AR2315_WLAN0, AR2315_IRQ_WLAN0);
 }
 
 static void ar2315_restart(char *command)
diff --git a/arch/mips/ar231x/ar5312.c b/arch/mips/ar231x/ar5312.c
index 5efbe00..33b22e2 100644
--- a/arch/mips/ar231x/ar5312.c
+++ b/arch/mips/ar231x/ar5312.c
@@ -237,6 +237,28 @@ void __init ar5312_init_devices(void)
 
 	platform_device_register(&ar5312_physmap_flash);
 	platform_device_register(&ar5312_gpio);
+
+	switch (ar231x_devtype) {
+	case DEV_TYPE_AR5312:
+		if (!ar231x_board.radio)
+			return;
+
+		if (!(config->flags & BD_WLAN0))
+			break;
+
+		ar231x_add_wmac(0, AR5312_WLAN0, AR5312_IRQ_WLAN0);
+		break;
+	case DEV_TYPE_AR2312:
+	case DEV_TYPE_AR2313:
+		if (!ar231x_board.radio)
+			return;
+		break;
+	default:
+		break;
+	}
+
+	if (config->flags & BD_WLAN1)
+		ar231x_add_wmac(1, AR5312_WLAN1, AR5312_IRQ_WLAN1);
 }
 
 static void ar5312_restart(char *command)
diff --git a/arch/mips/ar231x/devices.c b/arch/mips/ar231x/devices.c
index 21f90f2..65d1026 100644
--- a/arch/mips/ar231x/devices.c
+++ b/arch/mips/ar231x/devices.c
@@ -1,6 +1,7 @@
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/serial_8250.h>
+#include <linux/platform_device.h>
 #include <asm/bootinfo.h>
 
 #include <ar231x_platform.h>
@@ -11,6 +12,45 @@
 struct ar231x_board_config ar231x_board;
 int ar231x_devtype = DEV_TYPE_UNKNOWN;
 
+static struct resource ar231x_wmac0_res[] = {
+	{
+		.name = "wmac0_membase",
+		.flags = IORESOURCE_MEM,
+	},
+	{
+		.name = "wmac0_irq",
+		.flags = IORESOURCE_IRQ,
+	}
+};
+
+static struct resource ar231x_wmac1_res[] = {
+	{
+		.name = "wmac1_membase",
+		.flags = IORESOURCE_MEM,
+	},
+	{
+		.name = "wmac1_irq",
+		.flags = IORESOURCE_IRQ,
+	}
+};
+
+static struct platform_device ar231x_wmac[] = {
+	{
+		.id = 0,
+		.name = "ar231x-wmac",
+		.resource = ar231x_wmac0_res,
+		.num_resources = ARRAY_SIZE(ar231x_wmac0_res),
+		.dev.platform_data = &ar231x_board,
+	},
+	{
+		.id = 1,
+		.name = "ar231x-wmac",
+		.resource = ar231x_wmac1_res,
+		.num_resources = ARRAY_SIZE(ar231x_wmac1_res),
+		.dev.platform_data = &ar231x_board,
+	},
+};
+
 static const char * const devtype_strings[] = {
 	[DEV_TYPE_AR5312] = "Atheros AR5312",
 	[DEV_TYPE_AR2312] = "Atheros AR2312",
@@ -46,6 +86,20 @@ void __init ar231x_serial_setup(u32 mapbase, int irq, unsigned int uartclk)
 	early_serial_setup(&s);
 }
 
+int __init ar231x_add_wmac(int nr, u32 base, int irq)
+{
+	struct resource *res;
+
+	ar231x_wmac[nr].dev.platform_data = &ar231x_board;
+	res = &ar231x_wmac[nr].resource[0];
+	res->start = base;
+	res->end = base + 0x10000 - 1;
+	res++;
+	res->start = irq;
+	res->end = irq;
+	return platform_device_register(&ar231x_wmac[nr]);
+}
+
 static int __init ar231x_register_devices(void)
 {
 	ar5312_init_devices();
diff --git a/arch/mips/ar231x/devices.h b/arch/mips/ar231x/devices.h
index 5ffa091..6e3d242 100644
--- a/arch/mips/ar231x/devices.h
+++ b/arch/mips/ar231x/devices.h
@@ -24,6 +24,7 @@ extern void (*ar231x_irq_dispatch)(void);
 
 int ar231x_find_config(const u8 *flash_limit);
 void ar231x_serial_setup(u32 mapbase, int irq, unsigned int uartclk);
+int ar231x_add_wmac(int nr, u32 base, int irq);
 
 static inline bool is_2315(void)
 {
-- 
1.8.5.5

^ permalink raw reply related	[flat|nested] 37+ messages in thread

* Re: [PATCH 12/16] watchdog: add Atheros AR2315 watchdog driver
  2014-09-28 18:33 ` [PATCH 12/16] watchdog: add Atheros AR2315 watchdog driver Sergey Ryazanov
@ 2014-09-28 21:35   ` Guenter Roeck
  2014-09-29 20:14     ` Sergey Ryazanov
  0 siblings, 1 reply; 37+ messages in thread
From: Guenter Roeck @ 2014-09-28 21:35 UTC (permalink / raw)
  To: Sergey Ryazanov, Ralf Baechle
  Cc: Linux MIPS, Wim Van Sebroeck, linux-watchdog

On 09/28/2014 11:33 AM, Sergey Ryazanov wrote:
> Signed-off-by: Sergey Ryazanov <ryazanov.s.a@gmail.com>
> Cc: Wim Van Sebroeck <wim@iguana.be>
> Cc: linux-watchdog@vger.kernel.org
> ---
>
> Changes since RFC:
>    - use watchdog infrastructure
>    - remove deprecated IRQF_DISABLED flag
>    - move device registration to separate patch
>
>   drivers/watchdog/Kconfig      |   8 ++
>   drivers/watchdog/Makefile     |   1 +
>   drivers/watchdog/ar2315-wtd.c | 167 ++++++++++++++++++++++++++++++++++++++++++
>   3 files changed, 176 insertions(+)
>   create mode 100644 drivers/watchdog/ar2315-wtd.c
>
> diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig
> index f57312f..dbace99 100644
> --- a/drivers/watchdog/Kconfig
> +++ b/drivers/watchdog/Kconfig
> @@ -1186,6 +1186,14 @@ config RALINK_WDT
>   	help
>   	  Hardware driver for the Ralink SoC Watchdog Timer.
>
> +config AR2315_WDT
> +	tristate "Atheros AR2315+ WiSoCs Watchdog Timer"
> +	select WATCHDOG_CORE
> +	depends on SOC_AR2315
> +	help
> +	  Hardware driver for the built-in watchdog timer on the Atheros
> +	  AR2315/AR2316 WiSoCs.
> +
>   # PARISC Architecture
>
>   # POWERPC Architecture
> diff --git a/drivers/watchdog/Makefile b/drivers/watchdog/Makefile
> index 468c320..ef7f83b 100644
> --- a/drivers/watchdog/Makefile
> +++ b/drivers/watchdog/Makefile
> @@ -133,6 +133,7 @@ obj-$(CONFIG_WDT_MTX1) += mtx-1_wdt.o
>   obj-$(CONFIG_PNX833X_WDT) += pnx833x_wdt.o
>   obj-$(CONFIG_SIBYTE_WDOG) += sb_wdog.o
>   obj-$(CONFIG_AR7_WDT) += ar7_wdt.o
> +obj-$(CONFIG_AR2315_WDT) += ar2315-wtd.o
>   obj-$(CONFIG_TXX9_WDT) += txx9wdt.o
>   obj-$(CONFIG_OCTEON_WDT) += octeon-wdt.o
>   octeon-wdt-y := octeon-wdt-main.o octeon-wdt-nmi.o
> diff --git a/drivers/watchdog/ar2315-wtd.c b/drivers/watchdog/ar2315-wtd.c
> new file mode 100644
> index 0000000..4fd34d2
> --- /dev/null
> +++ b/drivers/watchdog/ar2315-wtd.c
> @@ -0,0 +1,167 @@
> +/*
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation; either version 2 of the License, or
> + * (at your option) any later version.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program; if not, see <http://www.gnu.org/licenses/>.
> + *
> + * Copyright (C) 2008 John Crispin <blogic@openwrt.org>
> + * Based on EP93xx and ifxmips wdt driver
> + */
> +
> +#include <linux/interrupt.h>
> +#include <linux/module.h>
> +#include <linux/watchdog.h>
> +#include <linux/reboot.h>
> +#include <linux/init.h>
> +#include <linux/platform_device.h>
> +#include <linux/io.h>
> +
> +#define DRIVER_NAME	"ar2315-wdt"
> +
> +#define CLOCK_RATE 40000000
> +
> +#define WDT_REG_TIMER		0x00
> +#define WDT_REG_CTRL		0x04
> +
> +#define WDT_CTRL_ACT_NONE	0x00000000	/* No action */
> +#define WDT_CTRL_ACT_NMI	0x00000001	/* NMI on watchdog */
> +#define WDT_CTRL_ACT_RESET	0x00000002	/* reset on watchdog */
> +
What are those defines for ? They don't seem to be used.

If the watchdog can result in an immediate restart, as
this define suggests, why don't you use it but rely on
the interrupt handler instead ?

This means the watchdog won't really fire if it times out, but depend
on the interrupt handler to work. Which it won't if there is a real
problem and interrupts are disabled (or if the system hangs entirely).

> +static int started;
> +static void __iomem *wdt_base;
> +
> +static inline void ar2315_wdt_wr(unsigned reg, u32 val)
> +{
> +	iowrite32(val, wdt_base + reg);
> +}
> +
> +static void ar2315_wdt_enable(struct watchdog_device *wdd)
> +{
> +	ar2315_wdt_wr(WDT_REG_TIMER, wdd->timeout * CLOCK_RATE);
> +}
> +
> +static int ar2315_wdt_start(struct watchdog_device *wdd)
> +{
> +	ar2315_wdt_enable(wdd);
> +	started = 1;

I don't really see why you would need this variable.

> +	return 0;
> +}
> +
> +static int ar2315_wdt_stop(struct watchdog_device *wdd)
> +{
> +	return 0;
> +}
> +
> +static int ar2315_wdt_ping(struct watchdog_device *wdd)
> +{
> +	ar2315_wdt_enable(wdd);
> +	return 0;
> +}
> +
> +static int ar2315_wdt_set_timeout(struct watchdog_device *wdd, unsigned val)
> +{
> +	wdd->timeout = val;
> +	return 0;
> +}
> +
> +static irqreturn_t ar2315_wdt_interrupt(int irq, void *dev)
> +{
> +	struct platform_device *pdev = (struct platform_device *)dev;
> +
> +	if (started) {
> +		dev_crit(&pdev->dev, "watchdog expired, rebooting system\n");
> +		emergency_restart();
> +	} else {
> +		ar2315_wdt_wr(WDT_REG_CTRL, 0);
> +		ar2315_wdt_wr(WDT_REG_TIMER, 0);
> +	}

This is quite unusual.
Why not stop the watchdog in the stop function ? Quite apparently
it can be stopped, or at least this is what it looks like.

When do you expect this function to be called in the first place
with started == 1 ?

If the idea is to stop the watchdog if it was already enabled
when probing the driver, why don't you stop it there ?


> +	return IRQ_HANDLED;
> +}
> +
> +static const struct watchdog_info ar2315_wdt_info = {
> +	.identity = "ar2315 Watchdog",
> +	.options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING,
> +};
> +
> +static const struct watchdog_ops ar2315_wdt_ops = {
> +	.owner = THIS_MODULE,
> +	.start = ar2315_wdt_start,
> +	.stop = ar2315_wdt_stop,
> +	.ping = ar2315_wdt_ping,
> +	.set_timeout = ar2315_wdt_set_timeout,
> +};
> +
> +static struct watchdog_device ar2315_wdt_dev = {
> +	.info = &ar2315_wdt_info,
> +	.ops = &ar2315_wdt_ops,
> +	.min_timeout = 1,
> +	.max_timeout = 90,
> +	.timeout = 20,
> +};
> +
> +static int ar2315_wdt_probe(struct platform_device *pdev)
> +{
> +	struct device *dev = &pdev->dev;
> +	struct resource *res;
> +	int ret = 0;
> +
> +	if (wdt_base)
> +		return -EBUSY;
> +
> +	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> +	wdt_base = devm_ioremap_resource(dev, res);
> +	if (IS_ERR(wdt_base))
> +		return PTR_ERR(wdt_base);
> +
> +	res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
> +	if (!res) {
> +		dev_err(dev, "no IRQ resource\n");
> +		return -ENOENT;
> +	}
> +
> +	ret = devm_request_irq(dev, res->start, ar2315_wdt_interrupt, 0,
> +			       DRIVER_NAME, pdev);
> +	if (ret) {
> +		dev_err(dev, "failed to register inetrrupt\n");
> +		return ret;
> +	}
> +
> +	ar2315_wdt_dev.parent = dev;
> +	ret = watchdog_register_device(&ar2315_wdt_dev);
> +	if (ret) {
> +		dev_err(dev, "failed to register watchdog device\n");
> +		return ret;
> +	}
> +
> +	return 0;
> +}
> +
> +static int ar2315_wdt_remove(struct platform_device *pdev)
> +{
> +	watchdog_unregister_device(&ar2315_wdt_dev);

Why don't you stop the watchdog on remove ?

> +	return 0;
> +}
> +
> +static struct platform_driver ar2315_wdt_driver = {
> +	.probe = ar2315_wdt_probe,
> +	.remove = ar2315_wdt_remove,
> +	.driver = {
> +		.name = DRIVER_NAME,
> +		.owner = THIS_MODULE,
> +	},
> +};
> +
> +module_platform_driver(ar2315_wdt_driver);
> +
> +MODULE_DESCRIPTION("Atheros AR2315 hardware watchdog driver");
> +MODULE_AUTHOR("John Crispin <blogic@openwrt.org>");
> +MODULE_LICENSE("GPL");
> +MODULE_ALIAS("platform:" DRIVER_NAME);
>


^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [PATCH 01/16] MIPS: ar231x: add common parts
  2014-09-28 18:33 ` [PATCH 01/16] MIPS: ar231x: add common parts Sergey Ryazanov
@ 2014-09-29  9:30   ` Jonas Gorski
  2014-09-29 20:57     ` Sergey Ryazanov
  0 siblings, 1 reply; 37+ messages in thread
From: Jonas Gorski @ 2014-09-29  9:30 UTC (permalink / raw)
  To: Sergey Ryazanov; +Cc: Ralf Baechle, Linux MIPS

On Sun, Sep 28, 2014 at 8:33 PM, Sergey Ryazanov <ryazanov.s.a@gmail.com> wrote:
> Add common code for Atheros AR5312 and Atheros AR2315 SoCs families.
>
> Signed-off-by: Sergey Ryazanov <ryazanov.s.a@gmail.com>
> ---
>  arch/mips/Kbuild.platforms                         |  1 +
>  arch/mips/Kconfig                                  | 13 ++++
>  arch/mips/ar231x/Makefile                          | 11 ++++
>  arch/mips/ar231x/Platform                          |  6 ++
>  arch/mips/ar231x/board.c                           | 53 +++++++++++++++
>  arch/mips/ar231x/devices.c                         | 20 ++++++
>  arch/mips/ar231x/devices.h                         | 22 +++++++
>  arch/mips/ar231x/prom.c                            | 26 ++++++++
>  arch/mips/include/asm/mach-ar231x/ar231x.h         | 29 +++++++++
>  .../asm/mach-ar231x/cpu-feature-overrides.h        | 76 ++++++++++++++++++++++
>  arch/mips/include/asm/mach-ar231x/dma-coherence.h  | 64 ++++++++++++++++++
>  arch/mips/include/asm/mach-ar231x/gpio.h           | 16 +++++
>  arch/mips/include/asm/mach-ar231x/war.h            | 25 +++++++
>  13 files changed, 362 insertions(+)
>  create mode 100644 arch/mips/ar231x/Makefile
>  create mode 100644 arch/mips/ar231x/Platform
>  create mode 100644 arch/mips/ar231x/board.c
>  create mode 100644 arch/mips/ar231x/devices.c
>  create mode 100644 arch/mips/ar231x/devices.h
>  create mode 100644 arch/mips/ar231x/prom.c
>  create mode 100644 arch/mips/include/asm/mach-ar231x/ar231x.h
>  create mode 100644 arch/mips/include/asm/mach-ar231x/cpu-feature-overrides.h
>  create mode 100644 arch/mips/include/asm/mach-ar231x/dma-coherence.h
>  create mode 100644 arch/mips/include/asm/mach-ar231x/gpio.h
>  create mode 100644 arch/mips/include/asm/mach-ar231x/war.h
>
> diff --git a/arch/mips/Kbuild.platforms b/arch/mips/Kbuild.platforms
> index f5e18bf..ee1940a 100644
> --- a/arch/mips/Kbuild.platforms
> +++ b/arch/mips/Kbuild.platforms
> @@ -1,6 +1,7 @@
>  # All platforms listed in alphabetic order
>
>  platforms += alchemy
> +platforms += ar231x
>  platforms += ar7
>  platforms += ath79
>  platforms += bcm47xx
> diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig
> index 01c0389..6adae4c 100644
> --- a/arch/mips/Kconfig
> +++ b/arch/mips/Kconfig
> @@ -73,6 +73,19 @@ config MIPS_ALCHEMY
>         select SYS_SUPPORTS_ZBOOT
>         select COMMON_CLK
>
> +config AR231X

I would suggest naming it ATH25, to match the other atheros target (ATH79).

> +       bool "Atheros AR231x/AR531x SoC support"
> +       select CEVT_R4K
> +       select CSRC_R4K
> +       select DMA_NONCOHERENT
> +       select IRQ_CPU
> +       select SYS_HAS_CPU_MIPS32_R1
> +       select SYS_SUPPORTS_BIG_ENDIAN
> +       select SYS_SUPPORTS_32BIT_KERNEL
> +       select ARCH_REQUIRE_GPIOLIB
> +       help
> +         Support for Atheros AR231x and Atheros AR531x based boards
> +
>  config AR7
>         bool "Texas Instruments AR7"
>         select BOOT_ELF32
> diff --git a/arch/mips/ar231x/Makefile b/arch/mips/ar231x/Makefile
> new file mode 100644
> index 0000000..9199fa1
> --- /dev/null
> +++ b/arch/mips/ar231x/Makefile
> @@ -0,0 +1,11 @@
> +#
> +# This file is subject to the terms and conditions of the GNU General Public
> +# License.  See the file "COPYING" in the main directory of this archive
> +# for more details.
> +#
> +# Copyright (C) 2006 FON Technology, SL.
> +# Copyright (C) 2006 Imre Kaloz <kaloz@openwrt.org>
> +# Copyright (C) 2006-2009 Felix Fietkau <nbd@openwrt.org>
> +#
> +
> +obj-y += board.o prom.o devices.o
> diff --git a/arch/mips/ar231x/Platform b/arch/mips/ar231x/Platform
> new file mode 100644
> index 0000000..c924fd1
> --- /dev/null
> +++ b/arch/mips/ar231x/Platform
> @@ -0,0 +1,6 @@
> +#
> +# Atheros AR531X/AR231X WiSoC
> +#
> +platform-$(CONFIG_AR231X)      += ar231x/
> +cflags-$(CONFIG_AR231X)                += -I$(srctree)/arch/mips/include/asm/mach-ar231x
> +load-$(CONFIG_AR231X)          += 0xffffffff80041000
> diff --git a/arch/mips/ar231x/board.c b/arch/mips/ar231x/board.c
> new file mode 100644
> index 0000000..9cde045
> --- /dev/null
> +++ b/arch/mips/ar231x/board.c
> @@ -0,0 +1,53 @@
> +/*
> + * This file is subject to the terms and conditions of the GNU General Public
> + * License.  See the file "COPYING" in the main directory of this archive
> + * for more details.
> + *
> + * Copyright (C) 2003 Atheros Communications, Inc.,  All Rights Reserved.
> + * Copyright (C) 2006 FON Technology, SL.
> + * Copyright (C) 2006 Imre Kaloz <kaloz@openwrt.org>
> + * Copyright (C) 2006-2009 Felix Fietkau <nbd@openwrt.org>
> + */
> +
> +#include <linux/init.h>
> +#include <linux/interrupt.h>
> +#include <asm/irq_cpu.h>
> +#include <asm/reboot.h>
> +#include <asm/bootinfo.h>
> +#include <asm/time.h>
> +
> +static void ar231x_halt(void)
> +{
> +       local_irq_disable();
> +       while (1)
> +               ;
> +}
> +
> +void __init plat_mem_setup(void)
> +{
> +       _machine_halt = ar231x_halt;
> +       pm_power_off = ar231x_halt;
> +
> +       /* Disable data watchpoints */
> +       write_c0_watchlo0(0);
> +}
> +
> +asmlinkage void plat_irq_dispatch(void)
> +{
> +}
> +
> +void __init plat_time_init(void)
> +{
> +}
> +
> +unsigned int __cpuinit get_c0_compare_int(void)
> +{
> +       return CP0_LEGACY_COMPARE_IRQ;
> +}
> +
> +void __init arch_init_irq(void)
> +{
> +       clear_c0_status(ST0_IM);
> +       mips_cpu_irq_init();
> +}
> +
> diff --git a/arch/mips/ar231x/devices.c b/arch/mips/ar231x/devices.c
> new file mode 100644
> index 0000000..f71a643
> --- /dev/null
> +++ b/arch/mips/ar231x/devices.c
> @@ -0,0 +1,20 @@
> +#include <linux/kernel.h>
> +#include <linux/init.h>
> +#include <asm/bootinfo.h>
> +
> +#include "devices.h"
> +
> +int ar231x_devtype = DEV_TYPE_UNKNOWN;
> +
> +static const char * const devtype_strings[] = {
> +       [DEV_TYPE_UNKNOWN] = "Atheros (unknown)",
> +};
> +
> +const char *get_system_type(void)
> +{
> +       if ((ar231x_devtype >= ARRAY_SIZE(devtype_strings)) ||
> +           !devtype_strings[ar231x_devtype])
> +               return devtype_strings[DEV_TYPE_UNKNOWN];
> +       return devtype_strings[ar231x_devtype];
> +}
> +
> diff --git a/arch/mips/ar231x/devices.h b/arch/mips/ar231x/devices.h
> new file mode 100644
> index 0000000..1590577
> --- /dev/null
> +++ b/arch/mips/ar231x/devices.h
> @@ -0,0 +1,22 @@
> +#ifndef __AR231X_DEVICES_H
> +#define __AR231X_DEVICES_H
> +
> +#include <linux/cpu.h>
> +
> +enum {
> +       DEV_TYPE_UNKNOWN
> +};
> +
> +extern int ar231x_devtype;
> +
> +static inline bool is_2315(void)

Since this is matching the whole family of ar231x SoCs, I would
suggest to give it a prefix and call it ath25_is_231x.
> +{
> +       return (current_cpu_data.cputype == CPU_4KEC);

Unnecessary ().

> +}
> +
> +static inline bool is_5312(void)

Same comment here for 5312 -> 531x.

> +{
> +       return !is_2315();
> +}
> +
> +#endif


Regards
Jonas

^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [PATCH 02/16] MIPS: ar231x: add basic AR5312 SoC support
  2014-09-28 18:33 ` [PATCH 02/16] MIPS: ar231x: add basic AR5312 SoC support Sergey Ryazanov
@ 2014-09-29  9:35   ` Jonas Gorski
  2014-09-29 21:05     ` Sergey Ryazanov
  0 siblings, 1 reply; 37+ messages in thread
From: Jonas Gorski @ 2014-09-29  9:35 UTC (permalink / raw)
  To: Sergey Ryazanov; +Cc: Ralf Baechle, Linux MIPS

On Sun, Sep 28, 2014 at 8:33 PM, Sergey Ryazanov <ryazanov.s.a@gmail.com> wrote:
> Add basic support for Atheros AR5312/AR2312 SoCs: registers definition
> file and initial setup code.

For the whole file: please use the style

do_foo()
{
  if (is_ar5312())
      ar5312_foo();
}

instead of

do_foo()
{
  ar5312_foo();
}

ar5312_foo()
{
  if (!is_ar5312())
    return;
}

also same comments regarding naming (ar531x instead of ar5312).

Regards
Jonas

^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [PATCH 03/16] MIPS: ar231x: add basic AR2315 SoC support
  2014-09-28 18:33 ` [PATCH 03/16] MIPS: ar231x: add basic AR2315 " Sergey Ryazanov
@ 2014-09-29  9:50   ` Jonas Gorski
  0 siblings, 0 replies; 37+ messages in thread
From: Jonas Gorski @ 2014-09-29  9:50 UTC (permalink / raw)
  To: Sergey Ryazanov; +Cc: Ralf Baechle, Linux MIPS

On Sun, Sep 28, 2014 at 8:33 PM, Sergey Ryazanov <ryazanov.s.a@gmail.com> wrote:
> Add basic support for Atheros AR2315+ SoCs: registers definition file
> and initial setup code.

Same comment regarding the style of checking the SoC family as for patch 2.


Regards
Jonas

^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [PATCH 05/16] MIPS: ar231x: add early printk support
  2014-09-28 18:33 ` [PATCH 05/16] MIPS: ar231x: add early printk support Sergey Ryazanov
@ 2014-09-29 12:47   ` Jonas Gorski
  2014-09-29 19:36     ` Sergey Ryazanov
  0 siblings, 1 reply; 37+ messages in thread
From: Jonas Gorski @ 2014-09-29 12:47 UTC (permalink / raw)
  To: Sergey Ryazanov; +Cc: Ralf Baechle, Linux MIPS

On Sun, Sep 28, 2014 at 8:33 PM, Sergey Ryazanov <ryazanov.s.a@gmail.com> wrote:
> Signed-off-by: Sergey Ryazanov <ryazanov.s.a@gmail.com>
> ---
>  arch/mips/Kconfig               |  1 +
>  arch/mips/ar231x/Makefile       |  2 ++
>  arch/mips/ar231x/early_printk.c | 45 +++++++++++++++++++++++++++++++++++++++++
>  3 files changed, 48 insertions(+)
>  create mode 100644 arch/mips/ar231x/early_printk.c
>
> diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig
> index bd81f7a..b89bfdf 100644
> --- a/arch/mips/Kconfig
> +++ b/arch/mips/Kconfig
> @@ -83,6 +83,7 @@ config AR231X
>         select SYS_SUPPORTS_BIG_ENDIAN
>         select SYS_SUPPORTS_32BIT_KERNEL
>         select ARCH_REQUIRE_GPIOLIB
> +       select SYS_HAS_EARLY_PRINTK
>         help
>           Support for Atheros AR231x and Atheros AR531x based boards
>
> diff --git a/arch/mips/ar231x/Makefile b/arch/mips/ar231x/Makefile
> index 201b7d4..eabad7d 100644
> --- a/arch/mips/ar231x/Makefile
> +++ b/arch/mips/ar231x/Makefile
> @@ -10,5 +10,7 @@
>
>  obj-y += board.o prom.o devices.o
>
> +obj-$(CONFIG_EARLY_PRINTK) += early_printk.o
> +
>  obj-$(CONFIG_SOC_AR5312) += ar5312.o
>  obj-$(CONFIG_SOC_AR2315) += ar2315.o
> diff --git a/arch/mips/ar231x/early_printk.c b/arch/mips/ar231x/early_printk.c
> new file mode 100644
> index 0000000..393c5ab
> --- /dev/null
> +++ b/arch/mips/ar231x/early_printk.c
> @@ -0,0 +1,45 @@
> +/*
> + * This file is subject to the terms and conditions of the GNU General Public
> + * License.  See the file "COPYING" in the main directory of this archive
> + * for more details.
> + *
> + * Copyright (C) 2010 Gabor Juhos <juhosg@openwrt.org>
> + */
> +
> +#include <linux/mm.h>
> +#include <linux/io.h>
> +#include <linux/serial_reg.h>
> +
> +#include <ar2315_regs.h>
> +#include <ar5312_regs.h>
> +#include "devices.h"
> +
> +static inline void prom_uart_wr(void __iomem *base, unsigned reg,
> +                               unsigned char ch)
> +{
> +       __raw_writel(ch, base + 4 * reg);
> +}
> +
> +static inline unsigned char prom_uart_rr(void __iomem *base, unsigned reg)
> +{
> +       return __raw_readl(base + 4 * reg);
> +}
> +
> +void prom_putchar(unsigned char ch)
> +{
> +       static void __iomem *base;
> +
> +       if (unlikely(base == NULL)) {
> +               if (is_2315())
> +                       base = (void __iomem *)(KSEG1ADDR(AR2315_UART0));
> +               else
> +                       base = (void __iomem *)(KSEG1ADDR(AR5312_UART0));
> +       }
> +
> +       while ((prom_uart_rr(base, UART_LSR) & UART_LSR_THRE) == 0)
> +               ;
> +       prom_uart_wr(base, UART_TX, ch);
> +       while ((prom_uart_rr(base, UART_LSR) & UART_LSR_THRE) == 0)
> +               ;
> +}


Have you tried using EARLY_PRINTK_8250 instead? Since this is a 8250 anyway.


Jonas

^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [PATCH 05/16] MIPS: ar231x: add early printk support
  2014-09-29 12:47   ` Jonas Gorski
@ 2014-09-29 19:36     ` Sergey Ryazanov
  0 siblings, 0 replies; 37+ messages in thread
From: Sergey Ryazanov @ 2014-09-29 19:36 UTC (permalink / raw)
  To: Jonas Gorski; +Cc: Ralf Baechle, Linux MIPS

2014-09-29 16:47 GMT+04:00 Jonas Gorski <jogo@openwrt.org>:
> Have you tried using EARLY_PRINTK_8250 instead? Since this is a 8250 anyway.
>
I plan to do that a bit later.

-- 
BR,
Sergey

^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [PATCH 12/16] watchdog: add Atheros AR2315 watchdog driver
  2014-09-28 21:35   ` Guenter Roeck
@ 2014-09-29 20:14     ` Sergey Ryazanov
  2014-09-29 20:46       ` Guenter Roeck
  0 siblings, 1 reply; 37+ messages in thread
From: Sergey Ryazanov @ 2014-09-29 20:14 UTC (permalink / raw)
  To: Guenter Roeck; +Cc: Ralf Baechle, Linux MIPS, Wim Van Sebroeck, linux-watchdog

2014-09-29 1:35 GMT+04:00 Guenter Roeck <linux@roeck-us.net>:
> On 09/28/2014 11:33 AM, Sergey Ryazanov wrote:
>>
>> Signed-off-by: Sergey Ryazanov <ryazanov.s.a@gmail.com>
>> Cc: Wim Van Sebroeck <wim@iguana.be>
>> Cc: linux-watchdog@vger.kernel.org
>> ---
>>
>> Changes since RFC:
>>    - use watchdog infrastructure
>>    - remove deprecated IRQF_DISABLED flag
>>    - move device registration to separate patch
>>
>>   drivers/watchdog/Kconfig      |   8 ++
>>   drivers/watchdog/Makefile     |   1 +
>>   drivers/watchdog/ar2315-wtd.c | 167
>> ++++++++++++++++++++++++++++++++++++++++++
>>   3 files changed, 176 insertions(+)
>>   create mode 100644 drivers/watchdog/ar2315-wtd.c
>>
>> diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig
>> index f57312f..dbace99 100644
>> --- a/drivers/watchdog/Kconfig
>> +++ b/drivers/watchdog/Kconfig
>> @@ -1186,6 +1186,14 @@ config RALINK_WDT
>>         help
>>           Hardware driver for the Ralink SoC Watchdog Timer.
>>
>> +config AR2315_WDT
>> +       tristate "Atheros AR2315+ WiSoCs Watchdog Timer"
>> +       select WATCHDOG_CORE
>> +       depends on SOC_AR2315
>> +       help
>> +         Hardware driver for the built-in watchdog timer on the Atheros
>> +         AR2315/AR2316 WiSoCs.
>> +
>>   # PARISC Architecture
>>
>>   # POWERPC Architecture
>> diff --git a/drivers/watchdog/Makefile b/drivers/watchdog/Makefile
>> index 468c320..ef7f83b 100644
>> --- a/drivers/watchdog/Makefile
>> +++ b/drivers/watchdog/Makefile
>> @@ -133,6 +133,7 @@ obj-$(CONFIG_WDT_MTX1) += mtx-1_wdt.o
>>   obj-$(CONFIG_PNX833X_WDT) += pnx833x_wdt.o
>>   obj-$(CONFIG_SIBYTE_WDOG) += sb_wdog.o
>>   obj-$(CONFIG_AR7_WDT) += ar7_wdt.o
>> +obj-$(CONFIG_AR2315_WDT) += ar2315-wtd.o
>>   obj-$(CONFIG_TXX9_WDT) += txx9wdt.o
>>   obj-$(CONFIG_OCTEON_WDT) += octeon-wdt.o
>>   octeon-wdt-y := octeon-wdt-main.o octeon-wdt-nmi.o
>> diff --git a/drivers/watchdog/ar2315-wtd.c b/drivers/watchdog/ar2315-wtd.c
>> new file mode 100644
>> index 0000000..4fd34d2
>> --- /dev/null
>> +++ b/drivers/watchdog/ar2315-wtd.c
>> @@ -0,0 +1,167 @@
>> +/*
>> + * This program is free software; you can redistribute it and/or modify
>> + * it under the terms of the GNU General Public License as published by
>> + * the Free Software Foundation; either version 2 of the License, or
>> + * (at your option) any later version.
>> + *
>> + * This program is distributed in the hope that it will be useful,
>> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
>> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
>> + * GNU General Public License for more details.
>> + *
>> + * You should have received a copy of the GNU General Public License
>> + * along with this program; if not, see <http://www.gnu.org/licenses/>.
>> + *
>> + * Copyright (C) 2008 John Crispin <blogic@openwrt.org>
>> + * Based on EP93xx and ifxmips wdt driver
>> + */
>> +
>> +#include <linux/interrupt.h>
>> +#include <linux/module.h>
>> +#include <linux/watchdog.h>
>> +#include <linux/reboot.h>
>> +#include <linux/init.h>
>> +#include <linux/platform_device.h>
>> +#include <linux/io.h>
>> +
>> +#define DRIVER_NAME    "ar2315-wdt"
>> +
>> +#define CLOCK_RATE 40000000
>> +
>> +#define WDT_REG_TIMER          0x00
>> +#define WDT_REG_CTRL           0x04
>> +
>> +#define WDT_CTRL_ACT_NONE      0x00000000      /* No action */
>> +#define WDT_CTRL_ACT_NMI       0x00000001      /* NMI on watchdog */
>> +#define WDT_CTRL_ACT_RESET     0x00000002      /* reset on watchdog */
>> +
>
> What are those defines for ? They don't seem to be used.
>
This defines for reference. There no documentation for this chips, so
I left this defines as some kind of documentation.

> If the watchdog can result in an immediate restart, as
> this define suggests, why don't you use it but rely on
> the interrupt handler instead ?
>
AFAIK some of chips have a HW bug in restarting unit, so chip specific
restart routine (in arch code) use a lot of hacks to reset chip. So we
use interrupt to call reset function, which should reliably reset
chip.

> This means the watchdog won't really fire if it times out, but depend
> on the interrupt handler to work. Which it won't if there is a real
> problem and interrupts are disabled (or if the system hangs entirely).
>
Sure. But without reset function call from the interrupt handler we
can not reliable reset chip (see above).

>> +static int started;
>> +static void __iomem *wdt_base;
>> +
>> +static inline void ar2315_wdt_wr(unsigned reg, u32 val)
>> +{
>> +       iowrite32(val, wdt_base + reg);
>> +}
>> +
>> +static void ar2315_wdt_enable(struct watchdog_device *wdd)
>> +{
>> +       ar2315_wdt_wr(WDT_REG_TIMER, wdd->timeout * CLOCK_RATE);
>> +}
>> +
>> +static int ar2315_wdt_start(struct watchdog_device *wdd)
>> +{
>> +       ar2315_wdt_enable(wdd);
>> +       started = 1;
>
>
> I don't really see why you would need this variable.
>
To protect against spurious interrupts, since the watchdog timer could
be started by bootloader.

>
>> +       return 0;
>> +}
>> +
>> +static int ar2315_wdt_stop(struct watchdog_device *wdd)
>> +{
>> +       return 0;
>> +}
>> +
>> +static int ar2315_wdt_ping(struct watchdog_device *wdd)
>> +{
>> +       ar2315_wdt_enable(wdd);
>> +       return 0;
>> +}
>> +
>> +static int ar2315_wdt_set_timeout(struct watchdog_device *wdd, unsigned
>> val)
>> +{
>> +       wdd->timeout = val;
>> +       return 0;
>> +}
>> +
>> +static irqreturn_t ar2315_wdt_interrupt(int irq, void *dev)
>> +{
>> +       struct platform_device *pdev = (struct platform_device *)dev;
>> +
>> +       if (started) {
>> +               dev_crit(&pdev->dev, "watchdog expired, rebooting
>> system\n");
>> +               emergency_restart();
>> +       } else {
>> +               ar2315_wdt_wr(WDT_REG_CTRL, 0);
>> +               ar2315_wdt_wr(WDT_REG_TIMER, 0);
>> +       }
>
>
> This is quite unusual.
> Why not stop the watchdog in the stop function ? Quite apparently
> it can be stopped, or at least this is what it looks like.
>
The started variable is set to true inside the watchdog start routine,
but it never reset to false. This code only disable the watchdog when
it was started by bootloader.

> When do you expect this function to be called in the first place
> with started == 1 ?
>
> If the idea is to stop the watchdog if it was already enabled
> when probing the driver, why don't you stop it there ?
>
Sure, I will try to do that.

>> +       return IRQ_HANDLED;
>> +}
>> +
>> +static const struct watchdog_info ar2315_wdt_info = {
>> +       .identity = "ar2315 Watchdog",
>> +       .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING,
>> +};
>> +
>> +static const struct watchdog_ops ar2315_wdt_ops = {
>> +       .owner = THIS_MODULE,
>> +       .start = ar2315_wdt_start,
>> +       .stop = ar2315_wdt_stop,
>> +       .ping = ar2315_wdt_ping,
>> +       .set_timeout = ar2315_wdt_set_timeout,
>> +};
>> +
>> +static struct watchdog_device ar2315_wdt_dev = {
>> +       .info = &ar2315_wdt_info,
>> +       .ops = &ar2315_wdt_ops,
>> +       .min_timeout = 1,
>> +       .max_timeout = 90,
>> +       .timeout = 20,
>> +};
>> +
>> +static int ar2315_wdt_probe(struct platform_device *pdev)
>> +{
>> +       struct device *dev = &pdev->dev;
>> +       struct resource *res;
>> +       int ret = 0;
>> +
>> +       if (wdt_base)
>> +               return -EBUSY;
>> +
>> +       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
>> +       wdt_base = devm_ioremap_resource(dev, res);
>> +       if (IS_ERR(wdt_base))
>> +               return PTR_ERR(wdt_base);
>> +
>> +       res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
>> +       if (!res) {
>> +               dev_err(dev, "no IRQ resource\n");
>> +               return -ENOENT;
>> +       }
>> +
>> +       ret = devm_request_irq(dev, res->start, ar2315_wdt_interrupt, 0,
>> +                              DRIVER_NAME, pdev);
>> +       if (ret) {
>> +               dev_err(dev, "failed to register inetrrupt\n");
>> +               return ret;
>> +       }
>> +
>> +       ar2315_wdt_dev.parent = dev;
>> +       ret = watchdog_register_device(&ar2315_wdt_dev);
>> +       if (ret) {
>> +               dev_err(dev, "failed to register watchdog device\n");
>> +               return ret;
>> +       }
>> +
>> +       return 0;
>> +}
>> +
>> +static int ar2315_wdt_remove(struct platform_device *pdev)
>> +{
>> +       watchdog_unregister_device(&ar2315_wdt_dev);
>
>
> Why don't you stop the watchdog on remove ?
>
While the watchdog is running, the watchdog core prevents the module
unloading, so this routine could not be called while the watchdog is
running. Isn't it?

>
>> +       return 0;
>> +}
>> +
>> +static struct platform_driver ar2315_wdt_driver = {
>> +       .probe = ar2315_wdt_probe,
>> +       .remove = ar2315_wdt_remove,
>> +       .driver = {
>> +               .name = DRIVER_NAME,
>> +               .owner = THIS_MODULE,
>> +       },
>> +};
>> +
>> +module_platform_driver(ar2315_wdt_driver);
>> +
>> +MODULE_DESCRIPTION("Atheros AR2315 hardware watchdog driver");
>> +MODULE_AUTHOR("John Crispin <blogic@openwrt.org>");
>> +MODULE_LICENSE("GPL");
>> +MODULE_ALIAS("platform:" DRIVER_NAME);
>>
>

-- 
BR,
Sergey

^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [PATCH 12/16] watchdog: add Atheros AR2315 watchdog driver
  2014-09-29 20:14     ` Sergey Ryazanov
@ 2014-09-29 20:46       ` Guenter Roeck
  2014-09-29 21:01         ` Sergey Ryazanov
  0 siblings, 1 reply; 37+ messages in thread
From: Guenter Roeck @ 2014-09-29 20:46 UTC (permalink / raw)
  To: Sergey Ryazanov
  Cc: Ralf Baechle, Linux MIPS, Wim Van Sebroeck, linux-watchdog

On Tue, Sep 30, 2014 at 12:14:58AM +0400, Sergey Ryazanov wrote:
> 2014-09-29 1:35 GMT+04:00 Guenter Roeck <linux@roeck-us.net>:
> > On 09/28/2014 11:33 AM, Sergey Ryazanov wrote:
> >>
> >> Signed-off-by: Sergey Ryazanov <ryazanov.s.a@gmail.com>
> >> Cc: Wim Van Sebroeck <wim@iguana.be>
> >> Cc: linux-watchdog@vger.kernel.org
> >> ---
> >>
> >> Changes since RFC:
> >>    - use watchdog infrastructure
> >>    - remove deprecated IRQF_DISABLED flag
> >>    - move device registration to separate patch
> >>
> >>   drivers/watchdog/Kconfig      |   8 ++
> >>   drivers/watchdog/Makefile     |   1 +
> >>   drivers/watchdog/ar2315-wtd.c | 167
> >> ++++++++++++++++++++++++++++++++++++++++++
> >>   3 files changed, 176 insertions(+)
> >>   create mode 100644 drivers/watchdog/ar2315-wtd.c
> >>
> >> diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig
> >> index f57312f..dbace99 100644
> >> --- a/drivers/watchdog/Kconfig
> >> +++ b/drivers/watchdog/Kconfig
> >> @@ -1186,6 +1186,14 @@ config RALINK_WDT
> >>         help
> >>           Hardware driver for the Ralink SoC Watchdog Timer.
> >>
> >> +config AR2315_WDT
> >> +       tristate "Atheros AR2315+ WiSoCs Watchdog Timer"
> >> +       select WATCHDOG_CORE
> >> +       depends on SOC_AR2315
> >> +       help
> >> +         Hardware driver for the built-in watchdog timer on the Atheros
> >> +         AR2315/AR2316 WiSoCs.
> >> +
> >>   # PARISC Architecture
> >>
> >>   # POWERPC Architecture
> >> diff --git a/drivers/watchdog/Makefile b/drivers/watchdog/Makefile
> >> index 468c320..ef7f83b 100644
> >> --- a/drivers/watchdog/Makefile
> >> +++ b/drivers/watchdog/Makefile
> >> @@ -133,6 +133,7 @@ obj-$(CONFIG_WDT_MTX1) += mtx-1_wdt.o
> >>   obj-$(CONFIG_PNX833X_WDT) += pnx833x_wdt.o
> >>   obj-$(CONFIG_SIBYTE_WDOG) += sb_wdog.o
> >>   obj-$(CONFIG_AR7_WDT) += ar7_wdt.o
> >> +obj-$(CONFIG_AR2315_WDT) += ar2315-wtd.o
> >>   obj-$(CONFIG_TXX9_WDT) += txx9wdt.o
> >>   obj-$(CONFIG_OCTEON_WDT) += octeon-wdt.o
> >>   octeon-wdt-y := octeon-wdt-main.o octeon-wdt-nmi.o
> >> diff --git a/drivers/watchdog/ar2315-wtd.c b/drivers/watchdog/ar2315-wtd.c
> >> new file mode 100644
> >> index 0000000..4fd34d2
> >> --- /dev/null
> >> +++ b/drivers/watchdog/ar2315-wtd.c
> >> @@ -0,0 +1,167 @@
> >> +/*
> >> + * This program is free software; you can redistribute it and/or modify
> >> + * it under the terms of the GNU General Public License as published by
> >> + * the Free Software Foundation; either version 2 of the License, or
> >> + * (at your option) any later version.
> >> + *
> >> + * This program is distributed in the hope that it will be useful,
> >> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> >> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> >> + * GNU General Public License for more details.
> >> + *
> >> + * You should have received a copy of the GNU General Public License
> >> + * along with this program; if not, see <http://www.gnu.org/licenses/>.
> >> + *
> >> + * Copyright (C) 2008 John Crispin <blogic@openwrt.org>
> >> + * Based on EP93xx and ifxmips wdt driver
> >> + */
> >> +
> >> +#include <linux/interrupt.h>
> >> +#include <linux/module.h>
> >> +#include <linux/watchdog.h>
> >> +#include <linux/reboot.h>
> >> +#include <linux/init.h>
> >> +#include <linux/platform_device.h>
> >> +#include <linux/io.h>
> >> +
> >> +#define DRIVER_NAME    "ar2315-wdt"
> >> +
> >> +#define CLOCK_RATE 40000000
> >> +
> >> +#define WDT_REG_TIMER          0x00
> >> +#define WDT_REG_CTRL           0x04
> >> +
> >> +#define WDT_CTRL_ACT_NONE      0x00000000      /* No action */
> >> +#define WDT_CTRL_ACT_NMI       0x00000001      /* NMI on watchdog */
> >> +#define WDT_CTRL_ACT_RESET     0x00000002      /* reset on watchdog */
> >> +
> >
> > What are those defines for ? They don't seem to be used.
> >
> This defines for reference. There no documentation for this chips, so
> I left this defines as some kind of documentation.
> 
If they are not used, please drop those defines. They only create unnecessary
confusion if unused.

> > If the watchdog can result in an immediate restart, as
> > this define suggests, why don't you use it but rely on
> > the interrupt handler instead ?
> >
> AFAIK some of chips have a HW bug in restarting unit, so chip specific
> restart routine (in arch code) use a lot of hacks to reset chip. So we
> use interrupt to call reset function, which should reliably reset
> chip.
> 
> > This means the watchdog won't really fire if it times out, but depend
> > on the interrupt handler to work. Which it won't if there is a real
> > problem and interrupts are disabled (or if the system hangs entirely).
> >
> Sure. But without reset function call from the interrupt handler we
> can not reliable reset chip (see above).
> 
> >> +static int started;
> >> +static void __iomem *wdt_base;
> >> +
> >> +static inline void ar2315_wdt_wr(unsigned reg, u32 val)
> >> +{
> >> +       iowrite32(val, wdt_base + reg);
> >> +}
> >> +
> >> +static void ar2315_wdt_enable(struct watchdog_device *wdd)
> >> +{
> >> +       ar2315_wdt_wr(WDT_REG_TIMER, wdd->timeout * CLOCK_RATE);
> >> +}
> >> +
> >> +static int ar2315_wdt_start(struct watchdog_device *wdd)
> >> +{
> >> +       ar2315_wdt_enable(wdd);
> >> +       started = 1;
> >
> >
> > I don't really see why you would need this variable.
> >
> To protect against spurious interrupts, since the watchdog timer could
> be started by bootloader.
> 
Then it would be appropriate to stop it in the probe function.

> >
> >> +       return 0;
> >> +}
> >> +
> >> +static int ar2315_wdt_stop(struct watchdog_device *wdd)
> >> +{
> >> +       return 0;
> >> +}
> >> +
> >> +static int ar2315_wdt_ping(struct watchdog_device *wdd)
> >> +{
> >> +       ar2315_wdt_enable(wdd);
> >> +       return 0;
> >> +}
> >> +
> >> +static int ar2315_wdt_set_timeout(struct watchdog_device *wdd, unsigned
> >> val)
> >> +{
> >> +       wdd->timeout = val;
> >> +       return 0;
> >> +}
> >> +
> >> +static irqreturn_t ar2315_wdt_interrupt(int irq, void *dev)
> >> +{
> >> +       struct platform_device *pdev = (struct platform_device *)dev;
> >> +
> >> +       if (started) {
> >> +               dev_crit(&pdev->dev, "watchdog expired, rebooting
> >> system\n");
> >> +               emergency_restart();
> >> +       } else {
> >> +               ar2315_wdt_wr(WDT_REG_CTRL, 0);
> >> +               ar2315_wdt_wr(WDT_REG_TIMER, 0);
> >> +       }
> >
> >
> > This is quite unusual.
> > Why not stop the watchdog in the stop function ? Quite apparently
> > it can be stopped, or at least this is what it looks like.
> >
> The started variable is set to true inside the watchdog start routine,
> but it never reset to false. This code only disable the watchdog when
> it was started by bootloader.
> 
> > When do you expect this function to be called in the first place
> > with started == 1 ?
> >
> > If the idea is to stop the watchdog if it was already enabled
> > when probing the driver, why don't you stop it there ?
> >
> Sure, I will try to do that.
> 
> >> +       return IRQ_HANDLED;
> >> +}
> >> +
> >> +static const struct watchdog_info ar2315_wdt_info = {
> >> +       .identity = "ar2315 Watchdog",
> >> +       .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING,
> >> +};
> >> +
> >> +static const struct watchdog_ops ar2315_wdt_ops = {
> >> +       .owner = THIS_MODULE,
> >> +       .start = ar2315_wdt_start,
> >> +       .stop = ar2315_wdt_stop,
> >> +       .ping = ar2315_wdt_ping,
> >> +       .set_timeout = ar2315_wdt_set_timeout,
> >> +};
> >> +
> >> +static struct watchdog_device ar2315_wdt_dev = {
> >> +       .info = &ar2315_wdt_info,
> >> +       .ops = &ar2315_wdt_ops,
> >> +       .min_timeout = 1,
> >> +       .max_timeout = 90,
> >> +       .timeout = 20,
> >> +};
> >> +
> >> +static int ar2315_wdt_probe(struct platform_device *pdev)
> >> +{
> >> +       struct device *dev = &pdev->dev;
> >> +       struct resource *res;
> >> +       int ret = 0;
> >> +
> >> +       if (wdt_base)
> >> +               return -EBUSY;
> >> +
> >> +       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> >> +       wdt_base = devm_ioremap_resource(dev, res);
> >> +       if (IS_ERR(wdt_base))
> >> +               return PTR_ERR(wdt_base);
> >> +
> >> +       res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
> >> +       if (!res) {
> >> +               dev_err(dev, "no IRQ resource\n");
> >> +               return -ENOENT;
> >> +       }
> >> +
> >> +       ret = devm_request_irq(dev, res->start, ar2315_wdt_interrupt, 0,
> >> +                              DRIVER_NAME, pdev);
> >> +       if (ret) {
> >> +               dev_err(dev, "failed to register inetrrupt\n");
> >> +               return ret;
> >> +       }
> >> +
> >> +       ar2315_wdt_dev.parent = dev;
> >> +       ret = watchdog_register_device(&ar2315_wdt_dev);
> >> +       if (ret) {
> >> +               dev_err(dev, "failed to register watchdog device\n");
> >> +               return ret;
> >> +       }
> >> +
> >> +       return 0;
> >> +}
> >> +
> >> +static int ar2315_wdt_remove(struct platform_device *pdev)
> >> +{
> >> +       watchdog_unregister_device(&ar2315_wdt_dev);
> >
> >
> > Why don't you stop the watchdog on remove ?
> >
> While the watchdog is running, the watchdog core prevents the module
> unloading, so this routine could not be called while the watchdog is
> running. Isn't it?
> 
Only you never stop the watchdog nor disable the chip interrupt,
even on close (the stop function above does nothing).

Guenter

^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [PATCH 01/16] MIPS: ar231x: add common parts
  2014-09-29  9:30   ` Jonas Gorski
@ 2014-09-29 20:57     ` Sergey Ryazanov
  0 siblings, 0 replies; 37+ messages in thread
From: Sergey Ryazanov @ 2014-09-29 20:57 UTC (permalink / raw)
  To: Jonas Gorski; +Cc: Ralf Baechle, Linux MIPS

2014-09-29 13:30 GMT+04:00 Jonas Gorski <jogo@openwrt.org>:
> On Sun, Sep 28, 2014 at 8:33 PM, Sergey Ryazanov <ryazanov.s.a@gmail.com> wrote:
>> Add common code for Atheros AR5312 and Atheros AR2315 SoCs families.
>>
>> Signed-off-by: Sergey Ryazanov <ryazanov.s.a@gmail.com>
>> ---
>>  arch/mips/Kbuild.platforms                         |  1 +
>>  arch/mips/Kconfig                                  | 13 ++++
>>  arch/mips/ar231x/Makefile                          | 11 ++++
>>  arch/mips/ar231x/Platform                          |  6 ++
>>  arch/mips/ar231x/board.c                           | 53 +++++++++++++++
>>  arch/mips/ar231x/devices.c                         | 20 ++++++
>>  arch/mips/ar231x/devices.h                         | 22 +++++++
>>  arch/mips/ar231x/prom.c                            | 26 ++++++++
>>  arch/mips/include/asm/mach-ar231x/ar231x.h         | 29 +++++++++
>>  .../asm/mach-ar231x/cpu-feature-overrides.h        | 76 ++++++++++++++++++++++
>>  arch/mips/include/asm/mach-ar231x/dma-coherence.h  | 64 ++++++++++++++++++
>>  arch/mips/include/asm/mach-ar231x/gpio.h           | 16 +++++
>>  arch/mips/include/asm/mach-ar231x/war.h            | 25 +++++++
>>  13 files changed, 362 insertions(+)
>>  create mode 100644 arch/mips/ar231x/Makefile
>>  create mode 100644 arch/mips/ar231x/Platform
>>  create mode 100644 arch/mips/ar231x/board.c
>>  create mode 100644 arch/mips/ar231x/devices.c
>>  create mode 100644 arch/mips/ar231x/devices.h
>>  create mode 100644 arch/mips/ar231x/prom.c
>>  create mode 100644 arch/mips/include/asm/mach-ar231x/ar231x.h
>>  create mode 100644 arch/mips/include/asm/mach-ar231x/cpu-feature-overrides.h
>>  create mode 100644 arch/mips/include/asm/mach-ar231x/dma-coherence.h
>>  create mode 100644 arch/mips/include/asm/mach-ar231x/gpio.h
>>  create mode 100644 arch/mips/include/asm/mach-ar231x/war.h
>>
>> diff --git a/arch/mips/Kbuild.platforms b/arch/mips/Kbuild.platforms
>> index f5e18bf..ee1940a 100644
>> --- a/arch/mips/Kbuild.platforms
>> +++ b/arch/mips/Kbuild.platforms
>> @@ -1,6 +1,7 @@
>>  # All platforms listed in alphabetic order
>>
>>  platforms += alchemy
>> +platforms += ar231x
>>  platforms += ar7
>>  platforms += ath79
>>  platforms += bcm47xx
>> diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig
>> index 01c0389..6adae4c 100644
>> --- a/arch/mips/Kconfig
>> +++ b/arch/mips/Kconfig
>> @@ -73,6 +73,19 @@ config MIPS_ALCHEMY
>>         select SYS_SUPPORTS_ZBOOT
>>         select COMMON_CLK
>>
>> +config AR231X
>
> I would suggest naming it ATH25, to match the other atheros target (ATH79).
I have been thinking about such name. But decided to keep code closer
to owrt realization. May be maintainers could suggest smth. Ralf, what
do you think?

>
>> +       bool "Atheros AR231x/AR531x SoC support"
>> +       select CEVT_R4K
>> +       select CSRC_R4K
>> +       select DMA_NONCOHERENT
>> +       select IRQ_CPU
>> +       select SYS_HAS_CPU_MIPS32_R1
>> +       select SYS_SUPPORTS_BIG_ENDIAN
>> +       select SYS_SUPPORTS_32BIT_KERNEL
>> +       select ARCH_REQUIRE_GPIOLIB
>> +       help
>> +         Support for Atheros AR231x and Atheros AR531x based boards
>> +
>>  config AR7
>>         bool "Texas Instruments AR7"
>>         select BOOT_ELF32
>> diff --git a/arch/mips/ar231x/Makefile b/arch/mips/ar231x/Makefile
>> new file mode 100644
>> index 0000000..9199fa1
>> --- /dev/null
>> +++ b/arch/mips/ar231x/Makefile
>> @@ -0,0 +1,11 @@
>> +#
>> +# This file is subject to the terms and conditions of the GNU General Public
>> +# License.  See the file "COPYING" in the main directory of this archive
>> +# for more details.
>> +#
>> +# Copyright (C) 2006 FON Technology, SL.
>> +# Copyright (C) 2006 Imre Kaloz <kaloz@openwrt.org>
>> +# Copyright (C) 2006-2009 Felix Fietkau <nbd@openwrt.org>
>> +#
>> +
>> +obj-y += board.o prom.o devices.o
>> diff --git a/arch/mips/ar231x/Platform b/arch/mips/ar231x/Platform
>> new file mode 100644
>> index 0000000..c924fd1
>> --- /dev/null
>> +++ b/arch/mips/ar231x/Platform
>> @@ -0,0 +1,6 @@
>> +#
>> +# Atheros AR531X/AR231X WiSoC
>> +#
>> +platform-$(CONFIG_AR231X)      += ar231x/
>> +cflags-$(CONFIG_AR231X)                += -I$(srctree)/arch/mips/include/asm/mach-ar231x
>> +load-$(CONFIG_AR231X)          += 0xffffffff80041000
>> diff --git a/arch/mips/ar231x/board.c b/arch/mips/ar231x/board.c
>> new file mode 100644
>> index 0000000..9cde045
>> --- /dev/null
>> +++ b/arch/mips/ar231x/board.c
>> @@ -0,0 +1,53 @@
>> +/*
>> + * This file is subject to the terms and conditions of the GNU General Public
>> + * License.  See the file "COPYING" in the main directory of this archive
>> + * for more details.
>> + *
>> + * Copyright (C) 2003 Atheros Communications, Inc.,  All Rights Reserved.
>> + * Copyright (C) 2006 FON Technology, SL.
>> + * Copyright (C) 2006 Imre Kaloz <kaloz@openwrt.org>
>> + * Copyright (C) 2006-2009 Felix Fietkau <nbd@openwrt.org>
>> + */
>> +
>> +#include <linux/init.h>
>> +#include <linux/interrupt.h>
>> +#include <asm/irq_cpu.h>
>> +#include <asm/reboot.h>
>> +#include <asm/bootinfo.h>
>> +#include <asm/time.h>
>> +
>> +static void ar231x_halt(void)
>> +{
>> +       local_irq_disable();
>> +       while (1)
>> +               ;
>> +}
>> +
>> +void __init plat_mem_setup(void)
>> +{
>> +       _machine_halt = ar231x_halt;
>> +       pm_power_off = ar231x_halt;
>> +
>> +       /* Disable data watchpoints */
>> +       write_c0_watchlo0(0);
>> +}
>> +
>> +asmlinkage void plat_irq_dispatch(void)
>> +{
>> +}
>> +
>> +void __init plat_time_init(void)
>> +{
>> +}
>> +
>> +unsigned int __cpuinit get_c0_compare_int(void)
>> +{
>> +       return CP0_LEGACY_COMPARE_IRQ;
>> +}
>> +
>> +void __init arch_init_irq(void)
>> +{
>> +       clear_c0_status(ST0_IM);
>> +       mips_cpu_irq_init();
>> +}
>> +
>> diff --git a/arch/mips/ar231x/devices.c b/arch/mips/ar231x/devices.c
>> new file mode 100644
>> index 0000000..f71a643
>> --- /dev/null
>> +++ b/arch/mips/ar231x/devices.c
>> @@ -0,0 +1,20 @@
>> +#include <linux/kernel.h>
>> +#include <linux/init.h>
>> +#include <asm/bootinfo.h>
>> +
>> +#include "devices.h"
>> +
>> +int ar231x_devtype = DEV_TYPE_UNKNOWN;
>> +
>> +static const char * const devtype_strings[] = {
>> +       [DEV_TYPE_UNKNOWN] = "Atheros (unknown)",
>> +};
>> +
>> +const char *get_system_type(void)
>> +{
>> +       if ((ar231x_devtype >= ARRAY_SIZE(devtype_strings)) ||
>> +           !devtype_strings[ar231x_devtype])
>> +               return devtype_strings[DEV_TYPE_UNKNOWN];
>> +       return devtype_strings[ar231x_devtype];
>> +}
>> +
>> diff --git a/arch/mips/ar231x/devices.h b/arch/mips/ar231x/devices.h
>> new file mode 100644
>> index 0000000..1590577
>> --- /dev/null
>> +++ b/arch/mips/ar231x/devices.h
>> @@ -0,0 +1,22 @@
>> +#ifndef __AR231X_DEVICES_H
>> +#define __AR231X_DEVICES_H
>> +
>> +#include <linux/cpu.h>
>> +
>> +enum {
>> +       DEV_TYPE_UNKNOWN
>> +};
>> +
>> +extern int ar231x_devtype;
>> +
>> +static inline bool is_2315(void)
>
> Since this is matching the whole family of ar231x SoCs, I would
> suggest to give it a prefix and call it ath25_is_231x.
Only AR2315 and later chips have the 4KEc core.

>> +{
>> +       return (current_cpu_data.cputype == CPU_4KEC);
>
> Unnecessary ().
Thank you, I missed this braces during cleanup.

>
>> +}
>> +
>> +static inline bool is_5312(void)
>
> Same comment here for 5312 -> 531x.
>
This test is true for AR5312, AR2312 and AR2313 (see SoC type
detection patch), also we support only AR5312 SoC from whole AR531x
series.

>> +{
>> +       return !is_2315();
>> +}
>> +
>> +#endif
>
>
> Regards
> Jonas

-- 
BR,
Sergey

^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [PATCH 12/16] watchdog: add Atheros AR2315 watchdog driver
  2014-09-29 20:46       ` Guenter Roeck
@ 2014-09-29 21:01         ` Sergey Ryazanov
  0 siblings, 0 replies; 37+ messages in thread
From: Sergey Ryazanov @ 2014-09-29 21:01 UTC (permalink / raw)
  To: Guenter Roeck; +Cc: Ralf Baechle, Linux MIPS, Wim Van Sebroeck, linux-watchdog

2014-09-30 0:46 GMT+04:00 Guenter Roeck <linux@roeck-us.net>:
> On Tue, Sep 30, 2014 at 12:14:58AM +0400, Sergey Ryazanov wrote:
>> 2014-09-29 1:35 GMT+04:00 Guenter Roeck <linux@roeck-us.net>:
>> > On 09/28/2014 11:33 AM, Sergey Ryazanov wrote:
>> >>
>> >> Signed-off-by: Sergey Ryazanov <ryazanov.s.a@gmail.com>
>> >> Cc: Wim Van Sebroeck <wim@iguana.be>
>> >> Cc: linux-watchdog@vger.kernel.org
>> >> ---
>> >>
>> >> Changes since RFC:
>> >>    - use watchdog infrastructure
>> >>    - remove deprecated IRQF_DISABLED flag
>> >>    - move device registration to separate patch
>> >>
>> >>   drivers/watchdog/Kconfig      |   8 ++
>> >>   drivers/watchdog/Makefile     |   1 +
>> >>   drivers/watchdog/ar2315-wtd.c | 167
>> >> ++++++++++++++++++++++++++++++++++++++++++
>> >>   3 files changed, 176 insertions(+)
>> >>   create mode 100644 drivers/watchdog/ar2315-wtd.c
>> >>
>> >> diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig
>> >> index f57312f..dbace99 100644
>> >> --- a/drivers/watchdog/Kconfig
>> >> +++ b/drivers/watchdog/Kconfig
>> >> @@ -1186,6 +1186,14 @@ config RALINK_WDT
>> >>         help
>> >>           Hardware driver for the Ralink SoC Watchdog Timer.
>> >>
>> >> +config AR2315_WDT
>> >> +       tristate "Atheros AR2315+ WiSoCs Watchdog Timer"
>> >> +       select WATCHDOG_CORE
>> >> +       depends on SOC_AR2315
>> >> +       help
>> >> +         Hardware driver for the built-in watchdog timer on the Atheros
>> >> +         AR2315/AR2316 WiSoCs.
>> >> +
>> >>   # PARISC Architecture
>> >>
>> >>   # POWERPC Architecture
>> >> diff --git a/drivers/watchdog/Makefile b/drivers/watchdog/Makefile
>> >> index 468c320..ef7f83b 100644
>> >> --- a/drivers/watchdog/Makefile
>> >> +++ b/drivers/watchdog/Makefile
>> >> @@ -133,6 +133,7 @@ obj-$(CONFIG_WDT_MTX1) += mtx-1_wdt.o
>> >>   obj-$(CONFIG_PNX833X_WDT) += pnx833x_wdt.o
>> >>   obj-$(CONFIG_SIBYTE_WDOG) += sb_wdog.o
>> >>   obj-$(CONFIG_AR7_WDT) += ar7_wdt.o
>> >> +obj-$(CONFIG_AR2315_WDT) += ar2315-wtd.o
>> >>   obj-$(CONFIG_TXX9_WDT) += txx9wdt.o
>> >>   obj-$(CONFIG_OCTEON_WDT) += octeon-wdt.o
>> >>   octeon-wdt-y := octeon-wdt-main.o octeon-wdt-nmi.o
>> >> diff --git a/drivers/watchdog/ar2315-wtd.c b/drivers/watchdog/ar2315-wtd.c
>> >> new file mode 100644
>> >> index 0000000..4fd34d2
>> >> --- /dev/null
>> >> +++ b/drivers/watchdog/ar2315-wtd.c
>> >> @@ -0,0 +1,167 @@
>> >> +/*
>> >> + * This program is free software; you can redistribute it and/or modify
>> >> + * it under the terms of the GNU General Public License as published by
>> >> + * the Free Software Foundation; either version 2 of the License, or
>> >> + * (at your option) any later version.
>> >> + *
>> >> + * This program is distributed in the hope that it will be useful,
>> >> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
>> >> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
>> >> + * GNU General Public License for more details.
>> >> + *
>> >> + * You should have received a copy of the GNU General Public License
>> >> + * along with this program; if not, see <http://www.gnu.org/licenses/>.
>> >> + *
>> >> + * Copyright (C) 2008 John Crispin <blogic@openwrt.org>
>> >> + * Based on EP93xx and ifxmips wdt driver
>> >> + */
>> >> +
>> >> +#include <linux/interrupt.h>
>> >> +#include <linux/module.h>
>> >> +#include <linux/watchdog.h>
>> >> +#include <linux/reboot.h>
>> >> +#include <linux/init.h>
>> >> +#include <linux/platform_device.h>
>> >> +#include <linux/io.h>
>> >> +
>> >> +#define DRIVER_NAME    "ar2315-wdt"
>> >> +
>> >> +#define CLOCK_RATE 40000000
>> >> +
>> >> +#define WDT_REG_TIMER          0x00
>> >> +#define WDT_REG_CTRL           0x04
>> >> +
>> >> +#define WDT_CTRL_ACT_NONE      0x00000000      /* No action */
>> >> +#define WDT_CTRL_ACT_NMI       0x00000001      /* NMI on watchdog */
>> >> +#define WDT_CTRL_ACT_RESET     0x00000002      /* reset on watchdog */
>> >> +
>> >
>> > What are those defines for ? They don't seem to be used.
>> >
>> This defines for reference. There no documentation for this chips, so
>> I left this defines as some kind of documentation.
>>
> If they are not used, please drop those defines. They only create unnecessary
> confusion if unused.
>
Ok.

>> > If the watchdog can result in an immediate restart, as
>> > this define suggests, why don't you use it but rely on
>> > the interrupt handler instead ?
>> >
>> AFAIK some of chips have a HW bug in restarting unit, so chip specific
>> restart routine (in arch code) use a lot of hacks to reset chip. So we
>> use interrupt to call reset function, which should reliably reset
>> chip.
>>
>> > This means the watchdog won't really fire if it times out, but depend
>> > on the interrupt handler to work. Which it won't if there is a real
>> > problem and interrupts are disabled (or if the system hangs entirely).
>> >
>> Sure. But without reset function call from the interrupt handler we
>> can not reliable reset chip (see above).
>>
>> >> +static int started;
>> >> +static void __iomem *wdt_base;
>> >> +
>> >> +static inline void ar2315_wdt_wr(unsigned reg, u32 val)
>> >> +{
>> >> +       iowrite32(val, wdt_base + reg);
>> >> +}
>> >> +
>> >> +static void ar2315_wdt_enable(struct watchdog_device *wdd)
>> >> +{
>> >> +       ar2315_wdt_wr(WDT_REG_TIMER, wdd->timeout * CLOCK_RATE);
>> >> +}
>> >> +
>> >> +static int ar2315_wdt_start(struct watchdog_device *wdd)
>> >> +{
>> >> +       ar2315_wdt_enable(wdd);
>> >> +       started = 1;
>> >
>> >
>> > I don't really see why you would need this variable.
>> >
>> To protect against spurious interrupts, since the watchdog timer could
>> be started by bootloader.
>>
> Then it would be appropriate to stop it in the probe function.
>
Yes sure.

>> >
>> >> +       return 0;
>> >> +}
>> >> +
>> >> +static int ar2315_wdt_stop(struct watchdog_device *wdd)
>> >> +{
>> >> +       return 0;
>> >> +}
>> >> +
>> >> +static int ar2315_wdt_ping(struct watchdog_device *wdd)
>> >> +{
>> >> +       ar2315_wdt_enable(wdd);
>> >> +       return 0;
>> >> +}
>> >> +
>> >> +static int ar2315_wdt_set_timeout(struct watchdog_device *wdd, unsigned
>> >> val)
>> >> +{
>> >> +       wdd->timeout = val;
>> >> +       return 0;
>> >> +}
>> >> +
>> >> +static irqreturn_t ar2315_wdt_interrupt(int irq, void *dev)
>> >> +{
>> >> +       struct platform_device *pdev = (struct platform_device *)dev;
>> >> +
>> >> +       if (started) {
>> >> +               dev_crit(&pdev->dev, "watchdog expired, rebooting
>> >> system\n");
>> >> +               emergency_restart();
>> >> +       } else {
>> >> +               ar2315_wdt_wr(WDT_REG_CTRL, 0);
>> >> +               ar2315_wdt_wr(WDT_REG_TIMER, 0);
>> >> +       }
>> >
>> >
>> > This is quite unusual.
>> > Why not stop the watchdog in the stop function ? Quite apparently
>> > it can be stopped, or at least this is what it looks like.
>> >
>> The started variable is set to true inside the watchdog start routine,
>> but it never reset to false. This code only disable the watchdog when
>> it was started by bootloader.
>>
>> > When do you expect this function to be called in the first place
>> > with started == 1 ?
>> >
>> > If the idea is to stop the watchdog if it was already enabled
>> > when probing the driver, why don't you stop it there ?
>> >
>> Sure, I will try to do that.
>>
>> >> +       return IRQ_HANDLED;
>> >> +}
>> >> +
>> >> +static const struct watchdog_info ar2315_wdt_info = {
>> >> +       .identity = "ar2315 Watchdog",
>> >> +       .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING,
>> >> +};
>> >> +
>> >> +static const struct watchdog_ops ar2315_wdt_ops = {
>> >> +       .owner = THIS_MODULE,
>> >> +       .start = ar2315_wdt_start,
>> >> +       .stop = ar2315_wdt_stop,
>> >> +       .ping = ar2315_wdt_ping,
>> >> +       .set_timeout = ar2315_wdt_set_timeout,
>> >> +};
>> >> +
>> >> +static struct watchdog_device ar2315_wdt_dev = {
>> >> +       .info = &ar2315_wdt_info,
>> >> +       .ops = &ar2315_wdt_ops,
>> >> +       .min_timeout = 1,
>> >> +       .max_timeout = 90,
>> >> +       .timeout = 20,
>> >> +};
>> >> +
>> >> +static int ar2315_wdt_probe(struct platform_device *pdev)
>> >> +{
>> >> +       struct device *dev = &pdev->dev;
>> >> +       struct resource *res;
>> >> +       int ret = 0;
>> >> +
>> >> +       if (wdt_base)
>> >> +               return -EBUSY;
>> >> +
>> >> +       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
>> >> +       wdt_base = devm_ioremap_resource(dev, res);
>> >> +       if (IS_ERR(wdt_base))
>> >> +               return PTR_ERR(wdt_base);
>> >> +
>> >> +       res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
>> >> +       if (!res) {
>> >> +               dev_err(dev, "no IRQ resource\n");
>> >> +               return -ENOENT;
>> >> +       }
>> >> +
>> >> +       ret = devm_request_irq(dev, res->start, ar2315_wdt_interrupt, 0,
>> >> +                              DRIVER_NAME, pdev);
>> >> +       if (ret) {
>> >> +               dev_err(dev, "failed to register inetrrupt\n");
>> >> +               return ret;
>> >> +       }
>> >> +
>> >> +       ar2315_wdt_dev.parent = dev;
>> >> +       ret = watchdog_register_device(&ar2315_wdt_dev);
>> >> +       if (ret) {
>> >> +               dev_err(dev, "failed to register watchdog device\n");
>> >> +               return ret;
>> >> +       }
>> >> +
>> >> +       return 0;
>> >> +}
>> >> +
>> >> +static int ar2315_wdt_remove(struct platform_device *pdev)
>> >> +{
>> >> +       watchdog_unregister_device(&ar2315_wdt_dev);
>> >
>> >
>> > Why don't you stop the watchdog on remove ?
>> >
>> While the watchdog is running, the watchdog core prevents the module
>> unloading, so this routine could not be called while the watchdog is
>> running. Isn't it?
>>
> Only you never stop the watchdog nor disable the chip interrupt,
> even on close (the stop function above does nothing).
>
Oops. I really forget to disable interrupt. Thank you!

-- 
BR,
Sergey

^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [PATCH 02/16] MIPS: ar231x: add basic AR5312 SoC support
  2014-09-29  9:35   ` Jonas Gorski
@ 2014-09-29 21:05     ` Sergey Ryazanov
  0 siblings, 0 replies; 37+ messages in thread
From: Sergey Ryazanov @ 2014-09-29 21:05 UTC (permalink / raw)
  To: Jonas Gorski; +Cc: Ralf Baechle, Linux MIPS

2014-09-29 13:35 GMT+04:00 Jonas Gorski <jogo@openwrt.org>:
> On Sun, Sep 28, 2014 at 8:33 PM, Sergey Ryazanov <ryazanov.s.a@gmail.com> wrote:
>> Add basic support for Atheros AR5312/AR2312 SoCs: registers definition
>> file and initial setup code.
>
> For the whole file: please use the style
>
> do_foo()
> {
>   if (is_ar5312())
>       ar5312_foo();
> }
>
> instead of
>
> do_foo()
> {
>   ar5312_foo();
> }
>
> ar5312_foo()
> {
>   if (!is_ar5312())
>     return;
> }
>
Ok.

> also same comments regarding naming (ar531x instead of ar5312).
>
Seems there are no reasons to change naming approach (see details in
previous patch discussion).

> Regards
> Jonas

-- 
BR,
Sergey

^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [PATCH 15/16] ath5k: update dependencies
  2014-09-28 18:33 ` [PATCH 15/16] ath5k: update dependencies Sergey Ryazanov
@ 2014-09-30 17:20   ` John W. Linville
  2014-10-01 14:41     ` Sergey Ryazanov
  0 siblings, 1 reply; 37+ messages in thread
From: John W. Linville @ 2014-09-30 17:20 UTC (permalink / raw)
  To: Sergey Ryazanov
  Cc: Ralf Baechle, Linux MIPS, Jiri Slaby, Nick Kossifidis,
	Luis R. Rodriguez, linux-wireless, ath5k-devel

This patch does not seem to apply to wireless-next.  What tree is it
based upon?

John

On Sun, Sep 28, 2014 at 10:33:14PM +0400, Sergey Ryazanov wrote:
> - Use config symbol defined in the driver instead of arch specific one for
>   conditional compilation.
> - Rename the ATHEROS_AR231X config symbol to AR231X.
> - Some of AR231x SoCs (e.g. AR2315) have PCI bus support, so remove !PCI
>   dependency, which block AHB support build.
> 
> Signed-off-by: Sergey Ryazanov <ryazanov.s.a@gmail.com>
> Cc: Jiri Slaby <jirislaby@gmail.com>
> Cc: Nick Kossifidis <mickflemm@gmail.com>
> Cc: "Luis R. Rodriguez" <mcgrof@do-not-panic.com>
> Cc: linux-wireless@vger.kernel.org
> Cc: ath5k-devel@lists.ath5k.org
> ---
> 
> Changes since RFC:
>   - merge together patches that update ath5k dependencies
> 
>  drivers/net/wireless/ath/ath5k/Kconfig | 10 +++++-----
>  drivers/net/wireless/ath/ath5k/ath5k.h |  2 +-
>  drivers/net/wireless/ath/ath5k/base.c  |  4 ++--
>  drivers/net/wireless/ath/ath5k/led.c   |  4 ++--
>  4 files changed, 10 insertions(+), 10 deletions(-)
> 
> diff --git a/drivers/net/wireless/ath/ath5k/Kconfig b/drivers/net/wireless/ath/ath5k/Kconfig
> index c9f81a3..2b2a399 100644
> --- a/drivers/net/wireless/ath/ath5k/Kconfig
> +++ b/drivers/net/wireless/ath/ath5k/Kconfig
> @@ -1,13 +1,13 @@
>  config ATH5K
>  	tristate "Atheros 5xxx wireless cards support"
> -	depends on (PCI || ATHEROS_AR231X) && MAC80211
> +	depends on (PCI || AR231X) && MAC80211
>  	select ATH_COMMON
>  	select MAC80211_LEDS
>  	select LEDS_CLASS
>  	select NEW_LEDS
>  	select AVERAGE
> -	select ATH5K_AHB if (ATHEROS_AR231X && !PCI)
> -	select ATH5K_PCI if (!ATHEROS_AR231X && PCI)
> +	select ATH5K_AHB if AR231X
> +	select ATH5K_PCI if !AR231X
>  	---help---
>  	  This module adds support for wireless adapters based on
>  	  Atheros 5xxx chipset.
> @@ -54,14 +54,14 @@ config ATH5K_TRACER
>  
>  config ATH5K_AHB
>  	bool "Atheros 5xxx AHB bus support"
> -	depends on (ATHEROS_AR231X && !PCI)
> +	depends on AR231X
>  	---help---
>  	  This adds support for WiSoC type chipsets of the 5xxx Atheros
>  	  family.
>  
>  config ATH5K_PCI
>  	bool "Atheros 5xxx PCI bus support"
> -	depends on (!ATHEROS_AR231X && PCI)
> +	depends on (!AR231X && PCI)
>  	---help---
>  	  This adds support for PCI type chipsets of the 5xxx Atheros
>  	  family.
> diff --git a/drivers/net/wireless/ath/ath5k/ath5k.h b/drivers/net/wireless/ath/ath5k/ath5k.h
> index 85316bb..1ed7a88 100644
> --- a/drivers/net/wireless/ath/ath5k/ath5k.h
> +++ b/drivers/net/wireless/ath/ath5k/ath5k.h
> @@ -1647,7 +1647,7 @@ static inline struct ath_regulatory *ath5k_hw_regulatory(struct ath5k_hw *ah)
>  	return &(ath5k_hw_common(ah)->regulatory);
>  }
>  
> -#ifdef CONFIG_ATHEROS_AR231X
> +#ifdef CONFIG_ATH5K_AHB
>  #define AR5K_AR2315_PCI_BASE	((void __iomem *)0xb0100000)
>  
>  static inline void __iomem *ath5k_ahb_reg(struct ath5k_hw *ah, u16 reg)
> diff --git a/drivers/net/wireless/ath/ath5k/base.c b/drivers/net/wireless/ath/ath5k/base.c
> index 8ad2550..dd42487 100644
> --- a/drivers/net/wireless/ath/ath5k/base.c
> +++ b/drivers/net/wireless/ath/ath5k/base.c
> @@ -99,7 +99,7 @@ static int ath5k_reset(struct ath5k_hw *ah, struct ieee80211_channel *chan,
>  
>  /* Known SREVs */
>  static const struct ath5k_srev_name srev_names[] = {
> -#ifdef CONFIG_ATHEROS_AR231X
> +#ifdef CONFIG_ATH5K_AHB
>  	{ "5312",	AR5K_VERSION_MAC,	AR5K_SREV_AR5312_R2 },
>  	{ "5312",	AR5K_VERSION_MAC,	AR5K_SREV_AR5312_R7 },
>  	{ "2313",	AR5K_VERSION_MAC,	AR5K_SREV_AR2313_R8 },
> @@ -142,7 +142,7 @@ static const struct ath5k_srev_name srev_names[] = {
>  	{ "5413",	AR5K_VERSION_RAD,	AR5K_SREV_RAD_5413 },
>  	{ "5424",	AR5K_VERSION_RAD,	AR5K_SREV_RAD_5424 },
>  	{ "5133",	AR5K_VERSION_RAD,	AR5K_SREV_RAD_5133 },
> -#ifdef CONFIG_ATHEROS_AR231X
> +#ifdef CONFIG_ATH5K_AHB
>  	{ "2316",	AR5K_VERSION_RAD,	AR5K_SREV_RAD_2316 },
>  	{ "2317",	AR5K_VERSION_RAD,	AR5K_SREV_RAD_2317 },
>  #endif
> diff --git a/drivers/net/wireless/ath/ath5k/led.c b/drivers/net/wireless/ath/ath5k/led.c
> index 48a6a69b..c730677 100644
> --- a/drivers/net/wireless/ath/ath5k/led.c
> +++ b/drivers/net/wireless/ath/ath5k/led.c
> @@ -162,7 +162,7 @@ int ath5k_init_leds(struct ath5k_hw *ah)
>  {
>  	int ret = 0;
>  	struct ieee80211_hw *hw = ah->hw;
> -#ifndef CONFIG_ATHEROS_AR231X
> +#ifndef CONFIG_ATH5K_AHB
>  	struct pci_dev *pdev = ah->pdev;
>  #endif
>  	char name[ATH5K_LED_MAX_NAME_LEN + 1];
> @@ -171,7 +171,7 @@ int ath5k_init_leds(struct ath5k_hw *ah)
>  	if (!ah->pdev)
>  		return 0;
>  
> -#ifdef CONFIG_ATHEROS_AR231X
> +#ifdef CONFIG_ATH5K_AHB
>  	match = NULL;
>  #else
>  	match = pci_match_id(&ath5k_led_devices[0], pdev);
> -- 
> 1.8.5.5
> 
> --
> To unsubscribe from this list: send the line "unsubscribe linux-wireless" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
> 

-- 
John W. Linville		Someday the world will need a hero, and you
linville@tuxdriver.com			might be all we have.  Be ready.

^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [PATCH 15/16] ath5k: update dependencies
  2014-09-30 17:20   ` John W. Linville
@ 2014-10-01 14:41     ` Sergey Ryazanov
  2014-10-02 17:37       ` John W. Linville
  0 siblings, 1 reply; 37+ messages in thread
From: Sergey Ryazanov @ 2014-10-01 14:41 UTC (permalink / raw)
  To: John W. Linville
  Cc: Ralf Baechle, Linux MIPS, Jiri Slaby, Nick Kossifidis,
	Luis R. Rodriguez, linux-wireless, ath5k-devel

2014-09-30 21:20 GMT+04:00 John W. Linville <linville@tuxdriver.com>:
> This patch does not seem to apply to wireless-next.  What tree is it
> based upon?
>
> John
>
Its based on linux-mips. I thought that ath5k was not changed in
recent time and did not  rebase patch on top of wireless-next.

John, could you delay patch merging? There is an idea to rename ar231x
in ath25, to be consistent with ath79 for AR71xx/AR9xxx.

> On Sun, Sep 28, 2014 at 10:33:14PM +0400, Sergey Ryazanov wrote:
>> - Use config symbol defined in the driver instead of arch specific one for
>>   conditional compilation.
>> - Rename the ATHEROS_AR231X config symbol to AR231X.
>> - Some of AR231x SoCs (e.g. AR2315) have PCI bus support, so remove !PCI
>>   dependency, which block AHB support build.
>>
>> Signed-off-by: Sergey Ryazanov <ryazanov.s.a@gmail.com>
>> Cc: Jiri Slaby <jirislaby@gmail.com>
>> Cc: Nick Kossifidis <mickflemm@gmail.com>
>> Cc: "Luis R. Rodriguez" <mcgrof@do-not-panic.com>
>> Cc: linux-wireless@vger.kernel.org
>> Cc: ath5k-devel@lists.ath5k.org
>> ---
>>
>> Changes since RFC:
>>   - merge together patches that update ath5k dependencies
>>
>>  drivers/net/wireless/ath/ath5k/Kconfig | 10 +++++-----
>>  drivers/net/wireless/ath/ath5k/ath5k.h |  2 +-
>>  drivers/net/wireless/ath/ath5k/base.c  |  4 ++--
>>  drivers/net/wireless/ath/ath5k/led.c   |  4 ++--
>>  4 files changed, 10 insertions(+), 10 deletions(-)
>>
>> diff --git a/drivers/net/wireless/ath/ath5k/Kconfig b/drivers/net/wireless/ath/ath5k/Kconfig
>> index c9f81a3..2b2a399 100644
>> --- a/drivers/net/wireless/ath/ath5k/Kconfig
>> +++ b/drivers/net/wireless/ath/ath5k/Kconfig
>> @@ -1,13 +1,13 @@
>>  config ATH5K
>>       tristate "Atheros 5xxx wireless cards support"
>> -     depends on (PCI || ATHEROS_AR231X) && MAC80211
>> +     depends on (PCI || AR231X) && MAC80211
>>       select ATH_COMMON
>>       select MAC80211_LEDS
>>       select LEDS_CLASS
>>       select NEW_LEDS
>>       select AVERAGE
>> -     select ATH5K_AHB if (ATHEROS_AR231X && !PCI)
>> -     select ATH5K_PCI if (!ATHEROS_AR231X && PCI)
>> +     select ATH5K_AHB if AR231X
>> +     select ATH5K_PCI if !AR231X
>>       ---help---
>>         This module adds support for wireless adapters based on
>>         Atheros 5xxx chipset.
>> @@ -54,14 +54,14 @@ config ATH5K_TRACER
>>
>>  config ATH5K_AHB
>>       bool "Atheros 5xxx AHB bus support"
>> -     depends on (ATHEROS_AR231X && !PCI)
>> +     depends on AR231X
>>       ---help---
>>         This adds support for WiSoC type chipsets of the 5xxx Atheros
>>         family.
>>
>>  config ATH5K_PCI
>>       bool "Atheros 5xxx PCI bus support"
>> -     depends on (!ATHEROS_AR231X && PCI)
>> +     depends on (!AR231X && PCI)
>>       ---help---
>>         This adds support for PCI type chipsets of the 5xxx Atheros
>>         family.
>> diff --git a/drivers/net/wireless/ath/ath5k/ath5k.h b/drivers/net/wireless/ath/ath5k/ath5k.h
>> index 85316bb..1ed7a88 100644
>> --- a/drivers/net/wireless/ath/ath5k/ath5k.h
>> +++ b/drivers/net/wireless/ath/ath5k/ath5k.h
>> @@ -1647,7 +1647,7 @@ static inline struct ath_regulatory *ath5k_hw_regulatory(struct ath5k_hw *ah)
>>       return &(ath5k_hw_common(ah)->regulatory);
>>  }
>>
>> -#ifdef CONFIG_ATHEROS_AR231X
>> +#ifdef CONFIG_ATH5K_AHB
>>  #define AR5K_AR2315_PCI_BASE ((void __iomem *)0xb0100000)
>>
>>  static inline void __iomem *ath5k_ahb_reg(struct ath5k_hw *ah, u16 reg)
>> diff --git a/drivers/net/wireless/ath/ath5k/base.c b/drivers/net/wireless/ath/ath5k/base.c
>> index 8ad2550..dd42487 100644
>> --- a/drivers/net/wireless/ath/ath5k/base.c
>> +++ b/drivers/net/wireless/ath/ath5k/base.c
>> @@ -99,7 +99,7 @@ static int ath5k_reset(struct ath5k_hw *ah, struct ieee80211_channel *chan,
>>
>>  /* Known SREVs */
>>  static const struct ath5k_srev_name srev_names[] = {
>> -#ifdef CONFIG_ATHEROS_AR231X
>> +#ifdef CONFIG_ATH5K_AHB
>>       { "5312",       AR5K_VERSION_MAC,       AR5K_SREV_AR5312_R2 },
>>       { "5312",       AR5K_VERSION_MAC,       AR5K_SREV_AR5312_R7 },
>>       { "2313",       AR5K_VERSION_MAC,       AR5K_SREV_AR2313_R8 },
>> @@ -142,7 +142,7 @@ static const struct ath5k_srev_name srev_names[] = {
>>       { "5413",       AR5K_VERSION_RAD,       AR5K_SREV_RAD_5413 },
>>       { "5424",       AR5K_VERSION_RAD,       AR5K_SREV_RAD_5424 },
>>       { "5133",       AR5K_VERSION_RAD,       AR5K_SREV_RAD_5133 },
>> -#ifdef CONFIG_ATHEROS_AR231X
>> +#ifdef CONFIG_ATH5K_AHB
>>       { "2316",       AR5K_VERSION_RAD,       AR5K_SREV_RAD_2316 },
>>       { "2317",       AR5K_VERSION_RAD,       AR5K_SREV_RAD_2317 },
>>  #endif
>> diff --git a/drivers/net/wireless/ath/ath5k/led.c b/drivers/net/wireless/ath/ath5k/led.c
>> index 48a6a69b..c730677 100644
>> --- a/drivers/net/wireless/ath/ath5k/led.c
>> +++ b/drivers/net/wireless/ath/ath5k/led.c
>> @@ -162,7 +162,7 @@ int ath5k_init_leds(struct ath5k_hw *ah)
>>  {
>>       int ret = 0;
>>       struct ieee80211_hw *hw = ah->hw;
>> -#ifndef CONFIG_ATHEROS_AR231X
>> +#ifndef CONFIG_ATH5K_AHB
>>       struct pci_dev *pdev = ah->pdev;
>>  #endif
>>       char name[ATH5K_LED_MAX_NAME_LEN + 1];
>> @@ -171,7 +171,7 @@ int ath5k_init_leds(struct ath5k_hw *ah)
>>       if (!ah->pdev)
>>               return 0;
>>
>> -#ifdef CONFIG_ATHEROS_AR231X
>> +#ifdef CONFIG_ATH5K_AHB
>>       match = NULL;
>>  #else
>>       match = pci_match_id(&ath5k_led_devices[0], pdev);
>> --
>> 1.8.5.5
>>

-- 
BR,
Sergey

С наилучшими пожеланиями
Рязанов Сергей

^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [PATCH 15/16] ath5k: update dependencies
  2014-10-01 14:41     ` Sergey Ryazanov
@ 2014-10-02 17:37       ` John W. Linville
  0 siblings, 0 replies; 37+ messages in thread
From: John W. Linville @ 2014-10-02 17:37 UTC (permalink / raw)
  To: Sergey Ryazanov
  Cc: Ralf Baechle, Linux MIPS, Jiri Slaby, Nick Kossifidis,
	Luis R. Rodriguez, linux-wireless, ath5k-devel

On Wed, Oct 01, 2014 at 06:41:34PM +0400, Sergey Ryazanov wrote:
> 2014-09-30 21:20 GMT+04:00 John W. Linville <linville@tuxdriver.com>:
> > This patch does not seem to apply to wireless-next.  What tree is it
> > based upon?
> >
> > John
> >
> Its based on linux-mips. I thought that ath5k was not changed in
> recent time and did not  rebase patch on top of wireless-next.
> 
> John, could you delay patch merging? There is an idea to rename ar231x
> in ath25, to be consistent with ath79 for AR71xx/AR9xxx.

OK

-- 
John W. Linville		Someday the world will need a hero, and you
linville@tuxdriver.com			might be all we have.  Be ready.

^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [PATCH 09/16] gpio: add driver for Atheros AR5312 SoC GPIO controller
  2014-09-28 18:33 ` [PATCH 09/16] gpio: add driver for Atheros AR5312 SoC GPIO controller Sergey Ryazanov
@ 2014-10-15  7:33   ` Linus Walleij
  0 siblings, 0 replies; 37+ messages in thread
From: Linus Walleij @ 2014-10-15  7:33 UTC (permalink / raw)
  To: Sergey Ryazanov; +Cc: Ralf Baechle, Linux MIPS, Alexandre Courbot, linux-gpio

On Sun, Sep 28, 2014 at 8:33 PM, Sergey Ryazanov <ryazanov.s.a@gmail.com> wrote:

> Atheros AR5312 SoC have a builtin GPIO controller, which could be accessed
> via memory mapped registers. This patch adds new driver for them.
>
> Signed-off-by: Sergey Ryazanov <ryazanov.s.a@gmail.com>
> Cc: Linus Walleij <linus.walleij@linaro.org>
> Cc: Alexandre Courbot <gnurou@gmail.com>
> Cc: linux-gpio@vger.kernel.org

This driver is extremely simple. You should be able to use
drivers/gpio/gpio-generic.c for this.

NAK for the time being.

> +#define AR5312_GPIO_CR_INT(x)  (1 << ((x)+8))  /* mask for interrupt */

Seems to be unused.
For a MMIO gpiochip using interrupts it's still possible
to use gpio-generic.c as a library-

> +#define AR5312_GPIO_CR_UART(x) (1 << ((x)+16)) /* uart multiplex */

That sounds like pin control business.

Yours,
Linus Walleij

^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [PATCH 10/16] gpio: add driver for Atheros AR2315 SoC GPIO controller
  2014-09-28 18:33 ` [PATCH 10/16] gpio: add driver for Atheros AR2315 " Sergey Ryazanov
@ 2014-10-15  8:58   ` Linus Walleij
  2014-10-15 11:12     ` Sergey Ryazanov
  0 siblings, 1 reply; 37+ messages in thread
From: Linus Walleij @ 2014-10-15  8:58 UTC (permalink / raw)
  To: Sergey Ryazanov; +Cc: Ralf Baechle, Linux MIPS, Alexandre Courbot, linux-gpio

On Sun, Sep 28, 2014 at 8:33 PM, Sergey Ryazanov <ryazanov.s.a@gmail.com> wrote:

> Atheros AR2315 SoC have a builtin GPIO controller, which could be
> accessed via memory mapped registers. This patch adds new driver
> for them.
>
> Signed-off-by: Sergey Ryazanov <ryazanov.s.a@gmail.com>
> Cc: Linus Walleij <linus.walleij@linaro.org>
> Cc: Alexandre Courbot <gnurou@gmail.com>
> Cc: linux-gpio@vger.kernel.org

> +config GPIO_AR2315
> +       bool "AR2315 SoC GPIO support"
> +       default y if SOC_AR2315
> +       depends on SOC_AR2315
> +       help
> +         Say yes here to enable GPIO support for Atheros AR2315+ SoCs.

select GPIOLIB_IRQCHIP

As far as I can see this driver should use the gpiolib irqchip helpers
and create a cascading irqchip. The code uses some copy/pasting
from earlier drivers which is not a good idea. Look at one of the drivers
using GPIOLIB_IRQCHIP and be inspired, check e.g. gpio-pl061.c
or gpio-zynq.c

> +static u32 ar2315_gpio_intmask;
> +static u32 ar2315_gpio_intval;
> +static unsigned ar2315_gpio_irq_base;
> +static void __iomem *ar2315_mem;

No static locals. Allocate and use a state container, see
Documentation/driver-model/design-patterns.txt

> +static inline u32 ar2315_gpio_reg_read(unsigned reg)
> +{
> +       return __raw_readl(ar2315_mem + reg);
> +}

Use readl_relaxed() instead.

> +static inline void ar2315_gpio_reg_write(unsigned reg, u32 val)
> +{
> +       __raw_writel(val, ar2315_mem + reg);
> +}

Use writel_relaxed() instead.

When you use the state container, you need to do a
state dereference like that:

mystate->base + reg

So I don't think these inlines buy you anything. Just use
readl/writel_relaxed directly in the code.

> +static inline void ar2315_gpio_reg_mask(unsigned reg, u32 mask, u32 val)
> +{
> +       ar2315_gpio_reg_write(reg, (ar2315_gpio_reg_read(reg) & ~mask) | val);
> +}

Too simple helper IMO, if you wanna do this in some organized fashion,
use regmap.

> +static void ar2315_gpio_int_setup(unsigned gpio, int trig)
> +{
> +       u32 reg = ar2315_gpio_reg_read(AR2315_GPIO_INT);
> +
> +       reg &= ~(AR2315_GPIO_INT_NUM_M | AR2315_GPIO_INT_TRIG_M);
> +       reg |= gpio | AR2315_GPIO_INT_TRIG(trig);
> +       ar2315_gpio_reg_write(AR2315_GPIO_INT, reg);
> +}

Trig? Isn't this supposed to be done in the .set_type()
callback?

> +static void ar2315_gpio_irq_unmask(struct irq_data *d)
> +{
> +       unsigned gpio = d->irq - ar2315_gpio_irq_base;

This kind of weird calculations go away with irqdomain and that
is in turn used by GPIOLIB_IRQCHIP.

After that you will just use d->hwirq. And name the variable
"offset" while you're at it.

> +       u32 dir = ar2315_gpio_reg_read(AR2315_GPIO_DIR);
> +
> +       /* Enable interrupt with edge detection */
> +       if ((dir & AR2315_GPIO_DIR_M(gpio)) != AR2315_GPIO_DIR_I(gpio))
> +               return;
> +
> +       ar2315_gpio_intmask |= (1 << gpio);

#include <linux/bitops.h>

ar2315_gpio_intmask |= BIT(gpio);

> +       ar2315_gpio_int_setup(gpio, AR2315_GPIO_INT_TRIG_EDGE);
> +}

> +static struct irq_chip ar2315_gpio_irq_chip = {
> +       .name           = DRIVER_NAME,
> +       .irq_unmask     = ar2315_gpio_irq_unmask,
> +       .irq_mask       = ar2315_gpio_irq_mask,
> +};

So why is .set_type() not implemented and instead hard-coded into
the unmask function? Please fix this. It will be called by the
core eventually no matter what.

> +static void ar2315_gpio_irq_init(unsigned irq)
> +{
> +       unsigned i;
> +
> +       ar2315_gpio_intval = ar2315_gpio_reg_read(AR2315_GPIO_DI);
> +       for (i = 0; i < AR2315_GPIO_NUM; i++) {
> +               unsigned _irq = ar2315_gpio_irq_base + i;
> +
> +               irq_set_chip_and_handler(_irq, &ar2315_gpio_irq_chip,
> +                                        handle_level_irq);
> +       }
> +       irq_set_chained_handler(irq, ar2315_gpio_irq_handler);
> +}

No, use the gpiolib irqchip helpers.

> +static int ar2315_gpio_get_val(struct gpio_chip *chip, unsigned gpio)
> +{
> +       return (ar2315_gpio_reg_read(AR2315_GPIO_DI) >> gpio) & 1;
> +}

Do this instead:

return !!(ar2315_gpio_reg_read(AR2315_GPIO_DI) & BIT(offset));

> +static int ar2315_gpio_to_irq(struct gpio_chip *chip, unsigned gpio)
> +{
> +       return ar2315_gpio_irq_base + gpio;
> +}

You do not implement this at all when using the gpiolib irqchip helpers.

> +static int ar2315_gpio_probe(struct platform_device *pdev)
> +{
> +       struct device *dev = &pdev->dev;
> +       struct resource *res;
> +       unsigned irq;
> +       int ret;
> +
> +       if (ar2315_mem)
> +               return -EBUSY;
> +
> +       res = platform_get_resource_byname(pdev, IORESOURCE_IRQ, DRIVER_NAME);
> +       if (!res) {
> +               dev_err(dev, "not found IRQ number\n");
> +               return -ENXIO;
> +       }
> +       irq = res->start;

Use

irq = platform_get_irq_byname(pdev, DRIVER_NAME);
if (irq < 0)...

> +       ret = irq_alloc_descs(-1, 0, AR2315_GPIO_NUM, 0);
> +       if (ret < 0) {
> +               dev_err(dev, "failed to allocate IRQ numbers\n");
> +               return ret;
> +       }
> +       ar2315_gpio_irq_base = ret;
> +
> +       ar2315_gpio_irq_init(irq);

No, let GPIOLIB_IRQCHIP handle this.

> +static int __init ar2315_gpio_init(void)
> +{
> +       return platform_driver_register(&ar2315_gpio_driver);
> +}
> +subsys_initcall(ar2315_gpio_init);

Why are you using subsys_initcall()?

This should not be necessary.

Yours,
Linus Walleij

^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [PATCH 10/16] gpio: add driver for Atheros AR2315 SoC GPIO controller
  2014-10-15  8:58   ` Linus Walleij
@ 2014-10-15 11:12     ` Sergey Ryazanov
  2014-10-28 14:37       ` Linus Walleij
  0 siblings, 1 reply; 37+ messages in thread
From: Sergey Ryazanov @ 2014-10-15 11:12 UTC (permalink / raw)
  To: Linus Walleij; +Cc: Ralf Baechle, Linux MIPS, Alexandre Courbot, linux-gpio

Hi Linus,

thank you for so detailed review!

I have one more generic question: could you merge driver without
GPIOLIB_IRQCHIP usage? Currently no one driver for the AR231x SoCs
uses irq_domain and I do not like to enable IRQ_DOMAIN just for one
driver. I plan to convert drivers to make them irq_domain aware a bit
later.

Please, find my comments below.

2014-10-15 12:58 GMT+04:00, Linus Walleij <linus.walleij@linaro.org>:
> On Sun, Sep 28, 2014 at 8:33 PM, Sergey Ryazanov <ryazanov.s.a@gmail.com>
> wrote:
>
>> Atheros AR2315 SoC have a builtin GPIO controller, which could be
>> accessed via memory mapped registers. This patch adds new driver
>> for them.
>>
>> Signed-off-by: Sergey Ryazanov <ryazanov.s.a@gmail.com>
>> Cc: Linus Walleij <linus.walleij@linaro.org>
>> Cc: Alexandre Courbot <gnurou@gmail.com>
>> Cc: linux-gpio@vger.kernel.org
>
>> +config GPIO_AR2315
>> +       bool "AR2315 SoC GPIO support"
>> +       default y if SOC_AR2315
>> +       depends on SOC_AR2315
>> +       help
>> +         Say yes here to enable GPIO support for Atheros AR2315+ SoCs.
>
> select GPIOLIB_IRQCHIP
>
> As far as I can see this driver should use the gpiolib irqchip helpers
> and create a cascading irqchip. The code uses some copy/pasting
> from earlier drivers which is not a good idea. Look at one of the drivers
> using GPIOLIB_IRQCHIP and be inspired, check e.g. gpio-pl061.c
> or gpio-zynq.c
>
Yes, this driver is pretty old, I updated it with newer API except
IRQ_DOMAIN, which I left for stage 2. Thank you for your hint about
reference realization.

>> +static u32 ar2315_gpio_intmask;
>> +static u32 ar2315_gpio_intval;
>> +static unsigned ar2315_gpio_irq_base;
>> +static void __iomem *ar2315_mem;
>
> No static locals. Allocate and use a state container, see
> Documentation/driver-model/design-patterns.txt
>
Is that rule mandatory for drivers, which serve only one device?

>> +static inline u32 ar2315_gpio_reg_read(unsigned reg)
>> +{
>> +       return __raw_readl(ar2315_mem + reg);
>> +}
>
> Use readl_relaxed() instead.
>
readl_relaxed() converts the bit ordering and seems inapplicable in this case.

>> +static inline void ar2315_gpio_reg_write(unsigned reg, u32 val)
>> +{
>> +       __raw_writel(val, ar2315_mem + reg);
>> +}
>
> Use writel_relaxed() instead.
>
> When you use the state container, you need to do a
> state dereference like that:
>
> mystate->base + reg
>
> So I don't think these inlines buy you anything. Just use
> readl/writel_relaxed directly in the code.
>
These helpers make code shorter and clearer. I can use macros if you
do preferred.

>> +static inline void ar2315_gpio_reg_mask(unsigned reg, u32 mask, u32 val)
>> +{
>> +       ar2315_gpio_reg_write(reg, (ar2315_gpio_reg_read(reg) & ~mask) |
>> val);
>> +}
>
> Too simple helper IMO, if you wanna do this in some organized fashion,
> use regmap.
>
>> +static void ar2315_gpio_int_setup(unsigned gpio, int trig)
>> +{
>> +       u32 reg = ar2315_gpio_reg_read(AR2315_GPIO_INT);
>> +
>> +       reg &= ~(AR2315_GPIO_INT_NUM_M | AR2315_GPIO_INT_TRIG_M);
>> +       reg |= gpio | AR2315_GPIO_INT_TRIG(trig);
>> +       ar2315_gpio_reg_write(AR2315_GPIO_INT, reg);
>> +}
>
> Trig? Isn't this supposed to be done in the .set_type()
> callback?
>
Yep. I tried to cheat kernel and made as if driver does not supports
any other trigger types :)

>> +static void ar2315_gpio_irq_unmask(struct irq_data *d)
>> +{
>> +       unsigned gpio = d->irq - ar2315_gpio_irq_base;
>
> This kind of weird calculations go away with irqdomain and that
> is in turn used by GPIOLIB_IRQCHIP.
>
> After that you will just use d->hwirq. And name the variable
> "offset" while you're at it.
>
>> +       u32 dir = ar2315_gpio_reg_read(AR2315_GPIO_DIR);
>> +
>> +       /* Enable interrupt with edge detection */
>> +       if ((dir & AR2315_GPIO_DIR_M(gpio)) != AR2315_GPIO_DIR_I(gpio))
>> +               return;
>> +
>> +       ar2315_gpio_intmask |= (1 << gpio);
>
> #include <linux/bitops.h>
>
> ar2315_gpio_intmask |= BIT(gpio);
>
>> +       ar2315_gpio_int_setup(gpio, AR2315_GPIO_INT_TRIG_EDGE);
>> +}
>
>> +static struct irq_chip ar2315_gpio_irq_chip = {
>> +       .name           = DRIVER_NAME,
>> +       .irq_unmask     = ar2315_gpio_irq_unmask,
>> +       .irq_mask       = ar2315_gpio_irq_mask,
>> +};
>
> So why is .set_type() not implemented and instead hard-coded into
> the unmask function? Please fix this. It will be called by the
> core eventually no matter what.
>
The interrupt configuration is a bit complex. This controller could be
configured to generate interrupts only for two lines at once. Or in
other words: user could select any two lines to generate interrupt.

>> +static void ar2315_gpio_irq_init(unsigned irq)
>> +{
>> +       unsigned i;
>> +
>> +       ar2315_gpio_intval = ar2315_gpio_reg_read(AR2315_GPIO_DI);
>> +       for (i = 0; i < AR2315_GPIO_NUM; i++) {
>> +               unsigned _irq = ar2315_gpio_irq_base + i;
>> +
>> +               irq_set_chip_and_handler(_irq, &ar2315_gpio_irq_chip,
>> +                                        handle_level_irq);
>> +       }
>> +       irq_set_chained_handler(irq, ar2315_gpio_irq_handler);
>> +}
>
> No, use the gpiolib irqchip helpers.
>
>> +static int ar2315_gpio_get_val(struct gpio_chip *chip, unsigned gpio)
>> +{
>> +       return (ar2315_gpio_reg_read(AR2315_GPIO_DI) >> gpio) & 1;
>> +}
>
> Do this instead:
>
> return !!(ar2315_gpio_reg_read(AR2315_GPIO_DI) & BIT(offset));
>
>> +static int ar2315_gpio_to_irq(struct gpio_chip *chip, unsigned gpio)
>> +{
>> +       return ar2315_gpio_irq_base + gpio;
>> +}
>
> You do not implement this at all when using the gpiolib irqchip helpers.
>
>> +static int ar2315_gpio_probe(struct platform_device *pdev)
>> +{
>> +       struct device *dev = &pdev->dev;
>> +       struct resource *res;
>> +       unsigned irq;
>> +       int ret;
>> +
>> +       if (ar2315_mem)
>> +               return -EBUSY;
>> +
>> +       res = platform_get_resource_byname(pdev, IORESOURCE_IRQ,
>> DRIVER_NAME);
>> +       if (!res) {
>> +               dev_err(dev, "not found IRQ number\n");
>> +               return -ENXIO;
>> +       }
>> +       irq = res->start;
>
> Use
>
> irq = platform_get_irq_byname(pdev, DRIVER_NAME);
> if (irq < 0)...
>
>> +       ret = irq_alloc_descs(-1, 0, AR2315_GPIO_NUM, 0);
>> +       if (ret < 0) {
>> +               dev_err(dev, "failed to allocate IRQ numbers\n");
>> +               return ret;
>> +       }
>> +       ar2315_gpio_irq_base = ret;
>> +
>> +       ar2315_gpio_irq_init(irq);
>
> No, let GPIOLIB_IRQCHIP handle this.
>
>> +static int __init ar2315_gpio_init(void)
>> +{
>> +       return platform_driver_register(&ar2315_gpio_driver);
>> +}
>> +subsys_initcall(ar2315_gpio_init);
>
> Why are you using subsys_initcall()?
>
> This should not be necessary.
>
I have users of GPIO in arch code, what called earlier than the
devices initcall.

> Yours,
> Linus Walleij
>

-- 
BR,
Sergey

^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [PATCH 10/16] gpio: add driver for Atheros AR2315 SoC GPIO controller
  2014-10-15 11:12     ` Sergey Ryazanov
@ 2014-10-28 14:37       ` Linus Walleij
  2014-10-28 21:08         ` Sergey Ryazanov
  0 siblings, 1 reply; 37+ messages in thread
From: Linus Walleij @ 2014-10-28 14:37 UTC (permalink / raw)
  To: Sergey Ryazanov; +Cc: Ralf Baechle, Linux MIPS, Alexandre Courbot, linux-gpio

On Wed, Oct 15, 2014 at 1:12 PM, Sergey Ryazanov <ryazanov.s.a@gmail.com> wrote:
> 2014-10-15 12:58 GMT+04:00, Linus Walleij <linus.walleij@linaro.org>:
>> On Sun, Sep 28, 2014 at 8:33 PM, Sergey Ryazanov <ryazanov.s.a@gmail.com>

> I have one more generic question: could you merge driver without
> GPIOLIB_IRQCHIP usage?

No.

> Currently no one driver for the AR231x SoCs
> uses irq_domain and I do not like to enable IRQ_DOMAIN just for one
> driver. I plan to convert drivers to make them irq_domain aware a bit
> later.

I don't believe any such promises. It's nothing personal, just I've
been burned too many times by people promising to "fix later".

>>> +static u32 ar2315_gpio_intmask;
>>> +static u32 ar2315_gpio_intval;
>>> +static unsigned ar2315_gpio_irq_base;
>>> +static void __iomem *ar2315_mem;
>>
>> No static locals. Allocate and use a state container, see
>> Documentation/driver-model/design-patterns.txt
>>
> Is that rule mandatory for drivers, which serve only one device?

There is no central authority which decides what is mandatory
or not. It is mandatory to get a driver past the GPIO maintainer.

>>> +static inline u32 ar2315_gpio_reg_read(unsigned reg)
>>> +{
>>> +       return __raw_readl(ar2315_mem + reg);
>>> +}
>>
>> Use readl_relaxed() instead.
>>
> readl_relaxed() converts the bit ordering and seems inapplicable in this case.

It assumes the peripherals IO memory is little endian.

If the IO memory for this device is little endian, please stay with
[readl|writel]_relaxed so it looks familiar.

Or is this machine really using big endian hardware registers?
In that case I understand your comment...

>> When you use the state container, you need to do a
>> state dereference like that:
>>
>> mystate->base + reg
>>
>> So I don't think these inlines buy you anything. Just use
>> readl/writel_relaxed directly in the code.
>>
> These helpers make code shorter and clearer. I can use macros if you
> do preferred.

No big deal. Keep it if you like it this way.

>> So why is .set_type() not implemented and instead hard-coded into
>> the unmask function? Please fix this. It will be called by the
>> core eventually no matter what.
>>
> The interrupt configuration is a bit complex. This controller could be
> configured to generate interrupts only for two lines at once. Or in
> other words: user could select any two lines to generate interrupt.

Oh well, better just handle it I guess...

>>> +static int __init ar2315_gpio_init(void)
>>> +{
>>> +       return platform_driver_register(&ar2315_gpio_driver);
>>> +}
>>> +subsys_initcall(ar2315_gpio_init);
>>
>> Why are you using subsys_initcall()?
>>
>> This should not be necessary.
>>
> I have users of GPIO in arch code, what called earlier than the
> devices initcall.

OK? Why are there such users that early and what do they
use the GPIOs for? Any reason they cannot be device_initcall()s?

Yours,
Linus Walleij

^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [PATCH 10/16] gpio: add driver for Atheros AR2315 SoC GPIO controller
  2014-10-28 14:37       ` Linus Walleij
@ 2014-10-28 21:08         ` Sergey Ryazanov
  0 siblings, 0 replies; 37+ messages in thread
From: Sergey Ryazanov @ 2014-10-28 21:08 UTC (permalink / raw)
  To: Linus Walleij; +Cc: Ralf Baechle, Linux MIPS, Alexandre Courbot, linux-gpio

2014-10-28 17:37 GMT+03:00 Linus Walleij <linus.walleij@linaro.org>:
> On Wed, Oct 15, 2014 at 1:12 PM, Sergey Ryazanov <ryazanov.s.a@gmail.com> wrote:
>> 2014-10-15 12:58 GMT+04:00, Linus Walleij <linus.walleij@linaro.org>:
>>> On Sun, Sep 28, 2014 at 8:33 PM, Sergey Ryazanov <ryazanov.s.a@gmail.com>
>
>> I have one more generic question: could you merge driver without
>> GPIOLIB_IRQCHIP usage?
>
> No.
>
Ok.

>> Currently no one driver for the AR231x SoCs
>> uses irq_domain and I do not like to enable IRQ_DOMAIN just for one
>> driver. I plan to convert drivers to make them irq_domain aware a bit
>> later.
>
> I don't believe any such promises. It's nothing personal, just I've
> been burned too many times by people promising to "fix later".
>
Now I drop the driver from the series and return to the development a
bit later, when finished the basic code for the MIPS architecture. In
that case I will have a time to write the driver that does not require
further fixes.


>>>> +static u32 ar2315_gpio_intmask;
>>>> +static u32 ar2315_gpio_intval;
>>>> +static unsigned ar2315_gpio_irq_base;
>>>> +static void __iomem *ar2315_mem;
>>>
>>> No static locals. Allocate and use a state container, see
>>> Documentation/driver-model/design-patterns.txt
>>>
>> Is that rule mandatory for drivers, which serve only one device?
>
> There is no central authority which decides what is mandatory
> or not. It is mandatory to get a driver past the GPIO maintainer.
>
Nice point :)

>>>> +static inline u32 ar2315_gpio_reg_read(unsigned reg)
>>>> +{
>>>> +       return __raw_readl(ar2315_mem + reg);
>>>> +}
>>>
>>> Use readl_relaxed() instead.
>>>
>> readl_relaxed() converts the bit ordering and seems inapplicable in this case.
>
> It assumes the peripherals IO memory is little endian.
>
> If the IO memory for this device is little endian, please stay with
> [readl|writel]_relaxed so it looks familiar.
>
> Or is this machine really using big endian hardware registers?
> In that case I understand your comment...
>
Yes, AR5312 and AR2315 SoCs are big endian machines with big endian registers.


>>> When you use the state container, you need to do a
>>> state dereference like that:
>>>
>>> mystate->base + reg
>>>
>>> So I don't think these inlines buy you anything. Just use
>>> readl/writel_relaxed directly in the code.
>>>
>> These helpers make code shorter and clearer. I can use macros if you
>> do preferred.
>
> No big deal. Keep it if you like it this way.
>
>>> So why is .set_type() not implemented and instead hard-coded into
>>> the unmask function? Please fix this. It will be called by the
>>> core eventually no matter what.
>>>
>> The interrupt configuration is a bit complex. This controller could be
>> configured to generate interrupts only for two lines at once. Or in
>> other words: user could select any two lines to generate interrupt.
>
> Oh well, better just handle it I guess...
>
Will do in v2.

>>>> +static int __init ar2315_gpio_init(void)
>>>> +{
>>>> +       return platform_driver_register(&ar2315_gpio_driver);
>>>> +}
>>>> +subsys_initcall(ar2315_gpio_init);
>>>
>>> Why are you using subsys_initcall()?
>>>
>>> This should not be necessary.
>>>
>> I have users of GPIO in arch code, what called earlier than the
>> devices initcall.
>
> OK? Why are there such users that early and what do they
> use the GPIOs for? Any reason they cannot be device_initcall()s?
>
One GPIO line is used in reset handler to be able to reliably reset
the chip. This is a workaround from vendor's reference design to
eliminate a hw bug in the reset circuit of the AR2315 SoC. So I prefer
to have GPIO controller in ready state as soon as possible.

> Yours,
> Linus Walleij

-- 
BR,
Sergey

^ permalink raw reply	[flat|nested] 37+ messages in thread

end of thread, other threads:[~2014-10-28 21:09 UTC | newest]

Thread overview: 37+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2014-09-28 18:32 [PATCH 00/16] MIPS: support for the Atheros AR231X SoCs Sergey Ryazanov
2014-09-28 18:33 ` [PATCH 01/16] MIPS: ar231x: add common parts Sergey Ryazanov
2014-09-29  9:30   ` Jonas Gorski
2014-09-29 20:57     ` Sergey Ryazanov
2014-09-28 18:33 ` [PATCH 02/16] MIPS: ar231x: add basic AR5312 SoC support Sergey Ryazanov
2014-09-29  9:35   ` Jonas Gorski
2014-09-29 21:05     ` Sergey Ryazanov
2014-09-28 18:33 ` [PATCH 03/16] MIPS: ar231x: add basic AR2315 " Sergey Ryazanov
2014-09-29  9:50   ` Jonas Gorski
2014-09-28 18:33 ` [PATCH 04/16] MIPS: ar231x: add interrupts handling routines Sergey Ryazanov
2014-09-28 18:33 ` [PATCH 05/16] MIPS: ar231x: add early printk support Sergey Ryazanov
2014-09-29 12:47   ` Jonas Gorski
2014-09-29 19:36     ` Sergey Ryazanov
2014-09-28 18:33 ` [PATCH 06/16] MIPS: ar231x: add UART support Sergey Ryazanov
2014-09-28 18:33 ` [PATCH 07/16] MIPS: ar231x: add board configuration detection Sergey Ryazanov
2014-09-28 18:33 ` [PATCH 08/16] MIPS: ar231x: add SoC type detection Sergey Ryazanov
2014-09-28 18:33 ` [PATCH 09/16] gpio: add driver for Atheros AR5312 SoC GPIO controller Sergey Ryazanov
2014-10-15  7:33   ` Linus Walleij
2014-09-28 18:33 ` [PATCH 10/16] gpio: add driver for Atheros AR2315 " Sergey Ryazanov
2014-10-15  8:58   ` Linus Walleij
2014-10-15 11:12     ` Sergey Ryazanov
2014-10-28 14:37       ` Linus Walleij
2014-10-28 21:08         ` Sergey Ryazanov
2014-09-28 18:33 ` [PATCH 11/16] mtd: add Atheros AR2315 SPI Flash driver Sergey Ryazanov
2014-09-28 18:33   ` Sergey Ryazanov
2014-09-28 18:33 ` [PATCH 12/16] watchdog: add Atheros AR2315 watchdog driver Sergey Ryazanov
2014-09-28 21:35   ` Guenter Roeck
2014-09-29 20:14     ` Sergey Ryazanov
2014-09-29 20:46       ` Guenter Roeck
2014-09-29 21:01         ` Sergey Ryazanov
2014-09-28 18:33 ` [PATCH 13/16] MIPS: ar231x: register various chip devices Sergey Ryazanov
2014-09-28 18:33 ` [PATCH 14/16] MIPS: ar231x: add AR2315 PCI host controller driver Sergey Ryazanov
2014-09-28 18:33 ` [PATCH 15/16] ath5k: update dependencies Sergey Ryazanov
2014-09-30 17:20   ` John W. Linville
2014-10-01 14:41     ` Sergey Ryazanov
2014-10-02 17:37       ` John W. Linville
2014-09-28 18:33 ` [PATCH 16/16] MIPS: ar231x: add Wireless device support Sergey Ryazanov

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.