realtek: 6.6: copy files and config from 5.15

Copy files and config from 5.15 kernel version. Because of the big version jump
leave out the patches for now so we can treat them individually later on.

Signed-off-by: Markus Stockhausen <markus.stockhausen@gmx.de>
This commit is contained in:
Markus Stockhausen 2024-09-01 14:43:41 -04:00 committed by Sander Vanheule
parent 0f7131baf3
commit 325d79f0f9
40 changed files with 26764 additions and 0 deletions

View File

@ -0,0 +1,85 @@
# SPDX-License-Identifier: GPL-2.0
%YAML 1.2
---
$id: http://devicetree.org/schemas/timer/realtek,rtl8300-timer.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Realtek Timer Device Tree Bindings
maintainers:
- Markus Stockhausen <markus.stockhausen@gmx.de>
description: |
The Realtek SOCs of the RTL83XX and RTL93XX series have at least 5 known
timers with corresponding interrupt lines . Their speed is derived from the
Lexra Bus (LXB) by dividers. Each timer has a block of 4 control registers in
the address range 0xb800xxxx with following start offsets.
RTL83XX: 0x3100, 0x3110, 0x3120, 0x3130, 0x3140
RTL93XX: 0x3200, 0x3210, 0x3220, 0x3230, 0x3240
properties:
compatible:
items:
- enum:
- realtek,rtl8380-timer
- realtek,rtl8390-timer
- realtek,rtl9300-timer
- const: realtek,otto-timer
reg:
minItems: 5
maxItems: 5
description:
List of timer register addresses.
interrupts:
minItems: 5
maxItems: 5
description:
List of timer interrupts.
clocks:
maxItems: 1
required:
- compatible
- reg
- interrupts
- clocks
additionalProperties: false
examples:
- |
timer0: timer@3100 {
compatible = "realtek,rtl8380-timer", "realtek,otto-timer";
reg = <0x3100 0x10>, <0x3110 0x10>, <0x3120 0x10>,
<0x3130 0x10>, <0x3140 0x10>;
interrupt-parent = <&intc>;
interrupts = <29 4>, <28 4>, <17 4>, <16 4>, <15 4>;
clocks = <&ccu CLK_LXB>;
};
- |
timer0: timer@3100 {
compatible = "realtek,rtl8390-timer", "realtek,otto-timer";
reg = <0x3100 0x10>, <0x3110 0x10>, <0x3120 0x10>,
<0x3130 0x10>, <0x3140 0x10>;
interrupt-parent = <&intc>;
interrupts = <29 4>, <28 4>, <17 4>, <16 4>, <15 4>;
clocks = <&ccu CLK_LXB>;
};
- |
timer0: timer@3200 {
compatible = "realtek,rtl9300-timer", "realtek,otto-timer";
reg = <0x3200 0x10>, <0x3210 0x10>, <0x3220 0x10>,
<0x3230 0x10>, <0x3240 0x10>;
interrupt-parent = <&intc>;
interrupts = <7 4>, <8 4>, <9 4>, <10 4>, <11 4>;
clocks = <&ccu CLK_LXB>;
};
...

View File

@ -0,0 +1,29 @@
/* SPDX-License-Identifier: GPL-2.0-only */
#ifndef RTL838X_IOREMAP_H_
#define RTL838X_IOREMAP_H_
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,415 @@
/* 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_
#include <asm/types.h>
/*
* Register access macros
*/
#define RTL838X_SW_BASE ((volatile void *) 0xBB000000)
#define rtl83xx_r32(reg) readl(reg)
#define rtl83xx_w32(val, reg) writel(val, reg)
#define rtl83xx_w32_mask(clear, set, reg) rtl83xx_w32((rtl83xx_r32(reg) & ~(clear)) | (set), reg)
#define rtl83xx_r8(reg) readb(reg)
#define rtl83xx_w8(val, reg) writeb(val, reg)
#define sw_r32(reg) readl(RTL838X_SW_BASE + reg)
#define sw_w32(val, reg) 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)readl(RTL838X_SW_BASE + reg)) << 32) | \
readl(RTL838X_SW_BASE + reg + 4))
#define sw_w64(val, reg) do { \
writel((u32)((val) >> 32), RTL838X_SW_BASE + reg); \
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
#define RTL83XX_IRQ_UART0 31
#define RTL83XX_IRQ_UART1 30
#define RTL83XX_IRQ_TC0 29
#define RTL83XX_IRQ_TC1 28
#define RTL83XX_IRQ_OCPTO 27
#define RTL83XX_IRQ_HLXTO 26
#define RTL83XX_IRQ_SLXTO 25
#define RTL83XX_IRQ_NIC 24
#define RTL83XX_IRQ_GPIO_ABCD 23
#define RTL83XX_IRQ_GPIO_EFGH 22
#define RTL83XX_IRQ_RTC 21
#define RTL83XX_IRQ_SWCORE 20
#define RTL83XX_IRQ_WDT_IP1 19
#define RTL83XX_IRQ_WDT_IP2 18
#define RTL9300_UART1_IRQ 31
#define RTL9300_UART0_IRQ 30
#define RTL9300_USB_H2_IRQ 28
#define RTL9300_NIC_IRQ 24
#define RTL9300_SWCORE_IRQ 23
#define RTL9300_GPIO_ABC_IRQ 13
#define RTL9300_TC4_IRQ 11
#define RTL9300_TC3_IRQ 10
#define RTL9300_TC2_IRQ 9
#define RTL9300_TC1_IRQ 8
#define RTL9300_TC0_IRQ 7
/*
* 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)
/* 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 UART1_LCR (RTL838X_UART1_BASE + 0x00C)
#define UART1_MCR (RTL838X_UART1_BASE + 0x010)
#define UART1_LSR (RTL838X_UART1_BASE + 0x014)
/*
* 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 RTL930X_GPIO_CTRL_REG_BASE ((volatile void *) 0xb8003300)
#define RTL930X_GPIO_PABCD_DIR (RTL930X_GPIO_CTRL_REG_BASE + 0x8)
#define RTL930X_GPIO_PABCD_DAT (RTL930X_GPIO_CTRL_REG_BASE + 0xc)
#define RTL930X_GPIO_PABCD_ISR (RTL930X_GPIO_CTRL_REG_BASE + 0x10)
#define RTL930X_GPIO_PAB_IMR (RTL930X_GPIO_CTRL_REG_BASE + 0x14)
#define RTL930X_GPIO_PCD_IMR (RTL930X_GPIO_CTRL_REG_BASE + 0x18)
#define RTL838X_MODEL_NAME_INFO (0x00D4)
#define RTL839X_MODEL_NAME_INFO (0x0FF0)
#define RTL93XX_MODEL_NAME_INFO (0x0004)
#define RTL931X_CHIP_INFO_ADDR (0x0008)
#define RTL838X_LED_GLB_CTRL (0xA000)
#define RTL839X_LED_GLB_CTRL (0x00E4)
#define RTL9302_LED_GLB_CTRL (0xcc00)
#define RTL930X_LED_GLB_CTRL (0xCC00)
#define RTL931X_LED_GLB_CTRL (0x0600)
#define RTL838X_EXT_GPIO_DIR (0xA08C)
#define RTL839X_EXT_GPIO_DIR (0x0214)
#define RTL838X_EXT_GPIO_DATA (0xA094)
#define RTL839X_EXT_GPIO_DATA (0x021c)
#define RTL838X_EXT_GPIO_INDRT_ACCESS (0xA09C)
#define RTL839X_EXT_GPIO_INDRT_ACCESS (0x0224)
#define RTL838X_EXTRA_GPIO_CTRL (0xA0E0)
#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 RTL838X_RST_GLB_CTRL_0 (0x003c)
#define RTL838X_RST_GLB_CTRL_1 (0x0040)
#define RTL839X_RST_GLB_CTRL (0x0014)
#define RTL930X_RST_GLB_CTRL_0 (0x000c)
#define RTL931X_RST_GLB_CTRL (0x0400)
/* 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 RTL839X_LED_SW_CTRL (0xA00C)
#define RTL838X_LED_SW_P_EN_CTRL (0xA010)
#define RTL839X_LED_SW_P_EN_CTRL (0x012C)
#define RTL838X_LED0_SW_P_EN_CTRL (0xA010)
#define RTL839X_LED0_SW_P_EN_CTRL (0x012C)
#define RTL838X_LED1_SW_P_EN_CTRL (0xA014)
#define RTL839X_LED1_SW_P_EN_CTRL (0x0130)
#define RTL838X_LED2_SW_P_EN_CTRL (0xA018)
#define RTL839X_LED2_SW_P_EN_CTRL (0x0134)
#define RTL838X_LED_SW_P_CTRL (0xA01C)
#define RTL838X_LED_SW_P_CTRL_PORT(p) (RTL838X_LED_SW_P_CTRL + (((p) << 2)))
#define RTL839X_LED_SW_P_CTRL (0x0144)
#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 (0x03E4)
#define RTL839X_PHYREG_DATA_CTRL (0x03F0)
#define RTL839X_PHYREG_MMD_CTRL (0x3F4)
#define RTL930X_SMI_GLB_CTRL (0xCA00)
#define RTL930X_SMI_POLL_CTRL (0xca90)
#define RTL930X_SMI_PORT0_15_POLLING_SEL (0xCA08)
#define RTL930X_SMI_PORT16_27_POLLING_SEL (0xCA0C)
#define RTL930X_SMI_PORT0_5_ADDR (0xCB80)
#define RTL930X_SMI_ACCESS_PHY_CTRL_0 (0xCB70)
#define RTL930X_SMI_ACCESS_PHY_CTRL_1 (0xCB74)
#define RTL930X_SMI_ACCESS_PHY_CTRL_2 (0xCB78)
#define RTL930X_SMI_ACCESS_PHY_CTRL_3 (0xCB7C)
#define RTL931X_SMI_GLB_CTRL1 (0x0CBC)
#define RTL931X_SMI_GLB_CTRL0 (0x0CC0)
#define RTL931X_SMI_PORT_POLLING_CTRL (0x0CCC)
#define RTL931X_SMI_PORT_ADDR (0x0C74)
#define RTL931X_SMI_PORT_POLLING_SEL (0x0C9C)
#define RTL9310_SMI_PORT_POLLING_CTRL (0x0CCC)
#define RTL931X_SMI_INDRT_ACCESS_CTRL_0 (0x0C00)
#define RTL931X_SMI_INDRT_ACCESS_CTRL_1 (0x0C04)
#define RTL931X_SMI_INDRT_ACCESS_CTRL_2 (0x0C08)
#define RTL931X_SMI_INDRT_ACCESS_CTRL_3 (0x0C10)
#define RTL931X_SMI_INDRT_ACCESS_BC_PHYID_CTRL (0x0C14)
#define RTL931X_SMI_INDRT_ACCESS_MMD_CTRL (0xC18)
#define RTL931X_MAC_L2_GLOBAL_CTRL2 (0x1358)
#define RTL931X_MAC_L2_GLOBAL_CTRL1 (0x5548)
/* 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)
#define RTL930X_IMR_GLB (0xC628)
#define RTL930X_IMR_PORT_LINK_STS_CHG (0xC62C)
#define RTL930X_ISR_GLB (0xC658)
#define RTL930X_ISR_PORT_LINK_STS_CHG (0xC660)
/* IMR_GLB does not exit on RTL931X */
#define RTL931X_IMR_PORT_LINK_STS_CHG (0x126C)
#define RTL931X_ISR_GLB_SRC (0x12B4)
#define RTL931X_ISR_PORT_LINK_STS_CHG (0x12B8)
/* 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)
#define RTL9300_FAMILY_ID (0x9300)
#define RTL9310_FAMILY_ID (0x9310)
/* SPI Support */
#define RTL931X_SPI_CTRL0 (0x103C)
/* Basic SoC Features */
#define RTL838X_CPU_PORT 28
#define RTL839X_CPU_PORT 52
#define RTL930X_CPU_PORT 28
#define RTL931X_CPU_PORT 56
struct rtl83xx_soc_info {
unsigned char *name;
unsigned int id;
unsigned int family;
unsigned char *compatible;
volatile void *sw_base;
volatile void *icu_base;
int cpu_port;
};
/* rtl83xx-related functions used across subsystems */
int rtl838x_smi_wait_op(int timeout);
int rtl838x_read_phy(u32 port, u32 page, u32 reg, u32 *val);
int rtl838x_write_phy(u32 port, u32 page, u32 reg, u32 val);
int rtl839x_read_phy(u32 port, u32 page, u32 reg, u32 *val);
int rtl839x_write_phy(u32 port, u32 page, u32 reg, u32 val);
int rtl930x_read_phy(u32 port, u32 page, u32 reg, u32 *val);
int rtl930x_write_phy(u32 port, u32 page, u32 reg, u32 val);
int rtl931x_read_phy(u32 port, u32 page, u32 reg, u32 *val);
int rtl931x_write_phy(u32 port, u32 page, u32 reg, u32 val);
#endif /* _MACH_RTL838X_H_ */

View File

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

View File

@ -0,0 +1,5 @@
#
# Realtek RTL838x SoCs
#
cflags-$(CONFIG_RTL83XX) += -I$(srctree)/arch/mips/include/asm/mach-rtl838x/
load-$(CONFIG_RTL83XX) += 0xffffffff80100000

View File

@ -0,0 +1,212 @@
// 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 <asm/fw/fw.h>
#include <asm/smp-ops.h>
#include <asm/mips-cps.h>
#include <mach-rtl83xx.h>
extern char arcs_cmdline[];
struct rtl83xx_soc_info soc_info;
const void *fdt;
#ifdef CONFIG_MIPS_MT_SMP
extern const struct plat_smp_ops vsmp_smp_ops;
static struct plat_smp_ops rtl_smp_ops;
static void rtl_init_secondary(void)
{
#ifndef CONFIG_CEVT_R4K
/*
* These devices are low on resources. There might be the chance that CEVT_R4K
* is not enabled in kernel build. Nevertheless the timer and interrupt 7 might
* be active by default after startup of secondary VPE. With no registered
* handler that leads to continuous unhandeled interrupts. In this case disable
* counting (DC) in the core and confirm a pending interrupt.
*/
write_c0_cause(read_c0_cause() | CAUSEF_DC);
write_c0_compare(0);
#endif /* CONFIG_CEVT_R4K */
/*
* Enable all CPU interrupts, as everything is managed by the external
* controller. TODO: Standard vsmp_init_secondary() has special treatment for
* Malta if external GIC is available. Maybe we need this too.
*/
if (mips_gic_present())
pr_warn("%s: GIC present. Maybe interrupt enabling required.\n", __func__);
else
set_c0_status(ST0_IM);
}
#endif /* CONFIG_MIPS_MT_SMP */
const char *get_system_type(void)
{
return soc_info.name;
}
void __init prom_free_prom_memory(void)
{
}
void __init device_tree_init(void)
{
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();
}
void __init identify_rtl9302(void)
{
switch (sw_r32(RTL93XX_MODEL_NAME_INFO) & 0xfffffff0) {
case 0x93020810:
soc_info.name = "RTL9302A 12x2.5G";
break;
case 0x93021010:
soc_info.name = "RTL9302B 8x2.5G";
break;
case 0x93021810:
soc_info.name = "RTL9302C 16x2.5G";
break;
case 0x93022010:
soc_info.name = "RTL9302D 24x2.5G";
break;
case 0x93020800:
soc_info.name = "RTL9302A";
break;
case 0x93021000:
soc_info.name = "RTL9302B";
break;
case 0x93021800:
soc_info.name = "RTL9302C";
break;
case 0x93022000:
soc_info.name = "RTL9302D";
break;
case 0x93023001:
soc_info.name = "RTL9302F";
break;
default:
soc_info.name = "RTL9302";
}
}
void __init prom_init(void)
{
uint32_t model;
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;
}
if ((model & 0x8390) != 0x8380 && (model & 0x8390) != 0x8390) {
model = sw_r32(RTL93XX_MODEL_NAME_INFO);
pr_info("RTL93XX 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;
case 0x9301:
soc_info.name = "RTL9301";
soc_info.family = RTL9300_FAMILY_ID;
break;
case 0x9302:
identify_rtl9302();
soc_info.family = RTL9300_FAMILY_ID;
break;
case 0x9303:
soc_info.name = "RTL9303";
soc_info.family = RTL9300_FAMILY_ID;
break;
case 0x9313:
soc_info.name = "RTL9313";
soc_info.family = RTL9310_FAMILY_ID;
break;
default:
soc_info.name = "DEFAULT";
soc_info.family = 0;
}
pr_info("SoC Type: %s\n", get_system_type());
fw_init_cmdline();
mips_cpc_probe();
if (!register_cps_smp_ops())
return;
#ifdef CONFIG_MIPS_MT_SMP
if (cpu_has_mipsmt) {
rtl_smp_ops = vsmp_smp_ops;
rtl_smp_ops.init_secondary = rtl_init_secondary;
register_smp_ops(&rtl_smp_ops);
return;
}
#endif
register_up_smp_ops();
}

View File

@ -0,0 +1,102 @@
// 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/clkdev.h>
#include <linux/clk-provider.h>
#include <linux/clk.h>
#include <linux/delay.h>
#include <linux/of_fdt.h>
#include <linux/irqchip.h>
#include <asm/addrspace.h>
#include <asm/io.h>
#include <asm/bootinfo.h>
#include <asm/time.h>
#include <asm/prom.h>
#include <asm/smp-ops.h>
#include "mach-rtl83xx.h"
extern struct rtl83xx_soc_info soc_info;
void __init plat_mem_setup(void)
{
void *dtb;
set_io_port_base(KSEG1);
dtb = get_fdt();
if (!dtb)
panic("no dtb found");
/*
* Load the devicetree. This causes the chosen node to be
* parsed resulting in our memory appearing
*/
__dt_setup_arch(dtb);
}
void plat_time_init_fallback(void)
{
struct device_node *np;
u32 freq = 500000000;
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: %dMHz", freq / 1000000);
of_node_put(np);
}
mips_hpt_frequency = freq / 2;
}
void __init plat_time_init(void)
{
/*
* Initialization routine resembles generic MIPS plat_time_init() with
* lazy error handling. The final fallback is only needed until we have
* converted all device trees to new clock syntax.
*/
struct device_node *np;
struct clk *clk;
of_clk_init(NULL);
mips_hpt_frequency = 0;
np = of_get_cpu_node(0, NULL);
if (!np) {
pr_err("Failed to get CPU node\n");
} else {
clk = of_clk_get(np, 0);
if (IS_ERR(clk)) {
pr_err("Failed to get CPU clock: %ld\n", PTR_ERR(clk));
} else {
mips_hpt_frequency = clk_get_rate(clk) / 2;
clk_put(clk);
}
}
if (!mips_hpt_frequency)
plat_time_init_fallback();
timer_probe();
}
void __init arch_init_irq(void)
{
irqchip_init();
}

View File

@ -0,0 +1,19 @@
# SPDX-License-Identifier: GPL-2.0-only
menuconfig COMMON_CLK_REALTEK
bool "Support for Realtek's clock controllers"
depends on RTL83XX
if COMMON_CLK_REALTEK
config COMMON_CLK_RTL83XX
bool "Clock driver for Realtek RTL83XX"
depends on RTL83XX
select SRAM
help
This driver adds support for the Realtek RTL83xx series basic clocks.
This includes chips in the RTL838x series, such as RTL8380, RTL8381,
RTL832, as well as chips from the RTL839x series, such as RTL8390,
RT8391, RTL8392, RTL8393 and RTL8396.
endif

View File

@ -0,0 +1,2 @@
# SPDX-License-Identifier: GPL-2.0-only
obj-$(CONFIG_COMMON_CLK_RTL83XX) += clk-rtl83xx.o clk-rtl838x-sram.o clk-rtl839x-sram.o

View File

@ -0,0 +1,149 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Realtek RTL838X SRAM clock setters
* Copyright (C) 2022 Markus Stockhausen <markus.stockhausen@gmx.de>
*/
#include <dt-bindings/clock/rtl83xx-clk.h>
#include "clk-rtl83xx.h"
#define rGLB $t0
#define rCTR $t1
#define rMSK $t2
#define rSLP $t3
#define rTMP $t4
.set noreorder
.globl rtcl_838x_dram_start
rtcl_838x_dram_start:
/*
* Functions start here and should avoid access to normal memory. REMARK! Do not forget about
* stack pointer and dirty caches that might interfere.
*/
.globl rtcl_838x_dram_set_rate
.ent rtcl_838x_dram_set_rate
rtcl_838x_dram_set_rate:
#ifdef CONFIG_RTL838X
li rCTR, RTL_SW_CORE_BASE
addiu rGLB, rCTR, RTL838X_PLL_GLB_CTRL
ori rTMP, $0, CLK_CPU
beq $a0, rTMP, pre_cpu
ori rTMP, $0, CLK_MEM
beq $a0, rTMP, pre_mem
nop
pre_lxb:
ori rSLP, $0, RTL838X_GLB_CTRL_LXB_PLL_READY_MASK
addiu rCTR, rCTR, RTL838X_PLL_LXB_CTRL0
b main_set
ori rMSK, $0, RTL838X_GLB_CTRL_EN_LXB_PLL_MASK
pre_mem:
/* simple 64K data cache flush to avoid unexpected memory access */
li rMSK, RTL_SRAM_BASE
li rTMP, 2048
pre_flush:
lw $0, 0(rMSK)
addiu rMSK, rMSK, 32
addiu rTMP, rTMP, -1
bne rTMP, $0, pre_flush
lw $0, -4(rMSK)
ori rSLP, $0, RTL838X_GLB_CTRL_MEM_PLL_READY_MASK
addiu rCTR, rCTR, RTL838X_PLL_MEM_CTRL0
b main_set
ori rMSK, $0, RTL838X_GLB_CTRL_EN_MEM_PLL_MASK
pre_cpu:
/* switch CPU to LXB clock */
ori rMSK, $0, RTL838X_GLB_CTRL_CPU_PLL_SC_MUX_MASK
nor rMSK, rMSK, $0
sync
lw rTMP, 0(rGLB)
and rTMP, rTMP, rMSK
sw rTMP, 0(rGLB)
sync
ori rSLP, $0, RTL838X_GLB_CTRL_CPU_PLL_READY_MASK
addiu rCTR, rCTR, RTL838X_PLL_CPU_CTRL0
ori rMSK, $0, RTL838X_GLB_CTRL_EN_CPU_PLL_MASK
main_set:
/* disable PLL */
nor rMSK, rMSK, 0
sync
lw rTMP, 0(rGLB)
sync
and rTMP, rTMP, rMSK
sync
sw rTMP, 0(rGLB)
/* set new PLL values */
sync
sw $a1, 0(rCTR)
sw $a2, 4(rCTR)
sync
/* enable PLL (will reset it and clear ready status) */
nor rMSK, rMSK, 0
sync
lw rTMP, 0(rGLB)
sync
or rTMP, rTMP, rMSK
sync
sw rTMP, 0(rGLB)
/* wait for PLL to become ready */
wait_ready:
lw rTMP, 0(rGLB)
and rTMP, rTMP, rSLP
bne rTMP, $0, wait_ready
sync
/* branch to post processing */
ori rTMP, $0, CLK_CPU
beq $a0, rTMP, post_cpu
ori rTMP, $0, CLK_MEM
beq $a0, rTMP, post_mem
nop
post_lxb:
jr $ra
nop
post_mem:
jr $ra
nop
post_cpu:
/* stabilize clock to avoid crash, empirically determined */
ori rSLP, $0, 0x3000
wait_cpu:
bnez rSLP, wait_cpu
addiu rSLP, rSLP, -1
/* switch CPU to PLL clock */
ori rMSK, $0, RTL838X_GLB_CTRL_CPU_PLL_SC_MUX_MASK
sync
lw rTMP, 0(rGLB)
or rTMP, rTMP, rMSK
sw rTMP, 0(rGLB)
sync
jr $ra
nop
#else /* !CONFIG_RTL838X */
jr $ra
nop
#endif
.end rtcl_838x_dram_set_rate
/*
* End marker. Do not delete.
*/
.word RTL_SRAM_MARKER
.globl rtcl_838x_dram_size
rtcl_838x_dram_size:
.word .-rtcl_838x_dram_start

View File

@ -0,0 +1,141 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Realtek RTL839X SRAM clock setters
* Copyright (C) 2022 Markus Stockhausen <markus.stockhausen@gmx.de>
*/
#include <asm/mipsregs.h>
#include <dt-bindings/clock/rtl83xx-clk.h>
#include "clk-rtl83xx.h"
#define rGLB $t0
#define rCTR $t1
#define rMSK $t2
#define rSLP1 $t3
#define rSLP2 $t4
#define rSLP3 $t5
#define rTMP $t6
#define rCP0 $t7
.set noreorder
.globl rtcl_839x_dram_start
rtcl_839x_dram_start:
/*
* Functions start here and should avoid access to normal memory. REMARK! Do not forget about
* stack pointer and dirty caches that might interfere.
*/
.globl rtcl_839x_dram_set_rate
.ent rtcl_839x_dram_set_rate
rtcl_839x_dram_set_rate:
#ifdef CONFIG_RTL839X
/* disable MIPS 34K branch and return prediction */
mfc0 rCP0, CP0_CONFIG, 7
ori rTMP, rCP0, 0xc
mtc0 rTMP, CP0_CONFIG, 7
li rCTR, RTL_SW_CORE_BASE
addiu rGLB, rCTR, RTL839X_PLL_GLB_CTRL
ori rTMP, $0, CLK_CPU
beq $a0, rTMP, pre_cpu
ori rTMP, $0, CLK_MEM
beq $a0, rTMP, pre_mem
nop
pre_lxb:
li rSLP1, 0x400000
li rSLP2, 0x400000
li rSLP3, 0x400000
addiu rCTR, rCTR, RTL839X_PLL_LXB_CTRL0
b main_set
ori rMSK, $0, RTL839X_GLB_CTRL_LXB_CLKSEL_MASK
pre_mem:
/* try to avoid memory access with simple 64K data cache flush */
li rMSK, RTL_SRAM_BASE
li rTMP, 2048
pre_flush:
lw $0, 0(rMSK)
addiu rMSK, rMSK, 32
addiu rTMP, rTMP, -1
bne rTMP, $0, pre_flush
lw $0, -4(rMSK)
li rSLP1, 0x10000
li rSLP2, 0x10000
li rSLP3, 0x10000
addiu rCTR, rCTR, RTL839X_PLL_MEM_CTRL0
b main_set
ori rMSK, $0, RTL839X_GLB_CTRL_MEM_CLKSEL_MASK
pre_cpu:
li rSLP1, 0x1000
li rSLP2, 0x1000
li rSLP3, 0x200
addiu rCTR, rCTR, RTL839X_PLL_CPU_CTRL0
ori rMSK, $0, RTL839X_GLB_CTRL_CPU_CLKSEL_MASK
main_set:
/* switch to fixed clock */
sync
lw rTMP, 0(rGLB)
sync
or rTMP, rTMP, rMSK
sync
sw rTMP, 0(rGLB)
/* wait until fixed clock in use */
or rTMP, rSLP1, $0
wait_fixclock:
bnez rTMP, wait_fixclock
addiu rTMP, rTMP, -1
/* set new PLL values */
sync
sw $a1, 0(rCTR)
sw $a2, 4(rCTR)
sync
/* wait for value takeover */
or rTMP, rSLP2, $0
wait_pll:
bnez rTMP, wait_pll
addiu rTMP, rTMP, -1
/* switch back to PLL clock*/
nor rMSK, rMSK, $0
sync
lw rTMP, 0(rGLB)
sync
and rTMP, rTMP, rMSK
sync
sw rTMP, 0(rGLB)
/* wait until PLL clock in use */
or rTMP, rSLP3, $0
wait_pllclock:
bnez rTMP, wait_pllclock
addiu rTMP, rTMP, -1
/* restore branch prediction */
mtc0 rCP0, CP0_CONFIG, 7
jr $ra
nop
#else /* !CONFIG_RTL839X */
jr $ra
nop
#endif
.end rtcl_839x_dram_set_rate
/*
* End marker. Do not delete.
*/
.word RTL_SRAM_MARKER
.globl rtcl_839x_dram_size
rtcl_839x_dram_size:
.word .-rtcl_839x_dram_start

View File

