diff options
Diffstat (limited to 'target/linux/realtek/files-5.4/arch/mips/rtl838x')
5 files changed, 411 insertions, 0 deletions
diff --git a/target/linux/realtek/files-5.4/arch/mips/rtl838x/Makefile b/target/linux/realtek/files-5.4/arch/mips/rtl838x/Makefile new file mode 100644 index 0000000000..8212dc3f48 --- /dev/null +++ b/target/linux/realtek/files-5.4/arch/mips/rtl838x/Makefile @@ -0,0 +1,5 @@ +# +# Makefile for the rtl838x specific parts of the kernel +# + +obj-y := setup.o prom.o irq.o diff --git a/target/linux/realtek/files-5.4/arch/mips/rtl838x/Platform b/target/linux/realtek/files-5.4/arch/mips/rtl838x/Platform new file mode 100644 index 0000000000..4d48932d80 --- /dev/null +++ b/target/linux/realtek/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/realtek/files-5.4/arch/mips/rtl838x/irq.c b/target/linux/realtek/files-5.4/arch/mips/rtl838x/irq.c new file mode 100644 index 0000000000..9057d48543 --- /dev/null +++ b/target/linux/realtek/files-5.4/arch/mips/rtl838x/irq.c @@ -0,0 +1,167 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Realtek RTL83XX architecture specific IRQ handling + * + * based on the original BSP + * Copyright (C) 2006-2012 Tony Wu (tonywu@realtek.com) + * Copyright (C) 2020 B. Koblitz + * Copyright (C) 2020 Bert Vermeulen <bert@biot.com> + * Copyright (C) 2020 John Crispin <john@phrozen.org> + */ + +#include <linux/irqchip.h> +#include <linux/spinlock.h> +#include <linux/of_address.h> +#include <asm/irq_cpu.h> +#include <linux/of_irq.h> +#include <asm/cevt-r4k.h> + +#include <mach-rtl83xx.h> +#include "irq.h" + +#define REALTEK_CPU_IRQ_SHARED0 (MIPS_CPU_IRQ_BASE + 2) +#define REALTEK_CPU_IRQ_UART (MIPS_CPU_IRQ_BASE + 3) +#define REALTEK_CPU_IRQ_SWITCH (MIPS_CPU_IRQ_BASE + 4) +#define REALTEK_CPU_IRQ_SHARED1 (MIPS_CPU_IRQ_BASE + 5) +#define REALTEK_CPU_IRQ_EXTERNAL (MIPS_CPU_IRQ_BASE + 6) +#define REALTEK_CPU_IRQ_COUNTER (MIPS_CPU_IRQ_BASE + 7) + +#define REG(x) (rtl83xx_ictl_base + x) + +extern struct rtl83xx_soc_info soc_info; + +static DEFINE_RAW_SPINLOCK(irq_lock); +static void __iomem *rtl83xx_ictl_base; + +static void rtl83xx_ictl_enable_irq(struct irq_data *i) +{ + unsigned long flags; + u32 value; + + raw_spin_lock_irqsave(&irq_lock, flags); + + value = rtl83xx_r32(REG(RTL83XX_ICTL_GIMR)); + value |= BIT(i->hwirq); + rtl83xx_w32(value, REG(RTL83XX_ICTL_GIMR)); + + raw_spin_unlock_irqrestore(&irq_lock, flags); +} + +static void rtl83xx_ictl_disable_irq(struct irq_data *i) +{ + unsigned long flags; + u32 value; + + raw_spin_lock_irqsave(&irq_lock, flags); + + value = rtl83xx_r32(REG(RTL83XX_ICTL_GIMR)); + value &= ~BIT(i->hwirq); + rtl83xx_w32(value, REG(RTL83XX_ICTL_GIMR)); + + raw_spin_unlock_irqrestore(&irq_lock, flags); +} + +static struct irq_chip rtl83xx_ictl_irq = { + .name = "RTL83xx", + .irq_enable = rtl83xx_ictl_enable_irq, + .irq_disable = rtl83xx_ictl_disable_irq, + .irq_ack = rtl83xx_ictl_disable_irq, + .irq_mask = rtl83xx_ictl_disable_irq, + .irq_unmask = rtl83xx_ictl_enable_irq, + .irq_eoi = rtl83xx_ictl_enable_irq, +}; + +static int intc_map(struct irq_domain *d, unsigned int irq, irq_hw_number_t hw) +{ + irq_set_chip_and_handler(hw, &rtl83xx_ictl_irq, handle_level_irq); + + return 0; +} + +static const struct irq_domain_ops irq_domain_ops = { + .map = intc_map, + .xlate = irq_domain_xlate_onecell, +}; + +static void rtl838x_irq_dispatch(struct irq_desc *desc) +{ + unsigned int pending = rtl83xx_r32(REG(RTL83XX_ICTL_GIMR)) & rtl83xx_r32(REG(RTL83XX_ICTL_GISR)); + + if (pending) { + struct irq_domain *domain = irq_desc_get_handler_data(desc); + generic_handle_irq(irq_find_mapping(domain, __ffs(pending))); + } else { + spurious_interrupt(); + } +} + +asmlinkage void plat_irq_dispatch(void) +{ + unsigned int pending; + + pending = read_c0_cause() & read_c0_status() & ST0_IM; + + if (pending & CAUSEF_IP7) + do_IRQ(REALTEK_CPU_IRQ_COUNTER); + + else if (pending & CAUSEF_IP6) + do_IRQ(REALTEK_CPU_IRQ_EXTERNAL); + + else if (pending & CAUSEF_IP5) + do_IRQ(REALTEK_CPU_IRQ_SHARED1); + + else if (pending & CAUSEF_IP4) + do_IRQ(REALTEK_CPU_IRQ_SWITCH); + + else if (pending & CAUSEF_IP3) + do_IRQ(REALTEK_CPU_IRQ_UART); + + else if (pending & CAUSEF_IP2) + do_IRQ(REALTEK_CPU_IRQ_SHARED0); + + else + spurious_interrupt(); +} + +static void __init icu_of_init(struct device_node *node, struct device_node *parent) +{ + struct irq_domain *domain; + + domain = irq_domain_add_simple(node, 32, 0, + &irq_domain_ops, NULL); + irq_set_chained_handler_and_data(2, rtl838x_irq_dispatch, domain); + irq_set_chained_handler_and_data(5, rtl838x_irq_dispatch, domain); + + rtl83xx_ictl_base = of_iomap(node, 0); + if (!rtl83xx_ictl_base) + return; + + /* Disable all cascaded interrupts */ + rtl83xx_w32(0, REG(RTL83XX_ICTL_GIMR)); + + /* Set up interrupt routing */ + rtl83xx_w32(RTL83XX_IRR0_SETTING, REG(RTL83XX_IRR0)); + rtl83xx_w32(RTL83XX_IRR1_SETTING, REG(RTL83XX_IRR1)); + rtl83xx_w32(RTL83XX_IRR2_SETTING, REG(RTL83XX_IRR2)); + rtl83xx_w32(RTL83XX_IRR3_SETTING, REG(RTL83XX_IRR3)); + + /* Clear timer interrupt */ + write_c0_compare(0); + + /* Enable all CPU interrupts */ + write_c0_status(read_c0_status() | ST0_IM); + + /* Enable timer0 and uart0 interrupts */ + rtl83xx_w32(BIT(RTL83XX_IRQ_TC0) | BIT(RTL83XX_IRQ_UART0), REG(RTL83XX_ICTL_GIMR)); +} + +static struct of_device_id __initdata of_irq_ids[] = { + { .compatible = "mti,cpu-interrupt-controller", .data = mips_cpu_irq_of_init }, + { .compatible = "realtek,rt8380-intc", .data = icu_of_init }, + {}, +}; + +void __init arch_init_irq(void) +{ + of_irq_init(of_irq_ids); +} diff --git a/target/linux/realtek/files-5.4/arch/mips/rtl838x/prom.c b/target/linux/realtek/files-5.4/arch/mips/rtl838x/prom.c new file mode 100644 index 0000000000..5278afae03 --- /dev/null +++ b/target/linux/realtek/files-5.4/arch/mips/rtl838x/prom.c @@ -0,0 +1,124 @@ +// 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-rtl83xx.h> + +extern char arcs_cmdline[]; +extern const char __appended_dtb; + +struct rtl83xx_soc_info soc_info; +const void *fdt; + +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(); +} + +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); +} + +void __init prom_init(void) +{ + uint32_t model; + + /* uart0 */ + setup_8250_early_printk_port(0xb8002000, 2, 0); + + soc_info.sw_base = RTL838X_SW_BASE; + + model = sw_r32(RTL838X_MODEL_NAME_INFO) >> 16; + if (model != 0x8328 && model != 0x8330 && model != 0x8332 && + model != 0x8380 && model != 0x8382) + model = sw_r32(RTL839X_MODEL_NAME_INFO) >> 16; + + 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/realtek/files-5.4/arch/mips/rtl838x/setup.c b/target/linux/realtek/files-5.4/arch/mips/rtl838x/setup.c new file mode 100644 index 0000000000..dbabb0354b --- /dev/null +++ b/target/linux/realtek/files-5.4/arch/mips/rtl838x/setup.c @@ -0,0 +1,109 @@ +// 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-rtl83xx.h" + +extern int rtl838x_serial_init(void); +extern struct rtl83xx_soc_info soc_info; + +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); +} + +void __init plat_mem_setup(void) +{ + void *dtb; + + set_io_port_base(KSEG1); + _machine_restart = rtl838x_restart; + _machine_halt = rtl838x_halt; + + 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); +} + +void __init plat_time_init(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: %d", freq); + of_node_put(np); + } + + mips_hpt_frequency = freq / 2; + + pll_reset_value = sw_r32(RTL838X_PLL_CML_CTRL); +} |