rtl838x: add new architecture

This adds support for the RTL838x Architecture.
SoCs of this type are used in managed and un-managed Switches and Routers
with 8-28 ports. Drivers are provided for SoC initialization, GPIOs, Flash,
Ethernet including a DSA switch driver and internal and external PHYs used
with these switches.

Supported SoCs:

	RTL8380M
	RTL8381M
	RTL8382M

The kernel will also boot on the following RTL839x SoCs, however driver
support apart from spi-nor is missing:

	RTL8390
	RTL8391
	RTL8393

The following PHYs are supported:

	RTL8214FC (Quad QSGMII multiplexing GMAC and SFP port)
	RTL8218B internal: internal PHY of the RTL838x chips
	RTL8318b external (QSGMII 8-port GMAC phy)
	RTL8382M SerDes for 2 SFP ports
	Initialization sequences for the PHYs are provided in the form of
	firmware files.

Flash driver supports 3 / 4 byte access

DSA switch driver supports VLANs, port isolation, STP and port mirroring.

The ALLNET ALL-SG8208M is supported as Proof of Concept:

	RTL8382M SoC
	1 MIPS 4KEc core @ 500MHz
	8 Internal PHYs (RTL8218B)
	128MB DRAM (Nanya NT5TU128MB)
	16MB NOR Flash (MXIC 25L128)
	8 GBEthernet ports with one green status LED each (SoC controlled)
	1 Power LED (not configurable)
	1 SYS LED (configurable)
	1 On-Off switch (not configurable)
	1 Reset button at the right behind right air-vent (not configurable)
	1 Reset button on front panel (configurable)
	12V 1A barrel connector
	1 serial header with populated standard pin connector and with markings
	  GND TX RX Vcc(3.3V), connection properties: 115200 8N1

To install, upload the sysupgrade image to the OEM webpage.

Signed-off-by: Birger Koblitz <git@birger-koblitz.de>
master
Birger Koblitz 2020-09-13 09:06:13 +02:00 committed by John Crispin
parent 7bb1bd469e
commit df8e6be59a
39 changed files with 8828 additions and 0 deletions

View File

@ -0,0 +1,22 @@
# This is free software, licensed under the GNU General Public License v2.
# See /LICENSE for more information.
#
include $(TOPDIR)/rules.mk
ARCH:=mips
CPU_TYPE:=4kec
BOARD:=rtl838x
BOARDNAME:=Realtek MIPS
FEATURES:=ramdisk squashfs
KERNEL_PATCHVER:=5.4
define Target/Description
Build firmware images for Realtek RTL838x based boards.
endef
include $(INCLUDE_DIR)/target.mk
DEFAULT_PACKAGES += swconfig uboot-envtools ethtool kmod-gpio-button-hotplug
$(eval $(call BuildTarget))

View File

@ -0,0 +1,15 @@
#!/bin/sh
. /lib/functions/uci-defaults.sh
board=$(board_name)
boardname="${board##*,}"
board_config_update
case $board in
esac
board_config_flush
exit 0

View File

@ -0,0 +1,87 @@
#!/bin/sh
. /lib/functions.sh
. /lib/functions/uci-defaults.sh
. /lib/functions/system.sh
rtl838x_setup_switch()
{
local switchid net portid master device lan_role lan_list
json_select_object switch
# Find slave ports
for net in $(ls -d /sys/class/net/*); do
switchid=$(cat $net/phys_switch_id 2>/dev/null)
[ -z "$switchid" ] && continue
device=$(basename $net)
portid=$(cat $net/phys_port_name)
lan_role="$lan_role ${portid##p}"
lan_list="$lan_list $device"
json_select_object "switch$((switchid))"
json_add_boolean enable 1
json_add_boolean reset 0
json_add_boolean dsa 1
json_select_array ports
json_add_object
json_add_int num "${portid##p}"
json_add_string role "lan"
json_add_string device "$device"
json_close_object
json_select ..
json_select ..
done
# Add switch master device
for net in $(ls -d /sys/class/net/*/dsa); do
master=$(dirname $net)
device=$(basename $master)
portid=$(cat $master/phys_port_name)
lan_role="$lan_role ${portid##p}"
json_select_object "switch$((switchid))"
json_select_array ports
json_add_object
json_add_int num "${portid##p}"
json_add_string device "$device"
json_add_boolean need_tag 0
json_add_boolean want_untag 0
json_add_boolean master 1
json_close_object
json_select ..
json_select_array roles
json_add_object
json_add_string role "lan"
lan_role=$(echo $lan_role | xargs -n1 | sort -n | xargs)
json_add_string ports "$lan_role"
json_close_object
json_select ..
json_select ..
done
json_select ..
lan_list=$(echo $lan_list | xargs -n1 | sort -V | xargs)
ucidef_set_interface_lan "$lan_list"
}
rtl838x_setup_macs()
{
local board="$1"
local lan_mac
local wan_mac
local label_mac
case $board in
allnet,all-sg8208m)
lan_mac=$(mtd_get_mac_ascii u-boot-env ethaddr)
label_mac=$lan_mac
esac
[ -n "$lan_mac" ] && ucidef_set_interface_macaddr "lan" $lan_mac
[ -n "$wan_mac" ] && ucidef_set_interface_macaddr "wan" $wan_mac
[ -n "$label_mac" ] && ucidef_set_label_macaddr $label_mac
}
board_config_update
board=$(board_name)
rtl838x_setup_switch
rtl838x_setup_macs $board
board_config_flush
exit 0

View File

@ -0,0 +1,3 @@
::sysinit:/etc/init.d/rcS S boot
::shutdown:/etc/init.d/rcS K shutdown
::askconsole:/usr/libexec/login.sh

View File

@ -0,0 +1,19 @@
PART_NAME=firmware
REQUIRE_IMAGE_METADATA=1
RAMFS_COPY_BIN='fw_printenv fw_setenv'
RAMFS_COPY_DATA='/etc/fw_env.config /var/lock/fw_printenv.lock'
platform_check_image() {
return 0
}
platform_do_upgrade() {
local board=$(board_name)
case "$board" in
*)
default_do_upgrade "$1"
;;
esac
}

View File

@ -0,0 +1,226 @@
CONFIG_ARCH_32BIT_OFF_T=y
CONFIG_ARCH_CLOCKSOURCE_DATA=y
CONFIG_ARCH_HAS_DMA_COHERENT_TO_PFN=y
CONFIG_ARCH_HAS_DMA_PREP_COHERENT=y
CONFIG_ARCH_HAS_DMA_WRITE_COMBINE=y
CONFIG_ARCH_HAS_ELF_RANDOMIZE=y
CONFIG_ARCH_HAS_RESET_CONTROLLER=y
CONFIG_ARCH_HAS_SYNC_DMA_FOR_DEVICE=y
CONFIG_ARCH_HAS_UNCACHED_SEGMENT=y
CONFIG_ARCH_HIBERNATION_POSSIBLE=y
CONFIG_ARCH_MMAP_RND_BITS_MAX=15
CONFIG_ARCH_MMAP_RND_COMPAT_BITS_MAX=15
CONFIG_ARCH_SUPPORTS_UPROBES=y
CONFIG_ARCH_SUSPEND_POSSIBLE=y
CONFIG_ARCH_USE_BUILTIN_BSWAP=y
CONFIG_ARCH_USE_MEMREMAP_PROT=y
CONFIG_ARCH_USE_QUEUED_RWLOCKS=y
CONFIG_ARCH_USE_QUEUED_SPINLOCKS=y
CONFIG_ARCH_WANT_DEFAULT_TOPDOWN_MMAP_LAYOUT=y
CONFIG_ARCH_WANT_IPC_PARSE_VERSION=y
CONFIG_BLK_DEV_RAM=y
CONFIG_BLK_DEV_RAM_COUNT=16
CONFIG_BLK_DEV_RAM_SIZE=4096
CONFIG_CEVT_R4K=y
CONFIG_CLKDEV_LOOKUP=y
CONFIG_CLONE_BACKWARDS=y
CONFIG_COMMON_CLK=y
# CONFIG_COMMON_CLK_BOSTON is not set
CONFIG_COMPAT_32BIT_TIME=y
CONFIG_CONSOLE_LOGLEVEL_DEFAULT=15
CONFIG_CPU_BIG_ENDIAN=y
CONFIG_CPU_GENERIC_DUMP_TLB=y
CONFIG_CPU_HAS_LOAD_STORE_LR=y
CONFIG_CPU_HAS_PREFETCH=y
CONFIG_CPU_HAS_RIXI=y
CONFIG_CPU_HAS_SYNC=y
CONFIG_CPU_MIPS32=y
# CONFIG_CPU_MIPS32_R1 is not set
CONFIG_CPU_MIPS32_R2=y
CONFIG_CPU_MIPSR2=y
CONFIG_CPU_NEEDS_NO_SMARTMIPS_OR_MICROMIPS=y
CONFIG_CPU_R4K_CACHE_TLB=y
CONFIG_CPU_SUPPORTS_32BIT_KERNEL=y
CONFIG_CPU_SUPPORTS_HIGHMEM=y
CONFIG_CPU_SUPPORTS_MSA=y
CONFIG_CRYPTO_HASH=y
CONFIG_CRYPTO_HASH2=y
CONFIG_CRYPTO_RNG2=y
CONFIG_CSRC_R4K=y
CONFIG_DEBUG_INFO=y
CONFIG_DEBUG_SECTION_MISMATCH=y
CONFIG_DMA_NONCOHERENT=y
CONFIG_DMA_NONCOHERENT_CACHE_SYNC=y
CONFIG_DTC=y
CONFIG_EARLY_PRINTK=y
CONFIG_EFI_EARLYCON=y
CONFIG_ETHERNET_PACKET_MANGLE=y
# CONFIG_FIXED_PHY is not set
# CONFIG_FONT_SUPPORT is not set
CONFIG_FW_LOADER_PAGED_BUF=y
CONFIG_GENERIC_ATOMIC64=y
CONFIG_GENERIC_CLOCKEVENTS=y
CONFIG_GENERIC_CMOS_UPDATE=y
CONFIG_GENERIC_CPU_AUTOPROBE=y
CONFIG_GENERIC_GETTIMEOFDAY=y
CONFIG_GENERIC_IOMAP=y
CONFIG_GENERIC_IRQ_CHIP=y
CONFIG_GENERIC_IRQ_EFFECTIVE_AFF_MASK=y
CONFIG_GENERIC_IRQ_IPI=y
CONFIG_GENERIC_IRQ_SHOW=y
CONFIG_GENERIC_LIB_ASHLDI3=y
CONFIG_GENERIC_LIB_ASHRDI3=y
CONFIG_GENERIC_LIB_CMPDI2=y
CONFIG_GENERIC_LIB_LSHRDI3=y
CONFIG_GENERIC_LIB_UCMPDI2=y
CONFIG_GENERIC_PCI_IOMAP=y
CONFIG_GENERIC_PHY=y
CONFIG_GENERIC_SCHED_CLOCK=y
CONFIG_GENERIC_SMP_IDLE_THREAD=y
CONFIG_GENERIC_TIME_VSYSCALL=y
CONFIG_GPIOLIB=y
CONFIG_GPIO_SYSFS=y
CONFIG_HANDLE_DOMAIN_IRQ=y
CONFIG_HARDWARE_WATCHPOINTS=y
CONFIG_HAS_DMA=y
CONFIG_HAS_IOMEM=y
CONFIG_HAS_IOPORT_MAP=y
CONFIG_HAVE_ARCH_COMPILER_H=y
CONFIG_HAVE_ARCH_JUMP_LABEL=y
CONFIG_HAVE_ARCH_KGDB=y
CONFIG_HAVE_ARCH_SECCOMP_FILTER=y
CONFIG_HAVE_ARCH_TRACEHOOK=y
CONFIG_HAVE_ASM_MODVERSIONS=y
CONFIG_HAVE_CLK=y
CONFIG_HAVE_CONTEXT_TRACKING=y
CONFIG_HAVE_COPY_THREAD_TLS=y
CONFIG_HAVE_C_RECORDMCOUNT=y
CONFIG_HAVE_DEBUG_KMEMLEAK=y
CONFIG_HAVE_DEBUG_STACKOVERFLOW=y
CONFIG_HAVE_DMA_CONTIGUOUS=y
CONFIG_HAVE_DYNAMIC_FTRACE=y
CONFIG_HAVE_FAST_GUP=y
CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y
CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y
CONFIG_HAVE_FUNCTION_TRACER=y
CONFIG_HAVE_GENERIC_VDSO=y
CONFIG_HAVE_IDE=y
CONFIG_HAVE_IOREMAP_PROT=y
CONFIG_HAVE_IRQ_EXIT_ON_IRQ_STACK=y
CONFIG_HAVE_IRQ_TIME_ACCOUNTING=y
CONFIG_HAVE_KVM=y
CONFIG_HAVE_LD_DEAD_CODE_DATA_ELIMINATION=y
CONFIG_HAVE_MEMBLOCK_NODE_MAP=y
CONFIG_HAVE_MOD_ARCH_SPECIFIC=y
CONFIG_HAVE_NET_DSA=y
CONFIG_HAVE_OPROFILE=y
CONFIG_HAVE_PERF_EVENTS=y
CONFIG_HAVE_REGS_AND_STACK_ACCESS_API=y
CONFIG_HAVE_RSEQ=y
CONFIG_HAVE_SYSCALL_TRACEPOINTS=y
CONFIG_HAVE_VIRT_CPU_ACCOUNTING_GEN=y
# CONFIG_HIGH_RES_TIMERS is not set
CONFIG_HZ_PERIODIC=y
CONFIG_INITRAMFS_SOURCE=""
CONFIG_IRQCHIP=y
CONFIG_IRQ_DOMAIN=y
CONFIG_IRQ_DOMAIN_HIERARCHY=y
CONFIG_IRQ_FORCED_THREADING=y
CONFIG_IRQ_MIPS_CPU=y
CONFIG_IRQ_WORK=y
CONFIG_LEDS_GPIO=y
CONFIG_LEGACY_PTYS=y
CONFIG_LEGACY_PTY_COUNT=256
CONFIG_LIBFDT=y
CONFIG_LOCK_DEBUGGING_SUPPORT=y
CONFIG_MDIO_BUS=y
CONFIG_MDIO_DEVICE=y
CONFIG_MEMFD_CREATE=y
CONFIG_MFD_SYSCON=y
CONFIG_MIGRATION=y
CONFIG_MIPS=y
CONFIG_MIPS_ASID_BITS=8
CONFIG_MIPS_ASID_SHIFT=0
CONFIG_MIPS_CLOCK_VSYSCALL=y
# CONFIG_MIPS_CMDLINE_DTB_EXTEND is not set
# CONFIG_MIPS_CMDLINE_FROM_BOOTLOADER is not set
CONFIG_MIPS_CMDLINE_FROM_DTB=y
# CONFIG_MIPS_ELF_APPENDED_DTB is not set
CONFIG_MIPS_L1_CACHE_SHIFT=5
# CONFIG_MIPS_MT_SMP is not set
# CONFIG_MIPS_NO_APPENDED_DTB is not set
CONFIG_MIPS_RAW_APPENDED_DTB=y
CONFIG_MIPS_SPRAM=y
# CONFIG_MIPS_VPE_LOADER is not set
CONFIG_MODULES_USE_ELF_REL=y
CONFIG_MTD_CFI_ADV_OPTIONS=y
CONFIG_MTD_CFI_GEOMETRY=y
CONFIG_MTD_CMDLINE_PARTS=y
CONFIG_MTD_JEDECPROBE=y
CONFIG_MTD_SPI_NOR=y
CONFIG_MTD_SPLIT_BRNIMAGE_FW=y
CONFIG_MTD_SPLIT_EVA_FW=y
CONFIG_MTD_SPLIT_FIRMWARE=y
CONFIG_MTD_SPLIT_TPLINK_FW=y
CONFIG_MTD_SPLIT_UIMAGE_FW=y
CONFIG_NEED_DMA_MAP_STATE=y
CONFIG_NEED_PER_CPU_KM=y
CONFIG_NET_DEVLINK=y
CONFIG_NET_DSA=y
CONFIG_NET_DSA_RTL838X=y
CONFIG_NET_DSA_TAG_TRAILER=y
CONFIG_NET_RTL838X=y
CONFIG_NET_SWITCHDEV=y
CONFIG_NO_GENERIC_PCI_IOPORT_MAP=y
CONFIG_NVMEM=y
CONFIG_OF=y
CONFIG_OF_ADDRESS=y
CONFIG_OF_EARLY_FLATTREE=y
CONFIG_OF_FLATTREE=y
CONFIG_OF_GPIO=y
CONFIG_OF_IRQ=y
CONFIG_OF_KOBJ=y
CONFIG_OF_MDIO=y
CONFIG_OF_NET=y
CONFIG_SERIAL_OF_PLATFORM=y
CONFIG_PCI_DRIVERS_LEGACY=y
CONFIG_PERF_USE_VMALLOC=y
CONFIG_PGTABLE_LEVELS=2
# CONFIG_PHYLIB is not set
CONFIG_PHYLINK=y
CONFIG_PINCTRL=y
# CONFIG_PINCTRL_SINGLE is not set
CONFIG_POWER_RESET=y
CONFIG_POWER_RESET_SYSCON=y
CONFIG_PSB6970_PHY=y
CONFIG_REGMAP=y
CONFIG_REGMAP_MMIO=y
CONFIG_RESET_CONTROLLER=y
CONFIG_RTL838X=y
CONFIG_GPIO_RTL838X=y
CONFIG_SERIAL_8250_RUNTIME_UARTS=2
CONFIG_SERIAL_8250_NR_UARTS=2
CONFIG_SERIAL_MCTRL_GPIO=y
CONFIG_SPI=y
CONFIG_SPI_MASTER=y
CONFIG_SPI_MEM=y
CONFIG_SPI_RTL838X=y
CONFIG_SRCU=y
CONFIG_SWAP_IO_SPACE=y
CONFIG_SWCONFIG=y
CONFIG_SWPHY=y
CONFIG_SYSCTL_EXCEPTION_TRACE=y
CONFIG_SYS_HAS_CPU_MIPS32_R1=y
CONFIG_SYS_HAS_CPU_MIPS32_R2=y
CONFIG_SYS_HAS_EARLY_PRINTK=y
CONFIG_SYS_SUPPORTS_32BIT_KERNEL=y
CONFIG_SYS_SUPPORTS_ARBIT_HZ=y
CONFIG_SYS_SUPPORTS_BIG_ENDIAN=y
CONFIG_SYS_SUPPORTS_MIPS16=y
CONFIG_SYS_SUPPORTS_MULTITHREADING=y
CONFIG_SYS_SUPPORTS_VPE_LOADER=y
CONFIG_TARGET_ISA_REV=2
CONFIG_TICK_CPU_ACCOUNTING=y
CONFIG_TINY_SRCU=y
CONFIG_USE_OF=y
CONFIG_JFFS2_ZLIB=y

View File

