realtek: drop 5.15 support

Drop config and files for Linux 5.15.

Signed-off-by: Mieczyslaw Nalewaj <namiltd@yahoo.com>
Link: https://github.com/openwrt/openwrt/pull/16417
Signed-off-by: Robert Marko <robimarko@gmail.com>
This commit is contained in:
Mieczyslaw Nalewaj 2024-09-17 21:59:28 +02:00 committed by Robert Marko
parent f368e2d5ec
commit 3dd3c61c30
73 changed files with 0 additions and 29809 deletions

View File

@ -1,85 +0,0 @@
# 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

@ -1,29 +0,0 @@
/* 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

@ -1,415 +0,0 @@
/* 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

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

View File

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

View File

@ -1,212 +0,0 @@
// 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

@ -1,102 +0,0 @@
// 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

@ -1,19 +0,0 @@
# 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

@ -1,2 +0,0 @@
# 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

@ -1,149 +0,0 @@
/* 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

@ -1,141 +0,0 @@
/* 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

@ -1,770 +0,0 @@
// 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

@ -1,75 +0,0 @@
/* 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

@ -1,286 +0,0 @@
/* 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

@ -1,364 +0,0 @@
// 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

@ -1,486 +0,0 @@
// 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

@ -1,62 +0,0 @@
#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

@ -1,293 +0,0 @@
// 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

@ -1,7 +0,0 @@
# 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

@ -1,3 +0,0 @@
# 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

View File

@ -1,719 +0,0 @@
// 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

@ -1,565 +0,0 @@
// 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);
}

View File

@ -1,136 +0,0 @@
/* 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 */

View File

@ -1,410 +0,0 @@
// 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;
}

View File

@ -1,470 +0,0 @@
/* 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 extaddr;
int rawpage;
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

@ -1,64 +0,0 @@
// 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

@ -1,15 +0,0 @@
/* 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

@ -1,467 +0,0 @@
From 293903b9dfe43520f01374dc1661be11d6838c49 Mon Sep 17 00:00:00 2001
From: Sander Vanheule <sander@svanheule.net>
Date: Thu, 18 Nov 2021 17:29:52 +0100
Subject: watchdog: Add Realtek Otto watchdog timer
Realtek MIPS SoCs (platform name Otto) have a watchdog timer with
pretimeout notifitication support. The WDT can (partially) hard reset,
or soft reset the SoC.
This driver implements all features as described in the devicetree
binding, except the phase2 interrupt, and also functions as a restart
handler. The cpu reset mode is considered to be a "warm" restart, since
this mode does not reset all peripherals. Being an embedded system
though, the "cpu" and "software" modes will still cause the bootloader
to run on restart.
It is not known how a forced system reset can be disabled on the
supported platforms. This means that the phase2 interrupt will only fire
at the same time as reset, so implementing phase2 is of little use.
Signed-off-by: Sander Vanheule <sander@svanheule.net>
Reviewed-by: Guenter Roeck <linux@roeck-us.net>
Link: https://lore.kernel.org/r/6d060bccbdcc709cfa79203485db85aad3c3beb5.1637252610.git.sander@svanheule.net
Signed-off-by: Guenter Roeck <linux@roeck-us.net>
---
MAINTAINERS | 7 +
drivers/watchdog/Kconfig | 13 ++
drivers/watchdog/Makefile | 1 +
drivers/watchdog/realtek_otto_wdt.c | 384 ++++++++++++++++++++++++++++++++++++
4 files changed, 405 insertions(+)
create mode 100644 drivers/watchdog/realtek_otto_wdt.c
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -15903,6 +15903,13 @@ S: Maintained
F: include/sound/rt*.h
F: sound/soc/codecs/rt*
+REALTEK OTTO WATCHDOG
+M: Sander Vanheule <sander@svanheule.net>
+L: linux-watchdog@vger.kernel.org
+S: Maintained
+F: Documentation/devicetree/bindings/watchdog/realtek,otto-wdt.yaml
+F: driver/watchdog/realtek_otto_wdt.c
+
REALTEK RTL83xx SMI DSA ROUTER CHIPS
M: Linus Walleij <linus.walleij@linaro.org>
S: Maintained
--- a/drivers/watchdog/Kconfig
+++ b/drivers/watchdog/Kconfig
@@ -954,6 +954,19 @@ config RTD119X_WATCHDOG
Say Y here to include support for the watchdog timer in
Realtek RTD1295 SoCs.
+config REALTEK_OTTO_WDT
+ tristate "Realtek Otto MIPS watchdog support"
+ depends on MACH_REALTEK_RTL || COMPILE_TEST
+ depends on COMMON_CLK
+ select WATCHDOG_CORE
+ default MACH_REALTEK_RTL
+ help
+ Say Y here to include support for the watchdog timer on Realtek
+ RTL838x, RTL839x, RTL930x SoCs. This watchdog has pretimeout
+ notifications and system reset on timeout.
+
+ When built as a module this will be called realtek_otto_wdt.
+
config SPRD_WATCHDOG
tristate "Spreadtrum watchdog support"
depends on ARCH_SPRD || COMPILE_TEST
--- a/drivers/watchdog/Makefile
+++ b/drivers/watchdog/Makefile
@@ -171,6 +171,7 @@ obj-$(CONFIG_IMGPDC_WDT) += imgpdc_wdt.o
obj-$(CONFIG_MT7621_WDT) += mt7621_wdt.o
obj-$(CONFIG_PIC32_WDT) += pic32-wdt.o
obj-$(CONFIG_PIC32_DMT) += pic32-dmt.o
+obj-$(CONFIG_REALTEK_OTTO_WDT) += realtek_otto_wdt.o
# PARISC Architecture
--- /dev/null
+++ b/drivers/watchdog/realtek_otto_wdt.c
@@ -0,0 +1,384 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
+/*
+ * Realtek Otto MIPS platform watchdog
+ *
+ * Watchdog timer that will reset the system after timeout, using the selected
+ * reset mode.
+ *
+ * Counter scaling and timeouts:
+ * - Base prescale of (2 << 25), providing tick duration T_0: 168ms @ 200MHz
+ * - PRESCALE: logarithmic prescaler adding a factor of {1, 2, 4, 8}
+ * - Phase 1: Times out after (PHASE1 + 1) × PRESCALE × T_0
+ * Generates an interrupt, WDT cannot be stopped after phase 1
+ * - Phase 2: starts after phase 1, times out after (PHASE2 + 1) × PRESCALE × T_0
+ * Resets the system according to RST_MODE
+ */
+
+#include <linux/bits.h>
+#include <linux/bitfield.h>
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/math.h>
+#include <linux/minmax.h>
+#include <linux/module.h>
+#include <linux/mod_devicetable.h>
+#include <linux/platform_device.h>
+#include <linux/property.h>
+#include <linux/reboot.h>
+#include <linux/watchdog.h>
+
+#define OTTO_WDT_REG_CNTR 0x0
+#define OTTO_WDT_CNTR_PING BIT(31)
+
+#define OTTO_WDT_REG_INTR 0x4
+#define OTTO_WDT_INTR_PHASE_1 BIT(31)
+#define OTTO_WDT_INTR_PHASE_2 BIT(30)
+
+#define OTTO_WDT_REG_CTRL 0x8
+#define OTTO_WDT_CTRL_ENABLE BIT(31)
+#define OTTO_WDT_CTRL_PRESCALE GENMASK(30, 29)
+#define OTTO_WDT_CTRL_PHASE1 GENMASK(26, 22)
+#define OTTO_WDT_CTRL_PHASE2 GENMASK(19, 15)
+#define OTTO_WDT_CTRL_RST_MODE GENMASK(1, 0)
+#define OTTO_WDT_MODE_SOC 0
+#define OTTO_WDT_MODE_CPU 1
+#define OTTO_WDT_MODE_SOFTWARE 2
+#define OTTO_WDT_CTRL_DEFAULT OTTO_WDT_MODE_CPU
+
+#define OTTO_WDT_PRESCALE_MAX 3
+
+/*
+ * One higher than the max values contained in PHASE{1,2}, since a value of 0
+ * corresponds to one tick.
+ */
+#define OTTO_WDT_PHASE_TICKS_MAX 32
+
+/*
+ * The maximum reset delay is actually 2×32 ticks, but that would require large
+ * pretimeout values for timeouts longer than 32 ticks. Limit the maximum timeout
+ * to 32 + 1 to ensure small pretimeout values can be configured as expected.
+ */
+#define OTTO_WDT_TIMEOUT_TICKS_MAX (OTTO_WDT_PHASE_TICKS_MAX + 1)
+
+struct otto_wdt_ctrl {
+ struct watchdog_device wdev;
+ struct device *dev;
+ void __iomem *base;
+ unsigned int clk_rate_khz;
+ int irq_phase1;
+};
+
+static int otto_wdt_start(struct watchdog_device *wdev)
+{
+ struct otto_wdt_ctrl *ctrl = watchdog_get_drvdata(wdev);
+ u32 v;
+
+ v = ioread32(ctrl->base + OTTO_WDT_REG_CTRL);
+ v |= OTTO_WDT_CTRL_ENABLE;
+ iowrite32(v, ctrl->base + OTTO_WDT_REG_CTRL);
+
+ return 0;
+}
+
+static int otto_wdt_stop(struct watchdog_device *wdev)
+{
+ struct otto_wdt_ctrl *ctrl = watchdog_get_drvdata(wdev);
+ u32 v;
+
+ v = ioread32(ctrl->base + OTTO_WDT_REG_CTRL);
+ v &= ~OTTO_WDT_CTRL_ENABLE;
+ iowrite32(v, ctrl->base + OTTO_WDT_REG_CTRL);
+
+ return 0;
+}
+
+static int otto_wdt_ping(struct watchdog_device *wdev)
+{
+ struct otto_wdt_ctrl *ctrl = watchdog_get_drvdata(wdev);
+
+ iowrite32(OTTO_WDT_CNTR_PING, ctrl->base + OTTO_WDT_REG_CNTR);
+
+ return 0;
+}
+
+static int otto_wdt_tick_ms(struct otto_wdt_ctrl *ctrl, int prescale)
+{
+ return DIV_ROUND_CLOSEST(1 << (25 + prescale), ctrl->clk_rate_khz);
+}
+
+/*
+ * The timer asserts the PHASE1/PHASE2 IRQs when the number of ticks exceeds
+ * the value stored in those fields. This means each phase will run for at least
+ * one tick, so small values need to be clamped to correctly reflect the timeout.
+ */
+static inline unsigned int div_round_ticks(unsigned int val, unsigned int tick_duration,
+ unsigned int min_ticks)
+{
+ return max(min_ticks, DIV_ROUND_UP(val, tick_duration));
+}
+
+static int otto_wdt_determine_timeouts(struct watchdog_device *wdev, unsigned int timeout,
+ unsigned int pretimeout)
+{
+ struct otto_wdt_ctrl *ctrl = watchdog_get_drvdata(wdev);
+ unsigned int pretimeout_ms = pretimeout * 1000;
+ unsigned int timeout_ms = timeout * 1000;
+ unsigned int prescale_next = 0;
+ unsigned int phase1_ticks;
+ unsigned int phase2_ticks;
+ unsigned int total_ticks;
+ unsigned int prescale;
+ unsigned int tick_ms;
+ u32 v;
+
+ do {
+ prescale = prescale_next;
+ if (prescale > OTTO_WDT_PRESCALE_MAX)
+ return -EINVAL;
+
+ tick_ms = otto_wdt_tick_ms(ctrl, prescale);
+ total_ticks = div_round_ticks(timeout_ms, tick_ms, 2);
+ phase1_ticks = div_round_ticks(timeout_ms - pretimeout_ms, tick_ms, 1);
+ phase2_ticks = total_ticks - phase1_ticks;
+
+ prescale_next++;
+ } while (phase1_ticks > OTTO_WDT_PHASE_TICKS_MAX
+ || phase2_ticks > OTTO_WDT_PHASE_TICKS_MAX);
+
+ v = ioread32(ctrl->base + OTTO_WDT_REG_CTRL);
+
+ v &= ~(OTTO_WDT_CTRL_PRESCALE | OTTO_WDT_CTRL_PHASE1 | OTTO_WDT_CTRL_PHASE2);
+ v |= FIELD_PREP(OTTO_WDT_CTRL_PHASE1, phase1_ticks - 1);
+ v |= FIELD_PREP(OTTO_WDT_CTRL_PHASE2, phase2_ticks - 1);
+ v |= FIELD_PREP(OTTO_WDT_CTRL_PRESCALE, prescale);
+
+ iowrite32(v, ctrl->base + OTTO_WDT_REG_CTRL);
+
+ timeout_ms = total_ticks * tick_ms;
+ ctrl->wdev.timeout = timeout_ms / 1000;
+
+ pretimeout_ms = phase2_ticks * tick_ms;
+ ctrl->wdev.pretimeout = pretimeout_ms / 1000;
+
+ return 0;
+}
+
+static int otto_wdt_set_timeout(struct watchdog_device *wdev, unsigned int val)
+{
+ return otto_wdt_determine_timeouts(wdev, val, min(wdev->pretimeout, val - 1));
+}
+
+static int otto_wdt_set_pretimeout(struct watchdog_device *wdev, unsigned int val)
+{
+ return otto_wdt_determine_timeouts(wdev, wdev->timeout, val);
+}
+
+static int otto_wdt_restart(struct watchdog_device *wdev, unsigned long reboot_mode,
+ void *data)
+{
+ struct otto_wdt_ctrl *ctrl = watchdog_get_drvdata(wdev);
+ u32 reset_mode;
+ u32 v;
+
+ disable_irq(ctrl->irq_phase1);
+
+ switch (reboot_mode) {
+ case REBOOT_SOFT:
+ reset_mode = OTTO_WDT_MODE_SOFTWARE;
+ break;
+ case REBOOT_WARM:
+ reset_mode = OTTO_WDT_MODE_CPU;
+ break;
+ default:
+ reset_mode = OTTO_WDT_MODE_SOC;
+ break;
+ }
+
+ /* Configure for shortest timeout and wait for reset to occur */
+ v = FIELD_PREP(OTTO_WDT_CTRL_RST_MODE, reset_mode) | OTTO_WDT_CTRL_ENABLE;
+ iowrite32(v, ctrl->base + OTTO_WDT_REG_CTRL);
+
+ mdelay(3 * otto_wdt_tick_ms(ctrl, 0));
+
+ return 0;
+}
+
+static irqreturn_t otto_wdt_phase1_isr(int irq, void *dev_id)
+{
+ struct otto_wdt_ctrl *ctrl = dev_id;
+
+ iowrite32(OTTO_WDT_INTR_PHASE_1, ctrl->base + OTTO_WDT_REG_INTR);
+ dev_crit(ctrl->dev, "phase 1 timeout\n");
+ watchdog_notify_pretimeout(&ctrl->wdev);
+
+ return IRQ_HANDLED;
+}
+
+static const struct watchdog_ops otto_wdt_ops = {
+ .owner = THIS_MODULE,
+ .start = otto_wdt_start,
+ .stop = otto_wdt_stop,
+ .ping = otto_wdt_ping,
+ .set_timeout = otto_wdt_set_timeout,
+ .set_pretimeout = otto_wdt_set_pretimeout,
+ .restart = otto_wdt_restart,
+};
+
+static const struct watchdog_info otto_wdt_info = {
+ .identity = "Realtek Otto watchdog timer",
+ .options = WDIOF_KEEPALIVEPING |
+ WDIOF_MAGICCLOSE |
+ WDIOF_SETTIMEOUT |
+ WDIOF_PRETIMEOUT,
+};
+
+static void otto_wdt_clock_action(void *data)
+{
+ clk_disable_unprepare(data);
+}
+
+static int otto_wdt_probe_clk(struct otto_wdt_ctrl *ctrl)
+{
+ struct clk *clk = devm_clk_get(ctrl->dev, NULL);
+ int ret;
+
+ if (IS_ERR(clk))
+ return dev_err_probe(ctrl->dev, PTR_ERR(clk), "Failed to get clock\n");
+
+ ret = clk_prepare_enable(clk);
+ if (ret)
+ return dev_err_probe(ctrl->dev, ret, "Failed to enable clock\n");
+
+ ret = devm_add_action_or_reset(ctrl->dev, otto_wdt_clock_action, clk);
+ if (ret)
+ return ret;
+
+ ctrl->clk_rate_khz = clk_get_rate(clk) / 1000;
+ if (ctrl->clk_rate_khz == 0)
+ return dev_err_probe(ctrl->dev, -ENXIO, "Failed to get clock rate\n");
+
+ return 0;
+}
+
+static int otto_wdt_probe_reset_mode(struct otto_wdt_ctrl *ctrl)
+{
+ static const char *mode_property = "realtek,reset-mode";
+ const struct fwnode_handle *node = ctrl->dev->fwnode;
+ int mode_count;
+ u32 mode;
+ u32 v;
+
+ if (!node)
+ return -ENXIO;
+
+ mode_count = fwnode_property_string_array_count(node, mode_property);
+ if (mode_count < 0)
+ return mode_count;
+ else if (mode_count == 0)
+ return 0;
+ else if (mode_count != 1)
+ return -EINVAL;
+
+ if (fwnode_property_match_string(node, mode_property, "soc") == 0)
+ mode = OTTO_WDT_MODE_SOC;
+ else if (fwnode_property_match_string(node, mode_property, "cpu") == 0)
+ mode = OTTO_WDT_MODE_CPU;
+ else if (fwnode_property_match_string(node, mode_property, "software") == 0)
+ mode = OTTO_WDT_MODE_SOFTWARE;
+ else
+ return -EINVAL;
+
+ v = ioread32(ctrl->base + OTTO_WDT_REG_CTRL);
+ v &= ~OTTO_WDT_CTRL_RST_MODE;
+ v |= FIELD_PREP(OTTO_WDT_CTRL_RST_MODE, mode);
+ iowrite32(v, ctrl->base + OTTO_WDT_REG_CTRL);
+
+ return 0;
+}
+
+static int otto_wdt_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct otto_wdt_ctrl *ctrl;
+ unsigned int max_tick_ms;
+ int ret;
+
+ ctrl = devm_kzalloc(dev, sizeof(*ctrl), GFP_KERNEL);
+ if (!ctrl)
+ return -ENOMEM;
+
+ ctrl->dev = dev;
+ ctrl->base = devm_platform_ioremap_resource(pdev, 0);
+ if (IS_ERR(ctrl->base))
+ return PTR_ERR(ctrl->base);
+
+ /* Clear any old interrupts and reset initial state */
+ iowrite32(OTTO_WDT_INTR_PHASE_1 | OTTO_WDT_INTR_PHASE_2,
+ ctrl->base + OTTO_WDT_REG_INTR);
+ iowrite32(OTTO_WDT_CTRL_DEFAULT, ctrl->base + OTTO_WDT_REG_CTRL);
+
+ ret = otto_wdt_probe_clk(ctrl);
+ if (ret)
+ return ret;
+
+ ctrl->irq_phase1 = platform_get_irq_byname(pdev, "phase1");
+ if (ctrl->irq_phase1 < 0)
+ return ctrl->irq_phase1;
+
+ ret = devm_request_irq(dev, ctrl->irq_phase1, otto_wdt_phase1_isr, 0,
+ "realtek-otto-wdt", ctrl);
+ if (ret)
+ return dev_err_probe(dev, ret, "Failed to get IRQ for phase1\n");
+
+ ret = otto_wdt_probe_reset_mode(ctrl);
+ if (ret)
+ return dev_err_probe(dev, ret, "Invalid reset mode specified\n");
+
+ ctrl->wdev.parent = dev;
+ ctrl->wdev.info = &otto_wdt_info;
+ ctrl->wdev.ops = &otto_wdt_ops;
+
+ /*
+ * Since pretimeout cannot be disabled, min. timeout is twice the
+ * subsystem resolution. Max. timeout is ca. 43s at a bus clock of 200MHz.
+ */
+ ctrl->wdev.min_timeout = 2;
+ max_tick_ms = otto_wdt_tick_ms(ctrl, OTTO_WDT_PRESCALE_MAX);
+ ctrl->wdev.max_hw_heartbeat_ms = max_tick_ms * OTTO_WDT_TIMEOUT_TICKS_MAX;
+ ctrl->wdev.timeout = min(30U, ctrl->wdev.max_hw_heartbeat_ms / 1000);
+
+ watchdog_set_drvdata(&ctrl->wdev, ctrl);
+ watchdog_init_timeout(&ctrl->wdev, 0, dev);
+ watchdog_stop_on_reboot(&ctrl->wdev);
+ watchdog_set_restart_priority(&ctrl->wdev, 128);
+
+ ret = otto_wdt_determine_timeouts(&ctrl->wdev, ctrl->wdev.timeout, 1);
+ if (ret)
+ return dev_err_probe(dev, ret, "Failed to set timeout\n");
+
+ return devm_watchdog_register_device(dev, &ctrl->wdev);
+}
+
+static const struct of_device_id otto_wdt_ids[] = {
+ { .compatible = "realtek,rtl8380-wdt" },
+ { .compatible = "realtek,rtl8390-wdt" },
+ { .compatible = "realtek,rtl9300-wdt" },
+ { }
+};
+MODULE_DEVICE_TABLE(of, otto_wdt_ids);
+
+static struct platform_driver otto_wdt_driver = {
+ .probe = otto_wdt_probe,
+ .driver = {
+ .name = "realtek-otto-watchdog",
+ .of_match_table = otto_wdt_ids,
+ },
+};
+module_platform_driver(otto_wdt_driver);
+
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Sander Vanheule <sander@svanheule.net>");
+MODULE_DESCRIPTION("Realtek Otto watchdog timer driver");