@ -0,0 +1,770 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Realtek RTL83XX clock driver
* Copyright (C) 2022 Markus Stockhausen <markus.stockhausen@gmx.de>
*
* This driver provides basic clock support for the central core clock unit (CCU) and its PLLs
* inside the RTL838X and RTL8389X SOC. Currently CPU, memory and LXB clock information can be
* accessed. To make use of the driver add the following devices and configurations at the
* appropriate locations to the DT.
*
* #include <dt-bindings/clock/rtl83xx-clk.h>
*
* sram0: sram@9f000000 {
* compatible = "mmio-sram";
* reg = <0x9f000000 0x18000>;
* #address-cells = <1>;
* #size-cells = <1>;
* ranges = <0 0x9f000000 0x18000>;
* };
*
* osc: oscillator {
* compatible = "fixed-clock";
* #clock-cells = <0>;
* clock-frequency = <25000000>;
* };
*
* ccu: clock-controller {
* compatible = "realtek,rtl8380-clock";
* #clock-cells = <1>;
* clocks = <&osc>;
* clock-names = "ref_clk";
* };
*
*
* The SRAM part is needed to be able to set clocks. When changing clocks the code must not run
* from DRAM. Otherwise system might freeze. Take care to adjust CCU compatibility, SRAM address
* and size to the target SOC device. Afterwards one can access/identify the clocks in the other
* DT devices with <&ccu CLK_CPU>, <&ccu CLK_MEM> or <&ccu CLK_LXB>. Additionally the clocks can
* be used inside the kernel with
*
* cpu_clk = clk_get(NULL, "cpu_clk");
* mem_clk = clk_get(NULL, "mem_clk");
* lxb_clk = clk_get(NULL, "lxb_clk");
*
* This driver can be directly used by the DT based cpufreq driver (CONFIG_CPUFREQ_DT) if CPU
* references the right clock and sane operating points (OPP) are provided. E.g.
*
* cpu@0 {
* compatible = "mips,mips4KEc";
* reg = <0>;
* clocks = <&ccu CLK_CPU>;
* operating-points-v2 = <&cpu_opp_table>;
* };
*
* cpu_opp_table: opp-table-0 {
* compatible = "operating-points-v2";
* opp-shared;
* opp00 {
* opp-hz = /bits/ 64 <425000000>;
* };
* ...
* }
*/
#include <asm/cacheflush.h>
#include <asm/mipsmtregs.h>
#include <dt-bindings/clock/rtl83xx-clk.h>
#include <linux/clk.h>
#include <linux/clk-provider.h>
#include <linux/clkdev.h>
#include <linux/cpu.h>
#include <linux/delay.h>
#include <linux/genalloc.h>
#include <linux/io.h>
#include <linux/ioport.h>
#include <linux/of_address.h>
#include <linux/of_platform.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
#include "clk-rtl83xx.h"
#define read_sw(reg) ioread32(((void *)RTL_SW_CORE_BASE) + reg)
#define read_soc(reg) ioread32(((void *)RTL_SOC_BASE) + reg)
#define write_sw(val, reg) iowrite32(val, ((void *)RTL_SW_CORE_BASE) + reg)
#define write_soc(val, reg) iowrite32(val, ((void *)RTL_SOC_BASE) + reg)
/*
* some hardware specific definitions
*/
#define SOC_RTL838X 0
#define SOC_RTL839X 1
#define SOC_COUNT 2
#define MEM_DDR1 1
#define MEM_DDR2 2
#define MEM_DDR3 3
#define REG_CTRL0 0
#define REG_CTRL1 1
#define REG_COUNT 2
#define OSC_RATE 25000000
static const int rtcl_regs[SOC_COUNT][REG_COUNT][CLK_COUNT] = {
{
{ RTL838X_PLL_CPU_CTRL0, RTL838X_PLL_MEM_CTRL0, RTL838X_PLL_LXB_CTRL0 },
{ RTL838X_PLL_CPU_CTRL1, RTL838X_PLL_MEM_CTRL1, RTL838X_PLL_LXB_CTRL1 },
}, {
{ RTL839X_PLL_CPU_CTRL0, RTL839X_PLL_MEM_CTRL0, RTL839X_PLL_LXB_CTRL0 },
{ RTL839X_PLL_CPU_CTRL1, RTL839X_PLL_MEM_CTRL1, RTL839X_PLL_LXB_CTRL1 },
}
};
#define RTCL_REG_SET(_rate, _ctrl0, _ctrl1) \
{ \
.rate = _rate, \
.ctrl0 = _ctrl0, \
.ctrl1 = _ctrl1, \
}
struct rtcl_reg_set {
unsigned int rate;
unsigned int ctrl0;
unsigned int ctrl1;
};
/*
* The following configuration tables are valid operation points for their
* corresponding PLLs. The magic numbers are precalculated mulitpliers and
* dividers to keep the driver simple. They also provide rates outside the
* allowed physical specifications. E.g. DDR3 memory has a lower limit of 303
* MHz or the CPU might get unstable if set to anything above its startup
* frequency. Additionally the Realtek SOCs tend to expect CPU speed larger
* than MEM speed larger than LXB speed. The caller or DT configuration must
* take care that only valid operating points are selected.
*/
static const struct rtcl_reg_set rtcl_838x_cpu_reg_set[] = {
RTCL_REG_SET(300000000, 0x045c8, 0x1414530e),
RTCL_REG_SET(325000000, 0x04648, 0x1414530e),
RTCL_REG_SET(350000000, 0x046c8, 0x1414530e),
RTCL_REG_SET(375000000, 0x04748, 0x1414530e),
RTCL_REG_SET(400000000, 0x045c8, 0x0c14530e),
RTCL_REG_SET(425000000, 0x04628, 0x0c14530e),
RTCL_REG_SET(450000000, 0x04688, 0x0c14530e),
RTCL_REG_SET(475000000, 0x046e8, 0x0c14530e),
RTCL_REG_SET(500000000, 0x04748, 0x0c14530e),
RTCL_REG_SET(525000000, 0x047a8, 0x0c14530e),
RTCL_REG_SET(550000000, 0x04808, 0x0c14530e),
RTCL_REG_SET(575000000, 0x04868, 0x0c14530e),
RTCL_REG_SET(600000000, 0x048c8, 0x0c14530e),
RTCL_REG_SET(625000000, 0x04928, 0x0c14530e)
};
static const struct rtcl_reg_set rtcl_838x_mem_reg_set[] = {
RTCL_REG_SET(200000000, 0x041bc, 0x14018C80),
RTCL_REG_SET(225000000, 0x0417c, 0x0c018C80),
RTCL_REG_SET(250000000, 0x041ac, 0x0c018C80),
RTCL_REG_SET(275000000, 0x0412c, 0x04018C80),
RTCL_REG_SET(300000000, 0x0414c, 0x04018c80),
RTCL_REG_SET(325000000, 0x0416c, 0x04018c80),
RTCL_REG_SET(350000000, 0x0418c, 0x04018c80),
RTCL_REG_SET(375000000, 0x041ac, 0x04018c80)
};
static const struct rtcl_reg_set rtcl_838x_lxb_reg_set[] = {
RTCL_REG_SET(100000000, 0x043c8, 0x001ad30e),
RTCL_REG_SET(125000000, 0x043c8, 0x001ad30e),
RTCL_REG_SET(150000000, 0x04508, 0x1c1ad30e),
RTCL_REG_SET(175000000, 0x04508, 0x1c1ad30e),
RTCL_REG_SET(200000000, 0x047c8, 0x001ad30e)
};
static const struct rtcl_reg_set rtcl_839x_cpu_reg_set[] = {
RTCL_REG_SET(400000000, 0x0414c, 0x00000005),
RTCL_REG_SET(425000000, 0x041ec, 0x00000006),
RTCL_REG_SET(450000000, 0x0417c, 0x00000005),
RTCL_REG_SET(475000000, 0x0422c, 0x00000006),
RTCL_REG_SET(500000000, 0x041ac, 0x00000005),
RTCL_REG_SET(525000000, 0x0426c, 0x00000006),
RTCL_REG_SET(550000000, 0x0412c, 0x00000004),
RTCL_REG_SET(575000000, 0x042ac, 0x00000006),
RTCL_REG_SET(600000000, 0x0414c, 0x00000004),
RTCL_REG_SET(625000000, 0x042ec, 0x00000006),
RTCL_REG_SET(650000000, 0x0416c, 0x00000004),
RTCL_REG_SET(675000000, 0x04324, 0x00000006),
RTCL_REG_SET(700000000, 0x0418c, 0x00000004),
RTCL_REG_SET(725000000, 0x0436c, 0x00000006),
RTCL_REG_SET(750000000, 0x0438c, 0x00000006),
RTCL_REG_SET(775000000, 0x043ac, 0x00000006),
RTCL_REG_SET(800000000, 0x043cc, 0x00000006),
RTCL_REG_SET(825000000, 0x043ec, 0x00000006),
RTCL_REG_SET(850000000, 0x0440c, 0x00000006)
};
static const struct rtcl_reg_set rtcl_839x_mem_reg_set[] = {
RTCL_REG_SET(100000000, 0x041cc, 0x00000000),
RTCL_REG_SET(125000000, 0x041ac, 0x00000007),
RTCL_REG_SET(150000000, 0x0414c, 0x00000006),
RTCL_REG_SET(175000000, 0x0418c, 0x00000006),
RTCL_REG_SET(200000000, 0x041cc, 0x00000006),
RTCL_REG_SET(225000000, 0x0417c, 0x00000005),
RTCL_REG_SET(250000000, 0x041ac, 0x00000005),
RTCL_REG_SET(275000000, 0x0412c, 0x00000004),
RTCL_REG_SET(300000000, 0x0414c, 0x00000004),
RTCL_REG_SET(325000000, 0x0416c, 0x00000004),
RTCL_REG_SET(350000000, 0x0418c, 0x00000004),
RTCL_REG_SET(375000000, 0x041ac, 0x00000004),
RTCL_REG_SET(400000000, 0x041cc, 0x00000004)
};
static const struct rtcl_reg_set rtcl_839x_lxb_reg_set[] = {
RTCL_REG_SET(50000000, 0x1414c, 0x00000003),
RTCL_REG_SET(100000000, 0x0814c, 0x00000003),
RTCL_REG_SET(150000000, 0x0414c, 0x00000003),
RTCL_REG_SET(200000000, 0x0414c, 0x00000007)
};
struct rtcl_rtab_set {
int count;
const struct rtcl_reg_set *rset;
};
#define RTCL_RTAB_SET(_rset) \
{ \
.count = ARRAY_SIZE(_rset), \
.rset = _rset, \
}
static const struct rtcl_rtab_set rtcl_rtab_set[SOC_COUNT][CLK_COUNT] = {
{
RTCL_RTAB_SET(rtcl_838x_cpu_reg_set),
RTCL_RTAB_SET(rtcl_838x_mem_reg_set),
RTCL_RTAB_SET(rtcl_838x_lxb_reg_set)
}, {
RTCL_RTAB_SET(rtcl_839x_cpu_reg_set),
RTCL_RTAB_SET(rtcl_839x_mem_reg_set),
RTCL_RTAB_SET(rtcl_839x_lxb_reg_set)
}
};
#define RTCL_ROUND_SET(_min, _max, _step) \
{ \
.min = _min, \
.max = _max, \
.step = _step, \
}
struct rtcl_round_set {
unsigned long min;
unsigned long max;
unsigned long step;
};
static const struct rtcl_round_set rtcl_round_set[SOC_COUNT][CLK_COUNT] = {
{
RTCL_ROUND_SET(300000000, 625000000, 25000000),
RTCL_ROUND_SET(200000000, 375000000, 25000000),
RTCL_ROUND_SET(100000000, 200000000, 25000000)
}, {
RTCL_ROUND_SET(400000000, 850000000, 25000000),
RTCL_ROUND_SET(100000000, 400000000, 25000000),
RTCL_ROUND_SET(50000000, 200000000, 50000000)
}
};
static const int rtcl_divn3[] = { 2, 3, 4, 6 };
static const int rtcl_xdiv[] = { 2, 4, 2 };
/*
* module data structures
*/
#define RTCL_CLK_INFO(_idx, _name, _pname, _dname) \
{ \
.idx = _idx, \
.name = _name, \
.parent_name = _pname, \
.display_name = _dname, \
}
struct rtcl_clk_info {
unsigned int idx;
const char *name;
const char *parent_name;
const char *display_name;
};
struct rtcl_clk {
struct clk_hw hw;
unsigned int idx;
unsigned long min;
unsigned long max;
unsigned long rate;
unsigned long startup;
};
static const struct rtcl_clk_info rtcl_clk_info[CLK_COUNT] = {
RTCL_CLK_INFO(CLK_CPU, "cpu_clk", "ref_clk", "CPU"),
RTCL_CLK_INFO(CLK_MEM, "mem_clk", "ref_clk", "MEM"),
RTCL_CLK_INFO(CLK_LXB, "lxb_clk", "ref_clk", "LXB")
};
struct rtcl_dram {
int type;
int buswidth;
};
struct rtcl_sram {
int *pmark;
unsigned long vbase;
};
struct rtcl_ccu {
spinlock_t lock;
unsigned int soc;
struct rtcl_sram sram;
struct rtcl_dram dram;
struct device_node *np;
struct platform_device *pdev;
struct rtcl_clk clks[CLK_COUNT];
};
struct rtcl_ccu *rtcl_ccu;
#define rtcl_hw_to_clk(_hw) container_of(_hw, struct rtcl_clk, hw)
/*
* SRAM relocatable assembler functions. The dram() parts point to normal kernel
* memory while the sram() parts are the same functions but relocated to SRAM.
*/
extern void rtcl_838x_dram_start(void);
extern int rtcl_838x_dram_size;
extern void (*rtcl_838x_dram_set_rate)(int clk_idx, int ctrl0, int ctrl1);
static void (*rtcl_838x_sram_set_rate)(int clk_idx, int ctrl0, int ctrl1);
extern void rtcl_839x_dram_start(void);
extern int rtcl_839x_dram_size;
extern void (*rtcl_839x_dram_set_rate)(int clk_idx, int ctrl0, int ctrl1);
static void (*rtcl_839x_sram_set_rate)(int clk_idx, int ctrl0, int ctrl1);
/*
* clock setter/getter functions
*/
static unsigned long rtcl_recalc_rate(struct clk_hw *hw, unsigned long parent_rate)
{
struct rtcl_clk *clk = rtcl_hw_to_clk(hw);
unsigned int ctrl0, ctrl1, div1, div2, cmu_ncode_in;
unsigned int cmu_sel_prediv, cmu_sel_div4, cmu_divn2, cmu_divn2_selb, cmu_divn3_sel;
if ((clk->idx >= CLK_COUNT) || (!rtcl_ccu) || (rtcl_ccu->soc >= SOC_COUNT))
return 0;
ctrl0 = read_sw(rtcl_regs[rtcl_ccu->soc][REG_CTRL0][clk->idx]);
ctrl1 = read_sw(rtcl_regs[rtcl_ccu->soc][REG_CTRL1][clk->idx]);
cmu_sel_prediv = 1 << RTL_PLL_CTRL0_CMU_SEL_PREDIV(ctrl0);
cmu_sel_div4 = RTL_PLL_CTRL0_CMU_SEL_DIV4(ctrl0) ? 4 : 1;
cmu_ncode_in = RTL_PLL_CTRL0_CMU_NCODE_IN(ctrl0) + 4;
cmu_divn2 = RTL_PLL_CTRL0_CMU_DIVN2(ctrl0) + 4;
switch (rtcl_ccu->soc) {
case SOC_RTL838X:
if ((ctrl0 == 0) && (ctrl1 == 0) && (clk->idx == CLK_LXB))
return 200000000;
cmu_divn2_selb = RTL838X_PLL_CTRL1_CMU_DIVN2_SELB(ctrl1);
cmu_divn3_sel = rtcl_divn3[RTL838X_PLL_CTRL1_CMU_DIVN3_SEL(ctrl1)];
break;
case SOC_RTL839X:
cmu_divn2_selb = RTL839X_PLL_CTRL1_CMU_DIVN2_SELB(ctrl1);
cmu_divn3_sel = rtcl_divn3[RTL839X_PLL_CTRL1_CMU_DIVN3_SEL(ctrl1)];
break;
}
div1 = cmu_divn2_selb ? cmu_divn3_sel : cmu_divn2;
div2 = rtcl_xdiv[clk->idx];
return (((parent_rate / 16) * cmu_ncode_in) / (div1 * div2)) *
cmu_sel_prediv * cmu_sel_div4 * 16;
}
static int rtcl_838x_set_rate(int clk_idx, const struct rtcl_reg_set *reg)
{
unsigned long irqflags;
/*
* Runtime of this function (including locking)
* CPU: up to 14000 cycles / up to 56 us at 250 MHz (half default speed)
*/
spin_lock_irqsave(&rtcl_ccu->lock, irqflags);
rtcl_838x_sram_set_rate(clk_idx, reg->ctrl0, reg->ctrl1);
spin_unlock_irqrestore(&rtcl_ccu->lock, irqflags);
return 0;
}
static int rtcl_839x_set_rate(int clk_idx, const struct rtcl_reg_set *reg)
{
unsigned long vpflags;
unsigned long irqflags;
/*
* Runtime of this function (including locking)
* CPU: up to 31000 cycles / up to 89 us at 350 MHz (half default speed)
*/
spin_lock_irqsave(&rtcl_ccu->lock, irqflags);
vpflags = dvpe();
rtcl_839x_sram_set_rate(clk_idx, reg->ctrl0, reg->ctrl1);
evpe(vpflags);
spin_unlock_irqrestore(&rtcl_ccu->lock, irqflags);
return 0;
}
static int rtcl_set_rate(struct clk_hw *hw, unsigned long rate, unsigned long parent_rate)
{
int tab_idx;
struct rtcl_clk *clk = rtcl_hw_to_clk(hw);
const struct rtcl_rtab_set *rtab = &rtcl_rtab_set[rtcl_ccu->soc][clk->idx];
const struct rtcl_round_set *round = &rtcl_round_set[rtcl_ccu->soc][clk->idx];
if ((parent_rate != OSC_RATE) || (!rtcl_ccu->sram.vbase))
return -EINVAL;
/*
* Currently we do not know if SRAM is stable on these devices. Maybe someone
* changes memory in this region and does not care about proper allocation. So
* check if something might go wrong.
*/
if (unlikely(*rtcl_ccu->sram.pmark != RTL_SRAM_MARKER)) {
dev_err(&rtcl_ccu->pdev->dev, "SRAM code lost\n");
return -EINVAL;
}
tab_idx = (rate - round->min) / round->step;
if ((tab_idx < 0) || (tab_idx >= rtab->count) || (rtab->rset[tab_idx].rate != rate))
return -EINVAL;
rtcl_ccu->clks[clk->idx].rate = rate;
switch (rtcl_ccu->soc) {
case SOC_RTL838X:
return rtcl_838x_set_rate(clk->idx, &rtab->rset[tab_idx]);
case SOC_RTL839X:
return rtcl_839x_set_rate(clk->idx, &rtab->rset[tab_idx]);
}
return -ENXIO;
}
static long rtcl_round_rate(struct clk_hw *hw, unsigned long rate, unsigned long *parent_rate)
{
struct rtcl_clk *clk = rtcl_hw_to_clk(hw);
unsigned long rrate = max(clk->min, min(clk->max, rate));
const struct rtcl_round_set *round = &rtcl_round_set[rtcl_ccu->soc][clk->idx];
rrate = ((rrate + (round->step >> 1)) / round->step) * round->step;
rrate -= (rrate > clk->max) ? round->step : 0;
rrate += (rrate < clk->min) ? round->step : 0;
return rrate;
}
/*
* Initialization functions to register the CCU and its clocks
*/
#define RTCL_SRAM_FUNC(SOC, PBASE, FN) ({ \
rtcl_##SOC##_sram_##FN = ((void *)&rtcl_##SOC##_dram_##FN - \
(void *)&rtcl_##SOC##_dram_start) + \
(void *)PBASE; })
static const struct clk_ops rtcl_clk_ops = {
.set_rate = rtcl_set_rate,
.round_rate = rtcl_round_rate,
.recalc_rate = rtcl_recalc_rate,
};
static int rtcl_ccu_create(struct device_node *np)
{
int soc;
if (of_device_is_compatible(np, "realtek,rtl8380-clock"))
soc = SOC_RTL838X;
else if (of_device_is_compatible(np, "realtek,rtl8390-clock"))
soc = SOC_RTL839X;
else
return -ENXIO;
rtcl_ccu = kzalloc(sizeof(*rtcl_ccu), GFP_KERNEL);
if (IS_ERR(rtcl_ccu))
return -ENOMEM;
rtcl_ccu->np = np;
rtcl_ccu->soc = soc;
rtcl_ccu->dram.type = RTL_MC_MCR_DRAMTYPE(read_soc(RTL_MC_MCR));
rtcl_ccu->dram.buswidth = RTL_MC_DCR_BUSWIDTH(read_soc(RTL_MC_DCR));
spin_lock_init(&rtcl_ccu->lock);
return 0;
}
int rtcl_register_clkhw(int clk_idx)
{
int ret;
struct clk *clk;
struct clk_init_data hw_init = { };
struct rtcl_clk *rclk = &rtcl_ccu->clks[clk_idx];
struct clk_parent_data parent_data = { .fw_name = rtcl_clk_info[clk_idx].parent_name };
rclk->idx = clk_idx;
rclk->hw.init = &hw_init;
hw_init.num_parents = 1;
hw_init.ops = &rtcl_clk_ops;
hw_init.parent_data = &parent_data;
hw_init.name = rtcl_clk_info[clk_idx].name;
ret = of_clk_hw_register(rtcl_ccu->np, &rclk->hw);
if (ret)
return ret;
clk_hw_register_clkdev(&rclk->hw, rtcl_clk_info[clk_idx].name, NULL);
clk = clk_get(NULL, rtcl_clk_info[clk_idx].name);
rclk->startup = clk_get_rate(clk);
clk_put(clk);
switch (clk_idx) {
case CLK_CPU:
rclk->min = rtcl_round_set[rtcl_ccu->soc][clk_idx].min;
rclk->max = rtcl_round_set[rtcl_ccu->soc][clk_idx].max;
break;
default:
/*
* TODO: This driver supports PLL reclocking and nothing else. Additional
* required steps for non CPU PLLs are missing. E.g. if we want to change memory
* clocks the right way we must adapt a lot of other settings. This includes
* MCR and DTRx timing registers (0xb80001000, 0xb8001008, ...) and a DLL reset
* so that hardware operates in the allowed limits. This is far too complex
* without official support. Avoid this for now.
*/
rclk->min = rclk->max = rclk->startup;
break;
}
return 0;
}
static struct clk_hw *rtcl_get_clkhw(struct of_phandle_args *clkspec, void *prv)
{
unsigned int idx = clkspec->args[0];
if (idx >= CLK_COUNT) {
pr_err("%s: Invalid index %u\n", __func__, idx);
return ERR_PTR(-EINVAL);
}
return &rtcl_ccu->clks[idx].hw;
}
static int rtcl_ccu_register_clocks(void)
{
int clk_idx, ret;
for (clk_idx = 0; clk_idx < CLK_COUNT; clk_idx++) {
ret = rtcl_register_clkhw(clk_idx);
if (ret) {
pr_err("%s: Couldn't register %s clock\n",
__func__, rtcl_clk_info[clk_idx].display_name);
goto err_hw_unregister;
}
}
ret = of_clk_add_hw_provider(rtcl_ccu->np, rtcl_get_clkhw, rtcl_ccu);
if (ret) {
pr_err("%s: Couldn't register clock provider of %s\n",
__func__, of_node_full_name(rtcl_ccu->np));
goto err_hw_unregister;
}
return 0;
err_hw_unregister:
for (--clk_idx; clk_idx >= 0; --clk_idx)
clk_hw_unregister(&rtcl_ccu->clks[clk_idx].hw);
return ret;
}
int rtcl_init_sram(void)
{
struct gen_pool *sram_pool;
phys_addr_t sram_pbase;
unsigned long sram_vbase;
struct device_node *node;
struct platform_device *pdev = NULL;
void *dram_start;
int dram_size;
const char *wrn = ", rate setting disabled.\n";
switch (rtcl_ccu->soc) {
case SOC_RTL838X:
dram_start = &rtcl_838x_dram_start;
dram_size = rtcl_838x_dram_size;
break;
case SOC_RTL839X:
dram_start = &rtcl_839x_dram_start;
dram_size = rtcl_839x_dram_size;
break;
default:
return -ENXIO;
}
for_each_compatible_node(node, NULL, "mmio-sram") {
pdev = of_find_device_by_node(node);
if (pdev) {
of_node_put(node);
break;
}
}
if (!pdev) {
dev_warn(&rtcl_ccu->pdev->dev, "no SRAM device found%s", wrn);
return -ENXIO;
}
sram_pool = gen_pool_get(&pdev->dev, NULL);
if (!sram_pool) {
dev_warn(&rtcl_ccu->pdev->dev, "SRAM pool unavailable%s", wrn);
goto err_put_device;
}
sram_vbase = gen_pool_alloc(sram_pool, dram_size);
if (!sram_vbase) {
dev_warn(&rtcl_ccu->pdev->dev, "can not allocate SRAM%s", wrn);
goto err_put_device;
}
sram_pbase = gen_pool_virt_to_phys(sram_pool, sram_vbase);
memcpy((void *)sram_pbase, dram_start, dram_size);
flush_icache_range((unsigned long)sram_pbase, (unsigned long)(sram_pbase + dram_size));
switch (rtcl_ccu->soc) {
case SOC_RTL838X:
RTCL_SRAM_FUNC(838x, sram_pbase, set_rate);
break;
case SOC_RTL839X:
RTCL_SRAM_FUNC(839x, sram_pbase, set_rate);
break;
}
rtcl_ccu->sram.pmark = (int *)((void *)sram_pbase + (dram_size - 4));
rtcl_ccu->sram.vbase = sram_vbase;
return 0;
err_put_device:
put_device(&pdev->dev);
return -ENXIO;
}
void rtcl_ccu_log_early(void)
{
char meminfo[80], clkinfo[255], msg[255] = "rtl83xx-clk: initialized";
sprintf(meminfo, " (%d Bit DDR%d)", rtcl_ccu->dram.buswidth, rtcl_ccu->dram.type);
for (int clk_idx = 0; clk_idx < CLK_COUNT; clk_idx++) {
sprintf(clkinfo, ", %s %lu MHz", rtcl_clk_info[clk_idx].display_name,
rtcl_ccu->clks[clk_idx].startup / 1000000);
if (clk_idx == CLK_MEM)
strcat(clkinfo, meminfo);
strcat(msg, clkinfo);
}
pr_info("%s\n", msg);
}
void rtcl_ccu_log_late(void)
{
struct rtcl_clk *rclk;
bool overclock = false;
char clkinfo[80], msg[255] = "rate setting enabled";
for (int clk_idx = 0; clk_idx < CLK_COUNT; clk_idx++) {
rclk = &rtcl_ccu->clks[clk_idx];
overclock |= rclk->max > rclk->startup;
sprintf(clkinfo, ", %s %lu-%lu MHz", rtcl_clk_info[clk_idx].display_name,
rclk->min / 1000000, rclk->max / 1000000);
strcat(msg, clkinfo);
}
if (overclock)
strcat(msg, ", OVERCLOCK AT OWN RISK");
dev_info(&rtcl_ccu->pdev->dev, "%s\n", msg);
}
/*
* Early registration: This module provides core startup clocks that are needed
* for generic SOC init and for further builtin devices (e.g. UART). Register
* asap via clock framework.
*/
static void __init rtcl_probe_early(struct device_node *np)
{
if (rtcl_ccu_create(np))
return;
if (rtcl_ccu_register_clocks())
kfree(rtcl_ccu);
else
rtcl_ccu_log_early();
}
CLK_OF_DECLARE_DRIVER(rtl838x_clk, "realtek,rtl8380-clock", rtcl_probe_early);
CLK_OF_DECLARE_DRIVER(rtl839x_clk, "realtek,rtl8390-clock", rtcl_probe_early);
/*
* Late registration: Finally register as normal platform driver. At this point
* we can make use of other modules like SRAM.
*/
static const struct of_device_id rtcl_dt_ids[] = {
{ .compatible = "realtek,rtl8380-clock" },
{ .compatible = "realtek,rtl8390-clock" },
{}
};
static int rtcl_probe_late(struct platform_device *pdev)
{
int ret;
if (!rtcl_ccu) {
dev_err(&pdev->dev, "early initialization not run");
return -ENXIO;
}
rtcl_ccu->pdev = pdev;
ret = rtcl_init_sram();
if (ret)
return ret;
rtcl_ccu_log_late();
return 0;
}
static struct platform_driver rtcl_platform_driver = {
.driver = {
.name = "rtl83xx-clk",
.of_match_table = rtcl_dt_ids,
},
.probe = rtcl_probe_late,
};
static int __init rtcl_init_subsys(void)
{
return platform_driver_register(&rtcl_platform_driver);
}
/*
* The driver does not know when SRAM module has finally loaded. With an
* arch_initcall() we might overtake SRAM initialization. Be polite and give the
* system a little more time.
*/
subsys_initcall(rtcl_init_subsys);

View File

@ -0,0 +1,75 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Realtek RTL83XX clock headers
* Copyright (C) 2022 Markus Stockhausen <markus.stockhausen@gmx.de>
*/
/*
* Switch registers (e.g. PLL)
*/
#define RTL_SW_CORE_BASE (0xbb000000)
#define RTL838X_PLL_GLB_CTRL (0x0fc0)
#define RTL838X_PLL_CPU_CTRL0 (0x0fc4)
#define RTL838X_PLL_CPU_CTRL1 (0x0fc8)
#define RTL838X_PLL_LXB_CTRL0 (0x0fd0)
#define RTL838X_PLL_LXB_CTRL1 (0x0fd4)
#define RTL838X_PLL_MEM_CTRL0 (0x0fdc)
#define RTL838X_PLL_MEM_CTRL1 (0x0fe0)
#define RTL839X_PLL_GLB_CTRL (0x0024)
#define RTL839X_PLL_CPU_CTRL0 (0x0028)
#define RTL839X_PLL_CPU_CTRL1 (0x002c)
#define RTL839X_PLL_LXB_CTRL0 (0x0038)
#define RTL839X_PLL_LXB_CTRL1 (0x003c)
#define RTL839X_PLL_MEM_CTRL0 (0x0048)
#define RTL839X_PLL_MEM_CTRL1 (0x004c)
#define RTL_PLL_CTRL0_CMU_SEL_PREDIV(v) (((v) >> 0) & 0x3)
#define RTL_PLL_CTRL0_CMU_SEL_DIV4(v) (((v) >> 2) & 0x1)
#define RTL_PLL_CTRL0_CMU_NCODE_IN(v) (((v) >> 4) & 0xff)
#define RTL_PLL_CTRL0_CMU_DIVN2(v) (((v) >> 12) & 0xff)
#define RTL838X_GLB_CTRL_EN_CPU_PLL_MASK (1 << 0)
#define RTL838X_GLB_CTRL_EN_LXB_PLL_MASK (1 << 1)
#define RTL838X_GLB_CTRL_EN_MEM_PLL_MASK (1 << 2)
#define RTL838X_GLB_CTRL_CPU_PLL_READY_MASK (1 << 8)
#define RTL838X_GLB_CTRL_LXB_PLL_READY_MASK (1 << 9)
#define RTL838X_GLB_CTRL_MEM_PLL_READY_MASK (1 << 10)
#define RTL838X_GLB_CTRL_CPU_PLL_SC_MUX_MASK (1 << 12)
#define RTL838X_PLL_CTRL1_CMU_DIVN2_SELB(v) (((v) >> 26) & 0x1)
#define RTL838X_PLL_CTRL1_CMU_DIVN3_SEL(v) (((v) >> 27) & 0x3)
#define RTL839X_GLB_CTRL_CPU_CLKSEL_MASK (1 << 11)
#define RTL839X_GLB_CTRL_MEM_CLKSEL_MASK (1 << 12)
#define RTL839X_GLB_CTRL_LXB_CLKSEL_MASK (1 << 13)
#define RTL839X_PLL_CTRL1_CMU_DIVN2_SELB(v) (((v) >> 2) & 0x1)
#define RTL839X_PLL_CTRL1_CMU_DIVN3_SEL(v) (((v) >> 0) & 0x3)
/*
* Core registers (e.g. memory controller)
*/
#define RTL_SOC_BASE (0xB8000000)
#define RTL_MC_MCR (0x1000)
#define RTL_MC_DCR (0x1004)
#define RTL_MC_DTR0 (0x1008)
#define RTL_MC_DTR1 (0x100c)
#define RTL_MC_DTR2 (0x1010)
#define RTL_MC_DMCR (0x101c)
#define RTL_MC_DACCR (0x1500)
#define RTL_MC_DCDR (0x1060)
#define RTL_MC_MCR_DRAMTYPE(v) ((((v) >> 28) & 0xf) + 1)
#define RTL_MC_DCR_BUSWIDTH(v) (8 << (((v) >> 24) & 0xf))
/*
* Other stuff
*/
#define RTL_SRAM_MARKER (0x5eaf00d5)
#define RTL_SRAM_BASE (0x9f000000)

View File