@ -0,0 +1,221 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/dts-v1/;
#include "rtl838x.dtsi"
#include <dt-bindings/input/input.h>
#include <dt-bindings/gpio/gpio.h>
/ {
compatible = "allnet,all-sg8208m", "realtek,rtl838x-soc";
model = "ALLNET ALL-SG8208M";
aliases {
led-boot = &led_sys;
led-failsafe = &led_sys;
led-running = &led_sys;
led-upgrade = &led_sys;
};
chosen {
bootargs = "console=ttyS0,115200";
};
keys {
compatible = "gpio-keys-polled";
poll-interval = <20>;
reset {
label = "reset";
gpios = <&gpio0 67 GPIO_ACTIVE_LOW>;
linux,code = <KEY_RESTART>;
};
};
leds {
compatible = "gpio-leds";
led_sys: sys {
label = "all-sg8208m:green:sys";
gpios = <&gpio0 47 GPIO_ACTIVE_HIGH>;
};
// GPIO 25: power on/off all port leds
};
};
&gpio0 {
indirect-access-bus-id = <0>;
};
&spi0 {
status = "okay";
flash@0 {
compatible = "jedec,spi-nor";
reg = <0>;
spi-max-frequency = <10000000>;
partitions {
compatible = "fixed-partitions";
#address-cells = <1>;
#size-cells = <1>;
partition@0 {
label = "u-boot";
reg = <0x0 0x80000>;
read-only;
};
partition@80000 {
label = "u-boot-env";
reg = <0x80000 0x10000>;
read-only;
};
partition@90000 {
label = "u-boot-env2";
reg = <0x90000 0x10000>;
read-only;
};
partition@a0000 {
label = "jffs";
reg = <0xa0000 0x100000>;
};
partition@1a0000 {
label = "jffs2";
reg = <0x1a0000 0x100000>;
};
partition@2a0000 {
label = "firmware";
reg = <0x2a0000 0xd60000>;
compatible = "allnet,uimage";
};
};
};
};
&ethernet0 {
mdio: mdio-bus {
compatible = "realtek,rtl838x-mdio";
regmap = <&ethernet0>;
#address-cells = <1>;
#size-cells = <0>;
/* Internal phy */
phy8: ethernet-phy@8 {
reg = <8>;
compatible = "ethernet-phy-ieee802.3-c22";
};
phy9: ethernet-phy@9 {
reg = <9>;
compatible = "ethernet-phy-ieee802.3-c22";
};
phy10: ethernet-phy@10 {
reg = <10>;
compatible = "ethernet-phy-ieee802.3-c22";
};
phy11: ethernet-phy@11 {
reg = <11>;
compatible = "ethernet-phy-ieee802.3-c22";
};
phy12: ethernet-phy@12 {
reg = <12>;
compatible = "ethernet-phy-ieee802.3-c22";
};
phy13: ethernet-phy@13 {
reg = <13>;
compatible = "ethernet-phy-ieee802.3-c22";
};
phy14: ethernet-phy@14 {
reg = <14>;
compatible = "ethernet-phy-ieee802.3-c22";
};
phy15: ethernet-phy@15 {
reg = <15>;
compatible = "ethernet-phy-ieee802.3-c22";
};
};
};
&switch0 {
ports {
#address-cells = <1>;
#size-cells = <0>;
port@0 {
reg = <8>;
label = "lan1";
phy-handle = <&phy8>;
phy-mode = "internal";
};
port@1 {
reg = <9>;
label = "lan2";
phy-handle = <&phy9>;
phy-mode = "internal";
};
port@2 {
reg = <10>;
label = "lan3";
phy-handle = <&phy10>;
phy-mode = "internal";
};
port@3 {
reg = <11>;
label = "lan4";
phy-handle = <&phy11>;
phy-mode = "internal";
};
port@4 {
reg = <12>;
label = "lan5";
phy-handle = <&phy12>;
phy-mode = "internal";
};
port@5 {
reg = <13>;
label = "lan6";
phy-handle = <&phy13>;
phy-mode = "internal";
};
port@6 {
reg = <14>;
label = "lan7";
phy-handle = <&phy14>;
phy-mode = "internal";
};
port@7 {
reg = <15>;
label = "lan8";
phy-handle = <&phy15>;
phy-mode = "internal";
};
port@28 {
ethernet = <&ethernet0>;
reg = <28>;
phy-mode = "internal";
fixed-link {
speed = <1000>;
full-duplex;
};
};
};
};

View File

@ -0,0 +1,110 @@
// SPDX-License-Identifier: GPL-2.0-or-later OR MIT
/ {
#address-cells = <1>;
#size-cells = <1>;
compatible = "realtek,rtl838x-soc";
reg = <0xbb000000 0xa000>;
cpus {
#address-cells = <1>;
#size-cells = <0>;
frequency = <500000000>;
cpu@0 {
compatible = "mips,mips4KEc";
reg = <0>;
};
};
memory@0 {
device_type = "memory";
reg = <0x0 0x8000000>;
};
chosen {
bootargs = "console=ttyS0,38400";
};
cpuintc: cpuintc {
#address-cells = <0>;
#interrupt-cells = <1>;
interrupt-controller;
compatible = "rtl838x,icu";
reg = <0xb8003000 0x20>;
};
spi0: spi@b8001200 {
status = "okay";
compatible = "realtek,rtl838x-nor";
reg = <0xb8001200 0x100>;
#address-cells = <1>;
#size-cells = <0>;
};
uart0: uart@b8002000 {
status = "disabled";
compatible = "ns16550a";
reg = <0xb8002000 0x100>;
clock-frequency = <200000000>;
interrupts = <31>;
reg-io-width = <1>;
reg-shift = <2>;
fifo-size = <1>;
no-loopback-test;
};
uart1: uart@b8002100 {
status = "okay";
compatible = "ns16550a";
reg = <0xb8002100 0x100>;
clock-frequency = <200000000>;
interrupt-parent = <&cpuintc>;
interrupts = <30>;
reg-io-width = <1>;
reg-shift = <2>;
fifo-size = <1>;
no-loopback-test;
};
gpio0: gpio-controller@b8003500 {
compatible = "realtek,rtl838x-gpio";
reg = <0xb8003500 0x20>;
gpio-controller;
#gpio-cells = <2>;
interrupt-parent = <&cpuintc>;
interrupts = <23>;
};
ethernet0: ethernet@bb00a300 {
status = "okay";
compatible = "realtek,rtl838x-eth";
reg = <0xbb00a300 0x100>;
interrupt-parent = <&cpuintc>;
interrupts = <24>;
#interrupt-cells = <1>;
phy-mode = "internal";
fixed-link {
speed = <1000>;
full-duplex;
};
};
switch0: switch@bb000000 {
status = "okay";
compatible = "realtek,rtl838x-switch";
};
};

View File

@ -0,0 +1,34 @@
/* SPDX-License-Identifier: GPL-2.0-only */
#ifndef RTL838X_IOREMAP_H_
#define RTL838X_IOREMAP_H_
static inline phys_addr_t fixup_bigphys_addr(phys_addr_t phys_addr, phys_addr_t size)
{
return phys_addr;
}
static inline int is_rtl838x_internal_registers(phys_addr_t offset)
{
/* IO-Block */
if (offset >= 0xb8000000 && offset < 0xb9000000)
return 1;
/* Switch block */
if (offset >= 0xbb000000 && offset < 0xbc000000)
return 1;
return 0;
}
static inline void __iomem *plat_ioremap(phys_addr_t offset, unsigned long size,
unsigned long flags)
{
if (is_rtl838x_internal_registers(offset))
return (void __iomem *)offset;
return NULL;
}
static inline int plat_iounmap(const volatile void __iomem *addr)
{
return is_rtl838x_internal_registers((unsigned long)addr);
}
#endif

View File

@ -0,0 +1,10 @@
/* SPDX-License-Identifier: GPL-2.0-only */
#ifndef __ASM_MACH_RTL838X_IRQ_H
#define __ASM_MACH_RTL838X_IRQ_H
#define MIPS_CPU_IRQ_BASE 0
#define NR_IRQS 64
#include_next <irq.h>
#endif /* __ASM_MACH_ATH79_IRQ_H */

View File

@ -0,0 +1,428 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (C) 2006-2012 Tony Wu (tonywu@realtek.com)
* Copyright (C) 2020 B. Koblitz
*/
#ifndef _MACH_RTL838X_H_
#define _MACH_RTL838X_H_
/*
* Register access macros
*/
#define RTL838X_SW_BASE ((volatile void *) 0xBB000000)
#define rtl838x_r32(reg) __raw_readl(reg)
#define rtl838x_w32(val, reg) __raw_writel(val, reg)
#define rtl838x_w32_mask(clear, set, reg) rtl838x_w32((rtl838x_r32(reg) & ~(clear)) | (set), reg)
#define sw_r32(reg) __raw_readl(RTL838X_SW_BASE + reg)
#define sw_w32(val, reg) __raw_writel(val, RTL838X_SW_BASE + reg)
#define sw_w32_mask(clear, set, reg) \
sw_w32((sw_r32(reg) & ~(clear)) | (set), reg)
#define sw_r64(reg) ((((u64)__raw_readl(RTL838X_SW_BASE + reg)) << 32) | \
__raw_readl(RTL838X_SW_BASE + reg + 4))
#define sw_w64(val, reg) do { \
__raw_writel((u32)((val) >> 32), RTL838X_SW_BASE + reg); \
__raw_writel((u32)((val) & 0xffffffff), \
RTL838X_SW_BASE + reg + 4); \
} while (0)
/*
* SPRAM
*/
#define RTL838X_ISPRAM_BASE 0x0
#define RTL838X_DSPRAM_BASE 0x0
/*
* IRQ Controller
*/
#define RTL838X_IRQ_CPU_BASE 0
#define RTL838X_IRQ_CPU_NUM 8
#define RTL838X_IRQ_ICTL_BASE (RTL838X_IRQ_CPU_BASE + RTL838X_IRQ_CPU_NUM)
#define RTL838X_IRQ_ICTL_NUM 32
/*
* MIPS32R2 counter
*/
#define RTL838X_COMPARE_IRQ (RTL838X_IRQ_CPU_BASE + 7)
/*
* ICTL
* Base address 0xb8003000UL
*/
#define RTL838X_ICTL1_IRQ (RTL838X_IRQ_CPU_BASE + 2)
#define RTL838X_ICTL2_IRQ (RTL838X_IRQ_CPU_BASE + 3)
#define RTL838X_ICTL3_IRQ (RTL838X_IRQ_CPU_BASE + 4)
#define RTL838X_ICTL4_IRQ (RTL838X_IRQ_CPU_BASE + 5)
#define RTL838X_ICTL5_IRQ (RTL838X_IRQ_CPU_BASE + 6)
#define GIMR (0x00)
#define UART0_IE (1 << 31)
#define UART1_IE (1 << 30)
#define TC0_IE (1 << 29)
#define TC1_IE (1 << 28)
#define OCPTO_IE (1 << 27)
#define HLXTO_IE (1 << 26)
#define SLXTO_IE (1 << 25)
#define NIC_IE (1 << 24)
#define GPIO_ABCD_IE (1 << 23)
#define GPIO_EFGH_IE (1 << 22)
#define RTC_IE (1 << 21)
#define WDT_IP1_IE (1 << 19)
#define WDT_IP2_IE (1 << 18)
#define GISR (0x04)
#define UART0_IP (1 << 31)
#define UART1_IP (1 << 30)
#define TC0_IP (1 << 29)
#define TC1_IP (1 << 28)
#define OCPTO_IP (1 << 27)
#define HLXTO_IP (1 << 26)
#define SLXTO_IP (1 << 25)
#define NIC_IP (1 << 24)
#define GPIO_ABCD_IP (1 << 23)
#define GPIO_EFGH_IP (1 << 22)
#define RTC_IP (1 << 21)
#define WDT_IP1_IP (1 << 19)
#define WDT_IP2_IP (1 << 18)
#define IRR0 (0x08)
#define IRR0_SETTING ((UART0_RS << 28) | \
(UART1_RS << 24) | \
(TC0_RS << 20) | \
(TC1_RS << 16) | \
(OCPTO_RS << 12) | \
(HLXTO_RS << 8) | \
(SLXTO_RS << 4) | \
(NIC_RS << 0) \
)
#define IRR1 (0x0c)
#define IRR1_SETTING ((GPIO_ABCD_RS << 28) | \
(GPIO_EFGH_RS << 24) | \
(RTC_RS << 20) | \
(SWCORE_RS << 16) \
)
#define IRR2 (0x10)
#define IRR2_SETTING 0
#define IRR3 (0x14)
#define IRR3_SETTING 0
/* Interrupt Routing Selection */
#define UART0_RS 2
#define UART1_RS 1
#define TC0_RS 5
#define TC1_RS 1
#define OCPTO_RS 1
#define HLXTO_RS 1
#define SLXTO_RS 1
#define NIC_RS 4
#define GPIO_ABCD_RS 4
#define GPIO_EFGH_RS 4
#define RTC_RS 4
#define SWCORE_RS 3
#define WDT_IP1_RS 4
#define WDT_IP2_RS 5
/* Interrupt IRQ Assignments */
#define UART0_IRQ 31
#define UART1_IRQ 30
#define TC0_IRQ 29
#define TC1_IRQ 28
#define OCPTO_IRQ 27
#define HLXTO_IRQ 26
#define SLXTO_IRQ 25
#define NIC_IRQ 24
#define GPIO_ABCD_IRQ 23
#define GPIO_EFGH_IRQ 22
#define RTC_IRQ 21
#define SWCORE_IRQ 20
#define WDT_IP1_IRQ 19
#define WDT_IP2_IRQ 18
#define SYSTEM_FREQ 200000000
#define RTL838X_UART0_BASE ((volatile void *)(0xb8002000UL))
#define RTL838X_UART0_BAUD 38400 /* ex. 19200 or 38400 or 57600 or 115200 */
#define RTL838X_UART0_FREQ (SYSTEM_FREQ - RTL838X_UART0_BAUD * 24)
#define RTL838X_UART0_MAPBASE 0x18002000UL
#define RTL838X_UART0_MAPSIZE 0x100
#define RTL838X_UART0_IRQ UART0_IRQ
#define RTL838X_UART1_BASE ((volatile void *)(0xb8002100UL))
#define RTL838X_UART1_BAUD 38400 /* ex. 19200 or 38400 or 57600 or 115200 */
#define RTL838X_UART1_FREQ (SYSTEM_FREQ - RTL838X_UART1_BAUD * 24)
#define RTL838X_UART1_MAPBASE 0x18002100UL
#define RTL838X_UART1_MAPSIZE 0x100
#define RTL838X_UART1_IRQ UART1_IRQ
#define UART0_RBR (RTL838X_UART0_BASE + 0x000)
#define UART0_THR (RTL838X_UART0_BASE + 0x000)
#define UART0_DLL (RTL838X_UART0_BASE + 0x000)
#define UART0_IER (RTL838X_UART0_BASE + 0x004)
#define UART0_DLM (RTL838X_UART0_BASE + 0x004)
#define UART0_IIR (RTL838X_UART0_BASE + 0x008)
#define UART0_FCR (RTL838X_UART0_BASE + 0x008)
#define UART0_LCR (RTL838X_UART0_BASE + 0x00C)
#define UART0_MCR (RTL838X_UART0_BASE + 0x010)
#define UART0_LSR (RTL838X_UART0_BASE + 0x014)
#define UART1_RBR (RTL838X_UART1_BASE + 0x000)
#define UART1_THR (RTL838X_UART1_BASE + 0x000)
#define UART1_DLL (RTL838X_UART1_BASE + 0x000)
#define UART1_IER (RTL838X_UART1_BASE + 0x004)
#define UART1_DLM (RTL838X_UART1_BASE + 0x004)
#define UART1_IIR (RTL838X_UART1_BASE + 0x008)
#define UART1_FCR (RTL838X_UART1_BASE + 0x008)
#define FCR_EN 0x01
#define FCR_RXRST 0x02
#define XRST 0x02
#define FCR_TXRST 0x04
#define TXRST 0x04
#define FCR_DMA 0x08
#define FCR_RTRG 0xC0
#define CHAR_TRIGGER_01 0x00
#define CHAR_TRIGGER_04 0x40
#define CHAR_TRIGGER_08 0x80
#define CHAR_TRIGGER_14 0xC0
#define UART1_LCR (RTL838X_UART1_BASE + 0x00C)
#define LCR_WLN 0x03
#define CHAR_LEN_5 0x00
#define CHAR_LEN_6 0x01
#define CHAR_LEN_7 0x02
#define CHAR_LEN_8 0x03
#define LCR_STB 0x04
#define ONE_STOP 0x00
#define TWO_STOP 0x04
#define LCR_PEN 0x08
#define PARITY_ENABLE 0x01
#define PARITY_DISABLE 0x00
#define LCR_EPS 0x30
#define PARITY_ODD 0x00
#define PARITY_EVEN 0x10
#define PARITY_MARK 0x20
#define PARITY_SPACE 0x30
#define LCR_BRK 0x40
#define LCR_DLAB 0x80
#define DLAB 0x80
#define UART1_MCR (RTL838X_UART1_BASE + 0x010)
#define UART1_LSR (RTL838X_UART1_BASE + 0x014)
#define LSR_DR 0x01
#define RxCHAR_AVAIL 0x01
#define LSR_OE 0x02
#define LSR_PE 0x04
#define LSR_FE 0x08
#define LSR_BI 0x10
#define LSR_THRE 0x20
#define TxCHAR_AVAIL 0x00
#define TxCHAR_EMPTY 0x20
#define LSR_TEMT 0x40
#define LSR_RFE 0x80
/*
* Timer/counter for 8390/80/28 TC & MP chip
*/
#define RTL838X_TIMER0_BASE ((volatile void *)(0xb8003100UL))
#define RTL838X_TIMER0_IRQ RTL838X_TC0_EXT_IRQ
#define RTL8390TC_TC1DATA (RTL838X_TIMER0_BASE + 0x04)
#define RTL8390TC_TCD_OFFSET 8
#define RTL8390TC_TC0CNT (RTL838X_TIMER0_BASE + 0x08)
#define RTL8390TC_TC1CNT (RTL838X_TIMER0_BASE + 0x0C)
#define RTL8390TC_TCCNR (RTL838X_TIMER0_BASE + 0x10)
#define RTL8390TC_TC0EN (1 << 31)
#define RTL8390TC_TC0MODE_TIMER (1 << 30)
#define RTL8390TC_TC1EN (1 << 29)
#define RTL8390TC_TC1MODE_TIMER (1 << 28)
#define RTL8390TC_TCIR (RTL838X_TIMER0_BASE + 0x14)
#define RTL8390TC_TC0IE (1 << 31)
#define RTL8390TC_TC1IE (1 << 30)
#define RTL8390TC_TC0IP (1 << 29)
#define RTL8390TC_TC1IP (1 << 28)
#define RTL8390TC_CDBR (RTL838X_TIMER0_BASE + 0x18)
#define RTL8390TC_DIVF_OFFSET 16
#define RTL8390TC_WDTCNR (RTL838X_TIMER0_BASE + 0x1C)
#define RTL8390MP_TC1DATA (RTL838X_TIMER0_BASE + 0x10)
#define RTL8390MP_TC0CNT (RTL838X_TIMER0_BASE + 0x04)
#define RTL8390MP_TC1CNT (RTL838X_TIMER0_BASE + 0x14)
#define RTL8390MP_TC0CTL (RTL838X_TIMER0_BASE + 0x08)
#define RTL8390MP_TC1CTL (RTL838X_TIMER0_BASE + 0x18)
#define RTL8390MP_TCEN (1 << 28)
#define RTL8390MP_TCMODE_TIMER (1 << 24)
#define RTL8390MP_TCDIV_FACTOR (0xFFFF << 0)
#define RTL8390MP_TC0INT (RTL838X_TIMER0_BASE + 0xC)
#define RTL8390MP_TC1INT (RTL838X_TIMER0_BASE + 0x1C)
#define RTL8390MP_TCIE (1 << 20)
#define RTL8390MP_TCIP (1 << 16)
#define RTL8390MP_WDTCNR (RTL838X_TIMER0_BASE + 0x50)
#define RTL8380MP_TC0DATA (RTL838X_TIMER0_BASE + 0x00)
#define RTL8380MP_TC1DATA (RTL838X_TIMER0_BASE + 0x10)
#define RTL8380MP_TC0CNT (RTL838X_TIMER0_BASE + 0x04)
#define RTL8380MP_TC1CNT (RTL838X_TIMER0_BASE + 0x14)
#define RTL8380MP_TC0CTL (RTL838X_TIMER0_BASE + 0x08)
#define RTL8380MP_TC1CTL (RTL838X_TIMER0_BASE + 0x18)
#define RTL8380MP_TCEN (1 << 28)
#define RTL8380MP_TCMODE_TIMER (1 << 24)
#define RTL8380MP_TCDIV_FACTOR (0xFFFF << 0)
#define RTL8380MP_TC0INT (RTL838X_TIMER0_BASE + 0xC)
#define RTL8380MP_TC1INT (RTL838X_TIMER0_BASE + 0x1C)
#define RTL8380MP_TCIE (1 << 20)
#define RTL8380MP_TCIP (1 << 16)
#define RTL8380MP_WDTCNR (RTL838X_TIMER0_BASE + 0x50)
#define DIVISOR_RTL8390 55
#define DIVISOR_RTL8380 2500
#define DIVISOR_MAX 16834
/*
* Memory Controller
*/
#define MC_MCR 0xB8001000
#define MC_MCR_VAL 0x00000000
#define MC_DCR 0xB8001004
#define MC_DCR0_VAL 0x54480000
#define MC_DTCR 0xB8001008
#define MC_DTCR_VAL 0xFFFF05C0
/*
* GPIO
*/
#define GPIO_CTRL_REG_BASE ((volatile void *) 0xb8003500)
#define RTL838X_GPIO_PABC_CNR (GPIO_CTRL_REG_BASE + 0x0)
#define RTL838X_GPIO_PABC_TYPE (GPIO_CTRL_REG_BASE + 0x04)
#define RTL838X_GPIO_PABC_DIR (GPIO_CTRL_REG_BASE + 0x8)
#define RTL838X_GPIO_PABC_DATA (GPIO_CTRL_REG_BASE + 0xc)
#define RTL838X_GPIO_PABC_ISR (GPIO_CTRL_REG_BASE + 0x10)
#define RTL838X_GPIO_PAB_IMR (GPIO_CTRL_REG_BASE + 0x14)
#define RTL838X_GPIO_PC_IMR (GPIO_CTRL_REG_BASE + 0x18)
#define RTL838X_MODEL_NAME_INFO (0x00D4)
#define RTL839X_MODEL_NAME_INFO (0x0FF0)
#define RTL838X_LED_GLB_CTRL (0xA000)
#define RTL839X_LED_GLB_CTRL (0x00E4)
#define RTL838X_EXT_GPIO_DIR_0 (0xA08C)
#define RTL838X_EXT_GPIO_DIR_1 (0xA090)
#define RTL838X_EXT_GPIO_DATA_0 (0xA094)
#define RTL838X_EXT_GPIO_DATA_1 (0xA098)
#define RTL838X_EXT_GPIO_INDRT_ACCESS (0xA09C)
#define RTL838X_EXTRA_GPIO_CTRL (0xA0E0)
#define RTL838X_EXTRA_GPIO_DIR_0 (0xA0E4)
#define RTL838X_EXTRA_GPIO_DIR_1 (0xA0E8)
#define RTL838X_EXTRA_GPIO_DATA_0 (0xA0EC)
#define RTL838X_EXTRA_GPIO_DATA_1 (0xA0F0)
#define RTL838X_DMY_REG5 (0x0144)
#define RTL838X_EXTRA_GPIO_CTRL (0xA0E0)
#define RTL838X_GMII_INTF_SEL (0x1000)
#define RTL838X_IO_DRIVING_ABILITY_CTRL (0x1010)
#define RTL838X_GPIO_A7 31
#define RTL838X_GPIO_A6 30
#define RTL838X_GPIO_A5 29
#define RTL838X_GPIO_A4 28
#define RTL838X_GPIO_A3 27
#define RTL838X_GPIO_A2 26
#define RTL838X_GPIO_A1 25
#define RTL838X_GPIO_A0 24
#define RTL838X_GPIO_B7 23
#define RTL838X_GPIO_B6 22
#define RTL838X_GPIO_B5 21
#define RTL838X_GPIO_B4 20
#define RTL838X_GPIO_B3 19
#define RTL838X_GPIO_B2 18
#define RTL838X_GPIO_B1 17
#define RTL838X_GPIO_B0 16
#define RTL838X_GPIO_C7 15
#define RTL838X_GPIO_C6 14
#define RTL838X_GPIO_C5 13
#define RTL838X_GPIO_C4 12
#define RTL838X_GPIO_C3 11
#define RTL838X_GPIO_C2 10
#define RTL838X_GPIO_C1 9
#define RTL838X_GPIO_C0 8
#define RTL838X_INT_RW_CTRL (0x0058)
#define RTL838X_EXT_VERSION (0x00D0)
#define RTL838X_PLL_CML_CTRL (0x0FF8)
#define RTL838X_STRAP_DBG (0x100C)
/*
* Reset
*/
#define RGCR (0x1E70)
#define RTL839X_RST_GLB_CTRL (0x0014)
#define RTL838X_RST_GLB_CTRL_1 (0x0040)
/* LED control by switch */
#define RTL838X_LED_MODE_SEL (0x1004)
#define RTL838X_LED_MODE_CTRL (0xA004)
#define RTL838X_LED_P_EN_CTRL (0xA008)
/* LED control by software */
#define RTL838X_LED_SW_CTRL (0xA00C)
#define RTL838X_LED0_SW_P_EN_CTRL (0xA010)
#define RTL838X_LED1_SW_P_EN_CTRL (0xA014)
#define RTL838X_LED2_SW_P_EN_CTRL (0xA018)
#define RTL838X_LED_SW_P_CTRL(p) (0xA01C + ((p) << 2))
#define RTL839X_MAC_EFUSE_CTRL (0x02ac)
/*
* MDIO via Realtek's SMI interface
*/
#define RTL838X_SMI_GLB_CTRL (0xa100)
#define RTL838X_SMI_ACCESS_PHY_CTRL_0 (0xa1b8)
#define RTL838X_SMI_ACCESS_PHY_CTRL_1 (0xa1bc)
#define RTL838X_SMI_ACCESS_PHY_CTRL_2 (0xa1c0)
#define RTL838X_SMI_ACCESS_PHY_CTRL_3 (0xa1c4)
#define RTL838X_SMI_PORT0_5_ADDR_CTRL (0xa1c8)
#define RTL838X_SMI_POLL_CTRL (0xa17c)
#define RTL839X_SMI_GLB_CTRL (0x03f8)
#define RTL839X_SMI_PORT_POLLING_CTRL (0x03fc)
#define RTL839X_PHYREG_ACCESS_CTRL (0x03DC)
#define RTL839X_PHYREG_CTRL (0x03E0)
#define RTL839X_PHYREG_PORT_CTRL(p) (0x03E4 + ((p >> 5) << 2))
#define RTL839X_PHYREG_DATA_CTRL (0x03F0)
/*
* Switch interrupts
*/
#define RTL838X_IMR_GLB (0x1100)
#define RTL838X_IMR_PORT_LINK_STS_CHG (0x1104)
#define RTL838X_ISR_GLB_SRC (0x1148)
#define RTL838X_ISR_PORT_LINK_STS_CHG (0x114C)
#define RTL839X_IMR_GLB (0x0064)
#define RTL839X_IMR_PORT_LINK_STS_CHG (0x0068)
#define RTL839X_ISR_GLB_SRC (0x009c)
#define RTL839X_ISR_PORT_LINK_STS_CHG (0x00a0)
/* Definition of family IDs */
#define RTL8389_FAMILY_ID (0x8389)
#define RTL8328_FAMILY_ID (0x8328)
#define RTL8390_FAMILY_ID (0x8390)
#define RTL8350_FAMILY_ID (0x8350)
#define RTL8380_FAMILY_ID (0x8380)
#define RTL8330_FAMILY_ID (0x8330)
struct rtl838x_soc_info {
unsigned char *name;
unsigned int id;
unsigned int family;
unsigned char *compatible;
volatile void *sw_base;
volatile void *icu_base;
};
void rtl838x_soc_detect(struct rtl838x_soc_info *i);
#endif /* _MACH_RTL838X_H_ */