View File

@ -1,53 +0,0 @@
From c6af53f038aa32cec12e8a305ba07c7ef168f1b0 Mon Sep 17 00:00:00 2001
From: "Russell King (Oracle)" <rmk+kernel@armlinux.org.uk>
Date: Tue, 4 Jan 2022 12:07:00 +0000
Subject: [PATCH 2/3] net: mdio: add helpers to extract clause 45 regad and
devad fields
Add a couple of helpers and definitions to extract the clause 45 regad
and devad fields from the regnum passed into MDIO drivers.
Tested-by: Daniel Golle <daniel@makrotopia.org>
Reviewed-by: Andrew Lunn <andrew@lunn.ch>
Signed-off-by: Russell King (Oracle) <rmk+kernel@armlinux.org.uk>
Signed-off-by: Daniel Golle <daniel@makrotopia.org>
Signed-off-by: David S. Miller <davem@davemloft.net>
---
include/linux/mdio.h | 12 ++++++++++++
1 file changed, 12 insertions(+)
--- a/include/linux/mdio.h
+++ b/include/linux/mdio.h
@@ -7,6 +7,7 @@
#define __LINUX_MDIO_H__
#include <uapi/linux/mdio.h>
+#include <linux/bitfield.h>
#include <linux/mod_devicetable.h>
/* Or MII_ADDR_C45 into regnum for read/write on mii_bus to enable the 21 bit
@@ -14,6 +15,7 @@
*/
#define MII_ADDR_C45 (1<<30)
#define MII_DEVADDR_C45_SHIFT 16
+#define MII_DEVADDR_C45_MASK GENMASK(20, 16)
#define MII_REGADDR_C45_MASK GENMASK(15, 0)
struct gpio_desc;
@@ -355,6 +357,16 @@ static inline u32 mdiobus_c45_addr(int d
return MII_ADDR_C45 | devad << MII_DEVADDR_C45_SHIFT | regnum;
}
+static inline u16 mdiobus_c45_regad(u32 regnum)
+{
+ return FIELD_GET(MII_REGADDR_C45_MASK, regnum);
+}
+
+static inline u16 mdiobus_c45_devad(u32 regnum)
+{
+ return FIELD_GET(MII_DEVADDR_C45_MASK, regnum);
+}
+
static inline int __mdiobus_c45_read(struct mii_bus *bus, int prtad, int devad,
u16 regnum)
{

View File

@ -1,123 +0,0 @@
From 512c5be35223d9baa2629efa1084cf5210eaee80 Mon Sep 17 00:00:00 2001
From: Sander Vanheule <sander@svanheule.net>
Date: Sat, 9 Apr 2022 21:55:47 +0200
Subject: [PATCH 2/6] gpio: realtek-otto: Support reversed port layouts
The GPIO port layout on the RTL930x SoC series is reversed compared to
the RTL838x and RTL839x SoC series. Add new port offset calculator
functions to ensure the correct order is used when reading port IRQ
data, and ensure bgpio uses the right byte ordering.
Signed-off-by: Sander Vanheule <sander@svanheule.net>
Signed-off-by: Bartosz Golaszewski <brgl@bgdev.pl>
---
drivers/gpio/gpio-realtek-otto.c | 55 +++++++++++++++++++++++++++++---
1 file changed, 51 insertions(+), 4 deletions(-)
--- a/drivers/gpio/gpio-realtek-otto.c
+++ b/drivers/gpio/gpio-realtek-otto.c
@@ -58,6 +58,8 @@ struct realtek_gpio_ctrl {
raw_spinlock_t lock;
u16 intr_mask[REALTEK_GPIO_PORTS_PER_BANK];
u16 intr_type[REALTEK_GPIO_PORTS_PER_BANK];
+ unsigned int (*port_offset_u8)(unsigned int port);
+ unsigned int (*port_offset_u16)(unsigned int port);
};
/* Expand with more flags as devices with other quirks are added */
@@ -69,6 +71,11 @@ enum realtek_gpio_flags {
* line the IRQ handler was assigned to, causing uncaught interrupts.
*/
GPIO_INTERRUPTS_DISABLED = BIT(0),
+ /*
+ * Port order is reversed, meaning DCBA register layout for 1-bit
+ * fields, and [BA, DC] for 2-bit fields.
+ */
+ GPIO_PORTS_REVERSED = BIT(1),
};
static struct realtek_gpio_ctrl *irq_data_to_ctrl(struct irq_data *data)
@@ -86,21 +93,50 @@ static struct realtek_gpio_ctrl *irq_dat
* port. The two interrupt mask registers store two bits per GPIO, so use u16
* values.
*/
+static unsigned int realtek_gpio_port_offset_u8(unsigned int port)
+{
+ return port;
+}
+
+static unsigned int realtek_gpio_port_offset_u16(unsigned int port)
+{
+ return 2 * port;
+}
+
+/*
+ * Reversed port order register access
+ *
+ * For registers with one bit per GPIO, all ports are stored as u8-s in one
+ * register in reversed order. The two interrupt mask registers store two bits
+ * per GPIO, so use u16 values. The first register contains ports 1 and 0, the
+ * second ports 3 and 2.
+ */
+static unsigned int realtek_gpio_port_offset_u8_rev(unsigned int port)
+{
+ return 3 - port;
+}
+
+static unsigned int realtek_gpio_port_offset_u16_rev(unsigned int port)
+{
+ return 2 * (port ^ 1);
+}
+
static void realtek_gpio_write_imr(struct realtek_gpio_ctrl *ctrl,
unsigned int port, u16 irq_type, u16 irq_mask)
{
- iowrite16(irq_type & irq_mask, ctrl->base + REALTEK_GPIO_REG_IMR + 2 * port);
+ iowrite16(irq_type & irq_mask,
+ ctrl->base + REALTEK_GPIO_REG_IMR + ctrl->port_offset_u16(port));
}
static void realtek_gpio_clear_isr(struct realtek_gpio_ctrl *ctrl,
unsigned int port, u8 mask)
{
- iowrite8(mask, ctrl->base + REALTEK_GPIO_REG_ISR + port);
+ iowrite8(mask, ctrl->base + REALTEK_GPIO_REG_ISR + ctrl->port_offset_u8(port));
}
static u8 realtek_gpio_read_isr(struct realtek_gpio_ctrl *ctrl, unsigned int port)
{
- return ioread8(ctrl->base + REALTEK_GPIO_REG_ISR + port);
+ return ioread8(ctrl->base + REALTEK_GPIO_REG_ISR + ctrl->port_offset_u8(port));
}
/* Set the rising and falling edge mask bits for a GPIO port pin */
@@ -250,6 +286,7 @@ MODULE_DEVICE_TABLE(of, realtek_gpio_of_
static int realtek_gpio_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
+ unsigned long bgpio_flags;
unsigned int dev_flags;
struct gpio_irq_chip *girq;
struct realtek_gpio_ctrl *ctrl;
@@ -277,10 +314,20 @@ static int realtek_gpio_probe(struct pla
raw_spin_lock_init(&ctrl->lock);
+ if (dev_flags & GPIO_PORTS_REVERSED) {
+ bgpio_flags = 0;
+ ctrl->port_offset_u8 = realtek_gpio_port_offset_u8_rev;
+ ctrl->port_offset_u16 = realtek_gpio_port_offset_u16_rev;
+ } else {
+ bgpio_flags = BGPIOF_BIG_ENDIAN_BYTE_ORDER;
+ ctrl->port_offset_u8 = realtek_gpio_port_offset_u8;
+ ctrl->port_offset_u16 = realtek_gpio_port_offset_u16;
+ }
+
err = bgpio_init(&ctrl->gc, dev, 4,
ctrl->base + REALTEK_GPIO_REG_DATA, NULL, NULL,
ctrl->base + REALTEK_GPIO_REG_DIR, NULL,
- BGPIOF_BIG_ENDIAN_BYTE_ORDER);
+ bgpio_flags);
if (err) {
dev_err(dev, "unable to init generic GPIO");
return err;

View File

@ -1,153 +0,0 @@
From 95fa6dbe58f286a8f87cb37b7516232eb678de2d Mon Sep 17 00:00:00 2001
From: Sander Vanheule <sander@svanheule.net>
Date: Sat, 9 Apr 2022 21:55:48 +0200
Subject: [PATCH 3/6] gpio: realtek-otto: Support per-cpu interrupts
On SoCs with multiple cores, it is possible that the GPIO interrupt
controller supports assigning specific pins to one or more cores.
IRQ balancing can be performed on a line-by-line basis if the parent
interrupt is routed to all available cores, which is the default upon
initialisation.
Signed-off-by: Sander Vanheule <sander@svanheule.net>
Signed-off-by: Bartosz Golaszewski <brgl@bgdev.pl>
---
drivers/gpio/gpio-realtek-otto.c | 75 +++++++++++++++++++++++++++++++-
1 file changed, 74 insertions(+), 1 deletion(-)
--- a/drivers/gpio/gpio-realtek-otto.c
+++ b/drivers/gpio/gpio-realtek-otto.c
@@ -1,6 +1,7 @@
// SPDX-License-Identifier: GPL-2.0-only
#include <linux/gpio/driver.h>
+#include <linux/cpumask.h>
#include <linux/irq.h>
#include <linux/minmax.h>
#include <linux/mod_devicetable.h>
@@ -55,6 +56,8 @@
struct realtek_gpio_ctrl {
struct gpio_chip gc;
void __iomem *base;
+ void __iomem *cpumask_base;
+ struct cpumask cpu_irq_maskable;
raw_spinlock_t lock;
u16 intr_mask[REALTEK_GPIO_PORTS_PER_BANK];
u16 intr_type[REALTEK_GPIO_PORTS_PER_BANK];
@@ -76,6 +79,11 @@ enum realtek_gpio_flags {
* fields, and [BA, DC] for 2-bit fields.
*/
GPIO_PORTS_REVERSED = BIT(1),
+ /*
+ * Interrupts can be enabled per cpu. This requires a secondary IO
+ * range, where the per-cpu enable masks are located.
+ */
+ GPIO_INTERRUPTS_PER_CPU = BIT(2),
};
static struct realtek_gpio_ctrl *irq_data_to_ctrl(struct irq_data *data)
@@ -247,14 +255,61 @@ static void realtek_gpio_irq_handler(str
chained_irq_exit(irq_chip, desc);
}
+static inline void __iomem *realtek_gpio_irq_cpu_mask(struct realtek_gpio_ctrl *ctrl,
+ unsigned int port, int cpu)
+{
+ return ctrl->cpumask_base + ctrl->port_offset_u8(port) +
+ REALTEK_GPIO_PORTS_PER_BANK * cpu;
+}
+
+static int realtek_gpio_irq_set_affinity(struct irq_data *data,
+ const struct cpumask *dest, bool force)
+{
+ struct realtek_gpio_ctrl *ctrl = irq_data_to_ctrl(data);
+ unsigned int line = irqd_to_hwirq(data);
+ unsigned int port = line / 8;
+ unsigned int port_pin = line % 8;
+ void __iomem *irq_cpu_mask;
+ unsigned long flags;
+ int cpu;
+ u8 v;
+
+ if (!ctrl->cpumask_base)
+ return -ENXIO;
+
+ raw_spin_lock_irqsave(&ctrl->lock, flags);
+
+ for_each_cpu(cpu, &ctrl->cpu_irq_maskable) {
+ irq_cpu_mask = realtek_gpio_irq_cpu_mask(ctrl, port, cpu);
+ v = ioread8(irq_cpu_mask);
+
+ if (cpumask_test_cpu(cpu, dest))
+ v |= BIT(port_pin);
+ else
+ v &= ~BIT(port_pin);
+
+ iowrite8(v, irq_cpu_mask);
+ }
+
+ raw_spin_unlock_irqrestore(&ctrl->lock, flags);
+
+ irq_data_update_effective_affinity(data, dest);
+
+ return 0;
+}
+
static int realtek_gpio_irq_init(struct gpio_chip *gc)
{
struct realtek_gpio_ctrl *ctrl = gpiochip_get_data(gc);
unsigned int port;
+ int cpu;
for (port = 0; (port * 8) < gc->ngpio; port++) {
realtek_gpio_write_imr(ctrl, port, 0, 0);
realtek_gpio_clear_isr(ctrl, port, GENMASK(7, 0));
+
+ for_each_cpu(cpu, &ctrl->cpu_irq_maskable)
+ iowrite8(GENMASK(7, 0), realtek_gpio_irq_cpu_mask(ctrl, port, cpu));
}
return 0;
@@ -266,6 +321,7 @@ static struct irq_chip realtek_gpio_irq_
.irq_mask = realtek_gpio_irq_mask,
.irq_unmask = realtek_gpio_irq_unmask,
.irq_set_type = realtek_gpio_irq_set_type,
+ .irq_set_affinity = realtek_gpio_irq_set_affinity,
};
static const struct of_device_id realtek_gpio_of_match[] = {
@@ -290,8 +346,10 @@ static int realtek_gpio_probe(struct pla
unsigned int dev_flags;
struct gpio_irq_chip *girq;
struct realtek_gpio_ctrl *ctrl;
+ struct resource *res;
u32 ngpios;
- int err, irq;
+ unsigned int nr_cpus;
+ int cpu, err, irq;
ctrl = devm_kzalloc(dev, sizeof(*ctrl), GFP_KERNEL);
if (!ctrl)
@@ -352,6 +410,21 @@ static int realtek_gpio_probe(struct pla
girq->init_hw = realtek_gpio_irq_init;
}
+ cpumask_clear(&ctrl->cpu_irq_maskable);
+
+ if ((dev_flags & GPIO_INTERRUPTS_PER_CPU) && irq > 0) {
+ ctrl->cpumask_base = devm_platform_get_and_ioremap_resource(pdev, 1, &res);
+ if (IS_ERR(ctrl->cpumask_base))
+ return dev_err_probe(dev, PTR_ERR(ctrl->cpumask_base),
+ "missing CPU IRQ mask registers");
+
+ nr_cpus = resource_size(res) / REALTEK_GPIO_PORTS_PER_BANK;
+ nr_cpus = min(nr_cpus, num_present_cpus());
+
+ for (cpu = 0; cpu < nr_cpus; cpu++)
+ cpumask_set_cpu(cpu, &ctrl->cpu_irq_maskable);
+ }
+
return devm_gpiochip_add_data(dev, &ctrl->gc, ctrl);
}

View File

@ -1,29 +0,0 @@
From deaf1cecdeb052cdb5e92fd642016198724b44a4 Mon Sep 17 00:00:00 2001
From: Sander Vanheule <sander@svanheule.net>
Date: Sat, 9 Apr 2022 21:55:49 +0200
Subject: [PATCH 4/6] gpio: realtek-otto: Add RTL930x support
The RTL930x SoC series has support for 24 GPIOs, with the port order
reversed compared to RTL838x and RTL839x. The RTL930x series also has
two CPUs (VPEs) and can distribute individual GPIO interrupts between
them.
Signed-off-by: Sander Vanheule <sander@svanheule.net>
Signed-off-by: Bartosz Golaszewski <brgl@bgdev.pl>
---
drivers/gpio/gpio-realtek-otto.c | 4 ++++
1 file changed, 4 insertions(+)
--- a/drivers/gpio/gpio-realtek-otto.c
+++ b/drivers/gpio/gpio-realtek-otto.c
@@ -335,6 +335,10 @@ static const struct of_device_id realtek
{
.compatible = "realtek,rtl8390-gpio",
},
+ {
+ .compatible = "realtek,rtl9300-gpio",
+ .data = (void *)(GPIO_PORTS_REVERSED | GPIO_INTERRUPTS_PER_CPU)
+ },
{}
};
MODULE_DEVICE_TABLE(of, realtek_gpio_of_match);

View File

@ -1,30 +0,0 @@
From d3bf3dc4bbbf6109bd9b4bd60089d36205ec4a37 Mon Sep 17 00:00:00 2001
From: Sander Vanheule <sander@svanheule.net>
Date: Sat, 9 Apr 2022 21:55:51 +0200
Subject: [PATCH 6/6] gpio: realtek-otto: Add RTL931x support
The RTL931x SoC series has support for 32 GPIOs, although not all lines
may be broken out to a physical pad.
The GPIO bank's parent interrupt can be routed to either or both of the
SoC's CPU cores by the GIC. Line-by-line IRQ balancing is not possible
on these SoCs.
Signed-off-by: Sander Vanheule <sander@svanheule.net>
Signed-off-by: Bartosz Golaszewski <brgl@bgdev.pl>
---
drivers/gpio/gpio-realtek-otto.c | 3 +++
1 file changed, 3 insertions(+)
--- a/drivers/gpio/gpio-realtek-otto.c
+++ b/drivers/gpio/gpio-realtek-otto.c
@@ -339,6 +339,9 @@ static const struct of_device_id realtek
.compatible = "realtek,rtl9300-gpio",
.data = (void *)(GPIO_PORTS_REVERSED | GPIO_INTERRUPTS_PER_CPU)
},
+ {
+ .compatible = "realtek,rtl9310-gpio",
+ },
{}
};
MODULE_DEVICE_TABLE(of, realtek_gpio_of_match);

View File

@ -1,86 +0,0 @@
From fce11f68491b46b93df69de0630cd9edb90bc772 Mon Sep 17 00:00:00 2001
From: Birger Koblitz <git@birger-koblitz.de>
Date: Wed, 29 Dec 2021 21:54:21 +0100
Subject: [PATCH] realtek: Create 4 different Realtek Platforms
Creates RTL83XX as a basic kernel config parameter for the
RTL838X, RTL839x, RTL930X and RTL931X platforms with respective
configurations for the SoCs, which are introduced in addition.
Submitted-by: Birger Koblitz <git@birger-koblitz.de>
---
arch/mips/Kbuild.platforms | 1 +
arch/mips/Kconfig | 57 ++++++++++++++
2 files changed, 58 insertions(+)
--- a/arch/mips/Kbuild.platforms
+++ b/arch/mips/Kbuild.platforms
@@ -23,6 +23,7 @@ platform-$(CONFIG_NLM_COMMON) += netlog
platform-$(CONFIG_PIC32MZDA) += pic32/
platform-$(CONFIG_RALINK) += ralink/
platform-$(CONFIG_MIKROTIK_RB532) += rb532/
+platform-$(CONFIG_RTL83XX) += rtl838x/
platform-$(CONFIG_SGI_IP22) += sgi-ip22/
platform-$(CONFIG_SGI_IP27) += sgi-ip27/
platform-$(CONFIG_SGI_IP28) += sgi-ip22/
--- a/arch/mips/Kconfig
+++ b/arch/mips/Kconfig
@@ -1056,8 +1056,58 @@ config NLM_XLP_BOARD
This board is based on Netlogic XLP Processor.
Say Y here if you have a XLP based board.
+config RTL83XX
+ bool "Realtek based platforms"
+ select DMA_NONCOHERENT
+ select IRQ_MIPS_CPU
+ select NO_EXCEPT_FILL
+ select SYS_HAS_CPU_MIPS32_R1
+ select SYS_HAS_CPU_MIPS32_R2
+ select SYS_SUPPORTS_BIG_ENDIAN
+ select SYS_SUPPORTS_HIGHMEM
+ select SYS_SUPPORTS_32BIT_KERNEL
+ select SYS_SUPPORTS_MIPS16
+ select SYS_HAS_EARLY_PRINTK
+ select SYS_HAS_EARLY_PRINTK_8250
+ select USE_GENERIC_EARLY_PRINTK_8250
+ select BOOT_RAW
+ select PINCTRL
+ select ARCH_HAS_RESET_CONTROLLER
+ select RESET_CONTROLLER
+ select USE_OF
+
endchoice
+config RTL838X
+ bool "Realtek RTL838X based platforms"
+ depends on RTL83XX
+ select CPU_SUPPORTS_CPUFREQ
+ select MIPS_EXTERNAL_TIMER
+
+config RTL839X
+ bool "Realtek RTL839X based platforms"
+ depends on RTL83XX
+ select CPU_SUPPORTS_CPUFREQ
+ select MIPS_EXTERNAL_TIMER
+ select SYS_SUPPORTS_MULTITHREADING
+
+config RTL930X
+ bool "Realtek RTL930X based platforms"
+ depends on RTL83XX
+ select MIPS_CPU_SCACHE
+ select MIPS_EXTERNAL_TIMER
+ select SYS_SUPPORTS_MULTITHREADING
+
+config RTL931X
+ bool "Realtek RTL931X based platforms"
+ depends on RTL930X
+ select MIPS_GIC
+ select COMMON_CLK
+ select CLKSRC_MIPS_GIC
+ select SYS_SUPPORTS_VPE_LOADER
+ select SYS_SUPPORTS_SMP
+ select SYS_SUPPORTS_MIPS_CPS
+
source "arch/mips/alchemy/Kconfig"
source "arch/mips/ath25/Kconfig"
source "arch/mips/ath79/Kconfig"

View File

@ -1,50 +0,0 @@
From 2b88563ee5aafd9571d965b7f2093a0f58d98a31 Mon Sep 17 00:00:00 2001
From: John Crispin <john@phrozen.org>
Date: Thu, 26 Nov 2020 12:02:21 +0100
Subject: [PATCH] realtek: update the tree to the latest refactored version
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
* rename the target to realtek
* add refactored DSA driver
* add latest gpio driver
* lots of arch cleanups
* new irq driver
* additional boards
Submitted-by: Bert Vermeulen <bert@biot.com>
Submitted-by: Birger Koblitz <mail@birger-koblitz.de>
Submitted-by: Sander Vanheule <sander@svanheule.net>
Submitted-by: Bjørn Mork <bjorn@mork.no>
Submitted-by: John Crispin <john@phrozen.org>
---
drivers/gpio/Kconfig | 6 ++++++
drivers/gpio/Makefile | 1 +
2 files changed, 7 insertions(+)
--- a/drivers/gpio/Kconfig
+++ b/drivers/gpio/Kconfig
@@ -529,6 +529,12 @@ config GPIO_ROCKCHIP
help
Say yes here to support GPIO on Rockchip SoCs.
+config GPIO_RTL8231
+ tristate "RTL8231 GPIO"
+ depends on RTL83XX
+ help
+ Say yes here to support Realtek RTL8231 GPIO expansion chips.
+
config GPIO_SAMA5D2_PIOBU
tristate "SAMA5D2 PIOBU GPIO support"
depends on MFD_SYSCON
--- a/drivers/gpio/Makefile
+++ b/drivers/gpio/Makefile
@@ -129,6 +129,7 @@ obj-$(CONFIG_GPIO_RDC321X) += gpio-rdc3
obj-$(CONFIG_GPIO_REALTEK_OTTO) += gpio-realtek-otto.o
obj-$(CONFIG_GPIO_REG) += gpio-reg.o
obj-$(CONFIG_GPIO_ROCKCHIP) += gpio-rockchip.o
+obj-$(CONFIG_GPIO_RTL8231) += gpio-rtl8231.o
obj-$(CONFIG_ARCH_SA1100) += gpio-sa1100.o
obj-$(CONFIG_GPIO_SAMA5D2_PIOBU) += gpio-sama5d2-piobu.o
obj-$(CONFIG_GPIO_SCH311X) += gpio-sch311x.o

View File

@ -1,93 +0,0 @@
From 3cc8011171186d906c547bc6f0c1f8e350edc7cf Mon Sep 17 00:00:00 2001
From: Markus Stockhausen <markus.stockhausen@gmx.de>
Date: Mon, 3 Oct 2022 14:45:21 +0200
Subject: [PATCH] realtek: resurrect timer driver
Now that we provide a clock driver for the Reltek SOCs the CPU frequency might
change on demand. This has direct visible effects during operation
- the CEVT 4K timer is no longer a stable clocksource
- after CPU frequencies changes time calculation works wrong
- sched_clock falls back to kernel default interval (100 Hz)
- timestamps in dmesg have only 2 digits left
[ 0.000000] sched_clock: 32 bits at 100 Hz, resolution 10000000ns, wraps ...
[ 0.060000] pid_max: default: 32768 minimum: 301
[ 0.070000] Mount-cache hash table entries: 1024 (order: 0, 4096 bytes, linear)
[ 0.070000] Mountpoint-cache hash table entries: 1024 (order: 0, 4096 bytes, linear)
[ 0.080000] dyndbg: Ignore empty _ddebug table in a CONFIG_DYNAMIC_DEBUG_CORE build
[ 0.090000] clocksource: jiffies: mask: 0xffffffff max_cycles: 0xffffffff, ...
Looking around where we can start the CEVT timer for RTL930X is a good basis.
Initially it was developed as a clocksource driver for the broken timer in that
specific SOC series. Afterwards it was shifted around to the CEVT location,
got SMP enablement and lost its clocksource feature. So we at least have
something to copy from. As the timers on these devices are well understood
the implementation follows this way:
- leave the RTL930X implementation as is
- provide a new driver for RTL83XX devices only
- swap RTL930X driver at a later time
Like the clock driver this patch contains a self contained module that is SOC
independet and already provides full support for the RTL838X, RTL839X and
RTL930X devices. Some of the new (or reestablished) features are:
- simplified initialization routines
- SMP setup with CPU hotplug framework
- derived from LXB clock speed
- supplied clocksource
- dedicated register functions for better readability
- documentation about some caveats
Signed-off-by: Markus Stockhausen <markus.stockhausen@gmx.de>
[remove unused header includes, remove old CONFIG_MIPS dependency, add
REALTEK_ prefix to driver symbol]
Signed-off-by: Sander Vanheule <sander@svanheule.net>
---
drivers/clocksource/Kconfig | 12 +++
drivers/clocksource/Makefile | 1 +
include/linux/cpuhotplug.h | 1 +
3 files changed, 14 insertions(+)
--- a/drivers/clocksource/Kconfig
+++ b/drivers/clocksource/Kconfig
@@ -127,6 +127,17 @@ config RDA_TIMER
help
Enables the support for the RDA Micro timer driver.
+config REALTEK_OTTO_TIMER
+ bool "Clocksource/timer for the Realtek Otto platform"
+ select COMMON_CLK
+ select TIMER_OF
+ help
+ This driver adds support for the timers found in the Realtek RTL83xx
+ and RTL93xx SoCs series. This includes chips such as RTL8380, RTL8381
+ and RTL832, as well as chips from the RTL839x series, such as RTL8390
+ RT8391, RTL8392, RTL8393 and RTL8396 and chips of the RTL930x series
+ such as RTL9301, RTL9302 or RTL9303.
+
config SUN4I_TIMER
bool "Sun4i timer driver" if COMPILE_TEST
depends on HAS_IOMEM
--- a/drivers/clocksource/Makefile
+++ b/drivers/clocksource/Makefile
@@ -58,6 +58,7 @@ obj-$(CONFIG_MILBEAUT_TIMER) += timer-mi
obj-$(CONFIG_SPRD_TIMER) += timer-sprd.o
obj-$(CONFIG_NPCM7XX_TIMER) += timer-npcm7xx.o
obj-$(CONFIG_RDA_TIMER) += timer-rda.o
+obj-$(CONFIG_REALTEK_OTTO_TIMER) += timer-rtl-otto.o
obj-$(CONFIG_ARC_TIMERS) += arc_timer.o
obj-$(CONFIG_ARM_ARCH_TIMER) += arm_arch_timer.o
--- a/include/linux/cpuhotplug.h
+++ b/include/linux/cpuhotplug.h
@@ -176,6 +176,7 @@ enum cpuhp_state {
CPUHP_AP_MARCO_TIMER_STARTING,
CPUHP_AP_MIPS_GIC_TIMER_STARTING,
CPUHP_AP_ARC_TIMER_STARTING,
+ CPUHP_AP_REALTEK_TIMER_STARTING,
CPUHP_AP_RISCV_TIMER_STARTING,
CPUHP_AP_CLINT_TIMER_STARTING,
CPUHP_AP_CSKY_TIMER_STARTING,

View File

@ -1,26 +0,0 @@
From 9bac1c20b8f39f2e0e342b087add5093b94feaed Mon Sep 17 00:00:00 2001
From: INAGAKI Hiroshi <musashino.open@gmail.com>
Date: Wed, 5 May 2021 22:05:39 +0900
Subject: realtek: backport gpio-realtek-otto driver from 5.13 to 5.10
This patch backports "gpio-realtek-otto" driver to Kernel 5.10.
"MACH_REALTEK_RTL" is used as a platform name in upstream, but "RTL838X"
is used in OpenWrt, so update the dependency by the additional patch.
Submitted-by: INAGAKI Hiroshi <musashino.open@gmail.com>
---
drivers/gpio/Kconfig | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
--- a/drivers/gpio/Kconfig
+++ b/drivers/gpio/Kconfig
@@ -503,8 +503,8 @@ config GPIO_RDA
config GPIO_REALTEK_OTTO
tristate "Realtek Otto GPIO support"
- depends on MACH_REALTEK_RTL
- default MACH_REALTEK_RTL
+ depends on RTL83XX
+ default RTL838X
select GPIO_GENERIC
select GPIOLIB_IRQCHIP
help

View File

@ -1,25 +0,0 @@
From 0b000cbfe0aa0323bffa855ef8449c0687a4c071 Mon Sep 17 00:00:00 2001
From: INAGAKI Hiroshi <musashino.open@gmail.com>
Date: Thu, 6 May 2021 19:30:58 +0900
Subject: realtek: backport spi-realtek-rtl driver from 5.12 to 5.10
This patch backports "spi-realtek-rtl" driver to Kernel 5.10 from 5.12.
"MACH_REALTEK_RTL" is used as a platform name in upstream, but "RTL838X"
is used in OpenWrt, so update the dependency by the additional patch.
Submitted-by: INAGAKI Hiroshi <musashino.open@gmail.com>
---
drivers/spi/Makefile | 2 +-
1 files changed, 1 insertion(+), 1 deletion(-)
--- a/drivers/spi/Makefile
+++ b/drivers/spi/Makefile
@@ -97,7 +97,7 @@ obj-$(CONFIG_SPI_QUP) += spi-qup.o
obj-$(CONFIG_SPI_ROCKCHIP) += spi-rockchip.o
obj-$(CONFIG_SPI_ROCKCHIP_SFC) += spi-rockchip-sfc.o
obj-$(CONFIG_SPI_RB4XX) += spi-rb4xx.o
-obj-$(CONFIG_MACH_REALTEK_RTL) += spi-realtek-rtl.o
+obj-$(CONFIG_RTL83XX) += spi-realtek-rtl.o
obj-$(CONFIG_SPI_RPCIF) += spi-rpc-if.o
obj-$(CONFIG_SPI_RSPI) += spi-rspi.o
obj-$(CONFIG_SPI_S3C24XX) += spi-s3c24xx-hw.o

View File

@ -1,25 +0,0 @@
From 2cd00b51470a30198b048a5fca48a04db77e29cc Mon Sep 17 00:00:00 2001
From: INAGAKI Hiroshi <musashino.open@gmail.com>
Date: Fri, 21 May 2021 23:16:37 +0900
Subject: [PATCH] realtek: backport irq-realtek-rtl driver from 5.12 to 5.10
This patch backports "irq-realtek-rtl" driver to Kernel 5.10 from 5.12.
"MACH_REALTEK_RTL" is used as a platform name in upstream, but "RTL838X"
is used in OpenWrt, so update the dependency by the additional patch.
Submitted-by: INAGAKI Hiroshi <musashino.open@gmail.com>
---
drivers/irqchip/Makefile | 2 +-
1 files changed, 1 insertion(+), 1 deletion(-)
--- a/drivers/irqchip/Makefile
+++ b/drivers/irqchip/Makefile
@@ -112,7 +112,7 @@ obj-$(CONFIG_LOONGSON_PCH_PIC) += irq-l
obj-$(CONFIG_LOONGSON_PCH_MSI) += irq-loongson-pch-msi.o
obj-$(CONFIG_MST_IRQ) += irq-mst-intc.o
obj-$(CONFIG_SL28CPLD_INTC) += irq-sl28cpld.o
-obj-$(CONFIG_MACH_REALTEK_RTL) += irq-realtek-rtl.o
+obj-$(CONFIG_RTL83XX) += irq-realtek-rtl.o
obj-$(CONFIG_WPCM450_AIC) += irq-wpcm450-aic.o
obj-$(CONFIG_IRQ_IDT3243X) += irq-idt3243x.o
obj-$(CONFIG_APPLE_AIC) += irq-apple-aic.o

View File

@ -1,32 +0,0 @@
From b8fc5eecdc5d33cf261986436597b5482ab856da Mon Sep 17 00:00:00 2001
From: Sander Vanheule <sander@svanheule.net>
Date: Sun, 14 Nov 2021 19:45:32 +0100
Subject: [PATCH] realtek: Backport Realtek Otto WDT driver
Add patch submitted upstream to linux-watchdog and replace the MIPS
architecture symbols. Requires one extra patch for the DIV_ROUND_*
macros, which have moved to a different header since 5.10.
Submitted-by: Sander Vanheule <sander@svanheule.net>
Tested-by: Stijn Segers <foss@volatilesystems.org>
Tested-by: Paul Fertser <fercerpav@gmail.com>
Tested-by: Stijn Tintel <stijn@linux-ipv6.be>
---
drivers/watchdog/Kconfig | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
--- a/drivers/watchdog/Kconfig
+++ b/drivers/watchdog/Kconfig
@@ -956,10 +956,10 @@ config RTD119X_WATCHDOG
config REALTEK_OTTO_WDT
tristate "Realtek Otto MIPS watchdog support"
- depends on MACH_REALTEK_RTL || COMPILE_TEST
+ depends on RTL83XX
depends on COMMON_CLK
select WATCHDOG_CORE
- default MACH_REALTEK_RTL
+ default RTL83XX
help
Say Y here to include support for the watchdog timer on Realtek
RTL838x, RTL839x, RTL930x SoCs. This watchdog has pretimeout

View File

@ -1,28 +0,0 @@
From b8fc5eecdc5d33cf261986436597b5482ab856da Mon Sep 17 00:00:00 2001
From: Sander Vanheule <sander@svanheule.net>
Date: Sun, 14 Nov 2021 19:45:32 +0100
Subject: [PATCH] realtek: Backport Realtek Otto WDT driver
Add patch submitted upstream to linux-watchdog and replace the MIPS
architecture symbols. Requires one extra patch for the DIV_ROUND_*
macros, which have moved to a different header since 5.10.
Submitted-by: Sander Vanheule <sander@svanheule.net>
Tested-by: Stijn Segers <foss@volatilesystems.org>
Tested-by: Paul Fertser <fercerpav@gmail.com>
Tested-by: Stijn Tintel <stijn@linux-ipv6.be>
---
drivers/watchdog/realtek_otto_wdt.c | 2 +-
1 files changed, 1 insertion(+), 1 deletion(-)
--- a/drivers/watchdog/realtek_otto_wdt.c
+++ b/drivers/watchdog/realtek_otto_wdt.c
@@ -21,7 +21,7 @@
#include <linux/delay.h>
#include <linux/interrupt.h>
#include <linux/io.h>
-#include <linux/math.h>
+#include <linux/kernel.h>
#include <linux/minmax.h>
#include <linux/module.h>
#include <linux/mod_devicetable.h>

View File

@ -1,46 +0,0 @@
From 63a0a4d85bc900464c5b046b13808a582345f8c8 Mon Sep 17 00:00:00 2001
From: Birger Koblitz <git@birger-koblitz.de>
Date: Sat, 11 Dec 2021 20:14:47 +0100
Subject: [PATCH] realtek: Add support for RTL9300/RTL9310 I2C controller
This adds support for the RTL9300 and RTL9310 I2C controller.
The controller implements the SMBus protocol for SMBus transfers
over an I2C bus. The driver supports selecting one of the 2 possible
SCL pins and any of the 8 possible SDA pins. Bus speeds of
100kHz (standard speed) and 400kHz (high speed I2C) are supported.
Submitted-by: Birger Koblitz <git@birger-koblitz.de>
---
drivers/i2c/busses/Kconfig | 10 +++++++++
drivers/i2c/busses/Makefile | 1 +
2 files changed, 11 insertions(+)
--- a/drivers/i2c/busses/Kconfig
+++ b/drivers/i2c/busses/Kconfig
@@ -949,6 +949,16 @@ config I2C_RK3X
This driver can also be built as a module. If so, the module will
be called i2c-rk3x.
+config I2C_RTL9300
+ tristate "Realtek RTL9300 I2C adapter"
+ depends on OF
+ help
+ Say Y here to include support for the I2C adapter in Realtek RTL9300
+ and RTL9310 SoCs.
+
+ This driver can also be built as a module. If so, the module will
+ be called i2c-rtl9300.
+
config HAVE_S3C2410_I2C
bool
help
--- a/drivers/i2c/busses/Makefile
+++ b/drivers/i2c/busses/Makefile
@@ -94,6 +94,7 @@ obj-$(CONFIG_I2C_QCOM_GENI) += i2c-qcom-
obj-$(CONFIG_I2C_QUP) += i2c-qup.o
obj-$(CONFIG_I2C_RIIC) += i2c-riic.o
obj-$(CONFIG_I2C_RK3X) += i2c-rk3x.o
+obj-$(CONFIG_I2C_RTL9300) += i2c-rtl9300.o
obj-$(CONFIG_I2C_S3C2410) += i2c-s3c2410.o
obj-$(CONFIG_I2C_SH7760) += i2c-sh7760.o
obj-$(CONFIG_I2C_SH_MOBILE) += i2c-sh_mobile.o

View File

@ -1,46 +0,0 @@
From f4bdb7fdccdfe3fa382abe77f72a16c2f2e6add0 Mon Sep 17 00:00:00 2001
From: Birger Koblitz <git@birger-koblitz.de>
Date: Sat, 11 Dec 2021 20:25:37 +0100
Subject: [PATCH] realtek: Add support for RTL9300/RTL9310 I2C multiplexing
The RTL9300/RTL9310 I2C controllers have support for 2 independent I2C
masters, each with a fixed SCL pin, that cannot be changed. Each of these
masters can use 8 (RTL9300) or 16 (RTL9310) different pins for SDA.
This multiplexer directly controls the two masters and their shared
IO configuration registers to allow multiplexing between any of these
busses. The two masters cannot be used in parallel as the multiplex
is protected by a standard multiplex lock.
Submitted-by: Birger Koblitz <git@birger-koblitz.de>
---
drivers/i2c/muxes/Kconfig | 9 +++++++
drivers/i2c/muxes/Makefile | 1 +
2 files changed, 10 insertions(+)
--- a/drivers/i2c/muxes/Kconfig
+++ b/drivers/i2c/muxes/Kconfig
@@ -99,6 +99,15 @@ config I2C_MUX_REG
This driver can also be built as a module. If so, the module
will be called i2c-mux-reg.
+config I2C_MUX_RTL9300
+ tristate "RTL9300 based I2C multiplexer"
+ help
+ If you say yes to this option, support will be included for a
+ RTL9300 based I2C multiplexer.
+
+ This driver can also be built as a module. If so, the module
+ will be called i2c-mux-reg.
+
config I2C_DEMUX_PINCTRL
tristate "pinctrl-based I2C demultiplexer"
depends on PINCTRL && OF
--- a/drivers/i2c/muxes/Makefile
+++ b/drivers/i2c/muxes/Makefile
@@ -14,5 +14,6 @@ obj-$(CONFIG_I2C_MUX_PCA9541) += i2c-mux
obj-$(CONFIG_I2C_MUX_PCA954x) += i2c-mux-pca954x.o
obj-$(CONFIG_I2C_MUX_PINCTRL) += i2c-mux-pinctrl.o
obj-$(CONFIG_I2C_MUX_REG) += i2c-mux-reg.o
+obj-$(CONFIG_I2C_MUX_RTL9300) += i2c-mux-rtl9300.o
ccflags-$(CONFIG_I2C_DEBUG_BUS) := -DDEBUG

View File

@ -1,402 +0,0 @@
From 6c18e9c491959ac0674ebe36b09f9ddc3f2c9bce Mon Sep 17 00:00:00 2001
From: Birger Koblitz <git@birger-koblitz.de>
Date: Fri, 31 Dec 2021 11:56:49 +0100
Subject: [PATCH] realtek: Add VPE support for the IRQ driver
In order to support VSMP, enable support for both VPEs
of the RTL839X and RTL930X SoCs in the irq-realtek-rtl
driver. Add support for IRQ affinity setting.
Submitted-by: Birger Koblitz <git@birger-koblitz.de>
---
drivers/irqchip/irq-realtek-rtl.c | 152 +++++++++++++++---
1 file changed, 73 insertions(+), 76 deletions(-)
--- a/drivers/irqchip/irq-realtek-rtl.c
+++ b/drivers/irqchip/irq-realtek-rtl.c
@@ -21,21 +21,63 @@
#define RTL_ICTL_IRR2 0x10
#define RTL_ICTL_IRR3 0x14
-#define REG(x) (realtek_ictl_base + x)
+#define RTL_ICTL_NUM_INPUTS 32
+#define RTL_ICTL_NUM_OUTPUTS 15
static DEFINE_RAW_SPINLOCK(irq_lock);
-static void __iomem *realtek_ictl_base;
+
+#define REG(offset, cpu) (realtek_ictl_base[cpu] + offset)
+
+static void __iomem *realtek_ictl_base[NR_CPUS];
+static cpumask_t realtek_ictl_cpu_configurable;
+
+struct realtek_ictl_output {
+ /* IRQ controller data */
+ struct fwnode_handle *fwnode;
+ /* Output specific data */
+ unsigned int output_index;
+ struct irq_domain *domain;
+ u32 child_mask;
+};
+
+/*
+ * IRR0-IRR3 store 4 bits per interrupt, but Realtek uses inverted numbering,
+ * placing IRQ 31 in the first four bits. A routing value of '0' means the
+ * interrupt is left disconnected. Routing values {1..15} connect to output
+ * lines {0..14}.
+ */
+#define IRR_OFFSET(idx) (4 * (3 - (idx * 4) / 32))
+#define IRR_SHIFT(idx) ((idx * 4) % 32)
+
+static inline u32 read_irr(void __iomem *irr0, int idx)
+{
+ return (readl(irr0 + IRR_OFFSET(idx)) >> IRR_SHIFT(idx)) & 0xf;
+}
+
+static inline void write_irr(void __iomem *irr0, int idx, u32 value)
+{
+ unsigned int offset = IRR_OFFSET(idx);
+ unsigned int shift = IRR_SHIFT(idx);
+ u32 irr;
+
+ irr = readl(irr0 + offset) & ~(0xf << shift);
+ irr |= (value & 0xf) << shift;
+ writel(irr, irr0 + offset);
+}
static void realtek_ictl_unmask_irq(struct irq_data *i)
{
unsigned long flags;
u32 value;
+ int cpu;
raw_spin_lock_irqsave(&irq_lock, flags);
- value = readl(REG(RTL_ICTL_GIMR));
- value |= BIT(i->hwirq);
- writel(value, REG(RTL_ICTL_GIMR));
+ for_each_cpu(cpu, &realtek_ictl_cpu_configurable) {
+ value = readl(REG(RTL_ICTL_GIMR, cpu));
+ value |= BIT(i->hwirq);
+ writel(value, REG(RTL_ICTL_GIMR, cpu));
+ }
raw_spin_unlock_irqrestore(&irq_lock, flags);
}
@@ -44,52 +86,137 @@ static void realtek_ictl_mask_irq(struct
{
unsigned long flags;
u32 value;
+ int cpu;
raw_spin_lock_irqsave(&irq_lock, flags);
- value = readl(REG(RTL_ICTL_GIMR));
- value &= ~BIT(i->hwirq);
- writel(value, REG(RTL_ICTL_GIMR));
+ for_each_cpu(cpu, &realtek_ictl_cpu_configurable) {
+ value = readl(REG(RTL_ICTL_GIMR, cpu));
+ value &= ~BIT(i->hwirq);
+ writel(value, REG(RTL_ICTL_GIMR, cpu));
+ }
raw_spin_unlock_irqrestore(&irq_lock, flags);
}
+static int __maybe_unused realtek_ictl_irq_affinity(struct irq_data *i,
+ const struct cpumask *dest, bool force)
+{
+ struct realtek_ictl_output *output = i->domain->host_data;
+ cpumask_t cpu_configure;
+ cpumask_t cpu_disable;
+ cpumask_t cpu_enable;
+ unsigned long flags;
+ int cpu;
+
+ raw_spin_lock_irqsave(&irq_lock, flags);
+
+ cpumask_and(&cpu_configure, cpu_present_mask, &realtek_ictl_cpu_configurable);
+
+ cpumask_and(&cpu_enable, &cpu_configure, dest);
+ cpumask_andnot(&cpu_disable, &cpu_configure, dest);
+
+ for_each_cpu(cpu, &cpu_disable)
+ write_irr(REG(RTL_ICTL_IRR0, cpu), i->hwirq, 0);
+
+ for_each_cpu(cpu, &cpu_enable)
+ write_irr(REG(RTL_ICTL_IRR0, cpu), i->hwirq, output->output_index + 1);
+
+ irq_data_update_effective_affinity(i, &cpu_enable);
+
+ raw_spin_unlock_irqrestore(&irq_lock, flags);
+
+ return IRQ_SET_MASK_OK;
+}
+
static struct irq_chip realtek_ictl_irq = {
.name = "realtek-rtl-intc",
.irq_mask = realtek_ictl_mask_irq,
.irq_unmask = realtek_ictl_unmask_irq,
+#ifdef CONFIG_SMP
+ .irq_set_affinity = realtek_ictl_irq_affinity,
+#endif
};
static int intc_map(struct irq_domain *d, unsigned int irq, irq_hw_number_t hw)
{
+ struct realtek_ictl_output *output = d->host_data;
+ unsigned long flags;
+
irq_set_chip_and_handler(irq, &realtek_ictl_irq, handle_level_irq);
+ raw_spin_lock_irqsave(&irq_lock, flags);
+
+ output->child_mask |= BIT(hw);
+ write_irr(REG(RTL_ICTL_IRR0, 0), hw, output->output_index + 1);
+
+ raw_spin_unlock_irqrestore(&irq_lock, flags);
+
return 0;
}
+static int intc_select(struct irq_domain *d, struct irq_fwspec *fwspec,
+ enum irq_domain_bus_token bus_token)
+{
+ struct realtek_ictl_output *output = d->host_data;
+ bool routed_elsewhere;
+ unsigned long flags;
+ u32 routing_old;
+ int cpu;
+
+ if (fwspec->fwnode != output->fwnode)
+ return false;
+
+ /* Original specifiers had only one parameter */
+ if (fwspec->param_count < 2)
+ return true;
+
+ raw_spin_lock_irqsave(&irq_lock, flags);
+
+ /*
+ * Inputs can only be routed to one output, so they shouldn't be
+ * allowed to end up in multiple domains.
+ */
+ for_each_cpu(cpu, &realtek_ictl_cpu_configurable) {
+ routing_old = read_irr(REG(RTL_ICTL_IRR0, cpu), fwspec->param[0]);
+ routed_elsewhere = routing_old && fwspec->param[1] != routing_old - 1;
+ if (routed_elsewhere) {
+ pr_warn("soc int %d already routed to output %d\n",
+ fwspec->param[0], routing_old - 1);
+ break;
+ }
+ }
+
+ raw_spin_unlock_irqrestore(&irq_lock, flags);
+
+ return !routed_elsewhere && fwspec->param[1] == output->output_index;
+}
+
static const struct irq_domain_ops irq_domain_ops = {
.map = intc_map,
+ .select = intc_select,
.xlate = irq_domain_xlate_onecell,
};
static void realtek_irq_dispatch(struct irq_desc *desc)
{
+ struct realtek_ictl_output *output = irq_desc_get_handler_data(desc);
struct irq_chip *chip = irq_desc_get_chip(desc);
- struct irq_domain *domain;
+ int cpu = smp_processor_id();
unsigned long pending;
unsigned int soc_int;
chained_irq_enter(chip, desc);
- pending = readl(REG(RTL_ICTL_GIMR)) & readl(REG(RTL_ICTL_GISR));
+ pending = readl(REG(RTL_ICTL_GIMR, cpu)) & readl(REG(RTL_ICTL_GISR, cpu))
+ & output->child_mask;
if (unlikely(!pending)) {
spurious_interrupt();
goto out;
}
- domain = irq_desc_get_handler_data(desc);
- for_each_set_bit(soc_int, &pending, 32)
- generic_handle_domain_irq(domain, soc_int);
+ for_each_set_bit(soc_int, &pending, RTL_ICTL_NUM_INPUTS)
+ generic_handle_domain_irq(output->domain, soc_int);
out:
chained_irq_exit(chip, desc);
@@ -102,85 +229,110 @@ out:
* thus go into 4 IRRs. A routing value of '0' means the interrupt is left
* disconnected. Routing values {1..15} connect to output lines {0..14}.
*/
-static int __init map_interrupts(struct device_node *node, struct irq_domain *domain)
+static int __init setup_parent_interrupts(struct device_node *node, int *parents,
+ unsigned int num_parents)
{
- struct device_node *cpu_ictl;
- const __be32 *imap;
- u32 imaplen, soc_int, cpu_int, tmp, regs[4];
- int ret, i, irr_regs[] = {
- RTL_ICTL_IRR3,
- RTL_ICTL_IRR2,
- RTL_ICTL_IRR1,
- RTL_ICTL_IRR0,
- };
- u8 mips_irqs_set;
+ struct realtek_ictl_output *outputs;
+ struct realtek_ictl_output *output;
+ struct irq_domain *domain;
+ unsigned int p;
- ret = of_property_read_u32(node, "#address-cells", &tmp);
- if (ret || tmp)
- return -EINVAL;
+ outputs = kcalloc(num_parents, sizeof(*outputs), GFP_KERNEL);
+ if (!outputs)
+ return -ENOMEM;
- imap = of_get_property(node, "interrupt-map", &imaplen);
- if (!imap || imaplen % 3)
- return -EINVAL;
+ for (p = 0; p < num_parents; p++) {
+ output = outputs + p;
- mips_irqs_set = 0;
- memset(regs, 0, sizeof(regs));
- for (i = 0; i < imaplen; i += 3 * sizeof(u32)) {
- soc_int = be32_to_cpup(imap);
- if (soc_int > 31)
- return -EINVAL;
-
- cpu_ictl = of_find_node_by_phandle(be32_to_cpup(imap + 1));
- if (!cpu_ictl)
- return -EINVAL;
- ret = of_property_read_u32(cpu_ictl, "#interrupt-cells", &tmp);
- of_node_put(cpu_ictl);
- if (ret || tmp != 1)
- return -EINVAL;
-
- cpu_int = be32_to_cpup(imap + 2);
- if (cpu_int > 7 || cpu_int < 2)
- return -EINVAL;
-
- if (!(mips_irqs_set & BIT(cpu_int))) {
- irq_set_chained_handler_and_data(cpu_int, realtek_irq_dispatch,
- domain);
- mips_irqs_set |= BIT(cpu_int);
- }
+ domain = irq_domain_add_linear(node, RTL_ICTL_NUM_INPUTS, &irq_domain_ops, output);
+ if (!domain)
+ goto domain_err;
- /* Use routing values (1..6) for CPU interrupts (2..7) */
- regs[(soc_int * 4) / 32] |= (cpu_int - 1) << (soc_int * 4) % 32;
- imap += 3;
- }
+ output->fwnode = of_node_to_fwnode(node);
+ output->output_index = p;
+ output->domain = domain;
- for (i = 0; i < 4; i++)
- writel(regs[i], REG(irr_regs[i]));
+ irq_set_chained_handler_and_data(parents[p], realtek_irq_dispatch, output);
+ }
return 0;
+
+domain_err:
+ while (p--) {
+ irq_set_chained_handler_and_data(parents[p], NULL, NULL);
+ irq_domain_remove(outputs[p].domain);
+ }
+
+ kfree(outputs);
+
+ return -ENOMEM;
}
static int __init realtek_rtl_of_init(struct device_node *node, struct device_node *parent)
{
- struct irq_domain *domain;
- int ret;
+ int parent_irqs[RTL_ICTL_NUM_OUTPUTS];
+ struct of_phandle_args oirq;
+ unsigned int num_parents;
+ unsigned int soc_irq;
+ unsigned int p;
+ int cpu;
+
+ cpumask_clear(&realtek_ictl_cpu_configurable);
+
+ for (cpu = 0; cpu < NR_CPUS; cpu++) {
+ realtek_ictl_base[cpu] = of_iomap(node, cpu);
+ if (realtek_ictl_base[cpu]) {
+ cpumask_set_cpu(cpu, &realtek_ictl_cpu_configurable);
+
+ /* Disable all cascaded interrupts and clear routing */
+ writel(0, REG(RTL_ICTL_GIMR, cpu));
+ for (soc_irq = 0; soc_irq < RTL_ICTL_NUM_INPUTS; soc_irq++)
+ write_irr(REG(RTL_ICTL_IRR0, cpu), soc_irq, 0);
+ }
+ }
- realtek_ictl_base = of_iomap(node, 0);
- if (!realtek_ictl_base)
+ if (cpumask_empty(&realtek_ictl_cpu_configurable))
return -ENXIO;
- /* Disable all cascaded interrupts */
- writel(0, REG(RTL_ICTL_GIMR));
+ num_parents = of_irq_count(node);
+ if (num_parents > RTL_ICTL_NUM_OUTPUTS) {
+ pr_err("too many parent interrupts\n");
+ return -EINVAL;
+ }
- domain = irq_domain_add_simple(node, 32, 0,
- &irq_domain_ops, NULL);
+ for (p = 0; p < num_parents; p++)
+ parent_irqs[p] = of_irq_get(node, p);
- ret = map_interrupts(node, domain);
- if (ret) {
- pr_err("invalid interrupt map\n");
- return ret;
+ if (WARN_ON(!num_parents)) {
+ /*
+ * If DT contains no parent interrupts, assume MIPS CPU IRQ 2
+ * (HW0) is connected to the first output. This is the case for
+ * all known hardware anyway. "interrupt-map" is deprecated, so
+ * don't bother trying to parse that.
+ * Since this is to account for old devicetrees with one-cell
+ * interrupt specifiers, only one output domain is needed.
+ */
+ oirq.np = of_find_compatible_node(NULL, NULL, "mti,cpu-interrupt-controller");
+ if (oirq.np) {
+ oirq.args_count = 1;
+ oirq.args[0] = 2;
+
+ parent_irqs[0] = irq_create_of_mapping(&oirq);
+ num_parents = 1;
+ }
+
+ of_node_put(oirq.np);
}
- return 0;
+ /* Ensure we haven't collected any errors before proceeding */
+ for (p = 0; p < num_parents; p++) {
+ if (parent_irqs[p] < 0)
+ return parent_irqs[p];
+ if (!parent_irqs[p])
+ return -ENODEV;
+ }
+
+ return setup_parent_interrupts(node, &parent_irqs[0], num_parents);
}
IRQCHIP_DECLARE(realtek_rtl_intc, "realtek,rtl-intc", realtek_rtl_of_init);

View File

@ -1,51 +0,0 @@
From bde6311569ef25a00c3beaeabfd6b78b19651872 Mon Sep 17 00:00:00 2001
From: Sander Vanheule <sander@svanheule.net>
Date: Sun, 29 May 2022 19:38:09 +0200
Subject: [PATCH] realtek: don't unmask non-maskable GPIO IRQs
On uniprocessor builds, for_each_cpu(cpu, mask) will assume 'mask'
always contains exactly one CPU, and ignore the actual mask contents.
This causes the loop to run, even when it shouldn't on an empty mask,
and tries to access an uninitialised pointer.
Fix this by wrapping the loop in a cpumask_empty() check, to ensure it
will not run on uniprocessor builds if the CPU mask is empty.
Fixes: af6cd37f42f3 ("realtek: replace RTL93xx GPIO patches")
Reported-by: INAGAKI Hiroshi <musashino.open@gmail.com>
Reported-by: Robert Marko <robimarko@gmail.com>
Tested-by: Robert Marko <robimarko@gmail.com>
Submitted-by: Sander Vanheule <sander@svanheule.net>
---
drivers/gpio/gpio-realtek-otto.c | 9 +++++++++++--
1 file changed, 11 insertions(+), 2 deletions(-)
--- a/drivers/gpio/gpio-realtek-otto.c
+++ b/drivers/gpio/gpio-realtek-otto.c
@@ -301,6 +301,7 @@ static int realtek_gpio_irq_set_affinity
static int realtek_gpio_irq_init(struct gpio_chip *gc)
{
struct realtek_gpio_ctrl *ctrl = gpiochip_get_data(gc);
+ void __iomem *irq_cpu_mask;
unsigned int port;
int cpu;
@@ -308,8 +309,16 @@ static int realtek_gpio_irq_init(struct
realtek_gpio_write_imr(ctrl, port, 0, 0);
realtek_gpio_clear_isr(ctrl, port, GENMASK(7, 0));
- for_each_cpu(cpu, &ctrl->cpu_irq_maskable)
- iowrite8(GENMASK(7, 0), realtek_gpio_irq_cpu_mask(ctrl, port, cpu));
+ /*
+ * Uniprocessor builds assume a mask always contains one CPU,
+ * so only start the loop if we have at least one maskable CPU.
+ */
+ if(!cpumask_empty(&ctrl->cpu_irq_maskable)) {
+ for_each_cpu(cpu, &ctrl->cpu_irq_maskable) {
+ irq_cpu_mask = realtek_gpio_irq_cpu_mask(ctrl, port, cpu);
+ iowrite8(GENMASK(7, 0), irq_cpu_mask);
+ }
+ }
}
return 0;

View File

@ -1,368 +0,0 @@
From ee0175b3b44288c74d5292c2a9c2c154f6c0317e Mon Sep 17 00:00:00 2001
From: Sander Vanheule <sander@svanheule.net>
Date: Sun, 7 Aug 2022 21:21:15 +0200
Subject: [PATCH] gpio: realtek-otto: switch to 32-bit I/O
By using 16-bit I/O on the GPIO peripheral, which is apparently not safe
on MIPS, the IMR can end up containing garbage. This then results in
interrupt triggers for lines that don't have an interrupt handler
associated. The irq_desc lookup fails, and the ISR will not be cleared,
keeping the CPU busy until reboot, or until another IMR operation
restores the correct value. This situation appears to happen very
rarely, for < 0.5% of IMR writes.
Instead of using 8-bit or 16-bit I/O operations on the 32-bit memory
mapped peripheral registers, switch to using 32-bit I/O only, operating
on the entire bank for all single bit line settings. For 2-bit line
settings, with 16-bit port values, stick to manual (un)packing.
This issue has been seen on RTL8382M (HPE 1920-16G), RTL8391M (Netgear
GS728TP v2), and RTL8393M (D-Link DGS-1210-52 F3, Zyxel GS1900-48).
Reported-by: Luiz Angelo Daros de Luca <luizluca@gmail.com> # DGS-1210-52
Reported-by: Birger Koblitz <mail@birger-koblitz.de> # GS728TP
Reported-by: Jan Hoffmann <jan@3e8.eu> # 1920-16G
Fixes: 0d82fb1127fb ("gpio: Add Realtek Otto GPIO support")
Signed-off-by: Sander Vanheule <sander@svanheule.net>
Cc: Paul Cercueil <paul@crapouillou.net>
Reviewed-by: Linus Walleij <linus.walleij@linaro.org>
Signed-off-by: Bartosz Golaszewski <brgl@bgdev.pl>
Update patch for missing upstream changes:
- commit a01a40e33499 ("gpio: realtek-otto: Make the irqchip immutable")
Signed-off-by: Sander Vanheule <sander@svanheule.net>
---
drivers/gpio/gpio-realtek-otto.c | 166 ++++++++++++++++---------------
1 file changed, 85 insertions(+), 81 deletions(-)
--- a/drivers/gpio/gpio-realtek-otto.c
+++ b/drivers/gpio/gpio-realtek-otto.c
@@ -46,10 +46,20 @@
* @lock: Lock for accessing the IRQ registers and values
* @intr_mask: Mask for interrupts lines
* @intr_type: Interrupt type selection
+ * @bank_read: Read a bank setting as a single 32-bit value
+ * @bank_write: Write a bank setting as a single 32-bit value
+ * @imr_line_pos: Bit shift of an IRQ line's IMR value.
+ *
+ * The DIR, DATA, and ISR registers consist of four 8-bit port values, packed
+ * into a single 32-bit register. Use @bank_read (@bank_write) to get (assign)
+ * a value from (to) these registers. The IMR register consists of four 16-bit
+ * port values, packed into two 32-bit registers. Use @imr_line_pos to get the
+ * bit shift of the 2-bit field for a line's IMR settings. Shifts larger than
+ * 32 overflow into the second register.
*
* Because the interrupt mask register (IMR) combines the function of IRQ type
* selection and masking, two extra values are stored. @intr_mask is used to
- * mask/unmask the interrupts for a GPIO port, and @intr_type is used to store
+ * mask/unmask the interrupts for a GPIO line, and @intr_type is used to store
* the selected interrupt types. The logical AND of these values is written to
* IMR on changes.
*/
@@ -59,10 +69,11 @@ struct realtek_gpio_ctrl {
void __iomem *cpumask_base;
struct cpumask cpu_irq_maskable;
raw_spinlock_t lock;
- u16 intr_mask[REALTEK_GPIO_PORTS_PER_BANK];
- u16 intr_type[REALTEK_GPIO_PORTS_PER_BANK];
- unsigned int (*port_offset_u8)(unsigned int port);
- unsigned int (*port_offset_u16)(unsigned int port);
+ u8 intr_mask[REALTEK_GPIO_MAX];
+ u8 intr_type[REALTEK_GPIO_MAX];
+ u32 (*bank_read)(void __iomem *reg);
+ void (*bank_write)(void __iomem *reg, u32 value);
+ unsigned int (*line_imr_pos)(unsigned int line);
};
/* Expand with more flags as devices with other quirks are added */
@@ -101,14 +112,22 @@ static struct realtek_gpio_ctrl *irq_dat
* port. The two interrupt mask registers store two bits per GPIO, so use u16
* values.
*/
-static unsigned int realtek_gpio_port_offset_u8(unsigned int port)
+static u32 realtek_gpio_bank_read_swapped(void __iomem *reg)
+{
+ return ioread32be(reg);
+}
+
+static void realtek_gpio_bank_write_swapped(void __iomem *reg, u32 value)
{
- return port;
+ iowrite32be(value, reg);
}
-static unsigned int realtek_gpio_port_offset_u16(unsigned int port)
+static unsigned int realtek_gpio_line_imr_pos_swapped(unsigned int line)
{
- return 2 * port;
+ unsigned int port_pin = line % 8;
+ unsigned int port = line / 8;
+
+ return 2 * (8 * (port ^ 1) + port_pin);
}
/*
@@ -119,64 +138,65 @@ static unsigned int realtek_gpio_port_of
* per GPIO, so use u16 values. The first register contains ports 1 and 0, the
* second ports 3 and 2.
*/
-static unsigned int realtek_gpio_port_offset_u8_rev(unsigned int port)
+static u32 realtek_gpio_bank_read(void __iomem *reg)
{
- return 3 - port;
+ return ioread32(reg);
}
-static unsigned int realtek_gpio_port_offset_u16_rev(unsigned int port)
+static void realtek_gpio_bank_write(void __iomem *reg, u32 value)
{
- return 2 * (port ^ 1);
+ iowrite32(value, reg);
}
-static void realtek_gpio_write_imr(struct realtek_gpio_ctrl *ctrl,
- unsigned int port, u16 irq_type, u16 irq_mask)
+static unsigned int realtek_gpio_line_imr_pos(unsigned int line)
{
- iowrite16(irq_type & irq_mask,
- ctrl->base + REALTEK_GPIO_REG_IMR + ctrl->port_offset_u16(port));
+ return 2 * line;
}
-static void realtek_gpio_clear_isr(struct realtek_gpio_ctrl *ctrl,
- unsigned int port, u8 mask)
+static void realtek_gpio_clear_isr(struct realtek_gpio_ctrl *ctrl, u32 mask)
{
- iowrite8(mask, ctrl->base + REALTEK_GPIO_REG_ISR + ctrl->port_offset_u8(port));
+ ctrl->bank_write(ctrl->base + REALTEK_GPIO_REG_ISR, mask);
}
-static u8 realtek_gpio_read_isr(struct realtek_gpio_ctrl *ctrl, unsigned int port)
+static u32 realtek_gpio_read_isr(struct realtek_gpio_ctrl *ctrl)
{
- return ioread8(ctrl->base + REALTEK_GPIO_REG_ISR + ctrl->port_offset_u8(port));
+ return ctrl->bank_read(ctrl->base + REALTEK_GPIO_REG_ISR);
}
-/* Set the rising and falling edge mask bits for a GPIO port pin */
-static u16 realtek_gpio_imr_bits(unsigned int pin, u16 value)
+/* Set the rising and falling edge mask bits for a GPIO pin */
+static void realtek_gpio_update_line_imr(struct realtek_gpio_ctrl *ctrl, unsigned int line)
{
- return (value & REALTEK_GPIO_IMR_LINE_MASK) << 2 * pin;
+ void __iomem *reg = ctrl->base + REALTEK_GPIO_REG_IMR;
+ unsigned int line_shift = ctrl->line_imr_pos(line);
+ unsigned int shift = line_shift % 32;
+ u32 irq_type = ctrl->intr_type[line];
+ u32 irq_mask = ctrl->intr_mask[line];
+ u32 reg_val;
+
+ reg += 4 * (line_shift / 32);
+ reg_val = ioread32(reg);
+ reg_val &= ~(REALTEK_GPIO_IMR_LINE_MASK << shift);
+ reg_val |= (irq_type & irq_mask & REALTEK_GPIO_IMR_LINE_MASK) << shift;
+ iowrite32(reg_val, reg);
}
static void realtek_gpio_irq_ack(struct irq_data *data)
{
struct realtek_gpio_ctrl *ctrl = irq_data_to_ctrl(data);
irq_hw_number_t line = irqd_to_hwirq(data);
- unsigned int port = line / 8;
- unsigned int port_pin = line % 8;
- realtek_gpio_clear_isr(ctrl, port, BIT(port_pin));
+ realtek_gpio_clear_isr(ctrl, BIT(line));
}
static void realtek_gpio_irq_unmask(struct irq_data *data)
{
struct realtek_gpio_ctrl *ctrl = irq_data_to_ctrl(data);
unsigned int line = irqd_to_hwirq(data);
- unsigned int port = line / 8;
- unsigned int port_pin = line % 8;
unsigned long flags;
- u16 m;
raw_spin_lock_irqsave(&ctrl->lock, flags);
- m = ctrl->intr_mask[port];
- m |= realtek_gpio_imr_bits(port_pin, REALTEK_GPIO_IMR_LINE_MASK);
- ctrl->intr_mask[port] = m;
- realtek_gpio_write_imr(ctrl, port, ctrl->intr_type[port], m);
+ ctrl->intr_mask[line] = REALTEK_GPIO_IMR_LINE_MASK;
+ realtek_gpio_update_line_imr(ctrl, line);
raw_spin_unlock_irqrestore(&ctrl->lock, flags);
}
@@ -184,16 +204,11 @@ static void realtek_gpio_irq_mask(struct
{
struct realtek_gpio_ctrl *ctrl = irq_data_to_ctrl(data);
unsigned int line = irqd_to_hwirq(data);
- unsigned int port = line / 8;
- unsigned int port_pin = line % 8;
unsigned long flags;
- u16 m;
raw_spin_lock_irqsave(&ctrl->lock, flags);
- m = ctrl->intr_mask[port];
- m &= ~realtek_gpio_imr_bits(port_pin, REALTEK_GPIO_IMR_LINE_MASK);
- ctrl->intr_mask[port] = m;
- realtek_gpio_write_imr(ctrl, port, ctrl->intr_type[port], m);
+ ctrl->intr_mask[line] = 0;
+ realtek_gpio_update_line_imr(ctrl, line);
raw_spin_unlock_irqrestore(&ctrl->lock, flags);
}
@@ -201,10 +216,8 @@ static int realtek_gpio_irq_set_type(str
{
struct realtek_gpio_ctrl *ctrl = irq_data_to_ctrl(data);
unsigned int line = irqd_to_hwirq(data);
- unsigned int port = line / 8;
- unsigned int port_pin = line % 8;
unsigned long flags;
- u16 type, t;
+ u8 type;
switch (flow_type & IRQ_TYPE_SENSE_MASK) {
case IRQ_TYPE_EDGE_FALLING:
@@ -223,11 +236,8 @@ static int realtek_gpio_irq_set_type(str
irq_set_handler_locked(data, handle_edge_irq);
raw_spin_lock_irqsave(&ctrl->lock, flags);
- t = ctrl->intr_type[port];
- t &= ~realtek_gpio_imr_bits(port_pin, REALTEK_GPIO_IMR_LINE_MASK);
- t |= realtek_gpio_imr_bits(port_pin, type);
- ctrl->intr_type[port] = t;
- realtek_gpio_write_imr(ctrl, port, t, ctrl->intr_mask[port]);
+ ctrl->intr_type[line] = type;
+ realtek_gpio_update_line_imr(ctrl, line);
raw_spin_unlock_irqrestore(&ctrl->lock, flags);
return 0;
@@ -238,28 +248,21 @@ static void realtek_gpio_irq_handler(str
struct gpio_chip *gc = irq_desc_get_handler_data(desc);
struct realtek_gpio_ctrl *ctrl = gpiochip_get_data(gc);
struct irq_chip *irq_chip = irq_desc_get_chip(desc);
- unsigned int lines_done;
- unsigned int port_pin_count;
unsigned long status;
int offset;
chained_irq_enter(irq_chip, desc);
- for (lines_done = 0; lines_done < gc->ngpio; lines_done += 8) {
- status = realtek_gpio_read_isr(ctrl, lines_done / 8);
- port_pin_count = min(gc->ngpio - lines_done, 8U);
- for_each_set_bit(offset, &status, port_pin_count)
- generic_handle_domain_irq(gc->irq.domain, offset + lines_done);
- }
+ status = realtek_gpio_read_isr(ctrl);
+ for_each_set_bit(offset, &status, gc->ngpio)
+ generic_handle_domain_irq(gc->irq.domain, offset);
chained_irq_exit(irq_chip, desc);
}
-static inline void __iomem *realtek_gpio_irq_cpu_mask(struct realtek_gpio_ctrl *ctrl,
- unsigned int port, int cpu)
+static inline void __iomem *realtek_gpio_irq_cpu_mask(struct realtek_gpio_ctrl *ctrl, int cpu)
{
- return ctrl->cpumask_base + ctrl->port_offset_u8(port) +
- REALTEK_GPIO_PORTS_PER_BANK * cpu;
+ return ctrl->cpumask_base + REALTEK_GPIO_PORTS_PER_BANK * cpu;
}
static int realtek_gpio_irq_set_affinity(struct irq_data *data,
@@ -267,12 +270,10 @@ static int realtek_gpio_irq_set_affinity
{
struct realtek_gpio_ctrl *ctrl = irq_data_to_ctrl(data);
unsigned int line = irqd_to_hwirq(data);
- unsigned int port = line / 8;
- unsigned int port_pin = line % 8;
void __iomem *irq_cpu_mask;
unsigned long flags;
int cpu;
- u8 v;
+ u32 v;
if (!ctrl->cpumask_base)
return -ENXIO;
@@ -280,15 +281,15 @@ static int realtek_gpio_irq_set_affinity
raw_spin_lock_irqsave(&ctrl->lock, flags);
for_each_cpu(cpu, &ctrl->cpu_irq_maskable) {
- irq_cpu_mask = realtek_gpio_irq_cpu_mask(ctrl, port, cpu);
- v = ioread8(irq_cpu_mask);
+ irq_cpu_mask = realtek_gpio_irq_cpu_mask(ctrl, cpu);
+ v = ctrl->bank_read(irq_cpu_mask);
if (cpumask_test_cpu(cpu, dest))
- v |= BIT(port_pin);
+ v |= BIT(line);
else
- v &= ~BIT(port_pin);
+ v &= ~BIT(line);
- iowrite8(v, irq_cpu_mask);
+ ctrl->bank_write(irq_cpu_mask, v);
}
raw_spin_unlock_irqrestore(&ctrl->lock, flags);
@@ -302,22 +303,23 @@ static int realtek_gpio_irq_init(struct
{
struct realtek_gpio_ctrl *ctrl = gpiochip_get_data(gc);
void __iomem *irq_cpu_mask;
- unsigned int port;
+ u32 mask_all = GENMASK(gc->ngpio - 1, 0);
+ unsigned int line;
int cpu;
- for (port = 0; (port * 8) < gc->ngpio; port++) {
- realtek_gpio_write_imr(ctrl, port, 0, 0);
- realtek_gpio_clear_isr(ctrl, port, GENMASK(7, 0));
-
- /*
- * Uniprocessor builds assume a mask always contains one CPU,
- * so only start the loop if we have at least one maskable CPU.
- */
- if(!cpumask_empty(&ctrl->cpu_irq_maskable)) {
- for_each_cpu(cpu, &ctrl->cpu_irq_maskable) {
- irq_cpu_mask = realtek_gpio_irq_cpu_mask(ctrl, port, cpu);
- iowrite8(GENMASK(7, 0), irq_cpu_mask);
- }
+ for (line = 0; line < gc->ngpio; line++)
+ realtek_gpio_update_line_imr(ctrl, line);
+
+ realtek_gpio_clear_isr(ctrl, mask_all);
+
+ /*
+ * Uniprocessor builds assume a mask always contains one CPU,
+ * so only start the loop if we have at least one maskable CPU.
+ */
+ if(!cpumask_empty(&ctrl->cpu_irq_maskable)) {
+ for_each_cpu(cpu, &ctrl->cpu_irq_maskable) {
+ irq_cpu_mask = realtek_gpio_irq_cpu_mask(ctrl, cpu);
+ ctrl->bank_write(irq_cpu_mask, mask_all);
}
}
@@ -390,12 +392,14 @@ static int realtek_gpio_probe(struct pla
if (dev_flags & GPIO_PORTS_REVERSED) {
bgpio_flags = 0;
- ctrl->port_offset_u8 = realtek_gpio_port_offset_u8_rev;
- ctrl->port_offset_u16 = realtek_gpio_port_offset_u16_rev;
+ ctrl->bank_read = realtek_gpio_bank_read;
+ ctrl->bank_write = realtek_gpio_bank_write;
+ ctrl->line_imr_pos = realtek_gpio_line_imr_pos;
} else {
bgpio_flags = BGPIOF_BIG_ENDIAN_BYTE_ORDER;
- ctrl->port_offset_u8 = realtek_gpio_port_offset_u8;
- ctrl->port_offset_u16 = realtek_gpio_port_offset_u16;
+ ctrl->bank_read = realtek_gpio_bank_read_swapped;
+ ctrl->bank_write = realtek_gpio_bank_write_swapped;
+ ctrl->line_imr_pos = realtek_gpio_line_imr_pos_swapped;
}
err = bgpio_init(&ctrl->gc, dev, 4,

View File

@ -1,33 +0,0 @@
From 800d5fb3c6a16661932c932bacd660e38d06b727 Mon Sep 17 00:00:00 2001
From: Markus Stockhausen <markus.stockhausen@gmx.de>
Date: Thu, 25 Aug 2022 08:22:36 +0200
Subject: [PATCH] realtek: add patch to enable new clock driver in kernel
Allow building the clock driver with kernel config options.
Submitted-by: Markus Stockhausen <markus.stockhausen@gmx.de>
---
drivers/clk/Kconfig | 1 +
drivers/clk/Makefile | 1 +
2 files changed, 2 insertions(+)
--- a/drivers/clk/Kconfig
+++ b/drivers/clk/Kconfig
@@ -406,6 +406,7 @@ source "drivers/clk/mstar/Kconfig"
source "drivers/clk/mvebu/Kconfig"
source "drivers/clk/pistachio/Kconfig"
source "drivers/clk/qcom/Kconfig"
+source "drivers/clk/realtek/Kconfig"
source "drivers/clk/ralink/Kconfig"
source "drivers/clk/renesas/Kconfig"
source "drivers/clk/rockchip/Kconfig"
--- a/drivers/clk/Makefile
+++ b/drivers/clk/Makefile
@@ -101,6 +101,7 @@ obj-$(CONFIG_COMMON_CLK_PISTACHIO) += pi
obj-$(CONFIG_COMMON_CLK_PXA) += pxa/
obj-$(CONFIG_COMMON_CLK_QCOM) += qcom/
obj-y += ralink/
+obj-$(CONFIG_COMMON_CLK_REALTEK) += realtek/
obj-y += renesas/
obj-$(CONFIG_ARCH_ROCKCHIP) += rockchip/
obj-$(CONFIG_COMMON_CLK_SAMSUNG) += samsung/

View File

@ -1,159 +0,0 @@
From 2cd00b51470a30198b048a5fca48a04db77e29cc Mon Sep 17 00:00:00 2001
From: INAGAKI Hiroshi <musashino.open@gmail.com>
Date: Fri, 21 May 2021 23:16:37 +0900
Subject: [PATCH] realtek: backport irq-realtek-rtl driver from 5.12 to 5.10
This patch backports "irq-realtek-rtl" driver to Kernel 5.10 from 5.12.
"MACH_REALTEK_RTL" is used as a platform name in upstream, but "RTL838X"
is used in OpenWrt, so update the dependency by the additional patch.
Submitted-by: INAGAKI Hiroshi <musashino.open@gmail.com>
---
drivers/irqchip/irq-realtek-rtl.c | 38 +++++++++++------
1 files changed, 58 insertions(+), 20 deletions(-)
--- a/drivers/irqchip/irq-realtek-rtl.c
+++ b/drivers/irqchip/irq-realtek-rtl.c
@@ -28,6 +28,7 @@ static DEFINE_RAW_SPINLOCK(irq_lock);
#define REG(offset, cpu) (realtek_ictl_base[cpu] + offset)
+static u32 realtek_ictl_unmask[NR_CPUS];
static void __iomem *realtek_ictl_base[NR_CPUS];
static cpumask_t realtek_ictl_cpu_configurable;
@@ -41,11 +42,29 @@ struct realtek_ictl_output {
};
/*
- * IRR0-IRR3 store 4 bits per interrupt, but Realtek uses inverted numbering,
- * placing IRQ 31 in the first four bits. A routing value of '0' means the
- * interrupt is left disconnected. Routing values {1..15} connect to output
- * lines {0..14}.
+ * Per CPU we have a set of 5 registers that determine interrupt handling for
+ * 32 external interrupts. GIMR (enable/disable interrupt) plus IRR0-IRR3 that
+ * contain "routing" or "priority" values. GIMR uses one bit for each interrupt
+ * and IRRx store 4 bits per interrupt. Realtek uses inverted numbering,
+ * placing IRQ 31 in the first four bits. The register combinations give the
+ * following results for a single interrupt in the wild:
+ *
+ * a) GIMR = 0 / IRRx > 0 -> no interrupts
+ * b) GIMR = 0 / IRRx = 0 -> no interrupts
+ * c) GIMR = 1 / IRRx > 0 -> interrupts
+ * d) GIMR = 1 / IRRx = 0 -> rare interrupts in SMP environment
+ *
+ * Combination d) seems to trigger interrupts only on a VPE if the other VPE
+ * has GIMR = 0 and IRRx > 0. E.g. busy without interrupts allowed. To provide
+ * IRQ balancing features in SMP this driver will handle the registers as
+ * follows:
+ *
+ * 1) set IRRx > 0 for VPE where the interrupt is desired
+ * 2) set IRRx = 0 for VPE where the interrupt is not desired
+ * 3) set both GIMR = 0 to mask (disabled) interrupt
+ * 4) set GIMR = 1 to unmask (enable) interrupt but only for VPE where IRRx > 0
*/
+
#define IRR_OFFSET(idx) (4 * (3 - (idx * 4) / 32))
#define IRR_SHIFT(idx) ((idx * 4) % 32)
@@ -65,19 +84,33 @@ static inline void write_irr(void __iome
writel(irr, irr0 + offset);
}
+static inline void enable_gimr(int hwirq, int cpu)
+{
+ u32 value;
+
+ value = readl(REG(RTL_ICTL_GIMR, cpu));
+ value |= (BIT(hwirq) & realtek_ictl_unmask[cpu]);
+ writel(value, REG(RTL_ICTL_GIMR, cpu));
+}
+
+static inline void disable_gimr(int hwirq, int cpu)
+{
+ u32 value;
+
+ value = readl(REG(RTL_ICTL_GIMR, cpu));
+ value &= ~BIT(hwirq);
+ writel(value, REG(RTL_ICTL_GIMR, cpu));
+}
+
static void realtek_ictl_unmask_irq(struct irq_data *i)
{
unsigned long flags;
- u32 value;
int cpu;
raw_spin_lock_irqsave(&irq_lock, flags);
- for_each_cpu(cpu, &realtek_ictl_cpu_configurable) {
- value = readl(REG(RTL_ICTL_GIMR, cpu));
- value |= BIT(i->hwirq);
- writel(value, REG(RTL_ICTL_GIMR, cpu));
- }
+ for_each_cpu(cpu, &realtek_ictl_cpu_configurable)
+ enable_gimr(i->hwirq, cpu);
raw_spin_unlock_irqrestore(&irq_lock, flags);
}
@@ -85,16 +118,12 @@ static void realtek_ictl_unmask_irq(stru
static void realtek_ictl_mask_irq(struct irq_data *i)
{
unsigned long flags;
- u32 value;
int cpu;
raw_spin_lock_irqsave(&irq_lock, flags);
- for_each_cpu(cpu, &realtek_ictl_cpu_configurable) {
- value = readl(REG(RTL_ICTL_GIMR, cpu));
- value &= ~BIT(i->hwirq);
- writel(value, REG(RTL_ICTL_GIMR, cpu));
- }
+ for_each_cpu(cpu, &realtek_ictl_cpu_configurable)
+ disable_gimr(i->hwirq, cpu);
raw_spin_unlock_irqrestore(&irq_lock, flags);
}
@@ -116,11 +145,17 @@ static int __maybe_unused realtek_ictl_i
cpumask_and(&cpu_enable, &cpu_configure, dest);
cpumask_andnot(&cpu_disable, &cpu_configure, dest);
- for_each_cpu(cpu, &cpu_disable)
+ for_each_cpu(cpu, &cpu_disable) {
write_irr(REG(RTL_ICTL_IRR0, cpu), i->hwirq, 0);
+ realtek_ictl_unmask[cpu] &= ~BIT(i->hwirq);
+ disable_gimr(i->hwirq, cpu);
+ }
- for_each_cpu(cpu, &cpu_enable)
+ for_each_cpu(cpu, &cpu_enable) {
write_irr(REG(RTL_ICTL_IRR0, cpu), i->hwirq, output->output_index + 1);
+ realtek_ictl_unmask[cpu] |= BIT(i->hwirq);
+ enable_gimr(i->hwirq, cpu);
+ }
irq_data_update_effective_affinity(i, &cpu_enable);
@@ -149,6 +184,7 @@ static int intc_map(struct irq_domain *d
output->child_mask |= BIT(hw);
write_irr(REG(RTL_ICTL_IRR0, 0), hw, output->output_index + 1);
+ realtek_ictl_unmask[0] |= BIT(hw);
raw_spin_unlock_irqrestore(&irq_lock, flags);
@@ -285,9 +321,11 @@ static int __init realtek_rtl_of_init(st
cpumask_set_cpu(cpu, &realtek_ictl_cpu_configurable);
/* Disable all cascaded interrupts and clear routing */
- writel(0, REG(RTL_ICTL_GIMR, cpu));
- for (soc_irq = 0; soc_irq < RTL_ICTL_NUM_INPUTS; soc_irq++)
+ for (soc_irq = 0; soc_irq < RTL_ICTL_NUM_INPUTS; soc_irq++) {
write_irr(REG(RTL_ICTL_IRR0, cpu), soc_irq, 0);
+ realtek_ictl_unmask[cpu] &= ~BIT(soc_irq);
+ disable_gimr(soc_irq, cpu);
+ }
}
}

View File

@ -1,42 +0,0 @@
From 2b88563ee5aafd9571d965b7f2093a0f58d98a31 Mon Sep 17 00:00:00 2001
From: John Crispin <john@phrozen.org>
Date: Thu, 26 Nov 2020 12:02:21 +0100
Subject: net: dsa: Add support for rtl838x switch
* rename the target to realtek
* add refactored DSA driver
* add latest gpio driver
* lots of arch cleanups
* new irq driver
* additional boards
Submitted-by: Bert Vermeulen <bert@biot.com>
Submitted-by: Birger Koblitz <mail@birger-koblitz.de>
Submitted-by: Sander Vanheule <sander@svanheule.net>
Submitted-by: Bjørn Mork <bjorn@mork.no>
Submitted-by: John Crispin <john@phrozen.org>
---
drivers/net/dsa/rtl83xx/Kconfig | 2 ++
drivers/net/dsa/rtl83xx/Makefile | 1 +
2 files changed, 3 insertions(+)
--- a/drivers/net/dsa/Kconfig
+++ b/drivers/net/dsa/Kconfig
@@ -85,6 +85,8 @@ source "drivers/net/dsa/sja1105/Kconfig"
source "drivers/net/dsa/xrs700x/Kconfig"
+source "drivers/net/dsa/rtl83xx/Kconfig"
+
config NET_DSA_REALTEK_SMI
tristate "Realtek SMI Ethernet switch family support"
select NET_DSA_TAG_RTL4_A
--- a/drivers/net/dsa/Makefile
+++ b/drivers/net/dsa/Makefile
@@ -24,5 +24,6 @@ obj-y += microchip/
obj-y += mv88e6xxx/
obj-y += ocelot/
obj-y += qca/
+obj-y += rtl83xx/
obj-y += sja1105/
obj-y += xrs700x/

View File

@ -1,61 +0,0 @@
From 2b88563ee5aafd9571d965b7f2093a0f58d98a31 Mon Sep 17 00:00:00 2001
From: John Crispin <john@phrozen.org>
Date: Thu, 26 Nov 2020 12:02:21 +0100
Subject: net: dsa: Add rtl838x support for tag trailer
* rename the target to realtek
* add refactored DSA driver
* add latest gpio driver
* lots of arch cleanups
* new irq driver
* additional boards
Submitted-by: Bert Vermeulen <bert@biot.com>
Submitted-by: Birger Koblitz <mail@birger-koblitz.de>
Submitted-by: Sander Vanheule <sander@svanheule.net>
Submitted-by: Bjørn Mork <bjorn@mork.no>
Submitted-by: John Crispin <john@phrozen.org>
---
net/dsa/tag_trailer.c | 16 +++++++++++++-
1 file changed, 17 insertions(+), 1 deletion(-)
--- a/net/dsa/tag_trailer.c
+++ b/net/dsa/tag_trailer.c
@@ -17,7 +17,12 @@ static struct sk_buff *trailer_xmit(stru
trailer = skb_put(skb, 4);
trailer[0] = 0x80;
+
+#ifdef CONFIG_NET_DSA_RTL83XX
+ trailer[1] = dp->index;
+#else
trailer[1] = 1 << dp->index;
+#endif /* CONFIG_NET_DSA_RTL838X */
trailer[2] = 0x10;
trailer[3] = 0x00;
@@ -33,12 +38,23 @@ static struct sk_buff *trailer_rcv(struc
return NULL;
trailer = skb_tail_pointer(skb) - 4;
+
+#ifdef CONFIG_NET_DSA_RTL83XX
+ if (trailer[0] != 0x80 || (trailer[1] & 0x80) != 0x00 ||
+ (trailer[2] & 0xef) != 0x00 || trailer[3] != 0x00)
+ return NULL;
+
+ if (trailer[1] & 0x40)
+ skb->offload_fwd_mark = 1;
+
+ source_port = trailer[1] & 0x3f;
+#else
if (trailer[0] != 0x80 || (trailer[1] & 0xf8) != 0x00 ||
(trailer[2] & 0xef) != 0x00 || trailer[3] != 0x00)
return NULL;
source_port = trailer[1] & 7;
-
+#endif
skb->dev = dsa_master_find_slave(dev, 0, source_port);
if (!skb->dev)
return NULL;

View File

@ -1,32 +0,0 @@
From 2b88563ee5aafd9571d965b7f2093a0f58d98a31 Mon Sep 17 00:00:00 2001
From: John Crispin <john@phrozen.org>
Date: Thu, 26 Nov 2020 12:02:21 +0100
Subject: net: dsa: Increase max ports for rtl838x
* rename the target to realtek
* add refactored DSA driver
* add latest gpio driver
* lots of arch cleanups
* new irq driver
* additional boards
Submitted-by: Bert Vermeulen <bert@biot.com>
Submitted-by: Birger Koblitz <mail@birger-koblitz.de>
Submitted-by: Sander Vanheule <sander@svanheule.net>
Submitted-by: Bjørn Mork <bjorn@mork.no>
Submitted-by: John Crispin <john@phrozen.org>
---
include/linux/platform_data/dsa.h | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
--- a/include/linux/platform_data/dsa.h
+++ b/include/linux/platform_data/dsa.h
@@ -6,7 +6,7 @@ struct device;
struct net_device;
#define DSA_MAX_SWITCHES 4
-#define DSA_MAX_PORTS 12
+#define DSA_MAX_PORTS 54
#define DSA_RTABLE_NONE -1
struct dsa_chip_data {

View File

@ -1,48 +0,0 @@
From 2b88563ee5aafd9571d965b7f2093a0f58d98a31 Mon Sep 17 00:00:00 2001
From: John Crispin <john@phrozen.org>
Date: Thu, 26 Nov 2020 12:02:21 +0100
Subject: net: ethernet: Add support for RTL838x ethernet
* rename the target to realtek
* add refactored DSA driver
* add latest gpio driver
* lots of arch cleanups
* new irq driver
* additional boards
Submitted-by: Bert Vermeulen <bert@biot.com>
Submitted-by: Birger Koblitz <mail@birger-koblitz.de>
Submitted-by: Sander Vanheule <sander@svanheule.net>
Submitted-by: Bjørn Mork <bjorn@mork.no>
Submitted-by: John Crispin <john@phrozen.org>
---
drivers/net/ethernet/Kconfig | 7 +-
drivers/net/ethernet/Makefile | 1 +
2 files changed, 8 insertions(+)
--- a/drivers/net/ethernet/Kconfig
+++ b/drivers/net/ethernet/Kconfig
@@ -166,6 +166,13 @@ source "drivers/net/ethernet/rdc/Kconfig
source "drivers/net/ethernet/realtek/Kconfig"
source "drivers/net/ethernet/renesas/Kconfig"
source "drivers/net/ethernet/rocker/Kconfig"
+
+config NET_RTL838X
+ tristate "Realtek rtl838x Ethernet MAC support"
+ depends on RTL83XX
+ help
+ Say Y here if you want to use the Realtek rtl838x Gbps Ethernet MAC.
+
source "drivers/net/ethernet/samsung/Kconfig"
source "drivers/net/ethernet/seeq/Kconfig"
source "drivers/net/ethernet/sgi/Kconfig"
--- a/drivers/net/ethernet/Makefile
+++ b/drivers/net/ethernet/Makefile
@@ -77,6 +77,7 @@ obj-$(CONFIG_NET_VENDOR_REALTEK) += real
obj-$(CONFIG_NET_VENDOR_RENESAS) += renesas/
obj-$(CONFIG_NET_VENDOR_RDC) += rdc/
obj-$(CONFIG_NET_VENDOR_ROCKER) += rocker/
+obj-$(CONFIG_NET_RTL838X) += rtl838x_eth.o
obj-$(CONFIG_NET_VENDOR_SAMSUNG) += samsung/
obj-$(CONFIG_NET_VENDOR_SEEQ) += seeq/
obj-$(CONFIG_NET_VENDOR_SILAN) += silan/

View File

@ -1,34 +0,0 @@
From 2b88563ee5aafd9571d965b7f2093a0f58d98a31 Mon Sep 17 00:00:00 2001
From: John Crispin <john@phrozen.org>
Date: Thu, 26 Nov 2020 12:02:21 +0100
Subject: phy: Add PHY ops for rtl838x EEE
* rename the target to realtek
* add refactored DSA driver
* add latest gpio driver
* lots of arch cleanups
* new irq driver
* additional boards
Submitted-by: Bert Vermeulen <bert@biot.com>
Submitted-by: Birger Koblitz <mail@birger-koblitz.de>
Submitted-by: Sander Vanheule <sander@svanheule.net>
Submitted-by: Bjørn Mork <bjorn@mork.no>
Submitted-by: John Crispin <john@phrozen.org>
---
include/linux/phy.h | 4 ++++
1 file changed, 4 insertions(+)
--- a/include/linux/phy.h
+++ b/include/linux/phy.h
@@ -1009,6 +1009,10 @@ struct phy_driver {
int (*led_blink_set)(struct phy_device *dev, u8 index,
unsigned long *delay_on,
unsigned long *delay_off);
+ int (*get_port)(struct phy_device *dev);
+ int (*set_port)(struct phy_device *dev, int port);
+ int (*get_eee)(struct phy_device *dev, struct ethtool_eee *e);
+ int (*set_eee)(struct phy_device *dev, struct ethtool_eee *e);
};
#define to_phy_driver(d) container_of(to_mdio_common_driver(d), \
struct phy_driver, mdiodrv)

View File

@ -1,61 +0,0 @@
From 2b88563ee5aafd9571d965b7f2093a0f58d98a31 Mon Sep 17 00:00:00 2001
From: John Crispin <john@phrozen.org>
Date: Thu, 26 Nov 2020 12:02:21 +0100
Subject: net: phy: EEE support for rtl838x
* rename the target to realtek
* add refactored DSA driver
* add latest gpio driver
* lots of arch cleanups
* new irq driver
* additional boards
Submitted-by: Bert Vermeulen <bert@biot.com>
Submitted-by: Birger Koblitz <mail@birger-koblitz.de>
Submitted-by: Sander Vanheule <sander@svanheule.net>
Submitted-by: Bjørn Mork <bjorn@mork.no>
Submitted-by: John Crispin <john@phrozen.org>
---
drivers/net/phy/phylink. | 14 +++++++++++--
1 file changed, 12 insertions(+), 2 deletions(-)
--- a/drivers/net/phy/phylink.c
+++ b/drivers/net/phy/phylink.c
@@ -1994,6 +1994,11 @@ int phylink_ethtool_ksettings_set(struct
* the presence of a PHY, this should not be changed as that
* should be determined from the media side advertisement.
*/
+ if (pl->phydev->drv->get_port && pl->phydev->drv->set_port) {
+ if(pl->phydev->drv->get_port(pl->phydev) != kset->base.port) {
+ pl->phydev->drv->set_port(pl->phydev, kset->base.port);
+ }
+ }
return phy_ethtool_ksettings_set(pl->phydev, kset);
}
@@ -2297,8 +2302,11 @@ int phylink_ethtool_get_eee(struct phyli
ASSERT_RTNL();
- if (pl->phydev)
+ if (pl->phydev) {
+ if (pl->phydev->drv->get_eee)
+ return pl->phydev->drv->get_eee(pl->phydev, eee);
ret = phy_ethtool_get_eee(pl->phydev, eee);
+ }
return ret;
}
@@ -2315,8 +2323,11 @@ int phylink_ethtool_set_eee(struct phyli
ASSERT_RTNL();
- if (pl->phydev)
+ if (pl->phydev) {
+ if (pl->phydev->drv->set_eee)
+ return pl->phydev->drv->set_eee(pl->phydev, eee);
ret = phy_ethtool_set_eee(pl->phydev, eee);
+ }
return ret;
}

View File

@ -1,62 +0,0 @@
From 9d9bf16aa8d966834ac1280f96c37d22552c33d1 Mon Sep 17 00:00:00 2001
From: Birger Koblitz <git@birger-koblitz.de>
Date: Wed, 8 Sep 2021 16:13:18 +0200
Subject: phy: Add PHY hsgmii mode
This adds RTL93xx-specific MAC configuration routines that allow also configuration
of 10GBit links for phylink. There is support for the Realtek-specific HISGMI
protocol.
Submitted-by: Birger Koblitz <git@birger-koblitz.de>
---
drivers/net/phy/phylink.c | 2 ++
include/linux/phy.h | 3 +++
2 file changed, 5 insertions(+)
--- a/drivers/net/phy/phy-core.c
+++ b/drivers/net/phy/phy-core.c
@@ -124,6 +124,7 @@ int phy_interface_num_ports(phy_interfac
case PHY_INTERFACE_MODE_MOCA:
case PHY_INTERFACE_MODE_TRGMII:
case PHY_INTERFACE_MODE_USXGMII:
+ case PHY_INTERFACE_MODE_HSGMII:
case PHY_INTERFACE_MODE_SGMII:
case PHY_INTERFACE_MODE_SMII:
case PHY_INTERFACE_MODE_1000BASEX:
--- a/drivers/net/phy/phylink.c
+++ b/drivers/net/phy/phylink.c
@@ -410,6 +410,7 @@ void phylink_get_linkmodes(unsigned long
case PHY_INTERFACE_MODE_XGMII:
case PHY_INTERFACE_MODE_RXAUI:
+ case PHY_INTERFACE_MODE_HSGMII:
case PHY_INTERFACE_MODE_XAUI:
case PHY_INTERFACE_MODE_10GBASER:
case PHY_INTERFACE_MODE_10GKR:
@@ -665,6 +666,7 @@ static int phylink_parse_mode(struct phy
fallthrough;
case PHY_INTERFACE_MODE_USXGMII:
case PHY_INTERFACE_MODE_10GKR:
+ case PHY_INTERFACE_MODE_HSGMII:
case PHY_INTERFACE_MODE_10GBASER:
phylink_set(pl->supported, 10baseT_Half);
phylink_set(pl->supported, 10baseT_Full);
--- a/include/linux/phy.h
+++ b/include/linux/phy.h
@@ -141,6 +141,7 @@ typedef enum {
PHY_INTERFACE_MODE_XGMII,
PHY_INTERFACE_MODE_XLGMII,
PHY_INTERFACE_MODE_MOCA,
+ PHY_INTERFACE_MODE_HSGMII,
PHY_INTERFACE_MODE_QSGMII,
PHY_INTERFACE_MODE_TRGMII,
PHY_INTERFACE_MODE_100BASEX,
@@ -248,6 +249,8 @@ static inline const char *phy_modes(phy_
return "xlgmii";
case PHY_INTERFACE_MODE_MOCA:
return "moca";
+ case PHY_INTERFACE_MODE_HSGMII:
+ return "hsgmii";
case PHY_INTERFACE_MODE_QSGMII:
return "qsgmii";
case PHY_INTERFACE_MODE_TRGMII:

View File

@ -1,39 +0,0 @@
From 89f71ebb355c624320c2b0ace8ae9488ff53cbeb Mon Sep 17 00:00:00 2001
From: Birger Koblitz <mail@birger-koblitz.de>
Date: Tue, 5 Jan 2021 20:40:52 +0100
Subject: PHY: Add realtek PHY
This fixes the build problems for the REALTEK target by adding a proper
configuration option for the phy module.
Submitted-by: Birger Koblitz <mail@birger-koblitz.de>
---
drivers/net/phy/Kconfig | 6 ++++++
drivers/net/phy/Makefile | 1 +
2 files changed, 7 insertions(+)
--- a/drivers/net/phy/Kconfig
+++ b/drivers/net/phy/Kconfig
@@ -354,6 +354,12 @@ config REALTEK_PHY
help
Supports the Realtek 821x PHY.
+config REALTEK_SOC_PHY
+ tristate "Realtek SoC PHYs"
+ depends on RTL83XX
+ help
+ Supports the PHYs found in combination with Realtek Switch SoCs
+
config RENESAS_PHY
tristate "Renesas PHYs"
help
--- a/drivers/net/phy/Makefile
+++ b/drivers/net/phy/Makefile
@@ -89,6 +89,7 @@ obj-$(CONFIG_NXP_C45_TJA11XX_PHY) += nxp
obj-$(CONFIG_NXP_TJA11XX_PHY) += nxp-tja11xx.o
obj-$(CONFIG_QSEMI_PHY) += qsemi.o
obj-$(CONFIG_REALTEK_PHY) += realtek.o
+obj-$(CONFIG_REALTEK_SOC_PHY) += rtl83xx-phy.o
obj-$(CONFIG_RENESAS_PHY) += uPD60620.o
obj-$(CONFIG_ROCKCHIP_PHY) += rockchip.o
obj-$(CONFIG_SMSC_PHY) += smsc.o

View File

@ -1,32 +0,0 @@
From 2b88563ee5aafd9571d965b7f2093a0f58d98a31 Mon Sep 17 00:00:00 2001
From: John Crispin <john@phrozen.org>
Date: Thu, 26 Nov 2020 12:02:21 +0100
Subject: PHY: Increase max PHY adddress number
* rename the target to realtek
* add refactored DSA driver
* add latest gpio driver
* lots of arch cleanups
* new irq driver
* additional boards
Submitted-by: Bert Vermeulen <bert@biot.com>
Submitted-by: Birger Koblitz <mail@birger-koblitz.de>
Submitted-by: Sander Vanheule <sander@svanheule.net>
Submitted-by: Bjørn Mork <bjorn@mork.no>
Submitted-by: John Crispin <john@phrozen.org>
---
include/linux/phy.h | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
--- a/include/linux/phy.h
+++ b/include/linux/phy.h
@@ -287,7 +287,7 @@ static inline const char *phy_modes(phy_
#define PHY_INIT_TIMEOUT 100000
#define PHY_FORCE_TIMEOUT 10
-#define PHY_MAX_ADDR 32
+#define PHY_MAX_ADDR 64
/* Used when trying to connect to a specific phy (mii bus id:phy device id) */
#define PHY_ID_FMT "%s:%02x"

View File

@ -1,26 +0,0 @@
From a381ac0aa281fdb0b41a39d8a2bc08fd88f6db92 Mon Sep 17 00:00:00 2001
From: Antoine Tenart <antoine.tenart@bootlin.com>
Date: Tue, 25 Feb 2020 16:32:37 +0100
Subject: [PATCH 1/3] net: phy: sfp: re-probe modules on DEV_UP event
Signed-off-by: Antoine Tenart <antoine.tenart@bootlin.com>
---
drivers/net/phy/sfp.c | 7 +++++++
1 file changed, 7 insertions(+)
--- a/drivers/net/phy/sfp.c
+++ b/drivers/net/phy/sfp.c
@@ -2160,6 +2160,13 @@ static void sfp_sm_module(struct sfp *sf
return;
}
+ /* Re-probe the SFP modules when an interface is brought up, as the MAC
+ * do not report its link status (This means Phylink wouldn't be
+ * triggered if the PHY had a link before a MAC is brought up).
+ */
+ if (event == SFP_E_DEV_UP && sfp->sm_mod_state == SFP_MOD_PRESENT)
+ sfp_sm_mod_next(sfp, SFP_MOD_PROBE, T_SERIAL);
+
switch (sfp->sm_mod_state) {
default:
if (event == SFP_E_INSERT) {

View File

@ -1,148 +0,0 @@
From d585c55b9f70cf9e8c66820d7efe7130c683f19e Mon Sep 17 00:00:00 2001
From: Antoine Tenart <antoine.tenart@bootlin.com>
Date: Fri, 21 Feb 2020 11:51:27 +0100
Subject: [PATCH 2/3] net: phy: add an MDIO SMBus library
Signed-off-by: Antoine Tenart <antoine.tenart@bootlin.com>
---
drivers/net/mdio/Kconfig | 11 +++++++
drivers/net/mdio/Makefile | 1 +
drivers/net/mdio/mdio-smbus.c | 62 +++++++++++++++++++++++++++++++++++
drivers/net/phy/Kconfig | 1 +
include/linux/mdio/mdio-i2c.h | 16 +++++++++
5 files changed, 91 insertions(+)
create mode 100644 drivers/net/mdio/mdio-smbus.c
--- a/drivers/net/mdio/Kconfig
+++ b/drivers/net/mdio/Kconfig
@@ -54,6 +54,17 @@ config MDIO_SUN4I
interface units of the Allwinner SoC that have an EMAC (A10,
A12, A10s, etc.)
+config MDIO_SMBUS
+ tristate
+ depends on I2C_SMBUS
+ help
+ Support SMBus based PHYs. This provides a MDIO bus bridged
+ to SMBus to allow PHYs connected in SMBus mode to be accessed
+ using the existing infrastructure.
+
+ This is library mode.
+
+
config MDIO_XGENE
tristate "APM X-Gene SoC MDIO bus controller"
depends on ARCH_XGENE || COMPILE_TEST
--- a/drivers/net/mdio/Makefile
+++ b/drivers/net/mdio/Makefile
@@ -19,6 +19,7 @@ obj-$(CONFIG_MDIO_MOXART) += mdio-moxar
obj-$(CONFIG_MDIO_MSCC_MIIM) += mdio-mscc-miim.o
obj-$(CONFIG_MDIO_MVUSB) += mdio-mvusb.o
obj-$(CONFIG_MDIO_OCTEON) += mdio-octeon.o
+obj-$(CONFIG_MDIO_SMBUS) += mdio-smbus.o
obj-$(CONFIG_MDIO_SUN4I) += mdio-sun4i.o
obj-$(CONFIG_MDIO_THUNDER) += mdio-thunder.o
obj-$(CONFIG_MDIO_XGENE) += mdio-xgene.o
--- /dev/null
+++ b/drivers/net/mdio/mdio-smbus.c
@@ -0,0 +1,62 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * MDIO SMBus bridge
+ *
+ * Copyright (C) 2020 Antoine Tenart
+ *
+ * Network PHYs can appear on SMBus when they are part of SFP modules.
+ */
+#include <linux/i2c.h>
+#include <linux/phy.h>
+#include <linux/mdio/mdio-i2c.h>
+
+static int smbus_mii_read(struct mii_bus *mii, int phy_id, int reg)
+{
+ struct i2c_adapter *i2c = mii->priv;
+ union i2c_smbus_data data;
+ int ret;
+
+ ret = i2c_smbus_xfer(i2c, i2c_mii_phy_addr(phy_id), 0, I2C_SMBUS_READ,
+ reg, I2C_SMBUS_BYTE_DATA, &data);
+ if (ret < 0)
+ return 0xff;
+
+ return data.byte;
+}
+
+static int smbus_mii_write(struct mii_bus *mii, int phy_id, int reg, u16 val)
+{
+ struct i2c_adapter *i2c = mii->priv;
+ union i2c_smbus_data data;
+ int ret;
+
+ data.byte = val;
+
+ ret = i2c_smbus_xfer(i2c, i2c_mii_phy_addr(phy_id), 0, I2C_SMBUS_WRITE,
+ reg, I2C_SMBUS_BYTE_DATA, &data);
+ return ret < 0 ? ret : 0;
+}
+
+struct mii_bus *mdio_smbus_alloc(struct device *parent, struct i2c_adapter *i2c)
+{
+ struct mii_bus *mii;
+
+ if (!i2c_check_functionality(i2c, I2C_FUNC_SMBUS_BYTE_DATA))
+ return ERR_PTR(-EINVAL);
+
+ mii = mdiobus_alloc();
+ if (!mii)
+ return ERR_PTR(-ENOMEM);
+
+ snprintf(mii->id, MII_BUS_ID_SIZE, "smbus:%s", dev_name(parent));
+ mii->parent = parent;
+ mii->read = smbus_mii_read;
+ mii->write = smbus_mii_write;
+ mii->priv = i2c;
+
+ return mii;
+}
+
+MODULE_AUTHOR("Antoine Tenart");
+MODULE_DESCRIPTION("MDIO SMBus bridge library");
+MODULE_LICENSE("GPL");
--- a/drivers/net/phy/Kconfig
+++ b/drivers/net/phy/Kconfig
@@ -61,6 +61,7 @@ config SFP
depends on I2C && PHYLINK
depends on HWMON || HWMON=n
select MDIO_I2C
+ select MDIO_SMBUS
comment "Switch configuration API + drivers"
--- a/include/linux/mdio/mdio-i2c.h
+++ b/include/linux/mdio/mdio-i2c.h
@@ -12,5 +12,8 @@ struct i2c_adapter;
struct mii_bus;
struct mii_bus *mdio_i2c_alloc(struct device *parent, struct i2c_adapter *i2c);
+struct mii_bus *mdio_smbus_alloc(struct device *parent, struct i2c_adapter *i2c);
+bool i2c_mii_valid_phy_id(int phy_id);
+unsigned int i2c_mii_phy_addr(int phy_id);
#endif
--- a/drivers/net/mdio/mdio-i2c.c
+++ b/drivers/net/mdio/mdio-i2c.c
@@ -18,12 +18,12 @@
* specified to be present in SFP modules. These correspond with PHY
* addresses 16 and 17. Disallow access to these "phy" addresses.
*/
-static bool i2c_mii_valid_phy_id(int phy_id)
+bool i2c_mii_valid_phy_id(int phy_id)
{
return phy_id != 0x10 && phy_id != 0x11;
}
-static unsigned int i2c_mii_phy_addr(int phy_id)
+unsigned int i2c_mii_phy_addr(int phy_id)
{
return phy_id + 0x40;
}

View File

@ -1,99 +0,0 @@
From 3cb0bde365d913c484d20224367a54a0eac780a7 Mon Sep 17 00:00:00 2001
From: Antoine Tenart <antoine.tenart@bootlin.com>
Date: Fri, 21 Feb 2020 11:55:29 +0100
Subject: [PATCH 3/3] net: phy: sfp: add support for SMBus
Signed-off-by: Antoine Tenart <antoine.tenart@bootlin.com>
---
drivers/net/phy/sfp.c | 68 ++++++++++++++++++++++++++++++++++---------
1 file changed, 54 insertions(+), 14 deletions(-)
--- a/drivers/net/phy/sfp.c
+++ b/drivers/net/phy/sfp.c
@@ -556,32 +556,72 @@ static int sfp_i2c_write(struct sfp *sfp
return ret == ARRAY_SIZE(msgs) ? len : 0;
}
+static int sfp_smbus_read(struct sfp *sfp, bool a2, u8 dev_addr, void *buf,
+ size_t len)
+{
+ u8 bus_addr = a2 ? 0x51 : 0x50, *val = buf;
+
+ bus_addr -= 0x40;
+
+ while (len > 0) {
+ *val = sfp->i2c_mii->read(sfp->i2c_mii, bus_addr, dev_addr);
+
+ val++;
+ dev_addr++;
+ len--;
+ }
+
+ return val - (u8 *)buf;
+}
+
+static int sfp_smbus_write(struct sfp *sfp, bool a2, u8 dev_addr, void *buf,
+ size_t len)
+{
+ u8 bus_addr = a2 ? 0x51 : 0x50;
+ u16 val;
+
+ memcpy(&val, buf, len);
+
+ return sfp->i2c_mii->write(sfp->i2c_mii, bus_addr, dev_addr, val);
+}
+
static int sfp_i2c_configure(struct sfp *sfp, struct i2c_adapter *i2c)
{
- struct mii_bus *i2c_mii;
+ struct mii_bus *mii;
int ret;
- if (!i2c_check_functionality(i2c, I2C_FUNC_I2C))
- return -EINVAL;
-
sfp->i2c = i2c;
- sfp->read = sfp_i2c_read;
- sfp->write = sfp_i2c_write;
- i2c_mii = mdio_i2c_alloc(sfp->dev, i2c);
- if (IS_ERR(i2c_mii))
- return PTR_ERR(i2c_mii);
+ if (i2c_check_functionality(i2c, I2C_FUNC_I2C)) {
+ sfp->read = sfp_i2c_read;
+ sfp->write = sfp_i2c_write;
+
+ mii = mdio_i2c_alloc(sfp->dev, i2c);
+ if (IS_ERR(mii))
+ return PTR_ERR(mii);
+
+ mii->name = "SFP I2C Bus";
+ } else if (i2c_check_functionality(i2c, I2C_FUNC_SMBUS_BYTE_DATA)) {
+ sfp->read = sfp_smbus_read;
+ sfp->write = sfp_smbus_write;
+
+ mii = mdio_smbus_alloc(sfp->dev, i2c);
+ if (IS_ERR(mii))
+ return PTR_ERR(mii);
- i2c_mii->name = "SFP I2C Bus";
- i2c_mii->phy_mask = ~0;
+ mii->name = "SFP SMBus";
+ } else {
+ return -EINVAL;
+ }
- ret = mdiobus_register(i2c_mii);
+ mii->phy_mask = ~0;
+ ret = mdiobus_register(mii);
if (ret < 0) {
- mdiobus_free(i2c_mii);
+ mdiobus_free(mii);
return ret;
}
- sfp->i2c_mii = i2c_mii;
+ sfp->i2c_mii = mii;
return 0;
}

View File

@ -1,224 +0,0 @@
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

@ -1,244 +0,0 @@
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_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_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_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_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

@ -1,205 +0,0 @@
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

@ -1,241 +0,0 @@
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