@ -0,0 +1,286 @@
/* SPDX-License-Identifier: GPL-2.0-only */
#include <linux/clk.h>
#include <linux/clockchips.h>
#include <linux/cpu.h>
#include <linux/cpuhotplug.h>
#include <linux/interrupt.h>
#include <linux/sched_clock.h>
#include "timer-of.h"
#define RTTM_DATA 0x0
#define RTTM_CNT 0x4
#define RTTM_CTRL 0x8
#define RTTM_INT 0xc
#define RTTM_CTRL_ENABLE BIT(28)
#define RTTM_INT_PENDING BIT(16)
#define RTTM_INT_ENABLE BIT(20)
/*
* The Otto platform provides multiple 28 bit timers/counters with the following
* operating logic. If enabled the timer counts up. Per timer one can set a
* maximum counter value as an end marker. If end marker is reached the timer
* fires an interrupt. If the timer "overflows" by reaching the end marker or
* by adding 1 to 0x0fffffff the counter is reset to 0. When this happens and
* the timer is in operating mode COUNTER it stops. In mode TIMER it will
* continue to count up.
*/
#define RTTM_CTRL_COUNTER 0
#define RTTM_CTRL_TIMER BIT(24)
#define RTTM_BIT_COUNT 28
#define RTTM_MIN_DELTA 8
#define RTTM_MAX_DELTA CLOCKSOURCE_MASK(28)
/*
* Timers are derived from the LXB clock frequency. Usually this is a fixed
* multiple of the 25 MHz oscillator. The 930X SOC is an exception from that.
* Its LXB clock has only dividers and uses the switch PLL of 2.45 GHz as its
* base. The only meaningful frequencies we can achieve from that are 175.000
* MHz and 153.125 MHz. The greatest common divisor of all explained possible
* speeds is 3125000. Pin the timers to this 3.125 MHz reference frequency.
*/
#define RTTM_TICKS_PER_SEC 3125000
struct rttm_cs {
struct timer_of to;
struct clocksource cs;
};
/* Simple internal register functions */
static inline void rttm_set_counter(void __iomem *base, unsigned int counter)
{
iowrite32(counter, base + RTTM_CNT);
}
static inline unsigned int rttm_get_counter(void __iomem *base)
{
return ioread32(base + RTTM_CNT);
}
static inline void rttm_set_period(void __iomem *base, unsigned int period)
{
iowrite32(period, base + RTTM_DATA);
}
static inline void rttm_disable_timer(void __iomem *base)
{
iowrite32(0, base + RTTM_CTRL);
}
static inline void rttm_enable_timer(void __iomem *base, u32 mode, u32 divisor)
{
iowrite32(RTTM_CTRL_ENABLE | mode | divisor, base + RTTM_CTRL);
}
static inline void rttm_ack_irq(void __iomem *base)
{
iowrite32(ioread32(base + RTTM_INT) | RTTM_INT_PENDING, base + RTTM_INT);
}
static inline void rttm_enable_irq(void __iomem *base)
{
iowrite32(RTTM_INT_ENABLE, base + RTTM_INT);
}
static inline void rttm_disable_irq(void __iomem *base)
{
iowrite32(0, base + RTTM_INT);
}
/* Aggregated control functions for kernel clock framework */
#define RTTM_DEBUG(base) \
pr_debug("------------- %s %d %08x\n", __func__, \
smp_processor_id(), (u32)base)
static irqreturn_t rttm_timer_interrupt(int irq, void *dev_id)
{
struct clock_event_device *clkevt = dev_id;
struct timer_of *to = to_timer_of(clkevt);
rttm_ack_irq(to->of_base.base);
RTTM_DEBUG(to->of_base.base);
clkevt->event_handler(clkevt);
return IRQ_HANDLED;
}
static void rttm_stop_timer(void __iomem *base)
{
rttm_disable_timer(base);
rttm_ack_irq(base);
}
static void rttm_start_timer(struct timer_of *to, u32 mode)
{
rttm_set_counter(to->of_base.base, 0);
rttm_enable_timer(to->of_base.base, mode, to->of_clk.rate / RTTM_TICKS_PER_SEC);
}
static int rttm_next_event(unsigned long delta, struct clock_event_device *clkevt)
{
struct timer_of *to = to_timer_of(clkevt);
RTTM_DEBUG(to->of_base.base);
rttm_stop_timer(to->of_base.base);
rttm_set_period(to->of_base.base, delta);
rttm_start_timer(to, RTTM_CTRL_COUNTER);
return 0;
}
static int rttm_state_oneshot(struct clock_event_device *clkevt)
{
struct timer_of *to = to_timer_of(clkevt);
RTTM_DEBUG(to->of_base.base);
rttm_stop_timer(to->of_base.base);
rttm_set_period(to->of_base.base, RTTM_TICKS_PER_SEC / HZ);
rttm_start_timer(to, RTTM_CTRL_COUNTER);
return 0;
}
static int rttm_state_periodic(struct clock_event_device *clkevt)
{
struct timer_of *to = to_timer_of(clkevt);
RTTM_DEBUG(to->of_base.base);
rttm_stop_timer(to->of_base.base);
rttm_set_period(to->of_base.base, RTTM_TICKS_PER_SEC / HZ);
rttm_start_timer(to, RTTM_CTRL_TIMER);
return 0;
}
static int rttm_state_shutdown(struct clock_event_device *clkevt)
{
struct timer_of *to = to_timer_of(clkevt);
RTTM_DEBUG(to->of_base.base);
rttm_stop_timer(to->of_base.base);
return 0;
}
static void rttm_setup_timer(void __iomem *base)
{
RTTM_DEBUG(base);
rttm_stop_timer(base);
rttm_set_period(base, 0);
}
static u64 rttm_read_clocksource(struct clocksource *cs)
{
struct rttm_cs *rcs = container_of(cs, struct rttm_cs, cs);
return (u64)rttm_get_counter(rcs->to.of_base.base);
}
/* Module initialization part. */
static DEFINE_PER_CPU(struct timer_of, rttm_to) = {
.flags = TIMER_OF_BASE | TIMER_OF_CLOCK | TIMER_OF_IRQ,
.of_irq = {
.flags = IRQF_PERCPU | IRQF_TIMER,
.handler = rttm_timer_interrupt,
},
.clkevt = {
.rating = 400,
.features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT,
.set_state_periodic = rttm_state_periodic,
.set_state_shutdown = rttm_state_shutdown,
.set_state_oneshot = rttm_state_oneshot,
.set_next_event = rttm_next_event
},
};
static int rttm_enable_clocksource(struct clocksource *cs)
{
struct rttm_cs *rcs = container_of(cs, struct rttm_cs, cs);
rttm_disable_irq(rcs->to.of_base.base);
rttm_setup_timer(rcs->to.of_base.base);
rttm_enable_timer(rcs->to.of_base.base, RTTM_CTRL_TIMER,
rcs->to.of_clk.rate / RTTM_TICKS_PER_SEC);
return 0;
}
struct rttm_cs rttm_cs = {
.to = {
.flags = TIMER_OF_BASE | TIMER_OF_CLOCK,
},
.cs = {
.name = "realtek_otto_timer",
.rating = 400,
.mask = CLOCKSOURCE_MASK(RTTM_BIT_COUNT),
.flags = CLOCK_SOURCE_IS_CONTINUOUS,
.read = rttm_read_clocksource,
}
};
static u64 notrace rttm_read_clock(void)
{
return (u64)rttm_get_counter(rttm_cs.to.of_base.base);
}
static int rttm_cpu_starting(unsigned int cpu)
{
struct timer_of *to = per_cpu_ptr(&rttm_to, cpu);
RTTM_DEBUG(to->of_base.base);
to->clkevt.cpumask = cpumask_of(cpu);
irq_force_affinity(to->of_irq.irq, to->clkevt.cpumask);
clockevents_config_and_register(&to->clkevt, RTTM_TICKS_PER_SEC,
RTTM_MIN_DELTA, RTTM_MAX_DELTA);
rttm_enable_irq(to->of_base.base);
return 0;
}
static int __init rttm_probe(struct device_node *np)
{
int cpu, cpu_rollback;
struct timer_of *to;
int clkidx = num_possible_cpus();
/* Use the first n timers as per CPU clock event generators */
for_each_possible_cpu(cpu) {
to = per_cpu_ptr(&rttm_to, cpu);
to->of_irq.index = to->of_base.index = cpu;
if (timer_of_init(np, to)) {
pr_err("%s: setup of timer %d failed\n", __func__, cpu);
goto rollback;
}
rttm_setup_timer(to->of_base.base);
}
/* Activate the n'th + 1 timer as a stable CPU clocksource. */
to = &rttm_cs.to;
to->of_base.index = clkidx;
timer_of_init(np, to);
if (rttm_cs.to.of_base.base && rttm_cs.to.of_clk.rate) {
rttm_enable_clocksource(&rttm_cs.cs);
clocksource_register_hz(&rttm_cs.cs, RTTM_TICKS_PER_SEC);
sched_clock_register(rttm_read_clock, RTTM_BIT_COUNT, RTTM_TICKS_PER_SEC);
} else
pr_err("%s: setup of timer %d as clocksoure failed", __func__, clkidx);
return cpuhp_setup_state(CPUHP_AP_REALTEK_TIMER_STARTING,
"timer/realtek:online",
rttm_cpu_starting, NULL);
rollback:
pr_err("%s: timer registration failed\n", __func__);
for_each_possible_cpu(cpu_rollback) {
if (cpu_rollback == cpu)
break;
to = per_cpu_ptr(&rttm_to, cpu_rollback);
timer_of_cleanup(to);
}
return -EINVAL;
}
TIMER_OF_DECLARE(otto_timer, "realtek,otto-timer", rttm_probe);

View File

@ -0,0 +1,364 @@
// 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-rtl83xx.h>
/* RTL8231 registers for LED control */
#define RTL8231_LED_FUNC0 0x0000
#define RTL8231_LED_FUNC1 0x0001
#define RTL8231_READY_MASK 0x03f0
#define RTL8231_READY_VALUE 0x0370
#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 USEC_TIMEOUT 5000
#define RTL8231_SMI_BUS_ID_MAX 0x1F
struct rtl8231_gpios {
struct gpio_chip gc;
struct device *dev;
u32 id;
u32 smi_bus_id;
u16 reg_shadow[0x20];
u32 reg_cached;
int ext_gpio_indrt_access;
};
extern struct rtl83xx_soc_info soc_info;
DEFINE_MUTEX(miim_lock);
static u32 rtl8231_read(struct rtl8231_gpios *gpios, u32 reg)
{
u32 t = 0, n = 0;
reg &= 0x1f;
/* Calculate read register address */
t = (gpios->smi_bus_id << 2) | (reg << 7);
/* Set execution bit: cleared when operation completed */
t |= 1;
/* Start execution */
sw_w32(t, gpios->ext_gpio_indrt_access);
do {
udelay(1);
t = sw_r32(gpios->ext_gpio_indrt_access);
n++;
} while ((t & 1) && (n < USEC_TIMEOUT));
if (n >= USEC_TIMEOUT)
return 0x80000000;
pr_debug("%s: %x, %x, %x\n", __func__, gpios->smi_bus_id,
reg, (t & 0xffff0000) >> 16);
return (t & 0xffff0000) >> 16;
}
static int rtl8231_write(struct rtl8231_gpios *gpios, u32 reg, u32 data)
{
u32 t = 0, n = 0;
pr_debug("%s: %x, %x, %x\n", __func__, gpios->smi_bus_id, reg, data);
reg &= 0x1f;
t = (gpios->smi_bus_id << 2) | (reg << 7) | (data << 16);
/* Set write bit */
t |= 2;
/* Set execution bit: cleared when operation completed */
t |= 1;
/* Start execution */
sw_w32(t, gpios->ext_gpio_indrt_access);
do {
udelay(1);
t = sw_r32(gpios->ext_gpio_indrt_access);
} while ((t & 1) && (n < USEC_TIMEOUT));
if (n >= USEC_TIMEOUT)
return -1;
return 0;
}
static u32 rtl8231_read_cached(struct rtl8231_gpios *gpios, u32 reg)
{
if (reg > 0x1f)
return 0;
if (gpios->reg_cached & (1 << reg))
return gpios->reg_shadow[reg];
return rtl8231_read(gpios, reg);
}
/* Set Direction of the RTL8231 pin:
* dir 1: input
* dir 0: output
*/
static int rtl8231_pin_dir(struct rtl8231_gpios *gpios, u32 gpio, u32 dir)
{
u32 v;
int pin_sel_addr = RTL8231_GPIO_PIN_SEL(gpio);
int pin_dir_addr = RTL8231_GPIO_DIR(gpio);
int dpin = gpio % 16;
if (gpio > 31) {
pr_debug("WARNING: HIGH pin\n");
dpin += 5;
pin_dir_addr = pin_sel_addr;
}
v = rtl8231_read_cached(gpios, pin_dir_addr);
if (v & 0x80000000) {
pr_err("Error reading RTL8231\n");
return -1;
}
v = (v & ~(1 << dpin)) | (dir << dpin);
rtl8231_write(gpios, pin_dir_addr, v);
gpios->reg_shadow[pin_dir_addr] = v;
gpios->reg_cached |= 1 << pin_dir_addr;
return 0;
}
static int rtl8231_pin_dir_get(struct rtl8231_gpios *gpios, 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 += 5;
}
v = rtl8231_read(gpios, pin_dir_addr);
if (v & (1 << pin))
*dir = 1;
else
*dir = 0;
return 0;
}
static int rtl8231_pin_set(struct rtl8231_gpios *gpios, u32 gpio, u32 data)
{
u32 v = rtl8231_read(gpios, RTL8231_GPIO_DATA(gpio));
pr_debug("%s: %d to %d\n", __func__, gpio, data);
if (v & 0x80000000) {
pr_err("Error reading RTL8231\n");
return -1;
}
v = (v & ~(1 << (gpio % 16))) | (data << (gpio % 16));
rtl8231_write(gpios, RTL8231_GPIO_DATA(gpio), v);
gpios->reg_shadow[RTL8231_GPIO_DATA(gpio)] = v;
gpios->reg_cached |= 1 << RTL8231_GPIO_DATA(gpio);
return 0;
}
static int rtl8231_pin_get(struct rtl8231_gpios *gpios, u32 gpio, u16 *state)
{
u32 v = rtl8231_read(gpios, RTL8231_GPIO_DATA(gpio));
if (v & 0x80000000) {
pr_err("Error reading RTL8231\n");
return -1;
}
*state = v & 0xffff;
return 0;
}
static int rtl8231_direction_input(struct gpio_chip *gc, unsigned int offset)
{
int err;
struct rtl8231_gpios *gpios = gpiochip_get_data(gc);
pr_debug("%s: %d\n", __func__, offset);
mutex_lock(&miim_lock);
err = rtl8231_pin_dir(gpios, offset, 1);
mutex_unlock(&miim_lock);
return err;
}
static int rtl8231_direction_output(struct gpio_chip *gc, unsigned int offset, int value)
{
int err;
struct rtl8231_gpios *gpios = gpiochip_get_data(gc);
pr_debug("%s: %d\n", __func__, offset);
mutex_lock(&miim_lock);
err = rtl8231_pin_dir(gpios, offset, 0);
mutex_unlock(&miim_lock);
if (!err)
err = rtl8231_pin_set(gpios, offset, value);
return err;
}
static int rtl8231_get_direction(struct gpio_chip *gc, unsigned int offset)
{
u32 v = 0;
struct rtl8231_gpios *gpios = gpiochip_get_data(gc);
pr_debug("%s: %d\n", __func__, offset);
mutex_lock(&miim_lock);
rtl8231_pin_dir_get(gpios, offset, &v);
mutex_unlock(&miim_lock);
return v;
}
static int rtl8231_gpio_get(struct gpio_chip *gc, unsigned int offset)
{
u16 state = 0;
struct rtl8231_gpios *gpios = gpiochip_get_data(gc);
mutex_lock(&miim_lock);
rtl8231_pin_get(gpios, offset, &state);
mutex_unlock(&miim_lock);
if (state & (1 << (offset % 16)))
return 1;
return 0;
}
void rtl8231_gpio_set(struct gpio_chip *gc, unsigned int offset, int value)
{
struct rtl8231_gpios *gpios = gpiochip_get_data(gc);
rtl8231_pin_set(gpios, offset, value);
}
int rtl8231_init(struct rtl8231_gpios *gpios)
{
u32 ret;
pr_info("%s called, MDIO bus ID: %d\n", __func__, gpios->smi_bus_id);
gpios->reg_cached = 0;
if (soc_info.family == RTL8390_FAMILY_ID) {
/* RTL8390: Enable external gpio in global led control register */
sw_w32_mask(0x7 << 18, 0x4 << 18, RTL839X_LED_GLB_CTRL);
} else if (soc_info.family == RTL8380_FAMILY_ID) {
/* RTL8380: Enable RTL8231 indirect access mode */
sw_w32_mask(0, 1, RTL838X_EXTRA_GPIO_CTRL);
sw_w32_mask(3, 1, RTL838X_DMY_REG5);
}
ret = rtl8231_read(gpios, RTL8231_LED_FUNC1);
if ((ret & 0x80000000) || ((ret & RTL8231_READY_MASK) != RTL8231_READY_VALUE))
return -ENXIO;
/* Select GPIO functionality and force input direction for pins 0-36 */
rtl8231_write(gpios, RTL8231_GPIO_PIN_SEL(0), 0xffff);
rtl8231_write(gpios, RTL8231_GPIO_DIR(0), 0xffff);
rtl8231_write(gpios, RTL8231_GPIO_PIN_SEL(16), 0xffff);
rtl8231_write(gpios, RTL8231_GPIO_DIR(16), 0xffff);
rtl8231_write(gpios, RTL8231_GPIO_PIN_SEL(32), 0x03ff);
/* Set LED_Start to enable drivers for output mode */
rtl8231_write(gpios, RTL8231_LED_FUNC0, 1 << 1);
return 0;
}
static const struct of_device_id rtl8231_gpio_of_match[] = {
{ .compatible = "realtek,rtl8231-gpio" },
{},
};
MODULE_DEVICE_TABLE(of, rtl8231_gpio_of_match);
static int rtl8231_gpio_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct device_node *np = dev->of_node;
struct rtl8231_gpios *gpios;
int err;
pr_info("Probing RTL8231 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 = soc_info.id;
if (soc_info.family == RTL8380_FAMILY_ID) {
gpios->ext_gpio_indrt_access = RTL838X_EXT_GPIO_INDRT_ACCESS;
}
if (soc_info.family == RTL8390_FAMILY_ID) {
gpios->ext_gpio_indrt_access = RTL839X_EXT_GPIO_INDRT_ACCESS;
}
err = of_property_read_u32(np, "indirect-access-bus-id", &gpios->smi_bus_id);
if (!err && gpios->smi_bus_id > RTL8231_SMI_BUS_ID_MAX)
err = -EINVAL;
if (err) {
dev_err(dev, "invalid or missing indirect-access-bus-id\n");
return err;
}
err = rtl8231_init(gpios);
if (err) {
dev_err(dev, "no device found at bus address %d\n", gpios->smi_bus_id);
return err;
}
gpios->dev = dev;
gpios->gc.base = -1;
gpios->gc.ngpio = 37;
gpios->gc.label = "rtl8231";
gpios->gc.parent = dev;
gpios->gc.owner = THIS_MODULE;
gpios->gc.can_sleep = true;
gpios->gc.direction_input = rtl8231_direction_input;
gpios->gc.direction_output = rtl8231_direction_output;
gpios->gc.set = rtl8231_gpio_set;
gpios->gc.get = rtl8231_gpio_get;
gpios->gc.get_direction = rtl8231_get_direction;
return devm_gpiochip_add_data(dev, &gpios->gc, gpios);
}
static struct platform_driver rtl8231_gpio_driver = {
.driver = {
.name = "rtl8231-gpio",
.of_match_table = rtl8231_gpio_of_match,
},
.probe = rtl8231_gpio_probe,
};
module_platform_driver(rtl8231_gpio_driver);
MODULE_DESCRIPTION("Realtek RTL8231 GPIO expansion chip support");
MODULE_LICENSE("GPL v2");

View File

@ -0,0 +1,486 @@
// SPDX-License-Identifier: GPL-2.0-only
#include <linux/module.h>
#include <linux/of_platform.h>
#include "i2c-rtl9300.h"
#define REG(i, x) (i->base + x + (i->scl_num ? i->mst2_offset : 0))
#define REG_MASK(i, clear, set, reg) \
writel((readl(REG(i, reg)) & ~(clear)) | (set), REG(i, reg))
struct i2c_drv_data {
int scl0_pin;
int scl1_pin;
int sda0_pin;
struct i2c_algorithm *algo;
int (*read)(struct rtl9300_i2c *i2c, u8 *buf, int len);
int (*write)(struct rtl9300_i2c *i2c, u8 *buf, int len);
void (*reg_addr_set)(struct rtl9300_i2c *i2c, u32 reg, u16 len);
int (*config_xfer)(struct rtl9300_i2c *i2c, u16 addr, u16 len);
int (*execute_xfer)(struct rtl9300_i2c *i2c, char read_write, int size,
union i2c_smbus_data * data, int len);
void (*writel)(struct rtl9300_i2c *i2c, u32 data);
void (*config_io)(struct rtl9300_i2c *i2c, int scl_num, int sda_num);
u32 mst2_offset;
};
DEFINE_MUTEX(i2c_lock);
static void rtl9300_i2c_reg_addr_set(struct rtl9300_i2c *i2c, u32 reg, u16 len)
{
/* Set register address width */
REG_MASK(i2c, 0x3 << RTL9300_I2C_CTRL2_MADDR_WIDTH, len << RTL9300_I2C_CTRL2_MADDR_WIDTH,
RTL9300_I2C_CTRL2);
/* Set register address */
REG_MASK(i2c, 0xffffff << RTL9300_I2C_CTRL1_MEM_ADDR, reg << RTL9300_I2C_CTRL1_MEM_ADDR,
RTL9300_I2C_CTRL1);
}
static void rtl9310_i2c_reg_addr_set(struct rtl9300_i2c *i2c, u32 reg, u16 len)
{
/* Set register address width */
REG_MASK(i2c, 0x3 << RTL9310_I2C_CTRL_MADDR_WIDTH, len << RTL9310_I2C_CTRL_MADDR_WIDTH,
RTL9310_I2C_CTRL);
/* Set register address */
writel(reg, REG(i2c, RTL9310_I2C_MEMADDR));
}
static void rtl9300_i2c_config_io(struct rtl9300_i2c *i2c, int scl_num, int sda_num)
{
u32 v;
/* Set SCL pin */
REG_MASK(i2c, 0, BIT(RTL9300_I2C_CTRL1_GPIO8_SCL_SEL), RTL9300_I2C_CTRL1);
/* Set SDA pin */
REG_MASK(i2c, 0x7 << RTL9300_I2C_CTRL1_SDA_OUT_SEL,
i2c->sda_num << RTL9300_I2C_CTRL1_SDA_OUT_SEL, RTL9300_I2C_CTRL1);
/* Set SDA pin to I2C functionality */
v = readl(i2c->base + RTL9300_I2C_MST_GLB_CTRL);
v |= BIT(i2c->sda_num);
writel(v, i2c->base + RTL9300_I2C_MST_GLB_CTRL);
}
static void rtl9310_i2c_config_io(struct rtl9300_i2c *i2c, int scl_num, int sda_num)
{
u32 v;
/* Set SCL pin */
REG_MASK(i2c, 0, BIT(RTL9310_I2C_MST_IF_SEL_GPIO_SCL_SEL + scl_num), RTL9310_I2C_MST_IF_SEL);
/* Set SDA pin */
REG_MASK(i2c, 0x7 << RTL9310_I2C_CTRL_SDA_OUT_SEL,
i2c->sda_num << RTL9310_I2C_CTRL_SDA_OUT_SEL, RTL9310_I2C_CTRL);
/* Set SDA pin to I2C functionality */
v = readl(i2c->base + RTL9310_I2C_MST_IF_SEL);
v |= BIT(i2c->sda_num);
writel(v, i2c->base + RTL9310_I2C_MST_IF_SEL);
}
static int rtl9300_i2c_config_xfer(struct rtl9300_i2c *i2c, u16 addr, u16 len)
{
/* Set bus frequency */
REG_MASK(i2c, 0x3 << RTL9300_I2C_CTRL2_SCL_FREQ,
i2c->bus_freq << RTL9300_I2C_CTRL2_SCL_FREQ, RTL9300_I2C_CTRL2);
/* Set slave device address */
REG_MASK(i2c, 0x7f << RTL9300_I2C_CTRL2_DEV_ADDR,
addr << RTL9300_I2C_CTRL2_DEV_ADDR, RTL9300_I2C_CTRL2);
/* Set data length */
REG_MASK(i2c, 0xf << RTL9300_I2C_CTRL2_DATA_WIDTH,
((len - 1) & 0xf) << RTL9300_I2C_CTRL2_DATA_WIDTH, RTL9300_I2C_CTRL2);
/* Set read mode to random */
REG_MASK(i2c, 0x1 << RTL9300_I2C_CTRL2_READ_MODE, 0, RTL9300_I2C_CTRL2);
return 0;
}
static int rtl9310_i2c_config_xfer(struct rtl9300_i2c *i2c, u16 addr, u16 len)
{
/* Set bus frequency */
REG_MASK(i2c, 0x3 << RTL9310_I2C_CTRL_SCL_FREQ,
i2c->bus_freq << RTL9310_I2C_CTRL_SCL_FREQ, RTL9310_I2C_CTRL);
/* Set slave device address */
REG_MASK(i2c, 0x7f << RTL9310_I2C_CTRL_DEV_ADDR,
addr << RTL9310_I2C_CTRL_DEV_ADDR, RTL9310_I2C_CTRL);
/* Set data length */
REG_MASK(i2c, 0xf << RTL9310_I2C_CTRL_DATA_WIDTH,
((len - 1) & 0xf) << RTL9310_I2C_CTRL_DATA_WIDTH, RTL9310_I2C_CTRL);
/* Set read mode to random */
REG_MASK(i2c, 0x1 << RTL9310_I2C_CTRL_READ_MODE, 0, RTL9310_I2C_CTRL);
return 0;
}
static int i2c_read(void __iomem *r0, u8 *buf, int len)
{
if (len > 16)
return -EIO;
for (int i = 0; i < len; i++) {
u32 v;
if (i % 4 == 0)
v = readl(r0 + i);
buf[i] = v;
v >>= 8;
}
return len;
}
static int i2c_write(void __iomem *r0, u8 *buf, int len)
{
if (len > 16)
return -EIO;
for (int i = 0; i < len; i++) {
u32 v;
if (! (i % 4))
v = 0;
v <<= 8;
v |= buf[i];
if (i % 4 == 3 || i == len - 1)
writel(v, r0 + (i / 4) * 4);
}
return len;
}
static int rtl9300_i2c_read(struct rtl9300_i2c *i2c, u8 *buf, int len)
{
return i2c_read(REG(i2c, RTL9300_I2C_DATA_WORD0), buf, len);
}
static int rtl9300_i2c_write(struct rtl9300_i2c *i2c, u8 *buf, int len)
{
return i2c_write(REG(i2c, RTL9300_I2C_DATA_WORD0), buf, len);
}
static int rtl9310_i2c_read(struct rtl9300_i2c *i2c, u8 *buf, int len)
{
return i2c_read(REG(i2c, RTL9310_I2C_DATA), buf, len);
}
static int rtl9310_i2c_write(struct rtl9300_i2c *i2c, u8 *buf, int len)
{
return i2c_write(REG(i2c, RTL9310_I2C_DATA), buf, len);
}
static void rtl9300_writel(struct rtl9300_i2c *i2c, u32 data)
{
writel(data, REG(i2c, RTL9300_I2C_DATA_WORD0));
}
static void rtl9310_writel(struct rtl9300_i2c *i2c, u32 data)
{
writel(data, REG(i2c, RTL9310_I2C_DATA));
}
static int rtl9300_execute_xfer(struct rtl9300_i2c *i2c, char read_write,
int size, union i2c_smbus_data * data, int len)
{
u32 v;
if (read_write == I2C_SMBUS_READ)
REG_MASK(i2c, BIT(RTL9300_I2C_CTRL1_RWOP), 0, RTL9300_I2C_CTRL1);
else
REG_MASK(i2c, 0, BIT(RTL9300_I2C_CTRL1_RWOP), RTL9300_I2C_CTRL1);
REG_MASK(i2c, 0, BIT(RTL9300_I2C_CTRL1_I2C_TRIG), RTL9300_I2C_CTRL1);
do {
v = readl(REG(i2c, RTL9300_I2C_CTRL1));
} while (v & BIT(RTL9300_I2C_CTRL1_I2C_TRIG));
if (v & BIT(RTL9300_I2C_CTRL1_I2C_FAIL))
return -EIO;
if (read_write == I2C_SMBUS_READ) {
if (size == I2C_SMBUS_BYTE || size == I2C_SMBUS_BYTE_DATA){
data->byte = readl(REG(i2c, RTL9300_I2C_DATA_WORD0));
} else if (size == I2C_SMBUS_WORD_DATA) {
data->word = readl(REG(i2c, RTL9300_I2C_DATA_WORD0));
} else if (len > 0) {
rtl9300_i2c_read(i2c, &data->block[0], len);
}
}
return 0;
}
static int rtl9310_execute_xfer(struct rtl9300_i2c *i2c, char read_write,
int size, union i2c_smbus_data * data, int len)
{
u32 v;
if (read_write == I2C_SMBUS_READ)
REG_MASK(i2c, BIT(RTL9310_I2C_CTRL_RWOP), 0, RTL9310_I2C_CTRL);
else
REG_MASK(i2c, 0, BIT(RTL9310_I2C_CTRL_RWOP), RTL9310_I2C_CTRL);
REG_MASK(i2c, 0, BIT(RTL9310_I2C_CTRL_I2C_TRIG), RTL9310_I2C_CTRL);
do {
v = readl(REG(i2c, RTL9310_I2C_CTRL));
} while (v & BIT(RTL9310_I2C_CTRL_I2C_TRIG));
if (v & BIT(RTL9310_I2C_CTRL_I2C_FAIL))
return -EIO;
if (read_write == I2C_SMBUS_READ) {
if (size == I2C_SMBUS_BYTE || size == I2C_SMBUS_BYTE_DATA){
data->byte = readl(REG(i2c, RTL9310_I2C_DATA));
} else if (size == I2C_SMBUS_WORD_DATA) {
data->word = readl(REG(i2c, RTL9310_I2C_DATA));
} else if (len > 0) {
rtl9310_i2c_read(i2c, &data->block[0], len);
}
}
return 0;
}
static int rtl9300_i2c_smbus_xfer(struct i2c_adapter * adap, u16 addr,
unsigned short flags, char read_write,
u8 command, int size, union i2c_smbus_data * data)
{
struct rtl9300_i2c *i2c = i2c_get_adapdata(adap);
struct i2c_drv_data *drv_data = (struct i2c_drv_data *)device_get_match_data(i2c->dev);
int len = 0, ret;
mutex_lock(&i2c_lock);
switch (size) {
case I2C_SMBUS_QUICK:
drv_data->config_xfer(i2c, addr, 0);
drv_data->reg_addr_set(i2c, 0, 0);
break;
case I2C_SMBUS_BYTE:
if (read_write == I2C_SMBUS_WRITE) {
drv_data->config_xfer(i2c, addr, 0);
drv_data->reg_addr_set(i2c, command, 1);
} else {
drv_data->config_xfer(i2c, addr, 1);
drv_data->reg_addr_set(i2c, 0, 0);
}
break;
case I2C_SMBUS_BYTE_DATA:
pr_debug("I2C_SMBUS_BYTE_DATA %02x, read %d cmd %02x\n", addr, read_write, command);
drv_data->reg_addr_set(i2c, command, 1);
drv_data->config_xfer(i2c, addr, 1);
if (read_write == I2C_SMBUS_WRITE) {
pr_debug("--> data %02x\n", data->byte);
drv_data->writel(i2c, data->byte);
}
break;
case I2C_SMBUS_WORD_DATA:
pr_debug("I2C_SMBUS_WORD %02x, read %d\n", addr, read_write);
drv_data->reg_addr_set(i2c, command, 1);
drv_data->config_xfer(i2c, addr, 2);
if (read_write == I2C_SMBUS_WRITE)
drv_data->writel(i2c, data->word);
break;
case I2C_SMBUS_BLOCK_DATA:
pr_debug("I2C_SMBUS_BLOCK_DATA %02x, read %d, len %d\n",
addr, read_write, data->block[0]);
drv_data->reg_addr_set(i2c, command, 1);
drv_data->config_xfer(i2c, addr, data->block[0]);
if (read_write == I2C_SMBUS_WRITE)
drv_data->write(i2c, &data->block[1], data->block[0]);
len = data->block[0];
break;
default:
dev_warn(&adap->dev, "Unsupported transaction %d\n", size);
return -EOPNOTSUPP;
}
ret = drv_data->execute_xfer(i2c, read_write, size, data, len);
mutex_unlock(&i2c_lock);
return ret;
}
static u32 rtl9300_i2c_func(struct i2c_adapter *a)
{
return I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE |
I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA |
I2C_FUNC_SMBUS_BLOCK_DATA;
}
static const struct i2c_algorithm rtl9300_i2c_algo = {
.smbus_xfer = rtl9300_i2c_smbus_xfer,
.functionality = rtl9300_i2c_func,
};
struct i2c_adapter_quirks rtl9300_i2c_quirks = {
.flags = I2C_AQ_NO_CLK_STRETCH,
.max_read_len = 16,
.max_write_len = 16,
};
static int rtl9300_i2c_probe(struct platform_device *pdev)
{
struct resource *res;
struct rtl9300_i2c *i2c;
struct i2c_adapter *adap;
struct i2c_drv_data *drv_data;
struct device_node *node = pdev->dev.of_node;
u32 clock_freq, pin;
int ret = 0;
pr_info("%s probing I2C adapter\n", __func__);
if (!node) {
dev_err(i2c->dev, "No DT found\n");
return -EINVAL;
}
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
drv_data = (struct i2c_drv_data *) device_get_match_data(&pdev->dev);
i2c = devm_kzalloc(&pdev->dev, sizeof(struct rtl9300_i2c), GFP_KERNEL);
if (!i2c)
return -ENOMEM;
i2c->base = devm_ioremap_resource(&pdev->dev, res);
i2c->mst2_offset = drv_data->mst2_offset;
if (IS_ERR(i2c->base))
return PTR_ERR(i2c->base);
pr_debug("%s base memory %08x\n", __func__, (u32)i2c->base);
i2c->dev = &pdev->dev;
if (of_property_read_u32(node, "clock-frequency", &clock_freq)) {
clock_freq = I2C_MAX_STANDARD_MODE_FREQ;
}
switch(clock_freq) {
case I2C_MAX_STANDARD_MODE_FREQ:
i2c->bus_freq = RTL9300_I2C_STD_FREQ;
break;
case I2C_MAX_FAST_MODE_FREQ:
i2c->bus_freq = RTL9300_I2C_FAST_FREQ;
break;
default:
dev_warn(i2c->dev, "clock-frequency %d not supported\n", clock_freq);
return -EINVAL;
}
dev_info(&pdev->dev, "SCL speed %d, mode is %d\n", clock_freq, i2c->bus_freq);
if (of_property_read_u32(node, "scl-pin", &pin)) {
dev_warn(i2c->dev, "SCL pin not found in DT, using default\n");
pin = drv_data->scl0_pin;
}
if (!(pin == drv_data->scl0_pin || pin == drv_data->scl1_pin)) {
dev_warn(i2c->dev, "SCL pin %d not supported\n", pin);
return -EINVAL;
}
i2c->scl_num = pin == drv_data->scl0_pin ? 0 : 1;
pr_info("%s scl_num %d\n", __func__, i2c->scl_num);
if (of_property_read_u32(node, "sda-pin", &pin)) {
dev_warn(i2c->dev, "SDA pin not found in DT, using default \n");
pin = drv_data->sda0_pin;
}
i2c->sda_num = pin - drv_data->sda0_pin;
if (i2c->sda_num < 0 || i2c->sda_num > 7) {
dev_warn(i2c->dev, "SDA pin %d not supported\n", pin);
return -EINVAL;
}
pr_info("%s sda_num %d\n", __func__, i2c->sda_num);
adap = &i2c->adap;
adap->owner = THIS_MODULE;
adap->algo = &rtl9300_i2c_algo;
adap->retries = 3;
adap->dev.parent = &pdev->dev;
i2c_set_adapdata(adap, i2c);
adap->dev.of_node = node;
strlcpy(adap->name, dev_name(&pdev->dev), sizeof(adap->name));
platform_set_drvdata(pdev, i2c);
drv_data->config_io(i2c, i2c->scl_num, i2c->sda_num);
ret = i2c_add_adapter(adap);
return ret;
}
static int rtl9300_i2c_remove(struct platform_device *pdev)
{
struct rtl9300_i2c *i2c = platform_get_drvdata(pdev);
i2c_del_adapter(&i2c->adap);
return 0;
}
struct i2c_drv_data rtl9300_i2c_drv_data = {
.scl0_pin = 8,
.scl1_pin = 17,
.sda0_pin = 9,
.read = rtl9300_i2c_read,
.read = rtl9300_i2c_write,
.reg_addr_set = rtl9300_i2c_reg_addr_set,
.config_xfer = rtl9300_i2c_config_xfer,
.execute_xfer = rtl9300_execute_xfer,
.writel = rtl9300_writel,
.config_io = rtl9300_i2c_config_io,
.mst2_offset = 0x1c,
};
struct i2c_drv_data rtl9310_i2c_drv_data = {
.scl0_pin = 13,
.scl1_pin = 14,
.sda0_pin = 0,
.read = rtl9310_i2c_read,
.read = rtl9310_i2c_write,
.reg_addr_set = rtl9310_i2c_reg_addr_set,
.config_xfer = rtl9310_i2c_config_xfer,
.execute_xfer = rtl9310_execute_xfer,
.writel = rtl9310_writel,
.config_io = rtl9310_i2c_config_io,
.mst2_offset = 0x18,
};
static const struct of_device_id i2c_rtl9300_dt_ids[] = {
{ .compatible = "realtek,rtl9300-i2c", .data = (void *) &rtl9300_i2c_drv_data },
{ .compatible = "realtek,rtl9310-i2c", .data = (void *) &rtl9310_i2c_drv_data },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, rtl838x_eth_of_ids);
static struct platform_driver rtl9300_i2c_driver = {
.probe = rtl9300_i2c_probe,
.remove = rtl9300_i2c_remove,
.driver = {
.name = "i2c-rtl9300",
.pm = NULL,
.of_match_table = i2c_rtl9300_dt_ids,
},
};
module_platform_driver(rtl9300_i2c_driver);
MODULE_AUTHOR("Birger Koblitz");
MODULE_DESCRIPTION("RTL9300 I2C host driver");
MODULE_LICENSE("GPL v2");