View File

@ -0,0 +1,5 @@
#
# Makefile for the rtl838x specific parts of the kernel
#
obj-y := serial.o setup.o prom.o irq.o

View File

@ -0,0 +1,6 @@
#
# Realtek RTL838x SoCs
#
platform-$(CONFIG_RTL838X) += rtl838x/
cflags-$(CONFIG_RTL838X) += -I$(srctree)/arch/mips/include/asm/mach-rtl838x/
load-$(CONFIG_RTL838X) += 0xffffffff80000000

View File

@ -0,0 +1,263 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Realtek RTL838X architecture specific IRQ handling
*
* Copyright (C) 2020 B. Koblitz
* based on the original BSP
* Copyright (C) 2006-2012 Tony Wu (tonywu@realtek.com)
*
*/
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/irqchip.h>
#include <linux/of_irq.h>
#include <linux/of_address.h>
#include <linux/spinlock.h>
#include <asm/irq_cpu.h>
#include <asm/mipsregs.h>
#include <mach-rtl838x.h>
extern struct rtl838x_soc_info soc_info;
#define icu_r32(reg) rtl838x_r32(soc_info.icu_base + reg)
#define icu_w32(val, reg) rtl838x_w32(val, soc_info.icu_base + reg)
#define icu_w32_mask(clear, set, reg) rtl838x_w32_mask(clear, set, soc_info.icu_base + reg)
static DEFINE_RAW_SPINLOCK(irq_lock);
extern irqreturn_t c0_compare_interrupt(int irq, void *dev_id);
unsigned int rtl838x_ictl_irq_dispatch1(void);
unsigned int rtl838x_ictl_irq_dispatch2(void);
unsigned int rtl838x_ictl_irq_dispatch3(void);
unsigned int rtl838x_ictl_irq_dispatch4(void);
unsigned int rtl838x_ictl_irq_dispatch5(void);
static struct irqaction irq_cascade1 = {
.handler = no_action,
.name = "RTL838X IRQ cascade1",
};
static struct irqaction irq_cascade2 = {
.handler = no_action,
.name = "RTL838X IRQ cascade2",
};
static struct irqaction irq_cascade3 = {
.handler = no_action,
.name = "RTL838X IRQ cascade3",
};
static struct irqaction irq_cascade4 = {
.handler = no_action,
.name = "RTL838X IRQ cascade4",
};
static struct irqaction irq_cascade5 = {
.handler = no_action,
.name = "RTL838X IRQ cascade5",
};
static void rtl838x_ictl_enable_irq(struct irq_data *i)
{
unsigned long flags;
raw_spin_lock_irqsave(&irq_lock, flags);
icu_w32_mask(0, 1 << i->irq, GIMR);
raw_spin_unlock_irqrestore(&irq_lock, flags);
}
static unsigned int rtl838x_ictl_startup_irq(struct irq_data *i)
{
rtl838x_ictl_enable_irq(i);
return 0;
}
static void rtl838x_ictl_disable_irq(struct irq_data *i)
{
unsigned long flags;
raw_spin_lock_irqsave(&irq_lock, flags);
icu_w32_mask(1 << i->irq, 0, GIMR);
raw_spin_unlock_irqrestore(&irq_lock, flags);
}
static void rtl838x_ictl_eoi_irq(struct irq_data *i)
{
unsigned long flags;
raw_spin_lock_irqsave(&irq_lock, flags);
icu_w32_mask(0, 1 << i->irq, GIMR);
raw_spin_unlock_irqrestore(&irq_lock, flags);
}
static struct irq_chip rtl838x_ictl_irq = {
.name = "RTL838X",
.irq_startup = rtl838x_ictl_startup_irq,
.irq_shutdown = rtl838x_ictl_disable_irq,
.irq_enable = rtl838x_ictl_enable_irq,
.irq_disable = rtl838x_ictl_disable_irq,
.irq_ack = rtl838x_ictl_disable_irq,
.irq_mask = rtl838x_ictl_disable_irq,
.irq_unmask = rtl838x_ictl_enable_irq,
.irq_eoi = rtl838x_ictl_eoi_irq,
};
/*
* RTL8390/80/28 Interrupt Scheme
*
* Source IRQ CPU INT
* -------- ------- -------
* UART0 31 IP3
* UART1 30 IP2
* TIMER0 29 IP6
* TIMER1 28 IP2
* OCPTO 27 IP2
* HLXTO 26 IP2
* SLXTO 25 IP2
* NIC 24 IP5
* GPIO_ABCD 23 IP5
* SWCORE 20 IP4
*/
unsigned int rtl838x_ictl_irq_dispatch1(void)
{
/* Identify shared IRQ */
unsigned int extint_ip = icu_r32(GIMR) & icu_r32(GISR);
if (extint_ip & TC1_IP)
do_IRQ(TC1_IRQ);
else if (extint_ip & UART1_IP)
do_IRQ(UART1_IRQ);
else
spurious_interrupt();
return IRQ_HANDLED;
}
unsigned int rtl838x_ictl_irq_dispatch2(void)
{
do_IRQ(UART0_IRQ);
return IRQ_HANDLED;
}
unsigned int rtl838x_ictl_irq_dispatch3(void)
{
do_IRQ(SWCORE_IRQ);
return IRQ_HANDLED;
}
unsigned int rtl838x_ictl_irq_dispatch4(void)
{
/* Identify shared IRQ */
unsigned int extint_ip = icu_r32(GIMR) & icu_r32(GISR);
if (extint_ip & NIC_IP)
do_IRQ(NIC_IRQ);
else if (extint_ip & GPIO_ABCD_IP)
do_IRQ(GPIO_ABCD_IRQ);
else if ((extint_ip & GPIO_EFGH_IP) && (soc_info.family == RTL8328_FAMILY_ID))
do_IRQ(GPIO_EFGH_IRQ);
else
spurious_interrupt();
return IRQ_HANDLED;
}
unsigned int rtl838x_ictl_irq_dispatch5(void)
{
do_IRQ(TC0_IRQ);
return IRQ_HANDLED;
}
asmlinkage void plat_irq_dispatch(void)
{
unsigned int pending;
pending = read_c0_cause() & read_c0_status() & ST0_IM;
if (pending & CAUSEF_IP7)
c0_compare_interrupt(7, NULL);
else if (pending & CAUSEF_IP6)
rtl838x_ictl_irq_dispatch5();
else if (pending & CAUSEF_IP5)
rtl838x_ictl_irq_dispatch4();
else if (pending & CAUSEF_IP4)
rtl838x_ictl_irq_dispatch3();
else if (pending & CAUSEF_IP3)
rtl838x_ictl_irq_dispatch2();
else if (pending & CAUSEF_IP2)
rtl838x_ictl_irq_dispatch1();
else
spurious_interrupt();
}
static void __init rtl838x_ictl_irq_init(unsigned int irq_base)
{
int i;
for (i = 0; i < RTL838X_IRQ_ICTL_NUM; i++)
irq_set_chip_and_handler(irq_base + i, &rtl838x_ictl_irq, handle_level_irq);
setup_irq(RTL838X_ICTL1_IRQ, &irq_cascade1);
setup_irq(RTL838X_ICTL2_IRQ, &irq_cascade2);
setup_irq(RTL838X_ICTL3_IRQ, &irq_cascade3);
setup_irq(RTL838X_ICTL4_IRQ, &irq_cascade4);
setup_irq(RTL838X_ICTL5_IRQ, &irq_cascade5);
/* Set GIMR, IRR */
icu_w32(TC0_IE | UART0_IE, GIMR);
icu_w32(IRR0_SETTING, IRR0);
icu_w32(IRR1_SETTING, IRR1);
icu_w32(IRR2_SETTING, IRR2);
icu_w32(IRR3_SETTING, IRR3);
}
static int intc_map(struct irq_domain *d, unsigned int irq, irq_hw_number_t hw)
{
irq_set_chip_and_handler(hw, &rtl838x_ictl_irq, handle_level_irq);
return 0;
}
static const struct irq_domain_ops irq_domain_ops = {
.xlate = irq_domain_xlate_onecell,
.map = intc_map,
};
int __init icu_of_init(struct device_node *node, struct device_node *parent)
{
int i;
struct irq_domain *domain;
struct resource res;
pr_info("Found Interrupt controller: %s (%s)\n", node->name, node->full_name);
if (of_address_to_resource(node, 0, &res)) {
panic("Failed to get icu memory range");
}
if (!request_mem_region(res.start, resource_size(&res), res.name))
pr_err("Failed to request icu memory\n");
soc_info.icu_base = ioremap(res.start, resource_size(&res));
pr_info("ICU Memory: %08x\n", (u32)soc_info.icu_base);
mips_cpu_irq_init();
domain = irq_domain_add_simple(node, 32, 0, &irq_domain_ops, NULL);
/* Setup all external HW irqs */
for (i = 8; i < 32; i++)
irq_domain_associate(domain, i, i);
rtl838x_ictl_irq_init(RTL838X_IRQ_ICTL_BASE);
return 0;
}
void __init arch_init_irq(void)
{
/* do board-specific irq initialization */
irqchip_init();
}
IRQCHIP_DECLARE(mips_cpu_intc, "rtl838x,icu", icu_of_init);

View File

@ -0,0 +1,174 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* prom.c
* Early intialization code for the Realtek RTL838X SoC
*
* based on the original BSP by
* Copyright (C) 2006-2012 Tony Wu (tonywu@realtek.com)
* Copyright (C) 2020 B. Koblitz
*
*/
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/string.h>
#include <linux/of_fdt.h>
#include <linux/libfdt.h>
#include <asm/bootinfo.h>
#include <asm/addrspace.h>
#include <asm/page.h>
#include <asm/cpu.h>
#include <mach-rtl838x.h>
extern char arcs_cmdline[];
const void *fdt;
extern const char __appended_dtb;
//extern int __init rtl838x_serial_init(void);
void prom_console_init(void)
{
/* UART 16550A is initialized by the bootloader */
}
#ifdef CONFIG_EARLY_PRINTK
#define rtl838x_r8(reg) __raw_readb(reg)
#define rtl838x_w8(val, reg) __raw_writeb(val, reg)
void unregister_prom_console(void)
{
}
void disable_early_printk(void)
{
}
void prom_putchar(char c)
{
unsigned int retry = 0;
do {
if (retry++ >= 30000) {
/* Reset Tx FIFO */
rtl838x_w8(TXRST | CHAR_TRIGGER_14, UART0_FCR);
return;
}
} while ((rtl838x_r8(UART0_LSR) & LSR_THRE) == TxCHAR_AVAIL);
/* Send Character */
rtl838x_w8(c, UART0_THR);
}
char prom_getchar(void)
{
return '\0';
}
#endif
struct rtl838x_soc_info soc_info;
const char *get_system_type(void)
{
return soc_info.name;
}
void __init prom_free_prom_memory(void)
{
}
void __init device_tree_init(void)
{
pr_info("%s called\r\n", __func__);
if (!fdt_check_header(&__appended_dtb)) {
fdt = &__appended_dtb;
pr_info("Using appended Device Tree.\n");
}
initial_boot_params = (void *)fdt;
unflatten_and_copy_device_tree();
}
static void __init prom_init_cmdline(void)
{
int argc = fw_arg0;
char **argv = (char **) KSEG1ADDR(fw_arg1);
int i;
arcs_cmdline[0] = '\0';
for (i = 0; i < argc; i++) {
char *p = (char *) KSEG1ADDR(argv[i]);
if (CPHYSADDR(p) && *p) {
strlcat(arcs_cmdline, p, sizeof(arcs_cmdline));
strlcat(arcs_cmdline, " ", sizeof(arcs_cmdline));
}
}
pr_info("Kernel command line: %s\n", arcs_cmdline);
}
/* Do basic initialization */
void __init prom_init(void)
{
uint32_t model;
pr_info("%s called\n", __func__);
soc_info.sw_base = RTL838X_SW_BASE;
model = sw_r32(RTL838X_MODEL_NAME_INFO);
pr_info("RTL838X model is %x\n", model);
model = model >> 16 & 0xFFFF;
if ((model != 0x8328) && (model != 0x8330) && (model != 0x8332)
&& (model != 0x8380) && (model != 0x8382)) {
model = sw_r32(RTL839X_MODEL_NAME_INFO);
pr_info("RTL839X model is %x\n", model);
model = model >> 16 & 0xFFFF;
}
soc_info.id = model;
switch (model) {
case 0x8328:
soc_info.name = "RTL8328";
soc_info.family = RTL8328_FAMILY_ID;
break;
case 0x8332:
soc_info.name = "RTL8332";
soc_info.family = RTL8380_FAMILY_ID;
break;
case 0x8380:
soc_info.name = "RTL8380";
soc_info.family = RTL8380_FAMILY_ID;
break;
case 0x8382:
soc_info.name = "RTL8382";
soc_info.family = RTL8380_FAMILY_ID;
break;
case 0x8390:
soc_info.name = "RTL8390";
soc_info.family = RTL8390_FAMILY_ID;
break;
case 0x8391:
soc_info.name = "RTL8391";
soc_info.family = RTL8390_FAMILY_ID;
break;
case 0x8392:
soc_info.name = "RTL8392";
soc_info.family = RTL8390_FAMILY_ID;
break;
case 0x8393:
soc_info.name = "RTL8393";
soc_info.family = RTL8390_FAMILY_ID;
break;
default:
soc_info.name = "DEFAULT";
soc_info.family = 0;
}
pr_info("SoC Type: %s\n", get_system_type());
prom_init_cmdline();
}

