[RFC v2 7/7] MIPS: Add Realtek RTL8186 SoC support

From: Yasha Cherikovsky
Date: Mon Oct 01 2018 - 06:30:34 EST


The Realtek RTL8186 SoC is a MIPS based SoC
used in some home routers [1][2].

The hardware includes Lexra LX5280 CPU with a TLB,
two Ethernet controllers, a WLAN controller and more.

With this patch, it is possible to successfully boot
the kernel and load userspace on the Edimax BR-6204Wg
router.
Network drivers support will come in future patches.

This patch includes:
- New MIPS rtl8186 platform (mostly DT based)
- defconfig file
- MIPS zboot UART support
- Device tree files for the RTL8186 SoC and Edimax BR-6204Wg
router

[1] https://www.linux-mips.org/wiki/Realtek_SOC#Realtek_RTL8186
[2] https://wikidevi.com/wiki/Realtek_RTL8186

Signed-off-by: Yasha Cherikovsky <yasha.che3@xxxxxxxxx>
Cc: Ralf Baechle <ralf@xxxxxxxxxxxxxx>
Cc: Paul Burton <paul.burton@xxxxxxxx>
Cc: James Hogan <jhogan@xxxxxxxxxx>
Cc: Rob Herring <robh+dt@xxxxxxxxxx>
Cc: Mark Rutland <mark.rutland@xxxxxxx>
Cc: linux-mips@xxxxxxxxxxxxxx
Cc: devicetree@xxxxxxxxxxxxxxx
Cc: linux-kernel@xxxxxxxxxxxxxxx
---
arch/mips/Kbuild.platforms | 1 +
arch/mips/Kconfig | 17 +++
arch/mips/boot/compressed/uart-16550.c | 5 +
arch/mips/boot/dts/Makefile | 1 +
arch/mips/boot/dts/realtek/Makefile | 4 +
arch/mips/boot/dts/realtek/rtl8186.dtsi | 86 ++++++++++++++
.../dts/realtek/rtl8186_edimax_br_6204wg.dts | 45 +++++++
arch/mips/configs/rtl8186_defconfig | 112 ++++++++++++++++++
arch/mips/include/asm/mach-rtl8186/rtl8186.h | 37 ++++++
arch/mips/rtl8186/Makefile | 2 +
arch/mips/rtl8186/Platform | 7 ++
arch/mips/rtl8186/irq.c | 8 ++
arch/mips/rtl8186/prom.c | 15 +++
arch/mips/rtl8186/setup.c | 80 +++++++++++++
arch/mips/rtl8186/time.c | 10 ++
15 files changed, 430 insertions(+)
create mode 100644 arch/mips/boot/dts/realtek/Makefile
create mode 100644 arch/mips/boot/dts/realtek/rtl8186.dtsi
create mode 100644 arch/mips/boot/dts/realtek/rtl8186_edimax_br_6204wg.dts
create mode 100644 arch/mips/configs/rtl8186_defconfig
create mode 100644 arch/mips/include/asm/mach-rtl8186/rtl8186.h
create mode 100644 arch/mips/rtl8186/Makefile
create mode 100644 arch/mips/rtl8186/Platform
create mode 100644 arch/mips/rtl8186/irq.c
create mode 100644 arch/mips/rtl8186/prom.c
create mode 100644 arch/mips/rtl8186/setup.c
create mode 100644 arch/mips/rtl8186/time.c

diff --git a/arch/mips/Kbuild.platforms b/arch/mips/Kbuild.platforms
index ac7ad54f984f..2793741f05e5 100644
--- a/arch/mips/Kbuild.platforms
+++ b/arch/mips/Kbuild.platforms
@@ -27,6 +27,7 @@ platforms += pmcs-msp71xx
platforms += pnx833x
platforms += ralink
platforms += rb532
+platforms += rtl8186
platforms += sgi-ip22
platforms += sgi-ip27
platforms += sgi-ip32
diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig
index bbeabd6b0a80..2f2ef09a1961 100644
--- a/arch/mips/Kconfig
+++ b/arch/mips/Kconfig
@@ -344,6 +344,23 @@ config MACH_DECSTATION

otherwise choose R3000.