View File

@ -0,0 +1,62 @@
#ifndef I2C_RTL9300_H
#define I2C_RTL9300_H
#include <linux/i2c.h>
#define RTL9300_I2C_CTRL1 0x00
#define RTL9300_I2C_CTRL1_MEM_ADDR 8
#define RTL9300_I2C_CTRL1_SDA_OUT_SEL 4
#define RTL9300_I2C_CTRL1_GPIO8_SCL_SEL 3
#define RTL9300_I2C_CTRL1_RWOP 2
#define RTL9300_I2C_CTRL1_I2C_FAIL 1
#define RTL9300_I2C_CTRL1_I2C_TRIG 0
#define RTL9300_I2C_CTRL2 0x04
#define RTL9300_I2C_CTRL2_DRIVE_ACK_DELAY 20
#define RTL9300_I2C_CTRL2_CHECK_ACK_DELAY 16
#define RTL9300_I2C_CTRL2_READ_MODE 15
#define RTL9300_I2C_CTRL2_DEV_ADDR 8
#define RTL9300_I2C_CTRL2_DATA_WIDTH 4
#define RTL9300_I2C_CTRL2_MADDR_WIDTH 2
#define RTL9300_I2C_CTRL2_SCL_FREQ 0
#define RTL9300_I2C_DATA_WORD0 0x08
#define RTL9300_I2C_MST_GLB_CTRL 0x18
#define RTL9310_I2C_MST_IF_CTRL 0x00
#define RTL9310_I2C_MST_IF_SEL 0x04
#define RTL9310_I2C_MST_IF_SEL_GPIO_SCL_SEL 12
#define RTL9310_I2C_CTRL 0x08
#define RTL9310_I2C_CTRL_SCL_FREQ 30
#define RTL9310_I2C_CTRL_CHECK_ACK_DELAY 26
#define RTL9310_I2C_CTRL_DRIVE_ACK_DELAY 22
#define RTL9310_I2C_CTRL_SDA_OUT_SEL 18
#define RTL9310_I2C_CTRL_DEV_ADDR 11
#define RTL9310_I2C_CTRL_MADDR_WIDTH 9
#define RTL9310_I2C_CTRL_DATA_WIDTH 5
#define RTL9310_I2C_CTRL_READ_MODE 4
#define RTL9310_I2C_CTRL_RWOP 2
#define RTL9310_I2C_CTRL_I2C_FAIL 1
#define RTL9310_I2C_CTRL_I2C_TRIG 0
#define RTL9310_I2C_MEMADDR 0x0c
#define RTL9310_I2C_DATA 0x10
#define RTL9300_I2C_STD_FREQ 0
#define RTL9300_I2C_FAST_FREQ 1
struct rtl9300_i2c {
void __iomem *base;
u32 mst2_offset;
struct device *dev;
struct i2c_adapter adap;
u8 bus_freq;
u8 sda_num; /* SDA channel number */
u8 scl_num; /* SCL channel, mapping to master 1 or 2 */
};
#endif

View File

@ -0,0 +1,293 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* I2C multiplexer for the 2 I2C Masters of the RTL9300
* with up to 8 channels each, but which are not entirely
* independent of each other
*/
#include <linux/i2c-mux.h>
#include <linux/module.h>
#include <linux/mux/consumer.h>
#include <linux/of_device.h>
#include <linux/of_address.h>
#include <linux/platform_device.h>
#include "../busses/i2c-rtl9300.h"
#define NUM_MASTERS 2
#define NUM_BUSSES 8
#define REG(mst, x) (mux->base + x + (mst ? mux->i2c->mst2_offset : 0))
#define REG_MASK(mst, clear, set, reg) \
writel((readl(REG((mst),(reg))) & ~(clear)) | (set), REG((mst),(reg)))
struct channel {
u8 sda_num;
u8 scl_num;
};
static struct channel channels[NUM_MASTERS * NUM_BUSSES];
struct rtl9300_mux {
void __iomem *base;
struct device *dev;
struct i2c_adapter *parent;
struct rtl9300_i2c * i2c;
};
struct i2c_mux_data {
int scl0_pin;
int scl1_pin;
int sda0_pin;
int sda_pins;
int (*i2c_mux_select)(struct i2c_mux_core *muxc, u32 chan);
int (*i2c_mux_deselect)(struct i2c_mux_core *muxc, u32 chan);
void (*sda_sel)(struct i2c_mux_core *muxc, int pin);
};
static int rtl9300_i2c_mux_select(struct i2c_mux_core *muxc, u32 chan)
{
struct rtl9300_mux *mux = i2c_mux_priv(muxc);
/* Set SCL pin */
REG_MASK(channels[chan].scl_num, 0,
BIT(RTL9300_I2C_CTRL1_GPIO8_SCL_SEL), RTL9300_I2C_CTRL1);
/* Set SDA pin */
REG_MASK(channels[chan].scl_num, 0x7 << RTL9300_I2C_CTRL1_SDA_OUT_SEL,
channels[chan].sda_num << RTL9300_I2C_CTRL1_SDA_OUT_SEL, RTL9300_I2C_CTRL1);
mux->i2c->sda_num = channels[chan].sda_num;
mux->i2c->scl_num = channels[chan].scl_num;
return 0;
}
static int rtl9310_i2c_mux_select(struct i2c_mux_core *muxc, u32 chan)
{
struct rtl9300_mux *mux = i2c_mux_priv(muxc);
/* Set SCL pin */
REG_MASK(0, 0, BIT(RTL9310_I2C_MST_IF_SEL_GPIO_SCL_SEL + channels[chan].scl_num),
RTL9310_I2C_MST_IF_SEL);
/* Set SDA pin */
REG_MASK(channels[chan].scl_num, 0xf << RTL9310_I2C_CTRL_SDA_OUT_SEL,
channels[chan].sda_num << RTL9310_I2C_CTRL_SDA_OUT_SEL, RTL9310_I2C_CTRL);
mux->i2c->sda_num = channels[chan].sda_num;
mux->i2c->scl_num = channels[chan].scl_num;
return 0;
}
static int rtl9300_i2c_mux_deselect(struct i2c_mux_core *muxc, u32 chan)
{
return 0;
}
static void rtl9300_sda_sel(struct i2c_mux_core *muxc, int pin)
{
struct rtl9300_mux *mux = i2c_mux_priv(muxc);
u32 v;
/* Set SDA pin to I2C functionality */
v = readl(REG(0, RTL9300_I2C_MST_GLB_CTRL));
v |= BIT(pin);
writel(v, REG(0, RTL9300_I2C_MST_GLB_CTRL));
}
static void rtl9310_sda_sel(struct i2c_mux_core *muxc, int pin)
{
struct rtl9300_mux *mux = i2c_mux_priv(muxc);
u32 v;
/* Set SDA pin to I2C functionality */
v = readl(REG(0, RTL9310_I2C_MST_IF_SEL));
v |= BIT(pin);
writel(v, REG(0, RTL9310_I2C_MST_IF_SEL));
}
static struct device_node *mux_parent_adapter(struct device *dev, struct rtl9300_mux *mux)
{
struct device_node *node = dev->of_node;
struct device_node *parent_np;
struct i2c_adapter *parent;
parent_np = of_parse_phandle(node, "i2c-parent", 0);
if (!parent_np) {
dev_err(dev, "Cannot parse i2c-parent\n");
return ERR_PTR(-ENODEV);
}
parent = of_find_i2c_adapter_by_node(parent_np);
of_node_put(parent_np);
if (!parent)
return ERR_PTR(-EPROBE_DEFER);
if (!(of_device_is_compatible(parent_np, "realtek,rtl9300-i2c") ||
of_device_is_compatible(parent_np, "realtek,rtl9310-i2c"))){
dev_err(dev, "I2C parent not an RTL9300 I2C controller\n");
return ERR_PTR(-ENODEV);
}
mux->parent = parent;
mux->i2c = (struct rtl9300_i2c *)i2c_get_adapdata(parent);
mux->base = mux->i2c->base;
return parent_np;
}
struct i2c_mux_data rtl9300_i2c_mux_data = {
.scl0_pin = 8,
.scl1_pin = 17,
.sda0_pin = 9,
.sda_pins = 8,
.i2c_mux_select = rtl9300_i2c_mux_select,
.i2c_mux_deselect = rtl9300_i2c_mux_deselect,
.sda_sel = rtl9300_sda_sel,
};
struct i2c_mux_data rtl9310_i2c_mux_data = {
.scl0_pin = 13,
.scl1_pin = 14,
.sda0_pin = 0,
.sda_pins = 16,
.i2c_mux_select = rtl9310_i2c_mux_select,
.i2c_mux_deselect = rtl9300_i2c_mux_deselect,
.sda_sel = rtl9310_sda_sel,
};
static const struct of_device_id rtl9300_i2c_mux_of_match[] = {
{ .compatible = "realtek,i2c-mux-rtl9300", .data = (void *) &rtl9300_i2c_mux_data},
{ .compatible = "realtek,i2c-mux-rtl9310", .data = (void *) &rtl9310_i2c_mux_data},
{},
};
MODULE_DEVICE_TABLE(of, rtl9300_i2c_mux_of_match);
static int rtl9300_i2c_mux_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct device_node *node = dev->of_node;
struct device_node *parent_np;
struct device_node *child;
struct i2c_mux_core *muxc;
struct rtl9300_mux *mux;
struct i2c_mux_data *mux_data;
int children;
int ret;
pr_info("%s probing I2C adapter\n", __func__);
if (!node) {
dev_err(dev, "No DT found\n");
return -EINVAL;
}
mux = devm_kzalloc(dev, sizeof(*mux), GFP_KERNEL);
if (!mux)
return -ENOMEM;
mux->dev = dev;
mux_data = (struct i2c_mux_data *) device_get_match_data(dev);
parent_np = mux_parent_adapter(dev, mux);
if (IS_ERR(parent_np))
return dev_err_probe(dev, PTR_ERR(parent_np), "i2c-parent adapter not found\n");
pr_info("%s base memory %08x\n", __func__, (u32)mux->base);
children = of_get_child_count(node);
muxc = i2c_mux_alloc(mux->parent, dev, children, 0, 0,
mux_data->i2c_mux_select, mux_data->i2c_mux_deselect);
if (!muxc) {
ret = -ENOMEM;
goto err_parent;
}
muxc->priv = mux;
platform_set_drvdata(pdev, muxc);
for_each_child_of_node(node, child) {
u32 chan;
u32 pin;
ret = of_property_read_u32(child, "reg", &chan);
if (ret < 0) {
dev_err(dev, "no reg property for node '%pOFn'\n",
child);
goto err_children;
}
if (chan >= NUM_MASTERS * NUM_BUSSES) {
dev_err(dev, "invalid reg %u\n", chan);
ret = -EINVAL;
goto err_children;
}
if (of_property_read_u32(child, "scl-pin", &pin)) {
dev_warn(dev, "SCL pin not found in DT, using default\n");
pin = mux_data->scl0_pin;
}
if (!(pin == mux_data->scl0_pin || pin == mux_data->scl1_pin)) {
dev_warn(dev, "SCL pin %d not supported\n", pin);
ret = -EINVAL;
goto err_children;
}
channels[chan].scl_num = pin == mux_data->scl0_pin ? 0 : 1;
pr_info("%s channel %d scl_num %d\n", __func__, chan, channels[chan].scl_num);
if (of_property_read_u32(child, "sda-pin", &pin)) {
dev_warn(dev, "SDA pin not found in DT, using default \n");
pin = mux_data->sda0_pin;
}
channels[chan].sda_num = pin - mux_data->sda0_pin;
if (channels[chan].sda_num < 0 || channels[chan].sda_num >= mux_data->sda_pins) {
dev_warn(dev, "SDA pin %d not supported\n", pin);
return -EINVAL;
}
pr_info("%s channel %d sda_num %d\n", __func__, chan, channels[chan].sda_num);
mux_data->sda_sel(muxc, channels[chan].sda_num);
ret = i2c_mux_add_adapter(muxc, 0, chan, 0);
if (ret)
goto err_children;
}
dev_info(dev, "%d-port mux on %s adapter\n", children, mux->parent->name);
return 0;
err_children:
i2c_mux_del_adapters(muxc);
err_parent:
i2c_put_adapter(mux->parent);
return ret;
}
static int rtl9300_i2c_mux_remove(struct platform_device *pdev)
{
struct i2c_mux_core *muxc = platform_get_drvdata(pdev);
i2c_mux_del_adapters(muxc);
i2c_put_adapter(muxc->parent);
return 0;
}
static struct platform_driver i2c_mux_driver = {
.probe = rtl9300_i2c_mux_probe,
.remove = rtl9300_i2c_mux_remove,
.driver = {
.name = "i2c-mux-rtl9300",
.of_match_table = rtl9300_i2c_mux_of_match,
},
};
module_platform_driver(i2c_mux_driver);
MODULE_DESCRIPTION("RTL9300 I2C multiplexer driver");
MODULE_AUTHOR("Birger Koblitz");
MODULE_LICENSE("GPL v2");

View File

@ -0,0 +1,7 @@
# SPDX-License-Identifier: GPL-2.0-only
config NET_DSA_RTL83XX
tristate "Realtek RTL838x/RTL839x switch support"
depends on RTL83XX
select NET_DSA_TAG_TRAILER
help
This driver adds support for Realtek RTL83xx series switching.

View File