View File

@ -0,0 +1,100 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* 8250 serial console setup for the Realtek RTL838X SoC
*
* based on the original BSP by
* Copyright (C) 2006-2012 Tony Wu (tonywu@realtek.com)
*
* Copyright (C) 2020 B. Koblitz
*
*/
#include <linux/types.h>
#include <linux/ctype.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/version.h>
#include <linux/serial.h>
#include <linux/serial_core.h>
#include <linux/serial_8250.h>
#include <linux/serial_reg.h>
#include <linux/tty.h>
#include <linux/clk.h>
#include <asm/mach-rtl838x/mach-rtl838x.h>
extern char arcs_cmdline[];
extern struct rtl838x_soc_info soc_info;
int __init rtl838x_serial_init(void)
{
#ifdef CONFIG_SERIAL_8250
int ret;
struct uart_port p;
unsigned long baud = 0;
int err;
char parity = '\0', bits = '\0', flow = '\0';
char *s;
struct device_node *dn;
dn = of_find_compatible_node(NULL, NULL, "ns16550a");
if (dn) {
pr_info("Found NS16550a: %s (%s)\n", dn->name, dn->full_name);
dn = of_find_compatible_node(dn, NULL, "ns16550a");
if (dn && of_device_is_available(dn) && soc_info.family == RTL8380_FAMILY_ID) {
/* Enable UART1 on RTL838x */
pr_info("Enabling uart1\n");
sw_w32(0x10, RTL838X_GMII_INTF_SEL);
}
} else {
pr_err("No NS16550a UART found!");
return -ENODEV;
}
s = strstr(arcs_cmdline, "console=ttyS0,");
if (s) {
s += 14;
baud = kstrtoul(s, 10, &baud);
if (err)
baud = 0;
while (isdigit(*s))
s++;
if (*s == ',')
s++;
if (*s)
parity = *s++;
if (*s == ',')
s++;
if (*s)
bits = *s++;
if (*s == ',')
s++;
if (*s == 'h')
flow = 'r';
}
if (baud == 0) {
baud = 38400;
pr_warn("Using default baud rate: %lu\n", baud);
}
if (parity != 'n' && parity != 'o' && parity != 'e')
parity = 'n';
if (bits != '7' && bits != '8')
bits = '8';
memset(&p, 0, sizeof(p));
p.type = PORT_16550A;
p.membase = (unsigned char *) RTL838X_UART0_BASE;
p.irq = RTL838X_UART0_IRQ;
p.uartclk = SYSTEM_FREQ - (24 * baud);
p.flags = UPF_SKIP_TEST | UPF_LOW_LATENCY | UPF_FIXED_TYPE;
p.iotype = UPIO_MEM;
p.regshift = 2;
p.fifosize = 1;
/* Call early_serial_setup() here, to set up 8250 console driver */
if (early_serial_setup(&p) != 0)
ret = 1;
#endif
return 0;
}

View File

@ -0,0 +1,187 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Setup for the Realtek RTL838X SoC:
* Memory, Timer and Serial
*
* Copyright (C) 2020 B. Koblitz
* based on the original BSP by
* Copyright (C) 2006-2012 Tony Wu (tonywu@realtek.com)
*
*/
#include <linux/console.h>
#include <linux/init.h>
#include <linux/clk.h>
#include <linux/clkdev.h>
#include <linux/clk-provider.h>
#include <asm/addrspace.h>
#include <asm/io.h>
#include <asm/bootinfo.h>
#include <linux/of_fdt.h>
#include <asm/reboot.h>
#include <asm/time.h> /* for mips_hpt_frequency */
#include <asm/prom.h>
#include <asm/smp-ops.h>
#include "mach-rtl838x.h"
extern int rtl838x_serial_init(void);
extern struct rtl838x_soc_info soc_info;
struct clk {
struct clk_lookup cl;
unsigned long rate;
};
struct clk cpu_clk;
u32 pll_reset_value;
static void rtl838x_restart(char *command)
{
u32 pll = sw_r32(RTL838X_PLL_CML_CTRL);
/* SoC reset vector (in flash memory): on RTL839x platform preferred way to reset */
void (*f)(void) = (void *) 0xbfc00000;
pr_info("System restart.\n");
if (soc_info.family == RTL8390_FAMILY_ID) {
f();
/* If calling reset vector fails, reset entire chip */
sw_w32(0xFFFFFFFF, RTL839X_RST_GLB_CTRL);
/* If this fails, halt the CPU */
while
(1);
}
pr_info("PLL control register: %x, applying reset value %x\n",
pll, pll_reset_value);
sw_w32(3, RTL838X_INT_RW_CTRL);
sw_w32(pll_reset_value, RTL838X_PLL_CML_CTRL);
sw_w32(0, RTL838X_INT_RW_CTRL);
pr_info("Resetting RTL838X SoC\n");
/* Reset Global Control1 Register */
sw_w32(1, RTL838X_RST_GLB_CTRL_1);
}
static void rtl838x_halt(void)
{
pr_info("System halted.\n");
while
(1);
}
static void __init rtl838x_setup(void)
{
unsigned int val;
pr_info("Registering _machine_restart\n");
_machine_restart = rtl838x_restart;
_machine_halt = rtl838x_halt;
val = rtl838x_r32((volatile void *)0xBB0040000);
if (val == 3)
pr_info("PCI device found\n");
else
pr_info("NO PCI device found\n");
/* Setup System LED. Bit 15 (14 for RTL8390) then allows to toggle it */
if (soc_info.family == RTL8380_FAMILY_ID)
sw_w32_mask(0, 3 << 16, RTL838X_LED_GLB_CTRL);
else
sw_w32_mask(0, 3 << 15, RTL839X_LED_GLB_CTRL);
}
void __init plat_mem_setup(void)
{
void *dtb;
pr_info("%s called\n", __func__);
set_io_port_base(KSEG1);
if (fw_passed_dtb) /* UHI interface */
dtb = (void *)fw_passed_dtb;
else if (__dtb_start != __dtb_end)
dtb = (void *)__dtb_start;
else
panic("no dtb found");
/*
* Load the devicetree. This causes the chosen node to be
* parsed resulting in our memory appearing
*/
__dt_setup_arch(dtb);
rtl838x_setup();
}
/*
* Linux clock API
*/
int clk_enable(struct clk *clk)
{
return 0;
}
EXPORT_SYMBOL_GPL(clk_enable);
void clk_disable(struct clk *clk)
{
}
EXPORT_SYMBOL_GPL(clk_disable);
unsigned long clk_get_rate(struct clk *clk)
{
if (!clk)
return 0;
return clk->rate;
}
EXPORT_SYMBOL_GPL(clk_get_rate);
int clk_set_rate(struct clk *clk, unsigned long rate)
{
return -1;
}
EXPORT_SYMBOL_GPL(clk_set_rate);
long clk_round_rate(struct clk *clk, unsigned long rate)
{
return -1;
}
EXPORT_SYMBOL_GPL(clk_round_rate);
void __init plat_time_init(void)
{
u32 freq = 500000000;
struct device_node *np;
struct clk *clk = &cpu_clk;
np = of_find_node_by_name(NULL, "cpus");
if (!np) {
pr_err("Missing 'cpus' DT node, using default frequency.");
} else {
if (of_property_read_u32(np, "frequency", &freq) < 0)
pr_err("No 'frequency' property in DT, using default.");
else
pr_info("CPU frequency from device tree: %d", freq);
of_node_put(np);
}
clk->rate = freq;
if (IS_ERR(clk))
panic("unable to get CPU clock, err=%ld", PTR_ERR(clk));
pr_info("CPU Clock: %ld MHz\n", clk->rate / 1000000);
mips_hpt_frequency = freq / 2;
pll_reset_value = sw_r32(RTL838X_PLL_CML_CTRL);
pr_info("PLL control register: %x\n", pll_reset_value);
/* With the info from the command line and cpu-freq we can setup the console */
rtl838x_serial_init();
}

View File

