realtek: remove patches, files and config for 6.6
Remove all files etc. for 6.6 because 6.12 is default now. Signed-off-by: Jonas Jelonek <jelonek.jonas@gmail.com> Link: https://github.com/openwrt/openwrt/pull/19139 Signed-off-by: Robert Marko <robimarko@gmail.com>
This commit is contained in:
parent
1cd68e915d
commit
12f13b227c
62 changed files with 0 additions and 30341 deletions
|
@ -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_MACH_REALTEK_RTL) += -I$(srctree)/arch/mips/include/asm/mach-rtl838x/
|
||||
load-$(CONFIG_MACH_REALTEK_RTL) += 0xffffffff80100000
|
|
@ -1,226 +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/prom.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();
|
||||
|
||||
/* delay cpc & smp probing to allow devicetree access */
|
||||
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();
|
||||
}
|
||||
|
||||
static 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 0x9311:
|
||||
soc_info.name = "RTL9311";
|
||||
soc_info.family = RTL9310_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_arg2 is be the pointer to the environment. Some devices (e.g. HP JG924A) hand
|
||||
* over other than expected kernel boot arguments. Something like 0xfffdffff looks
|
||||
* suspicous. Do extra cleanup for fw_init_cmdline() to avoid a hang during boot.
|
||||
*/
|
||||
if (fw_arg2 >= CKSEG2)
|
||||
fw_arg2 = 0;
|
||||
|
||||
fw_init_cmdline();
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
|
||||
static 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 MACH_REALTEK_RTL
|
||||
|
||||
if COMMON_CLK_REALTEK
|
||||
|
||||
config COMMON_CLK_RTL83XX
|
||||
bool "Clock driver for Realtek RTL83XX"
|
||||
depends on MACH_REALTEK_RTL
|
||||
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;
|
||||
}
|
||||
|
||||
static 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;
|
||||
}
|
||||
|
||||
static 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;
|
||||
}
|
||||
|
||||
static 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);
|
||||
}
|
||||
|
||||
static 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,483 +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 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;
|
||||
}
|
||||
|
||||
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_platform_ioremap_resource(pdev, 0);
|
||||
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,
|
||||
.write = 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,
|
||||
.write = 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 MACH_REALTEK_RTL
|
||||
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,710 +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)
|
||||
|
||||
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, },
|
||||
};
|
||||
|
||||
static 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
|
||||
*/
|
||||
static 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);
|
||||
}
|
||||
|
||||
|
||||
|
||||
static 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);
|
||||
}
|
||||
|
||||
static 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 */
|
||||
static 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);
|
||||
}
|
||||
|
||||
static 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 */
|
||||
static 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));
|
||||
}
|
||||
|
||||
static 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;
|
||||
}
|
||||
|
||||
static 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);
|
||||
}
|
||||
|
||||
static 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);
|
||||
}
|
||||
|
||||
static 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);
|
||||
}
|
||||
|
||||
static 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,174 +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);
|
||||
|
||||
void rtl83xx_fast_age(struct dsa_switch *ds, int port);
|
||||
int rtl83xx_packet_cntr_alloc(struct rtl838x_switch_priv *priv);
|
||||
int rtl83xx_port_get_stp_state(struct rtl838x_switch_priv *priv, int port);
|
||||
int rtl83xx_port_is_under(const struct net_device * dev, struct rtl838x_switch_priv *priv);
|
||||
void rtl83xx_port_stp_state_set(struct dsa_switch *ds, int port, u8 state);
|
||||
int rtl83xx_setup_tc(struct net_device *dev, enum tc_setup_type type, void *type_data);
|
||||
|
||||
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);
|
||||
u32 rtl839x_get_egress_rate(struct rtl838x_switch_priv *priv, int port);
|
||||
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);
|
||||
int rtl839x_set_egress_rate(struct rtl838x_switch_priv *priv, int port, u32 rate);
|
||||
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);
|
||||
u32 rtl838x_get_egress_rate(struct rtl838x_switch_priv *priv, int port);
|
||||
u64 rtl838x_get_port_reg(int reg);
|
||||
int rtl838x_set_egress_rate(struct rtl838x_switch_priv *priv, int port, u32 rate);
|
||||
|
||||
/* 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);
|
||||
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);
|
||||
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);
|
||||
extern 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);
|
||||
extern 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);
|
||||
|
||||
/* phy functions that will need to be moved to the future mdio driver */
|
||||
|
||||
int rtl838x_read_mmd_phy(u32 port, u32 addr, u32 reg, u32 *val);
|
||||
int rtl838x_write_mmd_phy(u32 port, u32 addr, 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_read_mmd_phy(u32 port, u32 devnum, u32 regnum, u32 *val);
|
||||
int rtl930x_write_mmd_phy(u32 port, u32 devnum, u32 regnum, u32 val);
|
||||
|
||||
int rtl931x_read_mmd_phy(u32 port, u32 devnum, u32 regnum, u32 *val);
|
||||
int rtl931x_write_mmd_phy(u32 port, u32 devnum, u32 regnum, u32 val);
|
||||
|
||||
/*
|
||||
* TODO: The following functions are currently not in use. So compiler will complain if
|
||||
* they are static and not made available externally. To preserve them for future use
|
||||
* collect them in this section.
|
||||
*/
|
||||
|
||||
void rtl838x_egress_rate_queue_limit(struct rtl838x_switch_priv *priv, int port,
|
||||
int queue, u32 rate);
|
||||
|
||||
int rtl8390_sds_power(int mac, int val);
|
||||
void rtl839x_pie_rule_dump(struct pie_rule *pr);
|
||||
void rtl839x_set_egress_queue(int port, int queue);
|
||||
|
||||
void rtl9300_dump_debug(void);
|
||||
void rtl930x_pie_rule_dump_raw(u32 r[]);
|
||||
|
||||
void rtl931x_print_matrix(void);
|
||||
void rtl931x_set_receive_management_action(int port, rma_ctrl_t type, action_type_t action);
|
||||
void rtl931x_sw_init(struct rtl838x_switch_priv *priv);
|
||||
|
||||
#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%llx\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,455 +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 (0x0dcc)
|
||||
|
||||
#define RTL83XX_DMA_IF_INTR_STS_NOTIFY_MASK GENMASK(22, 20)
|
||||
#define RTL83XX_DMA_IF_INTR_STS_RX_DONE_MASK GENMASK(15, 8)
|
||||
#define RTL83XX_DMA_IF_INTR_STS_RX_RUN_OUT_MASK GENMASK(7, 0)
|
||||
|
||||
/* 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_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 phy_package_port_read_paged(struct phy_device *phydev, int port, int page, u32 regnum);
|
||||
int phy_package_port_write_paged(struct phy_device *phydev, int port, int page, u32 regnum, u16 val);
|
||||
int phy_package_read_paged(struct phy_device *phydev, int page, u32 regnum);
|
||||
int phy_package_write_paged(struct phy_device *phydev, int page, u32 regnum, u16 val);
|
||||
int phy_port_read_paged(struct phy_device *phydev, int port, int page, u32 regnum);
|
||||
int phy_port_write_paged(struct phy_device *phydev, int port, int page, u32 regnum, u16 val);
|
||||
|
||||
#endif /* _RTL838X_ETH_H */
|
File diff suppressed because it is too large
Load diff
|
@ -1,98 +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"
|
||||
|
||||
#define PHY_ID_RTL8214C 0x001cc942
|
||||
#define PHY_ID_RTL8218B_E 0x001cc980
|
||||
#define PHY_ID_RTL8214_OR_8218 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
|
||||
|
||||
/* These PHYs share the same id (0x001cc981) */
|
||||
#define PHY_IS_NOT_RTL821X 0
|
||||
#define PHY_IS_RTL8214FC 1
|
||||
#define PHY_IS_RTL8214FB 2
|
||||
#define PHY_IS_RTL8218B_E 3
|
||||
|
||||
/* 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)))
|
||||
|
||||
int rtl839x_read_sds_phy(int phy_addr, int phy_reg);
|
||||
int rtl839x_write_sds_phy(int phy_addr, int phy_reg, u16 v);
|
||||
|
||||
int rtl9300_serdes_setup(int port, int sds_num, phy_interface_t phy_mode);
|
||||
int rtl930x_read_sds_phy(int phy_addr, int page, int phy_reg);
|
||||
int rtl930x_write_sds_phy(int phy_addr, int page, int phy_reg, u16 v);
|
||||
|
||||
int rtl931x_read_sds_phy(int phy_addr, int page, int phy_reg);
|
||||
int rtl931x_write_sds_phy(int phy_addr, int page, int phy_reg, u16 v);
|
||||
int rtl931x_sds_cmu_band_get(int sds, phy_interface_t mode);
|
||||
void rtl931x_sds_init(u32 sds, phy_interface_t mode);
|
||||
|
||||
/*
|
||||
* TODO: The following functions are currently not in use. So compiler will complain if
|
||||
* they are static and not made available externally. Collect them in this section to
|
||||
* preserve for future use.
|
||||
*/
|
||||
|
||||
void rtl9300_do_rx_calibration_3(int sds_num, phy_interface_t phy_mode);
|
||||
int rtl9300_sds_clock_wait(int timeout);
|
||||
int rtl9300_sds_cmu_band_get(int sds);
|
||||
void rtl9300_sds_rxcal_dcvs_get(u32 sds_num, u32 dcvs_id, u32 dcvs_list[]);
|
||||
void rtl9300_sds_rxcal_dcvs_manual(u32 sds_num, u32 dcvs_id, bool manual, u32 dvcs_list[]);
|
||||
void rtl9300_sds_set(int sds_num, u32 mode);
|
||||
|
||||
int rtl931x_link_sts_get(u32 sds);
|
||||
void rtl931x_sds_fiber_disable(u32 sds);
|
||||
int rtl931x_sds_cmu_band_set(int sds, bool enable, u32 band, phy_interface_t mode);
|
|
@ -1,190 +0,0 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* Realtek thermal sensor driver
|
||||
*
|
||||
* Copyright (C) 2025 Bjørn Mork <bjorn@mork.no>>
|
||||
*/
|
||||
|
||||
#include <linux/bitfield.h>
|
||||
#include <linux/mfd/syscon.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/regmap.h>
|
||||
#include "thermal_hwmon.h"
|
||||
|
||||
#define RTL8380_THERMAL_METER_CTRL0 0x98
|
||||
#define RTL8380_THERMAL_METER_CTRL1 0x9c
|
||||
#define RTL8380_THERMAL_METER_CTRL2 0xa0
|
||||
#define RTL8380_THERMAL_METER_RESULT 0xa4
|
||||
#define RTL8380_TM_ENABLE BIT(0)
|
||||
#define RTL8380_TEMP_VALID BIT(8)
|
||||
#define RTL8380_TEMP_OUT_MASK GENMASK(6, 0)
|
||||
|
||||
#define RTL8390_THERMAL_METER0_CTRL0 0x274
|
||||
#define RTL8390_THERMAL_METER0_CTRL1 0x278
|
||||
#define RTL8390_THERMAL_METER0_CTRL2 0x27c
|
||||
#define RTL8390_THERMAL_METER0_RESULT 0x280
|
||||
#define RTL8390_THERMAL_METER1_CTRL0 0x284
|
||||
#define RTL8390_THERMAL_METER1_CTRL1 0x288
|
||||
#define RTL8390_THERMAL_METER1_CTRL2 0x28c
|
||||
#define RTL8390_THERMAL_METER1_RESULT 0x290
|
||||
#define RTL8390_TM_ENABLE BIT(0)
|
||||
#define RTL8390_TEMP_VALID BIT(8)
|
||||
#define RTL8390_TEMP_OUT_MASK GENMASK(6, 0)
|
||||
|
||||
#define RTL9300_THERMAL_METER_CTRL0 0x60
|
||||
#define RTL9300_THERMAL_METER_CTRL1 0x64
|
||||
#define RTL9300_THERMAL_METER_CTRL2 0x68
|
||||
#define RTL9300_THERMAL_METER_RESULT0 0x6c
|
||||
#define RTL9300_THERMAL_METER_RESULT1 0x70
|
||||
#define RTL9300_TM_ENABLE BIT(16)
|
||||
#define RTL9300_TEMP_VALID BIT(24)
|
||||
#define RTL9300_TEMP_OUT_MASK GENMASK(23, 16)
|
||||
#define RTL9300_SAMPLE_DLY_SHIFT (16)
|
||||
#define RTL9300_SAMPLE_DLY_MASK GENMASK(RTL9300_SAMPLE_DLY_SHIFT + 15, RTL9300_SAMPLE_DLY_SHIFT)
|
||||
#define RTL9300_COMPARE_DLY_SHIFT (0)
|
||||
#define RTL9300_COMPARE_DLY_MASK GENMASK(RTL9300_COMPARE_DLY_SHIFT + 15, RTL9300_COMPARE_DLY_SHIFT)
|
||||
|
||||
struct realtek_thermal_priv {
|
||||
struct regmap *regmap;
|
||||
bool enabled;
|
||||
};
|
||||
|
||||
static void rtl8380_thermal_init(struct realtek_thermal_priv *priv)
|
||||
{
|
||||
priv->enabled = !regmap_update_bits(priv->regmap, RTL8380_THERMAL_METER_CTRL0, RTL8380_TM_ENABLE, RTL8380_TM_ENABLE);
|
||||
}
|
||||
|
||||
static int rtl8380_get_temp(struct thermal_zone_device *tz, int *res)
|
||||
{
|
||||
struct realtek_thermal_priv *priv = thermal_zone_device_priv(tz);
|
||||
int offset = thermal_zone_get_offset(tz);
|
||||
int slope = thermal_zone_get_slope(tz);
|
||||
u32 val;
|
||||
int ret;
|
||||
|
||||
if (!priv->enabled)
|
||||
rtl8380_thermal_init(priv);
|
||||
|
||||
ret = regmap_read(priv->regmap, RTL8380_THERMAL_METER_RESULT, &val);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (!(val & RTL8380_TEMP_VALID))
|
||||
return -EAGAIN;
|
||||
|
||||
*res = FIELD_GET(RTL8380_TEMP_OUT_MASK, val) * slope + offset;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct thermal_zone_device_ops rtl8380_ops = {
|
||||
.get_temp = rtl8380_get_temp,
|
||||
};
|
||||
|
||||
static void rtl8390_thermal_init(struct realtek_thermal_priv *priv)
|
||||
{
|
||||
priv->enabled = !regmap_update_bits(priv->regmap, RTL8390_THERMAL_METER0_CTRL0, RTL8390_TM_ENABLE, RTL8390_TM_ENABLE);
|
||||
}
|
||||
|
||||
static int rtl8390_get_temp(struct thermal_zone_device *tz, int *res)
|
||||
{
|
||||
struct realtek_thermal_priv *priv = thermal_zone_device_priv(tz);
|
||||
int offset = thermal_zone_get_offset(tz);
|
||||
int slope = thermal_zone_get_slope(tz);
|
||||
u32 val;
|
||||
int ret;
|
||||
|
||||
if (!priv->enabled)
|
||||
rtl8390_thermal_init(priv);
|
||||
/* assume sensor0 is the CPU, both sensor0 & sensor1 report same values +/- 1 degree C */
|
||||
ret = regmap_read(priv->regmap, RTL8390_THERMAL_METER0_RESULT, &val);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (!(val & RTL8390_TEMP_VALID))
|
||||
return -EAGAIN;
|
||||
|
||||
*res = FIELD_GET(RTL8390_TEMP_OUT_MASK, val) * slope + offset;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct thermal_zone_device_ops rtl8390_ops = {
|
||||
.get_temp = rtl8390_get_temp,
|
||||
};
|
||||
|
||||
static void rtl9300_thermal_init(struct realtek_thermal_priv *priv)
|
||||
{
|
||||
/* increasing sample delay makes get_temp() succeed more often */
|
||||
regmap_update_bits(priv->regmap, RTL9300_THERMAL_METER_CTRL1, RTL9300_SAMPLE_DLY_MASK, 0x0800 << RTL9300_SAMPLE_DLY_SHIFT);
|
||||
priv->enabled = !regmap_update_bits(priv->regmap, RTL9300_THERMAL_METER_CTRL2, RTL9300_TM_ENABLE, RTL9300_TM_ENABLE);
|
||||
}
|
||||
|
||||
static int rtl9300_get_temp(struct thermal_zone_device *tz, int *res)
|
||||
{
|
||||
struct realtek_thermal_priv *priv = thermal_zone_device_priv(tz);
|
||||
int offset = thermal_zone_get_offset(tz);
|
||||
int slope = thermal_zone_get_slope(tz);
|
||||
u32 val;
|
||||
int ret;
|
||||
|
||||
if (!priv->enabled)
|
||||
rtl9300_thermal_init(priv);
|
||||
|
||||
ret = regmap_read(priv->regmap, RTL9300_THERMAL_METER_RESULT0, &val);
|
||||
if (ret)
|
||||
return ret;
|
||||
if (!(val & RTL9300_TEMP_VALID))
|
||||
return -EAGAIN;
|
||||
|
||||
*res = FIELD_GET(RTL9300_TEMP_OUT_MASK, val) * slope + offset;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct thermal_zone_device_ops rtl9300_ops = {
|
||||
.get_temp = rtl9300_get_temp,
|
||||
};
|
||||
|
||||
static int realtek_thermal_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct realtek_thermal_priv *priv;
|
||||
struct thermal_zone_device *tzdev;
|
||||
struct device *dev = &pdev->dev;
|
||||
struct regmap *regmap;
|
||||
|
||||
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
|
||||
if (!priv)
|
||||
return -ENOMEM;
|
||||
|
||||
regmap = syscon_node_to_regmap(dev->of_node->parent);
|
||||
if (IS_ERR(regmap))
|
||||
return PTR_ERR(regmap);
|
||||
|
||||
priv->regmap = regmap;
|
||||
tzdev = devm_thermal_of_zone_register(dev, 0, priv, device_get_match_data(dev));
|
||||
if (IS_ERR(tzdev))
|
||||
return PTR_ERR(tzdev);
|
||||
|
||||
return devm_thermal_add_hwmon_sysfs(dev, tzdev);
|
||||
}
|
||||
|
||||
static const struct of_device_id realtek_sensor_ids[] = {
|
||||
{ .compatible = "realtek,rtl8380-thermal", .data = &rtl8380_ops, },
|
||||
{ .compatible = "realtek,rtl8390-thermal", .data = &rtl8390_ops, },
|
||||
{ .compatible = "realtek,rtl9300-thermal", .data = &rtl9300_ops, },
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, realtek_sensor_ids);
|
||||
|
||||
static struct platform_driver realtek_thermal_driver = {
|
||||
.probe = realtek_thermal_probe,
|
||||
.driver = {
|
||||
.name = "realtek-thermal",
|
||||
.of_match_table = realtek_sensor_ids,
|
||||
},
|
||||
};
|
||||
|
||||
module_platform_driver(realtek_thermal_driver);
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_AUTHOR("Bjørn Mork <bjorn@mork.no>");
|
||||
MODULE_DESCRIPTION("Realtek temperature sensor");
|
|
@ -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,89 +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>
|
||||
---
|
||||
--- a/arch/mips/Kbuild.platforms
|
||||
+++ b/arch/mips/Kbuild.platforms
|
||||
@@ -22,6 +22,7 @@ platform-$(CONFIG_MACH_NINTENDO64) += n6
|
||||
platform-$(CONFIG_PIC32MZDA) += pic32/
|
||||
platform-$(CONFIG_RALINK) += ralink/
|
||||
platform-$(CONFIG_MIKROTIK_RB532) += rb532/
|
||||
+platform-$(CONFIG_MACH_REALTEK_RTL) += 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
|
||||
@@ -620,21 +620,23 @@ config RALINK
|
||||
|
||||
config MACH_REALTEK_RTL
|
||||
bool "Realtek RTL838x/RTL839x based machines"
|
||||
- select MIPS_GENERIC
|
||||
select DMA_NONCOHERENT
|
||||
select IRQ_MIPS_CPU
|
||||
- select CSRC_R4K
|
||||
- select CEVT_R4K
|
||||
select SYS_HAS_CPU_MIPS32_R1
|
||||
select SYS_HAS_CPU_MIPS32_R2
|
||||
select SYS_SUPPORTS_BIG_ENDIAN
|
||||
select SYS_SUPPORTS_32BIT_KERNEL
|
||||
select SYS_SUPPORTS_MIPS16
|
||||
- select SYS_SUPPORTS_MULTITHREADING
|
||||
- select SYS_SUPPORTS_VPE_LOADER
|
||||
select BOOT_RAW
|
||||
select PINCTRL
|
||||
select USE_OF
|
||||
+ select NO_EXCEPT_FILL
|
||||
+ select SYS_SUPPORTS_HIGHMEM
|
||||
+ select SYS_HAS_EARLY_PRINTK
|
||||
+ select SYS_HAS_EARLY_PRINTK_8250
|
||||
+ select USE_GENERIC_EARLY_PRINTK_8250
|
||||
+ select ARCH_HAS_RESET_CONTROLLER
|
||||
+ select RESET_CONTROLLER
|
||||
|
||||
config SGI_IP22
|
||||
bool "SGI IP22 (Indy/Indigo2)"
|
||||
@@ -970,6 +972,36 @@ config CAVIUM_OCTEON_SOC
|
||||
|
||||
endchoice
|
||||
|
||||
+config RTL838X
|
||||
+ bool "Realtek RTL838X based platforms"
|
||||
+ depends on MACH_REALTEK_RTL
|
||||
+ select CPU_SUPPORTS_CPUFREQ
|
||||
+ select MIPS_EXTERNAL_TIMER
|
||||
+
|
||||
+config RTL839X
|
||||
+ bool "Realtek RTL839X based platforms"
|
||||
+ depends on MACH_REALTEK_RTL
|
||||
+ select CPU_SUPPORTS_CPUFREQ
|
||||
+ select MIPS_EXTERNAL_TIMER
|
||||
+ select SYS_SUPPORTS_MULTITHREADING
|
||||
+
|
||||
+config RTL930X
|
||||
+ bool "Realtek RTL930X based platforms"
|
||||
+ depends on MACH_REALTEK_RTL
|
||||
+ 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,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
|
||||
@@ -134,6 +134,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
|
||||
@@ -59,6 +59,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
|
||||
@@ -181,6 +181,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,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
|
||||
@@ -1023,6 +1023,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 I2C_RZV2M
|
||||
tristate "Renesas RZ/V2M adapter"
|
||||
depends on ARCH_RENESAS || COMPILE_TEST
|
||||
--- a/drivers/i2c/busses/Makefile
|
||||
+++ b/drivers/i2c/busses/Makefile
|
||||
@@ -101,6 +101,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_RZV2M) += i2c-rzv2m.o
|
||||
obj-$(CONFIG_I2C_S3C2410) += i2c-s3c2410.o
|
||||
obj-$(CONFIG_I2C_SH7760) += i2c-sh7760.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,427 +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.
|
||||
|
||||
Up to kernel 5.15 this patch was divided into two parts
|
||||
|
||||
315-irqchip-irq-realtek-rtl-add-VPE-support.patch
|
||||
319-irqchip-irq-realtek-rtl-fix-VPE-affinity.patch
|
||||
|
||||
As both parts will only work in combination they have been merged into
|
||||
one patch.
|
||||
|
||||
Submitted-by: Birger Koblitz <git@birger-koblitz.de>
|
||||
Submitted-by: INAGAKI Hiroshi <musashino.open@gmail.com>
|
||||
Signed-off-by: Markus Stockhausen <markus.stockhausen@gmx.de>
|
||||
---
|
||||
drivers/irqchip/irq-realtek-rtl.c | 296 +++++++++++++++++++++++++-----
|
||||
1 file changed, 249 insertions(+), 47 deletions(-)
|
||||
|
||||
--- a/drivers/irqchip/irq-realtek-rtl.c
|
||||
+++ b/drivers/irqchip/irq-realtek-rtl.c
|
||||
@@ -22,22 +22,58 @@
|
||||
#define RTL_ICTL_IRR3 0x14
|
||||
|
||||
#define RTL_ICTL_NUM_INPUTS 32
|
||||
-
|
||||
-#define REG(x) (realtek_ictl_base + x)
|
||||
+#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 u32 realtek_ictl_unmask[NR_CPUS];
|
||||
+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}.
|
||||
+ * 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)
|
||||
|
||||
-static void write_irr(void __iomem *irr0, int idx, u32 value)
|
||||
+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);
|
||||
@@ -48,16 +84,33 @@ static void write_irr(void __iomem *irr0
|
||||
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);
|
||||
|
||||
- value = readl(REG(RTL_ICTL_GIMR));
|
||||
- value |= BIT(i->hwirq);
|
||||
- writel(value, REG(RTL_ICTL_GIMR));
|
||||
+ for_each_cpu(cpu, &realtek_ictl_cpu_configurable)
|
||||
+ enable_gimr(i->hwirq, cpu);
|
||||
|
||||
raw_spin_unlock_irqrestore(&irq_lock, flags);
|
||||
}
|
||||
@@ -65,110 +118,259 @@ 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);
|
||||
|
||||
- value = readl(REG(RTL_ICTL_GIMR));
|
||||
- value &= ~BIT(i->hwirq);
|
||||
- writel(value, REG(RTL_ICTL_GIMR));
|
||||
+ for_each_cpu(cpu, &realtek_ictl_cpu_configurable)
|
||||
+ disable_gimr(i->hwirq, 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);
|
||||
+ realtek_ictl_unmask[cpu] &= ~BIT(i->hwirq);
|
||||
+ disable_gimr(i->hwirq, cpu);
|
||||
+ }
|
||||
+
|
||||
+ 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);
|
||||
+
|
||||
+ 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);
|
||||
- write_irr(REG(RTL_ICTL_IRR0), hw, 1);
|
||||
+
|
||||
+ 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);
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
+/*
|
||||
+ * SoC interrupts are cascaded to MIPS CPU interrupts according to the
|
||||
+ * interrupt-map in the device tree. Each SoC interrupt gets 4 bits for
|
||||
+ * the CPU interrupt in an Interrupt Routing Register. Max 32 SoC interrupts
|
||||
+ * 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 setup_parent_interrupts(struct device_node *node, int *parents,
|
||||
+ unsigned int num_parents)
|
||||
+{
|
||||
+ struct realtek_ictl_output *outputs;
|
||||
+ struct realtek_ictl_output *output;
|
||||
+ struct irq_domain *domain;
|
||||
+ unsigned int p;
|
||||
+
|
||||
+ outputs = kcalloc(num_parents, sizeof(*outputs), GFP_KERNEL);
|
||||
+ if (!outputs)
|
||||
+ return -ENOMEM;
|
||||
+
|
||||
+ for (p = 0; p < num_parents; p++) {
|
||||
+ output = outputs + p;
|
||||
+
|
||||
+ domain = irq_domain_add_linear(node, RTL_ICTL_NUM_INPUTS, &irq_domain_ops, output);
|
||||
+ if (!domain)
|
||||
+ goto domain_err;
|
||||
+
|
||||
+ output->fwnode = of_node_to_fwnode(node);
|
||||
+ output->output_index = p;
|
||||
+ output->domain = domain;
|
||||
+
|
||||
+ 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)
|
||||
{
|
||||
+ int parent_irqs[RTL_ICTL_NUM_OUTPUTS];
|
||||
struct of_phandle_args oirq;
|
||||
- struct irq_domain *domain;
|
||||
+ unsigned int num_parents;
|
||||
unsigned int soc_irq;
|
||||
- int parent_irq;
|
||||
+ unsigned int p;
|
||||
+ int cpu;
|
||||
+
|
||||
+ cpumask_clear(&realtek_ictl_cpu_configurable);
|
||||
|
||||
- realtek_ictl_base = of_iomap(node, 0);
|
||||
- if (!realtek_ictl_base)
|
||||
+ 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 */
|
||||
+ 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);
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ if (cpumask_empty(&realtek_ictl_cpu_configurable))
|
||||
return -ENXIO;
|
||||
|
||||
- /* Disable all cascaded interrupts and clear routing */
|
||||
- writel(0, REG(RTL_ICTL_GIMR));
|
||||
- for (soc_irq = 0; soc_irq < RTL_ICTL_NUM_INPUTS; soc_irq++)
|
||||
- write_irr(REG(RTL_ICTL_IRR0), soc_irq, 0);
|
||||
+ num_parents = of_irq_count(node);
|
||||
+ if (num_parents > RTL_ICTL_NUM_OUTPUTS) {
|
||||
+ pr_err("too many parent interrupts\n");
|
||||
+ return -EINVAL;
|
||||
+ }
|
||||
|
||||
- if (WARN_ON(!of_irq_count(node))) {
|
||||
+ for (p = 0; p < num_parents; p++)
|
||||
+ parent_irqs[p] = of_irq_get(node, p);
|
||||
+
|
||||
+ 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");
|
||||
- oirq.args_count = 1;
|
||||
- oirq.args[0] = 2;
|
||||
-
|
||||
- parent_irq = irq_create_of_mapping(&oirq);
|
||||
+ 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);
|
||||
- } else {
|
||||
- parent_irq = of_irq_get(node, 0);
|
||||
}
|
||||
|
||||
- if (parent_irq < 0)
|
||||
- return parent_irq;
|
||||
- else if (!parent_irq)
|
||||
- return -ENODEV;
|
||||
-
|
||||
- domain = irq_domain_add_linear(node, RTL_ICTL_NUM_INPUTS, &irq_domain_ops, NULL);
|
||||
- if (!domain)
|
||||
- return -ENOMEM;
|
||||
-
|
||||
- irq_set_chained_handler_and_data(parent_irq, realtek_irq_dispatch, domain);
|
||||
+ /* 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 0;
|
||||
+ return setup_parent_interrupts(node, &parent_irqs[0], num_parents);
|
||||
}
|
||||
|
||||
IRQCHIP_DECLARE(realtek_rtl_intc, "realtek,rtl-intc", realtek_rtl_of_init);
|
|
@ -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
|
||||
@@ -484,6 +484,7 @@ source "drivers/clk/mvebu/Kconfig"
|
||||
source "drivers/clk/nuvoton/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
|
||||
@@ -112,6 +112,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,21 +0,0 @@
|
|||
--- a/drivers/thermal/Kconfig
|
||||
+++ b/drivers/thermal/Kconfig
|
||||
@@ -522,4 +522,11 @@ config LOONGSON2_THERMAL
|
||||
is higher than the high temperature threshold or lower than the low
|
||||
temperature threshold, the interrupt will occur.
|
||||
|
||||
+config REALTEK_THERMAL
|
||||
+ tristate "Realtek RTL838x and RTL930x thermal sensor support"
|
||||
+ depends on RTL838X || RTL839X || RTL930X || COMPILE_TEST
|
||||
+ depends on THERMAL_OF
|
||||
+ help
|
||||
+ Support thermal sensor in Realtek RTL838x, RTL839x and RTL930x SoCs
|
||||
+
|
||||
endif
|
||||
--- a/drivers/thermal/Makefile
|
||||
+++ b/drivers/thermal/Makefile
|
||||
@@ -64,3 +64,4 @@ obj-$(CONFIG_AMLOGIC_THERMAL) += aml
|
||||
obj-$(CONFIG_SPRD_THERMAL) += sprd_thermal.o
|
||||
obj-$(CONFIG_KHADAS_MCU_FAN_THERMAL) += khadas_mcu_fan.o
|
||||
obj-$(CONFIG_LOONGSON2_THERMAL) += loongson2_thermal.o
|
||||
+obj-$(CONFIG_REALTEK_THERMAL) += realtek-thermal.o
|
|
@ -1,132 +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: realtek dsa/phy: Increase max ports for RTL839X/RTL931X
|
||||
|
||||
Linux standard can only support up to 32 devices per mdio bus and up to
|
||||
12 ports per DSA switch. This is not enough for the large RTL839X and
|
||||
RTL931X devices. Increase the max values accordingly. Additionally take
|
||||
care about the functions that work on bit masks.
|
||||
|
||||
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>
|
||||
Signed-off-by: Markus Stockhausen <markus.stockhausen@gmx.de>
|
||||
---
|
||||
drivers/net/mdio/fwnode_mdio.c | 2 +-
|
||||
include/linux/phy.h | 6 +++---
|
||||
include/linux/platform_data/dsa.h | 2 +-
|
||||
include/net/dsa.h | 14 +++++++-------
|
||||
net/dsa/slave.c | 4 ++--
|
||||
5 files changed, 14 insertions(+), 14 deletions(-)
|
||||
|
||||
--- a/drivers/net/mdio/fwnode_mdio.c
|
||||
+++ b/drivers/net/mdio/fwnode_mdio.c
|
||||
@@ -87,7 +87,7 @@ int fwnode_mdiobus_phy_device_register(s
|
||||
}
|
||||
|
||||
if (fwnode_property_read_bool(child, "broken-turn-around"))
|
||||
- mdio->phy_ignore_ta_mask |= 1 << addr;
|
||||
+ mdio->phy_ignore_ta_mask |= BIT_ULL(addr);
|
||||
|
||||
fwnode_property_read_u32(child, "reset-assert-us",
|
||||
&phy->mdio.reset_assert_delay);
|
||||
--- a/include/linux/phy.h
|
||||
+++ b/include/linux/phy.h
|
||||
@@ -294,7 +294,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"
|
||||
@@ -414,10 +414,10 @@ struct mii_bus {
|
||||
struct mdio_device *mdio_map[PHY_MAX_ADDR];
|
||||
|
||||
/** @phy_mask: PHY addresses to be ignored when probing */
|
||||
- u32 phy_mask;
|
||||
+ u64 phy_mask;
|
||||
|
||||
/** @phy_ignore_ta_mask: PHY addresses to ignore the TA/read failure */
|
||||
- u32 phy_ignore_ta_mask;
|
||||
+ u64 phy_ignore_ta_mask;
|
||||
|
||||
/**
|
||||
* @irq: An array of interrupts, each PHY's interrupt at the index
|
||||
--- 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 {
|
||||
--- a/include/net/dsa.h
|
||||
+++ b/include/net/dsa.h
|
||||
@@ -465,7 +465,7 @@ struct dsa_switch {
|
||||
/*
|
||||
* Slave mii_bus and devices for the individual ports.
|
||||
*/
|
||||
- u32 phys_mii_mask;
|
||||
+ u64 phys_mii_mask;
|
||||
struct mii_bus *slave_mii_bus;
|
||||
|
||||
/* Ageing Time limits in msecs */
|
||||
@@ -597,24 +597,24 @@ static inline bool dsa_is_user_port(stru
|
||||
dsa_switch_for_each_port_continue_reverse((_dp), (_ds)) \
|
||||
if (dsa_port_is_cpu((_dp)))
|
||||
|
||||
-static inline u32 dsa_user_ports(struct dsa_switch *ds)
|
||||
+static inline u64 dsa_user_ports(struct dsa_switch *ds)
|
||||
{
|
||||
struct dsa_port *dp;
|
||||
- u32 mask = 0;
|
||||
+ u64 mask = 0;
|
||||
|
||||
dsa_switch_for_each_user_port(dp, ds)
|
||||
- mask |= BIT(dp->index);
|
||||
+ mask |= BIT_ULL(dp->index);
|
||||
|
||||
return mask;
|
||||
}
|
||||
|
||||
-static inline u32 dsa_cpu_ports(struct dsa_switch *ds)
|
||||
+static inline u64 dsa_cpu_ports(struct dsa_switch *ds)
|
||||
{
|
||||
struct dsa_port *cpu_dp;
|
||||
- u32 mask = 0;
|
||||
+ u64 mask = 0;
|
||||
|
||||
dsa_switch_for_each_cpu_port(cpu_dp, ds)
|
||||
- mask |= BIT(cpu_dp->index);
|
||||
+ mask |= BIT_ULL(cpu_dp->index);
|
||||
|
||||
return mask;
|
||||
}
|
||||
--- a/net/dsa/slave.c
|
||||
+++ b/net/dsa/slave.c
|
||||
@@ -320,7 +320,7 @@ static int dsa_slave_phy_read(struct mii
|
||||
{
|
||||
struct dsa_switch *ds = bus->priv;
|
||||
|
||||
- if (ds->phys_mii_mask & (1 << addr))
|
||||
+ if (ds->phys_mii_mask & BIT_ULL(addr))
|
||||
return ds->ops->phy_read(ds, addr, reg);
|
||||
|
||||
return 0xffff;
|
||||
@@ -330,7 +330,7 @@ static int dsa_slave_phy_write(struct mi
|
||||
{
|
||||
struct dsa_switch *ds = bus->priv;
|
||||
|
||||
- if (ds->phys_mii_mask & (1 << addr))
|
||||
+ if (ds->phys_mii_mask & BIT_ULL(addr))
|
||||
return ds->ops->phy_write(ds, addr, reg, val);
|
||||
|
||||
return 0;
|
|
@ -1,79 +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: realtek 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 HSGMII
|
||||
protocol.
|
||||
|
||||
Submitted-by: Birger Koblitz <git@birger-koblitz.de>
|
||||
---
|
||||
drivers/net/phy/phy-core.c | 1 +
|
||||
drivers/net/phy/phylink.c | 4 ++++
|
||||
include/linux/phy.h | 3 +++
|
||||
3 files changed, 8 insertions(+)
|
||||
|
||||
--- a/drivers/net/phy/phy-core.c
|
||||
+++ b/drivers/net/phy/phy-core.c
|
||||
@@ -126,6 +126,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
|
||||
@@ -124,6 +124,7 @@ do { \
|
||||
static const phy_interface_t phylink_sfp_interface_preference[] = {
|
||||
PHY_INTERFACE_MODE_25GBASER,
|
||||
PHY_INTERFACE_MODE_USXGMII,
|
||||
+ PHY_INTERFACE_MODE_HSGMII,
|
||||
PHY_INTERFACE_MODE_10GBASER,
|
||||
PHY_INTERFACE_MODE_5GBASER,
|
||||
PHY_INTERFACE_MODE_2500BASEX,
|
||||
@@ -238,6 +239,7 @@ static int phylink_interface_max_speed(p
|
||||
|
||||
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:
|
||||
@@ -547,6 +549,7 @@ unsigned long phylink_get_capabilities(p
|
||||
break;
|
||||
|
||||
case PHY_INTERFACE_MODE_XGMII:
|
||||
+ case PHY_INTERFACE_MODE_HSGMII:
|
||||
case PHY_INTERFACE_MODE_RXAUI:
|
||||
case PHY_INTERFACE_MODE_XAUI:
|
||||
case PHY_INTERFACE_MODE_10GBASER:
|
||||
@@ -957,6 +960,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
|
||||
@@ -148,6 +148,7 @@ typedef enum {
|
||||
PHY_INTERFACE_MODE_XGMII,
|
||||
PHY_INTERFACE_MODE_XLGMII,
|
||||
PHY_INTERFACE_MODE_MOCA,
|
||||
+ PHY_INTERFACE_MODE_HSGMII,
|
||||
PHY_INTERFACE_MODE_PSGMII,
|
||||
PHY_INTERFACE_MODE_QSGMII,
|
||||
PHY_INTERFACE_MODE_TRGMII,
|
||||
@@ -256,6 +257,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_PSGMII:
|
||||
return "psgmii";
|
||||
case PHY_INTERFACE_MODE_QSGMII:
|
|
@ -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: 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
|
||||
@@ -1178,6 +1178,8 @@ struct phy_driver {
|
||||
*/
|
||||
int (*led_polarity_set)(struct phy_device *dev, int index,
|
||||
unsigned long modes);
|
||||
+ 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,49 +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
|
||||
@@ -2805,8 +2805,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;
|
||||
}
|
||||
@@ -2823,8 +2826,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,428 +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
|
||||
@@ -20,6 +20,7 @@ obj-$(CONFIG_MDIO_MSCC_MIIM) += mdio-ms
|
||||
obj-$(CONFIG_MDIO_MVUSB) += mdio-mvusb.o
|
||||
obj-$(CONFIG_MDIO_OCTEON) += mdio-octeon.o
|
||||
obj-$(CONFIG_MDIO_REGMAP) += mdio-regmap.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,341 @@
|
||||
+// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
+/*
|
||||
+ * MDIO SMBus bridge
|
||||
+ *
|
||||
+ * Copyright (C) 2020 Antoine Tenart
|
||||
+ * Copyright (C) 2025 Bjørn Mork <bjorn@mork.no>
|
||||
+ *
|
||||
+ * 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>
|
||||
+#include <linux/sfp.h>
|
||||
+
|
||||
+static int smbus_mii_read_c45(struct mii_bus *mii, int phy_id, int devad, int reg)
|
||||
+{
|
||||
+ u16 bus_addr = i2c_mii_phy_addr(phy_id);
|
||||
+ struct i2c_adapter *i2c = mii->priv;
|
||||
+ union i2c_smbus_data data;
|
||||
+ size_t addrlen;
|
||||
+ u8 buf[5], *p;
|
||||
+ int i, ret;
|
||||
+
|
||||
+ if (!i2c_mii_valid_phy_id(phy_id))
|
||||
+ return 0xffff;
|
||||
+
|
||||
+ p = buf;
|
||||
+ if (devad >= 0) {
|
||||
+ *p++ = 0x20 | devad;
|
||||
+ *p++ = reg >> 8;
|
||||
+ }
|
||||
+ *p++ = reg;
|
||||
+ addrlen = p - buf;
|
||||
+
|
||||
+ i2c_lock_bus(i2c, I2C_LOCK_SEGMENT);
|
||||
+ if (addrlen > 1) {
|
||||
+ for (i = 1; i < addrlen; i++) {
|
||||
+ data.byte = buf[i];
|
||||
+ ret = __i2c_smbus_xfer(i2c, bus_addr, 0, I2C_SMBUS_WRITE, buf[0], I2C_SMBUS_BYTE_DATA, &data);
|
||||
+ if (ret < 0)
|
||||
+ goto unlock;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ for (i = addrlen; i < addrlen + 2; i++) {
|
||||
+ ret = __i2c_smbus_xfer(i2c, bus_addr, 0, I2C_SMBUS_READ, buf[0], I2C_SMBUS_BYTE_DATA, &data);
|
||||
+ if (ret < 0)
|
||||
+ goto unlock;
|
||||
+ buf[i] = data.byte;
|
||||
+ }
|
||||
+
|
||||
+unlock:
|
||||
+ i2c_unlock_bus(i2c, I2C_LOCK_SEGMENT);
|
||||
+ if (ret < 0)
|
||||
+ return 0xffff;
|
||||
+ return buf[addrlen] << 8 | buf[addrlen + 1];
|
||||
+}
|
||||
+
|
||||
+static int smbus_mii_write_c45(struct mii_bus *mii, int phy_id, int devad, int reg, u16 val)
|
||||
+{
|
||||
+ u16 bus_addr = i2c_mii_phy_addr(phy_id);
|
||||
+ struct i2c_adapter *i2c = mii->priv;
|
||||
+ union i2c_smbus_data data;
|
||||
+ size_t buflen;
|
||||
+ u8 buf[5], *p;
|
||||
+ int i, ret;
|
||||
+
|
||||
+ if (!i2c_mii_valid_phy_id(phy_id))
|
||||
+ return 0;
|
||||
+
|
||||
+ p = buf;
|
||||
+ if (devad >= 0) {
|
||||
+ *p++ = devad;
|
||||
+ *p++ = reg >> 8;
|
||||
+ }
|
||||
+ *p++ = reg;
|
||||
+ *p++ = val >> 8;
|
||||
+ *p++ = val;
|
||||
+ buflen = p - buf;
|
||||
+
|
||||
+ i2c_lock_bus(i2c, I2C_LOCK_SEGMENT);
|
||||
+ for (i = 1; i < buflen; i++) {
|
||||
+ data.byte = buf[i];
|
||||
+ ret = __i2c_smbus_xfer(i2c, bus_addr, 0, I2C_SMBUS_WRITE, buf[0], I2C_SMBUS_BYTE_DATA, &data);
|
||||
+ if (ret < 0)
|
||||
+ goto unlock;
|
||||
+ }
|
||||
+unlock:
|
||||
+ i2c_unlock_bus(i2c, I2C_LOCK_SEGMENT);
|
||||
+ return ret < 0 ? ret : 0;
|
||||
+}
|
||||
+
|
||||
+static int smbus_mii_read_c22(struct mii_bus *bus, int phy_id, int reg)
|
||||
+{
|
||||
+ return smbus_mii_read_c45(bus, phy_id, -1, reg);
|
||||
+}
|
||||
+
|
||||
+static int smbus_mii_write_c22(struct mii_bus *bus, int phy_id, int reg, u16 val)
|
||||
+{
|
||||
+ return smbus_mii_write_c45(bus, phy_id, -1, reg, val);
|
||||
+}
|
||||
+
|
||||
+/* From mdio-i2c.c:
|
||||
+ *
|
||||
+ * RollBall SFPs do not access internal PHY via I2C address 0x56, but
|
||||
+ * instead via address 0x51, when SFP page is set to 0x03 and password to
|
||||
+ * 0xffffffff.
|
||||
+ *
|
||||
+ * address size contents description
|
||||
+ * ------- ---- -------- -----------
|
||||
+ * 0x80 1 CMD 0x01/0x02/0x04 for write/read/done
|
||||
+ * 0x81 1 DEV Clause 45 device
|
||||
+ * 0x82 2 REG Clause 45 register
|
||||
+ * 0x84 2 VAL Register value
|
||||
+ */
|
||||
+#define ROLLBALL_PHY_I2C_ADDR 0x51
|
||||
+
|
||||
+#define ROLLBALL_PASSWORD (SFP_VSL + 3)
|
||||
+
|
||||
+#define ROLLBALL_CMD_ADDR 0x80
|
||||
+#define ROLLBALL_DATA_ADDR 0x81
|
||||
+
|
||||
+#define ROLLBALL_CMD_WRITE 0x01
|
||||
+#define ROLLBALL_CMD_READ 0x02
|
||||
+#define ROLLBALL_CMD_DONE 0x04
|
||||
+
|
||||
+#define SFP_PAGE_ROLLBALL_MDIO 3
|
||||
+
|
||||
+static int smbus_set_sfp_page_lock(struct i2c_adapter *i2c, int bus_addr, u8 page)
|
||||
+{
|
||||
+ union i2c_smbus_data data;
|
||||
+ u8 oldpage;
|
||||
+ int ret;
|
||||
+
|
||||
+ i2c_lock_bus(i2c, I2C_LOCK_SEGMENT);
|
||||
+
|
||||
+ /* read current page */
|
||||
+ ret = __i2c_smbus_xfer(i2c, bus_addr, 0, I2C_SMBUS_READ, SFP_PAGE, I2C_SMBUS_BYTE_DATA, &data);
|
||||
+ if (ret < 0)
|
||||
+ goto unlock;
|
||||
+
|
||||
+ oldpage = data.byte;
|
||||
+ data.byte = page;
|
||||
+ ret = __i2c_smbus_xfer(i2c, bus_addr, 0, I2C_SMBUS_WRITE, SFP_PAGE, I2C_SMBUS_BYTE_DATA, &data);
|
||||
+ if (ret == 0)
|
||||
+ return oldpage;
|
||||
+
|
||||
+unlock:
|
||||
+ i2c_unlock_bus(i2c, I2C_LOCK_SEGMENT);
|
||||
+
|
||||
+ return ret;
|
||||
+}
|
||||
+
|
||||
+static int __smbus_set_sfp_page_unlock(struct i2c_adapter *i2c, int bus_addr, u8 page)
|
||||
+{
|
||||
+ union i2c_smbus_data data;
|
||||
+ int ret;
|
||||
+
|
||||
+ data.byte = page;
|
||||
+ ret = __i2c_smbus_xfer(i2c, bus_addr, 0, I2C_SMBUS_WRITE, SFP_PAGE, I2C_SMBUS_BYTE_DATA, &data);
|
||||
+ i2c_unlock_bus(i2c, I2C_LOCK_SEGMENT);
|
||||
+
|
||||
+ return ret;
|
||||
+}
|
||||
+
|
||||
+/* Wait for the ROLLBALL_CMD_ADDR register to read ROLLBALL_CMD_DONE,
|
||||
+ * indicating that the previous command has completed.
|
||||
+ *
|
||||
+ * Quoting from the mdio-i2c.c implementation:
|
||||
+ *
|
||||
+ * By experiment it takes up to 70 ms to access a register for these
|
||||
+ * SFPs. Sleep 20ms between iterations and try 10 times.
|
||||
+ */
|
||||
+static int __smbus_rollball_mii_poll(struct i2c_adapter *i2c , int bus_addr)
|
||||
+{
|
||||
+ union i2c_smbus_data data;
|
||||
+ int i, ret;
|
||||
+
|
||||
+ i = 10;
|
||||
+ do {
|
||||
+ msleep(20);
|
||||
+
|
||||
+ ret = __i2c_smbus_xfer(i2c, bus_addr, 0, I2C_SMBUS_READ, ROLLBALL_CMD_ADDR, I2C_SMBUS_BYTE_DATA, &data);
|
||||
+ if (ret < 0)
|
||||
+ return ret;
|
||||
+
|
||||
+ if (data.byte == ROLLBALL_CMD_DONE)
|
||||
+ return 0;
|
||||
+ } while (i-- > 0);
|
||||
+ dev_dbg(&i2c->dev, "poll timed out\n");
|
||||
+ return -ETIMEDOUT;
|
||||
+}
|
||||
+
|
||||
+static int smbus_mii_read_rollball(struct mii_bus *bus, int phy_id, int devad, int reg)
|
||||
+{
|
||||
+ struct i2c_adapter *i2c = bus->priv;
|
||||
+ union i2c_smbus_data data;
|
||||
+ int i, bus_addr, old, ret;
|
||||
+ u8 buf[6];
|
||||
+
|
||||
+ bus_addr = i2c_mii_phy_addr(phy_id);
|
||||
+ if (bus_addr != ROLLBALL_PHY_I2C_ADDR)
|
||||
+ return 0xffff;
|
||||
+
|
||||
+ old = smbus_set_sfp_page_lock(i2c, bus_addr, SFP_PAGE_ROLLBALL_MDIO);
|
||||
+ if (old < 0)
|
||||
+ return 0xffff;
|
||||
+
|
||||
+ /* set address */
|
||||
+ buf[0] = ROLLBALL_CMD_READ;
|
||||
+ buf[1] = devad;
|
||||
+ buf[2] = reg >> 8;
|
||||
+ buf[3] = reg & 0xff;
|
||||
+
|
||||
+ /* send address */
|
||||
+ for (i = 0; i < 4; i++) {
|
||||
+ data.byte = buf[i];
|
||||
+ ret = __i2c_smbus_xfer(i2c, bus_addr, 0, I2C_SMBUS_WRITE, ROLLBALL_CMD_ADDR + i, I2C_SMBUS_BYTE_DATA, &data);
|
||||
+ if (ret < 0)
|
||||
+ goto unlock;
|
||||
+ }
|
||||
+
|
||||
+ /* wait for command to complete */
|
||||
+ ret = __smbus_rollball_mii_poll(i2c, bus_addr);
|
||||
+ if (ret)
|
||||
+ goto unlock;
|
||||
+
|
||||
+ /* read result */
|
||||
+ for (i = 4; i < 6; i++) {
|
||||
+ ret = __i2c_smbus_xfer(i2c, bus_addr, 0, I2C_SMBUS_READ, ROLLBALL_CMD_ADDR + i, I2C_SMBUS_BYTE_DATA, &data);
|
||||
+ if (ret < 0)
|
||||
+ goto unlock;
|
||||
+ buf[i] = data.byte;
|
||||
+ }
|
||||
+
|
||||
+unlock:
|
||||
+ __smbus_set_sfp_page_unlock(i2c, bus_addr, old);
|
||||
+ if (ret < 0)
|
||||
+ return 0xffff;
|
||||
+ return buf[4] << 8 | buf[5];
|
||||
+}
|
||||
+
|
||||
+static int smbus_mii_write_rollball(struct mii_bus *bus, int phy_id, int devad, int reg, u16 val)
|
||||
+{
|
||||
+ struct i2c_adapter *i2c = bus->priv;
|
||||
+ union i2c_smbus_data data;
|
||||
+ int i, bus_addr, old, ret;
|
||||
+ u8 buf[6];
|
||||
+
|
||||
+ bus_addr = i2c_mii_phy_addr(phy_id);
|
||||
+ if (bus_addr != ROLLBALL_PHY_I2C_ADDR)
|
||||
+ return 0;
|
||||
+
|
||||
+ old = smbus_set_sfp_page_lock(i2c, bus_addr, SFP_PAGE_ROLLBALL_MDIO);
|
||||
+ if (old < 0)
|
||||
+ return old;
|
||||
+
|
||||
+ /* set address */
|
||||
+ buf[0] = ROLLBALL_CMD_WRITE;
|
||||
+ buf[1] = devad;
|
||||
+ buf[2] = reg >> 8;
|
||||
+ buf[3] = reg & 0xff;
|
||||
+ buf[4] = val >> 8;
|
||||
+ buf[5] = val & 0xff;
|
||||
+
|
||||
+ /* send address and value */
|
||||
+ for (i = 0; i < 6; i++) {
|
||||
+ data.byte = buf[i];
|
||||
+ ret = __i2c_smbus_xfer(i2c, bus_addr, 0, I2C_SMBUS_WRITE, ROLLBALL_CMD_ADDR + i, I2C_SMBUS_BYTE_DATA, &data);
|
||||
+ if (ret < 0)
|
||||
+ goto unlock;
|
||||
+ }
|
||||
+
|
||||
+ /* wait for command to complete */
|
||||
+ ret = __smbus_rollball_mii_poll(i2c, bus_addr);
|
||||
+
|
||||
+unlock:
|
||||
+ __smbus_set_sfp_page_unlock(i2c, bus_addr, old);
|
||||
+ return ret;
|
||||
+}
|
||||
+
|
||||
+/* write "password" - four 0xff bytes - to the ROLLBALL_PASSWORD register */
|
||||
+static int smbus_mii_init_rollball(struct i2c_adapter *i2c)
|
||||
+{
|
||||
+ union i2c_smbus_data data;
|
||||
+ int i, ret;
|
||||
+
|
||||
+ data.byte = 0xff;
|
||||
+ for (i = 0; i < 4; i++) {
|
||||
+ ret = i2c_smbus_xfer(i2c, ROLLBALL_PHY_I2C_ADDR, 0, I2C_SMBUS_WRITE, ROLLBALL_PASSWORD + i, I2C_SMBUS_BYTE_DATA, &data);
|
||||
+ if (ret < 0)
|
||||
+ return ret;
|
||||
+ }
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+struct mii_bus *mdio_smbus_alloc(struct device *parent, struct i2c_adapter *i2c,
|
||||
+ enum mdio_i2c_proto protocol)
|
||||
+{
|
||||
+ struct mii_bus *mii;
|
||||
+ int ret;
|
||||
+
|
||||
+ 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->priv = i2c;
|
||||
+
|
||||
+ switch (protocol) {
|
||||
+ case MDIO_I2C_ROLLBALL:
|
||||
+ ret = smbus_mii_init_rollball(i2c);
|
||||
+ if (ret < 0) {
|
||||
+ dev_err(parent,
|
||||
+ "Cannot initialize RollBall MDIO protocol on SMBus: %d\n",
|
||||
+ ret);
|
||||
+ mdiobus_free(mii);
|
||||
+ return ERR_PTR(ret);
|
||||
+ }
|
||||
+
|
||||
+ mii->read_c45 = smbus_mii_read_rollball;
|
||||
+ mii->write_c45 = smbus_mii_write_rollball;
|
||||
+ break;
|
||||
+ default:
|
||||
+ mii->read = smbus_mii_read_c22;
|
||||
+ mii->write = smbus_mii_write_c22;
|
||||
+ mii->read_c45 = smbus_mii_read_c45;
|
||||
+ mii->write_c45 = smbus_mii_write_c45;
|
||||
+ break;
|
||||
+ }
|
||||
+
|
||||
+ 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
|
||||
@@ -65,6 +65,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
|
||||
@@ -20,5 +20,9 @@ enum mdio_i2c_proto {
|
||||
|
||||
struct mii_bus *mdio_i2c_alloc(struct device *parent, struct i2c_adapter *i2c,
|
||||
enum mdio_i2c_proto protocol);
|
||||
+struct mii_bus *mdio_smbus_alloc(struct device *parent, struct i2c_adapter *i2c,
|
||||
+ enum mdio_i2c_proto protocol);
|
||||
+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
|
||||
@@ -20,12 +20,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,126 +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 | 92 +++++++++++++++++++++++++++++++++++++++++--
|
||||
1 file changed, 88 insertions(+), 4 deletions(-)
|
||||
|
||||
--- a/drivers/net/phy/sfp.c
|
||||
+++ b/drivers/net/phy/sfp.c
|
||||
@@ -675,10 +675,64 @@ 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;
|
||||
+ union i2c_smbus_data data;
|
||||
+ int ret;
|
||||
+
|
||||
+ bus_addr -= 0x40;
|
||||
+
|
||||
+ while (len > 0) {
|
||||
+ ret = i2c_smbus_xfer(sfp->i2c, i2c_mii_phy_addr(bus_addr), 0,
|
||||
+ I2C_SMBUS_READ, dev_addr,
|
||||
+ I2C_SMBUS_BYTE_DATA, &data);
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+ *val++ = data.byte;
|
||||
+ 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, *val = buf;
|
||||
+ union i2c_smbus_data data;
|
||||
+ int ret;
|
||||
+
|
||||
+ bus_addr -= 0x40;
|
||||
+
|
||||
+ while (len > 0) {
|
||||
+ data.byte = *val++;
|
||||
+ ret = i2c_smbus_xfer(sfp->i2c, i2c_mii_phy_addr(bus_addr), 0,
|
||||
+ I2C_SMBUS_WRITE, dev_addr,
|
||||
+ I2C_SMBUS_BYTE_DATA, &data);
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+ dev_addr++;
|
||||
+ len--;
|
||||
+ }
|
||||
+
|
||||
+ return val - (u8 *)buf;
|
||||
+}
|
||||
+
|
||||
static int sfp_i2c_configure(struct sfp *sfp, struct i2c_adapter *i2c)
|
||||
{
|
||||
- if (!i2c_check_functionality(i2c, I2C_FUNC_I2C))
|
||||
- return -EINVAL;
|
||||
+ if (!i2c_check_functionality(i2c, I2C_FUNC_I2C)) {
|
||||
+ if (i2c_check_functionality(i2c, I2C_FUNC_SMBUS_BYTE_DATA)) {
|
||||
+ sfp->i2c = i2c;
|
||||
+ sfp->read = sfp_smbus_read;
|
||||
+ sfp->write = sfp_smbus_write;
|
||||
+
|
||||
+ return 0;
|
||||
+ } else
|
||||
+ return -EINVAL;
|
||||
+ }
|
||||
|
||||
sfp->i2c = i2c;
|
||||
sfp->read = sfp_i2c_read;
|
||||
@@ -710,6 +764,29 @@ static int sfp_i2c_mdiobus_create(struct
|
||||
return 0;
|
||||
}
|
||||
|
||||
+static int sfp_sm_mdiobus_create(struct sfp *sfp)
|
||||
+{
|
||||
+ struct mii_bus *sm_mii;
|
||||
+ int ret;
|
||||
+
|
||||
+ sm_mii = mdio_smbus_alloc(sfp->dev, sfp->i2c, sfp->mdio_protocol);
|
||||
+ if (IS_ERR(sm_mii))
|
||||
+ return PTR_ERR(sm_mii);
|
||||
+
|
||||
+ sm_mii->name = "SFP SMBus";
|
||||
+ sm_mii->phy_mask = ~0;
|
||||
+
|
||||
+ ret = mdiobus_register(sm_mii);
|
||||
+ if (ret < 0) {
|
||||
+ mdiobus_free(sm_mii);
|
||||
+ return ret;
|
||||
+ }
|
||||
+
|
||||
+ sfp->i2c_mii = sm_mii;
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
static void sfp_i2c_mdiobus_destroy(struct sfp *sfp)
|
||||
{
|
||||
mdiobus_unregister(sfp->i2c_mii);
|
||||
@@ -1884,9 +1961,15 @@ static void sfp_sm_fault(struct sfp *sfp
|
||||
|
||||
static int sfp_sm_add_mdio_bus(struct sfp *sfp)
|
||||
{
|
||||
- if (sfp->mdio_protocol != MDIO_I2C_NONE)
|
||||
+ if (sfp->mdio_protocol == MDIO_I2C_NONE)
|
||||
+ return 0;
|
||||
+
|
||||
+ if (i2c_check_functionality(sfp->i2c, I2C_FUNC_I2C))
|
||||
return sfp_i2c_mdiobus_create(sfp);
|
||||
|
||||
+ if (i2c_check_functionality(sfp->i2c, I2C_FUNC_SMBUS_BYTE_DATA))
|
||||
+ return sfp_sm_mdiobus_create(sfp);
|
||||
+
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -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
|
||||
@@ -170,6 +170,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 MACH_REALTEK_RTL
|
||||
+ 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
|
||||
@@ -81,6 +81,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,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
|
||||
@@ -89,6 +89,8 @@ source "drivers/net/dsa/xrs700x/Kconfig"
|
||||
|
||||
source "drivers/net/dsa/realtek/Kconfig"
|
||||
|
||||
+source "drivers/net/dsa/rtl83xx/Kconfig"
|
||||
+
|
||||
config NET_DSA_RZN1_A5PSW
|
||||
tristate "Renesas RZ/N1 A5PSW Ethernet switch support"
|
||||
depends on OF && ARCH_RZN1
|
||||
--- a/drivers/net/dsa/Makefile
|
||||
+++ b/drivers/net/dsa/Makefile
|
||||
@@ -24,5 +24,6 @@ obj-y += mv88e6xxx/
|
||||
obj-y += ocelot/
|
||||
obj-y += qca/
|
||||
obj-y += realtek/
|
||||
+obj-y += rtl83xx/
|
||||
obj-y += sja1105/
|
||||
obj-y += xrs700x/
|
|
@ -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
|
||||
@@ -409,6 +409,12 @@ source "drivers/net/phy/realtek/Kconfig"
|
||||
|
||||
source "drivers/net/phy/rtl8261n/Kconfig"
|
||||
|
||||
+config REALTEK_SOC_PHY
|
||||
+ tristate "Realtek SoC PHYs"
|
||||
+ depends on MACH_REALTEK_RTL
|
||||
+ 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
|
||||
@@ -101,6 +101,7 @@ obj-y += qcom/
|
||||
obj-$(CONFIG_QSEMI_PHY) += qsemi.o
|
||||
obj-$(CONFIG_REALTEK_PHY) += realtek/
|
||||
obj-y += rtl8261n/
|
||||
+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,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
|
||||
@@ -19,7 +19,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;
|
||||
|
||||
@@ -35,12 +40,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,227 +0,0 @@
|
|||
From ffb7da9aa25765b2115e7ff3ee4f6dafa60f5421 Mon Sep 17 00:00:00 2001
|
||||
From: Sander Vanheule <sander@svanheule.net>
|
||||
Date: Fri, 27 Dec 2024 14:55:31 +0100
|
||||
Subject: [PATCH] net: mdio: Add Realtek Otto auxiliary controller
|
||||
|
||||
SoCs in Realtek's Otto platform such as the RTL8380, RTL8391, and
|
||||
RTL9302 have a simple auxiliary MDIO controller that is commonly used to
|
||||
manage RTL8231 GPIO expanders on switch devices.
|
||||
|
||||
Add a new MDIO controller driver supporting the RTL838x (maple), RTL839x
|
||||
(cypress), and RTL930x (longan) SoCs.
|
||||
|
||||
Signed-off-by: Sander Vanheule <sander@svanheule.net>
|
||||
---
|
||||
drivers/net/mdio/Kconfig | 10 ++
|
||||
drivers/net/mdio/Makefile | 1 +
|
||||
drivers/net/mdio/mdio-realtek-otto-aux.c | 175 +++++++++++++++++++++++
|
||||
3 files changed, 186 insertions(+)
|
||||
create mode 100644 drivers/net/mdio/mdio-realtek-otto-aux.c
|
||||
|
||||
--- a/drivers/net/mdio/Kconfig
|
||||
+++ b/drivers/net/mdio/Kconfig
|
||||
@@ -207,6 +207,16 @@ config MDIO_REGMAP
|
||||
regmap. Users willing to use this driver must explicitly select
|
||||
REGMAP.
|
||||
|
||||
+config MDIO_REALTEK_OTTO_AUX
|
||||
+ tristate "Realtek Otto auxiliary MDIO interface support"
|
||||
+ default MACH_REALTEK_RTL
|
||||
+ depends on MACH_REALTEK_RTL
|
||||
+ depends on MFD_SYSCON
|
||||
+ select MDIO_DEVRES
|
||||
+ help
|
||||
+ This driver supports the auxilairy MDIO bus on RTL838x SoCs. This bus
|
||||
+ is typically used to attach RTL8231 GPIO extenders.
|
||||
+
|
||||
config MDIO_THUNDER
|
||||
tristate "ThunderX SOCs MDIO buses"
|
||||
depends on 64BIT
|
||||
--- a/drivers/net/mdio/Makefile
|
||||
+++ b/drivers/net/mdio/Makefile
|
||||
@@ -20,6 +20,7 @@ obj-$(CONFIG_MDIO_MSCC_MIIM) += mdio-ms
|
||||
obj-$(CONFIG_MDIO_MVUSB) += mdio-mvusb.o
|
||||
obj-$(CONFIG_MDIO_OCTEON) += mdio-octeon.o
|
||||
obj-$(CONFIG_MDIO_REGMAP) += mdio-regmap.o
|
||||
+obj-$(CONFIG_MDIO_REALTEK_OTTO_AUX) += mdio-realtek-otto-aux.o
|
||||
obj-$(CONFIG_MDIO_SMBUS) += mdio-smbus.o
|
||||
obj-$(CONFIG_MDIO_SUN4I) += mdio-sun4i.o
|
||||
obj-$(CONFIG_MDIO_THUNDER) += mdio-thunder.o
|
||||
--- /dev/null
|
||||
+++ b/drivers/net/mdio/mdio-realtek-otto-aux.c
|
||||
@@ -0,0 +1,175 @@
|
||||
+// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
+
|
||||
+#include <linux/mfd/core.h>
|
||||
+#include <linux/mfd/syscon.h>
|
||||
+#include <linux/module.h>
|
||||
+#include <linux/of.h>
|
||||
+#include <linux/of_mdio.h>
|
||||
+#include <linux/of_platform.h>
|
||||
+#include <linux/phy.h>
|
||||
+#include <linux/platform_device.h>
|
||||
+#include <linux/regmap.h>
|
||||
+
|
||||
+#define RTL8380_EXT_GPIO_INDIRECT_ACCESS 0xA09C
|
||||
+#define RTL8390_EXT_GPIO_INDIRECT_ACCESS 0x0224
|
||||
+#define RTL9300_EXT_GPIO_INDIRECT_ACCESS 0xC620
|
||||
+
|
||||
+#define RTL83XX_AUX_MDIO_DATA_OFFSET 16
|
||||
+#define RTL83XX_AUX_MDIO_RCMD_FAIL 0
|
||||
+
|
||||
+#define RTL93XX_AUX_MDIO_DATA_OFFSET 12
|
||||
+#define RTL93XX_AUX_MDIO_RCMD_FAIL BIT(28)
|
||||
+
|
||||
+#define REALTEK_AUX_MDIO_REG GENMASK(11, 7)
|
||||
+#define REALTEK_AUX_MDIO_PHY_ADDR GENMASK(6, 2)
|
||||
+#define REALTEK_AUX_MDIO_WRITE BIT(1)
|
||||
+#define REALTEK_AUX_MDIO_READ 0
|
||||
+#define REALTEK_AUX_MDIO_EXEC BIT(0)
|
||||
+
|
||||
+struct realtek_aux_mdio_info {
|
||||
+ unsigned int cmd_reg;
|
||||
+ unsigned int data_offset;
|
||||
+ unsigned int rcmd_fail_mask;
|
||||
+ unsigned int timeout_us;
|
||||
+};
|
||||
+
|
||||
+static const struct realtek_aux_mdio_info info_rtl838x = {
|
||||
+ .cmd_reg = RTL8380_EXT_GPIO_INDIRECT_ACCESS,
|
||||
+ .data_offset = RTL83XX_AUX_MDIO_DATA_OFFSET,
|
||||
+ .rcmd_fail_mask = RTL83XX_AUX_MDIO_RCMD_FAIL,
|
||||
+ .timeout_us = 1700,
|
||||
+};
|
||||
+
|
||||
+static const struct realtek_aux_mdio_info info_rtl839x = {
|
||||
+ .cmd_reg = RTL8390_EXT_GPIO_INDIRECT_ACCESS,
|
||||
+ .data_offset = RTL83XX_AUX_MDIO_DATA_OFFSET,
|
||||
+ .rcmd_fail_mask = RTL83XX_AUX_MDIO_RCMD_FAIL,
|
||||
+ .timeout_us = 4120,
|
||||
+};
|
||||
+
|
||||
+static const struct realtek_aux_mdio_info info_rtl930x = {
|
||||
+ .cmd_reg = RTL9300_EXT_GPIO_INDIRECT_ACCESS,
|
||||
+ .data_offset = RTL93XX_AUX_MDIO_DATA_OFFSET,
|
||||
+ .rcmd_fail_mask = RTL93XX_AUX_MDIO_RCMD_FAIL,
|
||||
+ .timeout_us = 19000,
|
||||
+};
|
||||
+
|
||||
+struct realtek_aux_mdio_ctrl {
|
||||
+ struct device *dev;
|
||||
+ struct regmap *map;
|
||||
+ const struct realtek_aux_mdio_info *info;
|
||||
+};
|
||||
+
|
||||
+#define mii_bus_to_ctrl(bus) ((struct realtek_aux_mdio_ctrl *) bus->priv)
|
||||
+
|
||||
+static int realtek_aux_mdio_cmd(struct realtek_aux_mdio_ctrl *ctrl, int addr, int regnum,
|
||||
+ u32 rw_bit, u16 *data)
|
||||
+{
|
||||
+ unsigned int cmd;
|
||||
+ int err;
|
||||
+
|
||||
+ cmd = rw_bit | REALTEK_AUX_MDIO_EXEC;
|
||||
+ cmd |= FIELD_PREP(REALTEK_AUX_MDIO_PHY_ADDR, addr);
|
||||
+ cmd |= FIELD_PREP(REALTEK_AUX_MDIO_REG, regnum);
|
||||
+
|
||||
+ if (rw_bit == REALTEK_AUX_MDIO_WRITE)
|
||||
+ cmd |= *data << ctrl->info->data_offset;
|
||||
+
|
||||
+ err = regmap_write(ctrl->map, ctrl->info->cmd_reg, cmd);
|
||||
+ if (err)
|
||||
+ return err;
|
||||
+
|
||||
+ err = regmap_read_poll_timeout_atomic(ctrl->map, ctrl->info->cmd_reg, cmd,
|
||||
+ !(cmd & REALTEK_AUX_MDIO_EXEC), 3, ctrl->info->timeout_us);
|
||||
+ if (err)
|
||||
+ return err;
|
||||
+
|
||||
+ if (rw_bit == REALTEK_AUX_MDIO_READ) {
|
||||
+ if (cmd & ctrl->info->rcmd_fail_mask)
|
||||
+ return -EIO;
|
||||
+
|
||||
+ *data = (cmd >> ctrl->info->data_offset) & GENMASK(15, 0);
|
||||
+ }
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static int realtek_aux_mdio_read(struct mii_bus *bus, int addr, int regnum)
|
||||
+{
|
||||
+ struct realtek_aux_mdio_ctrl *ctrl = mii_bus_to_ctrl(bus);
|
||||
+ u16 data;
|
||||
+ int err;
|
||||
+
|
||||
+ err = realtek_aux_mdio_cmd(ctrl, addr, regnum, REALTEK_AUX_MDIO_READ, &data);
|
||||
+
|
||||
+ if (err)
|
||||
+ return err;
|
||||
+ else
|
||||
+ return data;
|
||||
+}
|
||||
+
|
||||
+static int realtek_aux_mdio_write(struct mii_bus *bus, int addr, int regnum, u16 val)
|
||||
+{
|
||||
+ struct realtek_aux_mdio_ctrl *ctrl = mii_bus_to_ctrl(bus);
|
||||
+
|
||||
+ return realtek_aux_mdio_cmd(ctrl, addr, regnum, REALTEK_AUX_MDIO_WRITE, &val);
|
||||
+}
|
||||
+
|
||||
+static int realtek_aux_mdio_probe(struct platform_device *pdev)
|
||||
+{
|
||||
+ struct device_node *np = pdev->dev.of_node;
|
||||
+ struct realtek_aux_mdio_ctrl *ctrl;
|
||||
+ struct mii_bus *bus;
|
||||
+
|
||||
+ bus = devm_mdiobus_alloc_size(&pdev->dev, sizeof(*ctrl));
|
||||
+ if (!bus)
|
||||
+ return -ENOMEM;
|
||||
+
|
||||
+ ctrl = bus->priv;
|
||||
+ ctrl->dev = &pdev->dev;
|
||||
+ ctrl->info = (const struct realtek_aux_mdio_info *) device_get_match_data(ctrl->dev);
|
||||
+ ctrl->map = syscon_node_to_regmap(np->parent);
|
||||
+ if (IS_ERR(ctrl->map))
|
||||
+ return PTR_ERR(ctrl->map);
|
||||
+
|
||||
+ bus->name = "Realtek auxiliary MDIO bus";
|
||||
+ snprintf(bus->id, MII_BUS_ID_SIZE, "realtek-aux-mdio") ;
|
||||
+ bus->parent = ctrl->dev;
|
||||
+ bus->read = realtek_aux_mdio_read;
|
||||
+ bus->write = realtek_aux_mdio_write;
|
||||
+ /* Don't have interrupts */
|
||||
+ for (unsigned int i = 0; i < PHY_MAX_ADDR; i++)
|
||||
+ bus->irq[i] = PHY_POLL;
|
||||
+
|
||||
+ return devm_of_mdiobus_register(ctrl->dev, bus, np);
|
||||
+}
|
||||
+
|
||||
+static const struct of_device_id realtek_aux_mdio_of_match[] = {
|
||||
+ {
|
||||
+ .compatible = "realtek,rtl8380-aux-mdio",
|
||||
+ .data = &info_rtl838x,
|
||||
+ },
|
||||
+ {
|
||||
+ .compatible = "realtek,rtl8390-aux-mdio",
|
||||
+ .data = &info_rtl839x,
|
||||
+ },
|
||||
+ {
|
||||
+ .compatible = "realtek,rtl9300-aux-mdio",
|
||||
+ .data = &info_rtl930x,
|
||||
+ },
|
||||
+ { /* sentinel */ }
|
||||
+};
|
||||
+MODULE_DEVICE_TABLE(of, realtek_aux_mdio_of_match);
|
||||
+
|
||||
+static struct platform_driver realtek_aux_mdio_driver = {
|
||||
+ .driver = {
|
||||
+ .name = "realtek-otto-aux-mdio",
|
||||
+ .of_match_table = realtek_aux_mdio_of_match
|
||||
+ },
|
||||
+ .probe = realtek_aux_mdio_probe,
|
||||
+};
|
||||
+module_platform_driver(realtek_aux_mdio_driver);
|
||||
+
|
||||
+MODULE_AUTHOR("Sander Vanheule <sander@svanheule.net>");
|
||||
+MODULE_DESCRIPTION("Realtek otto auxiliary MDIO bus");
|
||||
+MODULE_LICENSE("GPL v2");
|
|
@ -1,56 +0,0 @@
|
|||
From b3f79468c90d8770f007d628a1e32b2d5d44a5c2 Mon Sep 17 00:00:00 2001
|
||||
From: Sander Vanheule <sander@svanheule.net>
|
||||
Date: Sat, 15 May 2021 11:57:32 +0200
|
||||
Subject: [PATCH] gpio: regmap: Bypass cache for shadowed outputs
|
||||
|
||||
Some chips have the read-only input and write-only output data registers
|
||||
aliased to the same offset, but do not perform direction multiplexing on
|
||||
writes. Upon writing the register, this then always updates the output
|
||||
value, even when the pin is configured as input. As a result it is not
|
||||
safe to perform read-modify-writes on output pins, when other pins are
|
||||
still configured as input.
|
||||
|
||||
For example, on a bit-banged I2C bus, where the lines are switched
|
||||
between out-low and in (with external pull-up)
|
||||
|
||||
OUT(L) IN OUT(H)
|
||||
SCK ....../''''''|''''''
|
||||
|
||||
SDA '''''''''\..........
|
||||
^ ^- SCK switches to direction to OUT, but now has a high
|
||||
| value, breaking the clock.
|
||||
|
|
||||
\- Perform RMW to update SDA. This reads the current input
|
||||
value for SCK, updates the SDA value and writes back a 1
|
||||
for SCK as well.
|
||||
|
||||
If a register is used for both the data input and data output (and is
|
||||
not marked as volatile) the driver should ensure the cache is not
|
||||
updated on register reads. This ensures proper functioning of writing
|
||||
the output register with regmap_update_bits(), which will then use and
|
||||
update the cache only on register writes.
|
||||
|
||||
Signed-off-by: Sander Vanheule <sander@svanheule.net>
|
||||
---
|
||||
drivers/gpio/gpio-regmap.c | 10 +++++++++-
|
||||
1 file changed, 9 insertions(+), 1 deletion(-)
|
||||
|
||||
--- a/drivers/gpio/gpio-regmap.c
|
||||
+++ b/drivers/gpio/gpio-regmap.c
|
||||
@@ -74,7 +74,15 @@ static int gpio_regmap_get(struct gpio_c
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
- ret = regmap_read(gpio->regmap, reg, &val);
|
||||
+ /*
|
||||
+ * Ensure we don't spoil the register cache with pin input values and
|
||||
+ * perform a bypassed read. This way the cache (if any) is only used and
|
||||
+ * updated on register writes.
|
||||
+ */
|
||||
+ if (gpio->reg_dat_base == gpio->reg_set_base)
|
||||
+ ret = regmap_read_bypassed(gpio->regmap, reg, &val);
|
||||
+ else
|
||||
+ ret = regmap_read(gpio->regmap, reg, &val);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
|
@ -1,330 +0,0 @@
|
|||
From 4e3455e058d40eb2a7326016494e3c81dc506c33 Mon Sep 17 00:00:00 2001
|
||||
From: Sander Vanheule <sander@svanheule.net>
|
||||
Date: Mon, 10 May 2021 18:33:01 +0200
|
||||
Subject: [PATCH] mfd: Add RTL8231 core device
|
||||
|
||||
The RTL8231 is implemented as an MDIO device, and provides a regmap
|
||||
interface for register access by the core and child devices.
|
||||
|
||||
The chip can also be a device on an SMI bus, an I2C-like bus by Realtek.
|
||||
Since kernel support for SMI is limited, and no real-world SMI
|
||||
implementations have been encountered for this device, this is currently
|
||||
unimplemented. The use of the regmap interface should make any future
|
||||
support relatively straightforward.
|
||||
|
||||
After reset, all pins are muxed to GPIO inputs before the pin drivers
|
||||
are enabled. This is done to prevent accidental system resets, when a
|
||||
pin is connected to the parent SoC's reset line.
|
||||
|
||||
To provide different read and write semantics for the GPIO data
|
||||
registers, a secondary virtual register range is used to enable separate
|
||||
caching properties of pin input and output values.
|
||||
|
||||
Signed-off-by: Sander Vanheule <sander@svanheule.net>
|
||||
---
|
||||
drivers/mfd/Kconfig | 9 ++
|
||||
drivers/mfd/Makefile | 1 +
|
||||
drivers/mfd/rtl8231.c | 193 ++++++++++++++++++++++++++++++++++++
|
||||
include/linux/mfd/rtl8231.h | 71 +++++++++++++
|
||||
4 files changed, 274 insertions(+)
|
||||
create mode 100644 drivers/mfd/rtl8231.c
|
||||
create mode 100644 include/linux/mfd/rtl8231.h
|
||||
|
||||
--- a/drivers/mfd/Kconfig
|
||||
+++ b/drivers/mfd/Kconfig
|
||||
@@ -1171,6 +1171,15 @@ config MFD_RDC321X
|
||||
southbridge which provides access to GPIOs and Watchdog using the
|
||||
southbridge PCI device configuration space.
|
||||
|
||||
+config MFD_RTL8231
|
||||
+ tristate "Realtek RTL8231 GPIO and LED expander"
|
||||
+ select MFD_CORE
|
||||
+ select REGMAP_MDIO
|
||||
+ help
|
||||
+ Support for the Realtek RTL8231 GPIO and LED expander.
|
||||
+ Provides up to 37 GPIOs, 88 LEDs, and one PWM output.
|
||||
+ When built as a module, this module will be named rtl8231.
|
||||
+
|
||||
config MFD_RT4831
|
||||
tristate "Richtek RT4831 four channel WLED and Display Bias Voltage"
|
||||
depends on I2C
|
||||
--- a/drivers/mfd/Makefile
|
||||
+++ b/drivers/mfd/Makefile
|
||||
@@ -240,6 +240,7 @@ obj-$(CONFIG_MFD_HI6421_PMIC) += hi6421-
|
||||
obj-$(CONFIG_MFD_HI6421_SPMI) += hi6421-spmi-pmic.o
|
||||
obj-$(CONFIG_MFD_HI655X_PMIC) += hi655x-pmic.o
|
||||
obj-$(CONFIG_MFD_DLN2) += dln2.o
|
||||
+obj-$(CONFIG_MFD_RTL8231) += rtl8231.o
|
||||
obj-$(CONFIG_MFD_RT4831) += rt4831.o
|
||||
obj-$(CONFIG_MFD_RT5033) += rt5033.o
|
||||
obj-$(CONFIG_MFD_RT5120) += rt5120.o
|
||||
--- /dev/null
|
||||
+++ b/drivers/mfd/rtl8231.c
|
||||
@@ -0,0 +1,193 @@
|
||||
+// SPDX-License-Identifier: GPL-2.0-only
|
||||
+
|
||||
+#include <linux/bits.h>
|
||||
+#include <linux/bitfield.h>
|
||||
+#include <linux/delay.h>
|
||||
+#include <linux/gpio/consumer.h>
|
||||
+#include <linux/mfd/core.h>
|
||||
+#include <linux/mdio.h>
|
||||
+#include <linux/module.h>
|
||||
+#include <linux/platform_device.h>
|
||||
+#include <linux/property.h>
|
||||
+#include <linux/regmap.h>
|
||||
+
|
||||
+#include <linux/mfd/rtl8231.h>
|
||||
+
|
||||
+static bool rtl8231_volatile_reg(struct device *dev, unsigned int reg)
|
||||
+{
|
||||
+ switch (reg) {
|
||||
+ /*
|
||||
+ * Registers with self-clearing bits, strapping pin values.
|
||||
+ * Don't mark the data registers as volatile, since we need
|
||||
+ * caching for the output values.
|
||||
+ */
|
||||
+ case RTL8231_REG_FUNC0:
|
||||
+ case RTL8231_REG_FUNC1:
|
||||
+ case RTL8231_REG_PIN_HI_CFG:
|
||||
+ case RTL8231_REG_LED_END:
|
||||
+ return true;
|
||||
+ default:
|
||||
+ return false;
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+static const struct reg_field RTL8231_FIELD_LED_START = REG_FIELD(RTL8231_REG_FUNC0, 1, 1);
|
||||
+
|
||||
+static const struct mfd_cell rtl8231_cells[] = {
|
||||
+ {
|
||||
+ .name = "rtl8231-pinctrl",
|
||||
+ },
|
||||
+ {
|
||||
+ .name = "rtl8231-leds",
|
||||
+ .of_compatible = "realtek,rtl8231-leds",
|
||||
+ },
|
||||
+};
|
||||
+
|
||||
+static int rtl8231_soft_reset(struct regmap *map)
|
||||
+{
|
||||
+ const unsigned int all_pins_mask = GENMASK(RTL8231_BITS_VAL - 1, 0);
|
||||
+ unsigned int val;
|
||||
+ int err;
|
||||
+
|
||||
+ /* SOFT_RESET bit self-clears when done */
|
||||
+ regmap_write_bits(map, RTL8231_REG_PIN_HI_CFG,
|
||||
+ RTL8231_PIN_HI_CFG_SOFT_RESET, RTL8231_PIN_HI_CFG_SOFT_RESET);
|
||||
+ err = regmap_read_poll_timeout(map, RTL8231_REG_PIN_HI_CFG, val,
|
||||
+ !(val & RTL8231_PIN_HI_CFG_SOFT_RESET), 50, 1000);
|
||||
+ if (err)
|
||||
+ return err;
|
||||
+
|
||||
+ regcache_mark_dirty(map);
|
||||
+
|
||||
+ /*
|
||||
+ * Chip reset results in a pin configuration that is a mix of LED and GPIO outputs.
|
||||
+ * Select GPI functionality for all pins before enabling pin outputs.
|
||||
+ */
|
||||
+ regmap_write(map, RTL8231_REG_PIN_MODE0, all_pins_mask);
|
||||
+ regmap_write(map, RTL8231_REG_GPIO_DIR0, all_pins_mask);
|
||||
+ regmap_write(map, RTL8231_REG_PIN_MODE1, all_pins_mask);
|
||||
+ regmap_write(map, RTL8231_REG_GPIO_DIR1, all_pins_mask);
|
||||
+ regmap_write(map, RTL8231_REG_PIN_HI_CFG,
|
||||
+ RTL8231_PIN_HI_CFG_MODE_MASK | RTL8231_PIN_HI_CFG_DIR_MASK);
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static int rtl8231_init(struct device *dev, struct regmap *map)
|
||||
+{
|
||||
+ struct regmap_field *led_start;
|
||||
+ unsigned int started;
|
||||
+ unsigned int val;
|
||||
+ int err;
|
||||
+
|
||||
+ err = regmap_read(map, RTL8231_REG_FUNC1, &val);
|
||||
+ if (err) {
|
||||
+ dev_err(dev, "failed to read READY_CODE\n");
|
||||
+ return err;
|
||||
+ }
|
||||
+
|
||||
+ val = FIELD_GET(RTL8231_FUNC1_READY_CODE_MASK, val);
|
||||
+ if (val != RTL8231_FUNC1_READY_CODE_VALUE) {
|
||||
+ dev_err(dev, "RTL8231 not present or ready 0x%x != 0x%x\n",
|
||||
+ val, RTL8231_FUNC1_READY_CODE_VALUE);
|
||||
+ return -ENODEV;
|
||||
+ }
|
||||
+
|
||||
+ led_start = dev_get_drvdata(dev);
|
||||
+ err = regmap_field_read(led_start, &started);
|
||||
+ if (err)
|
||||
+ return err;
|
||||
+
|
||||
+ if (!started) {
|
||||
+ err = rtl8231_soft_reset(map);
|
||||
+ if (err)
|
||||
+ return err;
|
||||
+ /* LED_START enables power to output pins, and starts the LED engine */
|
||||
+ err = regmap_field_force_write(led_start, 1);
|
||||
+ }
|
||||
+
|
||||
+ return err;
|
||||
+}
|
||||
+
|
||||
+static const struct regmap_config rtl8231_mdio_regmap_config = {
|
||||
+ .val_bits = RTL8231_BITS_VAL,
|
||||
+ .reg_bits = RTL8231_BITS_REG,
|
||||
+ .volatile_reg = rtl8231_volatile_reg,
|
||||
+ .max_register = RTL8231_REG_COUNT - 1,
|
||||
+ .use_single_read = true,
|
||||
+ .use_single_write = true,
|
||||
+ .reg_format_endian = REGMAP_ENDIAN_BIG,
|
||||
+ .val_format_endian = REGMAP_ENDIAN_BIG,
|
||||
+ /* Cannot use REGCACHE_FLAT because it's not smart enough about cache invalidation */
|
||||
+ .cache_type = REGCACHE_RBTREE,
|
||||
+};
|
||||
+
|
||||
+static int rtl8231_mdio_probe(struct mdio_device *mdiodev)
|
||||
+{
|
||||
+ struct device *dev = &mdiodev->dev;
|
||||
+ struct regmap_field *led_start;
|
||||
+ struct regmap *map;
|
||||
+ int err;
|
||||
+
|
||||
+ map = devm_regmap_init_mdio(mdiodev, &rtl8231_mdio_regmap_config);
|
||||
+ if (IS_ERR(map)) {
|
||||
+ dev_err(dev, "failed to init regmap\n");
|
||||
+ return PTR_ERR(map);
|
||||
+ }
|
||||
+
|
||||
+ led_start = devm_regmap_field_alloc(dev, map, RTL8231_FIELD_LED_START);
|
||||
+ if (IS_ERR(led_start))
|
||||
+ return PTR_ERR(led_start);
|
||||
+
|
||||
+ dev_set_drvdata(dev, led_start);
|
||||
+
|
||||
+ mdiodev->reset_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_LOW);
|
||||
+ if (IS_ERR(mdiodev->reset_gpio))
|
||||
+ return PTR_ERR(mdiodev->reset_gpio);
|
||||
+
|
||||
+ device_property_read_u32(dev, "reset-assert-delay", &mdiodev->reset_assert_delay);
|
||||
+ device_property_read_u32(dev, "reset-deassert-delay", &mdiodev->reset_deassert_delay);
|
||||
+
|
||||
+ err = rtl8231_init(dev, map);
|
||||
+ if (err)
|
||||
+ return err;
|
||||
+
|
||||
+ return devm_mfd_add_devices(dev, PLATFORM_DEVID_AUTO, rtl8231_cells,
|
||||
+ ARRAY_SIZE(rtl8231_cells), NULL, 0, NULL);
|
||||
+}
|
||||
+
|
||||
+__maybe_unused static int rtl8231_suspend(struct device *dev)
|
||||
+{
|
||||
+ struct regmap_field *led_start = dev_get_drvdata(dev);
|
||||
+
|
||||
+ return regmap_field_force_write(led_start, 0);
|
||||
+}
|
||||
+
|
||||
+__maybe_unused static int rtl8231_resume(struct device *dev)
|
||||
+{
|
||||
+ struct regmap_field *led_start = dev_get_drvdata(dev);
|
||||
+
|
||||
+ return regmap_field_force_write(led_start, 1);
|
||||
+}
|
||||
+
|
||||
+static SIMPLE_DEV_PM_OPS(rtl8231_pm_ops, rtl8231_suspend, rtl8231_resume);
|
||||
+
|
||||
+static const struct of_device_id rtl8231_of_match[] = {
|
||||
+ { .compatible = "realtek,rtl8231" },
|
||||
+ {}
|
||||
+};
|
||||
+MODULE_DEVICE_TABLE(of, rtl8231_of_match);
|
||||
+
|
||||
+static struct mdio_driver rtl8231_mdio_driver = {
|
||||
+ .mdiodrv.driver = {
|
||||
+ .name = "rtl8231-expander",
|
||||
+ .of_match_table = rtl8231_of_match,
|
||||
+ .pm = pm_ptr(&rtl8231_pm_ops),
|
||||
+ },
|
||||
+ .probe = rtl8231_mdio_probe,
|
||||
+};
|
||||
+mdio_module_driver(rtl8231_mdio_driver);
|
||||
+
|
||||
+MODULE_AUTHOR("Sander Vanheule <sander@svanheule.net>");
|
||||
+MODULE_DESCRIPTION("Realtek RTL8231 GPIO and LED expander");
|
||||
+MODULE_LICENSE("GPL");
|
||||
--- /dev/null
|
||||
+++ b/include/linux/mfd/rtl8231.h
|
||||
@@ -0,0 +1,71 @@
|
||||
+/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
+/*
|
||||
+ * Register definitions the RTL8231 GPIO and LED expander chip
|
||||
+ */
|
||||
+
|
||||
+#ifndef __LINUX_MFD_RTL8231_H
|
||||
+#define __LINUX_MFD_RTL8231_H
|
||||
+
|
||||
+#include <linux/bits.h>
|
||||
+
|
||||
+/*
|
||||
+ * Registers addresses are 5 bit, values are 16 bit
|
||||
+ * Also define a duplicated range of virtual addresses, to enable
|
||||
+ * different read/write behaviour on the GPIO data registers
|
||||
+ */
|
||||
+#define RTL8231_BITS_VAL 16
|
||||
+#define RTL8231_BITS_REG 5
|
||||
+
|
||||
+/* Chip control */
|
||||
+#define RTL8231_REG_FUNC0 0x00
|
||||
+#define RTL8231_FUNC0_SCAN_MODE BIT(0)
|
||||
+#define RTL8231_FUNC0_SCAN_SINGLE 0
|
||||
+#define RTL8231_FUNC0_SCAN_BICOLOR BIT(0)
|
||||
+
|
||||
+#define RTL8231_REG_FUNC1 0x01
|
||||
+#define RTL8231_FUNC1_READY_CODE_VALUE 0x37
|
||||
+#define RTL8231_FUNC1_READY_CODE_MASK GENMASK(9, 4)
|
||||
+#define RTL8231_FUNC1_DEBOUNCE_MASK GENMASK(15, 10)
|
||||
+
|
||||
+/* Pin control */
|
||||
+#define RTL8231_REG_PIN_MODE0 0x02
|
||||
+#define RTL8231_REG_PIN_MODE1 0x03
|
||||
+
|
||||
+#define RTL8231_PIN_MODE_LED 0
|
||||
+#define RTL8231_PIN_MODE_GPIO 1
|
||||
+
|
||||
+/* Pin high config: pin and GPIO control for pins 32-26 */
|
||||
+#define RTL8231_REG_PIN_HI_CFG 0x04
|
||||
+#define RTL8231_PIN_HI_CFG_MODE_MASK GENMASK(4, 0)
|
||||
+#define RTL8231_PIN_HI_CFG_DIR_MASK GENMASK(9, 5)
|
||||
+#define RTL8231_PIN_HI_CFG_INV_MASK GENMASK(14, 10)
|
||||
+#define RTL8231_PIN_HI_CFG_SOFT_RESET BIT(15)
|
||||
+
|
||||
+/* GPIO control registers */
|
||||
+#define RTL8231_REG_GPIO_DIR0 0x05
|
||||
+#define RTL8231_REG_GPIO_DIR1 0x06
|
||||
+#define RTL8231_REG_GPIO_INVERT0 0x07
|
||||
+#define RTL8231_REG_GPIO_INVERT1 0x08
|
||||
+
|
||||
+#define RTL8231_GPIO_DIR_IN 1
|
||||
+#define RTL8231_GPIO_DIR_OUT 0
|
||||
+
|
||||
+/*
|
||||
+ * GPIO data registers
|
||||
+ * Only the output data can be written to these registers, and only the input
|
||||
+ * data can be read.
|
||||
+ */
|
||||
+#define RTL8231_REG_GPIO_DATA0 0x1c
|
||||
+#define RTL8231_REG_GPIO_DATA1 0x1d
|
||||
+#define RTL8231_REG_GPIO_DATA2 0x1e
|
||||
+#define RTL8231_PIN_HI_DATA_MASK GENMASK(4, 0)
|
||||
+
|
||||
+/* LED control base registers */
|
||||
+#define RTL8231_REG_LED0_BASE 0x09
|
||||
+#define RTL8231_REG_LED1_BASE 0x10
|
||||
+#define RTL8231_REG_LED2_BASE 0x17
|
||||
+#define RTL8231_REG_LED_END 0x1b
|
||||
+
|
||||
+#define RTL8231_REG_COUNT 0x1f
|
||||
+
|
||||
+#endif /* __LINUX_MFD_RTL8231_H */
|
|
@ -1,581 +0,0 @@
|
|||
From 098324288a63a6dcc44e96cc381aef3d5c48d89e Mon Sep 17 00:00:00 2001
|
||||
From: Sander Vanheule <sander@svanheule.net>
|
||||
Date: Mon, 10 May 2021 22:15:31 +0200
|
||||
Subject: [PATCH] pinctrl: Add RTL8231 pin control and GPIO support
|
||||
|
||||
This driver implements the GPIO and pin muxing features provided by the
|
||||
RTL8231. The device should be instantiated as an MFD child, where the
|
||||
parent device has already configured the regmap used for register
|
||||
access.
|
||||
|
||||
Debouncing is only available for the six highest GPIOs, and must be
|
||||
emulated when other pins are used for (button) inputs. Although
|
||||
described in the bindings, drive strength selection is currently not
|
||||
implemented.
|
||||
|
||||
Signed-off-by: Sander Vanheule <sander@svanheule.net>
|
||||
---
|
||||
drivers/pinctrl/Kconfig | 11 +
|
||||
drivers/pinctrl/Makefile | 1 +
|
||||
drivers/pinctrl/pinctrl-rtl8231.c | 521 ++++++++++++++++++++++++++++++
|
||||
3 files changed, 533 insertions(+)
|
||||
create mode 100644 drivers/pinctrl/pinctrl-rtl8231.c
|
||||
|
||||
--- a/drivers/pinctrl/Kconfig
|
||||
+++ b/drivers/pinctrl/Kconfig
|
||||
@@ -417,6 +417,17 @@ config PINCTRL_ROCKCHIP
|
||||
help
|
||||
This support pinctrl and GPIO driver for Rockchip SoCs.
|
||||
|
||||
+config PINCTRL_RTL8231
|
||||
+ tristate "Realtek RTL8231 GPIO expander's pin controller"
|
||||
+ depends on MFD_RTL8231
|
||||
+ default MFD_RTL8231
|
||||
+ select GPIO_REGMAP
|
||||
+ select GENERIC_PINCONF
|
||||
+ select GENERIC_PINMUX_FUNCTIONS
|
||||
+ help
|
||||
+ Support for RTL8231 expander's GPIOs and pin controller.
|
||||
+ When built as a module, the module will be called pinctrl-rtl8231.
|
||||
+
|
||||
config PINCTRL_SINGLE
|
||||
tristate "One-register-per-pin type device tree based pinctrl driver"
|
||||
depends on OF
|
||||
--- a/drivers/pinctrl/Makefile
|
||||
+++ b/drivers/pinctrl/Makefile
|
||||
@@ -43,6 +43,7 @@ obj-$(CONFIG_PINCTRL_PIC32) += pinctrl-p
|
||||
obj-$(CONFIG_PINCTRL_PISTACHIO) += pinctrl-pistachio.o
|
||||
obj-$(CONFIG_PINCTRL_RK805) += pinctrl-rk805.o
|
||||
obj-$(CONFIG_PINCTRL_ROCKCHIP) += pinctrl-rockchip.o
|
||||
+obj-$(CONFIG_PINCTRL_RTL8231) += pinctrl-rtl8231.o
|
||||
obj-$(CONFIG_PINCTRL_SINGLE) += pinctrl-single.o
|
||||
obj-$(CONFIG_PINCTRL_ST) += pinctrl-st.o
|
||||
obj-$(CONFIG_PINCTRL_STMFX) += pinctrl-stmfx.o
|
||||
--- /dev/null
|
||||
+++ b/drivers/pinctrl/pinctrl-rtl8231.c
|
||||
@@ -0,0 +1,525 @@
|
||||
+// SPDX-License-Identifier: GPL-2.0-only
|
||||
+
|
||||
+#include <linux/bitfield.h>
|
||||
+#include <linux/gpio/driver.h>
|
||||
+#include <linux/gpio/regmap.h>
|
||||
+#include <linux/module.h>
|
||||
+#include <linux/pinctrl/pinconf.h>
|
||||
+#include <linux/pinctrl/pinctrl.h>
|
||||
+#include <linux/pinctrl/pinmux.h>
|
||||
+#include <linux/platform_device.h>
|
||||
+#include <linux/regmap.h>
|
||||
+
|
||||
+#include "core.h"
|
||||
+#include "pinmux.h"
|
||||
+#include <linux/mfd/rtl8231.h>
|
||||
+
|
||||
+#define RTL8231_NUM_GPIOS 37
|
||||
+#define RTL8231_DEBOUNCE_USEC 100000
|
||||
+#define RTL8231_DEBOUNCE_MIN_OFFSET 31
|
||||
+
|
||||
+struct rtl8231_pin_ctrl {
|
||||
+ struct pinctrl_desc pctl_desc;
|
||||
+ struct regmap *map;
|
||||
+};
|
||||
+
|
||||
+/*
|
||||
+ * Pin controller functionality
|
||||
+ */
|
||||
+static const char * const rtl8231_pin_function_names[] = {
|
||||
+ "gpio",
|
||||
+ "led",
|
||||
+ "pwm",
|
||||
+};
|
||||
+
|
||||
+enum rtl8231_pin_function {
|
||||
+ RTL8231_PIN_FUNCTION_GPIO = BIT(0),
|
||||
+ RTL8231_PIN_FUNCTION_LED = BIT(1),
|
||||
+ RTL8231_PIN_FUNCTION_PWM = BIT(2),
|
||||
+};
|
||||
+
|
||||
+struct rtl8231_pin_desc {
|
||||
+ const enum rtl8231_pin_function functions;
|
||||
+ const u8 reg;
|
||||
+ const u8 offset;
|
||||
+ const u8 gpio_function_value;
|
||||
+};
|
||||
+
|
||||
+#define RTL8231_PIN_DESC(_num, _func, _reg, _fld, _val) \
|
||||
+ [_num] = { \
|
||||
+ .functions = RTL8231_PIN_FUNCTION_GPIO | _func, \
|
||||
+ .reg = _reg, \
|
||||
+ .offset = _fld, \
|
||||
+ .gpio_function_value = _val, \
|
||||
+ }
|
||||
+#define RTL8231_GPIO_PIN_DESC(_num, _reg, _fld) \
|
||||
+ RTL8231_PIN_DESC(_num, 0, _reg, _fld, RTL8231_PIN_MODE_GPIO)
|
||||
+#define RTL8231_LED_PIN_DESC(_num, _reg, _fld) \
|
||||
+ RTL8231_PIN_DESC(_num, RTL8231_PIN_FUNCTION_LED, _reg, _fld, RTL8231_PIN_MODE_GPIO)
|
||||
+#define RTL8231_PWM_PIN_DESC(_num, _reg, _fld) \
|
||||
+ RTL8231_PIN_DESC(_num, RTL8231_PIN_FUNCTION_PWM, _reg, _fld, 0)
|
||||
+
|
||||
+/*
|
||||
+ * All pins have a GPIO/LED mux bit, but the bits for pins 35/36 are read-only. Use this bit
|
||||
+ * for the GPIO-only pin instead of a placeholder, so the rest of the logic can stay generic.
|
||||
+ */
|
||||
+static struct rtl8231_pin_desc rtl8231_pin_data[RTL8231_NUM_GPIOS] = {
|
||||
+ RTL8231_LED_PIN_DESC(0, RTL8231_REG_PIN_MODE0, 0),
|
||||
+ RTL8231_LED_PIN_DESC(1, RTL8231_REG_PIN_MODE0, 1),
|
||||
+ RTL8231_LED_PIN_DESC(2, RTL8231_REG_PIN_MODE0, 2),
|
||||
+ RTL8231_LED_PIN_DESC(3, RTL8231_REG_PIN_MODE0, 3),
|
||||
+ RTL8231_LED_PIN_DESC(4, RTL8231_REG_PIN_MODE0, 4),
|
||||
+ RTL8231_LED_PIN_DESC(5, RTL8231_REG_PIN_MODE0, 5),
|
||||
+ RTL8231_LED_PIN_DESC(6, RTL8231_REG_PIN_MODE0, 6),
|
||||
+ RTL8231_LED_PIN_DESC(7, RTL8231_REG_PIN_MODE0, 7),
|
||||
+ RTL8231_LED_PIN_DESC(8, RTL8231_REG_PIN_MODE0, 8),
|
||||
+ RTL8231_LED_PIN_DESC(9, RTL8231_REG_PIN_MODE0, 9),
|
||||
+ RTL8231_LED_PIN_DESC(10, RTL8231_REG_PIN_MODE0, 10),
|
||||
+ RTL8231_LED_PIN_DESC(11, RTL8231_REG_PIN_MODE0, 11),
|
||||
+ RTL8231_LED_PIN_DESC(12, RTL8231_REG_PIN_MODE0, 12),
|
||||
+ RTL8231_LED_PIN_DESC(13, RTL8231_REG_PIN_MODE0, 13),
|
||||
+ RTL8231_LED_PIN_DESC(14, RTL8231_REG_PIN_MODE0, 14),
|
||||
+ RTL8231_LED_PIN_DESC(15, RTL8231_REG_PIN_MODE0, 15),
|
||||
+ RTL8231_LED_PIN_DESC(16, RTL8231_REG_PIN_MODE1, 0),
|
||||
+ RTL8231_LED_PIN_DESC(17, RTL8231_REG_PIN_MODE1, 1),
|
||||
+ RTL8231_LED_PIN_DESC(18, RTL8231_REG_PIN_MODE1, 2),
|
||||
+ RTL8231_LED_PIN_DESC(19, RTL8231_REG_PIN_MODE1, 3),
|
||||
+ RTL8231_LED_PIN_DESC(20, RTL8231_REG_PIN_MODE1, 4),
|
||||
+ RTL8231_LED_PIN_DESC(21, RTL8231_REG_PIN_MODE1, 5),
|
||||
+ RTL8231_LED_PIN_DESC(22, RTL8231_REG_PIN_MODE1, 6),
|
||||
+ RTL8231_LED_PIN_DESC(23, RTL8231_REG_PIN_MODE1, 7),
|
||||
+ RTL8231_LED_PIN_DESC(24, RTL8231_REG_PIN_MODE1, 8),
|
||||
+ RTL8231_LED_PIN_DESC(25, RTL8231_REG_PIN_MODE1, 9),
|
||||
+ RTL8231_LED_PIN_DESC(26, RTL8231_REG_PIN_MODE1, 10),
|
||||
+ RTL8231_LED_PIN_DESC(27, RTL8231_REG_PIN_MODE1, 11),
|
||||
+ RTL8231_LED_PIN_DESC(28, RTL8231_REG_PIN_MODE1, 12),
|
||||
+ RTL8231_LED_PIN_DESC(29, RTL8231_REG_PIN_MODE1, 13),
|
||||
+ RTL8231_LED_PIN_DESC(30, RTL8231_REG_PIN_MODE1, 14),
|
||||
+ RTL8231_LED_PIN_DESC(31, RTL8231_REG_PIN_MODE1, 15),
|
||||
+ RTL8231_LED_PIN_DESC(32, RTL8231_REG_PIN_HI_CFG, 0),
|
||||
+ RTL8231_LED_PIN_DESC(33, RTL8231_REG_PIN_HI_CFG, 1),
|
||||
+ RTL8231_LED_PIN_DESC(34, RTL8231_REG_PIN_HI_CFG, 2),
|
||||
+ RTL8231_PWM_PIN_DESC(35, RTL8231_REG_FUNC1, 3),
|
||||
+ RTL8231_GPIO_PIN_DESC(36, RTL8231_REG_PIN_HI_CFG, 4),
|
||||
+};
|
||||
+
|
||||
+#define RTL8231_PIN(_num) \
|
||||
+ { \
|
||||
+ .number = _num, \
|
||||
+ .name = "gpio" #_num, \
|
||||
+ .drv_data = &rtl8231_pin_data[_num] \
|
||||
+ }
|
||||
+
|
||||
+static const struct pinctrl_pin_desc rtl8231_pins[RTL8231_NUM_GPIOS] = {
|
||||
+ RTL8231_PIN(0),
|
||||
+ RTL8231_PIN(1),
|
||||
+ RTL8231_PIN(2),
|
||||
+ RTL8231_PIN(3),
|
||||
+ RTL8231_PIN(4),
|
||||
+ RTL8231_PIN(5),
|
||||
+ RTL8231_PIN(6),
|
||||
+ RTL8231_PIN(7),
|
||||
+ RTL8231_PIN(8),
|
||||
+ RTL8231_PIN(9),
|
||||
+ RTL8231_PIN(10),
|
||||
+ RTL8231_PIN(11),
|
||||
+ RTL8231_PIN(12),
|
||||
+ RTL8231_PIN(13),
|
||||
+ RTL8231_PIN(14),
|
||||
+ RTL8231_PIN(15),
|
||||
+ RTL8231_PIN(16),
|
||||
+ RTL8231_PIN(17),
|
||||
+ RTL8231_PIN(18),
|
||||
+ RTL8231_PIN(19),
|
||||
+ RTL8231_PIN(20),
|
||||
+ RTL8231_PIN(21),
|
||||
+ RTL8231_PIN(22),
|
||||
+ RTL8231_PIN(23),
|
||||
+ RTL8231_PIN(24),
|
||||
+ RTL8231_PIN(25),
|
||||
+ RTL8231_PIN(26),
|
||||
+ RTL8231_PIN(27),
|
||||
+ RTL8231_PIN(28),
|
||||
+ RTL8231_PIN(29),
|
||||
+ RTL8231_PIN(30),
|
||||
+ RTL8231_PIN(31),
|
||||
+ RTL8231_PIN(32),
|
||||
+ RTL8231_PIN(33),
|
||||
+ RTL8231_PIN(34),
|
||||
+ RTL8231_PIN(35),
|
||||
+ RTL8231_PIN(36),
|
||||
+};
|
||||
+
|
||||
+static int rtl8231_get_groups_count(struct pinctrl_dev *pctldev)
|
||||
+{
|
||||
+ return ARRAY_SIZE(rtl8231_pins);
|
||||
+}
|
||||
+
|
||||
+static const char *rtl8231_get_group_name(struct pinctrl_dev *pctldev, unsigned int selector)
|
||||
+{
|
||||
+ return rtl8231_pins[selector].name;
|
||||
+}
|
||||
+
|
||||
+static int rtl8231_get_group_pins(struct pinctrl_dev *pctldev, unsigned int selector,
|
||||
+ const unsigned int **pins, unsigned int *num_pins)
|
||||
+{
|
||||
+ if (selector >= ARRAY_SIZE(rtl8231_pins))
|
||||
+ return -EINVAL;
|
||||
+
|
||||
+ *pins = &rtl8231_pins[selector].number;
|
||||
+ *num_pins = 1;
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static const struct pinctrl_ops rtl8231_pinctrl_ops = {
|
||||
+ .get_groups_count = rtl8231_get_groups_count,
|
||||
+ .get_group_name = rtl8231_get_group_name,
|
||||
+ .get_group_pins = rtl8231_get_group_pins,
|
||||
+ .dt_node_to_map = pinconf_generic_dt_node_to_map_all,
|
||||
+ .dt_free_map = pinconf_generic_dt_free_map,
|
||||
+};
|
||||
+
|
||||
+static int rtl8231_set_mux(struct pinctrl_dev *pctldev, unsigned int func_selector,
|
||||
+ unsigned int group_selector)
|
||||
+{
|
||||
+ const struct function_desc *func = pinmux_generic_get_function(pctldev, func_selector);
|
||||
+ const struct rtl8231_pin_desc *desc = rtl8231_pins[group_selector].drv_data;
|
||||
+ const struct rtl8231_pin_ctrl *ctrl = pinctrl_dev_get_drvdata(pctldev);
|
||||
+ unsigned int func_flag = (uintptr_t) func->data;
|
||||
+ unsigned int function_mask;
|
||||
+ unsigned int gpio_function;
|
||||
+
|
||||
+ if (!(desc->functions & func_flag))
|
||||
+ return -EINVAL;
|
||||
+
|
||||
+ function_mask = BIT(desc->offset);
|
||||
+ gpio_function = desc->gpio_function_value << desc->offset;
|
||||
+
|
||||
+ if (func_flag == RTL8231_PIN_FUNCTION_GPIO)
|
||||
+ return regmap_update_bits(ctrl->map, desc->reg, function_mask, gpio_function);
|
||||
+ else
|
||||
+ return regmap_update_bits(ctrl->map, desc->reg, function_mask, ~gpio_function);
|
||||
+}
|
||||
+
|
||||
+static int rtl8231_gpio_request_enable(struct pinctrl_dev *pctldev,
|
||||
+ struct pinctrl_gpio_range *range, unsigned int offset)
|
||||
+{
|
||||
+ const struct rtl8231_pin_desc *desc = rtl8231_pins[offset].drv_data;
|
||||
+ struct rtl8231_pin_ctrl *ctrl = pinctrl_dev_get_drvdata(pctldev);
|
||||
+ unsigned int function_mask;
|
||||
+ unsigned int gpio_function;
|
||||
+
|
||||
+ function_mask = BIT(desc->offset);
|
||||
+ gpio_function = desc->gpio_function_value << desc->offset;
|
||||
+
|
||||
+ return regmap_update_bits(ctrl->map, desc->reg, function_mask, gpio_function);
|
||||
+}
|
||||
+
|
||||
+static const struct pinmux_ops rtl8231_pinmux_ops = {
|
||||
+ .get_functions_count = pinmux_generic_get_function_count,
|
||||
+ .get_function_name = pinmux_generic_get_function_name,
|
||||
+ .get_function_groups = pinmux_generic_get_function_groups,
|
||||
+ .set_mux = rtl8231_set_mux,
|
||||
+ .gpio_request_enable = rtl8231_gpio_request_enable,
|
||||
+ .strict = true,
|
||||
+};
|
||||
+
|
||||
+static int rtl8231_pin_config_get(struct pinctrl_dev *pctldev, unsigned int offset,
|
||||
+ unsigned long *config)
|
||||
+{
|
||||
+ struct rtl8231_pin_ctrl *ctrl = pinctrl_dev_get_drvdata(pctldev);
|
||||
+ unsigned int param = pinconf_to_config_param(*config);
|
||||
+ unsigned int arg;
|
||||
+ int err;
|
||||
+ int v;
|
||||
+
|
||||
+ switch (param) {
|
||||
+ case PIN_CONFIG_INPUT_DEBOUNCE:
|
||||
+ if (offset < RTL8231_DEBOUNCE_MIN_OFFSET)
|
||||
+ return -EINVAL;
|
||||
+
|
||||
+ err = regmap_read(ctrl->map, RTL8231_REG_FUNC1, &v);
|
||||
+ if (err)
|
||||
+ return err;
|
||||
+
|
||||
+ v = FIELD_GET(RTL8231_FUNC1_DEBOUNCE_MASK, v);
|
||||
+ if (v & BIT(offset - RTL8231_DEBOUNCE_MIN_OFFSET))
|
||||
+ arg = RTL8231_DEBOUNCE_USEC;
|
||||
+ else
|
||||
+ arg = 0;
|
||||
+ break;
|
||||
+ default:
|
||||
+ return -ENOTSUPP;
|
||||
+ }
|
||||
+
|
||||
+ *config = pinconf_to_config_packed(param, arg);
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static int rtl8231_pin_config_set(struct pinctrl_dev *pctldev, unsigned int offset,
|
||||
+ unsigned long *configs, unsigned int num_configs)
|
||||
+{
|
||||
+ struct rtl8231_pin_ctrl *ctrl = pinctrl_dev_get_drvdata(pctldev);
|
||||
+ unsigned int param, arg;
|
||||
+ unsigned int pin_mask;
|
||||
+ int err;
|
||||
+ int i;
|
||||
+
|
||||
+ for (i = 0; i < num_configs; i++) {
|
||||
+ param = pinconf_to_config_param(configs[i]);
|
||||
+ arg = pinconf_to_config_argument(configs[i]);
|
||||
+
|
||||
+ switch (param) {
|
||||
+ case PIN_CONFIG_INPUT_DEBOUNCE:
|
||||
+ if (offset < RTL8231_DEBOUNCE_MIN_OFFSET)
|
||||
+ return -EINVAL;
|
||||
+
|
||||
+ pin_mask = FIELD_PREP(RTL8231_FUNC1_DEBOUNCE_MASK,
|
||||
+ BIT(offset - RTL8231_DEBOUNCE_MIN_OFFSET));
|
||||
+
|
||||
+ switch (arg) {
|
||||
+ case 0:
|
||||
+ err = regmap_update_bits(ctrl->map, RTL8231_REG_FUNC1,
|
||||
+ pin_mask, 0);
|
||||
+ break;
|
||||
+ case RTL8231_DEBOUNCE_USEC:
|
||||
+ err = regmap_update_bits(ctrl->map, RTL8231_REG_FUNC1,
|
||||
+ pin_mask, pin_mask);
|
||||
+ break;
|
||||
+ default:
|
||||
+ return -EINVAL;
|
||||
+ }
|
||||
+
|
||||
+ break;
|
||||
+ default:
|
||||
+ return -ENOTSUPP;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ return err;
|
||||
+}
|
||||
+
|
||||
+static const struct pinconf_ops rtl8231_pinconf_ops = {
|
||||
+ .is_generic = true,
|
||||
+ .pin_config_get = rtl8231_pin_config_get,
|
||||
+ .pin_config_set = rtl8231_pin_config_set,
|
||||
+};
|
||||
+
|
||||
+static int rtl8231_pinctrl_init_functions(struct pinctrl_dev *pctl, struct rtl8231_pin_ctrl *ctrl)
|
||||
+{
|
||||
+ const char *function_name;
|
||||
+ const char **groups;
|
||||
+ unsigned int f_idx;
|
||||
+ unsigned int pin;
|
||||
+ int num_groups;
|
||||
+ int err;
|
||||
+
|
||||
+ for (f_idx = 0; f_idx < ARRAY_SIZE(rtl8231_pin_function_names); f_idx++) {
|
||||
+ function_name = rtl8231_pin_function_names[f_idx];
|
||||
+
|
||||
+ for (pin = 0, num_groups = 0; pin < ctrl->pctl_desc.npins; pin++)
|
||||
+ if (rtl8231_pin_data[pin].functions & BIT(f_idx))
|
||||
+ num_groups++;
|
||||
+
|
||||
+ groups = devm_kcalloc(pctl->dev, num_groups, sizeof(*groups), GFP_KERNEL);
|
||||
+ if (!groups)
|
||||
+ return -ENOMEM;
|
||||
+
|
||||
+ for (pin = 0, num_groups = 0; pin < ctrl->pctl_desc.npins; pin++)
|
||||
+ if (rtl8231_pin_data[pin].functions & BIT(f_idx))
|
||||
+ groups[num_groups++] = rtl8231_pins[pin].name;
|
||||
+
|
||||
+ err = pinmux_generic_add_function(pctl, function_name, groups, num_groups,
|
||||
+ (void *) BIT(f_idx));
|
||||
+ if (err < 0)
|
||||
+ return err;
|
||||
+ }
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+struct pin_field_info {
|
||||
+ const struct reg_field gpio_data;
|
||||
+ const struct reg_field gpio_dir;
|
||||
+ const struct reg_field mode;
|
||||
+};
|
||||
+
|
||||
+static const struct pin_field_info pin_fields[] = {
|
||||
+ {
|
||||
+ .gpio_data = REG_FIELD(RTL8231_REG_GPIO_DATA0, 0, 15),
|
||||
+ .gpio_dir = REG_FIELD(RTL8231_REG_GPIO_DIR0, 0, 15),
|
||||
+ .mode = REG_FIELD(RTL8231_REG_PIN_MODE0, 0, 15),
|
||||
+ },
|
||||
+ {
|
||||
+ .gpio_data = REG_FIELD(RTL8231_REG_GPIO_DATA1, 0, 15),
|
||||
+ .gpio_dir = REG_FIELD(RTL8231_REG_GPIO_DIR1, 0, 15),
|
||||
+ .mode = REG_FIELD(RTL8231_REG_PIN_MODE1, 0, 15),
|
||||
+ },
|
||||
+ {
|
||||
+ .gpio_data = REG_FIELD(RTL8231_REG_GPIO_DATA2, 0, 4),
|
||||
+ .gpio_dir = REG_FIELD(RTL8231_REG_PIN_HI_CFG, 5, 9),
|
||||
+ .mode = REG_FIELD(RTL8231_REG_PIN_HI_CFG, 0, 4),
|
||||
+ },
|
||||
+};
|
||||
+
|
||||
+static int rtl8231_configure_safe(struct device *dev, struct regmap *map)
|
||||
+{
|
||||
+ struct regmap_field *field_data;
|
||||
+ struct regmap_field *field_mode;
|
||||
+ struct regmap_field *field_dir;
|
||||
+ unsigned int is_output;
|
||||
+ unsigned int is_gpio;
|
||||
+ unsigned int data;
|
||||
+ unsigned int mode;
|
||||
+ unsigned int dir;
|
||||
+ int err;
|
||||
+
|
||||
+ for (unsigned int i = 0; i < ARRAY_SIZE(pin_fields); i++) {
|
||||
+ field_data = devm_regmap_field_alloc(dev, map, pin_fields[i].gpio_data);
|
||||
+ if (IS_ERR(field_data))
|
||||
+ return PTR_ERR(field_data);
|
||||
+
|
||||
+ field_dir = devm_regmap_field_alloc(dev, map, pin_fields[i].gpio_dir);
|
||||
+ if (IS_ERR(field_dir))
|
||||
+ return PTR_ERR(field_dir);
|
||||
+
|
||||
+ field_mode = devm_regmap_field_alloc(dev, map, pin_fields[i].mode);
|
||||
+ if (IS_ERR(field_mode))
|
||||
+ return PTR_ERR(field_mode);
|
||||
+
|
||||
+ /* The register cache is invalid at start-up, so this should read from HW */
|
||||
+ err = regmap_field_read(field_data, &data);
|
||||
+ if (err)
|
||||
+ return err;
|
||||
+
|
||||
+ err = regmap_field_read(field_dir, &dir);
|
||||
+ if (err)
|
||||
+ return err;
|
||||
+
|
||||
+ err = regmap_field_read(field_mode, &mode);
|
||||
+ if (err)
|
||||
+ return err;
|
||||
+
|
||||
+ /* Write back only the GPIO-out values to fix the cache */
|
||||
+ data &= ~dir;
|
||||
+ regmap_field_write(field_data, data);
|
||||
+
|
||||
+ /*
|
||||
+ * Set every pin that is configured as gpio-output but muxed for the alternative
|
||||
+ * (LED) function to gpio-in. That way the pin will be high impedance when it is
|
||||
+ * muxed to GPIO, preventing unwanted glitches.
|
||||
+ * The pin muxes are left as-is, so there are no signal changes.
|
||||
+ */
|
||||
+ is_gpio = mode;
|
||||
+ is_output = ~dir;
|
||||
+ regmap_field_write(field_dir, dir | (~is_gpio & is_output));
|
||||
+
|
||||
+ devm_regmap_field_free(dev, field_data);
|
||||
+ devm_regmap_field_free(dev, field_dir);
|
||||
+ devm_regmap_field_free(dev, field_mode);
|
||||
+ }
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static int rtl8231_pinctrl_init(struct device *dev, struct rtl8231_pin_ctrl *ctrl)
|
||||
+{
|
||||
+ struct pinctrl_dev *pctldev;
|
||||
+ int err;
|
||||
+
|
||||
+ ctrl->pctl_desc.name = "rtl8231-pinctrl";
|
||||
+ ctrl->pctl_desc.owner = THIS_MODULE;
|
||||
+ ctrl->pctl_desc.confops = &rtl8231_pinconf_ops;
|
||||
+ ctrl->pctl_desc.pctlops = &rtl8231_pinctrl_ops;
|
||||
+ ctrl->pctl_desc.pmxops = &rtl8231_pinmux_ops;
|
||||
+ ctrl->pctl_desc.npins = ARRAY_SIZE(rtl8231_pins);
|
||||
+ ctrl->pctl_desc.pins = rtl8231_pins;
|
||||
+
|
||||
+ err = devm_pinctrl_register_and_init(dev->parent, &ctrl->pctl_desc, ctrl, &pctldev);
|
||||
+ if (err) {
|
||||
+ dev_err(dev, "failed to register pin controller\n");
|
||||
+ return err;
|
||||
+ }
|
||||
+
|
||||
+ err = rtl8231_pinctrl_init_functions(pctldev, ctrl);
|
||||
+ if (err)
|
||||
+ return err;
|
||||
+
|
||||
+ err = pinctrl_enable(pctldev);
|
||||
+ if (err)
|
||||
+ dev_err(dev, "failed to enable pin controller\n");
|
||||
+
|
||||
+ return err;
|
||||
+}
|
||||
+
|
||||
+/*
|
||||
+ * GPIO controller functionality
|
||||
+ */
|
||||
+static int rtl8231_gpio_reg_mask_xlate(struct gpio_regmap *gpio, unsigned int base,
|
||||
+ unsigned int offset, unsigned int *reg, unsigned int *mask)
|
||||
+{
|
||||
+ unsigned int pin_mask = BIT(offset % RTL8231_BITS_VAL);
|
||||
+
|
||||
+ if (base == RTL8231_REG_GPIO_DATA0 || offset < 32) {
|
||||
+ *reg = base + offset / RTL8231_BITS_VAL;
|
||||
+ *mask = pin_mask;
|
||||
+ } else if (base == RTL8231_REG_GPIO_DIR0) {
|
||||
+ *reg = RTL8231_REG_PIN_HI_CFG;
|
||||
+ *mask = FIELD_PREP(RTL8231_PIN_HI_CFG_DIR_MASK, pin_mask);
|
||||
+ } else {
|
||||
+ return -EINVAL;
|
||||
+ }
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static int rtl8231_pinctrl_probe(struct platform_device *pdev)
|
||||
+{
|
||||
+ struct device *dev = &pdev->dev;
|
||||
+ struct rtl8231_pin_ctrl *ctrl;
|
||||
+ struct gpio_regmap_config gpio_cfg = {};
|
||||
+ int err;
|
||||
+
|
||||
+ ctrl = devm_kzalloc(dev, sizeof(*ctrl), GFP_KERNEL);
|
||||
+ if (!ctrl)
|
||||
+ return -ENOMEM;
|
||||
+
|
||||
+ ctrl->map = dev_get_regmap(dev->parent, NULL);
|
||||
+ if (!ctrl->map)
|
||||
+ return -ENODEV;
|
||||
+
|
||||
+ err = rtl8231_configure_safe(dev, ctrl->map);
|
||||
+ if (err)
|
||||
+ return err;
|
||||
+
|
||||
+ err = rtl8231_pinctrl_init(dev, ctrl);
|
||||
+ if (err)
|
||||
+ return err;
|
||||
+
|
||||
+ gpio_cfg.regmap = ctrl->map;
|
||||
+ gpio_cfg.parent = dev->parent;
|
||||
+ gpio_cfg.ngpio = RTL8231_NUM_GPIOS;
|
||||
+ gpio_cfg.ngpio_per_reg = RTL8231_BITS_VAL;
|
||||
+
|
||||
+ gpio_cfg.reg_dat_base = GPIO_REGMAP_ADDR(RTL8231_REG_GPIO_DATA0);
|
||||
+ gpio_cfg.reg_set_base = GPIO_REGMAP_ADDR(RTL8231_REG_GPIO_DATA0);
|
||||
+ gpio_cfg.reg_dir_in_base = GPIO_REGMAP_ADDR(RTL8231_REG_GPIO_DIR0);
|
||||
+
|
||||
+ gpio_cfg.reg_mask_xlate = rtl8231_gpio_reg_mask_xlate;
|
||||
+
|
||||
+ return PTR_ERR_OR_ZERO(devm_gpio_regmap_register(dev, &gpio_cfg));
|
||||
+}
|
||||
+
|
||||
+static struct platform_driver rtl8231_pinctrl_driver = {
|
||||
+ .driver = {
|
||||
+ .name = "rtl8231-pinctrl",
|
||||
+ },
|
||||
+ .probe = rtl8231_pinctrl_probe,
|
||||
+};
|
||||
+module_platform_driver(rtl8231_pinctrl_driver);
|
||||
+
|
||||
+MODULE_AUTHOR("Sander Vanheule <sander@svanheule.net>");
|
||||
+MODULE_DESCRIPTION("Realtek RTL8231 pin control and GPIO support");
|
||||
+MODULE_LICENSE("GPL");
|
|
@ -1,338 +0,0 @@
|
|||
From 6b797a97c007e46d6081fc6f4b41ce8407078605 Mon Sep 17 00:00:00 2001
|
||||
From: Sander Vanheule <sander@svanheule.net>
|
||||
Date: Mon, 10 May 2021 22:16:11 +0200
|
||||
Subject: [PATCH] leds: Add support for RTL8231 LED scan matrix
|
||||
|
||||
Both single and bi-color scanning modes are supported. The driver will
|
||||
verify that the addresses are valid for the current mode, before
|
||||
registering the LEDs. LEDs can be turned on, off, or toggled at one of
|
||||
six predefined rates from 40ms to 1280ms.
|
||||
|
||||
Implements a platform device for use as a child device with RTL8231 MFD,
|
||||
and uses the parent regmap to access the required registers.
|
||||
|
||||
Signed-off-by: Sander Vanheule <sander@svanheule.net>
|
||||
---
|
||||
drivers/leds/Kconfig | 10 ++
|
||||
drivers/leds/Makefile | 1 +
|
||||
drivers/leds/leds-rtl8231.c | 291 ++++++++++++++++++++++++++++++++++++
|
||||
3 files changed, 302 insertions(+)
|
||||
create mode 100644 drivers/leds/leds-rtl8231.c
|
||||
|
||||
--- a/drivers/leds/Kconfig
|
||||
+++ b/drivers/leds/Kconfig
|
||||
@@ -586,6 +586,16 @@ config LEDS_REGULATOR
|
||||
help
|
||||
This option enables support for regulator driven LEDs.
|
||||
|
||||
+config LEDS_RTL8231
|
||||
+ tristate "RTL8231 LED matrix support"
|
||||
+ depends on LEDS_CLASS
|
||||
+ depends on MFD_RTL8231
|
||||
+ default MFD_RTL8231
|
||||
+ help
|
||||
+ This option enables support for using the LED scanning matrix output
|
||||
+ of the RTL8231 GPIO and LED expander chip.
|
||||
+ When built as a module, this module will be named leds-rtl8231.
|
||||
+
|
||||
config LEDS_BD2606MVV
|
||||
tristate "LED driver for BD2606MVV"
|
||||
depends on LEDS_CLASS
|
||||
--- a/drivers/leds/Makefile
|
||||
+++ b/drivers/leds/Makefile
|
||||
@@ -77,6 +77,7 @@ obj-$(CONFIG_LEDS_PM8058) += leds-pm805
|
||||
obj-$(CONFIG_LEDS_POWERNV) += leds-powernv.o
|
||||
obj-$(CONFIG_LEDS_PWM) += leds-pwm.o
|
||||
obj-$(CONFIG_LEDS_REGULATOR) += leds-regulator.o
|
||||
+obj-$(CONFIG_LEDS_RTL8231) += leds-rtl8231.o
|
||||
obj-$(CONFIG_LEDS_SC27XX_BLTC) += leds-sc27xx-bltc.o
|
||||
obj-$(CONFIG_LEDS_ST1202) += leds-st1202.o
|
||||
obj-$(CONFIG_LEDS_SUNFIRE) += leds-sunfire.o
|
||||
--- /dev/null
|
||||
+++ b/drivers/leds/leds-rtl8231.c
|
||||
@@ -0,0 +1,285 @@
|
||||
+// SPDX-License-Identifier: GPL-2.0-only
|
||||
+
|
||||
+#include <linux/device.h>
|
||||
+#include <linux/leds.h>
|
||||
+#include <linux/mod_devicetable.h>
|
||||
+#include <linux/module.h>
|
||||
+#include <linux/platform_device.h>
|
||||
+#include <linux/property.h>
|
||||
+#include <linux/regmap.h>
|
||||
+
|
||||
+#include <linux/mfd/rtl8231.h>
|
||||
+
|
||||
+/**
|
||||
+ * struct led_toggle_rate - description of an LED blinking mode
|
||||
+ * @interval_ms: LED toggle rate in milliseconds
|
||||
+ * @mode: Register field value used to activate this mode
|
||||
+ *
|
||||
+ * For LED hardware accelerated blinking, with equal on and off delay.
|
||||
+ * Both delays are given by @interval, so the interval at which the LED blinks
|
||||
+ * (i.e. turn on and off once) is double this value.
|
||||
+ */
|
||||
+struct led_toggle_rate {
|
||||
+ u16 interval_ms;
|
||||
+ u8 mode;
|
||||
+};
|
||||
+
|
||||
+/**
|
||||
+ * struct led_modes - description of all LED modes
|
||||
+ * @toggle_rates: Array of led_toggle_rate values, sorted by ascending interval
|
||||
+ * @num_toggle_rates: Number of elements in @led_toggle_rate
|
||||
+ * @off: Register field value to turn LED off
|
||||
+ * @on: Register field value to turn LED on
|
||||
+ */
|
||||
+struct led_modes {
|
||||
+ const struct led_toggle_rate *toggle_rates;
|
||||
+ unsigned int num_toggle_rates;
|
||||
+ u8 off;
|
||||
+ u8 on;
|
||||
+};
|
||||
+
|
||||
+struct rtl8231_led {
|
||||
+ struct led_classdev led;
|
||||
+ const struct led_modes *modes;
|
||||
+ struct regmap_field *reg_field;
|
||||
+};
|
||||
+#define to_rtl8231_led(_cdev) container_of(_cdev, struct rtl8231_led, led)
|
||||
+
|
||||
+#define RTL8231_NUM_LEDS 3
|
||||
+#define RTL8231_LED_PER_REG 5
|
||||
+#define RTL8231_BITS_PER_LED 3
|
||||
+
|
||||
+static const unsigned int rtl8231_led_port_counts_single[RTL8231_NUM_LEDS] = {32, 32, 24};
|
||||
+static const unsigned int rtl8231_led_port_counts_bicolor[RTL8231_NUM_LEDS] = {24, 24, 24};
|
||||
+
|
||||
+static const unsigned int rtl8231_led_base[RTL8231_NUM_LEDS] = {
|
||||
+ RTL8231_REG_LED0_BASE,
|
||||
+ RTL8231_REG_LED1_BASE,
|
||||
+ RTL8231_REG_LED2_BASE,
|
||||
+};
|
||||
+
|
||||
+#define RTL8231_DEFAULT_TOGGLE_INTERVAL_MS 500
|
||||
+
|
||||
+static const struct led_toggle_rate rtl8231_toggle_rates[] = {
|
||||
+ { 40, 1},
|
||||
+ { 80, 2},
|
||||
+ { 160, 3},
|
||||
+ { 320, 4},
|
||||
+ { 640, 5},
|
||||
+ {1280, 6},
|
||||
+};
|
||||
+
|
||||
+static const struct led_modes rtl8231_led_modes = {
|
||||
+ .off = 0,
|
||||
+ .on = 7,
|
||||
+ .num_toggle_rates = ARRAY_SIZE(rtl8231_toggle_rates),
|
||||
+ .toggle_rates = rtl8231_toggle_rates,
|
||||
+};
|
||||
+
|
||||
+static void rtl8231_led_brightness_set(struct led_classdev *led_cdev,
|
||||
+ enum led_brightness brightness)
|
||||
+{
|
||||
+ struct rtl8231_led *pled = to_rtl8231_led(led_cdev);
|
||||
+
|
||||
+ if (brightness)
|
||||
+ regmap_field_write(pled->reg_field, pled->modes->on);
|
||||
+ else
|
||||
+ regmap_field_write(pled->reg_field, pled->modes->off);
|
||||
+}
|
||||
+
|
||||
+static enum led_brightness rtl8231_led_brightness_get(struct led_classdev *led_cdev)
|
||||
+{
|
||||
+ struct rtl8231_led *pled = to_rtl8231_led(led_cdev);
|
||||
+ u32 current_mode = pled->modes->off;
|
||||
+
|
||||
+ regmap_field_read(pled->reg_field, ¤t_mode);
|
||||
+
|
||||
+ if (current_mode == pled->modes->off)
|
||||
+ return LED_OFF;
|
||||
+ else
|
||||
+ return LED_ON;
|
||||
+}
|
||||
+
|
||||
+static unsigned int rtl8231_led_current_interval(struct rtl8231_led *pled)
|
||||
+{
|
||||
+ unsigned int mode;
|
||||
+ unsigned int i;
|
||||
+
|
||||
+ if (regmap_field_read(pled->reg_field, &mode))
|
||||
+ return 0;
|
||||
+
|
||||
+ for (i = 0; i < pled->modes->num_toggle_rates; i++)
|
||||
+ if (mode == pled->modes->toggle_rates[i].mode)
|
||||
+ return pled->modes->toggle_rates[i].interval_ms;
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static int rtl8231_led_blink_set(struct led_classdev *led_cdev, unsigned long *delay_on,
|
||||
+ unsigned long *delay_off)
|
||||
+{
|
||||
+ struct rtl8231_led *pled = to_rtl8231_led(led_cdev);
|
||||
+ const struct led_toggle_rate *rates = pled->modes->toggle_rates;
|
||||
+ unsigned int num_rates = pled->modes->num_toggle_rates;
|
||||
+ unsigned int interval_ms;
|
||||
+ unsigned int i;
|
||||
+ int err;
|
||||
+
|
||||
+ if (*delay_on == 0 && *delay_off == 0) {
|
||||
+ interval_ms = RTL8231_DEFAULT_TOGGLE_INTERVAL_MS;
|
||||
+ } else {
|
||||
+ /*
|
||||
+ * If the current mode is blinking, choose the delay that (likely) changed.
|
||||
+ * Otherwise, choose the interval that would have the same total delay.
|
||||
+ */
|
||||
+ interval_ms = rtl8231_led_current_interval(pled);
|
||||
+ if (interval_ms > 0 && interval_ms == *delay_off)
|
||||
+ interval_ms = *delay_on;
|
||||
+ else if (interval_ms > 0 && interval_ms == *delay_on)
|
||||
+ interval_ms = *delay_off;
|
||||
+ else
|
||||
+ interval_ms = (*delay_on + *delay_off) / 2;
|
||||
+ }
|
||||
+
|
||||
+ /* Find clamped toggle interval */
|
||||
+ for (i = 0; i < (num_rates - 1); i++)
|
||||
+ if (interval_ms > rates[i].interval_ms)
|
||||
+ break;
|
||||
+
|
||||
+ interval_ms = rates[i].interval_ms;
|
||||
+
|
||||
+ err = regmap_field_write(pled->reg_field, rates[i].mode);
|
||||
+ if (err)
|
||||
+ return err;
|
||||
+
|
||||
+ *delay_on = interval_ms;
|
||||
+ *delay_off = interval_ms;
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static int rtl8231_led_read_address(struct fwnode_handle *fwnode, unsigned int *addr_port,
|
||||
+ unsigned int *addr_led)
|
||||
+{
|
||||
+ u32 addr[2];
|
||||
+ int err;
|
||||
+
|
||||
+ err = fwnode_property_count_u32(fwnode, "reg");
|
||||
+ if (err < 0)
|
||||
+ return err;
|
||||
+ if (err != ARRAY_SIZE(addr))
|
||||
+ return -EINVAL;
|
||||
+
|
||||
+ err = fwnode_property_read_u32_array(fwnode, "reg", addr, ARRAY_SIZE(addr));
|
||||
+ if (err)
|
||||
+ return err;
|
||||
+
|
||||
+ *addr_port = addr[0];
|
||||
+ *addr_led = addr[1];
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static const struct regmap_field *rtl8231_led_get_field(struct device *dev, struct regmap *map,
|
||||
+ unsigned int port_index, unsigned int led_index)
|
||||
+{
|
||||
+ unsigned int offset = port_index / RTL8231_LED_PER_REG;
|
||||
+ unsigned int shift = (port_index % RTL8231_LED_PER_REG) * RTL8231_BITS_PER_LED;
|
||||
+ const struct reg_field field = REG_FIELD(rtl8231_led_base[led_index] + offset, shift,
|
||||
+ shift + RTL8231_BITS_PER_LED - 1);
|
||||
+
|
||||
+ return devm_regmap_field_alloc(dev, map, field);
|
||||
+}
|
||||
+
|
||||
+static int rtl8231_led_probe_single(struct device *dev, struct regmap *map,
|
||||
+ const unsigned int *port_counts, struct fwnode_handle *fwnode)
|
||||
+{
|
||||
+ struct led_init_data init_data = {};
|
||||
+ struct rtl8231_led *pled;
|
||||
+ unsigned int port_index;
|
||||
+ unsigned int led_index;
|
||||
+ int err;
|
||||
+
|
||||
+ pled = devm_kzalloc(dev, sizeof(*pled), GFP_KERNEL);
|
||||
+ if (!pled)
|
||||
+ return -ENOMEM;
|
||||
+
|
||||
+ err = rtl8231_led_read_address(fwnode, &port_index, &led_index);
|
||||
+ if (err) {
|
||||
+ dev_err(dev, "LED address invalid");
|
||||
+ return err;
|
||||
+ }
|
||||
+
|
||||
+ if (led_index >= RTL8231_NUM_LEDS || port_index >= port_counts[led_index]) {
|
||||
+ dev_err(dev, "LED address (%d.%d) invalid", port_index, led_index);
|
||||
+ return -EINVAL;
|
||||
+ }
|
||||
+
|
||||
+ pled->reg_field = rtl8231_led_get_field(dev, map, port_index, led_index);
|
||||
+ if (IS_ERR(pled->reg_field))
|
||||
+ return PTR_ERR(pled->reg_field);
|
||||
+
|
||||
+ pled->modes = &rtl8231_led_modes;
|
||||
+
|
||||
+ pled->led.max_brightness = 1;
|
||||
+ pled->led.brightness_get = rtl8231_led_brightness_get;
|
||||
+ pled->led.brightness_set = rtl8231_led_brightness_set;
|
||||
+ pled->led.blink_set = rtl8231_led_blink_set;
|
||||
+
|
||||
+ init_data.fwnode = fwnode;
|
||||
+
|
||||
+ return devm_led_classdev_register_ext(dev, &pled->led, &init_data);
|
||||
+}
|
||||
+
|
||||
+static int rtl8231_led_probe(struct platform_device *pdev)
|
||||
+{
|
||||
+ struct device *dev = &pdev->dev;
|
||||
+ const unsigned int *port_counts;
|
||||
+ struct fwnode_handle *child;
|
||||
+ struct regmap *map;
|
||||
+ int err;
|
||||
+
|
||||
+ map = dev_get_regmap(dev->parent, NULL);
|
||||
+ if (!map)
|
||||
+ return -ENODEV;
|
||||
+
|
||||
+ if (device_property_match_string(dev, "realtek,led-scan-mode", "single-color") >= 0) {
|
||||
+ port_counts = rtl8231_led_port_counts_single;
|
||||
+ regmap_update_bits(map, RTL8231_REG_FUNC0,
|
||||
+ RTL8231_FUNC0_SCAN_MODE, RTL8231_FUNC0_SCAN_SINGLE);
|
||||
+ } else if (device_property_match_string(dev, "realtek,led-scan-mode", "bi-color") >= 0) {
|
||||
+ port_counts = rtl8231_led_port_counts_bicolor;
|
||||
+ regmap_update_bits(map, RTL8231_REG_FUNC0,
|
||||
+ RTL8231_FUNC0_SCAN_MODE, RTL8231_FUNC0_SCAN_BICOLOR);
|
||||
+ } else {
|
||||
+ dev_err(dev, "scan mode missing or invalid");
|
||||
+ return -EINVAL;
|
||||
+ }
|
||||
+
|
||||
+ fwnode_for_each_available_child_node(dev->fwnode, child) {
|
||||
+ err = rtl8231_led_probe_single(dev, map, port_counts, child);
|
||||
+ if (err)
|
||||
+ dev_warn(dev, "failed to register LED %pfwP", child);
|
||||
+ }
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static const struct of_device_id of_rtl8231_led_match[] = {
|
||||
+ { .compatible = "realtek,rtl8231-leds" },
|
||||
+ {}
|
||||
+};
|
||||
+MODULE_DEVICE_TABLE(of, of_rtl8231_led_match);
|
||||
+
|
||||
+static struct platform_driver rtl8231_led_driver = {
|
||||
+ .driver = {
|
||||
+ .name = "rtl8231-leds",
|
||||
+ .of_match_table = of_rtl8231_led_match,
|
||||
+ },
|
||||
+ .probe = rtl8231_led_probe,
|
||||
+};
|
||||
+module_platform_driver(rtl8231_led_driver);
|
||||
+
|
||||
+MODULE_AUTHOR("Sander Vanheule <sander@svanheule.net>");
|
||||
+MODULE_DESCRIPTION("Realtek RTL8231 LED support");
|
||||
+MODULE_LICENSE("GPL");
|
|
@ -1,257 +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_COMPACT_UNEVICTABLE_DEFAULT=1
|
||||
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_MITIGATIONS=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_GF128MUL=y
|
||||
CONFIG_CRYPTO_LIB_POLY1305_RSIZE=2
|
||||
CONFIG_CRYPTO_LIB_SHA1=y
|
||||
CONFIG_CRYPTO_LIB_UTILS=y
|
||||
CONFIG_DEBUG_INFO=y
|
||||
CONFIG_DEBUG_SECTION_MISMATCH=y
|
||||
CONFIG_DMA_NONCOHERENT=y
|
||||
CONFIG_DTC=y
|
||||
CONFIG_EARLY_PRINTK=y
|
||||
CONFIG_EARLY_PRINTK_8250=y
|
||||
CONFIG_EXCLUSIVE_SYSTEM_RAM=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_NR_CPUS=y
|
||||
CONFIG_FS_IOMAP=y
|
||||
CONFIG_FUNCTION_ALIGNMENT=0
|
||||
CONFIG_FWNODE_MDIO=y
|
||||
CONFIG_FW_LOADER_PAGED_BUF=y
|
||||
CONFIG_FW_LOADER_SYSFS=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_GETTIMEOFDAY=y
|
||||
CONFIG_GENERIC_IDLE_POLL_SETUP=y
|
||||
CONFIG_GENERIC_IOMAP=y
|
||||
CONFIG_GENERIC_IRQ_CHIP=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_REGMAP=y
|
||||
CONFIG_GPIO_WATCHDOG=y
|
||||
# CONFIG_GPIO_WATCHDOG_ARCH_INITCALL is not set
|
||||
CONFIG_GRO_CELLS=y
|
||||
CONFIG_HARDWARE_WATCHPOINTS=y
|
||||
CONFIG_HAS_DMA=y
|
||||
CONFIG_HAS_IOMEM=y
|
||||
CONFIG_HAS_IOPORT=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_LEDS_RTL8231 is not set
|
||||
CONFIG_LIBFDT=y
|
||||
CONFIG_LOCK_DEBUGGING_SUPPORT=y
|
||||
CONFIG_MACH_REALTEK_RTL=y
|
||||
CONFIG_MARVELL_PHY=y
|
||||
CONFIG_MDIO_BITBANG=y
|
||||
CONFIG_MDIO_BUS=y
|
||||
CONFIG_MDIO_DEVICE=y
|
||||
CONFIG_MDIO_DEVRES=y
|
||||
CONFIG_MDIO_GPIO=y
|
||||
CONFIG_MDIO_I2C=y
|
||||
CONFIG_MDIO_REALTEK_OTTO_AUX=y
|
||||
CONFIG_MDIO_SMBUS=y
|
||||
CONFIG_MFD_CORE=y
|
||||
CONFIG_MFD_RTL8231=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_EXTERNAL_TIMER=y
|
||||
CONFIG_MIPS_L1_CACHE_SHIFT=5
|
||||
# CONFIG_MIPS_NO_APPENDED_DTB is not set
|
||||
CONFIG_MIPS_RAW_APPENDED_DTB=y
|
||||
CONFIG_MIPS_SPRAM=y
|
||||
CONFIG_MMU_LAZY_TLB_REFCOUNT=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_EGRESS=y
|
||||
CONFIG_NET_INGRESS=y
|
||||
CONFIG_NET_RTL838X=y
|
||||
CONFIG_NET_SELFTESTS=y
|
||||
CONFIG_NET_XGRESS=y
|
||||
CONFIG_NO_EXCEPT_FILL=y
|
||||
CONFIG_NO_GENERIC_PCI_IOPORT_MAP=y
|
||||
CONFIG_NVMEM=y
|
||||
CONFIG_NVMEM_LAYOUTS=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_PAGE_POOL=y
|
||||
CONFIG_PAGE_SIZE_LESS_THAN_256KB=y
|
||||
CONFIG_PAGE_SIZE_LESS_THAN_64KB=y
|
||||
CONFIG_PCI_DRIVERS_LEGACY=y
|
||||
CONFIG_PERF_USE_VMALLOC=y
|
||||
CONFIG_PGTABLE_LEVELS=2
|
||||
CONFIG_PHYLIB=y
|
||||
CONFIG_PHYLIB_LEDS=y
|
||||
CONFIG_PHYLINK=y
|
||||
CONFIG_PINCTRL=y
|
||||
CONFIG_PINCTRL_RTL8231=y
|
||||
CONFIG_PM_OPP=y
|
||||
CONFIG_POWER_RESET=y
|
||||
CONFIG_POWER_RESET_GPIO_RESTART=y
|
||||
CONFIG_POWER_RESET_SYSCON=y
|
||||
CONFIG_PREEMPT_NONE_BUILD=y
|
||||
CONFIG_PTP_1588_CLOCK_OPTIONAL=y
|
||||
CONFIG_RANDSTRUCT_NONE=y
|
||||
CONFIG_RATIONAL=y
|
||||
CONFIG_REALTEK_OTTO_TIMER=y
|
||||
CONFIG_REALTEK_OTTO_WDT=y
|
||||
CONFIG_REALTEK_PHY=y
|
||||
CONFIG_REALTEK_PHY_HWMON=y
|
||||
CONFIG_REALTEK_SOC_PHY=y
|
||||
CONFIG_REALTEK_THERMAL=y
|
||||
CONFIG_REGMAP=y
|
||||
CONFIG_REGMAP_I2C=y
|
||||
CONFIG_REGMAP_MDIO=y
|
||||
CONFIG_REGMAP_MMIO=y
|
||||
CONFIG_RESET_CONTROLLER=y
|
||||
CONFIG_RTL838X=y
|
||||
# CONFIG_RTL839X is not set
|
||||
# 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_SQUASHFS_DECOMP_MULTI_PERCPU=y
|
||||
CONFIG_SRAM=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_THERMAL=y
|
||||
# CONFIG_THERMAL_DEFAULT_GOV_FAIR_SHARE is not set
|
||||
CONFIG_THERMAL_DEFAULT_GOV_STEP_WISE=y
|
||||
# CONFIG_THERMAL_DEFAULT_GOV_USER_SPACE is not set
|
||||
CONFIG_THERMAL_EMERGENCY_POWEROFF_DELAY_MS=0
|
||||
CONFIG_THERMAL_GOV_STEP_WISE=y
|
||||
CONFIG_THERMAL_HWMON=y
|
||||
CONFIG_THERMAL_OF=y
|
||||
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,276 +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_CLONE_BACKWARDS=y
|
||||
CONFIG_COMMON_CLK=y
|
||||
CONFIG_COMMON_CLK_REALTEK=y
|
||||
CONFIG_COMMON_CLK_RTL83XX=y
|
||||
CONFIG_COMPACT_UNEVICTABLE_DEFAULT=1
|
||||
CONFIG_COMPAT_32BIT_TIME=y
|
||||
CONFIG_CONSOLE_LOGLEVEL_DEFAULT=15
|
||||
CONFIG_CONTEXT_TRACKING=y
|
||||
CONFIG_CONTEXT_TRACKING_IDLE=y
|
||||
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_MITIGATIONS=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_GF128MUL=y
|
||||
CONFIG_CRYPTO_LIB_POLY1305_RSIZE=2
|
||||
CONFIG_CRYPTO_LIB_SHA1=y
|
||||
CONFIG_CRYPTO_LIB_UTILS=y
|
||||
CONFIG_DEBUG_INFO=y
|
||||
CONFIG_DEBUG_SECTION_MISMATCH=y
|
||||
CONFIG_DMA_NONCOHERENT=y
|
||||
CONFIG_DTC=y
|
||||
CONFIG_EARLY_PRINTK=y
|
||||
CONFIG_EARLY_PRINTK_8250=y
|
||||
CONFIG_EXCLUSIVE_SYSTEM_RAM=y
|
||||
CONFIG_FIXED_PHY=y
|
||||
CONFIG_FS_IOMAP=y
|
||||
CONFIG_FUNCTION_ALIGNMENT=0
|
||||
CONFIG_FWNODE_MDIO=y
|
||||
CONFIG_FW_LOADER_PAGED_BUF=y
|
||||
CONFIG_FW_LOADER_SYSFS=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_GETTIMEOFDAY=y
|
||||
CONFIG_GENERIC_IDLE_POLL_SETUP=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_REGMAP=y
|
||||
CONFIG_GPIO_WATCHDOG=y
|
||||
# CONFIG_GPIO_WATCHDOG_ARCH_INITCALL is not set
|
||||
CONFIG_GRO_CELLS=y
|
||||
CONFIG_HARDWARE_WATCHPOINTS=y
|
||||
CONFIG_HAS_DMA=y
|
||||
CONFIG_HAS_IOMEM=y
|
||||
CONFIG_HAS_IOPORT=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_MUX_RTL9300 is not set
|
||||
# CONFIG_I2C_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_LEDS_RTL8231 is not set
|
||||
CONFIG_LIBFDT=y
|
||||
CONFIG_LOCK_DEBUGGING_SUPPORT=y
|
||||
CONFIG_MACH_REALTEK_RTL=y
|
||||
CONFIG_MARVELL_PHY=y
|
||||
CONFIG_MDIO_BUS=y
|
||||
CONFIG_MDIO_DEVICE=y
|
||||
CONFIG_MDIO_DEVRES=y
|
||||
CONFIG_MDIO_I2C=y
|
||||
CONFIG_MDIO_REALTEK_OTTO_AUX=y
|
||||
CONFIG_MDIO_SMBUS=y
|
||||
CONFIG_MFD_CORE=y
|
||||
CONFIG_MFD_RTL8231=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_EXTERNAL_TIMER=y
|
||||
CONFIG_MIPS_L1_CACHE_SHIFT=5
|
||||
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_MMU_LAZY_TLB_REFCOUNT=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_SRCU_NMI_SAFE=y
|
||||
CONFIG_NET_DEVLINK=y
|
||||
CONFIG_NET_DSA=y
|
||||
CONFIG_NET_DSA_RTL83XX=y
|
||||
CONFIG_NET_DSA_TAG_TRAILER=y
|
||||
CONFIG_NET_EGRESS=y
|
||||
CONFIG_NET_FLOW_LIMIT=y
|
||||
CONFIG_NET_INGRESS=y
|
||||
CONFIG_NET_RTL838X=y
|
||||
CONFIG_NET_SELFTESTS=y
|
||||
CONFIG_NET_XGRESS=y
|
||||
CONFIG_NO_EXCEPT_FILL=y
|
||||
CONFIG_NO_GENERIC_PCI_IOPORT_MAP=y
|
||||
CONFIG_NR_CPUS=2
|
||||
CONFIG_NVMEM=y
|
||||
CONFIG_NVMEM_LAYOUTS=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_PAGE_POOL=y
|
||||
CONFIG_PAGE_SIZE_LESS_THAN_256KB=y
|
||||
CONFIG_PAGE_SIZE_LESS_THAN_64KB=y
|
||||
CONFIG_PCI_DRIVERS_LEGACY=y
|
||||
CONFIG_PERF_USE_VMALLOC=y
|
||||
CONFIG_PGTABLE_LEVELS=2
|
||||
CONFIG_PHYLIB=y
|
||||
CONFIG_PHYLIB_LEDS=y
|
||||
CONFIG_PHYLINK=y
|
||||
CONFIG_PINCTRL=y
|
||||
CONFIG_PINCTRL_RTL8231=y
|
||||
CONFIG_PM_OPP=y
|
||||
CONFIG_POWER_RESET=y
|
||||
CONFIG_POWER_RESET_GPIO_RESTART=y
|
||||
CONFIG_POWER_RESET_SYSCON=y
|
||||
CONFIG_PREEMPT_NONE_BUILD=y
|
||||
CONFIG_PTP_1588_CLOCK_OPTIONAL=y
|
||||
CONFIG_QUEUED_RWLOCKS=y
|
||||
CONFIG_QUEUED_SPINLOCKS=y
|
||||
CONFIG_RANDSTRUCT_NONE=y
|
||||
CONFIG_RATIONAL=y
|
||||
CONFIG_REALTEK_OTTO_TIMER=y
|
||||
CONFIG_REALTEK_OTTO_WDT=y
|
||||
CONFIG_REALTEK_PHY=y
|
||||
CONFIG_REALTEK_PHY_HWMON=y
|
||||
CONFIG_REALTEK_SOC_PHY=y
|
||||
CONFIG_REALTEK_THERMAL=y
|
||||
CONFIG_REGMAP=y
|
||||
CONFIG_REGMAP_I2C=y
|
||||
CONFIG_REGMAP_MDIO=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_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_SQUASHFS_DECOMP_MULTI_PERCPU=y
|
||||
CONFIG_SRAM=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_THERMAL=y
|
||||
# CONFIG_THERMAL_DEFAULT_GOV_FAIR_SHARE is not set
|
||||
CONFIG_THERMAL_DEFAULT_GOV_STEP_WISE=y
|
||||
# CONFIG_THERMAL_DEFAULT_GOV_USER_SPACE is not set
|
||||
CONFIG_THERMAL_EMERGENCY_POWEROFF_DELAY_MS=0
|
||||
CONFIG_THERMAL_GOV_STEP_WISE=y
|
||||
CONFIG_THERMAL_HWMON=y
|
||||
CONFIG_THERMAL_OF=y
|
||||
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_XPS=y
|
||||
CONFIG_ZLIB_DEFLATE=y
|
||||
CONFIG_ZLIB_INFLATE=y
|
|
@ -1,236 +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_COMPACT_UNEVICTABLE_DEFAULT=1
|
||||
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_MITIGATIONS=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_CRC_CCITT=y
|
||||
CONFIG_CRYPTO_LIB_BLAKE2S_GENERIC=y
|
||||
CONFIG_CRYPTO_LIB_GF128MUL=y
|
||||
CONFIG_CRYPTO_LIB_POLY1305_RSIZE=2
|
||||
CONFIG_CRYPTO_LIB_SHA1=y
|
||||
CONFIG_CRYPTO_LIB_UTILS=y
|
||||
CONFIG_DEBUG_INFO=y
|
||||
CONFIG_DEBUG_SECTION_MISMATCH=y
|
||||
CONFIG_DMA_NONCOHERENT=y
|
||||
CONFIG_DTC=y
|
||||
CONFIG_EARLY_PRINTK=y
|
||||
CONFIG_EARLY_PRINTK_8250=y
|
||||
CONFIG_EXCLUSIVE_SYSTEM_RAM=y
|
||||
CONFIG_FIXED_PHY=y
|
||||
CONFIG_FORCE_NR_CPUS=y
|
||||
CONFIG_FS_IOMAP=y
|
||||
CONFIG_FUNCTION_ALIGNMENT=0
|
||||
CONFIG_FWNODE_MDIO=y
|
||||
CONFIG_FW_LOADER_PAGED_BUF=y
|
||||
CONFIG_FW_LOADER_SYSFS=y
|
||||
CONFIG_GENERIC_ATOMIC64=y
|
||||
CONFIG_GENERIC_CLOCKEVENTS=y
|
||||
CONFIG_GENERIC_CMOS_UPDATE=y
|
||||
CONFIG_GENERIC_CPU_AUTOPROBE=y
|
||||
CONFIG_GENERIC_GETTIMEOFDAY=y
|
||||
CONFIG_GENERIC_IDLE_POLL_SETUP=y
|
||||
CONFIG_GENERIC_IOMAP=y
|
||||
CONFIG_GENERIC_IRQ_CHIP=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_GRO_CELLS=y
|
||||
CONFIG_HARDWARE_WATCHPOINTS=y
|
||||
CONFIG_HAS_DMA=y
|
||||
CONFIG_HAS_IOMEM=y
|
||||
CONFIG_HAS_IOPORT=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_FORCED_THREADING=y
|
||||
CONFIG_IRQ_MIPS_CPU=y
|
||||
CONFIG_IRQ_WORK=y
|
||||
CONFIG_JFFS2_ZLIB=y
|
||||
CONFIG_LEDS_GPIO=y
|
||||
# CONFIG_LEDS_RTL8231 is not set
|
||||
CONFIG_LIBFDT=y
|
||||
CONFIG_LOCK_DEBUGGING_SUPPORT=y
|
||||
CONFIG_MACH_REALTEK_RTL=y
|
||||
CONFIG_MARVELL_PHY=y
|
||||
CONFIG_MDIO_BUS=y
|
||||
CONFIG_MDIO_DEVICE=y
|
||||
CONFIG_MDIO_DEVRES=y
|
||||
CONFIG_MDIO_I2C=y
|
||||
CONFIG_MDIO_REALTEK_OTTO_AUX=y
|
||||
CONFIG_MDIO_SMBUS=y
|
||||
CONFIG_MFD_RTL8231=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_EXTERNAL_TIMER=y
|
||||
CONFIG_MIPS_L1_CACHE_SHIFT=5
|
||||
# CONFIG_MIPS_MT_SMP is not set
|
||||
# CONFIG_MIPS_NO_APPENDED_DTB is not set
|
||||
CONFIG_MIPS_RAW_APPENDED_DTB=y
|
||||
CONFIG_MIPS_SPRAM=y
|
||||
CONFIG_MMU_LAZY_TLB_REFCOUNT=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_EGRESS=y
|
||||
CONFIG_NET_INGRESS=y
|
||||
CONFIG_NET_RTL838X=y
|
||||
CONFIG_NET_SELFTESTS=y
|
||||
CONFIG_NET_XGRESS=y
|
||||
CONFIG_NO_EXCEPT_FILL=y
|
||||
CONFIG_NO_GENERIC_PCI_IOPORT_MAP=y
|
||||
CONFIG_NVMEM=y
|
||||
CONFIG_NVMEM_LAYOUTS=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_PAGE_POOL=y
|
||||
CONFIG_PAGE_SIZE_LESS_THAN_256KB=y
|
||||
CONFIG_PAGE_SIZE_LESS_THAN_64KB=y
|
||||
CONFIG_PCI_DRIVERS_LEGACY=y
|
||||
CONFIG_PERF_USE_VMALLOC=y
|
||||
CONFIG_PGTABLE_LEVELS=2
|
||||
CONFIG_PHYLIB=y
|
||||
CONFIG_PHYLIB_LEDS=y
|
||||
CONFIG_PHYLINK=y
|
||||
CONFIG_PINCTRL=y
|
||||
CONFIG_PINCTRL_RTL8231=y
|
||||
CONFIG_POWER_RESET=y
|
||||
CONFIG_POWER_RESET_GPIO_RESTART=y
|
||||
CONFIG_POWER_RESET_SYSCON=y
|
||||
CONFIG_PREEMPT_NONE_BUILD=y
|
||||
CONFIG_PTP_1588_CLOCK_OPTIONAL=y
|
||||
CONFIG_RANDSTRUCT_NONE=y
|
||||
CONFIG_RATIONAL=y
|
||||
CONFIG_REALTEK_OTTO_TIMER=y
|
||||
CONFIG_REALTEK_OTTO_WDT=y
|
||||
CONFIG_REALTEK_PHY=y
|
||||
CONFIG_REALTEK_PHY_HWMON=y
|
||||
CONFIG_REALTEK_SOC_PHY=y
|
||||
CONFIG_REALTEK_THERMAL=y
|
||||
CONFIG_REGMAP=y
|
||||
CONFIG_REGMAP_I2C=y
|
||||
CONFIG_REGMAP_MDIO=y
|
||||
CONFIG_REGMAP_MMIO=y
|
||||
CONFIG_RESET_CONTROLLER=y
|
||||
# CONFIG_RTL838X is not set
|
||||
# CONFIG_RTL839X is not set
|
||||
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_SQUASHFS_DECOMP_MULTI_PERCPU=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_THERMAL=y
|
||||
# CONFIG_THERMAL_DEFAULT_GOV_FAIR_SHARE is not set
|
||||
CONFIG_THERMAL_DEFAULT_GOV_STEP_WISE=y
|
||||
# CONFIG_THERMAL_DEFAULT_GOV_USER_SPACE is not set
|
||||
CONFIG_THERMAL_EMERGENCY_POWEROFF_DELAY_MS=0
|
||||
CONFIG_THERMAL_GOV_STEP_WISE=y
|
||||
CONFIG_THERMAL_HWMON=y
|
||||
CONFIG_THERMAL_OF=y
|
||||
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,259 +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_CLKSRC_MIPS_GIC=y
|
||||
CONFIG_CLOCKSOURCE_WATCHDOG=y
|
||||
CONFIG_CLOCKSOURCE_WATCHDOG_MAX_SKEW_US=125
|
||||
CONFIG_CLONE_BACKWARDS=y
|
||||
CONFIG_COMMON_CLK=y
|
||||
# CONFIG_COMMON_CLK_REALTEK is not set
|
||||
CONFIG_COMPACT_UNEVICTABLE_DEFAULT=1
|
||||
CONFIG_COMPAT_32BIT_TIME=y
|
||||
CONFIG_CONSOLE_LOGLEVEL_DEFAULT=15
|
||||
CONFIG_CONTEXT_TRACKING=y
|
||||
CONFIG_CONTEXT_TRACKING_IDLE=y
|
||||
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_MITIGATIONS=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_GF128MUL=y
|
||||
CONFIG_CRYPTO_LIB_POLY1305_RSIZE=2
|
||||
CONFIG_CRYPTO_LIB_SHA1=y
|
||||
CONFIG_CRYPTO_LIB_UTILS=y
|
||||
CONFIG_DEBUG_INFO=y
|
||||
CONFIG_DEBUG_SECTION_MISMATCH=y
|
||||
CONFIG_DMA_NONCOHERENT=y
|
||||
CONFIG_DTC=y
|
||||
CONFIG_EARLY_PRINTK=y
|
||||
CONFIG_EARLY_PRINTK_8250=y
|
||||
CONFIG_EXCLUSIVE_SYSTEM_RAM=y
|
||||
CONFIG_FIXED_PHY=y
|
||||
CONFIG_FS_IOMAP=y
|
||||
CONFIG_FUNCTION_ALIGNMENT=0
|
||||
CONFIG_FWNODE_MDIO=y
|
||||
CONFIG_FW_LOADER_PAGED_BUF=y
|
||||
CONFIG_FW_LOADER_SYSFS=y
|
||||
CONFIG_GENERIC_ATOMIC64=y
|
||||
CONFIG_GENERIC_CLOCKEVENTS=y
|
||||
CONFIG_GENERIC_CMOS_UPDATE=y
|
||||
CONFIG_GENERIC_CPU_AUTOPROBE=y
|
||||
CONFIG_GENERIC_GETTIMEOFDAY=y
|
||||
CONFIG_GENERIC_IDLE_POLL_SETUP=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_GRO_CELLS=y
|
||||
CONFIG_HARDWARE_WATCHPOINTS=y
|
||||
CONFIG_HAS_DMA=y
|
||||
CONFIG_HAS_IOMEM=y
|
||||
CONFIG_HAS_IOPORT=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_MACH_REALTEK_RTL=y
|
||||
CONFIG_MARVELL_PHY=y
|
||||
CONFIG_MDIO_BUS=y
|
||||
CONFIG_MDIO_DEVICE=y
|
||||
CONFIG_MDIO_DEVRES=y
|
||||
CONFIG_MDIO_I2C=y
|
||||
# CONFIG_MDIO_REALTEK_OTTO_AUX is not set
|
||||
CONFIG_MDIO_SMBUS=y
|
||||
# CONFIG_MFD_RTL8231 is not set
|
||||
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_EXTERNAL_TIMER=y
|
||||
CONFIG_MIPS_GIC=y
|
||||
CONFIG_MIPS_L1_CACHE_SHIFT=5
|
||||
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_MMU_LAZY_TLB_REFCOUNT=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_SRCU_NMI_SAFE=y
|
||||
CONFIG_NET_DEVLINK=y
|
||||
CONFIG_NET_DSA=y
|
||||
CONFIG_NET_DSA_RTL83XX=y
|
||||
CONFIG_NET_DSA_TAG_TRAILER=y
|
||||
CONFIG_NET_EGRESS=y
|
||||
CONFIG_NET_FLOW_LIMIT=y
|
||||
CONFIG_NET_INGRESS=y
|
||||
CONFIG_NET_RTL838X=y
|
||||
CONFIG_NET_SELFTESTS=y
|
||||
CONFIG_NET_XGRESS=y
|
||||
CONFIG_NO_EXCEPT_FILL=y
|
||||
CONFIG_NO_GENERIC_PCI_IOPORT_MAP=y
|
||||
CONFIG_NR_CPUS=4
|
||||
CONFIG_NVMEM=y
|
||||
CONFIG_NVMEM_LAYOUTS=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_PAGE_POOL=y
|
||||
CONFIG_PAGE_SIZE_LESS_THAN_256KB=y
|
||||
CONFIG_PAGE_SIZE_LESS_THAN_64KB=y
|
||||
CONFIG_PCI_DRIVERS_LEGACY=y
|
||||
CONFIG_PERF_USE_VMALLOC=y
|
||||
CONFIG_PGTABLE_LEVELS=2
|
||||
CONFIG_PHYLIB=y
|
||||
CONFIG_PHYLIB_LEDS=y
|
||||
CONFIG_PHYLINK=y
|
||||
CONFIG_PINCTRL=y
|
||||
CONFIG_POWER_RESET=y
|
||||
CONFIG_POWER_RESET_SYSCON=y
|
||||
CONFIG_PREEMPT_NONE_BUILD=y
|
||||
CONFIG_PTP_1588_CLOCK_OPTIONAL=y
|
||||
CONFIG_QUEUED_RWLOCKS=y
|
||||
CONFIG_QUEUED_SPINLOCKS=y
|
||||
CONFIG_RANDSTRUCT_NONE=y
|
||||
CONFIG_RATIONAL=y
|
||||
# CONFIG_REALTEK_OTTO_TIMER is not set
|
||||
CONFIG_REALTEK_OTTO_WDT=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 is not set
|
||||
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_SQUASHFS_DECOMP_MULTI_PERCPU=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 a new issue