diff options
author | Birger Koblitz <git@birger-koblitz.de> | 2020-09-13 09:06:13 +0200 |
---|---|---|
committer | John Crispin <john@phrozen.org> | 2020-09-14 07:54:30 +0200 |
commit | df8e6be59a1fbce3f8c6878fe7440a129b1245d6 (patch) | |
tree | f7dc2da525ff9ef48b5609e96484c759a5b38e6f /target/linux/rtl838x/files-5.4/arch | |
parent | 7bb1bd469e98ba4bfd0cf774a82c35039c9b721a (diff) | |
download | upstream-df8e6be59a1fbce3f8c6878fe7440a129b1245d6.tar.gz upstream-df8e6be59a1fbce3f8c6878fe7440a129b1245d6.tar.bz2 upstream-df8e6be59a1fbce3f8c6878fe7440a129b1245d6.zip |
rtl838x: add new architecture
This adds support for the RTL838x Architecture.
SoCs of this type are used in managed and un-managed Switches and Routers
with 8-28 ports. Drivers are provided for SoC initialization, GPIOs, Flash,
Ethernet including a DSA switch driver and internal and external PHYs used
with these switches.
Supported SoCs:
RTL8380M
RTL8381M
RTL8382M
The kernel will also boot on the following RTL839x SoCs, however driver
support apart from spi-nor is missing:
RTL8390
RTL8391
RTL8393
The following PHYs are supported:
RTL8214FC (Quad QSGMII multiplexing GMAC and SFP port)
RTL8218B internal: internal PHY of the RTL838x chips
RTL8318b external (QSGMII 8-port GMAC phy)
RTL8382M SerDes for 2 SFP ports
Initialization sequences for the PHYs are provided in the form of
firmware files.
Flash driver supports 3 / 4 byte access
DSA switch driver supports VLANs, port isolation, STP and port mirroring.
The ALLNET ALL-SG8208M is supported as Proof of Concept:
RTL8382M SoC
1 MIPS 4KEc core @ 500MHz
8 Internal PHYs (RTL8218B)
128MB DRAM (Nanya NT5TU128MB)
16MB NOR Flash (MXIC 25L128)
8 GBEthernet ports with one green status LED each (SoC controlled)
1 Power LED (not configurable)
1 SYS LED (configurable)
1 On-Off switch (not configurable)
1 Reset button at the right behind right air-vent (not configurable)
1 Reset button on front panel (configurable)
12V 1A barrel connector
1 serial header with populated standard pin connector and with markings
GND TX RX Vcc(3.3V), connection properties: 115200 8N1
To install, upload the sysupgrade image to the OEM webpage.
Signed-off-by: Birger Koblitz <git@birger-koblitz.de>
Diffstat (limited to 'target/linux/rtl838x/files-5.4/arch')
9 files changed, 1207 insertions, 0 deletions
diff --git a/target/linux/rtl838x/files-5.4/arch/mips/include/asm/mach-rtl838x/ioremap.h b/target/linux/rtl838x/files-5.4/arch/mips/include/asm/mach-rtl838x/ioremap.h new file mode 100644 index 0000000000..e7a5bfaffc --- /dev/null +++ b/target/linux/rtl838x/files-5.4/arch/mips/include/asm/mach-rtl838x/ioremap.h @@ -0,0 +1,34 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +#ifndef RTL838X_IOREMAP_H_ +#define RTL838X_IOREMAP_H_ + +static inline phys_addr_t fixup_bigphys_addr(phys_addr_t phys_addr, phys_addr_t size) +{ + return phys_addr; +} + +static inline int is_rtl838x_internal_registers(phys_addr_t offset) +{ + /* IO-Block */ + if (offset >= 0xb8000000 && offset < 0xb9000000) + return 1; + /* Switch block */ + if (offset >= 0xbb000000 && offset < 0xbc000000) + return 1; + return 0; +} + +static inline void __iomem *plat_ioremap(phys_addr_t offset, unsigned long size, + unsigned long flags) +{ + if (is_rtl838x_internal_registers(offset)) + return (void __iomem *)offset; + return NULL; +} + +static inline int plat_iounmap(const volatile void __iomem *addr) +{ + return is_rtl838x_internal_registers((unsigned long)addr); +} + +#endif diff --git a/target/linux/rtl838x/files-5.4/arch/mips/include/asm/mach-rtl838x/irq.h b/target/linux/rtl838x/files-5.4/arch/mips/include/asm/mach-rtl838x/irq.h new file mode 100644 index 0000000000..e821111c5d --- /dev/null +++ b/target/linux/rtl838x/files-5.4/arch/mips/include/asm/mach-rtl838x/irq.h @@ -0,0 +1,10 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +#ifndef __ASM_MACH_RTL838X_IRQ_H +#define __ASM_MACH_RTL838X_IRQ_H + +#define MIPS_CPU_IRQ_BASE 0 +#define NR_IRQS 64 + +#include_next <irq.h> + +#endif /* __ASM_MACH_ATH79_IRQ_H */ diff --git a/target/linux/rtl838x/files-5.4/arch/mips/include/asm/mach-rtl838x/mach-rtl838x.h b/target/linux/rtl838x/files-5.4/arch/mips/include/asm/mach-rtl838x/mach-rtl838x.h new file mode 100644 index 0000000000..cece36635c --- /dev/null +++ b/target/linux/rtl838x/files-5.4/arch/mips/include/asm/mach-rtl838x/mach-rtl838x.h @@ -0,0 +1,428 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (C) 2006-2012 Tony Wu (tonywu@realtek.com) + * Copyright (C) 2020 B. Koblitz + */ +#ifndef _MACH_RTL838X_H_ +#define _MACH_RTL838X_H_ + +/* + * Register access macros + */ + +#define RTL838X_SW_BASE ((volatile void *) 0xBB000000) + +#define rtl838x_r32(reg) __raw_readl(reg) +#define rtl838x_w32(val, reg) __raw_writel(val, reg) +#define rtl838x_w32_mask(clear, set, reg) rtl838x_w32((rtl838x_r32(reg) & ~(clear)) | (set), reg) + +#define sw_r32(reg) __raw_readl(RTL838X_SW_BASE + reg) +#define sw_w32(val, reg) __raw_writel(val, RTL838X_SW_BASE + reg) +#define sw_w32_mask(clear, set, reg) \ + sw_w32((sw_r32(reg) & ~(clear)) | (set), reg) + +#define sw_r64(reg) ((((u64)__raw_readl(RTL838X_SW_BASE + reg)) << 32) | \ + __raw_readl(RTL838X_SW_BASE + reg + 4)) + +#define sw_w64(val, reg) do { \ + __raw_writel((u32)((val) >> 32), RTL838X_SW_BASE + reg); \ + __raw_writel((u32)((val) & 0xffffffff), \ + RTL838X_SW_BASE + reg + 4); \ + } while (0) + +/* + * SPRAM + */ +#define RTL838X_ISPRAM_BASE 0x0 +#define RTL838X_DSPRAM_BASE 0x0 + +/* + * IRQ Controller + */ +#define RTL838X_IRQ_CPU_BASE 0 +#define RTL838X_IRQ_CPU_NUM 8 +#define RTL838X_IRQ_ICTL_BASE (RTL838X_IRQ_CPU_BASE + RTL838X_IRQ_CPU_NUM) +#define RTL838X_IRQ_ICTL_NUM 32 + +/* + * MIPS32R2 counter + */ +#define RTL838X_COMPARE_IRQ (RTL838X_IRQ_CPU_BASE + 7) + +/* + * ICTL + * Base address 0xb8003000UL + */ +#define RTL838X_ICTL1_IRQ (RTL838X_IRQ_CPU_BASE + 2) +#define RTL838X_ICTL2_IRQ (RTL838X_IRQ_CPU_BASE + 3) +#define RTL838X_ICTL3_IRQ (RTL838X_IRQ_CPU_BASE + 4) +#define RTL838X_ICTL4_IRQ (RTL838X_IRQ_CPU_BASE + 5) +#define RTL838X_ICTL5_IRQ (RTL838X_IRQ_CPU_BASE + 6) + +#define GIMR (0x00) +#define UART0_IE (1 << 31) +#define UART1_IE (1 << 30) +#define TC0_IE (1 << 29) +#define TC1_IE (1 << 28) +#define OCPTO_IE (1 << 27) +#define HLXTO_IE (1 << 26) +#define SLXTO_IE (1 << 25) +#define NIC_IE (1 << 24) +#define GPIO_ABCD_IE (1 << 23) +#define GPIO_EFGH_IE (1 << 22) +#define RTC_IE (1 << 21) +#define WDT_IP1_IE (1 << 19) +#define WDT_IP2_IE (1 << 18) + +#define GISR (0x04) +#define UART0_IP (1 << 31) +#define UART1_IP (1 << 30) +#define TC0_IP (1 << 29) +#define TC1_IP (1 << 28) +#define OCPTO_IP (1 << 27) +#define HLXTO_IP (1 << 26) +#define SLXTO_IP (1 << 25) +#define NIC_IP (1 << 24) +#define GPIO_ABCD_IP (1 << 23) +#define GPIO_EFGH_IP (1 << 22) +#define RTC_IP (1 << 21) +#define WDT_IP1_IP (1 << 19) +#define WDT_IP2_IP (1 << 18) + +#define IRR0 (0x08) +#define IRR0_SETTING ((UART0_RS << 28) | \ + (UART1_RS << 24) | \ + (TC0_RS << 20) | \ + (TC1_RS << 16) | \ + (OCPTO_RS << 12) | \ + (HLXTO_RS << 8) | \ + (SLXTO_RS << 4) | \ + (NIC_RS << 0) \ + ) + +#define IRR1 (0x0c) + +#define IRR1_SETTING ((GPIO_ABCD_RS << 28) | \ + (GPIO_EFGH_RS << 24) | \ + (RTC_RS << 20) | \ + (SWCORE_RS << 16) \ + ) + +#define IRR2 (0x10) +#define IRR2_SETTING 0 + +#define IRR3 (0x14) +#define IRR3_SETTING 0 + +/* Interrupt Routing Selection */ +#define UART0_RS 2 +#define UART1_RS 1 +#define TC0_RS 5 +#define TC1_RS 1 +#define OCPTO_RS 1 +#define HLXTO_RS 1 +#define SLXTO_RS 1 +#define NIC_RS 4 +#define GPIO_ABCD_RS 4 +#define GPIO_EFGH_RS 4 +#define RTC_RS 4 +#define SWCORE_RS 3 +#define WDT_IP1_RS 4 +#define WDT_IP2_RS 5 + +/* Interrupt IRQ Assignments */ +#define UART0_IRQ 31 +#define UART1_IRQ 30 +#define TC0_IRQ 29 +#define TC1_IRQ 28 +#define OCPTO_IRQ 27 +#define HLXTO_IRQ 26 +#define SLXTO_IRQ 25 +#define NIC_IRQ 24 +#define GPIO_ABCD_IRQ 23 +#define GPIO_EFGH_IRQ 22 +#define RTC_IRQ 21 +#define SWCORE_IRQ 20 +#define WDT_IP1_IRQ 19 +#define WDT_IP2_IRQ 18 + +#define SYSTEM_FREQ 200000000 +#define RTL838X_UART0_BASE ((volatile void *)(0xb8002000UL)) +#define RTL838X_UART0_BAUD 38400 /* ex. 19200 or 38400 or 57600 or 115200 */ +#define RTL838X_UART0_FREQ (SYSTEM_FREQ - RTL838X_UART0_BAUD * 24) +#define RTL838X_UART0_MAPBASE 0x18002000UL +#define RTL838X_UART0_MAPSIZE 0x100 +#define RTL838X_UART0_IRQ UART0_IRQ + +#define RTL838X_UART1_BASE ((volatile void *)(0xb8002100UL)) +#define RTL838X_UART1_BAUD 38400 /* ex. 19200 or 38400 or 57600 or 115200 */ +#define RTL838X_UART1_FREQ (SYSTEM_FREQ - RTL838X_UART1_BAUD * 24) +#define RTL838X_UART1_MAPBASE 0x18002100UL +#define RTL838X_UART1_MAPSIZE 0x100 +#define RTL838X_UART1_IRQ UART1_IRQ + +#define UART0_RBR (RTL838X_UART0_BASE + 0x000) +#define UART0_THR (RTL838X_UART0_BASE + 0x000) +#define UART0_DLL (RTL838X_UART0_BASE + 0x000) +#define UART0_IER (RTL838X_UART0_BASE + 0x004) +#define UART0_DLM (RTL838X_UART0_BASE + 0x004) +#define UART0_IIR (RTL838X_UART0_BASE + 0x008) +#define UART0_FCR (RTL838X_UART0_BASE + 0x008) +#define UART0_LCR (RTL838X_UART0_BASE + 0x00C) +#define UART0_MCR (RTL838X_UART0_BASE + 0x010) +#define UART0_LSR (RTL838X_UART0_BASE + 0x014) + +#define UART1_RBR (RTL838X_UART1_BASE + 0x000) +#define UART1_THR (RTL838X_UART1_BASE + 0x000) +#define UART1_DLL (RTL838X_UART1_BASE + 0x000) +#define UART1_IER (RTL838X_UART1_BASE + 0x004) +#define UART1_DLM (RTL838X_UART1_BASE + 0x004) +#define UART1_IIR (RTL838X_UART1_BASE + 0x008) +#define UART1_FCR (RTL838X_UART1_BASE + 0x008) + #define FCR_EN 0x01 + #define FCR_RXRST 0x02 + #define XRST 0x02 + #define FCR_TXRST 0x04 + #define TXRST 0x04 + #define FCR_DMA 0x08 + #define FCR_RTRG 0xC0 + #define CHAR_TRIGGER_01 0x00 + #define CHAR_TRIGGER_04 0x40 + #define CHAR_TRIGGER_08 0x80 + #define CHAR_TRIGGER_14 0xC0 +#define UART1_LCR (RTL838X_UART1_BASE + 0x00C) + #define LCR_WLN 0x03 + #define CHAR_LEN_5 0x00 + #define CHAR_LEN_6 0x01 + #define CHAR_LEN_7 0x02 + #define CHAR_LEN_8 0x03 + #define LCR_STB 0x04 + #define ONE_STOP 0x00 + #define TWO_STOP 0x04 + #define LCR_PEN 0x08 + #define PARITY_ENABLE 0x01 + #define PARITY_DISABLE 0x00 + #define LCR_EPS 0x30 + #define PARITY_ODD 0x00 + #define PARITY_EVEN 0x10 + #define PARITY_MARK 0x20 + #define PARITY_SPACE 0x30 + #define LCR_BRK 0x40 + #define LCR_DLAB 0x80 + #define DLAB 0x80 +#define UART1_MCR (RTL838X_UART1_BASE + 0x010) +#define UART1_LSR (RTL838X_UART1_BASE + 0x014) + #define LSR_DR 0x01 + #define RxCHAR_AVAIL 0x01 + #define LSR_OE 0x02 + #define LSR_PE 0x04 + #define LSR_FE 0x08 + #define LSR_BI 0x10 + #define LSR_THRE 0x20 + #define TxCHAR_AVAIL 0x00 + #define TxCHAR_EMPTY 0x20 + #define LSR_TEMT 0x40 + #define LSR_RFE 0x80 + +/* + * Timer/counter for 8390/80/28 TC & MP chip + */ +#define RTL838X_TIMER0_BASE ((volatile void *)(0xb8003100UL)) +#define RTL838X_TIMER0_IRQ RTL838X_TC0_EXT_IRQ + +#define RTL8390TC_TC1DATA (RTL838X_TIMER0_BASE + 0x04) +#define RTL8390TC_TCD_OFFSET 8 +#define RTL8390TC_TC0CNT (RTL838X_TIMER0_BASE + 0x08) +#define RTL8390TC_TC1CNT (RTL838X_TIMER0_BASE + 0x0C) +#define RTL8390TC_TCCNR (RTL838X_TIMER0_BASE + 0x10) +#define RTL8390TC_TC0EN (1 << 31) +#define RTL8390TC_TC0MODE_TIMER (1 << 30) +#define RTL8390TC_TC1EN (1 << 29) +#define RTL8390TC_TC1MODE_TIMER (1 << 28) +#define RTL8390TC_TCIR (RTL838X_TIMER0_BASE + 0x14) +#define RTL8390TC_TC0IE (1 << 31) +#define RTL8390TC_TC1IE (1 << 30) +#define RTL8390TC_TC0IP (1 << 29) +#define RTL8390TC_TC1IP (1 << 28) +#define RTL8390TC_CDBR (RTL838X_TIMER0_BASE + 0x18) +#define RTL8390TC_DIVF_OFFSET 16 +#define RTL8390TC_WDTCNR (RTL838X_TIMER0_BASE + 0x1C) + +#define RTL8390MP_TC1DATA (RTL838X_TIMER0_BASE + 0x10) +#define RTL8390MP_TC0CNT (RTL838X_TIMER0_BASE + 0x04) +#define RTL8390MP_TC1CNT (RTL838X_TIMER0_BASE + 0x14) +#define RTL8390MP_TC0CTL (RTL838X_TIMER0_BASE + 0x08) +#define RTL8390MP_TC1CTL (RTL838X_TIMER0_BASE + 0x18) +#define RTL8390MP_TCEN (1 << 28) +#define RTL8390MP_TCMODE_TIMER (1 << 24) +#define RTL8390MP_TCDIV_FACTOR (0xFFFF << 0) +#define RTL8390MP_TC0INT (RTL838X_TIMER0_BASE + 0xC) +#define RTL8390MP_TC1INT (RTL838X_TIMER0_BASE + 0x1C) +#define RTL8390MP_TCIE (1 << 20) +#define RTL8390MP_TCIP (1 << 16) +#define RTL8390MP_WDTCNR (RTL838X_TIMER0_BASE + 0x50) + +#define RTL8380MP_TC0DATA (RTL838X_TIMER0_BASE + 0x00) +#define RTL8380MP_TC1DATA (RTL838X_TIMER0_BASE + 0x10) +#define RTL8380MP_TC0CNT (RTL838X_TIMER0_BASE + 0x04) +#define RTL8380MP_TC1CNT (RTL838X_TIMER0_BASE + 0x14) +#define RTL8380MP_TC0CTL (RTL838X_TIMER0_BASE + 0x08) +#define RTL8380MP_TC1CTL (RTL838X_TIMER0_BASE + 0x18) +#define RTL8380MP_TCEN (1 << 28) +#define RTL8380MP_TCMODE_TIMER (1 << 24) +#define RTL8380MP_TCDIV_FACTOR (0xFFFF << 0) +#define RTL8380MP_TC0INT (RTL838X_TIMER0_BASE + 0xC) +#define RTL8380MP_TC1INT (RTL838X_TIMER0_BASE + 0x1C) +#define RTL8380MP_TCIE (1 << 20) +#define RTL8380MP_TCIP (1 << 16) +#define RTL8380MP_WDTCNR (RTL838X_TIMER0_BASE + 0x50) + +#define DIVISOR_RTL8390 55 +#define DIVISOR_RTL8380 2500 +#define DIVISOR_MAX 16834 + +/* + * Memory Controller + */ +#define MC_MCR 0xB8001000 +#define MC_MCR_VAL 0x00000000 + +#define MC_DCR 0xB8001004 +#define MC_DCR0_VAL 0x54480000 + +#define MC_DTCR 0xB8001008 +#define MC_DTCR_VAL 0xFFFF05C0 + +/* + * GPIO + */ +#define GPIO_CTRL_REG_BASE ((volatile void *) 0xb8003500) +#define RTL838X_GPIO_PABC_CNR (GPIO_CTRL_REG_BASE + 0x0) +#define RTL838X_GPIO_PABC_TYPE (GPIO_CTRL_REG_BASE + 0x04) +#define RTL838X_GPIO_PABC_DIR (GPIO_CTRL_REG_BASE + 0x8) +#define RTL838X_GPIO_PABC_DATA (GPIO_CTRL_REG_BASE + 0xc) +#define RTL838X_GPIO_PABC_ISR (GPIO_CTRL_REG_BASE + 0x10) +#define RTL838X_GPIO_PAB_IMR (GPIO_CTRL_REG_BASE + 0x14) +#define RTL838X_GPIO_PC_IMR (GPIO_CTRL_REG_BASE + 0x18) + +#define RTL838X_MODEL_NAME_INFO (0x00D4) +#define RTL839X_MODEL_NAME_INFO (0x0FF0) +#define RTL838X_LED_GLB_CTRL (0xA000) +#define RTL839X_LED_GLB_CTRL (0x00E4) +#define RTL838X_EXT_GPIO_DIR_0 (0xA08C) +#define RTL838X_EXT_GPIO_DIR_1 (0xA090) +#define RTL838X_EXT_GPIO_DATA_0 (0xA094) +#define RTL838X_EXT_GPIO_DATA_1 (0xA098) +#define RTL838X_EXT_GPIO_INDRT_ACCESS (0xA09C) +#define RTL838X_EXTRA_GPIO_CTRL (0xA0E0) +#define RTL838X_EXTRA_GPIO_DIR_0 (0xA0E4) +#define RTL838X_EXTRA_GPIO_DIR_1 (0xA0E8) +#define RTL838X_EXTRA_GPIO_DATA_0 (0xA0EC) +#define RTL838X_EXTRA_GPIO_DATA_1 (0xA0F0) +#define RTL838X_DMY_REG5 (0x0144) +#define RTL838X_EXTRA_GPIO_CTRL (0xA0E0) + +#define RTL838X_GMII_INTF_SEL (0x1000) +#define RTL838X_IO_DRIVING_ABILITY_CTRL (0x1010) + +#define RTL838X_GPIO_A7 31 +#define RTL838X_GPIO_A6 30 +#define RTL838X_GPIO_A5 29 +#define RTL838X_GPIO_A4 28 +#define RTL838X_GPIO_A3 27 +#define RTL838X_GPIO_A2 26 +#define RTL838X_GPIO_A1 25 +#define RTL838X_GPIO_A0 24 +#define RTL838X_GPIO_B7 23 +#define RTL838X_GPIO_B6 22 +#define RTL838X_GPIO_B5 21 +#define RTL838X_GPIO_B4 20 +#define RTL838X_GPIO_B3 19 +#define RTL838X_GPIO_B2 18 +#define RTL838X_GPIO_B1 17 +#define RTL838X_GPIO_B0 16 +#define RTL838X_GPIO_C7 15 +#define RTL838X_GPIO_C6 14 +#define RTL838X_GPIO_C5 13 +#define RTL838X_GPIO_C4 12 +#define RTL838X_GPIO_C3 11 +#define RTL838X_GPIO_C2 10 +#define RTL838X_GPIO_C1 9 +#define RTL838X_GPIO_C0 8 + +#define RTL838X_INT_RW_CTRL (0x0058) +#define RTL838X_EXT_VERSION (0x00D0) +#define RTL838X_PLL_CML_CTRL (0x0FF8) +#define RTL838X_STRAP_DBG (0x100C) + +/* + * Reset + */ +#define RGCR (0x1E70) +#define RTL839X_RST_GLB_CTRL (0x0014) +#define RTL838X_RST_GLB_CTRL_1 (0x0040) + +/* LED control by switch */ +#define RTL838X_LED_MODE_SEL (0x1004) +#define RTL838X_LED_MODE_CTRL (0xA004) +#define RTL838X_LED_P_EN_CTRL (0xA008) + +/* LED control by software */ +#define RTL838X_LED_SW_CTRL (0xA00C) +#define RTL838X_LED0_SW_P_EN_CTRL (0xA010) +#define RTL838X_LED1_SW_P_EN_CTRL (0xA014) +#define RTL838X_LED2_SW_P_EN_CTRL (0xA018) +#define RTL838X_LED_SW_P_CTRL(p) (0xA01C + ((p) << 2)) + +#define RTL839X_MAC_EFUSE_CTRL (0x02ac) + +/* + * MDIO via Realtek's SMI interface + */ +#define RTL838X_SMI_GLB_CTRL (0xa100) +#define RTL838X_SMI_ACCESS_PHY_CTRL_0 (0xa1b8) +#define RTL838X_SMI_ACCESS_PHY_CTRL_1 (0xa1bc) +#define RTL838X_SMI_ACCESS_PHY_CTRL_2 (0xa1c0) +#define RTL838X_SMI_ACCESS_PHY_CTRL_3 (0xa1c4) +#define RTL838X_SMI_PORT0_5_ADDR_CTRL (0xa1c8) +#define RTL838X_SMI_POLL_CTRL (0xa17c) + +#define RTL839X_SMI_GLB_CTRL (0x03f8) +#define RTL839X_SMI_PORT_POLLING_CTRL (0x03fc) +#define RTL839X_PHYREG_ACCESS_CTRL (0x03DC) +#define RTL839X_PHYREG_CTRL (0x03E0) +#define RTL839X_PHYREG_PORT_CTRL(p) (0x03E4 + ((p >> 5) << 2)) +#define RTL839X_PHYREG_DATA_CTRL (0x03F0) + +/* + * Switch interrupts + */ +#define RTL838X_IMR_GLB (0x1100) +#define RTL838X_IMR_PORT_LINK_STS_CHG (0x1104) +#define RTL838X_ISR_GLB_SRC (0x1148) +#define RTL838X_ISR_PORT_LINK_STS_CHG (0x114C) +#define RTL839X_IMR_GLB (0x0064) +#define RTL839X_IMR_PORT_LINK_STS_CHG (0x0068) +#define RTL839X_ISR_GLB_SRC (0x009c) +#define RTL839X_ISR_PORT_LINK_STS_CHG (0x00a0) + +/* Definition of family IDs */ +#define RTL8389_FAMILY_ID (0x8389) +#define RTL8328_FAMILY_ID (0x8328) +#define RTL8390_FAMILY_ID (0x8390) +#define RTL8350_FAMILY_ID (0x8350) +#define RTL8380_FAMILY_ID (0x8380) +#define RTL8330_FAMILY_ID (0x8330) + +struct rtl838x_soc_info { + unsigned char *name; + unsigned int id; + unsigned int family; + unsigned char *compatible; + volatile void *sw_base; + volatile void *icu_base; +}; + +void rtl838x_soc_detect(struct rtl838x_soc_info *i); + +#endif /* _MACH_RTL838X_H_ */ diff --git a/target/linux/rtl838x/files-5.4/arch/mips/rtl838x/Makefile b/target/linux/rtl838x/files-5.4/arch/mips/rtl838x/Makefile new file mode 100644 index 0000000000..fe5e1d96a9 --- /dev/null +++ b/target/linux/rtl838x/files-5.4/arch/mips/rtl838x/Makefile @@ -0,0 +1,5 @@ +# +# Makefile for the rtl838x specific parts of the kernel +# + +obj-y := serial.o setup.o prom.o irq.o diff --git a/target/linux/rtl838x/files-5.4/arch/mips/rtl838x/Platform b/target/linux/rtl838x/files-5.4/arch/mips/rtl838x/Platform new file mode 100644 index 0000000000..4d48932d80 --- /dev/null +++ b/target/linux/rtl838x/files-5.4/arch/mips/rtl838x/Platform @@ -0,0 +1,6 @@ +# +# Realtek RTL838x SoCs +# +platform-$(CONFIG_RTL838X) += rtl838x/ +cflags-$(CONFIG_RTL838X) += -I$(srctree)/arch/mips/include/asm/mach-rtl838x/ +load-$(CONFIG_RTL838X) += 0xffffffff80000000 diff --git a/target/linux/rtl838x/files-5.4/arch/mips/rtl838x/irq.c b/target/linux/rtl838x/files-5.4/arch/mips/rtl838x/irq.c new file mode 100644 index 0000000000..34e90982b2 --- /dev/null +++ b/target/linux/rtl838x/files-5.4/arch/mips/rtl838x/irq.c @@ -0,0 +1,263 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Realtek RTL838X architecture specific IRQ handling + * + * Copyright (C) 2020 B. Koblitz + * based on the original BSP + * Copyright (C) 2006-2012 Tony Wu (tonywu@realtek.com) + * + */ + +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/interrupt.h> +#include <linux/irqchip.h> +#include <linux/of_irq.h> +#include <linux/of_address.h> +#include <linux/spinlock.h> + +#include <asm/irq_cpu.h> +#include <asm/mipsregs.h> +#include <mach-rtl838x.h> + +extern struct rtl838x_soc_info soc_info; + +#define icu_r32(reg) rtl838x_r32(soc_info.icu_base + reg) +#define icu_w32(val, reg) rtl838x_w32(val, soc_info.icu_base + reg) +#define icu_w32_mask(clear, set, reg) rtl838x_w32_mask(clear, set, soc_info.icu_base + reg) + +static DEFINE_RAW_SPINLOCK(irq_lock); + +extern irqreturn_t c0_compare_interrupt(int irq, void *dev_id); +unsigned int rtl838x_ictl_irq_dispatch1(void); +unsigned int rtl838x_ictl_irq_dispatch2(void); +unsigned int rtl838x_ictl_irq_dispatch3(void); +unsigned int rtl838x_ictl_irq_dispatch4(void); +unsigned int rtl838x_ictl_irq_dispatch5(void); + +static struct irqaction irq_cascade1 = { + .handler = no_action, + .name = "RTL838X IRQ cascade1", +}; + +static struct irqaction irq_cascade2 = { + .handler = no_action, + .name = "RTL838X IRQ cascade2", +}; + +static struct irqaction irq_cascade3 = { + .handler = no_action, + .name = "RTL838X IRQ cascade3", +}; + +static struct irqaction irq_cascade4 = { + .handler = no_action, + .name = "RTL838X IRQ cascade4", +}; + +static struct irqaction irq_cascade5 = { + .handler = no_action, + .name = "RTL838X IRQ cascade5", +}; + +static void rtl838x_ictl_enable_irq(struct irq_data *i) +{ + unsigned long flags; + + raw_spin_lock_irqsave(&irq_lock, flags); + icu_w32_mask(0, 1 << i->irq, GIMR); + raw_spin_unlock_irqrestore(&irq_lock, flags); +} + +static unsigned int rtl838x_ictl_startup_irq(struct irq_data *i) +{ + rtl838x_ictl_enable_irq(i); + return 0; +} + +static void rtl838x_ictl_disable_irq(struct irq_data *i) +{ + unsigned long flags; + + raw_spin_lock_irqsave(&irq_lock, flags); + icu_w32_mask(1 << i->irq, 0, GIMR); + raw_spin_unlock_irqrestore(&irq_lock, flags); +} + +static void rtl838x_ictl_eoi_irq(struct irq_data *i) +{ + unsigned long flags; + + raw_spin_lock_irqsave(&irq_lock, flags); + icu_w32_mask(0, 1 << i->irq, GIMR); + raw_spin_unlock_irqrestore(&irq_lock, flags); +} + +static struct irq_chip rtl838x_ictl_irq = { + .name = "RTL838X", + .irq_startup = rtl838x_ictl_startup_irq, + .irq_shutdown = rtl838x_ictl_disable_irq, + .irq_enable = rtl838x_ictl_enable_irq, + .irq_disable = rtl838x_ictl_disable_irq, + .irq_ack = rtl838x_ictl_disable_irq, + .irq_mask = rtl838x_ictl_disable_irq, + .irq_unmask = rtl838x_ictl_enable_irq, + .irq_eoi = rtl838x_ictl_eoi_irq, +}; + +/* + * RTL8390/80/28 Interrupt Scheme + * + * Source IRQ CPU INT + * -------- ------- ------- + * UART0 31 IP3 + * UART1 30 IP2 + * TIMER0 29 IP6 + * TIMER1 28 IP2 + * OCPTO 27 IP2 + * HLXTO 26 IP2 + * SLXTO 25 IP2 + * NIC 24 IP5 + * GPIO_ABCD 23 IP5 + * SWCORE 20 IP4 + */ + +unsigned int rtl838x_ictl_irq_dispatch1(void) +{ + /* Identify shared IRQ */ + unsigned int extint_ip = icu_r32(GIMR) & icu_r32(GISR); + + if (extint_ip & TC1_IP) + do_IRQ(TC1_IRQ); + else if (extint_ip & UART1_IP) + do_IRQ(UART1_IRQ); + else + spurious_interrupt(); + + return IRQ_HANDLED; +} + +unsigned int rtl838x_ictl_irq_dispatch2(void) +{ + do_IRQ(UART0_IRQ); + return IRQ_HANDLED; +} + +unsigned int rtl838x_ictl_irq_dispatch3(void) +{ + do_IRQ(SWCORE_IRQ); + return IRQ_HANDLED; +} + +unsigned int rtl838x_ictl_irq_dispatch4(void) +{ + /* Identify shared IRQ */ + unsigned int extint_ip = icu_r32(GIMR) & icu_r32(GISR); + + if (extint_ip & NIC_IP) + do_IRQ(NIC_IRQ); + else if (extint_ip & GPIO_ABCD_IP) + do_IRQ(GPIO_ABCD_IRQ); + else if ((extint_ip & GPIO_EFGH_IP) && (soc_info.family == RTL8328_FAMILY_ID)) + do_IRQ(GPIO_EFGH_IRQ); + else + spurious_interrupt(); + + return IRQ_HANDLED; +} + +unsigned int rtl838x_ictl_irq_dispatch5(void) +{ + do_IRQ(TC0_IRQ); + return IRQ_HANDLED; +} + +asmlinkage void plat_irq_dispatch(void) +{ + unsigned int pending; + + pending = read_c0_cause() & read_c0_status() & ST0_IM; + + if (pending & CAUSEF_IP7) + c0_compare_interrupt(7, NULL); + else if (pending & CAUSEF_IP6) + rtl838x_ictl_irq_dispatch5(); + else if (pending & CAUSEF_IP5) + rtl838x_ictl_irq_dispatch4(); + else if (pending & CAUSEF_IP4) + rtl838x_ictl_irq_dispatch3(); + else if (pending & CAUSEF_IP3) + rtl838x_ictl_irq_dispatch2(); + else if (pending & CAUSEF_IP2) + rtl838x_ictl_irq_dispatch1(); + else + spurious_interrupt(); +} + +static void __init rtl838x_ictl_irq_init(unsigned int irq_base) +{ + int i; + + for (i = 0; i < RTL838X_IRQ_ICTL_NUM; i++) + irq_set_chip_and_handler(irq_base + i, &rtl838x_ictl_irq, handle_level_irq); + + setup_irq(RTL838X_ICTL1_IRQ, &irq_cascade1); + setup_irq(RTL838X_ICTL2_IRQ, &irq_cascade2); + setup_irq(RTL838X_ICTL3_IRQ, &irq_cascade3); + setup_irq(RTL838X_ICTL4_IRQ, &irq_cascade4); + setup_irq(RTL838X_ICTL5_IRQ, &irq_cascade5); + + /* Set GIMR, IRR */ + icu_w32(TC0_IE | UART0_IE, GIMR); + icu_w32(IRR0_SETTING, IRR0); + icu_w32(IRR1_SETTING, IRR1); + icu_w32(IRR2_SETTING, IRR2); + icu_w32(IRR3_SETTING, IRR3); +} + +static int intc_map(struct irq_domain *d, unsigned int irq, irq_hw_number_t hw) +{ + irq_set_chip_and_handler(hw, &rtl838x_ictl_irq, handle_level_irq); + + return 0; +} + +static const struct irq_domain_ops irq_domain_ops = { + .xlate = irq_domain_xlate_onecell, + .map = intc_map, +}; + +int __init icu_of_init(struct device_node *node, struct device_node *parent) +{ + int i; + struct irq_domain *domain; + struct resource res; + + pr_info("Found Interrupt controller: %s (%s)\n", node->name, node->full_name); + if (of_address_to_resource(node, 0, &res)) { + panic("Failed to get icu memory range"); + } + if (!request_mem_region(res.start, resource_size(&res), res.name)) + pr_err("Failed to request icu memory\n"); + soc_info.icu_base = ioremap(res.start, resource_size(&res)); + pr_info("ICU Memory: %08x\n", (u32)soc_info.icu_base); + + mips_cpu_irq_init(); + + domain = irq_domain_add_simple(node, 32, 0, &irq_domain_ops, NULL); + + /* Setup all external HW irqs */ + for (i = 8; i < 32; i++) + irq_domain_associate(domain, i, i); + + rtl838x_ictl_irq_init(RTL838X_IRQ_ICTL_BASE); + return 0; +} + +void __init arch_init_irq(void) +{ + /* do board-specific irq initialization */ + irqchip_init(); +} + +IRQCHIP_DECLARE(mips_cpu_intc, "rtl838x,icu", icu_of_init); diff --git a/target/linux/rtl838x/files-5.4/arch/mips/rtl838x/prom.c b/target/linux/rtl838x/files-5.4/arch/mips/rtl838x/prom.c new file mode 100644 index 0000000000..604b01806c --- /dev/null +++ b/target/linux/rtl838x/files-5.4/arch/mips/rtl838x/prom.c @@ -0,0 +1,174 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * prom.c + * Early intialization code for the Realtek RTL838X SoC + * + * based on the original BSP by + * Copyright (C) 2006-2012 Tony Wu (tonywu@realtek.com) + * Copyright (C) 2020 B. Koblitz + * + */ + +#include <linux/init.h> +#include <linux/kernel.h> +#include <linux/string.h> +#include <linux/of_fdt.h> +#include <linux/libfdt.h> +#include <asm/bootinfo.h> +#include <asm/addrspace.h> +#include <asm/page.h> +#include <asm/cpu.h> + +#include <mach-rtl838x.h> + +extern char arcs_cmdline[]; +const void *fdt; +extern const char __appended_dtb; +//extern int __init rtl838x_serial_init(void); + +void prom_console_init(void) +{ + /* UART 16550A is initialized by the bootloader */ +} + +#ifdef CONFIG_EARLY_PRINTK +#define rtl838x_r8(reg) __raw_readb(reg) +#define rtl838x_w8(val, reg) __raw_writeb(val, reg) + +void unregister_prom_console(void) +{ + +} + +void disable_early_printk(void) +{ + +} + +void prom_putchar(char c) +{ + unsigned int retry = 0; + + do { + if (retry++ >= 30000) { + /* Reset Tx FIFO */ + rtl838x_w8(TXRST | CHAR_TRIGGER_14, UART0_FCR); + return; + } + } while ((rtl838x_r8(UART0_LSR) & LSR_THRE) == TxCHAR_AVAIL); + + /* Send Character */ + rtl838x_w8(c, UART0_THR); +} + +char prom_getchar(void) +{ + return '\0'; +} +#endif + +struct rtl838x_soc_info soc_info; + +const char *get_system_type(void) +{ + return soc_info.name; +} + + +void __init prom_free_prom_memory(void) +{ + +} + +void __init device_tree_init(void) +{ + pr_info("%s called\r\n", __func__); + if (!fdt_check_header(&__appended_dtb)) { + fdt = &__appended_dtb; + pr_info("Using appended Device Tree.\n"); + } + initial_boot_params = (void *)fdt; + unflatten_and_copy_device_tree(); +} + +static void __init prom_init_cmdline(void) +{ + int argc = fw_arg0; + char **argv = (char **) KSEG1ADDR(fw_arg1); + int i; + + arcs_cmdline[0] = '\0'; + + for (i = 0; i < argc; i++) { + char *p = (char *) KSEG1ADDR(argv[i]); + + if (CPHYSADDR(p) && *p) { + strlcat(arcs_cmdline, p, sizeof(arcs_cmdline)); + strlcat(arcs_cmdline, " ", sizeof(arcs_cmdline)); + } + } + pr_info("Kernel command line: %s\n", arcs_cmdline); +} + +/* Do basic initialization */ +void __init prom_init(void) +{ + uint32_t model; + + pr_info("%s called\n", __func__); + soc_info.sw_base = RTL838X_SW_BASE; + + model = sw_r32(RTL838X_MODEL_NAME_INFO); + pr_info("RTL838X model is %x\n", model); + model = model >> 16 & 0xFFFF; + + if ((model != 0x8328) && (model != 0x8330) && (model != 0x8332) + && (model != 0x8380) && (model != 0x8382)) { + model = sw_r32(RTL839X_MODEL_NAME_INFO); + pr_info("RTL839X model is %x\n", model); + model = model >> 16 & 0xFFFF; + } + + soc_info.id = model; + + switch (model) { + case 0x8328: + soc_info.name = "RTL8328"; + soc_info.family = RTL8328_FAMILY_ID; + break; + case 0x8332: + soc_info.name = "RTL8332"; + soc_info.family = RTL8380_FAMILY_ID; + break; + case 0x8380: + soc_info.name = "RTL8380"; + soc_info.family = RTL8380_FAMILY_ID; + break; + case 0x8382: + soc_info.name = "RTL8382"; + soc_info.family = RTL8380_FAMILY_ID; + break; + case 0x8390: + soc_info.name = "RTL8390"; + soc_info.family = RTL8390_FAMILY_ID; + break; + case 0x8391: + soc_info.name = "RTL8391"; + soc_info.family = RTL8390_FAMILY_ID; + break; + case 0x8392: + soc_info.name = "RTL8392"; + soc_info.family = RTL8390_FAMILY_ID; + break; + case 0x8393: + soc_info.name = "RTL8393"; + soc_info.family = RTL8390_FAMILY_ID; + break; + default: + soc_info.name = "DEFAULT"; + soc_info.family = 0; + } + pr_info("SoC Type: %s\n", get_system_type()); + prom_init_cmdline(); +} + diff --git a/target/linux/rtl838x/files-5.4/arch/mips/rtl838x/serial.c b/target/linux/rtl838x/files-5.4/arch/mips/rtl838x/serial.c new file mode 100644 index 0000000000..cebab1df8d --- /dev/null +++ b/target/linux/rtl838x/files-5.4/arch/mips/rtl838x/serial.c @@ -0,0 +1,100 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * 8250 serial console setup for the Realtek RTL838X SoC + * + * based on the original BSP by + * Copyright (C) 2006-2012 Tony Wu (tonywu@realtek.com) + * + * Copyright (C) 2020 B. Koblitz + * + */ +#include <linux/types.h> +#include <linux/ctype.h> +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/version.h> +#include <linux/serial.h> +#include <linux/serial_core.h> +#include <linux/serial_8250.h> +#include <linux/serial_reg.h> +#include <linux/tty.h> +#include <linux/clk.h> + +#include <asm/mach-rtl838x/mach-rtl838x.h> + +extern char arcs_cmdline[]; +extern struct rtl838x_soc_info soc_info; + +int __init rtl838x_serial_init(void) +{ +#ifdef CONFIG_SERIAL_8250 + int ret; + struct uart_port p; + unsigned long baud = 0; + int err; + char parity = '\0', bits = '\0', flow = '\0'; + char *s; + struct device_node *dn; + + dn = of_find_compatible_node(NULL, NULL, "ns16550a"); + if (dn) { + pr_info("Found NS16550a: %s (%s)\n", dn->name, dn->full_name); + dn = of_find_compatible_node(dn, NULL, "ns16550a"); + if (dn && of_device_is_available(dn) && soc_info.family == RTL8380_FAMILY_ID) { + /* Enable UART1 on RTL838x */ + pr_info("Enabling uart1\n"); + sw_w32(0x10, RTL838X_GMII_INTF_SEL); + } + } else { + pr_err("No NS16550a UART found!"); + return -ENODEV; + } + + s = strstr(arcs_cmdline, "console=ttyS0,"); + if (s) { + s += 14; + baud = kstrtoul(s, 10, &baud); + if (err) + baud = 0; + while (isdigit(*s)) + s++; + if (*s == ',') + s++; + if (*s) + parity = *s++; + if (*s == ',') + s++; + if (*s) + bits = *s++; + if (*s == ',') + s++; + if (*s == 'h') + flow = 'r'; + } + + if (baud == 0) { + baud = 38400; + pr_warn("Using default baud rate: %lu\n", baud); + } + if (parity != 'n' && parity != 'o' && parity != 'e') + parity = 'n'; + if (bits != '7' && bits != '8') + bits = '8'; + + memset(&p, 0, sizeof(p)); + + p.type = PORT_16550A; + p.membase = (unsigned char *) RTL838X_UART0_BASE; + p.irq = RTL838X_UART0_IRQ; + p.uartclk = SYSTEM_FREQ - (24 * baud); + p.flags = UPF_SKIP_TEST | UPF_LOW_LATENCY | UPF_FIXED_TYPE; + p.iotype = UPIO_MEM; + p.regshift = 2; + p.fifosize = 1; + + /* Call early_serial_setup() here, to set up 8250 console driver */ + if (early_serial_setup(&p) != 0) + ret = 1; +#endif + return 0; +} diff --git a/target/linux/rtl838x/files-5.4/arch/mips/rtl838x/setup.c b/target/linux/rtl838x/files-5.4/arch/mips/rtl838x/setup.c new file mode 100644 index 0000000000..6a9485c451 --- /dev/null +++ b/target/linux/rtl838x/files-5.4/arch/mips/rtl838x/setup.c @@ -0,0 +1,187 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Setup for the Realtek RTL838X SoC: + * Memory, Timer and Serial + * + * Copyright (C) 2020 B. Koblitz + * based on the original BSP by + * Copyright (C) 2006-2012 Tony Wu (tonywu@realtek.com) + * + */ +#include <linux/console.h> +#include <linux/init.h> +#include <linux/clk.h> +#include <linux/clkdev.h> +#include <linux/clk-provider.h> + +#include <asm/addrspace.h> +#include <asm/io.h> + +#include <asm/bootinfo.h> +#include <linux/of_fdt.h> +#include <asm/reboot.h> +#include <asm/time.h> /* for mips_hpt_frequency */ +#include <asm/prom.h> +#include <asm/smp-ops.h> + +#include "mach-rtl838x.h" + +extern int rtl838x_serial_init(void); +extern struct rtl838x_soc_info soc_info; + +struct clk { + struct clk_lookup cl; + unsigned long rate; +}; + +struct clk cpu_clk; + +u32 pll_reset_value; + +static void rtl838x_restart(char *command) +{ + u32 pll = sw_r32(RTL838X_PLL_CML_CTRL); + /* SoC reset vector (in flash memory): on RTL839x platform preferred way to reset */ + void (*f)(void) = (void *) 0xbfc00000; + + pr_info("System restart.\n"); + if (soc_info.family == RTL8390_FAMILY_ID) { + f(); + /* If calling reset vector fails, reset entire chip */ + sw_w32(0xFFFFFFFF, RTL839X_RST_GLB_CTRL); + /* If this fails, halt the CPU */ + while + (1); + } + + pr_info("PLL control register: %x, applying reset value %x\n", + pll, pll_reset_value); + sw_w32(3, RTL838X_INT_RW_CTRL); + sw_w32(pll_reset_value, RTL838X_PLL_CML_CTRL); + sw_w32(0, RTL838X_INT_RW_CTRL); + + pr_info("Resetting RTL838X SoC\n"); + /* Reset Global Control1 Register */ + sw_w32(1, RTL838X_RST_GLB_CTRL_1); +} + +static void rtl838x_halt(void) +{ + pr_info("System halted.\n"); + while + (1); +} + +static void __init rtl838x_setup(void) +{ + unsigned int val; + + pr_info("Registering _machine_restart\n"); + _machine_restart = rtl838x_restart; + _machine_halt = rtl838x_halt; + + val = rtl838x_r32((volatile void *)0xBB0040000); + if (val == 3) + pr_info("PCI device found\n"); + else + pr_info("NO PCI device found\n"); + + /* Setup System LED. Bit 15 (14 for RTL8390) then allows to toggle it */ + if (soc_info.family == RTL8380_FAMILY_ID) + sw_w32_mask(0, 3 << 16, RTL838X_LED_GLB_CTRL); + else + sw_w32_mask(0, 3 << 15, RTL839X_LED_GLB_CTRL); +} + +void __init plat_mem_setup(void) +{ + void *dtb; + + pr_info("%s called\n", __func__); + + set_io_port_base(KSEG1); + + if (fw_passed_dtb) /* UHI interface */ + dtb = (void *)fw_passed_dtb; + else if (__dtb_start != __dtb_end) + dtb = (void *)__dtb_start; + else + panic("no dtb found"); + + /* + * Load the devicetree. This causes the chosen node to be + * parsed resulting in our memory appearing + */ + __dt_setup_arch(dtb); + + rtl838x_setup(); +} + + +/* + * Linux clock API + */ +int clk_enable(struct clk *clk) +{ + return 0; +} +EXPORT_SYMBOL_GPL(clk_enable); + +void clk_disable(struct clk *clk) +{ + +} +EXPORT_SYMBOL_GPL(clk_disable); + +unsigned long clk_get_rate(struct clk *clk) +{ + if (!clk) + return 0; + + return clk->rate; +} +EXPORT_SYMBOL_GPL(clk_get_rate); + +int clk_set_rate(struct clk *clk, unsigned long rate) +{ + return -1; +} +EXPORT_SYMBOL_GPL(clk_set_rate); + +long clk_round_rate(struct clk *clk, unsigned long rate) +{ + return -1; +} +EXPORT_SYMBOL_GPL(clk_round_rate); + +void __init plat_time_init(void) +{ + u32 freq = 500000000; + struct device_node *np; + struct clk *clk = &cpu_clk; + + np = of_find_node_by_name(NULL, "cpus"); + if (!np) { + pr_err("Missing 'cpus' DT node, using default frequency."); + } else { + if (of_property_read_u32(np, "frequency", &freq) < 0) + pr_err("No 'frequency' property in DT, using default."); + else + pr_info("CPU frequency from device tree: %d", freq); + of_node_put(np); + } + + clk->rate = freq; + + if (IS_ERR(clk)) + panic("unable to get CPU clock, err=%ld", PTR_ERR(clk)); + + pr_info("CPU Clock: %ld MHz\n", clk->rate / 1000000); + mips_hpt_frequency = freq / 2; + + pll_reset_value = sw_r32(RTL838X_PLL_CML_CTRL); + pr_info("PLL control register: %x\n", pll_reset_value); + + /* With the info from the command line and cpu-freq we can setup the console */ + rtl838x_serial_init(); +} |