@ -0,0 +1,807 @@
// SPDX-License-Identifier: GPL-2.0-only
#include <linux/gpio/driver.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/delay.h>
#include <asm/mach-rtl838x/mach-rtl838x.h>
/* RTL8231 registers for LED control */
#define RTL8231_LED_FUNC0 0x0000
#define RTL8231_GPIO_PIN_SEL(gpio) ((0x0002) + ((gpio) >> 4))
#define RTL8231_GPIO_DIR(gpio) ((0x0005) + ((gpio) >> 4))
#define RTL8231_GPIO_DATA(gpio) ((0x001C) + ((gpio) >> 4))
#define RTL8231_GPIO_PIN_SEL0 0x0002
#define RTL8231_GPIO_PIN_SEL1 0x0003
#define RTL8231_GPIO_PIN_SEL2 0x0004
#define RTL8231_GPIO_IO_SEL0 0x0005
#define RTL8231_GPIO_IO_SEL1 0x0006
#define RTL8231_GPIO_IO_SEL2 0x0007
#define MDC_WAIT { int i; for (i = 0; i < 2; i++); }
#define I2C_WAIT { int i; for (i = 0; i < 5; i++); }
struct rtl838x_gpios {
struct gpio_chip gc;
u32 id;
struct device *dev;
int irq;
int bus_id;
int num_leds;
int min_led;
int leds_per_port;
u32 led_mode;
u16 rtl8381_phy_id;
int smi_clock;
int smi_data;
int i2c_sda;
int i2c_sdc;
};
extern struct mutex smi_lock;
u32 rtl838x_rtl8231_read(u8 bus_id, u32 reg)
{
u32 t = 0;
reg &= 0x1f;
bus_id &= 0x1f;
/* Calculate read register address */
t = (bus_id << 2) | (reg << 7);
mutex_lock(&smi_lock);
/* Set execution bit: cleared when operation completed */
t |= 1;
sw_w32(t, RTL838X_EXT_GPIO_INDRT_ACCESS);
do { /* TODO: Return 0x80000000 if timeout */
t = sw_r32(RTL838X_EXT_GPIO_INDRT_ACCESS);
} while (t & 1);
pr_debug("%s: %x, %x, %x\n", __func__, bus_id, reg, (t & 0xffff0000) >> 16);
mutex_unlock(&smi_lock);
return (t & 0xffff0000) >> 16;
}
int rtl838x_rtl8231_write(u8 bus_id, u32 reg, u32 data)
{
u32 t = 0;
pr_debug("%s: %x, %x, %x\n", __func__, bus_id, reg, data);
data &= 0xffff;
reg &= 0x1f;
bus_id &= 0x1f;
mutex_lock(&smi_lock);
t = (bus_id << 2) | (reg << 7) | (data << 16);
/* Set write bit */
t |= 2;
/* Set execution bit: cleared when operation completed */
t |= 1;
sw_w32(t, RTL838X_EXT_GPIO_INDRT_ACCESS);
do { /* TODO: Return -1 if timeout */
t = sw_r32(RTL838X_EXT_GPIO_INDRT_ACCESS);
} while (t & 1);
mutex_unlock(&smi_lock);
return 0;
}
static int rtl8231_pin_dir(u8 bus_id, u32 gpio, u32 dir)
{
/* dir 1: input
* dir 0: output
*/
u32 v;
int pin_sel_addr = RTL8231_GPIO_PIN_SEL(gpio);
int pin_dir_addr = RTL8231_GPIO_DIR(gpio);
int pin = gpio % 16;
int dpin = pin;
if (gpio > 31) {
dpin = pin << 5;
pin_dir_addr = pin_sel_addr;
}
/* Select GPIO function for pin */
v = rtl838x_rtl8231_read(bus_id, pin_sel_addr);
if (v & 0x80000000) {
pr_err("Error reading RTL8231\n");
return -1;
}
rtl838x_rtl8231_write(bus_id, pin_sel_addr, v | (1 << pin));
v = rtl838x_rtl8231_read(bus_id, pin_dir_addr);
if (v & 0x80000000) {
pr_err("Error reading RTL8231\n");
return -1;
}
rtl838x_rtl8231_write(bus_id, pin_dir_addr,
(v & ~(1 << dpin)) | (dir << dpin));
return 0;
}
static int rtl8231_pin_dir_get(u8 bus_id, u32 gpio, u32 *dir)
{
/* dir 1: input
* dir 0: output
*/
u32 v;
int pin_dir_addr = RTL8231_GPIO_DIR(gpio);
int pin = gpio % 16;
if (gpio > 31) {
pin_dir_addr = RTL8231_GPIO_PIN_SEL(gpio);
pin = pin << 5;
}
v = rtl838x_rtl8231_read(bus_id, pin_dir_addr);
if (v & (1 << pin))
*dir = 1;
else
*dir = 0;
return 0;
}
static int rtl8231_pin_set(u8 bus_id, u32 gpio, u32 data)
{
u32 v = rtl838x_rtl8231_read(bus_id, RTL8231_GPIO_DATA(gpio));
if (v & 0x80000000) {
pr_err("Error reading RTL8231\n");
return -1;
}
rtl838x_rtl8231_write(bus_id, RTL8231_GPIO_DATA(gpio),
(v & ~(1 << (gpio % 16))) | (data << (gpio % 16)));
return 0;
}
static int rtl8231_pin_get(u8 bus_id, u32 gpio, u16 *state)
{
u32 v = rtl838x_rtl8231_read(bus_id, RTL8231_GPIO_DATA(gpio));
if (v & 0x80000000) {
pr_err("Error reading RTL8231\n");
return -1;
}
*state = v & 0xffff;
return 0;
}
static int rtl838x_direction_input(struct gpio_chip *gc, unsigned int offset)
{
struct rtl838x_gpios *gpios = gpiochip_get_data(gc);
pr_debug("%s: %d\n", __func__, offset);
if (offset < 32) {
rtl838x_w32_mask(1 << offset, 0, RTL838X_GPIO_PABC_DIR);
return 0;
}
/* Internal LED driver does not support input */
if (offset >= 32 && offset < 64)
return -ENOTSUPP;
if (offset >= 64 && offset < 100 && gpios->bus_id >= 0)
return rtl8231_pin_dir(gpios->bus_id, offset - 64, 1);
return -ENOTSUPP;
}
static int rtl838x_direction_output(struct gpio_chip *gc, unsigned int offset, int value)
{
struct rtl838x_gpios *gpios = gpiochip_get_data(gc);
pr_debug("%s: %d\n", __func__, offset);
if (offset < 32)
rtl838x_w32_mask(0, 1 << offset, RTL838X_GPIO_PABC_DIR);
/* LED for PWR and SYS driver is direction output by default */
if (offset >= 32 && offset < 64)
return 0;
if (offset >= 64 && offset < 100 && gpios->bus_id >= 0)
return rtl8231_pin_dir(gpios->bus_id, offset - 64, 0);
return 0;
}
static int rtl838x_get_direction(struct gpio_chip *gc, unsigned int offset)
{
u32 v = 0;
struct rtl838x_gpios *gpios = gpiochip_get_data(gc);
pr_debug("%s: %d\n", __func__, offset);
if (offset < 32) {
v = rtl838x_r32(RTL838X_GPIO_PABC_DIR);
if (v & (1 << offset))
return 0;
return 1;
}
/* LED driver for PWR and SYS is direction output by default */
if (offset >= 32 && offset < 64)
return 0;
if (offset >= 64 && offset < 100 && gpios->bus_id >= 0) {
rtl8231_pin_dir_get(gpios->bus_id, offset - 64, &v);
return v;
}
return 0;
}
static int rtl838x_gpio_get(struct gpio_chip *gc, unsigned int offset)
{
u32 v;
u16 state = 0;
int bit;
struct rtl838x_gpios *gpios = gpiochip_get_data(gc);
pr_debug("%s: %d\n", __func__, offset);
/* Internal GPIO of the RTL8380 */
if (offset < 32) {
v = rtl838x_r32(RTL838X_GPIO_PABC_DATA);
if (v & (1 << offset))
return 1;
return 0;
}
/* LED driver for PWR and SYS */
if (offset >= 32 && offset < 64) {
v = sw_r32(RTL838X_LED_GLB_CTRL);
if (v & (1 << (offset-32)))
return 1;
return 0;
}
/* Indirect access GPIO with RTL8231 */
if (offset >= 64 && offset < 100 && gpios->bus_id >= 0) {
rtl8231_pin_get(gpios->bus_id, offset - 64, &state);
if (state & (1 << (offset % 16)))
return 1;
return 0;
}
bit = (offset - 100) % 32;
if (offset >= 100 && offset < 132) {
if (sw_r32(RTL838X_LED1_SW_P_EN_CTRL) & (1 << bit))
return 1;
return 0;
}
if (offset >= 132 && offset < 164) {
if (sw_r32(RTL838X_LED1_SW_P_EN_CTRL) & (1 << bit))
return 1;
return 0;
}
if (offset >= 164 && offset < 196) {
if (sw_r32(RTL838X_LED1_SW_P_EN_CTRL) & (1 << bit))
return 1;
return 0;
}
return 0;
}
void rtl838x_gpio_set(struct gpio_chip *gc, unsigned int offset, int value)
{
int bit;
struct rtl838x_gpios *gpios = gpiochip_get_data(gc);
pr_debug("rtl838x_set: %d, value: %d\n", offset, value);
/* Internal GPIO of the RTL8380 */
if (offset < 32) {
if (value)
rtl838x_w32_mask(0, 1 << offset, RTL838X_GPIO_PABC_DATA);
else
rtl838x_w32_mask(1 << offset, 0, RTL838X_GPIO_PABC_DATA);
}
/* LED driver for PWR and SYS */
if (offset >= 32 && offset < 64) {
bit = offset - 32;
if (value)
sw_w32_mask(0, 1 << bit, RTL838X_LED_GLB_CTRL);
else
sw_w32_mask(1 << bit, 0, RTL838X_LED_GLB_CTRL);
return;
}
/* Indirect access GPIO with RTL8231 */
if (offset >= 64 && offset < 100 && gpios->bus_id >= 0) {
rtl8231_pin_set(gpios->bus_id, offset - 64, value);
return;
}
bit = (offset - 100) % 32;
/* First Port-LED */
if (offset >= 100 && offset < 132
&& offset >= (100 + gpios->min_led)
&& offset < (100 + gpios->min_led + gpios->num_leds)) {
if (value)
sw_w32_mask(7, 5, RTL838X_LED_SW_P_CTRL(bit));
else
sw_w32_mask(7, 0, RTL838X_LED_SW_P_CTRL(bit));
}
if (offset >= 132 && offset < 164
&& offset >= (132 + gpios->min_led)
&& offset < (132 + gpios->min_led + gpios->num_leds)) {
if (value)
sw_w32_mask(7 << 3, 5 << 3, RTL838X_LED_SW_P_CTRL(bit));
else
sw_w32_mask(7 << 3, 0, RTL838X_LED_SW_P_CTRL(bit));
}
if (offset >= 164 && offset < 196
&& offset >= (164 + gpios->min_led)
&& offset < (164 + gpios->min_led + gpios->num_leds)) {
if (value)
sw_w32_mask(7 << 6, 5 << 6, RTL838X_LED_SW_P_CTRL(bit));
else
sw_w32_mask(7 << 6, 0, RTL838X_LED_SW_P_CTRL(bit));
}
__asm__ volatile ("sync");
}
int rtl8231_init(struct rtl838x_gpios *gpios)
{
uint32_t v;
u8 bus_id = gpios->bus_id;
pr_info("%s called\n", __func__);
/* Enable RTL8231 indirect access mode */
sw_w32_mask(0, 1, RTL838X_EXTRA_GPIO_CTRL);
sw_w32_mask(3, 1, RTL838X_DMY_REG5);
/* Enable RTL8231 via GPIO_A1 line */
rtl838x_w32_mask(0, 1 << RTL838X_GPIO_A1, RTL838X_GPIO_PABC_DIR);
rtl838x_w32_mask(0, 1 << RTL838X_GPIO_A1, RTL838X_GPIO_PABC_DATA);
mdelay(50); /* wait 50ms for reset */
/*Select GPIO functionality for pins 0-15, 16-31 and 32-37 */
rtl838x_rtl8231_write(bus_id, RTL8231_GPIO_PIN_SEL(0), 0xffff);
rtl838x_rtl8231_write(bus_id, RTL8231_GPIO_PIN_SEL(16), 0xffff);
rtl838x_rtl8231_write(bus_id, RTL8231_GPIO_PIN_SEL2, 0x03ff);
v = rtl838x_rtl8231_read(bus_id, RTL8231_LED_FUNC0);
pr_info("RTL8231 led function now: %x\n", v);
return 0;
}
static void smi_write_bit(struct rtl838x_gpios *gpios, u32 bit)
{
if (bit)
rtl838x_w32_mask(0, 1 << gpios->smi_data, RTL838X_GPIO_PABC_DATA);
else
rtl838x_w32_mask(1 << gpios->smi_data, 0, RTL838X_GPIO_PABC_DATA);
MDC_WAIT;
rtl838x_w32_mask(1 << gpios->smi_clock, 0, RTL838X_GPIO_PABC_DATA);
MDC_WAIT;
rtl838x_w32_mask(0, 1 << gpios->smi_clock, RTL838X_GPIO_PABC_DATA);
}
static int smi_read_bit(struct rtl838x_gpios *gpios)
{
u32 v;
MDC_WAIT;
rtl838x_w32_mask(1 << gpios->smi_clock, 0, RTL838X_GPIO_PABC_DATA);
MDC_WAIT;
rtl838x_w32_mask(0, 1 << gpios->smi_clock, RTL838X_GPIO_PABC_DATA);
v = rtl838x_r32(RTL838X_GPIO_PABC_DATA);
if (v & (1 << gpios->smi_data))
return 1;
return 0;
}
/* Tri-state of MDIO line */
static void smi_z(struct rtl838x_gpios *gpios)
{
/* MDIO pin to input */
rtl838x_w32_mask(1 << gpios->smi_data, 0, RTL838X_GPIO_PABC_DIR);
MDC_WAIT;
rtl838x_w32_mask(1 << gpios->smi_clock, 0, RTL838X_GPIO_PABC_DATA);
MDC_WAIT;
rtl838x_w32_mask(0, 1 << gpios->smi_clock, RTL838X_GPIO_PABC_DATA);
}
static void smi_write_bits(struct rtl838x_gpios *gpios, u32 data, int len)
{
while (len) {
len--;
smi_write_bit(gpios, data & (1 << len));
}
}
static void smi_read_bits(struct rtl838x_gpios *gpios, int len, u32 *data)
{
u32 v = 0;
while (len) {
len--;
v <<= 1;
v |= smi_read_bit(gpios);
}
*data = v;
}
/* Bit-banged verson of SMI write access, caller must hold smi_lock */
int rtl8380_smi_write(struct rtl838x_gpios *gpios, u16 reg, u32 data)
{
u16 bus_id = gpios->bus_id;
/* Set clock and data pins on RTL838X to output */
rtl838x_w32_mask(0, 1 << gpios->smi_clock, RTL838X_GPIO_PABC_DIR);
rtl838x_w32_mask(0, 1 << gpios->smi_data, RTL838X_GPIO_PABC_DIR);
/* Write start bits */
smi_write_bits(gpios, 0xffffffff, 32);
smi_write_bits(gpios, 0x5, 4); /* ST and write OP */
smi_write_bits(gpios, bus_id, 5); /* 5 bits: phy address */
smi_write_bits(gpios, reg, 5); /* 5 bits: register address */
smi_write_bits(gpios, 0x2, 2); /* TURNAROUND */
smi_write_bits(gpios, data, 16); /* 16 bits: data*/
smi_z(gpios);
return 0;
}
/* Bit-banged verson of SMI read access, caller must hold smi_lock */
int rtl8380_smi_read(struct rtl838x_gpios *gpios, u16 reg, u32 *data)
{
u16 bus_id = gpios->bus_id;
/* Set clock and data pins on RTL838X to output */
rtl838x_w32_mask(0, 1 << gpios->smi_clock, RTL838X_GPIO_PABC_DIR);
rtl838x_w32_mask(0, 1 << gpios->smi_data, RTL838X_GPIO_PABC_DIR);
/* Write start bits */
smi_write_bits(gpios, 0xffffffff, 32);
smi_write_bits(gpios, 0x6, 4); /* ST and read OP */
smi_write_bits(gpios, bus_id, 5); /* 5 bits: phy address */
smi_write_bits(gpios, reg, 5); /* 5 bits: register address */
smi_z(gpios); /* TURNAROUND */
smi_read_bits(gpios, 16, data);
return 0;
}
static void i2c_pin_set(struct rtl838x_gpios *gpios, int pin, u32 data)
{
u32 v;
rtl8380_smi_read(gpios, RTL8231_GPIO_DATA(pin), &v);
if (!data)
v &= ~(1 << (pin % 16));
else
v |= (1 << (pin % 16));
rtl8380_smi_write(gpios, RTL8231_GPIO_DATA(pin), v);
}
static void i2c_pin_get(struct rtl838x_gpios *gpios, int pin, u32 *data)
{
u32 v;
rtl8380_smi_read(gpios, RTL8231_GPIO_DATA(pin), &v);
if (v & (1 << (pin % 16))) {
*data = 1;
return;
}
*data = 0;
}
static void i2c_pin_dir(struct rtl838x_gpios *gpios, int pin, u16 direction)
{
u32 v;
rtl8380_smi_read(gpios, RTL8231_GPIO_DIR(pin), &v);
if (direction) // Output
v &= ~(1 << (pin % 16));
else
v |= (1 << (pin % 16));
rtl8380_smi_write(gpios, RTL8231_GPIO_DIR(pin), v);
}
static void i2c_start(struct rtl838x_gpios *gpios)
{
i2c_pin_dir(gpios, gpios->i2c_sda, 0); /* Output */
i2c_pin_dir(gpios, gpios->i2c_sdc, 0); /* Output */
I2C_WAIT;
i2c_pin_set(gpios, gpios->i2c_sdc, 1);
I2C_WAIT;
i2c_pin_set(gpios, gpios->i2c_sda, 1);
I2C_WAIT;
i2c_pin_set(gpios, gpios->i2c_sda, 0);
I2C_WAIT;
i2c_pin_set(gpios, gpios->i2c_sdc, 0);
I2C_WAIT;
}
static void i2c_stop(struct rtl838x_gpios *gpios)
{
I2C_WAIT;
i2c_pin_set(gpios, gpios->i2c_sdc, 1);
i2c_pin_set(gpios, gpios->i2c_sda, 0);
I2C_WAIT;
i2c_pin_set(gpios, gpios->i2c_sda, 1);
I2C_WAIT;
i2c_pin_set(gpios, gpios->i2c_sdc, 0);
i2c_pin_dir(gpios, gpios->i2c_sda, 1); /* Input */
i2c_pin_dir(gpios, gpios->i2c_sdc, 1); /* Input */
}
static void i2c_read_bits(struct rtl838x_gpios *gpios, int len, u32 *data)
{
u32 v = 0, t;
while (len) {
len--;
v <<= 1;
i2c_pin_set(gpios, gpios->i2c_sdc, 1);
I2C_WAIT;
i2c_pin_get(gpios, gpios->i2c_sda, &t);
v |= t;
i2c_pin_set(gpios, gpios->i2c_sdc, 0);
I2C_WAIT;
}
*data = v;
}
static void i2c_write_bits(struct rtl838x_gpios *gpios, u32 data, int len)
{
while (len) {
len--;
i2c_pin_set(gpios, gpios->i2c_sda, data & (1 << len));
I2C_WAIT;
i2c_pin_set(gpios, gpios->i2c_sdc, 1);
I2C_WAIT;
i2c_pin_set(gpios, gpios->i2c_sdc, 0);
I2C_WAIT;
}
}
/* This initializes direct external GPIOs via the RTL8231 */
int rtl8380_rtl8321_init(struct rtl838x_gpios *gpios)
{
u32 v;
int mdc = gpios->smi_clock;
int mdio = gpios->smi_data;
pr_info("Configuring SMI: Clock %d, Data %d\n", mdc, mdio);
sw_w32_mask(0, 0x2, RTL838X_IO_DRIVING_ABILITY_CTRL);
/* Enter simulated GPIO mode */
sw_w32_mask(1, 0, RTL838X_EXTRA_GPIO_CTRL);
/* MDIO clock to 2.6MHz */
sw_w32_mask(0x3 << 8, 0, RTL838X_EXTRA_GPIO_CTRL);
/* Configure SMI clock and data GPIO pins */
rtl838x_w32_mask((1 << mdc) | (1 << mdio), 0, RTL838X_GPIO_PABC_CNR);
rtl838x_w32_mask(0, (1 << mdc) | (1 << mdio), RTL838X_GPIO_PABC_DIR);
rtl8380_smi_write(gpios, RTL8231_GPIO_PIN_SEL0, 0xffff);
rtl8380_smi_write(gpios, RTL8231_GPIO_PIN_SEL1, 0xffff);
rtl8380_smi_read(gpios, RTL8231_GPIO_PIN_SEL2, &v);
v |= 0x1f;
rtl8380_smi_write(gpios, RTL8231_GPIO_PIN_SEL2, v);
rtl8380_smi_write(gpios, RTL8231_GPIO_IO_SEL0, 0xffff);
rtl8380_smi_write(gpios, RTL8231_GPIO_IO_SEL1, 0xffff);
rtl8380_smi_read(gpios, RTL8231_GPIO_IO_SEL2, &v);
v |= 0x1f << 5;
rtl8380_smi_write(gpios, RTL8231_GPIO_PIN_SEL2, v);
return 0;
}
void rtl8380_led_test(u32 mask)
{
int i;
u32 mode_sel = sw_r32(RTL838X_LED_MODE_SEL);
u32 led_gbl = sw_r32(RTL838X_LED_GLB_CTRL);
u32 led_p_en = sw_r32(RTL838X_LED_P_EN_CTRL);
/* 2 Leds for ports 0-23 and 24-27, 3 would be 0x7 */
sw_w32_mask(0x3f, 0x3 | (0x3 << 3), RTL838X_LED_GLB_CTRL);
/* Enable all leds */
sw_w32(0xFFFFFFF, RTL838X_LED_P_EN_CTRL);
/* Enable software control of all leds */
sw_w32(0xFFFFFFF, RTL838X_LED_SW_CTRL);
sw_w32(0xFFFFFFF, RTL838X_LED0_SW_P_EN_CTRL);
sw_w32(0xFFFFFFF, RTL838X_LED1_SW_P_EN_CTRL);
sw_w32(0x0000000, RTL838X_LED2_SW_P_EN_CTRL);
for (i = 0; i < 28; i++) {
if (mask & (1 << i))
sw_w32(5 | (5 << 3) | (5 << 6),
RTL838X_LED_SW_P_CTRL(i));
}
msleep(3000);
sw_w32(led_p_en, RTL838X_LED_P_EN_CTRL);
/* Disable software control of all leds */
sw_w32(0x0000000, RTL838X_LED_SW_CTRL);
sw_w32(0x0000000, RTL838X_LED0_SW_P_EN_CTRL);
sw_w32(0x0000000, RTL838X_LED1_SW_P_EN_CTRL);
sw_w32(0x0000000, RTL838X_LED2_SW_P_EN_CTRL);
sw_w32(led_gbl, RTL838X_LED_GLB_CTRL);
sw_w32(mode_sel, RTL838X_LED_MODE_SEL);
}
void take_port_leds(struct rtl838x_gpios *gpios)
{
int leds_per_port = gpios->leds_per_port;
int mode = gpios->led_mode;
pr_info("%s, %d, %x\n", __func__, leds_per_port, mode);
pr_debug("Bootloader settings: %x %x %x\n",
sw_r32(RTL838X_LED0_SW_P_EN_CTRL),
sw_r32(RTL838X_LED1_SW_P_EN_CTRL),
sw_r32(RTL838X_LED2_SW_P_EN_CTRL)
);
pr_debug("led glb: %x, sel %x\n",
sw_r32(RTL838X_LED_GLB_CTRL), sw_r32(RTL838X_LED_MODE_SEL));
pr_debug("RTL838X_LED_P_EN_CTRL: %x", sw_r32(RTL838X_LED_P_EN_CTRL));
pr_debug("RTL838X_LED_MODE_CTRL: %x", sw_r32(RTL838X_LED_MODE_CTRL));
sw_w32_mask(3, 0, RTL838X_LED_MODE_SEL);
sw_w32(mode, RTL838X_LED_MODE_CTRL);
/* Enable software control of all leds */
sw_w32(0xFFFFFFF, RTL838X_LED_SW_CTRL);
sw_w32(0xFFFFFFF, RTL838X_LED_P_EN_CTRL);
sw_w32(0x0000000, RTL838X_LED0_SW_P_EN_CTRL);
sw_w32(0x0000000, RTL838X_LED1_SW_P_EN_CTRL);
sw_w32(0x0000000, RTL838X_LED2_SW_P_EN_CTRL);
sw_w32_mask(0x3f, 0, RTL838X_LED_GLB_CTRL);
switch (leds_per_port) {
case 3:
sw_w32_mask(0, 0x7 | (0x7 << 3), RTL838X_LED_GLB_CTRL);
sw_w32(0xFFFFFFF, RTL838X_LED2_SW_P_EN_CTRL);
/* FALLTHRU */
case 2:
sw_w32_mask(0, 0x3 | (0x3 << 3), RTL838X_LED_GLB_CTRL);
sw_w32(0xFFFFFFF, RTL838X_LED1_SW_P_EN_CTRL);
/* FALLTHRU */
case 1:
sw_w32_mask(0, 0x1 | (0x1 << 3), RTL838X_LED_GLB_CTRL);
sw_w32(0xFFFFFFF, RTL838X_LED0_SW_P_EN_CTRL);
break;
default:
pr_err("No LEDS configured for software control\n");
}
}
static const struct of_device_id rtl838x_gpio_of_match[] = {
{ .compatible = "realtek,rtl838x-gpio" },
{},
};
MODULE_DEVICE_TABLE(of, rtl838x_gpio_of_match);
static int rtl838x_gpio_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct device_node *np = dev->of_node;
struct rtl838x_gpios *gpios;
int err;
u8 indirect_bus_id;
pr_info("Probing RTL838X GPIOs\n");
if (!np) {
dev_err(&pdev->dev, "No DT found\n");
return -EINVAL;
}
gpios = devm_kzalloc(dev, sizeof(*gpios), GFP_KERNEL);
if (!gpios)
return -ENOMEM;
gpios->id = sw_r32(RTL838X_MODEL_NAME_INFO) >> 16;
switch (gpios->id) {
case 0x8332:
pr_debug("Found RTL8332M GPIO\n");
break;
case 0x8380:
pr_debug("Found RTL8380M GPIO\n");
break;
case 0x8381:
pr_debug("Found RTL8381M GPIO\n");
break;
case 0x8382:
pr_debug("Found RTL8382M GPIO\n");
break;
default:
pr_err("Unknown GPIO chip id (%04x)\n", gpios->id);
return -ENODEV;
}
gpios->dev = dev;
gpios->gc.base = 0;
/* 0-31: internal
* 32-63, LED control register
* 64-99: external RTL8231
* 100-131: PORT-LED 0
* 132-163: PORT-LED 1
* 164-195: PORT-LED 2
*/
gpios->gc.ngpio = 196;
gpios->gc.label = "rtl838x";
gpios->gc.parent = dev;
gpios->gc.owner = THIS_MODULE;
gpios->gc.can_sleep = true;
gpios->bus_id = -1;
gpios->irq = 31;
gpios->gc.direction_input = rtl838x_direction_input;
gpios->gc.direction_output = rtl838x_direction_output;
gpios->gc.set = rtl838x_gpio_set;
gpios->gc.get = rtl838x_gpio_get;
gpios->gc.get_direction = rtl838x_get_direction;
if (!of_property_read_u8(np, "indirect-access-bus-id", &indirect_bus_id)) {
gpios->bus_id = indirect_bus_id;
rtl8231_init(gpios);
}
if (!of_property_read_u8(np, "smi-bus-id", &indirect_bus_id)) {
gpios->bus_id = indirect_bus_id;
gpios->smi_clock = RTL838X_GPIO_A2;
gpios->smi_data = RTL838X_GPIO_A3;
gpios->i2c_sda = 1;
gpios->i2c_sdc = 2;
rtl8380_rtl8321_init(gpios);
}
if (of_property_read_bool(np, "take-port-leds")) {
if (of_property_read_u32(np, "leds-per-port", &gpios->leds_per_port))
gpios->leds_per_port = 2;
if (of_property_read_u32(np, "led-mode", &gpios->led_mode))
gpios->led_mode = (0x1ea << 15) | 0x1ea;
if (of_property_read_u32(np, "num-leds", &gpios->num_leds))
gpios->num_leds = 32;
if (of_property_read_u32(np, "min-led", &gpios->min_led))
gpios->min_led = 0;
take_port_leds(gpios);
}
err = devm_gpiochip_add_data(dev, &gpios->gc, gpios);
return err;
}
static struct platform_driver rtl838x_gpio_driver = {
.driver = {
.name = "rtl838x-gpio",
.of_match_table = rtl838x_gpio_of_match,
},
.probe = rtl838x_gpio_probe,
};
module_platform_driver(rtl838x_gpio_driver);
MODULE_DESCRIPTION("Realtek RTL838X GPIO API support");
MODULE_LICENSE("GPL v2");

View File

