mirror of
https://github.com/openwrt/openwrt.git
synced 2024-12-19 21:58:04 +00:00
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:
parent
f368e2d5ec
commit
3dd3c61c30
@ -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>;
|
||||
};
|
||||
|
||||
...
|
@ -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
|
@ -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_ */
|
@ -1,5 +0,0 @@
|
||||
#
|
||||
# Makefile for the rtl838x specific parts of the kernel
|
||||
#
|
||||
|
||||
obj-y := setup.o prom.o
|
@ -1,5 +0,0 @@
|
||||
#
|
||||
# Realtek RTL838x SoCs
|
||||
#
|
||||
cflags-$(CONFIG_RTL83XX) += -I$(srctree)/arch/mips/include/asm/mach-rtl838x/
|
||||
load-$(CONFIG_RTL83XX) += 0xffffffff80100000
|
@ -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();
|
||||
}
|
@ -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();
|
||||
}
|
@ -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
|
@ -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
|
@ -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
|
@ -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
|
@ -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);
|
@ -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)
|
@ -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);
|
@ -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");
|
@ -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");
|
@ -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
|
@ -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");
|
@ -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.
|
@ -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
|
File diff suppressed because it is too large
Load Diff
@ -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
@ -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);
|
||||
}
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -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 */
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -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;
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@ -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
@ -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)))
|
@ -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 */
|
@ -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");
|
@ -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)
|
||||
{
|
@ -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;
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
@ -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);
|
@ -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"
|
@ -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
|
@ -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,
|
@ -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
|
@ -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
|
@ -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
|
@ -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
|
@ -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>
|
@ -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
|
@ -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
|
@ -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);
|
@ -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;
|
@ -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,
|
@ -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/
|
@ -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);
|
||||
+ }
|
||||
}
|
||||
}
|
||||
|
@ -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/
|
@ -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;
|
@ -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 {
|
@ -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/
|
@ -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)
|
@ -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;
|
||||
}
|
@ -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:
|
@ -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
|
@ -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"
|
@ -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) {
|
@ -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;
|
||||
}
|
@ -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;
|
||||
}
|
@ -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
|
@ -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
|
@ -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
|
@ -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
|
Loading…
Reference in New Issue
Block a user