@ -0,0 +1,3 @@
# SPDX-License-Identifier: GPL-2.0
obj-$(CONFIG_NET_DSA_RTL83XX) += common.o dsa.o \
rtl838x.o rtl839x.o rtl930x.o rtl931x.o debugfs.o qos.o tc.o

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,719 @@
// SPDX-License-Identifier: GPL-2.0-only
#include <linux/debugfs.h>
#include <linux/kernel.h>
#include <asm/mach-rtl838x/mach-rtl83xx.h>
#include "rtl83xx.h"
#define RTL838X_DRIVER_NAME "rtl838x"
#define RTL8390_LED_GLB_CTRL (0x00E4)
#define RTL8390_LED_SET_2_3_CTRL (0x00E8)
#define RTL8390_LED_SET_0_1_CTRL (0x00EC)
#define RTL8390_LED_COPR_SET_SEL_CTRL(p) (0x00F0 + (((p >> 4) << 2)))
#define RTL8390_LED_FIB_SET_SEL_CTRL(p) (0x0100 + (((p >> 4) << 2)))
#define RTL8390_LED_COPR_PMASK_CTRL(p) (0x0110 + (((p >> 5) << 2)))
#define RTL8390_LED_FIB_PMASK_CTRL(p) (0x00118 + (((p >> 5) << 2)))
#define RTL8390_LED_COMBO_CTRL(p) (0x0120 + (((p >> 5) << 2)))
#define RTL8390_LED_SW_CTRL (0x0128)
#define RTL8390_LED_SW_P_EN_CTRL(p) (0x012C + (((p / 10) << 2)))
#define RTL8390_LED_SW_P_CTRL(p) (0x0144 + (((p) << 2)))
#define RTL838X_MIR_QID_CTRL(grp) (0xAD44 + (((grp) << 2)))
#define RTL838X_MIR_RSPAN_VLAN_CTRL(grp) (0xA340 + (((grp) << 2)))
#define RTL838X_MIR_RSPAN_VLAN_CTRL_MAC(grp) (0xAA70 + (((grp) << 2)))
#define RTL838X_MIR_RSPAN_TX_CTRL (0xA350)
#define RTL838X_MIR_RSPAN_TX_TAG_RM_CTRL (0xAA80)
#define RTL838X_MIR_RSPAN_TX_TAG_EN_CTRL (0xAA84)
#define RTL839X_MIR_RSPAN_VLAN_CTRL(grp) (0xA340 + (((grp) << 2)))
#define RTL839X_MIR_RSPAN_TX_CTRL (0x69b0)
#define RTL839X_MIR_RSPAN_TX_TAG_RM_CTRL (0x2550)
#define RTL839X_MIR_RSPAN_TX_TAG_EN_CTRL (0x2554)
#define RTL839X_MIR_SAMPLE_RATE_CTRL (0x2558)
#define RTL838X_STAT_PRVTE_DROP_COUNTERS (0x6A00)
#define RTL839X_STAT_PRVTE_DROP_COUNTERS (0x3E00)
#define RTL930X_STAT_PRVTE_DROP_COUNTERS (0xB5B8)
#define RTL931X_STAT_PRVTE_DROP_COUNTERS (0xd800)
int rtl83xx_port_get_stp_state(struct rtl838x_switch_priv *priv, int port);
void rtl83xx_port_stp_state_set(struct dsa_switch *ds, int port, u8 state);
void rtl83xx_fast_age(struct dsa_switch *ds, int port);
u32 rtl838x_get_egress_rate(struct rtl838x_switch_priv *priv, int port);
u32 rtl839x_get_egress_rate(struct rtl838x_switch_priv *priv, int port);
int rtl838x_set_egress_rate(struct rtl838x_switch_priv *priv, int port, u32 rate);
int rtl839x_set_egress_rate(struct rtl838x_switch_priv *priv, int port, u32 rate);
const char *rtl838x_drop_cntr[] = {
"ALE_TX_GOOD_PKTS", "MAC_RX_DROP", "ACL_FWD_DROP", "HW_ATTACK_PREVENTION_DROP",
"RMA_DROP", "VLAN_IGR_FLTR_DROP", "INNER_OUTER_CFI_EQUAL_1_DROP", "PORT_MOVE_DROP",
"NEW_SA_DROP", "MAC_LIMIT_SYS_DROP", "MAC_LIMIT_VLAN_DROP", "MAC_LIMIT_PORT_DROP",
"SWITCH_MAC_DROP", "ROUTING_EXCEPTION_DROP", "DA_LKMISS_DROP", "RSPAN_DROP",
"ACL_LKMISS_DROP", "ACL_DROP", "INBW_DROP", "IGR_METER_DROP",
"ACCEPT_FRAME_TYPE_DROP", "STP_IGR_DROP", "INVALID_SA_DROP", "SA_BLOCKING_DROP",
"DA_BLOCKING_DROP", "L2_INVALID_DPM_DROP", "MCST_INVALID_DPM_DROP", "RX_FLOW_CONTROL_DROP",
"STORM_SPPRS_DROP", "LALS_DROP", "VLAN_EGR_FILTER_DROP", "STP_EGR_DROP",
"SRC_PORT_FILTER_DROP", "PORT_ISOLATION_DROP", "ACL_FLTR_DROP", "MIRROR_FLTR_DROP",
"TX_MAX_DROP", "LINK_DOWN_DROP", "FLOW_CONTROL_DROP", "BRIDGE .1d discards"
};
const char *rtl839x_drop_cntr[] = {
"ALE_TX_GOOD_PKTS", "ERROR_PKTS", "EGR_ACL_DROP", "EGR_METER_DROP",
"OAM", "CFM" "VLAN_IGR_FLTR", "VLAN_ERR",
"INNER_OUTER_CFI_EQUAL_1", "VLAN_TAG_FORMAT", "SRC_PORT_SPENDING_TREE", "INBW",
"RMA", "HW_ATTACK_PREVENTION", "PROTO_STORM", "MCAST_SA",
"IGR_ACL_DROP", "IGR_METER_DROP", "DFLT_ACTION_FOR_MISS_ACL_AND_C2SC", "NEW_SA",
"PORT_MOVE", "SA_BLOCKING", "ROUTING_EXCEPTION", "SRC_PORT_SPENDING_TREE_NON_FWDING",
"MAC_LIMIT", "UNKNOW_STORM", "MISS_DROP", "CPU_MAC_DROP",
"DA_BLOCKING", "SRC_PORT_FILTER_BEFORE_EGR_ACL", "VLAN_EGR_FILTER", "SPANNING_TRE",
"PORT_ISOLATION", "OAM_EGRESS_DROP", "MIRROR_ISOLATION", "MAX_LEN_BEFORE_EGR_ACL",
"SRC_PORT_FILTER_BEFORE_MIRROR", "MAX_LEN_BEFORE_MIRROR", "SPECIAL_CONGEST_BEFORE_MIRROR",
"LINK_STATUS_BEFORE_MIRROR",
"WRED_BEFORE_MIRROR", "MAX_LEN_AFTER_MIRROR", "SPECIAL_CONGEST_AFTER_MIRROR",
"LINK_STATUS_AFTER_MIRROR",
"WRED_AFTER_MIRROR"
};
const char *rtl930x_drop_cntr[] = {
"OAM_PARSER", "UC_RPF", "DEI_CFI", "MAC_IP_SUBNET_BASED_VLAN", "VLAN_IGR_FILTER",
"L2_UC_MC", "IPV_IP6_MC_BRIDGE", "PTP", "USER_DEF_0_3", "RESERVED",
"RESERVED1", "RESERVED2", "BPDU_RMA", "LACP", "LLDP",
"EAPOL", "XX_RMA", "L3_IPUC_NON_IP", "IP4_IP6_HEADER_ERROR", "L3_BAD_IP",
"L3_DIP_DMAC_MISMATCH", "IP4_IP_OPTION", "IP_UC_MC_ROUTING_LOOK_UP_MISS", "L3_DST_NULL_INTF",
"L3_PBR_NULL_INTF",
"HOST_NULL_INTF", "ROUTE_NULL_INTF", "BRIDGING_ACTION", "ROUTING_ACTION", "IPMC_RPF",
"L2_NEXTHOP_AGE_OUT", "L3_UC_TTL_FAIL", "L3_MC_TTL_FAIL", "L3_UC_MTU_FAIL", "L3_MC_MTU_FAIL",
"L3_UC_ICMP_REDIR", "IP6_MLD_OTHER_ACT", "ND", "IP_MC_RESERVED", "IP6_HBH",
"INVALID_SA", "L2_HASH_FULL", "NEW_SA", "PORT_MOVE_FORBID", "STATIC_PORT_MOVING",
"DYNMIC_PORT_MOVING", "L3_CRC", "MAC_LIMIT", "ATTACK_PREVENT", "ACL_FWD_ACTION",
"OAMPDU", "OAM_MUX", "TRUNK_FILTER", "ACL_DROP", "IGR_BW",
"ACL_METER", "VLAN_ACCEPT_FRAME_TYPE", "MSTP_SRC_DROP_DISABLED_BLOCKING", "SA_BLOCK", "DA_BLOCK",
"STORM_CONTROL", "VLAN_EGR_FILTER", "MSTP_DESTINATION_DROP", "SRC_PORT_FILTER", "PORT_ISOLATION",
"TX_MAX_FRAME_SIZE", "EGR_LINK_STATUS", "MAC_TX_DISABLE", "MAC_PAUSE_FRAME", "MAC_RX_DROP",
"MIRROR_ISOLATE", "RX_FC", "EGR_QUEUE", "HSM_RUNOUT", "ROUTING_DISABLE", "INVALID_L2_NEXTHOP_ENTRY",
"L3_MC_SRC_FLT", "CPUTAG_FLT", "FWD_PMSK_NULL", "IPUC_ROUTING_LOOKUP_MISS", "MY_DEV_DROP",
"STACK_NONUC_BLOCKING_PMSK", "STACK_PORT_NOT_FOUND", "ACL_LOOPBACK_DROP", "IP6_ROUTING_EXT_HEADER"
};
const char *rtl931x_drop_cntr[] = {
"ALE_RX_GOOD_PKTS", "RX_MAX_FRAME_SIZE", "MAC_RX_DROP", "OPENFLOW_IP_MPLS_TTL", "OPENFLOW_TBL_MISS",
"IGR_BW", "SPECIAL_CONGEST", "EGR_QUEUE", "RESERVED", "EGR_LINK_STATUS", "STACK_UCAST_NONUCAST_TTL", /* 10 */
"STACK_NONUC_BLOCKING_PMSK", "L2_CRC", "SRC_PORT_FILTER", "PARSER_PACKET_TOO_LONG", "PARSER_MALFORM_PACKET",
"MPLS_OVER_2_LBL", "EACL_METER", "IACL_METER", "PROTO_STORM", "INVALID_CAPWAP_HEADER", /* 20 */
"MAC_IP_SUBNET_BASED_VLAN", "OAM_PARSER", "UC_MC_RPF", "IP_MAC_BINDING_MATCH_MISMATCH", "SA_BLOCK",
"TUNNEL_IP_ADDRESS_CHECK", "EACL_DROP", "IACL_DROP", "ATTACK_PREVENT", "SYSTEM_PORT_LIMIT_LEARN", /* 30 */
"OAMPDU", "CCM_RX", "CFM_UNKNOWN_TYPE", "LBM_LBR_LTM_LTR", "Y_1731", "VLAN_LIMIT_LEARN",
"VLAN_ACCEPT_FRAME_TYPE", "CFI_1", "STATIC_DYNAMIC_PORT_MOVING", "PORT_MOVE_FORBID", /* 40 */
"L3_CRC", "BPDU_PTP_LLDP_EAPOL_RMA", "MSTP_SRC_DROP_DISABLED_BLOCKING", "INVALID_SA", "NEW_SA",
"VLAN_IGR_FILTER", "IGR_VLAN_CONVERT", "GRATUITOUS_ARP", "MSTP_SRC_DROP", "L2_HASH_FULL", /* 50 */
"MPLS_UNKNOWN_LBL", "L3_IPUC_NON_IP", "TTL", "MTU", "ICMP_REDIRECT", "STORM_CONTROL", "L3_DIP_DMAC_MISMATCH",
"IP4_IP_OPTION", "IP6_HBH_EXT_HEADER", "IP4_IP6_HEADER_ERROR", /* 60 */
"ROUTING_IP_ADDR_CHECK", "ROUTING_EXCEPTION", "DA_BLOCK", "OAM_MUX", "PORT_ISOLATION", "VLAN_EGR_FILTER",
"MIRROR_ISOLATE", "MSTP_DESTINATION_DROP", "L2_MC_BRIDGE", "IP_UC_MC_ROUTING_LOOK_UP_MISS", /* 70 */
"L2_UC", "L2_MC", "IP4_MC", "IP6_MC", "L3_UC_MC_ROUTE", "UNKNOWN_L2_UC_FLPM", "BC_FLPM",
"VLAN_PRO_UNKNOWN_L2_MC_FLPM", "VLAN_PRO_UNKNOWN_IP4_MC_FLPM", "VLAN_PROFILE_UNKNOWN_IP6_MC_FLPM", /* 80 */
};
static ssize_t rtl838x_common_read(char __user *buffer, size_t count,
loff_t *ppos, unsigned int value)
{
char *buf;
ssize_t len;
if (*ppos != 0)
return 0;
buf = kasprintf(GFP_KERNEL, "0x%08x\n", value);
if (!buf)
return -ENOMEM;
if (count < strlen(buf)) {
kfree(buf);
return -ENOSPC;
}
len = simple_read_from_buffer(buffer, count, ppos, buf, strlen(buf));
kfree(buf);
return len;
}
static ssize_t rtl838x_common_write(const char __user *buffer, size_t count,
loff_t *ppos, unsigned int *value)
{
char b[32];
ssize_t len;
int ret;
if (*ppos != 0)
return -EINVAL;
if (count >= sizeof(b))
return -ENOSPC;
len = simple_write_to_buffer(b, sizeof(b) - 1, ppos,
buffer, count);
if (len < 0)
return len;
b[len] = '\0';
ret = kstrtouint(b, 16, value);
if (ret)
return -EIO;
return len;
}
static ssize_t stp_state_read(struct file *filp, char __user *buffer, size_t count,
loff_t *ppos)
{
struct rtl838x_port *p = filp->private_data;
struct dsa_switch *ds = p->dp->ds;
int value = rtl83xx_port_get_stp_state(ds->priv, p->dp->index);
if (value < 0)
return -EINVAL;
return rtl838x_common_read(buffer, count, ppos, (u32)value);
}
static ssize_t stp_state_write(struct file *filp, const char __user *buffer,
size_t count, loff_t *ppos)
{
struct rtl838x_port *p = filp->private_data;
u32 value;
size_t res = rtl838x_common_write(buffer, count, ppos, &value);
if (res < 0)
return res;
rtl83xx_port_stp_state_set(p->dp->ds, p->dp->index, (u8)value);
return res;
}
static const struct file_operations stp_state_fops = {
.owner = THIS_MODULE,
.open = simple_open,
.read = stp_state_read,
.write = stp_state_write,
};
static ssize_t drop_counter_read(struct file *filp, char __user *buffer, size_t count,
loff_t *ppos)
{
struct rtl838x_switch_priv *priv = filp->private_data;
const char **d;
u32 v;
char *buf;
int n = 0, len, offset;
int num;
switch (priv->family_id) {
case RTL8380_FAMILY_ID:
d = rtl838x_drop_cntr;
offset = RTL838X_STAT_PRVTE_DROP_COUNTERS;
num = 40;
break;
case RTL8390_FAMILY_ID:
d = rtl839x_drop_cntr;
offset = RTL839X_STAT_PRVTE_DROP_COUNTERS;
num = 45;
break;
case RTL9300_FAMILY_ID:
d = rtl930x_drop_cntr;
offset = RTL930X_STAT_PRVTE_DROP_COUNTERS;
num = 85;
break;
case RTL9310_FAMILY_ID:
d = rtl931x_drop_cntr;
offset = RTL931X_STAT_PRVTE_DROP_COUNTERS;
num = 81;
break;
}
buf = kmalloc(30 * num, GFP_KERNEL);
if (!buf)
return -ENOMEM;
for (int i = 0; i < num; i++) {
v = sw_r32(offset + (i << 2)) & 0xffff;
n += sprintf(buf + n, "%s: %d\n", d[i], v);
}
if (count < strlen(buf)) {
kfree(buf);
return -ENOSPC;
}
len = simple_read_from_buffer(buffer, count, ppos, buf, strlen(buf));
kfree(buf);
return len;
}
static const struct file_operations drop_counter_fops = {
.owner = THIS_MODULE,
.open = simple_open,
.read = drop_counter_read,
};
static void l2_table_print_entry(struct seq_file *m, struct rtl838x_switch_priv *priv,
struct rtl838x_l2_entry *e)
{
u64 portmask;
if (e->type == L2_UNICAST) {
seq_puts(m, "L2_UNICAST\n");
seq_printf(m, " mac %02x:%02x:%02x:%02x:%02x:%02x vid %u rvid %u\n",
e->mac[0], e->mac[1], e->mac[2], e->mac[3], e->mac[4], e->mac[5],
e->vid, e->rvid);
seq_printf(m, " port %d age %d", e->port, e->age);
if (e->is_static)
seq_puts(m, " static");
if (e->block_da)
seq_puts(m, " block_da");
if (e->block_sa)
seq_puts(m, " block_sa");
if (e->suspended)
seq_puts(m, " suspended");
if (e->next_hop)
seq_printf(m, " next_hop route_id %u", e->nh_route_id);
seq_puts(m, "\n");
} else {
if (e->type == L2_MULTICAST) {
seq_puts(m, "L2_MULTICAST\n");
seq_printf(m, " mac %02x:%02x:%02x:%02x:%02x:%02x vid %u rvid %u\n",
e->mac[0], e->mac[1], e->mac[2], e->mac[3], e->mac[4], e->mac[5],
e->vid, e->rvid);
}
if (e->type == IP4_MULTICAST || e->type == IP6_MULTICAST) {
seq_puts(m, (e->type == IP4_MULTICAST) ?
"IP4_MULTICAST\n" : "IP6_MULTICAST\n");
seq_printf(m, " gip %08x sip %08x vid %u rvid %u\n",
e->mc_gip, e->mc_sip, e->vid, e->rvid);
}
portmask = priv->r->read_mcast_pmask(e->mc_portmask_index);
seq_printf(m, " index %u ports", e->mc_portmask_index);
for (int i = 0; i < 64; i++) {
if (portmask & BIT_ULL(i))
seq_printf(m, " %d", i);
}
seq_puts(m, "\n");
}
seq_puts(m, "\n");
}
static int l2_table_show(struct seq_file *m, void *v)
{
struct rtl838x_switch_priv *priv = m->private;
struct rtl838x_l2_entry e;
int bucket, index;
mutex_lock(&priv->reg_mutex);
for (int i = 0; i < priv->fib_entries; i++) {
bucket = i >> 2;
index = i & 0x3;
priv->r->read_l2_entry_using_hash(bucket, index, &e);
if (!e.valid)
continue;
seq_printf(m, "Hash table bucket %d index %d ", bucket, index);
l2_table_print_entry(m, priv, &e);
if (!((i + 1) % 64))
cond_resched();
}
for (int i = 0; i < 64; i++) {
priv->r->read_cam(i, &e);
if (!e.valid)
continue;
seq_printf(m, "CAM index %d ", i);
l2_table_print_entry(m, priv, &e);
}
mutex_unlock(&priv->reg_mutex);
return 0;
}
static int l2_table_open(struct inode *inode, struct file *filp)
{
return single_open(filp, l2_table_show, inode->i_private);
}
static const struct file_operations l2_table_fops = {
.owner = THIS_MODULE,
.open = l2_table_open,
.read = seq_read,
.llseek = seq_lseek,
.release = single_release,
};
static ssize_t age_out_read(struct file *filp, char __user *buffer, size_t count,
loff_t *ppos)
{
struct rtl838x_port *p = filp->private_data;
struct dsa_switch *ds = p->dp->ds;
struct rtl838x_switch_priv *priv = ds->priv;
int value = sw_r32(priv->r->l2_port_aging_out);
if (value < 0)
return -EINVAL;
return rtl838x_common_read(buffer, count, ppos, (u32)value);
}
static ssize_t age_out_write(struct file *filp, const char __user *buffer,
size_t count, loff_t *ppos)
{
struct rtl838x_port *p = filp->private_data;
u32 value;
size_t res = rtl838x_common_write(buffer, count, ppos, &value);
if (res < 0)
return res;
rtl83xx_fast_age(p->dp->ds, p->dp->index);
return res;
}
static const struct file_operations age_out_fops = {
.owner = THIS_MODULE,
.open = simple_open,
.read = age_out_read,
.write = age_out_write,
};
static ssize_t port_egress_rate_read(struct file *filp, char __user *buffer, size_t count,
loff_t *ppos)
{
struct rtl838x_port *p = filp->private_data;
struct dsa_switch *ds = p->dp->ds;
struct rtl838x_switch_priv *priv = ds->priv;
int value;
if (priv->family_id == RTL8380_FAMILY_ID)
value = rtl838x_get_egress_rate(priv, p->dp->index);
else
value = rtl839x_get_egress_rate(priv, p->dp->index);
if (value < 0)
return -EINVAL;
return rtl838x_common_read(buffer, count, ppos, (u32)value);
}
static ssize_t port_egress_rate_write(struct file *filp, const char __user *buffer,
size_t count, loff_t *ppos)
{
struct rtl838x_port *p = filp->private_data;
struct dsa_switch *ds = p->dp->ds;
struct rtl838x_switch_priv *priv = ds->priv;
u32 value;
size_t res = rtl838x_common_write(buffer, count, ppos, &value);
if (res < 0)
return res;
if (priv->family_id == RTL8380_FAMILY_ID)
rtl838x_set_egress_rate(priv, p->dp->index, value);
else
rtl839x_set_egress_rate(priv, p->dp->index, value);
return res;
}
static const struct file_operations port_egress_fops = {
.owner = THIS_MODULE,
.open = simple_open,
.read = port_egress_rate_read,
.write = port_egress_rate_write,
};
static const struct debugfs_reg32 port_ctrl_regs[] = {
{ .name = "port_isolation", .offset = RTL838X_PORT_ISO_CTRL(0), },
{ .name = "mac_force_mode", .offset = RTL838X_MAC_FORCE_MODE_CTRL, },
};
void rtl838x_dbgfs_cleanup(struct rtl838x_switch_priv *priv)
{
debugfs_remove_recursive(priv->dbgfs_dir);
/* kfree(priv->dbgfs_entries); */
}
static int rtl838x_dbgfs_port_init(struct dentry *parent, struct rtl838x_switch_priv *priv,
int port)
{
struct dentry *port_dir;
struct debugfs_regset32 *port_ctrl_regset;
port_dir = debugfs_create_dir(priv->ports[port].dp->name, parent);
if (priv->family_id == RTL8380_FAMILY_ID) {
debugfs_create_x32("storm_rate_uc", 0644, port_dir,
(u32 *)(RTL838X_SW_BASE + RTL838X_STORM_CTRL_PORT_UC(port)));
debugfs_create_x32("storm_rate_mc", 0644, port_dir,
(u32 *)(RTL838X_SW_BASE + RTL838X_STORM_CTRL_PORT_MC(port)));
debugfs_create_x32("storm_rate_bc", 0644, port_dir,
(u32 *)(RTL838X_SW_BASE + RTL838X_STORM_CTRL_PORT_BC(port)));
} else {
debugfs_create_x32("storm_rate_uc", 0644, port_dir,
(u32 *)(RTL838X_SW_BASE + RTL839X_STORM_CTRL_PORT_UC_0(port)));
debugfs_create_x32("storm_rate_mc", 0644, port_dir,
(u32 *)(RTL838X_SW_BASE + RTL839X_STORM_CTRL_PORT_MC_0(port)));
debugfs_create_x32("storm_rate_bc", 0644, port_dir,
(u32 *)(RTL838X_SW_BASE + RTL839X_STORM_CTRL_PORT_BC_0(port)));
}
debugfs_create_u32("id", 0444, port_dir, (u32 *)&priv->ports[port].dp->index);
port_ctrl_regset = devm_kzalloc(priv->dev, sizeof(*port_ctrl_regset), GFP_KERNEL);
if (!port_ctrl_regset)
return -ENOMEM;
port_ctrl_regset->regs = port_ctrl_regs;
port_ctrl_regset->nregs = ARRAY_SIZE(port_ctrl_regs);
port_ctrl_regset->base = (void *)(RTL838X_SW_BASE + (port << 2));
debugfs_create_regset32("port_ctrl", 0400, port_dir, port_ctrl_regset);
debugfs_create_file("stp_state", 0600, port_dir, &priv->ports[port], &stp_state_fops);
debugfs_create_file("age_out", 0600, port_dir, &priv->ports[port], &age_out_fops);
debugfs_create_file("port_egress_rate", 0600, port_dir, &priv->ports[port],
&port_egress_fops);
return 0;
}
static int rtl838x_dbgfs_leds(struct dentry *parent, struct rtl838x_switch_priv *priv)
{
struct dentry *led_dir;
led_dir = debugfs_create_dir("led", parent);
if (priv->family_id == RTL8380_FAMILY_ID) {
debugfs_create_x32("led_glb_ctrl", 0644, led_dir,
(u32 *)(RTL838X_SW_BASE + RTL838X_LED_GLB_CTRL));
debugfs_create_x32("led_mode_sel", 0644, led_dir,
(u32 *)(RTL838X_SW_BASE + RTL838X_LED_MODE_SEL));
debugfs_create_x32("led_mode_ctrl", 0644, led_dir,
(u32 *)(RTL838X_SW_BASE + RTL838X_LED_MODE_CTRL));
debugfs_create_x32("led_p_en_ctrl", 0644, led_dir,
(u32 *)(RTL838X_SW_BASE + RTL838X_LED_P_EN_CTRL));
debugfs_create_x32("led_sw_ctrl", 0644, led_dir,
(u32 *)(RTL838X_SW_BASE + RTL838X_LED_SW_CTRL));
debugfs_create_x32("led0_sw_p_en_ctrl", 0644, led_dir,
(u32 *)(RTL838X_SW_BASE + RTL838X_LED0_SW_P_EN_CTRL));
debugfs_create_x32("led1_sw_p_en_ctrl", 0644, led_dir,
(u32 *)(RTL838X_SW_BASE + RTL838X_LED1_SW_P_EN_CTRL));
debugfs_create_x32("led2_sw_p_en_ctrl", 0644, led_dir,
(u32 *)(RTL838X_SW_BASE + RTL838X_LED2_SW_P_EN_CTRL));
for (int p = 0; p < 28; p++) {
char led_sw_p_ctrl_name[20];
snprintf(led_sw_p_ctrl_name, sizeof(led_sw_p_ctrl_name),
"led_sw_p_ctrl.%02d", p);
debugfs_create_x32(led_sw_p_ctrl_name, 0644, led_dir,
(u32 *)(RTL838X_SW_BASE + RTL838X_LED_SW_P_CTRL_PORT(p)));
}
} else if (priv->family_id == RTL8390_FAMILY_ID) {
char port_led_name[20];
debugfs_create_x32("led_glb_ctrl", 0644, led_dir,
(u32 *)(RTL838X_SW_BASE + RTL8390_LED_GLB_CTRL));
debugfs_create_x32("led_set_2_3", 0644, led_dir,
(u32 *)(RTL838X_SW_BASE + RTL8390_LED_SET_2_3_CTRL));
debugfs_create_x32("led_set_0_1", 0644, led_dir,
(u32 *)(RTL838X_SW_BASE + RTL8390_LED_SET_0_1_CTRL));
for (int p = 0; p < 4; p++) {
snprintf(port_led_name, sizeof(port_led_name), "led_copr_set_sel.%1d", p);
debugfs_create_x32(port_led_name, 0644, led_dir,
(u32 *)(RTL838X_SW_BASE + RTL8390_LED_COPR_SET_SEL_CTRL(p << 4)));
snprintf(port_led_name, sizeof(port_led_name), "led_fib_set_sel.%1d", p);
debugfs_create_x32(port_led_name, 0644, led_dir,
(u32 *)(RTL838X_SW_BASE + RTL8390_LED_FIB_SET_SEL_CTRL(p << 4)));
}
debugfs_create_x32("led_copr_pmask_ctrl_0", 0644, led_dir,
(u32 *)(RTL838X_SW_BASE + RTL8390_LED_COPR_PMASK_CTRL(0)));
debugfs_create_x32("led_copr_pmask_ctrl_1", 0644, led_dir,
(u32 *)(RTL838X_SW_BASE + RTL8390_LED_COPR_PMASK_CTRL(32)));
debugfs_create_x32("led_fib_pmask_ctrl_0", 0644, led_dir,
(u32 *)(RTL838X_SW_BASE + RTL8390_LED_FIB_PMASK_CTRL(0)));
debugfs_create_x32("led_fib_pmask_ctrl_1", 0644, led_dir,
(u32 *)(RTL838X_SW_BASE + RTL8390_LED_FIB_PMASK_CTRL(32)));
debugfs_create_x32("led_combo_ctrl_0", 0644, led_dir,
(u32 *)(RTL838X_SW_BASE + RTL8390_LED_COMBO_CTRL(0)));
debugfs_create_x32("led_combo_ctrl_1", 0644, led_dir,
(u32 *)(RTL838X_SW_BASE + RTL8390_LED_COMBO_CTRL(32)));
debugfs_create_x32("led_sw_ctrl", 0644, led_dir,
(u32 *)(RTL838X_SW_BASE + RTL8390_LED_SW_CTRL));
for (int p = 0; p < 5; p++) {
snprintf(port_led_name, sizeof(port_led_name), "led_sw_p_en_ctrl.%1d", p);
debugfs_create_x32(port_led_name, 0644, led_dir,
(u32 *)(RTL838X_SW_BASE + RTL8390_LED_SW_P_EN_CTRL(p * 10)));
}
for (int p = 0; p < 28; p++) {
snprintf(port_led_name, sizeof(port_led_name), "led_sw_p_ctrl.%02d", p);
debugfs_create_x32(port_led_name, 0644, led_dir,
(u32 *)(RTL838X_SW_BASE + RTL8390_LED_SW_P_CTRL(p)));
}
}
return 0;
}
void rtl838x_dbgfs_init(struct rtl838x_switch_priv *priv)
{
struct dentry *rtl838x_dir;
struct dentry *port_dir;
struct dentry *mirror_dir;
struct debugfs_regset32 *port_ctrl_regset;
int ret;
char lag_name[10];
char mirror_name[10];
pr_info("%s called\n", __func__);
rtl838x_dir = debugfs_lookup(RTL838X_DRIVER_NAME, NULL);
if (!rtl838x_dir)
rtl838x_dir = debugfs_create_dir(RTL838X_DRIVER_NAME, NULL);
priv->dbgfs_dir = rtl838x_dir;
debugfs_create_x32("soc", 0444, rtl838x_dir,
(u32 *)(RTL838X_SW_BASE + RTL838X_MODEL_NAME_INFO));
/* Create one directory per port */
for (int i = 0; i < priv->cpu_port; i++) {
if (priv->ports[i].phy) {
ret = rtl838x_dbgfs_port_init(rtl838x_dir, priv, i);
if (ret)
goto err;
}
}
/* Create directory for CPU-port */
port_dir = debugfs_create_dir("cpu_port", rtl838x_dir);
port_ctrl_regset = devm_kzalloc(priv->dev, sizeof(*port_ctrl_regset), GFP_KERNEL);
if (!port_ctrl_regset) {
ret = -ENOMEM;
goto err;
}
port_ctrl_regset->regs = port_ctrl_regs;
port_ctrl_regset->nregs = ARRAY_SIZE(port_ctrl_regs);
port_ctrl_regset->base = (void *)(RTL838X_SW_BASE + (priv->cpu_port << 2));
debugfs_create_regset32("port_ctrl", 0400, port_dir, port_ctrl_regset);
debugfs_create_u8("id", 0444, port_dir, &priv->cpu_port);
/* Create entries for LAGs */
for (int i = 0; i < priv->n_lags; i++) {
snprintf(lag_name, sizeof(lag_name), "lag.%02d", i);
if (priv->family_id == RTL8380_FAMILY_ID)
debugfs_create_x32(lag_name, 0644, rtl838x_dir,
(u32 *)(RTL838X_SW_BASE + priv->r->trk_mbr_ctr(i)));
else
debugfs_create_x64(lag_name, 0644, rtl838x_dir,
(u64 *)(RTL838X_SW_BASE + priv->r->trk_mbr_ctr(i)));
}
/* Create directories for mirror groups */
for (int i = 0; i < 4; i++) {
snprintf(mirror_name, sizeof(mirror_name), "mirror.%1d", i);
mirror_dir = debugfs_create_dir(mirror_name, rtl838x_dir);
if (priv->family_id == RTL8380_FAMILY_ID) {
debugfs_create_x32("ctrl", 0644, mirror_dir,
(u32 *)(RTL838X_SW_BASE + RTL838X_MIR_CTRL + i * 4));
debugfs_create_x32("ingress_pm", 0644, mirror_dir,
(u32 *)(RTL838X_SW_BASE + priv->r->mir_spm + i * 4));
debugfs_create_x32("egress_pm", 0644, mirror_dir,
(u32 *)(RTL838X_SW_BASE + priv->r->mir_dpm + i * 4));
debugfs_create_x32("qid", 0644, mirror_dir,
(u32 *)(RTL838X_SW_BASE + RTL838X_MIR_QID_CTRL(i)));
debugfs_create_x32("rspan_vlan", 0644, mirror_dir,
(u32 *)(RTL838X_SW_BASE + RTL838X_MIR_RSPAN_VLAN_CTRL(i)));
debugfs_create_x32("rspan_vlan_mac", 0644, mirror_dir,
(u32 *)(RTL838X_SW_BASE + RTL838X_MIR_RSPAN_VLAN_CTRL_MAC(i)));
debugfs_create_x32("rspan_tx", 0644, mirror_dir,
(u32 *)(RTL838X_SW_BASE + RTL838X_MIR_RSPAN_TX_CTRL));
debugfs_create_x32("rspan_tx_tag_rm", 0644, mirror_dir,
(u32 *)(RTL838X_SW_BASE + RTL838X_MIR_RSPAN_TX_TAG_RM_CTRL));
debugfs_create_x32("rspan_tx_tag_en", 0644, mirror_dir,
(u32 *)(RTL838X_SW_BASE + RTL838X_MIR_RSPAN_TX_TAG_EN_CTRL));
} else {
debugfs_create_x32("ctrl", 0644, mirror_dir,
(u32 *)(RTL838X_SW_BASE + RTL839X_MIR_CTRL + i * 4));
debugfs_create_x64("ingress_pm", 0644, mirror_dir,
(u64 *)(RTL838X_SW_BASE + priv->r->mir_spm + i * 8));
debugfs_create_x64("egress_pm", 0644, mirror_dir,
(u64 *)(RTL838X_SW_BASE + priv->r->mir_dpm + i * 8));
debugfs_create_x32("rspan_vlan", 0644, mirror_dir,
(u32 *)(RTL838X_SW_BASE + RTL839X_MIR_RSPAN_VLAN_CTRL(i)));
debugfs_create_x32("rspan_tx", 0644, mirror_dir,
(u32 *)(RTL838X_SW_BASE + RTL839X_MIR_RSPAN_TX_CTRL));
debugfs_create_x32("rspan_tx_tag_rm", 0644, mirror_dir,
(u32 *)(RTL838X_SW_BASE + RTL839X_MIR_RSPAN_TX_TAG_RM_CTRL));
debugfs_create_x32("rspan_tx_tag_en", 0644, mirror_dir,
(u32 *)(RTL838X_SW_BASE + RTL839X_MIR_RSPAN_TX_TAG_EN_CTRL));
debugfs_create_x64("sample_rate", 0644, mirror_dir,
(u64 *)(RTL838X_SW_BASE + RTL839X_MIR_SAMPLE_RATE_CTRL));
}
}
if (priv->family_id == RTL8380_FAMILY_ID)
debugfs_create_x32("bpdu_flood_mask", 0644, rtl838x_dir,
(u32 *)(RTL838X_SW_BASE + priv->r->rma_bpdu_fld_pmask));
else
debugfs_create_x64("bpdu_flood_mask", 0644, rtl838x_dir,
(u64 *)(RTL838X_SW_BASE + priv->r->rma_bpdu_fld_pmask));
if (priv->family_id == RTL8380_FAMILY_ID)
debugfs_create_x32("vlan_ctrl", 0644, rtl838x_dir,
(u32 *)(RTL838X_SW_BASE + RTL838X_VLAN_CTRL));
else
debugfs_create_x32("vlan_ctrl", 0644, rtl838x_dir,
(u32 *)(RTL838X_SW_BASE + RTL839X_VLAN_CTRL));
ret = rtl838x_dbgfs_leds(rtl838x_dir, priv);
if (ret)
goto err;
debugfs_create_file("drop_counters", 0400, rtl838x_dir, priv, &drop_counter_fops);
debugfs_create_file("l2_table", 0400, rtl838x_dir, priv, &l2_table_fops);
return;
err:
rtl838x_dbgfs_cleanup(priv);
}
void rtl930x_dbgfs_init(struct rtl838x_switch_priv *priv)
{
struct dentry *dbg_dir;
pr_info("%s called\n", __func__);
dbg_dir = debugfs_lookup(RTL838X_DRIVER_NAME, NULL);
if (!dbg_dir)
dbg_dir = debugfs_create_dir(RTL838X_DRIVER_NAME, NULL);
priv->dbgfs_dir = dbg_dir;
debugfs_create_file("drop_counters", 0400, dbg_dir, priv, &drop_counter_fops);
debugfs_create_file("l2_table", 0400, dbg_dir, priv, &l2_table_fops);
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,565 @@
// SPDX-License-Identifier: GPL-2.0-only
#include <net/dsa.h>
#include <linux/delay.h>
#include <asm/mach-rtl838x/mach-rtl83xx.h>
#include "rtl83xx.h"
static struct rtl838x_switch_priv *switch_priv;
extern struct rtl83xx_soc_info soc_info;
enum scheduler_type {
WEIGHTED_FAIR_QUEUE = 0,
WEIGHTED_ROUND_ROBIN,
};
int max_available_queue[] = {0, 1, 2, 3, 4, 5, 6, 7};
int default_queue_weights[] = {1, 1, 1, 1, 1, 1, 1, 1};
int dot1p_priority_remapping[] = {0, 1, 2, 3, 4, 5, 6, 7};
static void rtl839x_read_scheduling_table(int port)
{
u32 cmd = 1 << 9 | /* Execute cmd */
0 << 8 | /* Read */
0 << 6 | /* Table type 0b00 */
(port & 0x3f);
rtl839x_exec_tbl2_cmd(cmd);
}
static void rtl839x_write_scheduling_table(int port)
{
u32 cmd = 1 << 9 | /* Execute cmd */
1 << 8 | /* Write */
0 << 6 | /* Table type 0b00 */
(port & 0x3f);
rtl839x_exec_tbl2_cmd(cmd);
}
static void rtl839x_read_out_q_table(int port)
{
u32 cmd = 1 << 9 | /* Execute cmd */
0 << 8 | /* Read */
2 << 6 | /* Table type 0b10 */
(port & 0x3f);
rtl839x_exec_tbl2_cmd(cmd);
}
static void rtl838x_storm_enable(struct rtl838x_switch_priv *priv, int port, bool enable)
{
/* Enable Storm control for that port for UC, MC, and BC */
if (enable)
sw_w32(0x7, RTL838X_STORM_CTRL_LB_CTRL(port));
else
sw_w32(0x0, RTL838X_STORM_CTRL_LB_CTRL(port));
}
u32 rtl838x_get_egress_rate(struct rtl838x_switch_priv *priv, int port)
{
if (port > priv->cpu_port)
return 0;
return sw_r32(RTL838X_SCHED_P_EGR_RATE_CTRL(port)) & 0x3fff;
}
/* Sets the rate limit, 10MBit/s is equal to a rate value of 625 */
int rtl838x_set_egress_rate(struct rtl838x_switch_priv *priv, int port, u32 rate)
{
u32 old_rate;
if (port > priv->cpu_port)
return -1;
old_rate = sw_r32(RTL838X_SCHED_P_EGR_RATE_CTRL(port));
sw_w32(rate, RTL838X_SCHED_P_EGR_RATE_CTRL(port));
return old_rate;
}
/* Set the rate limit for a particular queue in Bits/s
* units of the rate is 16Kbps
*/
void rtl838x_egress_rate_queue_limit(struct rtl838x_switch_priv *priv, int port,
int queue, u32 rate)
{
if (port > priv->cpu_port)
return;
if (queue > 7)
return;
sw_w32(rate, RTL838X_SCHED_Q_EGR_RATE_CTRL(port, queue));
}
static void rtl838x_rate_control_init(struct rtl838x_switch_priv *priv)
{
pr_info("Enabling Storm control\n");
/* TICK_PERIOD_PPS */
if (priv->id == 0x8380)
sw_w32_mask(0x3ff << 20, 434 << 20, RTL838X_SCHED_LB_TICK_TKN_CTRL_0);
/* Set burst rate */
sw_w32(0x00008000, RTL838X_STORM_CTRL_BURST_0); /* UC */
sw_w32(0x80008000, RTL838X_STORM_CTRL_BURST_1); /* MC and BC */
/* Set burst Packets per Second to 32 */
sw_w32(0x00000020, RTL838X_STORM_CTRL_BURST_PPS_0); /* UC */
sw_w32(0x00200020, RTL838X_STORM_CTRL_BURST_PPS_1); /* MC and BC */
/* Include IFG in storm control, rate based on bytes/s (0 = packets) */
sw_w32_mask(0, 1 << 6 | 1 << 5, RTL838X_STORM_CTRL);
/* Bandwidth control includes preamble and IFG (10 Bytes) */
sw_w32_mask(0, 1, RTL838X_SCHED_CTRL);
/* On SoCs except RTL8382M, set burst size of port egress */
if (priv->id != 0x8382)
sw_w32_mask(0xffff, 0x800, RTL838X_SCHED_LB_THR);
/* Enable storm control on all ports with a PHY and limit rates,
* for UC and MC for both known and unknown addresses
*/
for (int i = 0; i < priv->cpu_port; i++) {
if (priv->ports[i].phy) {
sw_w32((1 << 18) | 0x8000, RTL838X_STORM_CTRL_PORT_UC(i));
sw_w32((1 << 18) | 0x8000, RTL838X_STORM_CTRL_PORT_MC(i));
sw_w32(0x8000, RTL838X_STORM_CTRL_PORT_BC(i));
rtl838x_storm_enable(priv, i, true);
}
}
/* Attack prevention, enable all attack prevention measures */
/* sw_w32(0x1ffff, RTL838X_ATK_PRVNT_CTRL); */
/* Attack prevention, drop (bit = 0) problematic packets on all ports.
* Setting bit = 1 means: trap to CPU
*/
/* sw_w32(0, RTL838X_ATK_PRVNT_ACT); */
/* Enable attack prevention on all ports */
/* sw_w32(0x0fffffff, RTL838X_ATK_PRVNT_PORT_EN); */
}
/* Sets the rate limit, 10MBit/s is equal to a rate value of 625 */
u32 rtl839x_get_egress_rate(struct rtl838x_switch_priv *priv, int port)
{
u32 rate;
pr_debug("%s: Getting egress rate on port %d to %d\n", __func__, port, rate);
if (port >= priv->cpu_port)
return 0;
mutex_lock(&priv->reg_mutex);
rtl839x_read_scheduling_table(port);
rate = sw_r32(RTL839X_TBL_ACCESS_DATA_2(7));
rate <<= 12;
rate |= sw_r32(RTL839X_TBL_ACCESS_DATA_2(8)) >> 20;
mutex_unlock(&priv->reg_mutex);
return rate;
}
/* Sets the rate limit, 10MBit/s is equal to a rate value of 625, returns previous rate */
int rtl839x_set_egress_rate(struct rtl838x_switch_priv *priv, int port, u32 rate)
{
u32 old_rate;
pr_debug("%s: Setting egress rate on port %d to %d\n", __func__, port, rate);
if (port >= priv->cpu_port)
return -1;
mutex_lock(&priv->reg_mutex);
rtl839x_read_scheduling_table(port);
old_rate = sw_r32(RTL839X_TBL_ACCESS_DATA_2(7)) & 0xff;
old_rate <<= 12;
old_rate |= sw_r32(RTL839X_TBL_ACCESS_DATA_2(8)) >> 20;
sw_w32_mask(0xff, (rate >> 12) & 0xff, RTL839X_TBL_ACCESS_DATA_2(7));
sw_w32_mask(0xfff << 20, rate << 20, RTL839X_TBL_ACCESS_DATA_2(8));
rtl839x_write_scheduling_table(port);
mutex_unlock(&priv->reg_mutex);
return old_rate;
}
/* Set the rate limit for a particular queue in Bits/s
* units of the rate is 16Kbps
*/
void rtl839x_egress_rate_queue_limit(struct rtl838x_switch_priv *priv, int port,
int queue, u32 rate)
{
int lsb = 128 + queue * 20;
int low_byte = 8 - (lsb >> 5);
int start_bit = lsb - (low_byte << 5);
u32 high_mask = 0xfffff >> (32 - start_bit);
pr_debug("%s: Setting egress rate on port %d, queue %d to %d\n",
__func__, port, queue, rate);
if (port >= priv->cpu_port)
return;
if (queue > 7)
return;
mutex_lock(&priv->reg_mutex);
rtl839x_read_scheduling_table(port);
sw_w32_mask(0xfffff << start_bit, (rate & 0xfffff) << start_bit,
RTL839X_TBL_ACCESS_DATA_2(low_byte));
if (high_mask)
sw_w32_mask(high_mask, (rate & 0xfffff) >> (32- start_bit),
RTL839X_TBL_ACCESS_DATA_2(low_byte - 1));
rtl839x_write_scheduling_table(port);
mutex_unlock(&priv->reg_mutex);
}
static void rtl839x_rate_control_init(struct rtl838x_switch_priv *priv)
{
pr_info("%s: enabling rate control\n", __func__);
/* Tick length and token size settings for SoC with 250MHz,
* RTL8350 family would use 50MHz
*/
/* Set the special tick period */
sw_w32(976563, RTL839X_STORM_CTRL_SPCL_LB_TICK_TKN_CTRL);
/* Ingress tick period and token length 10G */
sw_w32(18 << 11 | 151, RTL839X_IGR_BWCTRL_LB_TICK_TKN_CTRL_0);
/* Ingress tick period and token length 1G */
sw_w32(245 << 11 | 129, RTL839X_IGR_BWCTRL_LB_TICK_TKN_CTRL_1);
/* Egress tick period 10G, bytes/token 10G and tick period 1G, bytes/token 1G */
sw_w32(18 << 24 | 151 << 16 | 185 << 8 | 97, RTL839X_SCHED_LB_TICK_TKN_CTRL);
/* Set the tick period of the CPU and the Token Len */
sw_w32(3815 << 8 | 1, RTL839X_SCHED_LB_TICK_TKN_PPS_CTRL);
/* Set the Weighted Fair Queueing burst size */
sw_w32_mask(0xffff, 4500, RTL839X_SCHED_LB_THR);
/* Storm-rate calculation is based on bytes/sec (bit 5), include IFG (bit 6) */
sw_w32_mask(0, 1 << 5 | 1 << 6, RTL839X_STORM_CTRL);
/* Based on the rate control mode being bytes/s
* set tick period and token length for 10G
*/
sw_w32(18 << 10 | 151, RTL839X_STORM_CTRL_LB_TICK_TKN_CTRL_0);
/* and for 1G ports */
sw_w32(246 << 10 | 129, RTL839X_STORM_CTRL_LB_TICK_TKN_CTRL_1);
/* Set default burst rates on all ports (the same for 1G / 10G) with a PHY
* for UC, MC and BC
* For 1G port, the minimum burst rate is 1700, maximum 65535,
* For 10G ports it is 2650 and 1048575 respectively */
for (int p = 0; p < priv->cpu_port; p++) {
if (priv->ports[p].phy && !priv->ports[p].is10G) {
sw_w32_mask(0xffff, 0x8000, RTL839X_STORM_CTRL_PORT_UC_1(p));
sw_w32_mask(0xffff, 0x8000, RTL839X_STORM_CTRL_PORT_MC_1(p));
sw_w32_mask(0xffff, 0x8000, RTL839X_STORM_CTRL_PORT_BC_1(p));
}
}
/* Setup ingress/egress per-port rate control */
for (int p = 0; p < priv->cpu_port; p++) {
if (!priv->ports[p].phy)
continue;
if (priv->ports[p].is10G)
rtl839x_set_egress_rate(priv, p, 625000); /* 10GB/s */
else
rtl839x_set_egress_rate(priv, p, 62500); /* 1GB/s */
/* Setup queues: all RTL83XX SoCs have 8 queues, maximum rate */
for (int q = 0; q < 8; q++)
rtl839x_egress_rate_queue_limit(priv, p, q, 0xfffff);
if (priv->ports[p].is10G) {
/* Set high threshold to maximum */
sw_w32_mask(0xffff, 0xffff, RTL839X_IGR_BWCTRL_PORT_CTRL_10G_0(p));
} else {
/* Set high threshold to maximum */
sw_w32_mask(0xffff, 0xffff, RTL839X_IGR_BWCTRL_PORT_CTRL_1(p));
}
}
/* Set global ingress low watermark rate */
sw_w32(65532, RTL839X_IGR_BWCTRL_CTRL_LB_THR);
}
void rtl838x_setup_prio2queue_matrix(int *min_queues)
{
u32 v = 0;
pr_info("Current Intprio2queue setting: %08x\n", sw_r32(RTL838X_QM_INTPRI2QID_CTRL));
for (int i = 0; i < MAX_PRIOS; i++)
v |= i << (min_queues[i] * 3);
sw_w32(v, RTL838X_QM_INTPRI2QID_CTRL);
}
void rtl839x_setup_prio2queue_matrix(int *min_queues)
{
pr_info("Current Intprio2queue setting: %08x\n", sw_r32(RTL839X_QM_INTPRI2QID_CTRL(0)));
for (int i = 0; i < MAX_PRIOS; i++) {
int q = min_queues[i];
sw_w32(i << (q * 3), RTL839X_QM_INTPRI2QID_CTRL(q));
}
}
/* Sets the CPU queue depending on the internal priority of a packet */
void rtl83xx_setup_prio2queue_cpu_matrix(int *max_queues)
{
int reg = soc_info.family == RTL8380_FAMILY_ID ? RTL838X_QM_PKT2CPU_INTPRI_MAP
: RTL839X_QM_PKT2CPU_INTPRI_MAP;
u32 v = 0;
pr_info("QM_PKT2CPU_INTPRI_MAP: %08x\n", sw_r32(reg));
for (int i = 0; i < MAX_PRIOS; i++)
v |= max_queues[i] << (i * 3);
sw_w32(v, reg);
}
void rtl83xx_setup_default_prio2queue(void)
{
if (soc_info.family == RTL8380_FAMILY_ID) {
rtl838x_setup_prio2queue_matrix(max_available_queue);
} else {
rtl839x_setup_prio2queue_matrix(max_available_queue);
}
rtl83xx_setup_prio2queue_cpu_matrix(max_available_queue);
}
/* Sets the output queue assigned to a port, the port can be the CPU-port */
void rtl839x_set_egress_queue(int port, int queue)
{
sw_w32(queue << ((port % 10) *3), RTL839X_QM_PORT_QNUM(port));
}
/* Sets the priority assigned of an ingress port, the port can be the CPU-port */
void rtl83xx_set_ingress_priority(int port, int priority)
{
if (soc_info.family == RTL8380_FAMILY_ID)
sw_w32(priority << ((port % 10) *3), RTL838X_PRI_SEL_PORT_PRI(port));
else
sw_w32(priority << ((port % 10) *3), RTL839X_PRI_SEL_PORT_PRI(port));
}
int rtl839x_get_scheduling_algorithm(struct rtl838x_switch_priv *priv, int port)
{
u32 v;
mutex_lock(&priv->reg_mutex);
rtl839x_read_scheduling_table(port);
v = sw_r32(RTL839X_TBL_ACCESS_DATA_2(8));
mutex_unlock(&priv->reg_mutex);
if (v & BIT(19))
return WEIGHTED_ROUND_ROBIN;
return WEIGHTED_FAIR_QUEUE;
}
void rtl839x_set_scheduling_algorithm(struct rtl838x_switch_priv *priv, int port,
enum scheduler_type sched)
{
enum scheduler_type t = rtl839x_get_scheduling_algorithm(priv, port);
u32 v, oam_state, oam_port_state;
u32 count;
int i, egress_rate;
mutex_lock(&priv->reg_mutex);
/* Check whether we need to empty the egress queue of that port due to Errata E0014503 */
if (sched == WEIGHTED_FAIR_QUEUE && t == WEIGHTED_ROUND_ROBIN && port != priv->cpu_port) {
/* Read Operations, Adminstatrion and Management control register */
oam_state = sw_r32(RTL839X_OAM_CTRL);
/* Get current OAM state */
oam_port_state = sw_r32(RTL839X_OAM_PORT_ACT_CTRL(port));
/* Disable OAM to block traffice */
v = sw_r32(RTL839X_OAM_CTRL);
sw_w32_mask(0, 1, RTL839X_OAM_CTRL);
v = sw_r32(RTL839X_OAM_CTRL);
/* Set to trap action OAM forward (bits 1, 2) and OAM Mux Action Drop (bit 0) */
sw_w32(0x2, RTL839X_OAM_PORT_ACT_CTRL(port));
/* Set port egress rate to unlimited */
egress_rate = rtl839x_set_egress_rate(priv, port, 0xFFFFF);
/* Wait until the egress used page count of that port is 0 */
i = 0;
do {
usleep_range(100, 200);
rtl839x_read_out_q_table(port);
count = sw_r32(RTL839X_TBL_ACCESS_DATA_2(6));
count >>= 20;
i++;
} while (i < 3500 && count > 0);
}
/* Actually set the scheduling algorithm */
rtl839x_read_scheduling_table(port);
sw_w32_mask(BIT(19), sched ? BIT(19) : 0, RTL839X_TBL_ACCESS_DATA_2(8));
rtl839x_write_scheduling_table(port);
if (sched == WEIGHTED_FAIR_QUEUE && t == WEIGHTED_ROUND_ROBIN && port != priv->cpu_port) {
/* Restore OAM state to control register */
sw_w32(oam_state, RTL839X_OAM_CTRL);
/* Restore trap action state */
sw_w32(oam_port_state, RTL839X_OAM_PORT_ACT_CTRL(port));
/* Restore port egress rate */
rtl839x_set_egress_rate(priv, port, egress_rate);
}
mutex_unlock(&priv->reg_mutex);
}
void rtl839x_set_scheduling_queue_weights(struct rtl838x_switch_priv *priv, int port,
int *queue_weights)
{
mutex_lock(&priv->reg_mutex);
rtl839x_read_scheduling_table(port);
for (int i = 0; i < 8; i++) {
int lsb = 48 + i * 8;
int low_byte = 8 - (lsb >> 5);
int start_bit = lsb - (low_byte << 5);
int high_mask = 0x3ff >> (32 - start_bit);
sw_w32_mask(0x3ff << start_bit, (queue_weights[i] & 0x3ff) << start_bit,
RTL839X_TBL_ACCESS_DATA_2(low_byte));
if (high_mask)
sw_w32_mask(high_mask, (queue_weights[i] & 0x3ff) >> (32- start_bit),
RTL839X_TBL_ACCESS_DATA_2(low_byte - 1));
}
rtl839x_write_scheduling_table(port);
mutex_unlock(&priv->reg_mutex);
}
void rtl838x_config_qos(void)
{
u32 v;
pr_info("Setting up RTL838X QoS\n");
pr_info("RTL838X_PRI_SEL_TBL_CTRL(i): %08x\n", sw_r32(RTL838X_PRI_SEL_TBL_CTRL(0)));
rtl83xx_setup_default_prio2queue();
/* Enable inner (bit 12) and outer (bit 13) priority remapping from DSCP */
sw_w32_mask(0, BIT(12) | BIT(13), RTL838X_PRI_DSCP_INVLD_CTRL0);
/* Set default weight for calculating internal priority, in prio selection group 0
* Port based (prio 3), Port outer-tag (4), DSCP (5), Inner Tag (6), Outer Tag (7)
*/
v = 3 | (4 << 3) | (5 << 6) | (6 << 9) | (7 << 12);
sw_w32(v, RTL838X_PRI_SEL_TBL_CTRL(0));
/* Set the inner and outer priority one-to-one to re-marked outer dot1p priority */
v = 0;
for (int p = 0; p < 8; p++)
v |= p << (3 * p);
sw_w32(v, RTL838X_RMK_OPRI_CTRL);
sw_w32(v, RTL838X_RMK_IPRI_CTRL);
v = 0;
for (int p = 0; p < 8; p++)
v |= (dot1p_priority_remapping[p] & 0x7) << (p * 3);
sw_w32(v, RTL838X_PRI_SEL_IPRI_REMAP);
/* On all ports set scheduler type to WFQ */
for (int i = 0; i <= soc_info.cpu_port; i++)
sw_w32(0, RTL838X_SCHED_P_TYPE_CTRL(i));
/* Enable egress scheduler for CPU-Port */
sw_w32_mask(0, BIT(8), RTL838X_SCHED_LB_CTRL(soc_info.cpu_port));
/* Enable egress drop allways on */
sw_w32_mask(0, BIT(11), RTL838X_FC_P_EGR_DROP_CTRL(soc_info.cpu_port));
/* Give special trap frames priority 7 (BPDUs) and routing exceptions: */
sw_w32_mask(0, 7 << 3 | 7, RTL838X_QM_PKT2CPU_INTPRI_2);
/* Give RMA frames priority 7: */
sw_w32_mask(0, 7, RTL838X_QM_PKT2CPU_INTPRI_1);
}
void rtl839x_config_qos(void)
{
u32 v;
struct rtl838x_switch_priv *priv = switch_priv;
pr_info("Setting up RTL839X QoS\n");
pr_info("RTL839X_PRI_SEL_TBL_CTRL(i): %08x\n", sw_r32(RTL839X_PRI_SEL_TBL_CTRL(0)));
rtl83xx_setup_default_prio2queue();
for (int port = 0; port < soc_info.cpu_port; port++)
sw_w32(7, RTL839X_QM_PORT_QNUM(port));
/* CPU-port gets queue number 7 */
sw_w32(7, RTL839X_QM_PORT_QNUM(soc_info.cpu_port));
for (int port = 0; port <= soc_info.cpu_port; port++) {
rtl83xx_set_ingress_priority(port, 0);
rtl839x_set_scheduling_algorithm(priv, port, WEIGHTED_FAIR_QUEUE);
rtl839x_set_scheduling_queue_weights(priv, port, default_queue_weights);
/* Do re-marking based on outer tag */
sw_w32_mask(0, BIT(port % 32), RTL839X_RMK_PORT_DEI_TAG_CTRL(port));
}
/* Remap dot1p priorities to internal priority, for this the outer tag needs be re-marked */
v = 0;
for (int p = 0; p < 8; p++)
v |= (dot1p_priority_remapping[p] & 0x7) << (p * 3);
sw_w32(v, RTL839X_PRI_SEL_IPRI_REMAP);
/* Configure Drop Precedence for Drop Eligible Indicator (DEI)
* Index 0: 0
* Index 1: 2
* Each indicator is 2 bits long
*/
sw_w32(2 << 2, RTL839X_PRI_SEL_DEI2DP_REMAP);
/* Re-mark DEI: 4 bit-fields of 2 bits each, field 0 is bits 0-1, ... */
sw_w32((0x1 << 2) | (0x1 << 4), RTL839X_RMK_DEI_CTRL);
/* Set Congestion avoidance drop probability to 0 for drop precedences 0-2 (bits 24-31)
* low threshold (bits 0-11) to 4095 and high threshold (bits 12-23) to 4095
* Weighted Random Early Detection (WRED) is used
*/
sw_w32(4095 << 12| 4095, RTL839X_WRED_PORT_THR_CTRL(0));
sw_w32(4095 << 12| 4095, RTL839X_WRED_PORT_THR_CTRL(1));
sw_w32(4095 << 12| 4095, RTL839X_WRED_PORT_THR_CTRL(2));
/* Set queue-based congestion avoidance properties, register fields are as
* for forward RTL839X_WRED_PORT_THR_CTRL
*/
for (int q = 0; q < 8; q++) {
sw_w32(255 << 24 | 78 << 12 | 68, RTL839X_WRED_QUEUE_THR_CTRL(q, 0));
sw_w32(255 << 24 | 74 << 12 | 64, RTL839X_WRED_QUEUE_THR_CTRL(q, 0));
sw_w32(255 << 24 | 70 << 12 | 60, RTL839X_WRED_QUEUE_THR_CTRL(q, 0));
}
}
void __init rtl83xx_setup_qos(struct rtl838x_switch_priv *priv)
{
switch_priv = priv;
pr_info("In %s\n", __func__);
if (priv->family_id == RTL8380_FAMILY_ID)
return rtl838x_config_qos();
else if (priv->family_id == RTL8390_FAMILY_ID)
return rtl839x_config_qos();
if (priv->family_id == RTL8380_FAMILY_ID)
rtl838x_rate_control_init(priv);
else if (priv->family_id == RTL8390_FAMILY_ID)
rtl839x_rate_control_init(priv);
}

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,136 @@
/* SPDX-License-Identifier: GPL-2.0-only */
#ifndef _NET_DSA_RTL83XX_H
#define _NET_DSA_RTL83XX_H
#include <net/dsa.h>
#include "rtl838x.h"
#define RTL8380_VERSION_A 'A'
#define RTL8390_VERSION_A 'A'
#define RTL8380_VERSION_B 'B'
struct fdb_update_work {
struct work_struct work;
struct net_device *ndev;
u64 macs[];
};
#define MIB_DESC(_size, _offset, _name) {.size = _size, .offset = _offset, .name = _name}
struct rtl83xx_mib_desc {
unsigned int size;
unsigned int offset;
const char *name;
};
/* API for switch table access */
struct table_reg {
u16 addr;
u16 data;
u8 max_data;
u8 c_bit;
u8 t_bit;
u8 rmode;
u8 tbl;
struct mutex lock;
};
#define TBL_DESC(_addr, _data, _max_data, _c_bit, _t_bit, _rmode) \
{ .addr = _addr, .data = _data, .max_data = _max_data, .c_bit = _c_bit, \
.t_bit = _t_bit, .rmode = _rmode \
}
typedef enum {
RTL8380_TBL_L2 = 0,
RTL8380_TBL_0,
RTL8380_TBL_1,
RTL8390_TBL_L2,
RTL8390_TBL_0,
RTL8390_TBL_1,
RTL8390_TBL_2,
RTL9300_TBL_L2,
RTL9300_TBL_0,
RTL9300_TBL_1,
RTL9300_TBL_2,
RTL9300_TBL_HSB,
RTL9300_TBL_HSA,
RTL9310_TBL_0,
RTL9310_TBL_1,
RTL9310_TBL_2,
RTL9310_TBL_3,
RTL9310_TBL_4,
RTL9310_TBL_5,
RTL_TBL_END
} rtl838x_tbl_reg_t;
void rtl_table_init(void);
struct table_reg *rtl_table_get(rtl838x_tbl_reg_t r, int t);
void rtl_table_release(struct table_reg *r);
int rtl_table_read(struct table_reg *r, int idx);
int rtl_table_write(struct table_reg *r, int idx);
inline u16 rtl_table_data(struct table_reg *r, int i);
inline u32 rtl_table_data_r(struct table_reg *r, int i);
inline void rtl_table_data_w(struct table_reg *r, u32 v, int i);
void __init rtl83xx_setup_qos(struct rtl838x_switch_priv *priv);
int rtl83xx_packet_cntr_alloc(struct rtl838x_switch_priv *priv);
int rtl83xx_port_is_under(const struct net_device * dev, struct rtl838x_switch_priv *priv);
int read_phy(u32 port, u32 page, u32 reg, u32 *val);
int write_phy(u32 port, u32 page, u32 reg, u32 val);
/* Port register accessor functions for the RTL839x and RTL931X SoCs */
void rtl839x_mask_port_reg_be(u64 clear, u64 set, int reg);
u64 rtl839x_get_port_reg_be(int reg);
void rtl839x_set_port_reg_be(u64 set, int reg);
void rtl839x_mask_port_reg_le(u64 clear, u64 set, int reg);
void rtl839x_set_port_reg_le(u64 set, int reg);
u64 rtl839x_get_port_reg_le(int reg);
/* Port register accessor functions for the RTL838x and RTL930X SoCs */
void rtl838x_mask_port_reg(u64 clear, u64 set, int reg);
void rtl838x_set_port_reg(u64 set, int reg);
u64 rtl838x_get_port_reg(int reg);
/* RTL838x-specific */
u32 rtl838x_hash(struct rtl838x_switch_priv *priv, u64 seed);
irqreturn_t rtl838x_switch_irq(int irq, void *dev_id);
void rtl8380_get_version(struct rtl838x_switch_priv *priv);
void rtl838x_vlan_profile_dump(int index);
int rtl83xx_dsa_phy_read(struct dsa_switch *ds, int phy_addr, int phy_reg);
void rtl8380_sds_rst(int mac);
int rtl8380_sds_power(int mac, int val);
void rtl838x_print_matrix(void);
/* RTL839x-specific */
u32 rtl839x_hash(struct rtl838x_switch_priv *priv, u64 seed);
irqreturn_t rtl839x_switch_irq(int irq, void *dev_id);
void rtl8390_get_version(struct rtl838x_switch_priv *priv);
void rtl839x_vlan_profile_dump(int index);
int rtl83xx_dsa_phy_write(struct dsa_switch *ds, int phy_addr, int phy_reg, u16 val);
void rtl839x_exec_tbl2_cmd(u32 cmd);
void rtl839x_print_matrix(void);
/* RTL930x-specific */
u32 rtl930x_hash(struct rtl838x_switch_priv *priv, u64 seed);
irqreturn_t rtl930x_switch_irq(int irq, void *dev_id);
irqreturn_t rtl839x_switch_irq(int irq, void *dev_id);
void rtl930x_vlan_profile_dump(int index);
int rtl9300_sds_power(int mac, int val);
void rtl9300_sds_rst(int sds_num, u32 mode);
int rtl9300_serdes_setup(int port, int sds_num, phy_interface_t phy_mode);
void rtl930x_print_matrix(void);
/* RTL931x-specific */
irqreturn_t rtl931x_switch_irq(int irq, void *dev_id);
int rtl931x_sds_cmu_band_get(int sds, phy_interface_t mode);
int rtl931x_sds_cmu_band_set(int sds, bool enable, u32 band, phy_interface_t mode);
void rtl931x_sds_init(u32 sds, phy_interface_t mode);
int rtl83xx_lag_add(struct dsa_switch *ds, int group, int port, struct netdev_lag_upper_info *info);
int rtl83xx_lag_del(struct dsa_switch *ds, int group, int port);
#endif /* _NET_DSA_RTL83XX_H */

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,410 @@
// SPDX-License-Identifier: GPL-2.0-only
#include <net/dsa.h>
#include <linux/delay.h>
#include <linux/etherdevice.h>
#include <linux/netdevice.h>
#include <net/flow_offload.h>
#include <linux/rhashtable.h>
#include <asm/mach-rtl838x/mach-rtl83xx.h>
#include "rtl83xx.h"
#include "rtl838x.h"
/* Parse the flow rule for the matching conditions */
static int rtl83xx_parse_flow_rule(struct rtl838x_switch_priv *priv,
struct flow_rule *rule, struct rtl83xx_flow *flow)
{
struct flow_dissector *dissector = rule->match.dissector;
pr_debug("In %s\n", __func__);
/* KEY_CONTROL and KEY_BASIC are needed for forming a meaningful key */
if ((dissector->used_keys & BIT(FLOW_DISSECTOR_KEY_CONTROL)) == 0 ||
(dissector->used_keys & BIT(FLOW_DISSECTOR_KEY_BASIC)) == 0) {
pr_err("Cannot form TC key: used_keys = 0x%x\n", dissector->used_keys);
return -EOPNOTSUPP;
}
if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_BASIC)) {
struct flow_match_basic match;
pr_debug("%s: BASIC\n", __func__);
flow_rule_match_basic(rule, &match);
if (match.key->n_proto == htons(ETH_P_ARP))
flow->rule.frame_type = 0;
if (match.key->n_proto == htons(ETH_P_IP))
flow->rule.frame_type = 2;
if (match.key->n_proto == htons(ETH_P_IPV6))
flow->rule.frame_type = 3;
if ((match.key->n_proto == htons(ETH_P_ARP)) || flow->rule.frame_type)
flow->rule.frame_type_m = 3;
if (flow->rule.frame_type >= 2) {
if (match.key->ip_proto == IPPROTO_UDP)
flow->rule.frame_type_l4 = 0;
if (match.key->ip_proto == IPPROTO_TCP)
flow->rule.frame_type_l4 = 1;
if (match.key->ip_proto == IPPROTO_ICMP || match.key->ip_proto == IPPROTO_ICMPV6)
flow->rule.frame_type_l4 = 2;
if (match.key->ip_proto == IPPROTO_TCP)
flow->rule.frame_type_l4 = 3;
if ((match.key->ip_proto == IPPROTO_UDP) || flow->rule.frame_type_l4)
flow->rule.frame_type_l4_m = 7;
}
}
if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_ETH_ADDRS)) {
struct flow_match_eth_addrs match;
pr_debug("%s: ETH_ADDR\n", __func__);
flow_rule_match_eth_addrs(rule, &match);
ether_addr_copy(flow->rule.dmac, match.key->dst);
ether_addr_copy(flow->rule.dmac_m, match.mask->dst);
ether_addr_copy(flow->rule.smac, match.key->src);
ether_addr_copy(flow->rule.smac_m, match.mask->src);
}
if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_VLAN)) {
struct flow_match_vlan match;
pr_debug("%s: VLAN\n", __func__);
flow_rule_match_vlan(rule, &match);
flow->rule.itag = match.key->vlan_id;
flow->rule.itag_m = match.mask->vlan_id;
/* TODO: What about match.key->vlan_priority? */
}
if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_IPV4_ADDRS)) {
struct flow_match_ipv4_addrs match;
pr_debug("%s: IPV4\n", __func__);
flow_rule_match_ipv4_addrs(rule, &match);
flow->rule.is_ipv6 = false;
flow->rule.dip = match.key->dst;
flow->rule.dip_m = match.mask->dst;
flow->rule.sip = match.key->src;
flow->rule.sip_m = match.mask->src;
} else if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_IPV6_ADDRS)) {
struct flow_match_ipv6_addrs match;
pr_debug("%s: IPV6\n", __func__);
flow->rule.is_ipv6 = true;
flow_rule_match_ipv6_addrs(rule, &match);
flow->rule.dip6 = match.key->dst;
flow->rule.dip6_m = match.mask->dst;
flow->rule.sip6 = match.key->src;
flow->rule.sip6_m = match.mask->src;
}
if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_PORTS)) {
struct flow_match_ports match;
pr_debug("%s: PORTS\n", __func__);
flow_rule_match_ports(rule, &match);
flow->rule.dport = match.key->dst;
flow->rule.dport_m = match.mask->dst;
flow->rule.sport = match.key->src;
flow->rule.sport_m = match.mask->src;
}
/* TODO: ICMP */
return 0;
}
static void rtl83xx_flow_bypass_all(struct rtl83xx_flow *flow)
{
flow->rule.bypass_sel = true;
flow->rule.bypass_all = true;
flow->rule.bypass_igr_stp = true;
flow->rule.bypass_ibc_sc = true;
}
static int rtl83xx_parse_fwd(struct rtl838x_switch_priv *priv,
const struct flow_action_entry *act, struct rtl83xx_flow *flow)
{
struct net_device *dev = act->dev;
int port;
port = rtl83xx_port_is_under(dev, priv);
if (port < 0) {
netdev_info(dev, "%s: not a DSA device.\n", __func__);
return -EINVAL;
}
flow->rule.fwd_sel = true;
flow->rule.fwd_data = port;
pr_debug("Using port index: %d\n", port);
rtl83xx_flow_bypass_all(flow);
return 0;
}
static int rtl83xx_add_flow(struct rtl838x_switch_priv *priv, struct flow_cls_offload *f,
struct rtl83xx_flow *flow)
{
struct flow_rule *rule = flow_cls_offload_flow_rule(f);
const struct flow_action_entry *act;
int i, err;
pr_debug("%s\n", __func__);
rtl83xx_parse_flow_rule(priv, rule, flow);
flow_action_for_each(i, act, &rule->action) {
switch (act->id) {
case FLOW_ACTION_DROP:
pr_debug("%s: DROP\n", __func__);
flow->rule.drop = true;
rtl83xx_flow_bypass_all(flow);
return 0;
case FLOW_ACTION_TRAP:
pr_debug("%s: TRAP\n", __func__);
flow->rule.fwd_data = priv->cpu_port;
flow->rule.fwd_act = PIE_ACT_REDIRECT_TO_PORT;
rtl83xx_flow_bypass_all(flow);
break;
case FLOW_ACTION_MANGLE:
pr_err("%s: FLOW_ACTION_MANGLE not supported\n", __func__);
return -EOPNOTSUPP;
case FLOW_ACTION_ADD:
pr_err("%s: FLOW_ACTION_ADD not supported\n", __func__);
return -EOPNOTSUPP;
case FLOW_ACTION_VLAN_PUSH:
pr_debug("%s: VLAN_PUSH\n", __func__);
/* TODO: act->vlan.proto */
flow->rule.ivid_act = PIE_ACT_VID_ASSIGN;
flow->rule.ivid_sel = true;
flow->rule.ivid_data = htons(act->vlan.vid);
flow->rule.ovid_act = PIE_ACT_VID_ASSIGN;
flow->rule.ovid_sel = true;
flow->rule.ovid_data = htons(act->vlan.vid);
flow->rule.fwd_mod_to_cpu = true;
break;
case FLOW_ACTION_VLAN_POP:
pr_debug("%s: VLAN_POP\n", __func__);
flow->rule.ivid_act = PIE_ACT_VID_ASSIGN;
flow->rule.ivid_data = 0;
flow->rule.ivid_sel = true;
flow->rule.ovid_act = PIE_ACT_VID_ASSIGN;
flow->rule.ovid_data = 0;
flow->rule.ovid_sel = true;
flow->rule.fwd_mod_to_cpu = true;
break;
case FLOW_ACTION_CSUM:
pr_err("%s: FLOW_ACTION_CSUM not supported\n", __func__);
return -EOPNOTSUPP;
case FLOW_ACTION_REDIRECT:
pr_debug("%s: REDIRECT\n", __func__);
err = rtl83xx_parse_fwd(priv, act, flow);
if (err)
return err;
flow->rule.fwd_act = PIE_ACT_REDIRECT_TO_PORT;
break;
case FLOW_ACTION_MIRRED:
pr_debug("%s: MIRRED\n", __func__);
err = rtl83xx_parse_fwd(priv, act, flow);
if (err)
return err;
flow->rule.fwd_act = PIE_ACT_COPY_TO_PORT;
break;
default:
pr_err("%s: Flow action not supported: %d\n", __func__, act->id);
return -EOPNOTSUPP;
}
}
return 0;
}
static const struct rhashtable_params tc_ht_params = {
.head_offset = offsetof(struct rtl83xx_flow, node),
.key_offset = offsetof(struct rtl83xx_flow, cookie),
.key_len = sizeof(((struct rtl83xx_flow *)0)->cookie),
.automatic_shrinking = true,
};
static int rtl83xx_configure_flower(struct rtl838x_switch_priv *priv,
struct flow_cls_offload *f)
{
struct rtl83xx_flow *flow;
int err = 0;
pr_debug("In %s\n", __func__);
rcu_read_lock();
pr_debug("Cookie %08lx\n", f->cookie);
flow = rhashtable_lookup(&priv->tc_ht, &f->cookie, tc_ht_params);
if (flow) {
pr_info("%s: Got flow\n", __func__);
err = -EEXIST;
goto rcu_unlock;
}
rcu_unlock:
rcu_read_unlock();
if (flow)
goto out;
pr_debug("%s: New flow\n", __func__);
flow = kzalloc(sizeof(*flow), GFP_KERNEL);
if (!flow) {
err = -ENOMEM;
goto out;
}
flow->cookie = f->cookie;
flow->priv = priv;
err = rhashtable_insert_fast(&priv->tc_ht, &flow->node, tc_ht_params);
if (err) {
pr_err("Could not insert add new rule\n");
goto out_free;
}
rtl83xx_add_flow(priv, f, flow); /* TODO: check error */
/* Add log action to flow */
flow->rule.packet_cntr = rtl83xx_packet_cntr_alloc(priv);
if (flow->rule.packet_cntr >= 0) {
pr_debug("Using packet counter %d\n", flow->rule.packet_cntr);
flow->rule.log_sel = true;
flow->rule.log_data = flow->rule.packet_cntr;
}
err = priv->r->pie_rule_add(priv, &flow->rule);
return err;
out_free:
kfree(flow);
out:
pr_err("%s: error %d\n", __func__, err);
return err;
}
static int rtl83xx_delete_flower(struct rtl838x_switch_priv *priv,
struct flow_cls_offload * cls_flower)
{
struct rtl83xx_flow *flow;
pr_debug("In %s\n", __func__);
rcu_read_lock();
flow = rhashtable_lookup_fast(&priv->tc_ht, &cls_flower->cookie, tc_ht_params);
if (!flow) {
rcu_read_unlock();
return -EINVAL;
}
priv->r->pie_rule_rm(priv, &flow->rule);
rhashtable_remove_fast(&priv->tc_ht, &flow->node, tc_ht_params);
kfree_rcu(flow, rcu_head);
rcu_read_unlock();
return 0;
}
static int rtl83xx_stats_flower(struct rtl838x_switch_priv *priv,
struct flow_cls_offload * cls_flower)
{
struct rtl83xx_flow *flow;
unsigned long lastused = 0;
int total_packets, new_packets;
pr_debug("%s: \n", __func__);
flow = rhashtable_lookup_fast(&priv->tc_ht, &cls_flower->cookie, tc_ht_params);
if (!flow)
return -1;
if (flow->rule.packet_cntr >= 0) {
total_packets = priv->r->packet_cntr_read(flow->rule.packet_cntr);
pr_debug("Total packets: %d\n", total_packets);
new_packets = total_packets - flow->rule.last_packet_cnt;
flow->rule.last_packet_cnt = total_packets;
}
/* TODO: We need a second PIE rule to count the bytes */
flow_stats_update(&cls_flower->stats, 100 * new_packets, new_packets, 0, lastused,
FLOW_ACTION_HW_STATS_IMMEDIATE);
return 0;
}
static int rtl83xx_setup_tc_cls_flower(struct rtl838x_switch_priv *priv,
struct flow_cls_offload *cls_flower)
{
pr_debug("%s: %d\n", __func__, cls_flower->command);
switch (cls_flower->command) {
case FLOW_CLS_REPLACE:
return rtl83xx_configure_flower(priv, cls_flower);
case FLOW_CLS_DESTROY:
return rtl83xx_delete_flower(priv, cls_flower);
case FLOW_CLS_STATS:
return rtl83xx_stats_flower(priv, cls_flower);
default:
return -EOPNOTSUPP;
}
}
static int rtl83xx_setup_tc_block_cb(enum tc_setup_type type, void *type_data,
void *cb_priv)
{
struct rtl838x_switch_priv *priv = cb_priv;
switch (type) {
case TC_SETUP_CLSFLOWER:
pr_debug("%s: TC_SETUP_CLSFLOWER\n", __func__);
return rtl83xx_setup_tc_cls_flower(priv, type_data);
default:
return -EOPNOTSUPP;
}
}
static LIST_HEAD(rtl83xx_block_cb_list);
int rtl83xx_setup_tc(struct net_device *dev, enum tc_setup_type type, void *type_data)
{
struct rtl838x_switch_priv *priv;
struct flow_block_offload *f = type_data;
static bool first_time = true;
int err;
pr_debug("%s: %d\n", __func__, type);
if(!netdev_uses_dsa(dev)) {
pr_err("%s: no DSA\n", __func__);
return 0;
}
priv = dev->dsa_ptr->ds->priv;
switch (type) {
case TC_SETUP_BLOCK:
if (first_time) {
first_time = false;
err = rhashtable_init(&priv->tc_ht, &tc_ht_params);
if (err)
pr_err("%s: Could not initialize hash table\n", __func__);
}
f->unlocked_driver_cb = true;
return flow_block_cb_setup_simple(type_data,
&rtl83xx_block_cb_list,
rtl83xx_setup_tc_block_cb,
priv, priv, true);
default:
return -EOPNOTSUPP;
}
return 0;
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,469 @@
/* SPDX-License-Identifier: GPL-2.0-only */
#ifndef _RTL838X_ETH_H
#define _RTL838X_ETH_H
/* Register definition */
/* Per port MAC control */
#define RTL838X_MAC_PORT_CTRL (0xd560)
#define RTL839X_MAC_PORT_CTRL (0x8004)
#define RTL930X_MAC_L2_PORT_CTRL (0x3268)
#define RTL930X_MAC_PORT_CTRL (0x3260)
#define RTL931X_MAC_L2_PORT_CTRL (0x6000)
#define RTL931X_MAC_PORT_CTRL (0x6004)
/* DMA interrupt control and status registers */
#define RTL838X_DMA_IF_CTRL (0x9f58)
#define RTL838X_DMA_IF_INTR_STS (0x9f54)
#define RTL838X_DMA_IF_INTR_MSK (0x9f50)
#define RTL839X_DMA_IF_CTRL (0x786c)
#define RTL839X_DMA_IF_INTR_STS (0x7868)
#define RTL839X_DMA_IF_INTR_MSK (0x7864)
#define RTL930X_DMA_IF_CTRL (0xe028)
#define RTL930X_DMA_IF_INTR_RX_RUNOUT_STS (0xe01C)
#define RTL930X_DMA_IF_INTR_RX_DONE_STS (0xe020)
#define RTL930X_DMA_IF_INTR_TX_DONE_STS (0xe024)
#define RTL930X_DMA_IF_INTR_RX_RUNOUT_MSK (0xe010)
#define RTL930X_DMA_IF_INTR_RX_DONE_MSK (0xe014)
#define RTL930X_DMA_IF_INTR_TX_DONE_MSK (0xe018)
#define RTL930X_L2_NTFY_IF_INTR_MSK (0xe04C)
#define RTL930X_L2_NTFY_IF_INTR_STS (0xe050)
/* TODO: RTL931X_DMA_IF_CTRL has different bits meanings */
#define RTL931X_DMA_IF_CTRL (0x0928)
#define RTL931X_DMA_IF_INTR_RX_RUNOUT_STS (0x091c)
#define RTL931X_DMA_IF_INTR_RX_DONE_STS (0x0920)
#define RTL931X_DMA_IF_INTR_TX_DONE_STS (0x0924)
#define RTL931X_DMA_IF_INTR_RX_RUNOUT_MSK (0x0910)
#define RTL931X_DMA_IF_INTR_RX_DONE_MSK (0x0914)
#define RTL931X_DMA_IF_INTR_TX_DONE_MSK (0x0918)
#define RTL931X_L2_NTFY_IF_INTR_MSK (0x09E4)
#define RTL931X_L2_NTFY_IF_INTR_STS (0x09E8)
#define RTL838X_MAC_FORCE_MODE_CTRL (0xa104)
#define RTL839X_MAC_FORCE_MODE_CTRL (0x02bc)
#define RTL930X_MAC_FORCE_MODE_CTRL (0xCA1C)
#define RTL931X_MAC_FORCE_MODE_CTRL (0x0ddc)
/* MAC address settings */
#define RTL838X_MAC (0xa9ec)
#define RTL839X_MAC (0x02b4)
#define RTL838X_MAC_ALE (0x6b04)
#define RTL838X_MAC2 (0xa320)
#define RTL930X_MAC_L2_ADDR_CTRL (0xC714)
#define RTL931X_MAC_L2_ADDR_CTRL (0x135c)
/* Ringbuffer setup */
#define RTL838X_DMA_RX_BASE (0x9f00)
#define RTL839X_DMA_RX_BASE (0x780c)
#define RTL930X_DMA_RX_BASE (0xdf00)
#define RTL931X_DMA_RX_BASE (0x0800)
#define RTL838X_DMA_TX_BASE (0x9f40)
#define RTL839X_DMA_TX_BASE (0x784c)
#define RTL930X_DMA_TX_BASE (0xe000)
#define RTL931X_DMA_TX_BASE (0x0900)
#define RTL838X_DMA_IF_RX_RING_SIZE (0xB7E4)
#define RTL839X_DMA_IF_RX_RING_SIZE (0x6038)
#define RTL930X_DMA_IF_RX_RING_SIZE (0x7C60)
#define RTL931X_DMA_IF_RX_RING_SIZE (0x2080)
#define RTL838X_DMA_IF_RX_RING_CNTR (0xB7E8)
#define RTL839X_DMA_IF_RX_RING_CNTR (0x603c)
#define RTL930X_DMA_IF_RX_RING_CNTR (0x7C8C)
#define RTL931X_DMA_IF_RX_RING_CNTR (0x20AC)
#define RTL838X_DMA_IF_RX_CUR (0x9F20)
#define RTL839X_DMA_IF_RX_CUR (0x782c)
#define RTL930X_DMA_IF_RX_CUR (0xdf80)
#define RTL931X_DMA_IF_RX_CUR (0x0880)
#define RTL838X_DMA_IF_TX_CUR_DESC_ADDR_CTRL (0x9F48)
#define RTL930X_DMA_IF_TX_CUR_DESC_ADDR_CTRL (0xE008)
#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)
/* L2 features */
#define RTL839X_TBL_ACCESS_L2_CTRL (0x1180)
#define RTL839X_TBL_ACCESS_L2_DATA(idx) (0x1184 + ((idx) << 2))
#define RTL838X_TBL_ACCESS_CTRL_0 (0x6914)
#define RTL838X_TBL_ACCESS_DATA_0(idx) (0x6918 + ((idx) << 2))
/* MAC-side link state handling */
#define RTL838X_MAC_LINK_STS (0xa188)
#define RTL839X_MAC_LINK_STS (0x0390)
#define RTL930X_MAC_LINK_STS (0xCB10)
#define RTL931X_MAC_LINK_STS (0x0ec0)
#define RTL838X_MAC_LINK_SPD_STS (0xa190)
#define RTL839X_MAC_LINK_SPD_STS (0x03a0)
#define RTL930X_MAC_LINK_SPD_STS (0xCB18)
#define RTL931X_MAC_LINK_SPD_STS (0x0ed0)
#define RTL838X_MAC_LINK_DUP_STS (0xa19c)
#define RTL839X_MAC_LINK_DUP_STS (0x03b0)
#define RTL930X_MAC_LINK_DUP_STS (0xCB28)
#define RTL931X_MAC_LINK_DUP_STS (0x0ef0)
/* TODO: RTL8390_MAC_LINK_MEDIA_STS_ADDR??? */
#define RTL838X_MAC_TX_PAUSE_STS (0xa1a0)
#define RTL839X_MAC_TX_PAUSE_STS (0x03b8)
#define RTL930X_MAC_TX_PAUSE_STS (0xCB2C)
#define RTL931X_MAC_TX_PAUSE_STS (0x0ef8)
#define RTL838X_MAC_RX_PAUSE_STS (0xa1a4)
#define RTL839X_MAC_RX_PAUSE_STS (0xCB30)
#define RTL930X_MAC_RX_PAUSE_STS (0xC2F8)
#define RTL931X_MAC_RX_PAUSE_STS (0x0f00)
#define RTL838X_EEE_TX_TIMER_GIGA_CTRL (0xaa04)
#define RTL838X_EEE_TX_TIMER_GELITE_CTRL (0xaa08)
#define RTL930X_L2_UNKN_UC_FLD_PMSK (0x9064)
#define RTL931X_L2_UNKN_UC_FLD_PMSK (0xC8F4)
#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)
#define RTL930X_L2_TBL_FLUSH_CTRL (0x9404)
#define RTL931X_L2_TBL_FLUSH_CTRL (0xCD9C)
#define RTL930X_L2_PORT_SABLK_CTRL (0x905c)
#define RTL930X_L2_PORT_DABLK_CTRL (0x9060)
/* 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)
/* L2 Notification DMA interface */
#define RTL839X_DMA_IF_NBUF_BASE_DESC_ADDR_CTRL (0x785C)
#define RTL839X_L2_NOTIFICATION_CTRL (0x7808)
#define RTL931X_L2_NTFY_RING_BASE_ADDR (0x09DC)
#define RTL931X_L2_NTFY_RING_CUR_ADDR (0x09E0)
#define RTL839X_L2_NOTIFICATION_CTRL (0x7808)
#define RTL931X_L2_NTFY_CTRL (0xCDC8)
#define RTL838X_L2_CTRL_0 (0x3200)
#define RTL839X_L2_CTRL_0 (0x3800)
#define RTL930X_L2_CTRL (0x8FD8)
#define RTL931X_L2_CTRL (0xC800)
/* TRAPPING to CPU-PORT */
#define RTL838X_SPCL_TRAP_IGMP_CTRL (0x6984)
#define RTL838X_RMA_CTRL_0 (0x4300)
#define RTL838X_RMA_CTRL_1 (0x4304)
#define RTL839X_RMA_CTRL_0 (0x1200)
#define RTL839X_SPCL_TRAP_IGMP_CTRL (0x1058)
#define RTL839X_RMA_CTRL_1 (0x1204)
#define RTL839X_RMA_CTRL_2 (0x1208)
#define RTL839X_RMA_CTRL_3 (0x120C)
#define RTL930X_VLAN_APP_PKT_CTRL (0xA23C)
#define RTL930X_RMA_CTRL_0 (0x9E60)
#define RTL930X_RMA_CTRL_1 (0x9E64)
#define RTL930X_RMA_CTRL_2 (0x9E68)
#define RTL931X_VLAN_APP_PKT_CTRL (0x96b0)
#define RTL931X_RMA_CTRL_0 (0x8800)
#define RTL931X_RMA_CTRL_1 (0x8804)
#define RTL931X_RMA_CTRL_2 (0x8808)
/* Advanced SMI control for clause 45 PHYs */
#define RTL930X_SMI_MAC_TYPE_CTRL (0xCA04)
#define RTL930X_SMI_PORT24_27_ADDR_CTRL (0xCB90)
#define RTL930X_SMI_PORT0_15_POLLING_SEL (0xCA08)
#define RTL930X_SMI_PORT16_27_POLLING_SEL (0xCA0C)
#define RTL930X_SMI_10GPHY_POLLING_REG0_CFG (0xCBB4)
#define RTL930X_SMI_10GPHY_POLLING_REG9_CFG (0xCBB8)
#define RTL930X_SMI_10GPHY_POLLING_REG10_CFG (0xCBBC)
#define RTL930X_SMI_PRVTE_POLLING_CTRL (0xCA10)
/* Registers of the internal Serdes of the 8390 */
#define RTL839X_SDS12_13_XSG0 (0xB800)
/* Chip configuration registers of the RTL9310 */
#define RTL931X_MEM_ENCAP_INIT (0x4854)
#define RTL931X_MEM_MIB_INIT (0x7E18)
#define RTL931X_MEM_ACL_INIT (0x40BC)
#define RTL931X_MEM_ALE_INIT_0 (0x83F0)
#define RTL931X_MEM_ALE_INIT_1 (0x83F4)
#define RTL931X_MEM_ALE_INIT_2 (0x82E4)
#define RTL931X_MDX_CTRL_RSVD (0x0fcc)
#define RTL931X_PS_SOC_CTRL (0x13f8)
#define RTL931X_SMI_10GPHY_POLLING_SEL2 (0xCF8)
#define RTL931X_SMI_10GPHY_POLLING_SEL3 (0xCFC)
#define RTL931X_SMI_10GPHY_POLLING_SEL4 (0xD00)
/* Registers of the internal Serdes of the 8380 */
#define RTL838X_SDS4_FIB_REG0 (0xF800)
/* Default MTU with jumbo frames support */
#define DEFAULT_MTU 9000
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);
}
/* On the RTL931XX, the functionality of the MAC port control register is split up
* into RTL931X_MAC_L2_PORT_CTRL and RTL931X_MAC_PORT_CTRL the functionality used
* by the Ethernet driver is in the same bits now in RTL931X_MAC_L2_PORT_CTRL
*/
inline int rtl930x_mac_port_ctrl(int p)
{
return RTL930X_MAC_L2_PORT_CTRL + (p << 6);
}
inline int rtl931x_mac_port_ctrl(int p)
{
return RTL931X_MAC_L2_PORT_CTRL + (p << 7);
}
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 rtl930x_dma_if_rx_ring_size(int i)
{
return RTL930X_DMA_IF_RX_RING_SIZE + ((i / 3) << 2);
}
inline int rtl931x_dma_if_rx_ring_size(int i)
{
return RTL931X_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 rtl930x_dma_if_rx_ring_cntr(int i)
{
return RTL930X_DMA_IF_RX_RING_CNTR + ((i / 3) << 2);
}
inline int rtl931x_dma_if_rx_ring_cntr(int i)
{
return RTL931X_DMA_IF_RX_RING_CNTR + ((i / 3) << 2);
}
inline u32 rtl838x_get_mac_link_sts(int port)
{
return (sw_r32(RTL838X_MAC_LINK_STS) & BIT(port));
}
inline u32 rtl839x_get_mac_link_sts(int p)
{
return (sw_r32(RTL839X_MAC_LINK_STS + ((p >> 5) << 2)) & BIT(p % 32));
}
inline u32 rtl930x_get_mac_link_sts(int port)
{
u32 link = sw_r32(RTL930X_MAC_LINK_STS);
link = sw_r32(RTL930X_MAC_LINK_STS);
pr_info("%s link state is %08x\n", __func__, link);
return link & BIT(port);
}
inline u32 rtl931x_get_mac_link_sts(int p)
{
return (sw_r32(RTL931X_MAC_LINK_STS + ((p >> 5) << 2)) & BIT(p % 32));
}
inline u32 rtl838x_get_mac_link_dup_sts(int port)
{
return (sw_r32(RTL838X_MAC_LINK_DUP_STS) & BIT(port));
}
inline u32 rtl839x_get_mac_link_dup_sts(int p)
{
return (sw_r32(RTL839X_MAC_LINK_DUP_STS + ((p >> 5) << 2)) & BIT(p % 32));
}
inline u32 rtl930x_get_mac_link_dup_sts(int port)
{
return (sw_r32(RTL930X_MAC_LINK_DUP_STS) & BIT(port));
}
inline u32 rtl931x_get_mac_link_dup_sts(int p)
{
return (sw_r32(RTL931X_MAC_LINK_DUP_STS + ((p >> 5) << 2)) & BIT(p % 32));
}
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 rtl930x_get_mac_link_spd_sts(int port)
{
int r = RTL930X_MAC_LINK_SPD_STS + ((port >> 3) << 2);
u32 speed = sw_r32(r);
speed >>= (port % 8) << 2;
return (speed & 0xf);
}
inline u32 rtl931x_get_mac_link_spd_sts(int port)
{
int r = RTL931X_MAC_LINK_SPD_STS + ((port >> 3) << 2);
u32 speed = sw_r32(r);
speed >>= (port % 8) << 2;
return (speed & 0xf);
}
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)) & BIT(p % 32));
}
inline u32 rtl930x_get_mac_rx_pause_sts(int port)
{
return (sw_r32(RTL930X_MAC_RX_PAUSE_STS) & (1 << port));
}
inline u32 rtl931x_get_mac_rx_pause_sts(int p)
{
return (sw_r32(RTL931X_MAC_RX_PAUSE_STS + ((p >> 5) << 2)) & BIT(p % 32));
}
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)) & BIT(p % 32));
}
inline u32 rtl930x_get_mac_tx_pause_sts(int port)
{
return (sw_r32(RTL930X_MAC_TX_PAUSE_STS) & (1 << port));
}
inline u32 rtl931x_get_mac_tx_pause_sts(int p)
{
return (sw_r32(RTL931X_MAC_TX_PAUSE_STS + ((p >> 5) << 2)) & BIT(p % 32));
}
struct p_hdr;
struct dsa_tag;
struct rtl838x_bus_priv {
struct rtl838x_eth_priv *eth_priv;
int portaddr;
int page[64];
bool raw[64];
int (*read_mmd_phy)(u32 port, u32 addr, u32 reg, u32 *val);
int (*write_mmd_phy)(u32 port, u32 addr, u32 reg, u32 val);
int (*read_phy)(u32 port, u32 page, u32 reg, u32 *val);
int (*write_phy)(u32 port, u32 page, u32 reg, u32 val);
};
struct rtl838x_eth_reg {
irqreturn_t (*net_irq)(int irq, void *dev_id);
int (*mac_port_ctrl)(int port);
int dma_if_intr_sts;
int dma_if_intr_msk;
int dma_if_intr_rx_runout_sts;
int dma_if_intr_rx_done_sts;
int dma_if_intr_tx_done_sts;
int dma_if_intr_rx_runout_msk;
int dma_if_intr_rx_done_msk;
int dma_if_intr_tx_done_msk;
int l2_ntfy_if_intr_sts;
int l2_ntfy_if_intr_msk;
int dma_if_ctrl;
int mac_force_mode_ctrl;
int dma_rx_base;
int dma_tx_base;
int (*dma_if_rx_ring_size)(int ring);
int (*dma_if_rx_ring_cntr)(int ring);
int dma_if_rx_cur;
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;
void (*update_cntr)(int r, int work_done);
void (*create_tx_header)(struct p_hdr *h, unsigned int dest_port, int prio);
bool (*decode_tag)(struct p_hdr *h, struct dsa_tag *tag);
};
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 rtl838x_write_mmd_phy(u32 port, u32 addr, u32 reg, u32 val);
int rtl838x_read_mmd_phy(u32 port, u32 addr, 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);
int rtl839x_read_mmd_phy(u32 port, u32 devnum, u32 regnum, u32 *val);
int rtl839x_write_mmd_phy(u32 port, u32 devnum, u32 regnum, u32 val);
int rtl930x_write_phy(u32 port, u32 page, u32 reg, u32 val);
int rtl930x_read_phy(u32 port, u32 page, u32 reg, u32 *val);
int rtl931x_write_phy(u32 port, u32 page, u32 reg, u32 val);
int rtl931x_read_phy(u32 port, u32 page, u32 reg, u32 *val);
int rtl83xx_setup_tc(struct net_device *dev, enum tc_setup_type type, void *type_data);
#endif /* _RTL838X_ETH_H */

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,64 @@
// SPDX-License-Identifier: GPL-2.0-only
struct rtl83xx_shared_private {
char *name;
};
struct __attribute__ ((__packed__)) part {
uint16_t start;
uint8_t wordsize;
uint8_t words;
};
struct __attribute__ ((__packed__)) fw_header {
uint32_t magic;
uint32_t phy;
uint32_t checksum;
uint32_t version;
struct part parts[10];
};
/* TODO: fixed path? */
#define FIRMWARE_838X_8380_1 "rtl838x_phy/rtl838x_8380.fw"
#define FIRMWARE_838X_8214FC_1 "rtl838x_phy/rtl838x_8214fc.fw"
#define FIRMWARE_838X_8218b_1 "rtl838x_phy/rtl838x_8218b.fw"
/* External RTL8218B and RTL8214FC IDs are identical */
#define PHY_ID_RTL8214C 0x001cc942
#define PHY_ID_RTL8214FC 0x001cc981
#define PHY_ID_RTL8218B_E 0x001cc981
#define PHY_ID_RTL8218D 0x001cc983
#define PHY_ID_RTL8218B_I 0x001cca40
#define PHY_ID_RTL8221B 0x001cc849
#define PHY_ID_RTL8226 0x001cc838
#define PHY_ID_RTL8390_GENERIC 0x001ccab0
#define PHY_ID_RTL8393_I 0x001c8393
#define PHY_ID_RTL9300_I 0x70d03106
/* Registers of the internal Serdes of the 8380 */
#define RTL838X_SDS_MODE_SEL (0x0028)
#define RTL838X_SDS_CFG_REG (0x0034)
#define RTL838X_INT_MODE_CTRL (0x005c)
#define RTL838X_DMY_REG31 (0x3b28)
#define RTL8380_SDS4_FIB_REG0 (0xF800)
#define RTL838X_SDS4_REG28 (0xef80)
#define RTL838X_SDS4_DUMMY0 (0xef8c)
#define RTL838X_SDS5_EXT_REG6 (0xf18c)
#define RTL838X_SDS4_FIB_REG0 (RTL838X_SDS4_REG28 + 0x880)
#define RTL838X_SDS5_FIB_REG0 (RTL838X_SDS4_REG28 + 0x980)
/* Registers of the internal SerDes of the RTL8390 */
#define RTL839X_SDS12_13_XSG0 (0xB800)
/* Registers of the internal Serdes of the 9300 */
#define RTL930X_SDS_INDACS_CMD (0x03B0)
#define RTL930X_SDS_INDACS_DATA (0x03B4)
#define RTL930X_MAC_FORCE_MODE_CTRL (0xCA1C)
/* Registers of the internal SerDes of the 9310 */
#define RTL931X_SERDES_INDRT_ACCESS_CTRL (0x5638)
#define RTL931X_SERDES_INDRT_DATA_CTRL (0x563C)
#define RTL931X_SERDES_MODE_CTRL (0x13cc)
#define RTL931X_PS_SERDES_OFF_MODE_CTRL_ADDR (0x13F4)
#define RTL931X_MAC_SERDES_MODE_CTRL(sds) (0x136C + (((sds) << 2)))