+config MACH_RTL8186
+ bool "Realtek RTL8186 SoC"
+ select SYS_SUPPORTS_BIG_ENDIAN
+ select SYS_SUPPORTS_32BIT_KERNEL
+ select SYS_HAS_CPU_LX5280
+ select DMA_NONCOHERENT
+ select SYS_SUPPORTS_ZBOOT_UART16550
+ select SYS_HAS_EARLY_PRINTK
+ select USE_GENERIC_EARLY_PRINTK_8250
+ select USE_OF
+ select COMMON_CLK
+ select RTL8186_IRQ
+ select RTL8186_TIMER
+ select BUILTIN_DTB
+ help
+ Realtek RTL8186 SoC support.
+
config MACH_JAZZ
bool "Jazz family of machines"
select ARCH_MIGHT_HAVE_PC_PARPORT
diff --git a/arch/mips/boot/compressed/uart-16550.c b/arch/mips/boot/compressed/uart-16550.c
index aee8d7b8f091..99314df48718 100644
--- a/arch/mips/boot/compressed/uart-16550.c
+++ b/arch/mips/boot/compressed/uart-16550.c
@@ -35,6 +35,11 @@
#define IOTYPE unsigned int
#endif

+#ifdef CONFIG_MACH_RTL8186
+#define UART0_BASE 0xbd0100c3
+#define PORT(offset) (UART0_BASE + (4 * offset))
+#endif
+
#ifndef IOTYPE
#define IOTYPE char
#endif
diff --git a/arch/mips/boot/dts/Makefile b/arch/mips/boot/dts/Makefile
index 1e79cab8e269..50dc192bbde5 100644
--- a/arch/mips/boot/dts/Makefile
+++ b/arch/mips/boot/dts/Makefile
@@ -11,6 +11,7 @@ subdir-y += ni
subdir-y += pic32
subdir-y += qca
subdir-y += ralink
+subdir-y += realtek
subdir-y += xilfpga