@ -0,0 +1,607 @@
// SPDX-License-Identifier: GPL-2.0-only
#include <linux/device.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
#include <linux/mtd/mtd.h>
#include <linux/mtd/partitions.h>
#include <linux/mtd/spi-nor.h>
#include "rtl838x-spi.h"
#include <asm/mach-rtl838x/mach-rtl838x.h>
extern struct rtl838x_soc_info soc_info;
struct rtl838x_nor {
struct spi_nor nor;
struct device *dev;
volatile void __iomem *base;
bool fourByteMode;
u32 chipSize;
uint32_t flags;
uint32_t io_status;
};
static uint32_t spi_prep(struct rtl838x_nor *rtl838x_nor)
{
/* Needed because of MMU constraints */
SPI_WAIT_READY;
spi_w32w(SPI_CS_INIT, SFCSR); //deactivate CS0, CS1
spi_w32w(0, SFCSR); //activate CS0,CS1
spi_w32w(SPI_CS_INIT, SFCSR); //deactivate CS0, CS1
return (CS0 & rtl838x_nor->flags) ? (SPI_eCS0 & SPI_LEN_INIT)
: ((SPI_eCS1 & SPI_LEN_INIT) | SFCSR_CHIP_SEL);
}
static uint32_t rtl838x_nor_get_SR(struct rtl838x_nor *rtl838x_nor)
{
uint32_t sfcsr, sfdr;
sfcsr = spi_prep(rtl838x_nor);
sfdr = (SPINOR_OP_RDSR)<<24;
pr_debug("%s: rdid,sfcsr_val = %.8x,SFDR = %.8x\n", __func__, sfcsr, sfdr);
pr_debug("rdid,sfcsr = %.8x\n", sfcsr | SPI_LEN4);
spi_w32w(sfcsr, SFCSR);
spi_w32w(sfdr, SFDR);
spi_w32_mask(0, SPI_LEN4, SFCSR);
SPI_WAIT_READY;
return spi_r32(SFDR);
}
static void spi_write_disable(struct rtl838x_nor *rtl838x_nor)
{
uint32_t sfcsr, sfdr;
sfcsr = spi_prep(rtl838x_nor);
sfdr = (SPINOR_OP_WRDI) << 24;
spi_w32w(sfcsr, SFCSR);
spi_w32w(sfdr, SFDR);
pr_debug("%s: sfcsr_val = %.8x,SFDR = %.8x", __func__, sfcsr, sfdr);
spi_prep(rtl838x_nor);
}
static void spi_write_enable(struct rtl838x_nor *rtl838x_nor)
{
uint32_t sfcsr, sfdr;
sfcsr = spi_prep(rtl838x_nor);
sfdr = (SPINOR_OP_WREN) << 24;
spi_w32w(sfcsr, SFCSR);
spi_w32w(sfdr, SFDR);
pr_debug("%s: sfcsr_val = %.8x,SFDR = %.8x", __func__, sfcsr, sfdr);
spi_prep(rtl838x_nor);
}
static void spi_4b_set(struct rtl838x_nor *rtl838x_nor, bool enable)
{
uint32_t sfcsr, sfdr;
sfcsr = spi_prep(rtl838x_nor);
if (enable)
sfdr = (SPINOR_OP_EN4B) << 24;
else
sfdr = (SPINOR_OP_EX4B) << 24;
spi_w32w(sfcsr, SFCSR);
spi_w32w(sfdr, SFDR);
pr_debug("%s: sfcsr_val = %.8x,SFDR = %.8x", __func__, sfcsr, sfdr);
spi_prep(rtl838x_nor);
}
static int rtl838x_get_addr_mode(struct rtl838x_nor *rtl838x_nor)
{
int res = 3;
u32 reg;
sw_w32(0x3, RTL838X_INT_RW_CTRL);
if (!sw_r32(RTL838X_EXT_VERSION)) {
if (sw_r32(RTL838X_STRAP_DBG) & (1 << 29))
res = 4;
} else {
reg = sw_r32(RTL838X_PLL_CML_CTRL);
if ((reg & (1 << 30)) && (reg & (1 << 31)))
res = 4;
if ((!(reg & (1 << 30)))
&& sw_r32(RTL838X_STRAP_DBG) & (1 << 29))
res = 4;
}
sw_w32(0x0, RTL838X_INT_RW_CTRL);
return res;
}
static int rtl8390_get_addr_mode(struct rtl838x_nor *rtl838x_nor)
{
if (spi_r32(RTL8390_SOC_SPI_MMIO_CONF) & (1 << 9))
return 4;
return 3;
}
ssize_t rtl838x_do_read(struct rtl838x_nor *rtl838x_nor, loff_t from,
size_t length, u_char *buffer, uint8_t command)
{
uint32_t sfcsr, sfdr;
uint32_t len = length;
sfcsr = spi_prep(rtl838x_nor);
sfdr = command << 24;
/* Perform SPINOR_OP_READ: 1 byte command & 3 byte addr*/
sfcsr |= SPI_LEN4;
sfdr |= from;
spi_w32w(sfcsr, SFCSR);
spi_w32w(sfdr, SFDR);
/* Read Data, 4 bytes at a time */
while (length >= 4) {
SPI_WAIT_READY;
*((uint32_t *) buffer) = spi_r32(SFDR);
/* printk("%.8x ", *((uint32_t*) buffer)); */
buffer += 4;
length -= 4;
}
/* The rest needs to be read 1 byte a time */
sfcsr &= SPI_LEN_INIT|SPI_LEN1;
SPI_WAIT_READY;
spi_w32w(sfcsr, SFCSR);
while (length > 0) {
SPI_WAIT_READY;
*(buffer) = spi_r32(SFDR) >> 24;
/* printk("%.2x ", *(buffer)); */
buffer++;
length--;
}
return len;
}
/*
* Do fast read in 3 or 4 Byte addressing mode
*/
static ssize_t rtl838x_do_4bf_read(struct rtl838x_nor *rtl838x_nor, loff_t from,
size_t length, u_char *buffer, uint8_t command)
{
int sfcsr_addr_len = rtl838x_nor->fourByteMode ? 0x3 : 0x2;
int sfdr_addr_shift = rtl838x_nor->fourByteMode ? 0 : 8;
uint32_t sfcsr;
uint32_t len = length;
pr_debug("Fast read from %llx, len %x, shift %d\n",
from, sfcsr_addr_len, sfdr_addr_shift);
sfcsr = spi_prep(rtl838x_nor);
/* Send read command */
spi_w32w(sfcsr | SPI_LEN1, SFCSR);
spi_w32w(command << 24, SFDR);
/* Send address */
spi_w32w(sfcsr | (sfcsr_addr_len << 28), SFCSR);
spi_w32w(from << sfdr_addr_shift, SFDR);
/* Dummy cycles */
spi_w32w(sfcsr | SPI_LEN1, SFCSR);
spi_w32w(0, SFDR);
/* Start reading */
spi_w32w(sfcsr | SPI_LEN4, SFCSR);
/* Read Data, 4 bytes at a time */
while (length >= 4) {
SPI_WAIT_READY;
*((uint32_t *) buffer) = spi_r32(SFDR);
/* printk("%.8x ", *((uint32_t*) buffer)); */
buffer += 4;
length -= 4;
}
/* The rest needs to be read 1 byte a time */
sfcsr &= SPI_LEN_INIT|SPI_LEN1;
SPI_WAIT_READY;
spi_w32w(sfcsr, SFCSR);
while (length > 0) {
SPI_WAIT_READY;
*(buffer) = spi_r32(SFDR) >> 24;
/* printk("%.2x ", *(buffer)); */
buffer++;
length--;
}
return len;
}
/*
* Do write (Page Programming) in 3 or 4 Byte addressing mode
*/
static ssize_t rtl838x_do_4b_write(struct rtl838x_nor *rtl838x_nor, loff_t to,
size_t length, const u_char *buffer,
uint8_t command)
{
int sfcsr_addr_len = rtl838x_nor->fourByteMode ? 0x3 : 0x2;
int sfdr_addr_shift = rtl838x_nor->fourByteMode ? 0 : 8;
uint32_t sfcsr;
uint32_t len = length;
pr_debug("Write to %llx, len %x, shift %d\n",
to, sfcsr_addr_len, sfdr_addr_shift);
sfcsr = spi_prep(rtl838x_nor);
/* Send write command, command IO-width is 1 (bit 25/26) */
spi_w32w(sfcsr | SPI_LEN1 | (0 << 25), SFCSR);
spi_w32w(command << 24, SFDR);
/* Send address */
spi_w32w(sfcsr | (sfcsr_addr_len << 28) | (0 << 25), SFCSR);
spi_w32w(to << sfdr_addr_shift, SFDR);
/* Write Data, 1 byte at a time, if we are not 4-byte aligned */
if (((long)buffer) % 4) {
spi_w32w(sfcsr | SPI_LEN1, SFCSR);
while (length > 0 && (((long)buffer) % 4)) {
SPI_WAIT_READY;
spi_w32(*(buffer) << 24, SFDR);
buffer += 1;
length -= 1;
}
}
/* Now we can write 4 bytes at a time */
SPI_WAIT_READY;
spi_w32w(sfcsr | SPI_LEN4, SFCSR);
while (length >= 4) {
SPI_WAIT_READY;
spi_w32(*((uint32_t *)buffer), SFDR);
buffer += 4;
length -= 4;
}
/* Final bytes might need to be written 1 byte at a time, again */
SPI_WAIT_READY;
spi_w32w(sfcsr | SPI_LEN1, SFCSR);
while (length > 0) {
SPI_WAIT_READY;
spi_w32(*(buffer) << 24, SFDR);
buffer++;
length--;
}
return len;
}
static ssize_t rtl838x_nor_write(struct spi_nor *nor, loff_t to, size_t len,
const u_char *buffer)
{
int ret = 0;
uint32_t offset = 0;
struct rtl838x_nor *rtl838x_nor = nor->priv;
size_t l = len;
uint8_t cmd = SPINOR_OP_PP;
/* Do write in 4-byte mode on large Macronix chips */
if (rtl838x_nor->fourByteMode) {
cmd = SPINOR_OP_PP_4B;
spi_4b_set(rtl838x_nor, true);
}
pr_debug("In %s %8x to: %llx\n", __func__,
(unsigned int) rtl838x_nor, to);
while (l >= SPI_MAX_TRANSFER_SIZE) {
while
(rtl838x_nor_get_SR(rtl838x_nor) & SPI_WIP);
do {
spi_write_enable(rtl838x_nor);
} while (!(rtl838x_nor_get_SR(rtl838x_nor) & SPI_WEL));
ret = rtl838x_do_4b_write(rtl838x_nor, to + offset,
SPI_MAX_TRANSFER_SIZE, buffer+offset, cmd);
l -= SPI_MAX_TRANSFER_SIZE;
offset += SPI_MAX_TRANSFER_SIZE;
}
if (l > 0) {
while
(rtl838x_nor_get_SR(rtl838x_nor) & SPI_WIP);
do {
spi_write_enable(rtl838x_nor);
} while (!(rtl838x_nor_get_SR(rtl838x_nor) & SPI_WEL));
ret = rtl838x_do_4b_write(rtl838x_nor, to+offset,
len, buffer+offset, cmd);
}
return len;
}
static ssize_t rtl838x_nor_read(struct spi_nor *nor, loff_t from,
size_t length, u_char *buffer)
{
uint32_t offset = 0;
uint8_t cmd = SPINOR_OP_READ_FAST;
size_t l = length;
struct rtl838x_nor *rtl838x_nor = nor->priv;
/* Do fast read in 3, or 4-byte mode on large Macronix chips */
if (rtl838x_nor->fourByteMode) {
cmd = SPINOR_OP_READ_FAST_4B;
spi_4b_set(rtl838x_nor, true);
}
/* TODO: do timeout and return error */
pr_debug("Waiting for pending writes\n");
while
(rtl838x_nor_get_SR(rtl838x_nor) & SPI_WIP);
do {
spi_write_enable(rtl838x_nor);
} while (!(rtl838x_nor_get_SR(rtl838x_nor) & SPI_WEL));
pr_debug("cmd is %d\n", cmd);
pr_debug("%s: addr %.8llx to addr %.8x, cmd %.8x, size %d\n", __func__,
from, (u32)buffer, (u32)cmd, length);
while (l >= SPI_MAX_TRANSFER_SIZE) {
rtl838x_do_4bf_read(rtl838x_nor, from + offset,
SPI_MAX_TRANSFER_SIZE, buffer+offset, cmd);
l -= SPI_MAX_TRANSFER_SIZE;
offset += SPI_MAX_TRANSFER_SIZE;
}
if (l > 0)
rtl838x_do_4bf_read(rtl838x_nor, from + offset, l, buffer+offset, cmd);
return length;
}
static int rtl838x_erase(struct spi_nor *nor, loff_t offs)
{
struct rtl838x_nor *rtl838x_nor = nor->priv;
int sfcsr_addr_len = rtl838x_nor->fourByteMode ? 0x3 : 0x2;
int sfdr_addr_shift = rtl838x_nor->fourByteMode ? 0 : 8;
uint32_t sfcsr;
uint8_t cmd = SPINOR_OP_SE;
pr_debug("Erasing sector at %llx\n", offs);
/* Do erase in 4-byte mode on large Macronix chips */
if (rtl838x_nor->fourByteMode) {
cmd = SPINOR_OP_SE_4B;
spi_4b_set(rtl838x_nor, true);
}
/* TODO: do timeout and return error */
while
(rtl838x_nor_get_SR(rtl838x_nor) & SPI_WIP);
do {
spi_write_enable(rtl838x_nor);
} while (!(rtl838x_nor_get_SR(rtl838x_nor) & SPI_WEL));
sfcsr = spi_prep(rtl838x_nor);
/* Send erase command, command IO-width is 1 (bit 25/26) */
spi_w32w(sfcsr | SPI_LEN1 | (0 << 25), SFCSR);
spi_w32w(cmd << 24, SFDR);
/* Send address */
spi_w32w(sfcsr | (sfcsr_addr_len << 28) | (0 << 25), SFCSR);
spi_w32w(offs << sfdr_addr_shift, SFDR);
return 0;
}
static int rtl838x_nor_read_reg(struct spi_nor *nor, u8 opcode, u8 *buf, int len)
{
int length = len;
u8 *buffer = buf;
uint32_t sfcsr, sfdr;
struct rtl838x_nor *rtl838x_nor = nor->priv;
pr_debug("In %s: opcode %x, len %x\n", __func__, opcode, len);
sfcsr = spi_prep(rtl838x_nor);
sfdr = opcode << 24;
sfcsr |= SPI_LEN1;
spi_w32w(sfcsr, SFCSR);
spi_w32w(sfdr, SFDR);
while (length > 0) {
SPI_WAIT_READY;
*(buffer) = spi_r32(SFDR) >> 24;
buffer++;
length--;
}
return len;
}
static int rtl838x_nor_write_reg(struct spi_nor *nor, u8 opcode, u8 *buf, int len)
{
uint32_t sfcsr, sfdr;
struct rtl838x_nor *rtl838x_nor = nor->priv;
pr_debug("In %s, opcode %x, len %x\n", __func__, opcode, len);
sfcsr = spi_prep(rtl838x_nor);
sfdr = opcode << 24;
if (len == 1) { /* SPINOR_OP_WRSR */
sfdr |= buf[0];
sfcsr |= SPI_LEN2;
}
spi_w32w(sfcsr, SFCSR);
spi_w32w(sfdr, SFDR);
return 0;
}
static int spi_enter_sio(struct spi_nor *nor)
{
uint32_t sfcsr, sfcr2, sfdr;
uint32_t ret = 0, reg = 0, size_bits;
struct rtl838x_nor *rtl838x_nor = nor->priv;
pr_debug("In %s\n", __func__);
rtl838x_nor->io_status = 0;
sfdr = SPI_C_RSTQIO << 24;
sfcsr = spi_prep(rtl838x_nor);
reg = spi_r32(SFCR2);
pr_debug("SFCR2: %x, size %x, rdopt: %x\n", reg, SFCR2_GETSIZE(reg),
(reg & SFCR2_RDOPT));
size_bits = rtl838x_nor->fourByteMode ? SFCR2_SIZE(0x6) : SFCR2_SIZE(0x7);
sfcr2 = SFCR2_HOLD_TILL_SFDR2 | size_bits
| (reg & SFCR2_RDOPT) | SFCR2_CMDIO(0)
| SFCR2_ADDRIO(0) | SFCR2_DUMMYCYCLE(4)
| SFCR2_DATAIO(0) | SFCR2_SFCMD(SPINOR_OP_READ_FAST);
pr_debug("SFCR2: %x, size %x\n", reg, SFCR2_GETSIZE(reg));
SPI_WAIT_READY;
spi_w32w(sfcr2, SFCR2);
spi_w32w(sfcsr, SFCSR);
spi_w32w(sfdr, SFDR);
spi_w32_mask(SFCR2_HOLD_TILL_SFDR2, 0, SFCR2);
rtl838x_nor->io_status &= ~IOSTATUS_CIO_MASK;
rtl838x_nor->io_status |= CIO1;
spi_prep(rtl838x_nor);
return ret;
}
int rtl838x_spi_nor_scan(struct spi_nor *nor, const char *name)
{
static const struct spi_nor_hwcaps hwcaps = {
.mask = SNOR_HWCAPS_READ | SNOR_HWCAPS_PP
| SNOR_HWCAPS_READ_FAST
};
struct rtl838x_nor *rtl838x_nor = nor->priv;
pr_debug("In %s\n", __func__);
spi_w32_mask(0, SFCR_EnableWBO, SFCR);
spi_w32_mask(0, SFCR_EnableRBO, SFCR);
rtl838x_nor->flags = CS0 | R_MODE;
spi_nor_scan(nor, NULL, &hwcaps);
pr_debug("------------- Got size: %llx\n", nor->mtd.size);
return 0;
}
int rtl838x_nor_init(struct rtl838x_nor *rtl838x_nor,
struct device_node *flash_node)
{
int ret;
struct spi_nor *nor;
pr_info("%s called\n", __func__);
nor = &rtl838x_nor->nor;
nor->dev = rtl838x_nor->dev;
nor->priv = rtl838x_nor;
spi_nor_set_flash_node(nor, flash_node);
nor->read_reg = rtl838x_nor_read_reg;
nor->write_reg = rtl838x_nor_write_reg;
nor->read = rtl838x_nor_read;
nor->write = rtl838x_nor_write;
nor->erase = rtl838x_erase;
nor->mtd.name = "rtl838x_nor";
nor->erase_opcode = rtl838x_nor->fourByteMode ? SPINOR_OP_SE_4B
: SPINOR_OP_SE;
/* initialized with NULL */
ret = rtl838x_spi_nor_scan(nor, NULL);
if (ret)
return ret;
spi_enter_sio(nor);
spi_write_disable(rtl838x_nor);
ret = mtd_device_parse_register(&nor->mtd, NULL, NULL, NULL, 0);
return ret;
}
static int rtl838x_nor_drv_probe(struct platform_device *pdev)
{
struct device_node *flash_np;
struct resource *res;
int ret;
struct rtl838x_nor *rtl838x_nor;
int addrMode;
pr_info("Initializing rtl838x_nor_driver\n");
if (!pdev->dev.of_node) {
dev_err(&pdev->dev, "No DT found\n");
return -EINVAL;
}
rtl838x_nor = devm_kzalloc(&pdev->dev, sizeof(*rtl838x_nor), GFP_KERNEL);
if (!rtl838x_nor)
return -ENOMEM;
platform_set_drvdata(pdev, rtl838x_nor);
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
rtl838x_nor->base = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR((void *)rtl838x_nor->base))
return PTR_ERR((void *)rtl838x_nor->base);
pr_info("SPI resource base is %08x\n", (u32)rtl838x_nor->base);
rtl838x_nor->dev = &pdev->dev;
/* only support one attached flash */
flash_np = of_get_next_available_child(pdev->dev.of_node, NULL);
if (!flash_np) {
dev_err(&pdev->dev, "no SPI flash device to configure\n");
ret = -ENODEV;
goto nor_free;
}
/* Get the 3/4 byte address mode as configure by bootloader */
if (soc_info.family == RTL8390_FAMILY_ID)
addrMode = rtl8390_get_addr_mode(rtl838x_nor);
else
addrMode = rtl838x_get_addr_mode(rtl838x_nor);
pr_info("Address mode is %d bytes\n", addrMode);
if (addrMode == 4)
rtl838x_nor->fourByteMode = true;
ret = rtl838x_nor_init(rtl838x_nor, flash_np);
nor_free:
return ret;
}
static int rtl838x_nor_drv_remove(struct platform_device *pdev)
{
/* struct rtl8xx_nor *rtl838x_nor = platform_get_drvdata(pdev); */
return 0;
}
static const struct of_device_id rtl838x_nor_of_ids[] = {
{ .compatible = "realtek,rtl838x-nor"},
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, rtl838x_nor_of_ids);
static struct platform_driver rtl838x_nor_driver = {
.probe = rtl838x_nor_drv_probe,
.remove = rtl838x_nor_drv_remove,
.driver = {
.name = "rtl838x-nor",
.pm = NULL,
.of_match_table = rtl838x_nor_of_ids,
},
};
module_platform_driver(rtl838x_nor_driver);
MODULE_LICENSE("GPL v2");
MODULE_DESCRIPTION("RTL838x SPI NOR Flash Driver");

