Resguardo inicial

This commit is contained in:
lastdragon
2026-09-06 12:53:21 -06:00
parent 662efe3c2a
commit ad2088d178
94853 changed files with 43200404 additions and 0 deletions
+17
View File
@@ -0,0 +1,17 @@
# SPDX-License-Identifier: GPL-2.0
#
# Carsten Langgaard, carstenl@mips.com
# Copyright (C) 1999,2000 MIPS Technologies, Inc. All rights reserved.
#
# Copyright (C) 2008 Wind River Systems, Inc.
# written by Ralf Baechle <ralf@linux-mips.org>
#
obj-y += malta-dtshim.o
obj-y += malta-init.o
obj-y += malta-int.o
obj-y += malta-memory.o
obj-y += malta-platform.o
obj-y += malta-setup.o
obj-y += malta-time.o
CFLAGS_malta-dtshim.o = -I$(src)/../../../scripts/dtc/libfdt
+6
View File
@@ -0,0 +1,6 @@
#
# MIPS Malta board
#
cflags-$(CONFIG_MIPS_MALTA) += -I$(srctree)/arch/mips/include/asm/mach-malta
load-$(CONFIG_MIPS_MALTA) += 0xffffffff80100000
all-$(CONFIG_MIPS_MALTA) := $(COMPRESSION_FNAME).bin
@@ -0,0 +1,333 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Copyright (C) 2015 Imagination Technologies
* Author: Paul Burton <paul.burton@mips.com>
*/
#include <linux/bug.h>
#include <linux/kernel.h>
#include <linux/libfdt.h>
#include <linux/of_fdt.h>
#include <linux/sizes.h>
#include <asm/addrspace.h>
#include <asm/bootinfo.h>
#include <asm/fw/fw.h>
#include <asm/mips-boards/generic.h>
#include <asm/mips-boards/malta.h>
#include <asm/mips-cps.h>
#include <asm/page.h>
#define ROCIT_REG_BASE 0x1f403000
#define ROCIT_CONFIG_GEN1 (ROCIT_REG_BASE + 0x04)
#define ROCIT_CONFIG_GEN1_MEMMAP_SHIFT 8
#define ROCIT_CONFIG_GEN1_MEMMAP_MASK (0xf << 8)
static unsigned char fdt_buf[16 << 10] __initdata __aligned(8);
/* determined physical memory size, not overridden by command line args */
extern unsigned long physical_memsize;
enum mem_map {
MEM_MAP_V1 = 0,
MEM_MAP_V2,
};
#define MAX_MEM_ARRAY_ENTRIES 2
static __init int malta_scon(void)
{
int scon = MIPS_REVISION_SCONID;
if (scon != MIPS_REVISION_SCON_OTHER)
return scon;
switch (MIPS_REVISION_CORID) {
case MIPS_REVISION_CORID_QED_RM5261:
case MIPS_REVISION_CORID_CORE_LV:
case MIPS_REVISION_CORID_CORE_FPGA:
case MIPS_REVISION_CORID_CORE_FPGAR2:
return MIPS_REVISION_SCON_GT64120;
case MIPS_REVISION_CORID_CORE_EMUL_BON:
case MIPS_REVISION_CORID_BONITO64:
case MIPS_REVISION_CORID_CORE_20K:
return MIPS_REVISION_SCON_BONITO;
case MIPS_REVISION_CORID_CORE_MSC:
case MIPS_REVISION_CORID_CORE_FPGA2:
case MIPS_REVISION_CORID_CORE_24K:
return MIPS_REVISION_SCON_SOCIT;
case MIPS_REVISION_CORID_CORE_FPGA3:
case MIPS_REVISION_CORID_CORE_FPGA4:
case MIPS_REVISION_CORID_CORE_FPGA5:
case MIPS_REVISION_CORID_CORE_EMUL_MSC:
default:
return MIPS_REVISION_SCON_ROCIT;
}
}
static unsigned __init gen_fdt_mem_array(__be32 *mem_array, unsigned long size,
enum mem_map map)
{
unsigned long size_preio;
unsigned entries;
entries = 1;
mem_array[0] = cpu_to_be32(PHYS_OFFSET);
if (IS_ENABLED(CONFIG_EVA)) {
/*
* The current Malta EVA configuration is "special" in that it
* always makes use of addresses in the upper half of the 32 bit
* physical address map, which gives it a contiguous region of
* DDR but limits it to 2GB.
*/
mem_array[1] = cpu_to_be32(size);
goto done;
}
size_preio = min_t(unsigned long, size, SZ_256M);
mem_array[1] = cpu_to_be32(size_preio);
size -= size_preio;
if (!size)
goto done;
if (map == MEM_MAP_V2) {
/*
* We have a flat 32 bit physical memory map with DDR filling
* all 4GB of the memory map, apart from the I/O region which
* obscures 256MB from 0x10000000-0x1fffffff.
*
* Therefore we discard the 256MB behind the I/O region.
*/
if (size <= SZ_256M)
goto done;
size -= SZ_256M;
/* Make use of the memory following the I/O region */
entries++;
mem_array[2] = cpu_to_be32(PHYS_OFFSET + SZ_512M);
mem_array[3] = cpu_to_be32(size);
} else {
/*
* We have a 32 bit physical memory map with a 2GB DDR region
* aliased in the upper & lower halves of it. The I/O region
* obscures 256MB from 0x10000000-0x1fffffff in the low alias
* but the DDR it obscures is accessible via the high alias.
*
* Simply access everything beyond the lowest 256MB of DDR using
* the high alias.
*/
entries++;
mem_array[2] = cpu_to_be32(PHYS_OFFSET + SZ_2G + SZ_256M);
mem_array[3] = cpu_to_be32(size);
}
done:
BUG_ON(entries > MAX_MEM_ARRAY_ENTRIES);
return entries;
}
static void __init append_memory(void *fdt, int root_off)
{
__be32 mem_array[2 * MAX_MEM_ARRAY_ENTRIES];
unsigned long memsize;
unsigned mem_entries;
int i, err, mem_off;
enum mem_map mem_map;
u32 config;
char *var, param_name[10], *var_names[] = {
"ememsize", "memsize",
};
/* if a memory node already exists, leave it alone */
mem_off = fdt_path_offset(fdt, "/memory");
if (mem_off >= 0)
return;
/* find memory size from the bootloader environment */
for (i = 0; i < ARRAY_SIZE(var_names); i++) {
var = fw_getenv(var_names[i]);
if (!var)
continue;
err = kstrtoul(var, 0, &physical_memsize);
if (!err)
break;
pr_warn("Failed to read the '%s' env variable '%s'\n",
var_names[i], var);
}
if (!physical_memsize) {
pr_warn("The bootloader didn't provide memsize: defaulting to 32MB\n");
physical_memsize = 32 << 20;
}
if (IS_ENABLED(CONFIG_CPU_BIG_ENDIAN)) {
/*
* SOC-it swaps, or perhaps doesn't swap, when DMA'ing
* the last word of physical memory.
*/
physical_memsize -= PAGE_SIZE;
}
/* default to using all available RAM */
memsize = physical_memsize;
/* allow the user to override the usable memory */
for (i = 0; i < ARRAY_SIZE(var_names); i++) {
snprintf(param_name, sizeof(param_name), "%s=", var_names[i]);
var = strstr(arcs_cmdline, param_name);
if (!var)
continue;
memsize = memparse(var + strlen(param_name), NULL);
}
/* if the user says there's more RAM than we thought, believe them */
physical_memsize = max_t(unsigned long, physical_memsize, memsize);
/* detect the memory map in use */
if (malta_scon() == MIPS_REVISION_SCON_ROCIT) {
/* ROCit has a register indicating the memory map in use */
config = readl((void __iomem *)CKSEG1ADDR(ROCIT_CONFIG_GEN1));
mem_map = config & ROCIT_CONFIG_GEN1_MEMMAP_MASK;
mem_map >>= ROCIT_CONFIG_GEN1_MEMMAP_SHIFT;
} else {
/* if not using ROCit, presume the v1 memory map */
mem_map = MEM_MAP_V1;
}
if (mem_map > MEM_MAP_V2)
panic("Unsupported physical memory map v%u detected",
(unsigned int)mem_map);
/* append memory to the DT */
mem_off = fdt_add_subnode(fdt, root_off, "memory");
if (mem_off < 0)
panic("Unable to add memory node to DT: %d", mem_off);
err = fdt_setprop_string(fdt, mem_off, "device_type", "memory");
if (err)
panic("Unable to set memory node device_type: %d", err);
mem_entries = gen_fdt_mem_array(mem_array, physical_memsize, mem_map);
err = fdt_setprop(fdt, mem_off, "reg", mem_array,
mem_entries * 2 * sizeof(mem_array[0]));
if (err)
panic("Unable to set memory regs property: %d", err);
mem_entries = gen_fdt_mem_array(mem_array, memsize, mem_map);
err = fdt_setprop(fdt, mem_off, "linux,usable-memory", mem_array,
mem_entries * 2 * sizeof(mem_array[0]));
if (err)
panic("Unable to set linux,usable-memory property: %d", err);
}
static void __init remove_gic(void *fdt)
{
int err, gic_off, i8259_off, cpu_off;
void __iomem *biu_base;
uint32_t cpu_phandle, sc_cfg;
/* if we have a CM which reports a GIC is present, leave the DT alone */
err = mips_cm_probe();
if (!err && (read_gcr_gic_status() & CM_GCR_GIC_STATUS_EX))
return;
if (malta_scon() == MIPS_REVISION_SCON_ROCIT) {
/*
* On systems using the RocIT system controller a GIC may be
* present without a CM. Detect whether that is the case.
*/
biu_base = ioremap(MSC01_BIU_REG_BASE,
MSC01_BIU_ADDRSPACE_SZ);
sc_cfg = __raw_readl(biu_base + MSC01_SC_CFG_OFS);
if (sc_cfg & MSC01_SC_CFG_GICPRES_MSK) {
/* enable the GIC at the system controller level */
sc_cfg |= BIT(MSC01_SC_CFG_GICENA_SHF);
__raw_writel(sc_cfg, biu_base + MSC01_SC_CFG_OFS);
return;
}
}
gic_off = fdt_node_offset_by_compatible(fdt, -1, "mti,gic");
if (gic_off < 0) {
pr_warn("malta-dtshim: unable to find DT GIC node: %d\n",
gic_off);
return;
}
err = fdt_nop_node(fdt, gic_off);
if (err)
pr_warn("malta-dtshim: unable to nop GIC node\n");
i8259_off = fdt_node_offset_by_compatible(fdt, -1, "intel,i8259");
if (i8259_off < 0) {
pr_warn("malta-dtshim: unable to find DT i8259 node: %d\n",
i8259_off);
return;
}
cpu_off = fdt_node_offset_by_compatible(fdt, -1,
"mti,cpu-interrupt-controller");
if (cpu_off < 0) {
pr_warn("malta-dtshim: unable to find CPU intc node: %d\n",
cpu_off);
return;
}
cpu_phandle = fdt_get_phandle(fdt, cpu_off);
if (!cpu_phandle) {
pr_warn("malta-dtshim: unable to get CPU intc phandle\n");
return;
}
err = fdt_setprop_u32(fdt, i8259_off, "interrupt-parent", cpu_phandle);
if (err) {
pr_warn("malta-dtshim: unable to set i8259 interrupt-parent: %d\n",
err);
return;
}
err = fdt_setprop_u32(fdt, i8259_off, "interrupts", 2);
if (err) {
pr_warn("malta-dtshim: unable to set i8259 interrupts: %d\n",
err);
return;
}
}
void __init *malta_dt_shim(void *fdt)
{
int root_off, len, err;
const char *compat;
if (fdt_check_header(fdt))
panic("Corrupt DT");
err = fdt_open_into(fdt, fdt_buf, sizeof(fdt_buf));
if (err)
panic("Unable to open FDT: %d", err);
root_off = fdt_path_offset(fdt_buf, "/");
if (root_off < 0)
panic("No / node in DT");
compat = fdt_getprop(fdt_buf, root_off, "compatible", &len);
if (!compat)
panic("No root compatible property in DT: %d", len);
/* if this isn't Malta, leave the DT alone */
if (strncmp(compat, "mti,malta", len))
return fdt;
append_memory(fdt_buf, root_off);
remove_gic(fdt_buf);
err = fdt_pack(fdt_buf);
if (err)
panic("Unable to pack FDT: %d\n", err);
return fdt_buf;
}
@@ -0,0 +1,301 @@
/*
* This file is subject to the terms and conditions of the GNU General Public
* License. See the file "COPYING" in the main directory of this archive
* for more details.
*
* PROM library initialisation code.
*
* Copyright (C) 1999,2000,2004,2005,2012 MIPS Technologies, Inc.
* All rights reserved.
* Authors: Carsten Langgaard <carstenl@mips.com>
* Maciej W. Rozycki <macro@mips.com>
* Steven J. Hill <sjhill@mips.com>
*/
#include <linux/init.h>
#include <linux/string.h>
#include <linux/kernel.h>
#include <linux/pci_regs.h>
#include <linux/serial_core.h>
#include <asm/cacheflush.h>
#include <asm/smp-ops.h>
#include <asm/traps.h>
#include <asm/fw/fw.h>
#include <asm/mips-cps.h>
#include <asm/mips-boards/generic.h>
#include <asm/mips-boards/malta.h>
static int mips_revision_corid;
int mips_revision_sconid;
/* Bonito64 system controller register base. */
unsigned long _pcictrl_bonito;
unsigned long _pcictrl_bonito_pcicfg;
/* GT64120 system controller register base */
unsigned long _pcictrl_gt64120;
/* MIPS System controller register base */
unsigned long _pcictrl_msc;
#ifdef CONFIG_SERIAL_8250_CONSOLE
static void __init console_config(void)
{
char console_string[40];
int baud = 0;
char parity = '\0', bits = '\0', flow = '\0';
char *s;
s = fw_getenv("modetty0");
if (s) {
while (*s >= '0' && *s <= '9')
baud = baud*10 + *s++ - '0';
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;
if (parity != 'n' && parity != 'o' && parity != 'e')
parity = 'n';
if (bits != '7' && bits != '8')
bits = '8';
if (flow == '\0')
flow = 'r';
if ((strstr(fw_getcmdline(), "earlycon=")) == NULL) {
sprintf(console_string, "uart8250,io,0x3f8,%d%c%c", baud,
parity, bits);
setup_earlycon(console_string);
}
if ((strstr(fw_getcmdline(), "console=")) == NULL) {
sprintf(console_string, " console=ttyS0,%d%c%c%c", baud,
parity, bits, flow);
strcat(fw_getcmdline(), console_string);
pr_info("Config serial console:%s\n", console_string);
}
}
#endif
static void __init mips_nmi_setup(void)
{
void *base;
base = cpu_has_veic ?
(void *)(CAC_BASE + 0xa80) :
(void *)(CAC_BASE + 0x380);
memcpy(base, except_vec_nmi, 0x80);
flush_icache_range((unsigned long)base, (unsigned long)base + 0x80);
}
static void __init mips_ejtag_setup(void)
{
void *base;
extern char except_vec_ejtag_debug[];
base = cpu_has_veic ?
(void *)(CAC_BASE + 0xa00) :
(void *)(CAC_BASE + 0x300);
memcpy(base, except_vec_ejtag_debug, 0x80);
flush_icache_range((unsigned long)base, (unsigned long)base + 0x80);
}
phys_addr_t mips_cpc_default_phys_base(void)
{
return CPC_BASE_ADDR;
}
void __init prom_init(void)
{
/*
* early setup of _pcictrl_bonito so that we can determine
* the system controller on a CORE_EMUL board
*/
_pcictrl_bonito = (unsigned long)ioremap(BONITO_REG_BASE, BONITO_REG_SIZE);
mips_revision_corid = MIPS_REVISION_CORID;
if (mips_revision_corid == MIPS_REVISION_CORID_CORE_EMUL) {
if (BONITO_PCIDID == 0x0001df53 ||
BONITO_PCIDID == 0x0003df53)
mips_revision_corid = MIPS_REVISION_CORID_CORE_EMUL_BON;
else
mips_revision_corid = MIPS_REVISION_CORID_CORE_EMUL_MSC;
}
mips_revision_sconid = MIPS_REVISION_SCONID;
if (mips_revision_sconid == MIPS_REVISION_SCON_OTHER) {
switch (mips_revision_corid) {
case MIPS_REVISION_CORID_QED_RM5261:
case MIPS_REVISION_CORID_CORE_LV:
case MIPS_REVISION_CORID_CORE_FPGA:
case MIPS_REVISION_CORID_CORE_FPGAR2:
mips_revision_sconid = MIPS_REVISION_SCON_GT64120;
break;
case MIPS_REVISION_CORID_CORE_EMUL_BON:
case MIPS_REVISION_CORID_BONITO64:
case MIPS_REVISION_CORID_CORE_20K:
mips_revision_sconid = MIPS_REVISION_SCON_BONITO;
break;
case MIPS_REVISION_CORID_CORE_MSC:
case MIPS_REVISION_CORID_CORE_FPGA2:
case MIPS_REVISION_CORID_CORE_24K:
/*
* SOCit/ROCit support is essentially identical
* but make an attempt to distinguish them
*/
mips_revision_sconid = MIPS_REVISION_SCON_SOCIT;
break;
case MIPS_REVISION_CORID_CORE_FPGA3:
case MIPS_REVISION_CORID_CORE_FPGA4:
case MIPS_REVISION_CORID_CORE_FPGA5:
case MIPS_REVISION_CORID_CORE_EMUL_MSC:
default:
/* See above */
mips_revision_sconid = MIPS_REVISION_SCON_ROCIT;
break;
}
}
switch (mips_revision_sconid) {
u32 start, map, mask, data;
case MIPS_REVISION_SCON_GT64120:
/*
* Setup the North bridge to do Master byte-lane swapping
* when running in bigendian.
*/
_pcictrl_gt64120 = (unsigned long)ioremap(MIPS_GT_BASE, 0x2000);
#ifdef CONFIG_CPU_LITTLE_ENDIAN
GT_WRITE(GT_PCI0_CMD_OFS, GT_PCI0_CMD_MBYTESWAP_BIT |
GT_PCI0_CMD_SBYTESWAP_BIT);
#else
GT_WRITE(GT_PCI0_CMD_OFS, 0);
#endif
/* Fix up PCI I/O mapping if necessary (for Atlas). */
start = GT_READ(GT_PCI0IOLD_OFS);
map = GT_READ(GT_PCI0IOREMAP_OFS);
if ((start & map) != 0) {
map &= ~start;
GT_WRITE(GT_PCI0IOREMAP_OFS, map);
}
set_io_port_base(MALTA_GT_PORT_BASE);
break;
case MIPS_REVISION_SCON_BONITO:
_pcictrl_bonito_pcicfg = (unsigned long)ioremap(BONITO_PCICFG_BASE, BONITO_PCICFG_SIZE);
/*
* Disable Bonito IOBC.
*/
BONITO_PCIMEMBASECFG = BONITO_PCIMEMBASECFG &
~(BONITO_PCIMEMBASECFG_MEMBASE0_CACHED |
BONITO_PCIMEMBASECFG_MEMBASE1_CACHED);
/*
* Setup the North bridge to do Master byte-lane swapping
* when running in bigendian.
*/
#ifdef CONFIG_CPU_LITTLE_ENDIAN
BONITO_BONGENCFG = BONITO_BONGENCFG &
~(BONITO_BONGENCFG_MSTRBYTESWAP |
BONITO_BONGENCFG_BYTESWAP);
#else
BONITO_BONGENCFG = BONITO_BONGENCFG |
BONITO_BONGENCFG_MSTRBYTESWAP |
BONITO_BONGENCFG_BYTESWAP;
#endif
set_io_port_base(MALTA_BONITO_PORT_BASE);
break;
case MIPS_REVISION_SCON_SOCIT:
case MIPS_REVISION_SCON_ROCIT:
_pcictrl_msc = (unsigned long)ioremap(MIPS_MSC01_PCI_REG_BASE, 0x2000);
mips_pci_controller:
mb();
MSC_READ(MSC01_PCI_CFG, data);
MSC_WRITE(MSC01_PCI_CFG, data & ~MSC01_PCI_CFG_EN_BIT);
wmb();
/* Fix up lane swapping. */
#ifdef CONFIG_CPU_LITTLE_ENDIAN
MSC_WRITE(MSC01_PCI_SWAP, MSC01_PCI_SWAP_NOSWAP);
#else
MSC_WRITE(MSC01_PCI_SWAP,
MSC01_PCI_SWAP_BYTESWAP << MSC01_PCI_SWAP_IO_SHF |
MSC01_PCI_SWAP_BYTESWAP << MSC01_PCI_SWAP_MEM_SHF |
MSC01_PCI_SWAP_BYTESWAP << MSC01_PCI_SWAP_BAR0_SHF);
#endif
/*
* Set up memory mapping in host bridge for PCI DMA masters,
* in transparent addressing mode. For EVA use the Malta
* maximum of 2 GiB memory in the alias space at 0x80000000
* as per PHYS_OFFSET. Otherwise use 256 MiB of memory in
* the regular space, avoiding mapping the PCI MMIO window
* for DMA as it seems to confuse the system controller's
* logic, causing PCI MMIO to stop working.
*/
mask = PHYS_OFFSET ? PHYS_OFFSET : 0xf0000000;
MSC_WRITE(MSC01_PCI_BAR0,
mask | PCI_BASE_ADDRESS_MEM_PREFETCH);
MSC_WRITE(MSC01_PCI_HEAD4,
PHYS_OFFSET | PCI_BASE_ADDRESS_MEM_PREFETCH);
MSC_WRITE(MSC01_PCI_P2SCMSKL, mask);
MSC_WRITE(MSC01_PCI_P2SCMAPL, PHYS_OFFSET);
/* Don't handle target retries indefinitely. */
if ((data & MSC01_PCI_CFG_MAXRTRY_MSK) ==
MSC01_PCI_CFG_MAXRTRY_MSK)
data = (data & ~(MSC01_PCI_CFG_MAXRTRY_MSK <<
MSC01_PCI_CFG_MAXRTRY_SHF)) |
((MSC01_PCI_CFG_MAXRTRY_MSK - 1) <<
MSC01_PCI_CFG_MAXRTRY_SHF);
wmb();
MSC_WRITE(MSC01_PCI_CFG, data);
mb();
set_io_port_base(MALTA_MSC_PORT_BASE);
break;
case MIPS_REVISION_SCON_SOCITSC:
case MIPS_REVISION_SCON_SOCITSCP:
_pcictrl_msc = (unsigned long)ioremap(MIPS_SOCITSC_PCI_REG_BASE, 0x2000);
goto mips_pci_controller;
default:
/* Unknown system controller */
while (1); /* We die here... */
}
board_nmi_handler_setup = mips_nmi_setup;
board_ejtag_handler_setup = mips_ejtag_setup;
fw_init_cmdline();
fw_meminit();
#ifdef CONFIG_SERIAL_8250_CONSOLE
console_config();
#endif
/* Early detection of CMP support */
mips_cpc_probe();
if (!register_cps_smp_ops())
return;
if (!register_vsmp_smp_ops())
return;
register_up_smp_ops();
}
+223
View File
@@ -0,0 +1,223 @@
/*
* This file is subject to the terms and conditions of the GNU General Public
* License. See the file "COPYING" in the main directory of this archive
* for more details.
*
* Carsten Langgaard, carstenl@mips.com
* Copyright (C) 2000, 2001, 2004 MIPS Technologies, Inc.
* Copyright (C) 2001 Ralf Baechle
* Copyright (C) 2013 Imagination Technologies Ltd.
*
* Routines for generic manipulation of the interrupts found on the MIPS
* Malta board. The interrupt controller is located in the South Bridge
* a PIIX4 device with two internal 82C95 interrupt controllers.
*/
#include <linux/init.h>
#include <linux/irq.h>
#include <linux/irqchip.h>
#include <linux/sched.h>
#include <linux/smp.h>
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/of_irq.h>
#include <linux/kernel_stat.h>
#include <linux/kernel.h>
#include <linux/random.h>
#include <asm/traps.h>
#include <asm/i8259.h>
#include <asm/irq_cpu.h>
#include <asm/irq_regs.h>
#include <asm/mips-boards/malta.h>
#include <asm/mips-boards/maltaint.h>
#include <asm/mips-cps.h>
#include <asm/gt64120.h>
#include <asm/mips-boards/generic.h>
#include <asm/mips-boards/msc01_pci.h>
#include <asm/msc01_ic.h>
#include <asm/setup.h>
#include <asm/rtlx.h>
static inline int mips_pcibios_iack(void)
{
int irq;
/*
* Determine highest priority pending interrupt by performing
* a PCI Interrupt Acknowledge cycle.
*/
switch (mips_revision_sconid) {
case MIPS_REVISION_SCON_SOCIT:
case MIPS_REVISION_SCON_ROCIT:
case MIPS_REVISION_SCON_SOCITSC:
case MIPS_REVISION_SCON_SOCITSCP:
MSC_READ(MSC01_PCI_IACK, irq);
irq &= 0xff;
break;
case MIPS_REVISION_SCON_GT64120:
irq = GT_READ(GT_PCI0_IACK_OFS);
irq &= 0xff;
break;
case MIPS_REVISION_SCON_BONITO:
/* The following will generate a PCI IACK cycle on the
* Bonito controller. It's a little bit kludgy, but it
* was the easiest way to implement it in hardware at
* the given time.
*/
BONITO_PCIMAP_CFG = 0x20000;
/* Flush Bonito register block */
(void) BONITO_PCIMAP_CFG;
iob(); /* sync */
irq = __raw_readl((u32 *)_pcictrl_bonito_pcicfg);
iob(); /* sync */
irq &= 0xff;
BONITO_PCIMAP_CFG = 0;
break;
default:
pr_emerg("Unknown system controller.\n");
return -1;
}
return irq;
}
static void corehi_irqdispatch(void)
{
unsigned int intedge, intsteer, pcicmd, pcibadaddr;
unsigned int pcimstat, intisr, inten, intpol;
unsigned int intrcause, datalo, datahi;
struct pt_regs *regs = get_irq_regs();
pr_emerg("CoreHI interrupt, shouldn't happen, we die here!\n");
pr_emerg("epc : %08lx\nStatus: %08lx\n"
"Cause : %08lx\nbadVaddr : %08lx\n",
regs->cp0_epc, regs->cp0_status,
regs->cp0_cause, regs->cp0_badvaddr);
/* Read all the registers and then print them as there is a
problem with interspersed printk's upsetting the Bonito controller.
Do it for the others too.
*/
switch (mips_revision_sconid) {
case MIPS_REVISION_SCON_SOCIT:
case MIPS_REVISION_SCON_ROCIT:
case MIPS_REVISION_SCON_SOCITSC:
case MIPS_REVISION_SCON_SOCITSCP:
ll_msc_irq();
break;
case MIPS_REVISION_SCON_GT64120:
intrcause = GT_READ(GT_INTRCAUSE_OFS);
datalo = GT_READ(GT_CPUERR_ADDRLO_OFS);
datahi = GT_READ(GT_CPUERR_ADDRHI_OFS);
pr_emerg("GT_INTRCAUSE = %08x\n", intrcause);
pr_emerg("GT_CPUERR_ADDR = %02x%08x\n",
datahi, datalo);
break;
case MIPS_REVISION_SCON_BONITO:
pcibadaddr = BONITO_PCIBADADDR;
pcimstat = BONITO_PCIMSTAT;
intisr = BONITO_INTISR;
inten = BONITO_INTEN;
intpol = BONITO_INTPOL;
intedge = BONITO_INTEDGE;
intsteer = BONITO_INTSTEER;
pcicmd = BONITO_PCICMD;
pr_emerg("BONITO_INTISR = %08x\n", intisr);
pr_emerg("BONITO_INTEN = %08x\n", inten);
pr_emerg("BONITO_INTPOL = %08x\n", intpol);
pr_emerg("BONITO_INTEDGE = %08x\n", intedge);
pr_emerg("BONITO_INTSTEER = %08x\n", intsteer);
pr_emerg("BONITO_PCICMD = %08x\n", pcicmd);
pr_emerg("BONITO_PCIBADADDR = %08x\n", pcibadaddr);
pr_emerg("BONITO_PCIMSTAT = %08x\n", pcimstat);
break;
}
die("CoreHi interrupt", regs);
}
static irqreturn_t corehi_handler(int irq, void *dev_id)
{
corehi_irqdispatch();
return IRQ_HANDLED;
}
static msc_irqmap_t msc_irqmap[] __initdata = {
{MSC01C_INT_TMR, MSC01_IRQ_EDGE, 0},
{MSC01C_INT_PCI, MSC01_IRQ_LEVEL, 0},
};
static int msc_nr_irqs __initdata = ARRAY_SIZE(msc_irqmap);
static msc_irqmap_t msc_eicirqmap[] __initdata = {
{MSC01E_INT_SW0, MSC01_IRQ_LEVEL, 0},
{MSC01E_INT_SW1, MSC01_IRQ_LEVEL, 0},
{MSC01E_INT_I8259A, MSC01_IRQ_LEVEL, 0},
{MSC01E_INT_SMI, MSC01_IRQ_LEVEL, 0},
{MSC01E_INT_COREHI, MSC01_IRQ_LEVEL, 0},
{MSC01E_INT_CORELO, MSC01_IRQ_LEVEL, 0},
{MSC01E_INT_TMR, MSC01_IRQ_EDGE, 0},
{MSC01E_INT_PCI, MSC01_IRQ_LEVEL, 0},
{MSC01E_INT_PERFCTR, MSC01_IRQ_LEVEL, 0},
{MSC01E_INT_CPUCTR, MSC01_IRQ_LEVEL, 0}
};
static int msc_nr_eicirqs __initdata = ARRAY_SIZE(msc_eicirqmap);
void __init arch_init_irq(void)
{
int corehi_irq;
/*
* Preallocate the i8259's expected virq's here. Since irqchip_init()
* will probe the irqchips in hierarchial order, i8259 is probed last.
* If anything allocates a virq before the i8259 is probed, it will
* be given one of the i8259's expected range and consequently setup
* of the i8259 will fail.
*/
WARN(irq_alloc_descs(I8259A_IRQ_BASE, I8259A_IRQ_BASE,
16, numa_node_id()) < 0,
"Cannot reserve i8259 virqs at IRQ%d\n", I8259A_IRQ_BASE);
i8259_set_poll(mips_pcibios_iack);
irqchip_init();
switch (mips_revision_sconid) {
case MIPS_REVISION_SCON_SOCIT:
case MIPS_REVISION_SCON_ROCIT:
if (cpu_has_veic)
init_msc_irqs(MIPS_MSC01_IC_REG_BASE,
MSC01E_INT_BASE, msc_eicirqmap,
msc_nr_eicirqs);
else
init_msc_irqs(MIPS_MSC01_IC_REG_BASE,
MSC01C_INT_BASE, msc_irqmap,
msc_nr_irqs);
break;
case MIPS_REVISION_SCON_SOCITSC:
case MIPS_REVISION_SCON_SOCITSCP:
if (cpu_has_veic)
init_msc_irqs(MIPS_SOCITSC_IC_REG_BASE,
MSC01E_INT_BASE, msc_eicirqmap,
msc_nr_eicirqs);
else
init_msc_irqs(MIPS_SOCITSC_IC_REG_BASE,
MSC01C_INT_BASE, msc_irqmap,
msc_nr_irqs);
}
if (mips_gic_present()) {
corehi_irq = MIPS_CPU_IRQ_BASE + MIPSCPU_INT_COREHI;
} else if (cpu_has_veic) {
set_vi_handler(MSC01E_INT_COREHI, corehi_irqdispatch);
corehi_irq = MSC01E_INT_BASE + MSC01E_INT_COREHI;
} else {
corehi_irq = MIPS_CPU_IRQ_BASE + MIPSCPU_INT_COREHI;
}
if (request_irq(corehi_irq, corehi_handler, IRQF_NO_THREAD, "CoreHi",
NULL))
pr_err("Failed to request irq %d (CoreHi)\n", corehi_irq);
}
@@ -0,0 +1,44 @@
/*
* This file is subject to the terms and conditions of the GNU General Public
* License. See the file "COPYING" in the main directory of this archive
* for more details.
*
* PROM library functions for acquiring/using memory descriptors given to
* us from the YAMON.
*
* Copyright (C) 1999,2000,2012 MIPS Technologies, Inc.
* All rights reserved.
* Authors: Carsten Langgaard <carstenl@mips.com>
* Steven J. Hill <sjhill@mips.com>
*/
#include <linux/init.h>
#include <linux/memblock.h>
#include <linux/string.h>
#include <asm/bootinfo.h>
#include <asm/cdmm.h>
#include <asm/maar.h>
#include <asm/sections.h>
#include <asm/fw/fw.h>
/* determined physical memory size, not overridden by command line args */
unsigned long physical_memsize = 0L;
static void free_init_pages_eva_malta(void *begin, void *end)
{
free_init_pages("unused kernel", __pa_symbol((unsigned long *)begin),
__pa_symbol((unsigned long *)end));
}
void __init fw_meminit(void)
{
bool eva = IS_ENABLED(CONFIG_EVA);
free_init_pages_eva = eva ? free_init_pages_eva_malta : NULL;
}
phys_addr_t mips_cdmm_phys_base(void)
{
/* This address is "typically unused" */
return 0x1fc10000;
}
@@ -0,0 +1,75 @@
/*
* This file is subject to the terms and conditions of the GNU General Public
* License. See the file "COPYING" in the main directory of this archive
* for more details.
*
* Copyright (C) 2006, 07 MIPS Technologies, Inc.
* written by Ralf Baechle (ralf@linux-mips.org)
* written by Ralf Baechle <ralf@linux-mips.org>
*
* Copyright (C) 2008 Wind River Systems, Inc.
* updated by Tiejun Chen <tiejun.chen@windriver.com>
*
* 1. Probe driver for the Malta's UART ports:
*
* o 2 ports in the SMC SuperIO
* o 1 port in the CBUS UART, a discrete 16550 which normally is only used
* for bringups.
*
* We don't use 8250_platform.c on Malta as it would result in the CBUS
* UART becoming ttyS0.
*
* 2. Register RTC-CMOS platform device on Malta.
*/
#include <linux/init.h>
#include <linux/serial_8250.h>
#include <linux/irq.h>
#include <linux/platform_device.h>
#include <asm/mips-boards/maltaint.h>
#define SMC_PORT(base, int) \
{ \
.iobase = base, \
.irq = int, \
.uartclk = 1843200, \
.iotype = UPIO_PORT, \
.flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST | \
UPF_MAGIC_MULTIPLIER, \
.regshift = 0, \
}
#define CBUS_UART_FLAGS (UPF_BOOT_AUTOCONF | UPF_SKIP_TEST | UPF_IOREMAP)
static struct plat_serial8250_port uart8250_data[] = {
SMC_PORT(0x3F8, 4),
SMC_PORT(0x2F8, 3),
{
.mapbase = 0x1f000900, /* The CBUS UART */
.irq = MIPS_CPU_IRQ_BASE + MIPSCPU_INT_MB2,
.uartclk = 3686400, /* Twice the usual clk! */
.iotype = IS_ENABLED(CONFIG_CPU_BIG_ENDIAN) ?
UPIO_MEM32BE : UPIO_MEM32,
.flags = CBUS_UART_FLAGS,
.regshift = 3,
},
{ },
};
static struct platform_device malta_uart8250_device = {
.name = "serial8250",
.id = PLAT8250_DEV_PLATFORM,
.dev = {
.platform_data = uart8250_data,
},
};
static struct platform_device *malta_devices[] __initdata = {
&malta_uart8250_device,
};
static int __init malta_add_devices(void)
{
return platform_add_devices(malta_devices, ARRAY_SIZE(malta_devices));
}
device_initcall(malta_add_devices);
@@ -0,0 +1,237 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Carsten Langgaard, carstenl@mips.com
* Copyright (C) 2000 MIPS Technologies, Inc. All rights reserved.
* Copyright (C) 2008 Dmitri Vorobiev
*/
#include <linux/cpu.h>
#include <linux/init.h>
#include <linux/sched.h>
#include <linux/ioport.h>
#include <linux/irq.h>
#include <linux/of_fdt.h>
#include <linux/pci.h>
#include <linux/screen_info.h>
#include <linux/time.h>
#include <linux/dma-map-ops.h> /* for dma_default_coherent */
#include <asm/fw/fw.h>
#include <asm/mips-cps.h>
#include <asm/mips-boards/generic.h>
#include <asm/mips-boards/malta.h>
#include <asm/mips-boards/maltaint.h>
#include <asm/dma.h>
#include <asm/prom.h>
#include <asm/traps.h>
#ifdef CONFIG_VT
#include <linux/console.h>
#endif
#define ROCIT_CONFIG_GEN0 0x1f403000
#define ROCIT_CONFIG_GEN0_PCI_IOCU BIT(7)
static struct resource standard_io_resources[] = {
{
.name = "dma1",
.start = 0x00,
.end = 0x1f,
.flags = IORESOURCE_IO | IORESOURCE_BUSY
},
{
.name = "timer",
.start = 0x40,
.end = 0x5f,
.flags = IORESOURCE_IO | IORESOURCE_BUSY
},
{
.name = "keyboard",
.start = 0x60,
.end = 0x6f,
.flags = IORESOURCE_IO
},
{
.name = "dma page reg",
.start = 0x80,
.end = 0x8f,
.flags = IORESOURCE_IO | IORESOURCE_BUSY
},
{
.name = "dma2",
.start = 0xc0,
.end = 0xdf,
.flags = IORESOURCE_IO | IORESOURCE_BUSY
},
};
const char *get_system_type(void)
{
return "MIPS Malta";
}
#ifdef CONFIG_BLK_DEV_FD
static void __init fd_activate(void)
{
/*
* Activate Floppy Controller in the SMSC FDC37M817 Super I/O
* Controller.
* Done by YAMON 2.00 onwards
*/
/* Entering config state. */
SMSC_WRITE(SMSC_CONFIG_ENTER, SMSC_CONFIG_REG);
/* Activate floppy controller. */
SMSC_WRITE(SMSC_CONFIG_DEVNUM, SMSC_CONFIG_REG);
SMSC_WRITE(SMSC_CONFIG_DEVNUM_FLOPPY, SMSC_DATA_REG);
SMSC_WRITE(SMSC_CONFIG_ACTIVATE, SMSC_CONFIG_REG);
SMSC_WRITE(SMSC_CONFIG_ACTIVATE_ENABLE, SMSC_DATA_REG);
/* Exit config state. */
SMSC_WRITE(SMSC_CONFIG_EXIT, SMSC_CONFIG_REG);
}
#endif
static void __init plat_setup_iocoherency(void)
{
u32 cfg;
if (mips_revision_sconid == MIPS_REVISION_SCON_BONITO) {
if (BONITO_PCICACHECTRL & BONITO_PCICACHECTRL_CPUCOH_PRES) {
BONITO_PCICACHECTRL |= BONITO_PCICACHECTRL_CPUCOH_EN;
pr_info("Enabled Bonito CPU coherency\n");
dma_default_coherent = true;
}
if (strstr(fw_getcmdline(), "iobcuncached")) {
BONITO_PCICACHECTRL &= ~BONITO_PCICACHECTRL_IOBCCOH_EN;
BONITO_PCIMEMBASECFG = BONITO_PCIMEMBASECFG &
~(BONITO_PCIMEMBASECFG_MEMBASE0_CACHED |
BONITO_PCIMEMBASECFG_MEMBASE1_CACHED);
pr_info("Disabled Bonito IOBC coherency\n");
} else {
BONITO_PCICACHECTRL |= BONITO_PCICACHECTRL_IOBCCOH_EN;
BONITO_PCIMEMBASECFG |=
(BONITO_PCIMEMBASECFG_MEMBASE0_CACHED |
BONITO_PCIMEMBASECFG_MEMBASE1_CACHED);
pr_info("Enabled Bonito IOBC coherency\n");
}
} else if (mips_cps_numiocu(0) != 0) {
/* Nothing special needs to be done to enable coherency */
pr_info("CMP IOCU detected\n");
cfg = __raw_readl((u32 *)CKSEG1ADDR(ROCIT_CONFIG_GEN0));
if (cfg & ROCIT_CONFIG_GEN0_PCI_IOCU)
dma_default_coherent = true;
else
pr_crit("IOCU OPERATION DISABLED BY SWITCH - DEFAULTING TO SW IO COHERENCY\n");
}
if (dma_default_coherent)
pr_info("Hardware DMA cache coherency enabled\n");
else
pr_info("Software DMA cache coherency enabled\n");
}
static void __init pci_clock_check(void)
{
unsigned int __iomem *jmpr_p =
(unsigned int *) ioremap(MALTA_JMPRS_REG, sizeof(unsigned int));
int jmpr = (__raw_readl(jmpr_p) >> 2) & 0x07;
static const int pciclocks[] __initconst = {
33, 20, 25, 30, 12, 16, 37, 10
};
int pciclock = pciclocks[jmpr];
char *optptr, *argptr = fw_getcmdline();
/*
* If user passed a pci_clock= option, don't tack on another one
*/
optptr = strstr(argptr, "pci_clock=");
if (optptr && (optptr == argptr || optptr[-1] == ' '))
return;
if (pciclock != 33) {
pr_warn("WARNING: PCI clock is %dMHz, setting pci_clock\n",
pciclock);
argptr += strlen(argptr);
sprintf(argptr, " pci_clock=%d", pciclock);
if (pciclock < 20 || pciclock > 66)
pr_warn("WARNING: IDE timing calculations will be "
"incorrect\n");
}
}
#if defined(CONFIG_VT) && defined(CONFIG_VGA_CONSOLE)
static void __init screen_info_setup(void)
{
static struct screen_info si = {
.orig_x = 0,
.orig_y = 25,
.ext_mem_k = 0,
.orig_video_page = 0,
.orig_video_mode = 0,
.orig_video_cols = 80,
.unused2 = 0,
.orig_video_ega_bx = 0,
.unused3 = 0,
.orig_video_lines = 25,
.orig_video_isVGA = VIDEO_TYPE_VGAC,
.orig_video_points = 16
};
vgacon_register_screen(&si);
}
#endif
static void __init bonito_quirks_setup(void)
{
char *argptr;
argptr = fw_getcmdline();
if (strstr(argptr, "debug")) {
BONITO_BONGENCFG |= BONITO_BONGENCFG_DEBUGMODE;
pr_info("Enabled Bonito debug mode\n");
} else
BONITO_BONGENCFG &= ~BONITO_BONGENCFG_DEBUGMODE;
}
void __init *plat_get_fdt(void)
{
return (void *)__dtb_start;
}
void __init plat_mem_setup(void)
{
unsigned int i;
void *fdt = plat_get_fdt();
fdt = malta_dt_shim(fdt);
__dt_setup_arch(fdt);
if (IS_ENABLED(CONFIG_EVA))
/* EVA has already been configured in mach-malta/kernel-init.h */
pr_info("Enhanced Virtual Addressing (EVA) activated\n");
mips_pcibios_init();
/* Request I/O space for devices used on the Malta board. */
for (i = 0; i < ARRAY_SIZE(standard_io_resources); i++)
insert_resource(&ioport_resource, standard_io_resources + i);
/*
* Enable DMA channel 4 (cascade channel) in the PIIX4 south bridge.
*/
enable_dma(4);
if (mips_revision_sconid == MIPS_REVISION_SCON_BONITO)
bonito_quirks_setup();
plat_setup_iocoherency();
pci_clock_check();
#ifdef CONFIG_BLK_DEV_FD
fd_activate();
#endif
#if defined(CONFIG_VT) && defined(CONFIG_VGA_CONSOLE)
screen_info_setup();
#endif
}
@@ -0,0 +1,253 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Carsten Langgaard, carstenl@mips.com
* Copyright (C) 1999,2000 MIPS Technologies, Inc. All rights reserved.
*
* Setting up the clock on the MIPS boards.
*/
#include <linux/types.h>
#include <linux/i8253.h>
#include <linux/init.h>
#include <linux/kernel_stat.h>
#include <linux/libfdt.h>
#include <linux/math64.h>
#include <linux/sched.h>
#include <linux/spinlock.h>
#include <linux/interrupt.h>
#include <linux/timex.h>
#include <linux/mc146818rtc.h>
#include <asm/cpu.h>
#include <asm/mipsregs.h>
#include <asm/mipsmtregs.h>
#include <asm/hardirq.h>
#include <asm/irq.h>
#include <asm/div64.h>
#include <asm/setup.h>
#include <asm/time.h>
#include <asm/mc146818-time.h>
#include <asm/msc01_ic.h>
#include <asm/mips-cps.h>
#include <asm/mips-boards/generic.h>
#include <asm/mips-boards/maltaint.h>
static int mips_cpu_timer_irq;
static int mips_cpu_perf_irq;
extern int cp0_perfcount_irq;
static unsigned int gic_frequency;
static void mips_timer_dispatch(void)
{
do_IRQ(mips_cpu_timer_irq);
}
static void mips_perf_dispatch(void)
{
do_IRQ(mips_cpu_perf_irq);
}
static unsigned int freqround(unsigned int freq, unsigned int amount)
{
freq += amount;
freq -= freq % (amount*2);
return freq;
}
/*
* Estimate CPU and GIC frequencies.
*/
static void __init estimate_frequencies(void)
{
unsigned long flags;
unsigned int count, start;
unsigned char secs1, secs2, ctrl;
int secs;
u64 giccount = 0, gicstart = 0;
local_irq_save(flags);
if (mips_gic_present())
clear_gic_config(GIC_CONFIG_COUNTSTOP);
/*
* Read counters exactly on rising edge of update flag.
* This helps get an accurate reading under virtualisation.
*/
while (CMOS_READ(RTC_REG_A) & RTC_UIP);
while (!(CMOS_READ(RTC_REG_A) & RTC_UIP));
start = read_c0_count();
if (mips_gic_present())
gicstart = read_gic_counter();
/* Wait for falling edge before reading RTC. */
while (CMOS_READ(RTC_REG_A) & RTC_UIP);
secs1 = CMOS_READ(RTC_SECONDS);
/* Read counters again exactly on rising edge of update flag. */
while (!(CMOS_READ(RTC_REG_A) & RTC_UIP));
count = read_c0_count();
if (mips_gic_present())
giccount = read_gic_counter();
/* Wait for falling edge before reading RTC again. */
while (CMOS_READ(RTC_REG_A) & RTC_UIP);
secs2 = CMOS_READ(RTC_SECONDS);
ctrl = CMOS_READ(RTC_CONTROL);
local_irq_restore(flags);
if (!(ctrl & RTC_DM_BINARY) || RTC_ALWAYS_BCD) {
secs1 = bcd2bin(secs1);
secs2 = bcd2bin(secs2);
}
secs = secs2 - secs1;
if (secs < 1)
secs += 60;
count -= start;
count /= secs;
mips_hpt_frequency = count;
if (mips_gic_present()) {
giccount = div_u64(giccount - gicstart, secs);
gic_frequency = giccount;
}
}
void read_persistent_clock64(struct timespec64 *ts)
{
ts->tv_sec = mc146818_get_cmos_time();
ts->tv_nsec = 0;
}
int get_c0_fdc_int(void)
{
/*
* Some cores claim the FDC is routable through the GIC, but it doesn't
* actually seem to be connected for those Malta bitstreams.
*/
switch (current_cpu_type()) {
case CPU_INTERAPTIV:
case CPU_PROAPTIV:
return -1;
}
if (cpu_has_veic)
return -1;
else if (mips_gic_present())
return gic_get_c0_fdc_int();
else if (cp0_fdc_irq >= 0)
return MIPS_CPU_IRQ_BASE + cp0_fdc_irq;
else
return -1;
}
int get_c0_perfcount_int(void)
{
if (cpu_has_veic) {
set_vi_handler(MSC01E_INT_PERFCTR, mips_perf_dispatch);
mips_cpu_perf_irq = MSC01E_INT_BASE + MSC01E_INT_PERFCTR;
} else if (mips_gic_present()) {
mips_cpu_perf_irq = gic_get_c0_perfcount_int();
} else if (cp0_perfcount_irq >= 0) {
mips_cpu_perf_irq = MIPS_CPU_IRQ_BASE + cp0_perfcount_irq;
} else {
mips_cpu_perf_irq = -1;
}
return mips_cpu_perf_irq;
}
EXPORT_SYMBOL_GPL(get_c0_perfcount_int);
unsigned int get_c0_compare_int(void)
{
if (cpu_has_veic) {
set_vi_handler(MSC01E_INT_CPUCTR, mips_timer_dispatch);
mips_cpu_timer_irq = MSC01E_INT_BASE + MSC01E_INT_CPUCTR;
} else if (mips_gic_present()) {
mips_cpu_timer_irq = gic_get_c0_compare_int();
} else {
mips_cpu_timer_irq = MIPS_CPU_IRQ_BASE + cp0_compare_irq;
}
return mips_cpu_timer_irq;
}
static void __init init_rtc(void)
{
unsigned char freq, ctrl;
/* Set 32KHz time base if not already set */
freq = CMOS_READ(RTC_FREQ_SELECT);
if ((freq & RTC_DIV_CTL) != RTC_REF_CLCK_32KHZ)
CMOS_WRITE(RTC_REF_CLCK_32KHZ, RTC_FREQ_SELECT);
/* Ensure SET bit is clear so RTC can run */
ctrl = CMOS_READ(RTC_CONTROL);
if (ctrl & RTC_SET)
CMOS_WRITE(ctrl & ~RTC_SET, RTC_CONTROL);
}
#ifdef CONFIG_CLKSRC_MIPS_GIC
static u32 gic_frequency_dt;
static struct property gic_frequency_prop = {
.name = "clock-frequency",
.length = sizeof(u32),
.value = &gic_frequency_dt,
};
static void update_gic_frequency_dt(void)
{
struct device_node *node;
gic_frequency_dt = cpu_to_be32(gic_frequency);
node = of_find_compatible_node(NULL, NULL, "mti,gic-timer");
if (!node) {
pr_err("mti,gic-timer device node not found\n");
return;
}
if (of_update_property(node, &gic_frequency_prop) < 0)
pr_err("error updating gic frequency property\n");
of_node_put(node);
}
#endif
void __init plat_time_init(void)
{
unsigned int prid = read_c0_prid() & (PRID_COMP_MASK | PRID_IMP_MASK);
unsigned int freq;
init_rtc();
estimate_frequencies();
freq = mips_hpt_frequency;
if ((prid != (PRID_COMP_MIPS | PRID_IMP_20KC)) &&
(prid != (PRID_COMP_MIPS | PRID_IMP_25KF)))
freq *= 2;
freq = freqround(freq, 5000);
printk("CPU frequency %d.%02d MHz\n", freq/1000000,
(freq%1000000)*100/1000000);
#ifdef CONFIG_I8253
/* Only Malta has a PIT. */
setup_pit_timer();
#endif
if (mips_gic_present()) {
freq = freqround(gic_frequency, 5000);
printk("GIC frequency %d.%02d MHz\n", freq/1000000,
(freq%1000000)*100/1000000);
#ifdef CONFIG_CLKSRC_MIPS_GIC
update_gic_frequency_dt();
timer_probe();
#endif
}
}