View File

@ -0,0 +1,15 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (C) 2022 Markus Stockhausen
*
* RTL83XX clock indices
*/
#ifndef __DT_BINDINGS_CLOCK_RTL83XX_H
#define __DT_BINDINGS_CLOCK_RTL83XX_H
#define CLK_CPU 0
#define CLK_MEM 1
#define CLK_LXB 2
#define CLK_COUNT 3
#endif /* __DT_BINDINGS_CLOCK_RTL83XX_H */

View File

@ -0,0 +1,224 @@
CONFIG_ARCH_32BIT_OFF_T=y
CONFIG_ARCH_HIBERNATION_POSSIBLE=y
CONFIG_ARCH_KEEP_MEMBLOCK=y
CONFIG_ARCH_MMAP_RND_BITS_MAX=15
CONFIG_ARCH_MMAP_RND_COMPAT_BITS_MAX=15
CONFIG_ARCH_SUSPEND_POSSIBLE=y
CONFIG_BLK_DEV_RAM=y
CONFIG_BLK_DEV_RAM_COUNT=16
CONFIG_BLK_DEV_RAM_SIZE=4096
# CONFIG_BMIPS_CPUFREQ is not set
CONFIG_CLONE_BACKWARDS=y
CONFIG_COMMON_CLK=y
CONFIG_COMMON_CLK_REALTEK=y
CONFIG_COMMON_CLK_RTL83XX=y
CONFIG_COMPAT_32BIT_TIME=y
CONFIG_CONSOLE_LOGLEVEL_DEFAULT=15
CONFIG_CPUFREQ_DT=y
CONFIG_CPUFREQ_DT_PLATDEV=y
CONFIG_CPU_BIG_ENDIAN=y
CONFIG_CPU_FREQ=y
# CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE is not set
CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE=y
CONFIG_CPU_FREQ_GOV_ATTR_SET=y
CONFIG_CPU_FREQ_GOV_COMMON=y
# CONFIG_CPU_FREQ_GOV_CONSERVATIVE is not set
CONFIG_CPU_FREQ_GOV_ONDEMAND=y
CONFIG_CPU_FREQ_GOV_PERFORMANCE=y
CONFIG_CPU_FREQ_GOV_POWERSAVE=y
CONFIG_CPU_FREQ_GOV_USERSPACE=y
CONFIG_CPU_FREQ_STAT=y
CONFIG_CPU_GENERIC_DUMP_TLB=y
CONFIG_CPU_HAS_DIEI=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_CPUFREQ=y
CONFIG_CPU_SUPPORTS_HIGHMEM=y
CONFIG_CPU_SUPPORTS_MSA=y
CONFIG_CRYPTO_LIB_BLAKE2S_GENERIC=y
CONFIG_CRYPTO_LIB_POLY1305_RSIZE=2
CONFIG_CRYPTO_RNG2=y
CONFIG_DEBUG_SECTION_MISMATCH=y
CONFIG_DMA_NONCOHERENT=y
CONFIG_DTC=y
CONFIG_EARLY_PRINTK=y
CONFIG_EARLY_PRINTK_8250=y
CONFIG_EXTRA_FIRMWARE="rtl838x_phy/rtl838x_8214fc.fw rtl838x_phy/rtl838x_8218b.fw rtl838x_phy/rtl838x_8380.fw"
CONFIG_EXTRA_FIRMWARE_DIR="firmware"
CONFIG_FIXED_PHY=y
CONFIG_FORCE_MAX_ZONEORDER=13
CONFIG_FWNODE_MDIO=y
CONFIG_FW_LOADER_PAGED_BUF=y
CONFIG_GENERIC_ALLOCATOR=y
CONFIG_GENERIC_ATOMIC64=y
CONFIG_GENERIC_CLOCKEVENTS=y
CONFIG_GENERIC_CMOS_UPDATE=y
CONFIG_GENERIC_CPU_AUTOPROBE=y
CONFIG_GENERIC_FIND_FIRST_BIT=y
CONFIG_GENERIC_GETTIMEOFDAY=y
CONFIG_GENERIC_IOMAP=y
CONFIG_GENERIC_IRQ_CHIP=y
CONFIG_GENERIC_IRQ_EFFECTIVE_AFF_MASK=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_PINCONF=y
CONFIG_GENERIC_PINCTRL_GROUPS=y
CONFIG_GENERIC_PINMUX_FUNCTIONS=y
CONFIG_GENERIC_SCHED_CLOCK=y
CONFIG_GENERIC_SMP_IDLE_THREAD=y
CONFIG_GENERIC_TIME_VSYSCALL=y
CONFIG_GPIOLIB_IRQCHIP=y
CONFIG_GPIO_CDEV=y
CONFIG_GPIO_GENERIC=y
CONFIG_GPIO_PCA953X=y
CONFIG_GPIO_PCA953X_IRQ=y
CONFIG_GPIO_REALTEK_OTTO=y
CONFIG_GPIO_RTL8231=y
CONFIG_GPIO_WATCHDOG=y
# CONFIG_GPIO_WATCHDOG_ARCH_INITCALL is not set
CONFIG_GRO_CELLS=y
CONFIG_HANDLE_DOMAIN_IRQ=y
CONFIG_HARDWARE_WATCHPOINTS=y
CONFIG_HAS_DMA=y
CONFIG_HAS_IOMEM=y
CONFIG_HAS_IOPORT_MAP=y
CONFIG_HWMON=y
CONFIG_HZ_PERIODIC=y
CONFIG_I2C=y
CONFIG_I2C_ALGOBIT=y
CONFIG_I2C_BOARDINFO=y
CONFIG_I2C_CHARDEV=y
CONFIG_I2C_GPIO=y
CONFIG_I2C_MUX=y
# CONFIG_I2C_MUX_RTL9300 is not set
# CONFIG_I2C_RTL9300 is not set
CONFIG_INITRAMFS_SOURCE=""
CONFIG_IRQCHIP=y
CONFIG_IRQ_DOMAIN=y
CONFIG_IRQ_FORCED_THREADING=y
CONFIG_IRQ_MIPS_CPU=y
CONFIG_IRQ_WORK=y
CONFIG_JFFS2_ZLIB=y
CONFIG_LEDS_GPIO=y
CONFIG_LIBFDT=y
CONFIG_LOCK_DEBUGGING_SUPPORT=y
CONFIG_MARVELL_PHY=y
CONFIG_MDIO_BUS=y
CONFIG_MDIO_DEVICE=y
CONFIG_MDIO_DEVRES=y
CONFIG_MDIO_I2C=y
CONFIG_MDIO_SMBUS=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_CMDLINE_FROM_BOOTLOADER is not set
CONFIG_MIPS_CMDLINE_FROM_DTB=y
CONFIG_MIPS_EBPF_JIT=y
CONFIG_MIPS_EXTERNAL_TIMER=y
CONFIG_MIPS_L1_CACHE_SHIFT=5
CONFIG_MIPS_LD_CAN_LINK_VDSO=y
# CONFIG_MIPS_NO_APPENDED_DTB is not set
CONFIG_MIPS_RAW_APPENDED_DTB=y
CONFIG_MIPS_SPRAM=y
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_H3C_VFS=y
CONFIG_MTD_SPLIT_TPLINK_FW=y
CONFIG_MTD_SPLIT_UIMAGE_FW=y
CONFIG_MTD_VIRT_CONCAT=y
CONFIG_NEED_DMA_MAP_STATE=y
CONFIG_NEED_PER_CPU_KM=y
CONFIG_NET_DEVLINK=y
CONFIG_NET_DSA=y
CONFIG_NET_DSA_RTL83XX=y
CONFIG_NET_DSA_TAG_TRAILER=y
CONFIG_NET_RTL838X=y
CONFIG_NET_SELFTESTS=y
CONFIG_NET_SWITCHDEV=y
CONFIG_NO_EXCEPT_FILL=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_PCI_DRIVERS_LEGACY=y
CONFIG_PERF_USE_VMALLOC=y
CONFIG_PGTABLE_LEVELS=2
CONFIG_PHYLIB=y
CONFIG_PHYLINK=y
CONFIG_PINCTRL=y
CONFIG_PM_OPP=y
CONFIG_POWER_RESET=y
CONFIG_POWER_RESET_GPIO_RESTART=y
CONFIG_POWER_RESET_SYSCON=y
CONFIG_PTP_1588_CLOCK_OPTIONAL=y
CONFIG_RATIONAL=y
CONFIG_REALTEK_OTTO_TIMER=y
CONFIG_REALTEK_OTTO_WDT=y
CONFIG_REALTEK_PHY=y
CONFIG_REALTEK_SOC_PHY=y
CONFIG_REGMAP=y
CONFIG_REGMAP_I2C=y
CONFIG_REGMAP_MMIO=y
CONFIG_RESET_CONTROLLER=y
CONFIG_RTL838X=y
# CONFIG_RTL839X is not set
CONFIG_RTL83XX=y
# CONFIG_RTL930X is not set
CONFIG_SERIAL_MCTRL_GPIO=y
CONFIG_SERIAL_OF_PLATFORM=y
CONFIG_SFP=y
CONFIG_SPI=y
CONFIG_SPI_MASTER=y
CONFIG_SPI_MEM=y
CONFIG_SRAM=y
CONFIG_SRCU=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_HIGHMEM=y
CONFIG_SYS_SUPPORTS_MIPS16=y
CONFIG_TARGET_ISA_REV=2
CONFIG_TICK_CPU_ACCOUNTING=y
CONFIG_TIMER_OF=y
CONFIG_TIMER_PROBE=y
CONFIG_TINY_SRCU=y
CONFIG_USE_GENERIC_EARLY_PRINTK_8250=y
CONFIG_USE_OF=y
CONFIG_WATCHDOG_CORE=y
CONFIG_ZLIB_DEFLATE=y
CONFIG_ZLIB_INFLATE=y