View File

@ -0,0 +1,111 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (C) 2009 Realtek Semiconductor Corp.
*
* 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 3 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.
*
*/
#ifndef _RTL838X_SPI_H
#define _RTL838X_SPI_H
/*
* Register access macros
*/
#define spi_r32(reg) __raw_readl(rtl838x_nor->base + reg)
#define spi_w32(val, reg) __raw_writel(val, rtl838x_nor->base + reg)
#define spi_w32_mask(clear, set, reg) \
spi_w32((spi_r32(reg) & ~(clear)) | (set), reg)
#define SPI_WAIT_READY do { \
} while (!(spi_r32(SFCSR) & SFCSR_SPI_RDY))
#define spi_w32w(val, reg) do { \
__raw_writel(val, rtl838x_nor->base + reg); \
SPI_WAIT_READY; \
} while (0)
#define SFCR (0x00) /*SPI Flash Configuration Register*/
#define SFCR_CLK_DIV(val) ((val)<<29)
#define SFCR_EnableRBO (1<<28)
#define SFCR_EnableWBO (1<<27)
#define SFCR_SPI_TCS(val) ((val)<<23) /*4 bit, 1111 */
#define SFCR2 (0x04) /*For memory mapped I/O */
#define SFCR2_SFCMD(val) ((val)<<24) /*8 bit, 1111_1111 */
#define SFCR2_SIZE(val) ((val)<<21) /*3 bit, 111 */
#define SFCR2_RDOPT (1<<20)
#define SFCR2_CMDIO(val) ((val)<<18) /*2 bit, 11 */
#define SFCR2_ADDRIO(val) ((val)<<16) /*2 bit, 11 */
#define SFCR2_DUMMYCYCLE(val) ((val)<<13) /*3 bit, 111 */
#define SFCR2_DATAIO(val) ((val)<<11) /*2 bit, 11 */
#define SFCR2_HOLD_TILL_SFDR2 (1<<10)
#define SFCR2_GETSIZE(x) (((x)&0x00E00000)>>21)
#define SFCSR (0x08) /*SPI Flash Control&Status Register*/
#define SFCSR_SPI_CSB0 (1<<31)
#define SFCSR_SPI_CSB1 (1<<30)
#define SFCSR_LEN(val) ((val)<<28) /*2 bits*/
#define SFCSR_SPI_RDY (1<<27)
#define SFCSR_IO_WIDTH(val) ((val)<<25) /*2 bits*/
#define SFCSR_CHIP_SEL (1<<24)
#define SFCSR_CMD_BYTE(val) ((val)<<16) /*8 bit, 1111_1111 */
#define SFDR (0x0C) /*SPI Flash Data Register*/
#define SFDR2 (0x10) /*SPI Flash Data Register - for post SPI bootup setting*/
#define SPI_CS_INIT (SFCSR_SPI_CSB0 | SFCSR_SPI_CSB1 | SPI_LEN1)
#define SPI_CS0 SFCSR_SPI_CSB0
#define SPI_CS1 SFCSR_SPI_CSB1
#define SPI_eCS0 ((SFCSR_SPI_CSB1)) /*and SFCSR to active CS0*/
#define SPI_eCS1 ((SFCSR_SPI_CSB0)) /*and SFCSR to active CS1*/
#define SPI_WIP (1) /* Write In Progress */
#define SPI_WEL (1<<1) /* Write Enable Latch*/
#define SPI_SST_QIO_WIP (1<<7) /* SST QIO Flash Write In Progress */
#define SPI_LEN_INIT 0xCFFFFFFF /* and SFCSR to init */
#define SPI_LEN4 0x30000000 /* or SFCSR to set */
#define SPI_LEN3 0x20000000 /* or SFCSR to set */
#define SPI_LEN2 0x10000000 /* or SFCSR to set */
#define SPI_LEN1 0x00000000 /* or SFCSR to set */
#define SPI_SETLEN(val) do { \
SPI_REG(SFCSR) &= 0xCFFFFFFF; \
SPI_REG(SFCSR) |= (val-1)<<28; \
} while (0)
/*
* SPI interface control
*/
#define RTL8390_SOC_SPI_MMIO_CONF (0x04)
#define IOSTATUS_CIO_MASK (0x00000038)
/* Chip select: bits 4-7*/
#define CS0 (1<<4)
#define R_MODE 0x04
/* io_status */
#define IO1 (1<<0)
#define IO2 (1<<1)
#define CIO1 (1<<3)
#define CIO2 (1<<4)
#define CMD_IO1 (1<<6)
#define W_ADDR_IO1 ((1)<<12)
#define R_ADDR_IO2 ((2)<<9)
#define R_DATA_IO2 ((2)<<15)
#define W_DATA_IO1 ((1)<<18)
/* Commands */
#define SPI_C_RSTQIO 0xFF
#define SPI_MAX_TRANSFER_SIZE 256
#endif /* _RTL838X_SPI_H */

View File

@ -0,0 +1,188 @@
/* SPDX-License-Identifier: GPL-2.0-only */
#ifndef _RTL838X_H
#define _RTL838X_H
#include <net/dsa.h>
/*
* Register definition
*/
#define RTL838X_CPU_PORT 28
#define RTL839X_CPU_PORT 52
#define RTL838X_MAC_PORT_CTRL(port) (0xd560 + (((port) << 7)))
#define RTL839X_MAC_PORT_CTRL(port) (0x8004 + (((port) << 7)))
#define RTL838X_RST_GLB_CTRL_0 (0x003c)
#define RTL838X_MAC_FORCE_MODE_CTRL (0xa104)
#define RTL839X_MAC_FORCE_MODE_CTRL (0x02bc)
#define RTL838X_DMY_REG31 (0x3b28)
#define RTL838X_SDS_MODE_SEL (0x0028)
#define RTL838X_SDS_CFG_REG (0x0034)
#define RTL838X_INT_MODE_CTRL (0x005c)
#define RTL838X_CHIP_INFO (0x00d8)
#define RTL839X_CHIP_INFO (0x0ff4)
#define RTL838X_SDS4_REG28 (0xef80)
#define RTL838X_SDS4_DUMMY0 (0xef8c)
#define RTL838X_SDS5_EXT_REG6 (0xf18c)
#define RTL838X_PORT_ISO_CTRL(port) (0x4100 + ((port) << 2))
#define RTL839X_PORT_ISO_CTRL(port) (0x1400 + ((port) << 3))
#define RTL8380_SDS4_FIB_REG0 (0xF800)
#define RTL838X_STAT_PORT_STD_MIB (0x1200)
#define RTL839X_STAT_PORT_STD_MIB (0xC000)
#define RTL838X_STAT_RST (0x3100)
#define RTL839X_STAT_RST (0xF504)
#define RTL838X_STAT_PORT_RST (0x3104)
#define RTL839X_STAT_PORT_RST (0xF508)
#define RTL838X_STAT_CTRL (0x3108)
#define RTL839X_STAT_CTRL (0x04cc)
/* Registers of the internal Serdes of the 8380 */
#define MAPLE_SDS4_REG0r RTL838X_SDS4_REG28
#define MAPLE_SDS5_REG0r (RTL838X_SDS4_REG28 + 0x100)
#define MAPLE_SDS4_REG3r RTL838X_SDS4_DUMMY0
#define MAPLE_SDS5_REG3r (RTL838X_SDS4_REG28 + 0x100)
#define MAPLE_SDS4_FIB_REG0r (RTL838X_SDS4_REG28 + 0x880)
#define MAPLE_SDS5_FIB_REG0r (RTL838X_SDS4_REG28 + 0x980)
/* VLAN registers */
#define RTL838X_VLAN_PROFILE(idx) (0x3A88 + ((idx) << 2))
#define RTL838X_VLAN_PORT_EGR_FLTR (0x3A84)
#define RTL838X_VLAN_PORT_PB_VLAN(port) (0x3C00 + ((port) << 2))
#define RTL838X_VLAN_PORT_IGR_FLTR_0 (0x3A7C)
#define RTL838X_VLAN_PORT_IGR_FLTR_1 (0x3A7C + 4)
/* Table 0/1 access registers */
#define RTL838X_TBL_ACCESS_CTRL_0 (0x6914)
#define RTL838X_TBL_ACCESS_DATA_0(idx) (0x6918 + ((idx) << 2))
#define RTL838X_TBL_ACCESS_CTRL_1 (0xA4C8)
#define RTL838X_TBL_ACCESS_DATA_1(idx) (0xA4CC + ((idx) << 2))
#define RTL839X_TBL_ACCESS_CTRL_0 (0x1190)
#define RTL839X_TBL_ACCESS_DATA_0(idx) (0x1194 + ((idx) << 2))
#define RTL839X_TBL_ACCESS_CTRL_1 (0x6b80)
#define RTL839X_TBL_ACCESS_DATA_1(idx) (0x6b84 + ((idx) << 2))
/* MAC handling */
#define RTL838X_MAC_LINK_STS (0xa188)
#define RTL839X_MAC_LINK_STS (0x0390)
#define RTL838X_MAC_LINK_SPD_STS(port) (0xa190 + (((port >> 4) << 2)))
#define RTL838X_MAC_LINK_DUP_STS (0xa19c)
#define RTL838X_MAC_TX_PAUSE_STS (0xa1a0)
#define RTL838X_MAC_RX_PAUSE_STS (0xa1a4)
#define RTL838X_EEE_TX_TIMER_GIGA_CTRL (0xaa04)
#define RTL838X_EEE_TX_TIMER_GELITE_CTRL (0xaa08)
/* MAC link state bits */
#define FORCE_EN (1 << 0)
#define FORCE_LINK_EN (1 << 1)
#define NWAY_EN (1 << 2)
#define DUPLX_MODE (1 << 3)
#define TX_PAUSE_EN (1 << 6)
#define RX_PAUSE_EN (1 << 7)
/* EEE */
#define RTL838X_MAC_EEE_ABLTY (0xa1a8)
#define RTL838X_EEE_PORT_TX_EN (0x014c)
#define RTL838X_EEE_PORT_RX_EN (0x0150)
#define RTL838X_EEE_CLK_STOP_CTRL (0x0148)
/* L2 functionality */
#define RTL838X_L2_CTRL_0 (0x3200)
#define RTL839X_L2_CTRL_0 (0x3800)
#define RTL838X_L2_CTRL_1 (0x3204)
#define RTL839X_L2_CTRL_1 (0x3804)
#define RTL838X_L2_PORT_AGING_OUT (0x3358)
#define RTL839X_L2_PORT_AGING_OUT (0x3b74)
#define RTL838X_TBL_ACCESS_L2_CTRL (0x6900)
#define RTL839X_TBL_ACCESS_L2_CTRL (0x1180)
#define RTL838X_TBL_ACCESS_L2_DATA(idx) (0x6908 + ((idx) << 2))
#define RTL838X_TBL_ACCESS_L2_DATA(idx) (0x6908 + ((idx) << 2))
#define RTL838X_L2_TBL_FLUSH_CTRL (0x3370)
#define RTL839X_L2_TBL_FLUSH_CTRL (0x3ba0)
/* Port Mirroring */
#define RTL838X_MIR_CTRL(grp) (0x5D00 + (((grp) << 2)))
#define RTL838X_MIR_DPM_CTRL(grp) (0x5D20 + (((grp) << 2)))
#define RTL838X_MIR_SPM_CTRL(grp) (0x5D10 + (((grp) << 2)))
enum phy_type {
PHY_NONE = 0,
PHY_RTL838X_SDS = 1,
PHY_RTL8218B_INT = 2,
PHY_RTL8218B_EXT = 3,
PHY_RTL8214FC = 4
};
struct rtl838x_port {
bool enable;
u64 pm;
u16 pvid;
bool eee_enabled;
enum phy_type phy;
};
struct rtl838x_vlan_info {
u64 untagged_ports;
u64 tagged_ports;
u32 vlan_conf;
};
struct rtl838x_switch_priv;
struct rtl838x_reg {
void (*mask_port_reg)(u64 clear, u64 set, int reg);
void (*set_port_reg)(u64 set, int reg);
u64 (*get_port_reg)(int reg);
int stat_port_rst;
int stat_rst;
int (*stat_port_std_mib)(int p);
void (*mask_port_iso_ctrl)(u64 clear, u64 set, int port);
void (*set_port_iso_ctrl)(u64 set, int port);
int l2_ctrl_0;
int l2_ctrl_1;
int l2_port_aging_out;
int smi_poll_ctrl;
int l2_tbl_flush_ctrl;
void (*exec_tbl0_cmd)(u32 cmd);
void (*exec_tbl1_cmd)(u32 cmd);
int (*tbl_access_data_0)(int i);
int isr_glb_src;
int isr_port_link_sts_chg;
int imr_port_link_sts_chg;
int imr_glb;
void (*vlan_tables_read)(u32 vlan, struct rtl838x_vlan_info *info);
void (*vlan_set_tagged)(u32 vlan, u64 portmask, u32 conf);
void (*vlan_set_untagged)(u32 vlan, u64 portmask);
int (*mac_force_mode_ctrl)(int port);
int rst_glb_ctrl;
};
struct rtl838x_switch_priv {
/* Switch operation */
struct dsa_switch *ds;
struct device *dev;
u16 id;
u16 family_id;
char version;
struct rtl838x_port ports[54]; /* TODO: correct size! */
struct mutex reg_mutex;
int link_state_irq;
int mirror_group_ports[4];
struct mii_bus *mii_bus;
const struct rtl838x_reg *r;
u8 cpu_port;
u8 port_mask;
};
extern struct rtl838x_soc_info soc_info;
extern void rtl8380_sds_rst(int mac);
extern int rtl838x_write_phy(u32 port, u32 page, u32 reg, u32 val);
extern int rtl839x_write_phy(u32 port, u32 page, u32 reg, u32 val);
extern int rtl838x_read_phy(u32 port, u32 page, u32 reg, u32 *val);
extern int rtl839x_read_phy(u32 port, u32 page, u32 reg, u32 *val);
extern int rtl838x_write_mmd_phy(u32 port, u32 addr, u32 reg, u32 val);
extern int rtl838x_read_mmd_phy(u32 port, u32 addr, u32 reg, u32 *val);
#endif /* _RTL838X_H */

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,261 @@
/* SPDX-License-Identifier: GPL-2.0-only */
#ifndef _RTL838X_ETH_H
#define _RTL838X_ETH_H
/*
* Register definition
*/
#define RTL838X_CPU_PORT 28
#define RTL839X_CPU_PORT 52
#define RTL838X_MAC_PORT_CTRL (0xd560)
#define RTL839X_MAC_PORT_CTRL (0x8004)
#define RTL838X_DMA_IF_INTR_STS (0x9f54)
#define RTL839X_DMA_IF_INTR_STS (0x7868)
#define RTL838X_DMA_IF_INTR_MSK (0x9f50)
#define RTL839X_DMA_IF_INTR_MSK (0x7864)
#define RTL838X_DMA_IF_CTRL (0x9f58)
#define RTL839X_DMA_IF_CTRL (0x786c)
#define RTL838X_RST_GLB_CTRL_0 (0x003c)
#define RTL838X_MAC_FORCE_MODE_CTRL (0xa104)
#define RTL839X_MAC_FORCE_MODE_CTRL (0x02bc)
/* MAC address settings */
#define RTL838X_MAC (0xa9ec)
#define RTL839X_MAC (0x02b4)
#define RTL838X_MAC_ALE (0x6b04)
#define RTL838X_MAC2 (0xa320)
#define RTL838X_DMA_RX_BASE (0x9f00)
#define RTL839X_DMA_RX_BASE (0x780c)
#define RTL838X_DMA_TX_BASE (0x9f40)
#define RTL839X_DMA_TX_BASE (0x784c)
#define RTL838X_DMA_IF_RX_RING_SIZE (0xB7E4)
#define RTL839X_DMA_IF_RX_RING_SIZE (0x6038)
#define RTL838X_DMA_IF_RX_RING_CNTR (0xB7E8)
#define RTL839X_DMA_IF_RX_RING_CNTR (0x603c)
#define RTL838X_DMA_IF_RX_CUR (0x9F20)
#define RTL839X_DMA_IF_RX_CUR (0x782c)
#define RTL838X_DMY_REG31 (0x3b28)
#define RTL838X_SDS_MODE_SEL (0x0028)
#define RTL838X_SDS_CFG_REG (0x0034)
#define RTL838X_INT_MODE_CTRL (0x005c)
#define RTL838X_CHIP_INFO (0x00d8)
#define RTL838X_SDS4_REG28 (0xef80)
#define RTL838X_SDS4_DUMMY0 (0xef8c)
#define RTL838X_SDS5_EXT_REG6 (0xf18c)
#define RTL838X_PORT_ISO_CTRL(port) (0x4100 + ((port) << 2))
#define RTL838X_STAT_PORT_STD_MIB(port) (0x1200 + (((port) << 8)))
#define RTL838X_STAT_RST (0x3100)
#define RTL838X_STAT_CTRL (0x3108)
/* Registers of the internal Serdes of the 8380 */
#define MAPLE_SDS4_REG0r RTL838X_SDS4_REG28
#define MAPLE_SDS5_REG0r (RTL838X_SDS4_REG28 + 0x100)
#define MAPLE_SDS4_REG3r RTL838X_SDS4_DUMMY0
#define MAPLE_SDS5_REG3r (RTL838X_SDS4_REG28 + 0x100)
#define MAPLE_SDS4_FIB_REG0r (RTL838X_SDS4_REG28 + 0x880)
#define MAPLE_SDS5_FIB_REG0r (RTL838X_SDS4_REG28 + 0x980)
/* VLAN registers */
#define RTL838X_VLAN_PROFILE(idx) (0x3A88 + ((idx) << 2))
#define RTL838X_VLAN_PORT_EGR_FLTR (0x3A84)
#define RTL838X_VLAN_PORT_PB_VLAN(port) (0x3C00 + ((port) << 2))
#define RTL838X_VLAN_PORT_IGR_FLTR_0 (0x3A7C)
#define RTL838X_VLAN_PORT_IGR_FLTR_1 (0x3A7C + 4)
#define RTL838X_TBL_ACCESS_CTRL_0 (0x6914)
#define RTL838X_TBL_ACCESS_DATA_0(idx) (0x6918 + ((idx) << 2))
#define RTL838X_TBL_ACCESS_CTRL_1 (0xA4C8)
#define RTL838X_TBL_ACCESS_DATA_1(idx) (0xA4CC + ((idx) << 2))
#define RTL839X_TBL_ACCESS_L2_CTRL (0x1180)
#define RTL839X_TBL_ACCESS_L2_DATA(idx) (0x1184 + ((idx) << 2))
/* MAC handling */
#define RTL838X_MAC_LINK_STS (0xa188)
#define RTL839X_MAC_LINK_STS (0x0390)
#define RTL838X_MAC_LINK_SPD_STS (0xa190)
#define RTL839X_MAC_LINK_SPD_STS (0x03a0)
#define RTL838X_MAC_LINK_DUP_STS (0xa19c)
#define RTL839X_MAC_LINK_DUP_STS (0x03b0)
// TODO: RTL8390_MAC_LINK_MEDIA_STS_ADDR ???
#define RTL838X_MAC_TX_PAUSE_STS (0xa1a0)
#define RTL839X_MAC_TX_PAUSE_STS (0x03b8)
#define RTL838X_MAC_RX_PAUSE_STS (0xa1a4)
#define RTL839X_MAC_RX_PAUSE_STS (0x03c0)
#define RTL838X_EEE_TX_TIMER_GIGA_CTRL (0xaa04)
#define RTL838X_EEE_TX_TIMER_GELITE_CTRL (0xaa08)
#define RTL839X_MAC_GLB_CTRL (0x02a8)
#define RTL839X_SCHED_LB_TICK_TKN_CTRL (0x60f8)
#define RTL838X_L2_TBL_FLUSH_CTRL (0x3370)
#define RTL839X_L2_TBL_FLUSH_CTRL (0x3ba0)
/* MAC link state bits */
#define FORCE_EN (1 << 0)
#define FORCE_LINK_EN (1 << 1)
#define NWAY_EN (1 << 2)
#define DUPLX_MODE (1 << 3)
#define TX_PAUSE_EN (1 << 6)
#define RX_PAUSE_EN (1 << 7)
inline int rtl838x_mac_port_ctrl(int p)
{
return RTL838X_MAC_PORT_CTRL + (p << 7);
}
inline int rtl839x_mac_port_ctrl(int p)
{
return RTL839X_MAC_PORT_CTRL + (p << 7);
}
static inline int rtl838x_mac_force_mode_ctrl(int p)
{
return RTL838X_MAC_FORCE_MODE_CTRL + (p << 2);
}
static inline int rtl839x_mac_force_mode_ctrl(int p)
{
return RTL839X_MAC_FORCE_MODE_CTRL + (p << 2);
}
inline int rtl838x_dma_rx_base(int i)
{
return RTL838X_DMA_RX_BASE + (i << 2);
}
inline int rtl839x_dma_rx_base(int i)
{
return RTL839X_DMA_RX_BASE + (i << 2);
}
inline int rtl838x_dma_tx_base(int i)
{
return RTL838X_DMA_TX_BASE + (i << 2);
}
inline int rtl839x_dma_tx_base(int i)
{
return RTL839X_DMA_TX_BASE + (i << 2);
}
inline int rtl838x_dma_if_rx_ring_size(int i)
{
return RTL838X_DMA_IF_RX_RING_SIZE + ((i >> 3) << 2);
}
inline int rtl839x_dma_if_rx_ring_size(int i)
{
return RTL839X_DMA_IF_RX_RING_SIZE + ((i >> 3) << 2);
}
inline int rtl838x_dma_if_rx_ring_cntr(int i)
{
return RTL838X_DMA_IF_RX_RING_CNTR + ((i >> 3) << 2);
}
inline int rtl839x_dma_if_rx_ring_cntr(int i)
{
return RTL839X_DMA_IF_RX_RING_CNTR + ((i >> 3) << 2);
}
inline int rtl838x_dma_if_rx_cur(int i)
{
return RTL838X_DMA_IF_RX_CUR + (i << 2);
}
inline int rtl839x_dma_if_rx_cur(int i)
{
return RTL839X_DMA_IF_RX_CUR + (i << 2);
}
inline u32 rtl838x_get_mac_link_sts(int port)
{
return (sw_r32(RTL838X_MAC_LINK_STS) & (1 << port));
}
inline u32 rtl839x_get_mac_link_sts(int p)
{
return (sw_r32(RTL839X_MAC_LINK_STS + ((p >> 5) << 2)) & (1 << p));
}
inline u32 rtl838x_get_mac_link_dup_sts(int port)
{
return (sw_r32(RTL838X_MAC_LINK_DUP_STS) & (1 << port));
}
inline u32 rtl839x_get_mac_link_dup_sts(int p)
{
return (sw_r32(RTL839X_MAC_LINK_DUP_STS + ((p >> 5) << 2)) & (1 << p));
}
inline u32 rtl838x_get_mac_link_spd_sts(int port)
{
int r = RTL838X_MAC_LINK_SPD_STS + ((port >> 4) << 2);
u32 speed = sw_r32(r);
speed >>= (port % 16) << 1;
return (speed & 0x3);
}
inline u32 rtl839x_get_mac_link_spd_sts(int port)
{
int r = RTL839X_MAC_LINK_SPD_STS + ((port >> 4) << 2);
u32 speed = sw_r32(r);
speed >>= (port % 16) << 1;
return (speed & 0x3);
}
inline u32 rtl838x_get_mac_rx_pause_sts(int port)
{
return (sw_r32(RTL838X_MAC_RX_PAUSE_STS) & (1 << port));
}
inline u32 rtl839x_get_mac_rx_pause_sts(int p)
{
return (sw_r32(RTL839X_MAC_RX_PAUSE_STS + ((p >> 5) << 2)) & (1 << p));
}
inline u32 rtl838x_get_mac_tx_pause_sts(int port)
{
return (sw_r32(RTL838X_MAC_TX_PAUSE_STS) & (1 << port));
}
inline u32 rtl839x_get_mac_tx_pause_sts(int p)
{
return (sw_r32(RTL839X_MAC_TX_PAUSE_STS + ((p >> 5) << 2)) & (1 << p));
}
struct rtl838x_reg {
int (*mac_port_ctrl)(int port);
int dma_if_intr_sts;
int dma_if_intr_msk;
int dma_if_ctrl;
int (*mac_force_mode_ctrl)(int port);
int (*dma_rx_base)(int ring);
int (*dma_tx_base)(int ring);
int (*dma_if_rx_ring_size)(int ring);
int (*dma_if_rx_ring_cntr)(int ring);
int (*dma_if_rx_cur)(int ring);
int rst_glb_ctrl;
u32 (*get_mac_link_sts)(int port);
u32 (*get_mac_link_dup_sts)(int port);
u32 (*get_mac_link_spd_sts)(int port);
u32 (*get_mac_rx_pause_sts)(int port);
u32 (*get_mac_tx_pause_sts)(int port);
int mac;
int l2_tbl_flush_ctrl;
};
int rtl838x_write_phy(u32 port, u32 page, u32 reg, u32 val);
int rtl838x_read_phy(u32 port, u32 page, u32 reg, u32 *val);
int rtl839x_write_phy(u32 port, u32 page, u32 reg, u32 val);
int rtl839x_read_phy(u32 port, u32 page, u32 reg, u32 *val);
extern int rtl8380_sds_power(int mac, int val);
#endif /* _RTL838X_ETH_H */