obj-$(CONFIG_BUILTIN_DTB) := $(addsuffix /, $(subdir-y))
diff --git a/arch/mips/boot/dts/realtek/Makefile b/arch/mips/boot/dts/realtek/Makefile
new file mode 100644
index 000000000000..654c3a8da574
--- /dev/null
+++ b/arch/mips/boot/dts/realtek/Makefile
@@ -0,0 +1,4 @@
+# SPDX-License-Identifier: GPL-2.0
+dtb-$(CONFIG_MACH_RTL8186) += rtl8186_edimax_br_6204wg.dtb
+
+obj-$(CONFIG_BUILTIN_DTB) += $(addsuffix .o, $(dtb-y))
diff --git a/arch/mips/boot/dts/realtek/rtl8186.dtsi b/arch/mips/boot/dts/realtek/rtl8186.dtsi
new file mode 100644
index 000000000000..d172999a42a6
--- /dev/null
+++ b/arch/mips/boot/dts/realtek/rtl8186.dtsi
@@ -0,0 +1,86 @@
+// SPDX-License-Identifier: GPL-2.0
+/ {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ compatible = "realtek,rtl8186-soc";
+
+ interrupt-parent = <&intc>;
+
+ cpus {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ cpu@0 {
+ device_type = "cpu";
+ compatible = "lexra,lx5280";
+ reg = <0>;
+ clocks = <&cpu_clk>;
+ d-cache-size = <8192>;
+ i-cache-size = <8192>;
+ d-cache-line-size = <16>;
+ i-cache-line-size = <16>;
+ tlb-entries = <16>;
+ };
+ };
+
+ cpu_clk: cpu_clk {
+ compatible = "fixed-clock";
+ #clock-cells = <0>;
+ clock-frequency = <200000000>; /* Stub. Varies with boards */
+ };
+
+ sysclk: sysclk {
+ compatible = "fixed-clock";
+ #clock-cells = <0>;
+ clock-frequency = <22000000>; /* 22MHz */
+ };
+
+ soc {
+ compatible = "simple-bus";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges = <0 0x1d010000 0x1000>;
+
+ intc: interrupt-controller@1d010000 {
+ compatible = "realtek,rtl8186-intc";
+
+ interrupt-controller;
+ #interrupt-cells = <1>;
+
+ reg = <0x0 0x8>;
+ };
+
+ timer {
+ compatible = "realtek,rtl8186-timer";
+ interrupts = <0>;
+ clocks = <&sysclk>;
+
+ reg = <0x50 0x30>;
+ };
+
+ uart0: serial@1d0100c3 {
+ compatible = "ns16550a";
+ reg = <0xc3 0x20>;
+ reg-io-width = <1>;
+ reg-shift = <2>;
+ interrupts = <3>;
+ clocks = <&cpu_clk>;
+ fifo-size = <16>;
+
+ status = "disabled";
+ };
+
+ uart1: serial@1d0100e3 {
+ compatible = "ns16550a";
+ reg = <0xe3 0x20>;
+ reg-io-width = <1>;
+ reg-shift = <2>;
+ interrupts = <3>;
+ clocks = <&cpu_clk>;
+ fifo-size = <16>;
+
+ status = "disabled";
+ };
+ };
+};
+
diff --git a/arch/mips/boot/dts/realtek/rtl8186_edimax_br_6204wg.dts b/arch/mips/boot/dts/realtek/rtl8186_edimax_br_6204wg.dts
new file mode 100644
index 000000000000..c28edb83de4e
--- /dev/null
+++ b/arch/mips/boot/dts/realtek/rtl8186_edimax_br_6204wg.dts
@@ -0,0 +1,45 @@
+// SPDX-License-Identifier: GPL-2.0
+/dts-v1/;
+
+/include/ "rtl8186.dtsi"
+
+/ {
+ compatible = "edimax,br-6204wg", "realtek,rtl8186-soc";
+ model = "Edimax BR-6204Wg";
+
+
+ memory@0 {
+ device_type = "memory";
+ reg = <0x00000000 0x01000000>; /* 16MB */
+ };
+
+ chosen {
+ bootargs = "console=ttyS0,38400n8";
+ };
+
+ flash0: flash@1e000000 {
+ compatible = "cfi-flash";
+ reg = <0x1e000000 0x200000>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+ bank-width = <2>;
+
+ partition@0 {
+ label = "bootloader+defaults";
+ reg = <0x0 0x8000>;
+ read-only;
+ };
+ partition@8000 {
+ label = "settings";
+ reg = <0x8000 0x8000>;
+ };
+ };
+};
+
+&uart0 {
+ status = "okay";
+};
+
+&cpu_clk {
+ clock-frequency = <180000000>; /* 180MHz */
+};
diff --git a/arch/mips/configs/rtl8186_defconfig b/arch/mips/configs/rtl8186_defconfig
new file mode 100644
index 000000000000..03be44de770d
--- /dev/null
+++ b/arch/mips/configs/rtl8186_defconfig
@@ -0,0 +1,112 @@
+CONFIG_MACH_RTL8186=y
+CONFIG_HZ_100=y
+CONFIG_MIPS_ELF_APPENDED_DTB=y
+CONFIG_KERNEL_XZ=y
+# CONFIG_SWAP is not set
+# CONFIG_CROSS_MEMORY_ATTACH is not set
+CONFIG_NO_HZ_IDLE=y
+CONFIG_HIGH_RES_TIMERS=y
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+# CONFIG_SGETMASK_SYSCALL is not set
+# CONFIG_FHANDLE is not set
+# CONFIG_SHMEM is not set
+# CONFIG_AIO is not set
+CONFIG_EMBEDDED=y
+# CONFIG_VM_EVENT_COUNTERS is not set
+# CONFIG_COMPAT_BRK is not set
+CONFIG_SLAB=y
+# CONFIG_STACKPROTECTOR_STRONG is not set
+# CONFIG_LBDAF is not set
+# CONFIG_BLK_DEV_BSG is not set
+CONFIG_PARTITION_ADVANCED=y
+# CONFIG_MSDOS_PARTITION is not set
+# CONFIG_EFI_PARTITION is not set
+# CONFIG_IOSCHED_DEADLINE is not set
+# CONFIG_IOSCHED_CFQ is not set
+# CONFIG_MQ_IOSCHED_DEADLINE is not set
+# CONFIG_MQ_IOSCHED_KYBER is not set
+# CONFIG_SUSPEND is not set
+CONFIG_NET=y
+CONFIG_PACKET=y
+CONFIG_UNIX=y
+CONFIG_INET=y
+CONFIG_NET_FOU=y
+# CONFIG_INET_XFRM_MODE_TRANSPORT is not set
+# CONFIG_INET_XFRM_MODE_TUNNEL is not set
+# CONFIG_INET_XFRM_MODE_BEET is not set
+# CONFIG_INET_DIAG is not set
+# CONFIG_IPV6 is not set
+CONFIG_NETFILTER=y
+# CONFIG_BRIDGE_NETFILTER is not set
+# CONFIG_NETFILTER_INGRESS is not set
+CONFIG_NF_CONNTRACK=y
+# CONFIG_NF_CONNTRACK_PROCFS is not set
+# CONFIG_NF_CT_PROTO_DCCP is not set
+# CONFIG_NF_CT_PROTO_SCTP is not set
+# CONFIG_NF_CT_PROTO_UDPLITE is not set
+CONFIG_NF_CONNTRACK_IPV4=y
+CONFIG_IP_NF_IPTABLES=y
+CONFIG_IP_NF_FILTER=y
+CONFIG_IP_NF_TARGET_SYNPROXY=y
+CONFIG_IP_NF_NAT=y
+CONFIG_IP_NF_TARGET_MASQUERADE=y
+CONFIG_BRIDGE=y
+# CONFIG_BRIDGE_IGMP_SNOOPING is not set
+CONFIG_NET_SCHED=y
+CONFIG_NET_SCH_FQ_CODEL=y
+CONFIG_NET_SCH_DEFAULT=y
+CONFIG_DEFAULT_FQ_CODEL=y
+# CONFIG_WIRELESS is not set
+CONFIG_DEVTMPFS=y
+# CONFIG_ALLOW_DEV_COREDUMP is not set
+CONFIG_MTD=y
+CONFIG_MTD_BLOCK_RO=y
+CONFIG_MTD_CFI=y
+CONFIG_MTD_CFI_AMDSTD=y
+CONFIG_MTD_PHYSMAP=y
+CONFIG_MTD_PHYSMAP_OF=y
+CONFIG_NETDEVICES=y
+# CONFIG_NET_CORE is not set
+# CONFIG_WLAN is not set
+# CONFIG_INPUT is not set
+# CONFIG_SERIO is not set
+# CONFIG_VT is not set
+# CONFIG_LEGACY_PTYS is not set
+# CONFIG_DEVMEM is not set
+CONFIG_SERIAL_8250=y
+# CONFIG_SERIAL_8250_DEPRECATED_OPTIONS is not set
+CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_SERIAL_8250_EXTENDED=y
+CONFIG_SERIAL_8250_SHARE_IRQ=y
+CONFIG_SERIAL_OF_PLATFORM=y
+# CONFIG_HW_RANDOM is not set
+# CONFIG_HWMON is not set
+# CONFIG_USB_SUPPORT is not set
+# CONFIG_IOMMU_SUPPORT is not set
+# CONFIG_FILE_LOCKING is not set
+# CONFIG_DNOTIFY is not set
+# CONFIG_PROC_PAGE_MONITOR is not set
+CONFIG_SQUASHFS=y
+CONFIG_SQUASHFS_FILE_DIRECT=y
+# CONFIG_SQUASHFS_ZLIB is not set
+CONFIG_SQUASHFS_XZ=y
+CONFIG_SQUASHFS_4K_DEVBLK_SIZE=y
+CONFIG_PRINTK_TIME=y
+CONFIG_DEBUG_INFO=y
+CONFIG_DEBUG_INFO_REDUCED=y
+CONFIG_DEBUG_INFO_SPLIT=y
+CONFIG_DEBUG_INFO_DWARF4=y
+CONFIG_MAGIC_SYSRQ=y
+CONFIG_SOFTLOCKUP_DETECTOR=y
+CONFIG_PANIC_TIMEOUT=10
+# CONFIG_SCHED_DEBUG is not set
+# CONFIG_FTRACE is not set
+CONFIG_DEBUG_ZBOOT=y
+# CONFIG_CRYPTO_ECHAINIV is not set
+# CONFIG_CRYPTO_HW is not set
+# CONFIG_XZ_DEC_X86 is not set
+# CONFIG_XZ_DEC_POWERPC is not set
+# CONFIG_XZ_DEC_IA64 is not set
+# CONFIG_XZ_DEC_ARM is not set
+# CONFIG_XZ_DEC_ARMTHUMB is not set
+# CONFIG_XZ_DEC_SPARC is not set
diff --git a/arch/mips/include/asm/mach-rtl8186/rtl8186.h b/arch/mips/include/asm/mach-rtl8186/rtl8186.h
new file mode 100644
index 000000000000..d699b25c7854
--- /dev/null
+++ b/arch/mips/include/asm/mach-rtl8186/rtl8186.h
@@ -0,0 +1,37 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef __ASM_RTL8186_H
+#define __ASM_RTL8186_H
+
+#include <linux/compiler.h>
+
+#define RTL8186_REG_BASE ((void __iomem *)0xbd010000)
+#define RTL8186_REGISTER(offset) (RTL8186_REG_BASE + offset)
+
+/* Watchdog registers */
+#define RTL8186_CDBR RTL8186_REGISTER(0x58)
+#define RTL8186_WDTCNR RTL8186_REGISTER(0x5C)
+
+/* UART addresses */
+#define RTL8186_UART0_BASE RTL8186_REGISTER(0xC3)
+#define RTL8186_UART1_BASE RTL8186_REGISTER(0xE3)
+
+/* GPIO registers */
+#define RTL8186_GPABDATA RTL8186_REGISTER(0x120)
+#define RTL8186_GPABDIR RTL8186_REGISTER(0x124)
+#define RTL8186_GPABIMR RTL8186_REGISTER(0x128)
+#define RTL8186_GPABISR RTL8186_REGISTER(0x12C)
+#define RTL8186_GPCDDATA RTL8186_REGISTER(0x130)
+#define RTL8186_GPCDDIR RTL8186_REGISTER(0x134)
+#define RTL8186_GPCDIMR RTL8186_REGISTER(0x138)
+#define RTL8186_GPCDISR RTL8186_REGISTER(0x13C)
+#define RTL8186_GPEFDATA RTL8186_REGISTER(0x140)
+#define RTL8186_GPEFDIR RTL8186_REGISTER(0x144)
+#define RTL8186_GPEFIMR RTL8186_REGISTER(0x148)
+#define RTL8186_GPEFISR RTL8186_REGISTER(0x14C)
+#define RTL8186_GPGDATA RTL8186_REGISTER(0x150)
+#define RTL8186_GPGDIR RTL8186_REGISTER(0x154)
+#define RTL8186_GPGIMR RTL8186_REGISTER(0x158)
+#define RTL8186_GPGISR RTL8186_REGISTER(0x15C)
+
+
+#endif /* __ASM_RTL8186_H */
diff --git a/arch/mips/rtl8186/Makefile b/arch/mips/rtl8186/Makefile
new file mode 100644
index 000000000000..010f38349aa6
--- /dev/null
+++ b/arch/mips/rtl8186/Makefile
@@ -0,0 +1,2 @@
+// SPDX-License-Identifier: GPL-2.0
+obj-y := prom.o setup.o irq.o time.o
diff --git a/arch/mips/rtl8186/Platform b/arch/mips/rtl8186/Platform
new file mode 100644
index 000000000000..5c23cfbffc62
--- /dev/null
+++ b/arch/mips/rtl8186/Platform
@@ -0,0 +1,7 @@
+#
+# RTL8186
+#
+platform-$(CONFIG_MACH_RTL8186) += rtl8186/
+cflags-$(CONFIG_MACH_RTL8186) += -I$(srctree)/arch/mips/include/asm/mach-rtl8186
+load-$(CONFIG_MACH_RTL8186) += 0xffffffff80010000
+zload-$(CONFIG_MACH_RTL8186) += 0xffffffff80800000
diff --git a/arch/mips/rtl8186/irq.c b/arch/mips/rtl8186/irq.c
new file mode 100644
index 000000000000..f158bfe25bca
--- /dev/null
+++ b/arch/mips/rtl8186/irq.c
@@ -0,0 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0
+#include <linux/init.h>
+#include <linux/irqchip.h>
+
+void __init arch_init_irq(void)
+{
+ irqchip_init();
+}
diff --git a/arch/mips/rtl8186/prom.c b/arch/mips/rtl8186/prom.c
new file mode 100644
index 000000000000..0ec7979a23f9
--- /dev/null
+++ b/arch/mips/rtl8186/prom.c
@@ -0,0 +1,15 @@
+// SPDX-License-Identifier: GPL-2.0
+#include <linux/init.h>
+
+#include <asm/setup.h>
+#include <asm/mach-rtl8186/rtl8186.h>
+
+void __init prom_init(void)
+{
+ setup_8250_early_printk_port((unsigned long)RTL8186_UART0_BASE, 2,
+ 10000);
+}
+
+void __init prom_free_prom_memory(void)
+{
+}
diff --git a/arch/mips/rtl8186/setup.c b/arch/mips/rtl8186/setup.c
new file mode 100644
index 000000000000..ac3a0e982493
--- /dev/null
+++ b/arch/mips/rtl8186/setup.c
@@ -0,0 +1,80 @@
+// SPDX-License-Identifier: GPL-2.0
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/of.h>
+#include <linux/of_fdt.h>
+#include <linux/libfdt.h>
+
+#include <asm/reboot.h>
+#include <asm/io.h>
+#include <asm/prom.h>
+#include <asm/bootinfo.h>
+
+#include <asm/mach-rtl8186/rtl8186.h>
+
+const char *get_system_type(void)
+{
+ return "Realtek RTL8186";
+}
+
+void rtl8186_machine_restart(char *command)
+{
+ /* Disable all interrupts */
+ local_irq_disable();
+
+ /* Use watchdog to reset the system */
+ writel(0x10, RTL8186_CDBR);
+ writel(0x00, RTL8186_WDTCNR);
+
+ for (;;)
+ ;
+}
+
+#define GPIO_A2 BIT(2)
+#define GPIO_A3 BIT(3)
+#define GPIO_A7 BIT(7)
+#define GPIO_A8 BIT(8)
+
+/* Temporary hack until rtl8186-gpio driver is implemented */
+void __init rtl8186_edimax_br6204wg_setup_leds(void)
+{
+ unsigned int gpabdir, gpabdata;
+
+ gpabdir = readl(RTL8186_GPABDIR);
+ gpabdata = readl(RTL8186_GPABDATA);
+
+ writel(gpabdir | (GPIO_A2 | GPIO_A3), RTL8186_GPABDIR);
+
+ gpabdata &= ~GPIO_A2; /* Turn on A2 - green PWR */
+ gpabdata |= GPIO_A3; /* Turn off A3 - orange WLAN */
+ writel(gpabdata, RTL8186_GPABDATA);
+}
+
+void __init *plat_get_fdt(void)
+{
+ if (fw_passed_dtb)
+ return (void *)fw_passed_dtb;
+
+ return NULL;
+}
+
+void __init plat_mem_setup(void)
+{
+ void *dtb;
+
+ _machine_restart = rtl8186_machine_restart;
+
+ dtb = plat_get_fdt();
+ if (!dtb)
+ panic("no dtb found");
+
+ __dt_setup_arch(dtb);
+}
+
+void __init device_tree_init(void)
+{
+ unflatten_and_copy_device_tree();
+
+ if (of_machine_is_compatible("edimax,br-6204wg"))
+ rtl8186_edimax_br6204wg_setup_leds();
+}
diff --git a/arch/mips/rtl8186/time.c b/arch/mips/rtl8186/time.c
new file mode 100644
index 000000000000..78062b588bb3
--- /dev/null
+++ b/arch/mips/rtl8186/time.c
@@ -0,0 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0
+#include <linux/init.h>
+#include <linux/clocksource.h>
+#include <linux/of_clk.h>
+
+void __init plat_time_init(void)
+{
+ of_clk_init(NULL);
+ timer_probe();
+}
--
2.19.0