View File

@ -0,0 +1,241 @@
CONFIG_ARCH_32BIT_OFF_T=y
CONFIG_ARCH_KEEP_MEMBLOCK=y
CONFIG_ARCH_MMAP_RND_BITS_MAX=15
CONFIG_ARCH_MMAP_RND_COMPAT_BITS_MAX=15
CONFIG_BLK_DEV_RAM=y
CONFIG_BLK_DEV_RAM_COUNT=16
CONFIG_BLK_DEV_RAM_SIZE=4096
# CONFIG_BMIPS_CPUFREQ is not set
CONFIG_CLKDEV_LOOKUP=y
CONFIG_CLONE_BACKWARDS=y
CONFIG_COMMON_CLK=y
CONFIG_COMMON_CLK_REALTEK=y
CONFIG_COMMON_CLK_RTL83XX=y
CONFIG_COMPAT_32BIT_TIME=y
CONFIG_CONSOLE_LOGLEVEL_DEFAULT=15
CONFIG_CPUFREQ_DT=y
CONFIG_CPUFREQ_DT_PLATDEV=y
CONFIG_CPU_BIG_ENDIAN=y
CONFIG_CPU_FREQ=y
# CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE is not set
CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE=y
CONFIG_CPU_FREQ_GOV_ATTR_SET=y
CONFIG_CPU_FREQ_GOV_COMMON=y
# CONFIG_CPU_FREQ_GOV_CONSERVATIVE is not set
CONFIG_CPU_FREQ_GOV_ONDEMAND=y
CONFIG_CPU_FREQ_GOV_PERFORMANCE=y
CONFIG_CPU_FREQ_GOV_POWERSAVE=y
CONFIG_CPU_FREQ_GOV_USERSPACE=y
CONFIG_CPU_FREQ_STAT=y
CONFIG_CPU_GENERIC_DUMP_TLB=y
CONFIG_CPU_HAS_DIEI=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_MIPSR2_IRQ_EI=y
CONFIG_CPU_MIPSR2_IRQ_VI=y
CONFIG_CPU_NEEDS_NO_SMARTMIPS_OR_MICROMIPS=y
CONFIG_CPU_R4K_CACHE_TLB=y
CONFIG_CPU_RMAP=y
CONFIG_CPU_SUPPORTS_32BIT_KERNEL=y
CONFIG_CPU_SUPPORTS_CPUFREQ=y
CONFIG_CPU_SUPPORTS_HIGHMEM=y
CONFIG_CPU_SUPPORTS_MSA=y
CONFIG_CRYPTO_LIB_BLAKE2S_GENERIC=y
CONFIG_CRYPTO_LIB_POLY1305_RSIZE=2
CONFIG_CRYPTO_RNG2=y
CONFIG_DEBUG_SECTION_MISMATCH=y
CONFIG_DMA_NONCOHERENT=y
CONFIG_DTC=y
CONFIG_EARLY_PRINTK=y
CONFIG_EARLY_PRINTK_8250=y
CONFIG_FIXED_PHY=y
CONFIG_FORCE_MAX_ZONEORDER=13
CONFIG_FWNODE_MDIO=y
CONFIG_FW_LOADER_PAGED_BUF=y
CONFIG_GENERIC_ALLOCATOR=y
CONFIG_GENERIC_ATOMIC64=y
CONFIG_GENERIC_CLOCKEVENTS=y
CONFIG_GENERIC_CMOS_UPDATE=y
CONFIG_GENERIC_CPU_AUTOPROBE=y
CONFIG_GENERIC_FIND_FIRST_BIT=y
CONFIG_GENERIC_GETTIMEOFDAY=y
CONFIG_GENERIC_IOMAP=y
CONFIG_GENERIC_IRQ_CHIP=y
CONFIG_GENERIC_IRQ_EFFECTIVE_AFF_MASK=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_PINCONF=y
CONFIG_GENERIC_PINCTRL_GROUPS=y
CONFIG_GENERIC_PINMUX_FUNCTIONS=y
CONFIG_GENERIC_SCHED_CLOCK=y
CONFIG_GENERIC_SMP_IDLE_THREAD=y
CONFIG_GENERIC_TIME_VSYSCALL=y
CONFIG_GPIOLIB_IRQCHIP=y
CONFIG_GPIO_CDEV=y
CONFIG_GPIO_GENERIC=y
CONFIG_GPIO_PCA953X=y
CONFIG_GPIO_PCA953X_IRQ=y
CONFIG_GPIO_REALTEK_OTTO=y
CONFIG_GPIO_RTL8231=y
CONFIG_GRO_CELLS=y
CONFIG_HANDLE_DOMAIN_IRQ=y
CONFIG_HARDWARE_WATCHPOINTS=y
CONFIG_HAS_DMA=y
CONFIG_HAS_IOMEM=y
CONFIG_HAS_IOPORT_MAP=y
CONFIG_HWMON=y
CONFIG_HZ_PERIODIC=y
CONFIG_I2C=y
CONFIG_I2C_ALGOBIT=y
CONFIG_I2C_BOARDINFO=y
CONFIG_I2C_GPIO=y
# CONFIG_I2C_RTL9300 is not set
# CONFIG_I2C_MUX_RTL9300 is not set
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_JFFS2_ZLIB=y
CONFIG_LEDS_GPIO=y
CONFIG_LIBFDT=y
CONFIG_LOCK_DEBUGGING_SUPPORT=y
CONFIG_MARVELL_PHY=y
CONFIG_MDIO_BUS=y
CONFIG_MDIO_DEVICE=y
CONFIG_MDIO_DEVRES=y
CONFIG_MDIO_I2C=y
CONFIG_MDIO_SMBUS=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_EBPF_JIT=y
CONFIG_MIPS_EXTERNAL_TIMER=y
CONFIG_MIPS_L1_CACHE_SHIFT=5
CONFIG_MIPS_LD_CAN_LINK_VDSO=y
CONFIG_MIPS_MT=y
# CONFIG_MIPS_MT_FPAFF is not set
CONFIG_MIPS_MT_SMP=y
# CONFIG_MIPS_NO_APPENDED_DTB is not set
CONFIG_MIPS_NR_CPU_NR_MAP=2
CONFIG_MIPS_PERF_SHARED_TC_COUNTERS=y
CONFIG_MIPS_RAW_APPENDED_DTB=y
CONFIG_MIPS_SPRAM=y
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_MTD_VIRT_CONCAT=y
CONFIG_NEED_DMA_MAP_STATE=y
CONFIG_NET_DEVLINK=y
CONFIG_NET_DSA=y
CONFIG_NET_DSA_RTL83XX=y
CONFIG_NET_DSA_TAG_TRAILER=y
CONFIG_NET_FLOW_LIMIT=y
CONFIG_NET_RTL838X=y
CONFIG_NET_SELFTESTS=y
CONFIG_NET_SWITCHDEV=y
CONFIG_NO_EXCEPT_FILL=y
CONFIG_NO_GENERIC_PCI_IOPORT_MAP=y
CONFIG_NR_CPUS=2
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_PADATA=y
CONFIG_PCI_DRIVERS_LEGACY=y
CONFIG_PERF_USE_VMALLOC=y
CONFIG_PGTABLE_LEVELS=2
CONFIG_PHYLIB=y
CONFIG_PHYLINK=y
CONFIG_PINCTRL=y
CONFIG_PM_OPP=y
CONFIG_POWER_RESET=y
CONFIG_POWER_RESET_GPIO_RESTART=y
CONFIG_POWER_RESET_SYSCON=y
CONFIG_PTP_1588_CLOCK_OPTIONAL=y
CONFIG_QUEUED_RWLOCKS=y
CONFIG_QUEUED_SPINLOCKS=y
CONFIG_RATIONAL=y
CONFIG_REALTEK_OTTO_TIMER=y
CONFIG_REALTEK_OTTO_WDT=y
CONFIG_REALTEK_PHY=y
CONFIG_REALTEK_SOC_PHY=y
CONFIG_REGMAP=y
CONFIG_REGMAP_I2C=y
CONFIG_REGMAP_MMIO=y
CONFIG_RESET_CONTROLLER=y
CONFIG_RFS_ACCEL=y
CONFIG_RPS=y
# CONFIG_RTL838X is not set
CONFIG_RTL839X=y
CONFIG_RTL83XX=y
# CONFIG_RTL930X is not set
CONFIG_SERIAL_MCTRL_GPIO=y
CONFIG_SERIAL_OF_PLATFORM=y
CONFIG_SFP=y
CONFIG_SMP=y
CONFIG_SMP_UP=y
CONFIG_SOCK_RX_QUEUE_MAPPING=y
CONFIG_SPI=y
CONFIG_SPI_MASTER=y
CONFIG_SPI_MEM=y
CONFIG_SRAM=y
CONFIG_SRCU=y
CONFIG_SWPHY=y
CONFIG_SYNC_R4K=y
CONFIG_SYSCTL_EXCEPTION_TRACE=y
CONFIG_SYS_HAS_CPU_MIPS32_R1=y
CONFIG_SYS_HAS_CPU_MIPS32_R2=y
CONFIG_SYS_HAS_EARLY_PRINTK=y
CONFIG_SYS_SUPPORTS_32BIT_KERNEL=y
CONFIG_SYS_SUPPORTS_ARBIT_HZ=y
CONFIG_SYS_SUPPORTS_BIG_ENDIAN=y
CONFIG_SYS_SUPPORTS_HIGHMEM=y
CONFIG_SYS_SUPPORTS_MIPS16=y
CONFIG_SYS_SUPPORTS_MULTITHREADING=y
CONFIG_SYS_SUPPORTS_SCHED_SMT=y
CONFIG_SYS_SUPPORTS_SMP=y
CONFIG_TARGET_ISA_REV=2
CONFIG_TICK_CPU_ACCOUNTING=y
CONFIG_TIMER_OF=y
CONFIG_TIMER_PROBE=y
CONFIG_TINY_SRCU=y
CONFIG_USE_GENERIC_EARLY_PRINTK_8250=y
CONFIG_USE_OF=y
CONFIG_WATCHDOG_CORE=y
CONFIG_XPS=y
CONFIG_ZLIB_DEFLATE=y
CONFIG_ZLIB_INFLATE=y