View File

@ -0,0 +1,44 @@
# This is free software, licensed under the GNU General Public License v2.
# See /LICENSE for more information.
#
include $(TOPDIR)/rules.mk
include $(INCLUDE_DIR)/image.mk
KERNEL_LOADADDR = 0x80000000
KERNEL_ENTRY = 0x80000400
define Build/custom-uimage
mkimage -A $(LINUX_KARCH) \
-O linux -T kernel \
-C gzip -a $(KERNEL_LOADADDR) $(if $(UIMAGE_MAGIC),-M $(UIMAGE_MAGIC),) \
-e $(if $(KERNEL_ENTRY),$(KERNEL_ENTRY),$(KERNEL_LOADADDR)) \
-n '$(1)' -d $@ $@.new
mv $@.new $@
endef
define Device/Default
PROFILES = Default
KERNEL := kernel-bin | append-dtb | gzip | uImage gzip
KERNEL_INITRAMFS := kernel-bin | append-dtb | gzip | uImage gzip
DEVICE_DTS_DIR := ../dts
DEVICE_DTS = $$(SOC)_$(1)
SUPPORTED_DEVICES := $(subst _,$(comma),$(1))
IMAGES := sysupgrade.bin
IMAGE/sysupgrade.bin := append-kernel | pad-to 64k | append-rootfs | pad-rootfs | \
append-metadata | check-size
endef
define Device/allnet_all-sg8208m
SOC := rtl8382
IMAGE_SIZE := 7168k
DEVICE_VENDOR := ALLNET
DEVICE_MODEL := ALL-SG8208M
UIMAGE_MAGIC := 0x00000006
KERNEL := kernel-bin | append-dtb | gzip | custom-uimage 2.2.2.0
KERNEL_INITRAMFS := kernel-bin | append-dtb | gzip | custom-uimage 2.2.2.0
DEVICE_PACKAGES := ip-full ip-bridge kmod-gpio-button-hotplug tc
endef
TARGET_DEVICES += allnet_all-sg8208m
$(eval $(call BuildImage))

View File

@ -0,0 +1,42 @@
--- a/arch/mips/Kbuild.platforms
+++ b/arch/mips/Kbuild.platforms
@@ -27,6 +27,7 @@ platforms += pistachio
platforms += pmcs-msp71xx
platforms += pnx833x
platforms += ralink
+platforms += rtl838x
platforms += rb532
platforms += sgi-ip22
platforms += sgi-ip27
--- a/arch/mips/Kconfig
+++ b/arch/mips/Kconfig
@@ -629,6 +629,29 @@ config RALINK
select ARCH_HAS_RESET_CONTROLLER
select RESET_CONTROLLER
+config RTL838X
+ bool "Realtek based platforms"
+ select DMA_NONCOHERENT
+ select IRQ_MIPS_CPU
+ select CSRC_R4K
+ select CEVT_R4K
+ select SYS_HAS_CPU_MIPS32_R1
+ select SYS_HAS_CPU_MIPS32_R2
+ select SYS_SUPPORTS_BIG_ENDIAN
+ select SYS_SUPPORTS_32BIT_KERNEL
+ select SYS_SUPPORTS_MIPS16
+ select SYS_SUPPORTS_MULTITHREADING
+ select SYS_SUPPORTS_VPE_LOADER
+ select SYS_HAS_EARLY_PRINTK
+ select SWAP_IO_SPACE
+ select BOOT_RAW
+ select CLKDEV_LOOKUP
+ select PINCTRL
+ select ARCH_HAS_RESET_CONTROLLER
+ select RESET_CONTROLLER
+ select RTL8380_SERIES
+ select USE_OF
+
config SGI_IP22
bool "SGI IP22 (Indy/Indigo2)"
select FW_ARC

View File

@ -0,0 +1,25 @@
--- a/drivers/gpio/Kconfig
+++ b/drivers/gpio/Kconfig
@@ -441,6 +441,12 @@
A 32-bit single register GPIO fixed in/out implementation. This
can be used to represent any register as a set of GPIO signals.
+config GPIO_RTL838X
+ tristate "RTL838X GPIO"
+ depends on RTL838X
+ help
+ Say yes here to support RTL838X GPIO devices.
+
config GPIO_SAMA5D2_PIOBU
tristate "SAMA5D2 PIOBU GPIO support"
depends on MFD_SYSCON
--- a/drivers/gpio/Makefile
+++ b/drivers/gpio/Makefile
@@ -117,6 +117,7 @@
obj-$(CONFIG_GPIO_RCAR) += gpio-rcar.o
obj-$(CONFIG_GPIO_RDC321X) += gpio-rdc321x.o
obj-$(CONFIG_GPIO_REG) += gpio-reg.o
+obj-$(CONFIG_GPIO_RTL838X) += gpio-rtl838x.o
obj-$(CONFIG_ARCH_SA1100) += gpio-sa1100.o
obj-$(CONFIG_GPIO_SAMA5D2_PIOBU) += gpio-sama5d2-piobu.o
obj-$(CONFIG_GPIO_SCH311X) += gpio-sch311x.o

View File

@ -0,0 +1,23 @@
--- a/drivers/mtd/spi-nor/Kconfig
+++ b/drivers/mtd/spi-nor/Kconfig
@@ -118,4 +118,13 @@ config SPI_INTEL_SPI_PLATFORM
To compile this driver as a module, choose M here: the module
will be called intel-spi-platform.
+config SPI_RTL838X
+ tristate "Realtek RTl838X SPI flash platform driver"
+ depends on RTL838X
+ help
+ This driver provides support for accessing SPI flash
+ in the RTL838X SoC.
+
+ Say N here unless you know what you are doing.
+
endif # MTD_SPI_NOR
--- a/drivers/mtd/spi-nor/Makefile
+++ b/drivers/mtd/spi-nor/Makefile
@@ -8,3 +8,4 @@ obj-$(CONFIG_SPI_NXP_SPIFI) += nxp-spifi
obj-$(CONFIG_SPI_INTEL_SPI) += intel-spi.o
obj-$(CONFIG_SPI_INTEL_SPI_PCI) += intel-spi-pci.o
obj-$(CONFIG_SPI_INTEL_SPI_PLATFORM) += intel-spi-platform.o
+obj-$(CONFIG_SPI_RTL838X) += rtl838x-nor.o

View File

@ -0,0 +1,26 @@
--- a/drivers/net/dsa/Kconfig
+++ b/drivers/net/dsa/Kconfig
@@ -74,6 +74,13 @@ config NET_DSA_REALTEK_SMI
This enables support for the Realtek SMI-based switch
chips, currently only RTL8366RB.
+config NET_DSA_RTL838X
+ tristate "Realtek rtl838x switch support"
+ depends on RTL838X
+ select NET_DSA_TAG_TRAILER
+ ---help---
+ Say Y here if you want to use the Realtek rtl838x switch.
+
config NET_DSA_SMSC_LAN9303
tristate
select NET_DSA_TAG_LAN9303
--- a/drivers/net/dsa/Makefile
+++ b/drivers/net/dsa/Makefile
@@ -11,6 +11,7 @@ obj-$(CONFIG_NET_DSA_MV88E6060) += mv88e
obj-$(CONFIG_NET_DSA_QCA8K) += qca8k.o
obj-$(CONFIG_NET_DSA_REALTEK_SMI) += realtek-smi.o
realtek-smi-objs := realtek-smi-core.o rtl8366.o rtl8366rb.o
+obj-$(CONFIG_NET_DSA_RTL838X) += rtl838x_sw.o rtl838x_phy.o
obj-$(CONFIG_NET_DSA_SMSC_LAN9303) += lan9303-core.o
obj-$(CONFIG_NET_DSA_SMSC_LAN9303_I2C) += lan9303_i2c.o
obj-$(CONFIG_NET_DSA_SMSC_LAN9303_MDIO) += lan9303_mdio.o

View File

@ -0,0 +1,37 @@
--- a/net/dsa/tag_trailer.c
+++ b/net/dsa/tag_trailer.c
@@ -44,7 +44,12 @@ static struct sk_buff *trailer_xmit(stru
trailer = skb_put(nskb, 4);
trailer[0] = 0x80;
+
+#ifdef CONFIG_NET_DSA_RTL838X
+ trailer[1] = dp->index;
+#else
trailer[1] = 1 << dp->index;
+#endif /* CONFIG_NET_DSA_RTL838X */
trailer[2] = 0x10;
trailer[3] = 0x00;
@@ -61,12 +66,20 @@ static struct sk_buff *trailer_rcv(struc
return NULL;
trailer = skb_tail_pointer(skb) - 4;
+
+#ifdef CONFIG_NET_DSA_RTL838X
+ if (trailer[0] != 0x80 || (trailer[1] & 0xe0) != 0x00 ||
+ (trailer[2] & 0xef) != 0x00 || trailer[3] != 0x00)
+ return NULL;
+
+ source_port = trailer[1] & 0x1f;
+#else
if (trailer[0] != 0x80 || (trailer[1] & 0xf8) != 0x00 ||
(trailer[2] & 0xef) != 0x00 || trailer[3] != 0x00)
return NULL;
source_port = trailer[1] & 7;
-
+#endif
skb->dev = dsa_master_find_slave(dev, 0, source_port);
if (!skb->dev)
return NULL;

View File

@ -0,0 +1,13 @@
Index: linux-5.4.24/include/linux/platform_data/dsa.h
===================================================================
--- linux-5.4.24.orig/include/linux/platform_data/dsa.h
+++ linux-5.4.24/include/linux/platform_data/dsa.h
@@ -6,7 +6,7 @@ struct device;
struct net_device;
#define DSA_MAX_SWITCHES 4
-#define DSA_MAX_PORTS 12
+#define DSA_MAX_PORTS 54
#define DSA_RTABLE_NONE -1
struct dsa_chip_data {

View File

@ -0,0 +1,26 @@
--- a/drivers/net/ethernet/Kconfig
+++ b/drivers/net/ethernet/Kconfig
@@ -163,6 +163,13 @@ source "drivers/net/ethernet/rdc/Kconfig
source "drivers/net/ethernet/realtek/Kconfig"
source "drivers/net/ethernet/renesas/Kconfig"
source "drivers/net/ethernet/rocker/Kconfig"
+
+config NET_RTL838X
+ tristate "Realtek rtl838x Ethernet MAC support"
+ depends on RTL838X
+ ---help---
+ Say Y here if you want to use the Realtek rtl838x Gbps Ethernet MAC.
+
source "drivers/net/ethernet/samsung/Kconfig"
source "drivers/net/ethernet/seeq/Kconfig"
source "drivers/net/ethernet/sfc/Kconfig"
--- a/drivers/net/ethernet/Makefile
+++ b/drivers/net/ethernet/Makefile
@@ -76,6 +76,7 @@ obj-$(CONFIG_NET_VENDOR_REALTEK) += real
obj-$(CONFIG_NET_VENDOR_RENESAS) += renesas/
obj-$(CONFIG_NET_VENDOR_RDC) += rdc/
obj-$(CONFIG_NET_VENDOR_ROCKER) += rocker/
+obj-$(CONFIG_NET_RTL838X) += rtl838x_eth.o
obj-$(CONFIG_NET_VENDOR_SAMSUNG) += samsung/
obj-$(CONFIG_NET_VENDOR_SEEQ) += seeq/
obj-$(CONFIG_NET_VENDOR_SILAN) += silan/

View File

@ -0,0 +1,13 @@
--- a/include/linux/phy.h
+++ b/include/linux/phy.h
@@ -628,6 +628,10 @@
struct ethtool_tunable *tuna,
const void *data);
int (*set_loopback)(struct phy_device *dev, bool enable);
+ int (*get_port)(struct phy_device *dev);
+ int (*set_port)(struct phy_device *dev, int port);
+ int (*get_eee)(struct phy_device *dev, struct ethtool_eee *e);
+ int (*set_eee)(struct phy_device *dev, struct ethtool_eee *e);
};
#define to_phy_driver(d) container_of(to_mdio_common_driver(d), \
struct phy_driver, mdiodrv)

View File

@ -0,0 +1,41 @@
--- a/drivers/net/phy/phylink.c
+++ b/drivers/net/phy/phylink.c
@@ -1244,6 +1244,11 @@
/* If we have a PHY, configure the phy */
if (pl->phydev) {
+ if (pl->phydev->drv->get_port && pl->phydev->drv->set_port) {
+ if(pl->phydev->drv->get_port(pl->phydev) != kset->base.port) {
+ pl->phydev->drv->set_port(pl->phydev, kset->base.port);
+ }
+ }
ret = phy_ethtool_ksettings_set(pl->phydev, &our_kset);
if (ret)
return ret;
@@ -1422,8 +1427,11 @@
ASSERT_RTNL();
- if (pl->phydev)
+ if (pl->phydev) {
+ if (pl->phydev->drv->get_eee)
+ return pl->phydev->drv->get_eee(pl->phydev, eee);
ret = phy_ethtool_get_eee(pl->phydev, eee);
+ }
return ret;
}
@@ -1440,9 +1448,11 @@
ASSERT_RTNL();
- if (pl->phydev)
+ if (pl->phydev) {
+ if (pl->phydev->drv->set_eee)
+ return pl->phydev->drv->set_eee(pl->phydev, eee);
ret = phy_ethtool_set_eee(pl->phydev, eee);
-
+ }
return ret;
}
EXPORT_SYMBOL_GPL(phylink_ethtool_set_eee);

View File

@ -0,0 +1,13 @@
# This is free software, licensed under the GNU General Public License v2.
# See /LICENSE for more information.
#
define Profile/Default
NAME:=Default Profile
PRIORITY:=1
endef
define Profile/Default/Description
Default package set compatible with most boards.
endef
$(eval $(call Profile,Default))