2019-05-27 14:55:01 +08:00
|
|
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
2009-07-02 23:22:36 +08:00
|
|
|
/*
|
|
|
|
* Based on Ocelot Linux port, which is
|
|
|
|
* Copyright 2001 MontaVista Software Inc.
|
|
|
|
* Author: jsun@mvista.com or jsun@junsun.net
|
|
|
|
*
|
|
|
|
* Copyright 2003 ICT CAS
|
|
|
|
* Author: Michael Guo <guoyi@ict.ac.cn>
|
|
|
|
*
|
2015-07-08 02:56:04 +08:00
|
|
|
* Copyright (C) 2007 Lemote Inc. & Institute of Computing Technology
|
2009-07-02 23:22:36 +08:00
|
|
|
* Author: Fuxin Zhang, zhangfx@lemote.com
|
|
|
|
*
|
2010-01-04 17:16:51 +08:00
|
|
|
* Copyright (C) 2009 Lemote Inc.
|
|
|
|
* Author: Wu Zhangjin, wuzhangjin@gmail.com
|
2009-07-02 23:22:36 +08:00
|
|
|
*/
|
2017-01-29 10:05:57 +08:00
|
|
|
#include <linux/export.h>
|
2020-04-03 17:29:49 +08:00
|
|
|
#include <linux/pci_ids.h>
|
2009-07-02 23:22:36 +08:00
|
|
|
#include <asm/bootinfo.h>
|
2009-07-02 23:23:03 +08:00
|
|
|
#include <loongson.h>
|
2014-03-21 18:44:02 +08:00
|
|
|
#include <boot_param.h>
|
2020-03-25 11:55:03 +08:00
|
|
|
#include <builtin_dtbs.h>
|
2014-11-04 14:13:27 +08:00
|
|
|
#include <workarounds.h>
|
2009-07-02 23:23:03 +08:00
|
|
|
|
2020-04-03 17:29:49 +08:00
|
|
|
#define HOST_BRIDGE_CONFIG_ADDR ((void __iomem *)TO_UNCAC(0x1a000000))
|
|
|
|
|
2014-03-21 18:44:02 +08:00
|
|
|
u32 cpu_clock_freq;
|
2009-11-17 01:32:59 +08:00
|
|
|
EXPORT_SYMBOL(cpu_clock_freq);
|
2014-03-21 18:44:02 +08:00
|
|
|
struct efi_memory_map_loongson *loongson_memmap;
|
|
|
|
struct loongson_system_configuration loongson_sysconf;
|
2009-07-02 23:22:36 +08:00
|
|
|
|
2020-10-13 13:55:01 +08:00
|
|
|
struct board_devices *eboard;
|
|
|
|
struct interface_info *einter;
|
|
|
|
struct loongson_special_attribute *especial;
|
|
|
|
|
2014-06-26 11:41:27 +08:00
|
|
|
u64 loongson_chipcfg[MAX_PACKAGES] = {0xffffffffbfc00180};
|
2015-03-29 10:54:09 +08:00
|
|
|
u64 loongson_chiptemp[MAX_PACKAGES];
|
2014-06-26 11:41:30 +08:00
|
|
|
u64 loongson_freqctrl[MAX_PACKAGES];
|
|
|
|
|
|
|
|
unsigned long long smp_group[4];
|
2014-06-26 11:41:27 +08:00
|
|
|
|
2019-10-20 23:01:35 +08:00
|
|
|
const char *get_system_type(void)
|
|
|
|
{
|
|
|
|
return "Generic Loongson64 System";
|
|
|
|
}
|
2009-07-02 23:22:36 +08:00
|
|
|
|
2021-03-15 15:49:59 +08:00
|
|
|
|
|
|
|
void __init prom_dtb_init_env(void)
|
|
|
|
{
|
|
|
|
if ((fw_arg2 < CKSEG0 || fw_arg2 > CKSEG1)
|
|
|
|
&& (fw_arg2 < XKPHYS || fw_arg2 > XKSEG))
|
|
|
|
|
|
|
|
loongson_fdt_blob = __dtb_loongson64_2core_2k1000_begin;
|
|
|
|
else
|
|
|
|
loongson_fdt_blob = (void *)fw_arg2;
|
|
|
|
}
|
|
|
|
|
|
|
|
void __init prom_lefi_init_env(void)
|
2009-07-02 23:22:36 +08:00
|
|
|
{
|
2014-03-21 18:44:02 +08:00
|
|
|
struct boot_params *boot_p;
|
|
|
|
struct loongson_params *loongson_p;
|
2014-11-04 14:13:27 +08:00
|
|
|
struct system_loongson *esys;
|
2014-03-21 18:44:02 +08:00
|
|
|
struct efi_cpuinfo_loongson *ecpu;
|
|
|
|
struct irq_source_routing_table *eirq_source;
|
2020-04-03 17:29:49 +08:00
|
|
|
u32 id;
|
2021-05-14 18:32:17 +08:00
|
|
|
u16 vendor;
|
2014-03-21 18:44:02 +08:00
|
|
|
|
|
|
|
/* firmware arguments are initialized in head.S */
|
|
|
|
boot_p = (struct boot_params *)fw_arg2;
|
|
|
|
loongson_p = &(boot_p->efi.smbios.lp);
|
|
|
|
|
2014-11-04 14:13:27 +08:00
|
|
|
esys = (struct system_loongson *)
|
|
|
|
((u64)loongson_p + loongson_p->system_offset);
|
2014-03-21 18:44:02 +08:00
|
|
|
ecpu = (struct efi_cpuinfo_loongson *)
|
|
|
|
((u64)loongson_p + loongson_p->cpu_offset);
|
2020-10-13 13:55:01 +08:00
|
|
|
eboard = (struct board_devices *)
|
|
|
|
((u64)loongson_p + loongson_p->boarddev_table_offset);
|
|
|
|
einter = (struct interface_info *)
|
|
|
|
((u64)loongson_p + loongson_p->interface_offset);
|
|
|
|
especial = (struct loongson_special_attribute *)
|
|
|
|
((u64)loongson_p + loongson_p->special_offset);
|
2014-03-21 18:44:02 +08:00
|
|
|
eirq_source = (struct irq_source_routing_table *)
|
|
|
|
((u64)loongson_p + loongson_p->irq_offset);
|
|
|
|
loongson_memmap = (struct efi_memory_map_loongson *)
|
|
|
|
((u64)loongson_p + loongson_p->memory_offset);
|
|
|
|
|
|
|
|
cpu_clock_freq = ecpu->cpu_clock_freq;
|
|
|
|
loongson_sysconf.cputype = ecpu->cputype;
|
2017-06-22 23:06:54 +08:00
|
|
|
switch (ecpu->cputype) {
|
|
|
|
case Legacy_3A:
|
|
|
|
case Loongson_3A:
|
2014-06-26 11:41:28 +08:00
|
|
|
loongson_sysconf.cores_per_node = 4;
|
|
|
|
loongson_sysconf.cores_per_package = 4;
|
2014-06-26 11:41:30 +08:00
|
|
|
smp_group[0] = 0x900000003ff01000;
|
|
|
|
smp_group[1] = 0x900010003ff01000;
|
|
|
|
smp_group[2] = 0x900020003ff01000;
|
|
|
|
smp_group[3] = 0x900030003ff01000;
|
2014-06-26 11:41:27 +08:00
|
|
|
loongson_chipcfg[0] = 0x900000001fe00180;
|
|
|
|
loongson_chipcfg[1] = 0x900010001fe00180;
|
|
|
|
loongson_chipcfg[2] = 0x900020001fe00180;
|
|
|
|
loongson_chipcfg[3] = 0x900030001fe00180;
|
2015-03-29 10:54:09 +08:00
|
|
|
loongson_chiptemp[0] = 0x900000001fe0019c;
|
|
|
|
loongson_chiptemp[1] = 0x900010001fe0019c;
|
|
|
|
loongson_chiptemp[2] = 0x900020001fe0019c;
|
|
|
|
loongson_chiptemp[3] = 0x900030001fe0019c;
|
2016-03-03 09:45:09 +08:00
|
|
|
loongson_freqctrl[0] = 0x900000001fe001d0;
|
|
|
|
loongson_freqctrl[1] = 0x900010001fe001d0;
|
|
|
|
loongson_freqctrl[2] = 0x900020001fe001d0;
|
|
|
|
loongson_freqctrl[3] = 0x900030001fe001d0;
|
2014-11-04 14:13:27 +08:00
|
|
|
loongson_sysconf.workarounds = WORKAROUND_CPUFREQ;
|
2017-06-22 23:06:54 +08:00
|
|
|
break;
|
|
|
|
case Legacy_3B:
|
|
|
|
case Loongson_3B:
|
2014-06-26 11:41:30 +08:00
|
|
|
loongson_sysconf.cores_per_node = 4; /* One chip has 2 nodes */
|
|
|
|
loongson_sysconf.cores_per_package = 8;
|
|
|
|
smp_group[0] = 0x900000003ff01000;
|
|
|
|
smp_group[1] = 0x900010003ff05000;
|
|
|
|
smp_group[2] = 0x900020003ff09000;
|
|
|
|
smp_group[3] = 0x900030003ff0d000;
|
|
|
|
loongson_chipcfg[0] = 0x900000001fe00180;
|
|
|
|
loongson_chipcfg[1] = 0x900020001fe00180;
|
|
|
|
loongson_chipcfg[2] = 0x900040001fe00180;
|
|
|
|
loongson_chipcfg[3] = 0x900060001fe00180;
|
2015-03-29 10:54:09 +08:00
|
|
|
loongson_chiptemp[0] = 0x900000001fe0019c;
|
|
|
|
loongson_chiptemp[1] = 0x900020001fe0019c;
|
|
|
|
loongson_chiptemp[2] = 0x900040001fe0019c;
|
|
|
|
loongson_chiptemp[3] = 0x900060001fe0019c;
|
2014-06-26 11:41:30 +08:00
|
|
|
loongson_freqctrl[0] = 0x900000001fe001d0;
|
|
|
|
loongson_freqctrl[1] = 0x900020001fe001d0;
|
|
|
|
loongson_freqctrl[2] = 0x900040001fe001d0;
|
|
|
|
loongson_freqctrl[3] = 0x900060001fe001d0;
|
2014-11-04 14:13:27 +08:00
|
|
|
loongson_sysconf.workarounds = WORKAROUND_CPUHOTPLUG;
|
2017-06-22 23:06:54 +08:00
|
|
|
break;
|
|
|
|
default:
|
2014-06-26 11:41:28 +08:00
|
|
|
loongson_sysconf.cores_per_node = 1;
|
|
|
|
loongson_sysconf.cores_per_package = 1;
|
2014-06-26 11:41:27 +08:00
|
|
|
loongson_chipcfg[0] = 0x900000001fe00180;
|
|
|
|
}
|
|
|
|
|
2014-03-21 18:44:02 +08:00
|
|
|
loongson_sysconf.nr_cpus = ecpu->nr_cpus;
|
2014-11-04 14:13:26 +08:00
|
|
|
loongson_sysconf.boot_cpu_id = ecpu->cpu_startup_core_id;
|
|
|
|
loongson_sysconf.reserved_cpus_mask = ecpu->reserved_cores_mask;
|
2014-03-21 18:44:02 +08:00
|
|
|
if (ecpu->nr_cpus > NR_CPUS || ecpu->nr_cpus == 0)
|
|
|
|
loongson_sysconf.nr_cpus = NR_CPUS;
|
2014-06-26 11:41:28 +08:00
|
|
|
loongson_sysconf.nr_nodes = (loongson_sysconf.nr_cpus +
|
|
|
|
loongson_sysconf.cores_per_node - 1) /
|
|
|
|
loongson_sysconf.cores_per_node;
|
2014-03-21 18:44:02 +08:00
|
|
|
|
|
|
|
loongson_sysconf.dma_mask_bits = eirq_source->dma_mask_bits;
|
|
|
|
if (loongson_sysconf.dma_mask_bits < 32 ||
|
|
|
|
loongson_sysconf.dma_mask_bits > 64)
|
|
|
|
loongson_sysconf.dma_mask_bits = 32;
|
|
|
|
|
|
|
|
loongson_sysconf.restart_addr = boot_p->reset_system.ResetWarm;
|
|
|
|
loongson_sysconf.poweroff_addr = boot_p->reset_system.Shutdown;
|
|
|
|
loongson_sysconf.suspend_addr = boot_p->reset_system.DoSuspend;
|
|
|
|
|
|
|
|
loongson_sysconf.vgabios_addr = boot_p->efi.smbios.vga_bios;
|
|
|
|
pr_debug("Shutdown Addr: %llx, Restart Addr: %llx, VBIOS Addr: %llx\n",
|
|
|
|
loongson_sysconf.poweroff_addr, loongson_sysconf.restart_addr,
|
|
|
|
loongson_sysconf.vgabios_addr);
|
2014-11-04 14:13:27 +08:00
|
|
|
|
|
|
|
loongson_sysconf.workarounds |= esys->workarounds;
|
|
|
|
|
2014-03-21 18:44:02 +08:00
|
|
|
pr_info("CpuClock = %u\n", cpu_clock_freq);
|
2020-04-03 17:29:49 +08:00
|
|
|
|
|
|
|
/* Read the ID of PCI host bridge to detect bridge type */
|
|
|
|
id = readl(HOST_BRIDGE_CONFIG_ADDR);
|
|
|
|
vendor = id & 0xffff;
|
|
|
|
|
2020-07-29 14:58:37 +08:00
|
|
|
switch (vendor) {
|
|
|
|
case PCI_VENDOR_ID_LOONGSON:
|
2020-04-03 17:29:49 +08:00
|
|
|
pr_info("The bridge chip is LS7A\n");
|
|
|
|
loongson_sysconf.bridgetype = LS7A;
|
MIPS: Loongson: Add DMA support for LS7A
In the current market, the most used bridge chip on the Loongson platform
are RS780E and LS7A, the RS780E bridge chip is already supported by the
mainline kernel.
If use the default implementation of __phys_to_dma() and __dma_to_phys()
in dma-direct.h when CONFIG_ARCH_HAS_PHYS_TO_DMA is not set, it works
well used with LS7A on the Loongson single-way and multi-way platform,
and also works well used with RS780E on the Loongson single-way platform,
but the DMA address will be wrong on the non-node0 used with RS780E on
the Loongson multi-way platform.
Just as the description in the code comment, the devices get node id from
40 bit of HyperTransport bus, so we extract 2 bit node id (bit 44~45) from
48 bit address space of Loongson CPU and embed it into HyperTransport bus
(bit 37-38), this operation can be done only at the software level used
with RS780E on the Loongson multi-way platform, because it has no hardware
function to translate address of node id, this is a hardware compatibility
problem.
Device
|
| DMA address
|
Host Bridge
|
| HT bus address (40 bit)
|
CPU
|
| physical address (48 bit)
|
RAM
The LS7A has dma_node_id_offset field in the DMA route config register,
the hardware can use the dma_node_id_offset to translate address of
node id automatically, so we can get correct address when just use the
dma_pfn_offset field in struct device.
For the above reasons, in order to maintain downward compatibility
to support the RS780E bridge chip, it is better to use the platform
dependent implementation of __phys_to_dma() and __dma_to_phys().
Signed-off-by: Tiezhu Yang <yangtiezhu@loongson.cn>
Signed-off-by: Thomas Bogendoerfer <tsbogend@alpha.franken.de>
2020-05-08 16:36:05 +08:00
|
|
|
loongson_sysconf.early_config = ls7a_early_config;
|
2020-07-29 14:58:37 +08:00
|
|
|
break;
|
|
|
|
case PCI_VENDOR_ID_AMD:
|
|
|
|
case PCI_VENDOR_ID_ATI:
|
2020-04-03 17:29:49 +08:00
|
|
|
pr_info("The bridge chip is RS780E or SR5690\n");
|
|
|
|
loongson_sysconf.bridgetype = RS780E;
|
MIPS: Loongson: Add DMA support for LS7A
In the current market, the most used bridge chip on the Loongson platform
are RS780E and LS7A, the RS780E bridge chip is already supported by the
mainline kernel.
If use the default implementation of __phys_to_dma() and __dma_to_phys()
in dma-direct.h when CONFIG_ARCH_HAS_PHYS_TO_DMA is not set, it works
well used with LS7A on the Loongson single-way and multi-way platform,
and also works well used with RS780E on the Loongson single-way platform,
but the DMA address will be wrong on the non-node0 used with RS780E on
the Loongson multi-way platform.
Just as the description in the code comment, the devices get node id from
40 bit of HyperTransport bus, so we extract 2 bit node id (bit 44~45) from
48 bit address space of Loongson CPU and embed it into HyperTransport bus
(bit 37-38), this operation can be done only at the software level used
with RS780E on the Loongson multi-way platform, because it has no hardware
function to translate address of node id, this is a hardware compatibility
problem.
Device
|
| DMA address
|
Host Bridge
|
| HT bus address (40 bit)
|
CPU
|
| physical address (48 bit)
|
RAM
The LS7A has dma_node_id_offset field in the DMA route config register,
the hardware can use the dma_node_id_offset to translate address of
node id automatically, so we can get correct address when just use the
dma_pfn_offset field in struct device.
For the above reasons, in order to maintain downward compatibility
to support the RS780E bridge chip, it is better to use the platform
dependent implementation of __phys_to_dma() and __dma_to_phys().
Signed-off-by: Tiezhu Yang <yangtiezhu@loongson.cn>
Signed-off-by: Thomas Bogendoerfer <tsbogend@alpha.franken.de>
2020-05-08 16:36:05 +08:00
|
|
|
loongson_sysconf.early_config = rs780e_early_config;
|
2020-07-29 14:58:37 +08:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
pr_info("The bridge chip is VIRTUAL\n");
|
|
|
|
loongson_sysconf.bridgetype = VIRTUAL;
|
|
|
|
loongson_sysconf.early_config = virtual_early_config;
|
|
|
|
loongson_fdt_blob = __dtb_loongson64v_4core_virtio_begin;
|
|
|
|
break;
|
2020-04-03 17:29:49 +08:00
|
|
|
}
|
2020-07-09 19:33:43 +08:00
|
|
|
|
|
|
|
if ((read_c0_prid() & PRID_IMP_MASK) == PRID_IMP_LOONGSON_64C) {
|
|
|
|
switch (read_c0_prid() & PRID_REV_MASK) {
|
|
|
|
case PRID_REV_LOONGSON3A_R1:
|
|
|
|
case PRID_REV_LOONGSON3A_R2_0:
|
|
|
|
case PRID_REV_LOONGSON3A_R2_1:
|
|
|
|
case PRID_REV_LOONGSON3A_R3_0:
|
|
|
|
case PRID_REV_LOONGSON3A_R3_1:
|
|
|
|
switch (loongson_sysconf.bridgetype) {
|
|
|
|
case LS7A:
|
|
|
|
loongson_fdt_blob = __dtb_loongson64c_4core_ls7a_begin;
|
|
|
|
break;
|
|
|
|
case RS780E:
|
|
|
|
loongson_fdt_blob = __dtb_loongson64c_4core_rs780e_begin;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case PRID_REV_LOONGSON3B_R1:
|
|
|
|
case PRID_REV_LOONGSON3B_R2:
|
|
|
|
if (loongson_sysconf.bridgetype == RS780E)
|
|
|
|
loongson_fdt_blob = __dtb_loongson64c_8core_rs780e_begin;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
} else if ((read_c0_prid() & PRID_IMP_MASK) == PRID_IMP_LOONGSON_64G) {
|
|
|
|
if (loongson_sysconf.bridgetype == LS7A)
|
|
|
|
loongson_fdt_blob = __dtb_loongson64g_4core_ls7a_begin;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!loongson_fdt_blob)
|
|
|
|
pr_err("Failed to determine built-in Loongson64 dtb\n");
|
2009-07-02 23:22:36 +08:00
|
|
|
}
|