View File

@ -0,0 +1,205 @@
CONFIG_AQUANTIA_PHY=y
CONFIG_ARCH_32BIT_OFF_T=y
CONFIG_ARCH_HIBERNATION_POSSIBLE=y
CONFIG_ARCH_KEEP_MEMBLOCK=y
CONFIG_ARCH_MMAP_RND_BITS_MAX=15
CONFIG_ARCH_MMAP_RND_COMPAT_BITS_MAX=15
CONFIG_ARCH_SUSPEND_POSSIBLE=y
CONFIG_BLK_DEV_RAM=y
CONFIG_BLK_DEV_RAM_COUNT=16
CONFIG_BLK_DEV_RAM_SIZE=4096
CONFIG_BOARD_SCACHE=y
CONFIG_CLONE_BACKWARDS=y
CONFIG_COMMON_CLK=y
# CONFIG_COMMON_CLK_REALTEK 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_DIEI=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_LIB_BLAKE2S_GENERIC=y
CONFIG_CRYPTO_LIB_POLY1305_RSIZE=2
CONFIG_CRYPTO_RNG2=y
CONFIG_DEBUG_SECTION_MISMATCH=y
CONFIG_DMA_NONCOHERENT=y
CONFIG_DTC=y
CONFIG_EARLY_PRINTK=y
CONFIG_EARLY_PRINTK_8250=y
CONFIG_FIXED_PHY=y
CONFIG_FORCE_MAX_ZONEORDER=13
CONFIG_FWNODE_MDIO=y
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_FIND_FIRST_BIT=y
CONFIG_GENERIC_GETTIMEOFDAY=y
CONFIG_GENERIC_IOMAP=y
CONFIG_GENERIC_IRQ_CHIP=y
CONFIG_GENERIC_IRQ_EFFECTIVE_AFF_MASK=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_PINCONF=y
CONFIG_GENERIC_PINCTRL_GROUPS=y
CONFIG_GENERIC_PINMUX_FUNCTIONS=y
CONFIG_GENERIC_SCHED_CLOCK=y
CONFIG_GENERIC_SMP_IDLE_THREAD=y
CONFIG_GENERIC_TIME_VSYSCALL=y
CONFIG_GPIOLIB_IRQCHIP=y
CONFIG_GPIO_CDEV=y
CONFIG_GPIO_GENERIC=y
CONFIG_GPIO_PCA953X=y
CONFIG_GPIO_REALTEK_OTTO=y
CONFIG_GPIO_RTL8231=y
CONFIG_GRO_CELLS=y
CONFIG_HANDLE_DOMAIN_IRQ=y
CONFIG_HARDWARE_WATCHPOINTS=y
CONFIG_HAS_DMA=y
CONFIG_HAS_IOMEM=y
CONFIG_HAS_IOPORT_MAP=y
CONFIG_HWMON=y
CONFIG_HZ_PERIODIC=y
CONFIG_I2C=y
CONFIG_I2C_ALGOBIT=y
CONFIG_I2C_BOARDINFO=y
CONFIG_I2C_CHARDEV=y
CONFIG_I2C_GPIO=y
CONFIG_I2C_MUX=y
CONFIG_I2C_MUX_RTL9300=y
CONFIG_I2C_RTL9300=y
CONFIG_I2C_SMBUS=y
CONFIG_INITRAMFS_SOURCE=""
CONFIG_IRQCHIP=y
CONFIG_IRQ_DOMAIN=y
CONFIG_IRQ_FORCED_THREADING=y
CONFIG_IRQ_MIPS_CPU=y
CONFIG_IRQ_WORK=y
CONFIG_JFFS2_ZLIB=y
CONFIG_LEDS_GPIO=y
CONFIG_LIBFDT=y
CONFIG_LOCK_DEBUGGING_SUPPORT=y
CONFIG_MARVELL_PHY=y
CONFIG_MDIO_BUS=y
CONFIG_MDIO_DEVICE=y
CONFIG_MDIO_DEVRES=y
CONFIG_MDIO_I2C=y
CONFIG_MDIO_SMBUS=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_CMDLINE_FROM_BOOTLOADER is not set
CONFIG_MIPS_CMDLINE_FROM_DTB=y
CONFIG_MIPS_CPU_SCACHE=y
CONFIG_MIPS_EBPF_JIT=y
CONFIG_MIPS_EXTERNAL_TIMER=y
CONFIG_MIPS_L1_CACHE_SHIFT=5
CONFIG_MIPS_LD_CAN_LINK_VDSO=y
# 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_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_RTL83XX=y
CONFIG_NET_DSA_TAG_TRAILER=y
CONFIG_NET_RTL838X=y
CONFIG_NET_SELFTESTS=y
CONFIG_NET_SWITCHDEV=y
CONFIG_NO_EXCEPT_FILL=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_PCI_DRIVERS_LEGACY=y
CONFIG_PERF_USE_VMALLOC=y
CONFIG_PGTABLE_LEVELS=2
CONFIG_PHYLIB=y
CONFIG_PHYLINK=y
CONFIG_PINCTRL=y
CONFIG_POWER_RESET=y
CONFIG_POWER_RESET_GPIO_RESTART=y
CONFIG_POWER_RESET_SYSCON=y
CONFIG_PTP_1588_CLOCK_OPTIONAL=y
CONFIG_RATIONAL=y
CONFIG_REALTEK_OTTO_TIMER=y
CONFIG_REALTEK_OTTO_WDT=y
CONFIG_REALTEK_PHY=y
CONFIG_REALTEK_SOC_PHY=y
CONFIG_REGMAP=y
CONFIG_REGMAP_I2C=y
CONFIG_REGMAP_MMIO=y
CONFIG_RESET_CONTROLLER=y
# CONFIG_RTL838X is not set
# CONFIG_RTL839X is not set
CONFIG_RTL83XX=y
CONFIG_RTL930X=y
# CONFIG_RTL931X is not set
CONFIG_SERIAL_MCTRL_GPIO=y
CONFIG_SERIAL_OF_PLATFORM=y
CONFIG_SFP=y
CONFIG_SPI=y
CONFIG_SPI_MASTER=y
CONFIG_SPI_MEM=y
CONFIG_SRCU=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_HIGHMEM=y
CONFIG_SYS_SUPPORTS_MIPS16=y
CONFIG_SYS_SUPPORTS_MULTITHREADING=y
CONFIG_TARGET_ISA_REV=2
CONFIG_TICK_CPU_ACCOUNTING=y
CONFIG_TIMER_OF=y
CONFIG_TIMER_PROBE=y
CONFIG_TINY_SRCU=y
CONFIG_USE_GENERIC_EARLY_PRINTK_8250=y
CONFIG_USE_OF=y
CONFIG_WATCHDOG_CORE=y
CONFIG_ZLIB_DEFLATE=y
CONFIG_ZLIB_INFLATE=y

View File

@ -0,0 +1,241 @@
CONFIG_ARCH_32BIT_OFF_T=y
CONFIG_ARCH_HIBERNATION_POSSIBLE=y
CONFIG_ARCH_KEEP_MEMBLOCK=y
CONFIG_ARCH_MMAP_RND_BITS_MAX=15
CONFIG_ARCH_MMAP_RND_COMPAT_BITS_MAX=15
CONFIG_ARCH_SUSPEND_POSSIBLE=y
CONFIG_BLK_DEV_RAM=y
CONFIG_BLK_DEV_RAM_COUNT=16
CONFIG_BLK_DEV_RAM_SIZE=4096
CONFIG_BOARD_SCACHE=y
CONFIG_CEVT_RTL9300=y
CONFIG_CLKSRC_MIPS_GIC=y
CONFIG_CLOCKSOURCE_WATCHDOG=y
CONFIG_CLONE_BACKWARDS=y
CONFIG_COMMON_CLK=y
# CONFIG_COMMON_CLK_REALTEK 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_DIEI=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_MIPSR2_IRQ_EI=y
CONFIG_CPU_MIPSR2_IRQ_VI=y
CONFIG_CPU_NEEDS_NO_SMARTMIPS_OR_MICROMIPS=y
CONFIG_CPU_R4K_CACHE_TLB=y
CONFIG_CPU_RMAP=y
CONFIG_CPU_SUPPORTS_32BIT_KERNEL=y
CONFIG_CPU_SUPPORTS_HIGHMEM=y
CONFIG_CPU_SUPPORTS_MSA=y
CONFIG_CRYPTO_LIB_BLAKE2S_GENERIC=y
CONFIG_CRYPTO_LIB_POLY1305_RSIZE=2
CONFIG_CRYPTO_RNG2=y
CONFIG_CSRC_R4K=y
CONFIG_DEBUG_SECTION_MISMATCH=y
CONFIG_DMA_NONCOHERENT=y
CONFIG_DTC=y
CONFIG_EARLY_PRINTK=y
CONFIG_EARLY_PRINTK_8250=y
CONFIG_FIXED_PHY=y
CONFIG_FORCE_MAX_ZONEORDER=13
CONFIG_FWNODE_MDIO=y
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_FIND_FIRST_BIT=y
CONFIG_GENERIC_GETTIMEOFDAY=y
CONFIG_GENERIC_IOMAP=y
CONFIG_GENERIC_IRQ_CHIP=y
CONFIG_GENERIC_IRQ_EFFECTIVE_AFF_MASK=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_PINCONF=y
CONFIG_GENERIC_PINCTRL_GROUPS=y
CONFIG_GENERIC_PINMUX_FUNCTIONS=y
CONFIG_GENERIC_SCHED_CLOCK=y
CONFIG_GENERIC_SMP_IDLE_THREAD=y
CONFIG_GENERIC_TIME_VSYSCALL=y
CONFIG_GPIOLIB_IRQCHIP=y
CONFIG_GPIO_CDEV=y
CONFIG_GPIO_GENERIC=y
CONFIG_GPIO_REALTEK_OTTO=y
CONFIG_GPIO_RTL8231=y
CONFIG_GRO_CELLS=y
CONFIG_HANDLE_DOMAIN_IRQ=y
CONFIG_HARDWARE_WATCHPOINTS=y
CONFIG_HAS_DMA=y
CONFIG_HAS_IOMEM=y
CONFIG_HAS_IOPORT_MAP=y
CONFIG_HIGHMEM=y
CONFIG_HWMON=y
CONFIG_HZ_PERIODIC=y
CONFIG_I2C=y
CONFIG_I2C_ALGOBIT=y
CONFIG_I2C_BOARDINFO=y
CONFIG_I2C_CHARDEV=y
CONFIG_I2C_GPIO=y
CONFIG_I2C_MUX=y
CONFIG_I2C_MUX_RTL9300=y
CONFIG_I2C_RTL9300=y
CONFIG_I2C_SMBUS=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_JFFS2_ZLIB=y
CONFIG_KMAP_LOCAL=y
CONFIG_LEDS_GPIO=y
CONFIG_LIBFDT=y
CONFIG_LOCK_DEBUGGING_SUPPORT=y
CONFIG_MARVELL_PHY=y
CONFIG_MDIO_BUS=y
CONFIG_MDIO_DEVICE=y
CONFIG_MDIO_DEVRES=y
CONFIG_MDIO_I2C=y
CONFIG_MDIO_SMBUS=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_CM=y
# CONFIG_MIPS_CMDLINE_FROM_BOOTLOADER is not set
CONFIG_MIPS_CMDLINE_FROM_DTB=y
CONFIG_MIPS_CPC=y
CONFIG_MIPS_CPS=y
# CONFIG_MIPS_CPS_NS16550_BOOL is not set
CONFIG_MIPS_CPU_SCACHE=y
CONFIG_MIPS_EBPF_JIT=y
CONFIG_MIPS_GIC=y
CONFIG_MIPS_L1_CACHE_SHIFT=5
CONFIG_MIPS_LD_CAN_LINK_VDSO=y
CONFIG_MIPS_MT=y
CONFIG_MIPS_MT_FPAFF=y
CONFIG_MIPS_MT_SMP=y
# CONFIG_MIPS_NO_APPENDED_DTB is not set
CONFIG_MIPS_NR_CPU_NR_MAP=2
CONFIG_MIPS_PERF_SHARED_TC_COUNTERS=y
CONFIG_MIPS_RAW_APPENDED_DTB=y
CONFIG_MIPS_SPRAM=y
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_NET_DEVLINK=y
CONFIG_NET_DSA=y
CONFIG_NET_DSA_RTL83XX=y
CONFIG_NET_DSA_TAG_TRAILER=y
CONFIG_NET_FLOW_LIMIT=y
CONFIG_NET_RTL838X=y
CONFIG_NET_SELFTESTS=y
CONFIG_NET_SWITCHDEV=y
CONFIG_NO_EXCEPT_FILL=y
CONFIG_NO_GENERIC_PCI_IOPORT_MAP=y
CONFIG_NR_CPUS=2
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_PADATA=y
CONFIG_PCI_DRIVERS_LEGACY=y
CONFIG_PERF_USE_VMALLOC=y
CONFIG_PGTABLE_LEVELS=2
CONFIG_PHYLIB=y
CONFIG_PHYLINK=y
CONFIG_PINCTRL=y
CONFIG_POWER_RESET=y
CONFIG_POWER_RESET_SYSCON=y
CONFIG_PTP_1588_CLOCK_OPTIONAL=y
CONFIG_QUEUED_RWLOCKS=y
CONFIG_QUEUED_SPINLOCKS=y
CONFIG_RATIONAL=y
# CONFIG_REALTEK_OTTO_TIMER is not set
CONFIG_REALTEK_OTTO_WDT=y
# CONFIG_REALTEK_PHY is not set
CONFIG_REALTEK_SOC_PHY=y
CONFIG_REGMAP=y
CONFIG_REGMAP_I2C=y
CONFIG_REGMAP_MMIO=y
CONFIG_RESET_CONTROLLER=y
CONFIG_RFS_ACCEL=y
CONFIG_RPS=y
# CONFIG_RTL838X is not set
# CONFIG_RTL839X is not set
CONFIG_RTL83XX=y
CONFIG_RTL930X=y
CONFIG_RTL931X=y
CONFIG_SENSORS_GPIO_FAN=y
CONFIG_SENSORS_LM75=y
CONFIG_SERIAL_MCTRL_GPIO=y
CONFIG_SERIAL_OF_PLATFORM=y
CONFIG_SFP=y
CONFIG_SMP=y
CONFIG_SMP_UP=y
CONFIG_SOCK_RX_QUEUE_MAPPING=y
CONFIG_SPI=y
CONFIG_SPI_MASTER=y
CONFIG_SPI_MEM=y
CONFIG_SRCU=y
CONFIG_SWPHY=y
CONFIG_SYNC_R4K=y
CONFIG_SYSCTL_EXCEPTION_TRACE=y
CONFIG_SYS_HAS_CPU_MIPS32_R1=y
CONFIG_SYS_HAS_CPU_MIPS32_R2=y
CONFIG_SYS_HAS_EARLY_PRINTK=y
CONFIG_SYS_SUPPORTS_32BIT_KERNEL=y
CONFIG_SYS_SUPPORTS_ARBIT_HZ=y
CONFIG_SYS_SUPPORTS_BIG_ENDIAN=y
CONFIG_SYS_SUPPORTS_HIGHMEM=y
CONFIG_SYS_SUPPORTS_HOTPLUG_CPU=y
CONFIG_SYS_SUPPORTS_MIPS16=y
CONFIG_SYS_SUPPORTS_MIPS_CPS=y
CONFIG_SYS_SUPPORTS_MULTITHREADING=y
CONFIG_SYS_SUPPORTS_SCHED_SMT=y
CONFIG_SYS_SUPPORTS_SMP=y
CONFIG_SYS_SUPPORTS_VPE_LOADER=y
CONFIG_TARGET_ISA_REV=2
CONFIG_TICK_CPU_ACCOUNTING=y
CONFIG_TIMER_OF=y
CONFIG_TIMER_PROBE=y
CONFIG_TREE_RCU=y
CONFIG_TREE_SRCU=y
CONFIG_USE_GENERIC_EARLY_PRINTK_8250=y
CONFIG_USE_OF=y
CONFIG_WATCHDOG_CORE=y
CONFIG_WEAK_ORDERING=y
CONFIG_XPS=y
CONFIG_ZLIB_DEFLATE=y
CONFIG_ZLIB_INFLATE=y