#include <sys/param.h>
#include <sys/systm.h>
#include <sys/kernel.h>
#include <sys/proc.h>
#include <sys/sysctl.h>
#include <uvm/uvm_extern.h>
#include <machine/autoconf.h>
#include <machine/cpu.h>
#include <machine/loongson2.h>
#include <machine/memconf.h>
#include <machine/pmon.h>
#include <loongson/dev/bonitoreg.h>
extern struct phys_mem_desc mem_layout[MAXMEMSEGS];
extern paddr_t loongson_memlo_alias;
int is_memory_range(paddr_t, psize_t, psize_t);
void loongson2e_setup(u_long, u_long);
void loongson2f_setup(u_long, u_long);
void loongson2f_setup_window(uint, uint, uint64_t, uint64_t, uint64_t, uint);
paddr_t loongson_dma_base = 0;
#define MASTER_CPU 0
#define MASTER_PCI 1
#define WINDOW_CPU_LOW 0
#define WINDOW_CPU_PCILO 1
#define WINDOW_CPU_PCIHI 2
#define WINDOW_CPU_DDR 3
#define WINDOW_PCI_DDR 0
#define DDR_PHYSICAL_BASE 0x0000000000000000UL
#define DDR_PHYSICAL_SIZE 0x0000000080000000UL
#define DDR_WINDOW_BASE 0x0000000080000000UL
#define PCI_RESOURCE_BASE 0x0000000000000000UL
#define PCI_RESOURCE_SIZE 0x0000000080000000UL
#define PCI_DDR_BASE 0x0000000080000000UL
void
loongson2e_setup(u_long memlo, u_long memhi)
{
if (memhi > ((DDR_PHYSICAL_SIZE - BONITO_PCIHI_BASE) >> 20)) {
pmon_printf("WARNING! %d MB of memory will not be used",
memhi - ((DDR_PHYSICAL_SIZE - BONITO_PCIHI_BASE) >> 20));
memhi = (DDR_PHYSICAL_SIZE - BONITO_PCIHI_BASE) >> 20;
}
memlo = atop(memlo << 20);
memhi = atop(memhi << 20);
physmem = memlo + memhi;
mem_layout[0].mem_first_page = atop(DDR_PHYSICAL_BASE) + 1;
mem_layout[0].mem_last_page = atop(DDR_PHYSICAL_BASE) + memlo;
if (memhi != 0) {
mem_layout[1].mem_first_page = atop(BONITO_PCIHI_BASE);
mem_layout[1].mem_last_page = atop(BONITO_PCIHI_BASE) +
memhi;
}
loongson_dma_base = PCI_DDR_BASE ^ DDR_PHYSICAL_BASE;
}
void
loongson2f_setup(u_long memlo, u_long memhi)
{
physmem = memlo + memhi;
if (physmem > (DDR_PHYSICAL_SIZE >> 20)) {
pmon_printf("WARNING! %d MB of memory will not be used",
physmem - (DDR_PHYSICAL_SIZE >> 20));
memhi = (DDR_PHYSICAL_SIZE >> 20) - 256;
}
memlo = atop(memlo << 20);
memhi = atop(memhi << 20);
physmem = memlo + memhi;
if (memhi != 0) {
mem_layout[0].mem_first_page = atop(DDR_WINDOW_BASE) + 1;
mem_layout[0].mem_last_page = atop(DDR_WINDOW_BASE) +
memlo + memhi;
loongson_dma_base = PCI_DDR_BASE ^ DDR_WINDOW_BASE;
loongson_memlo_alias = DDR_WINDOW_BASE;
} else {
mem_layout[0].mem_first_page = atop(DDR_PHYSICAL_BASE) + 1;
mem_layout[0].mem_last_page = atop(DDR_PHYSICAL_BASE) +
memlo ;
loongson_dma_base = PCI_DDR_BASE ^ DDR_PHYSICAL_BASE;
}
loongson2f_setup_window(MASTER_CPU, WINDOW_CPU_LOW, DDR_PHYSICAL_BASE,
~(0x0fffffffUL), DDR_PHYSICAL_BASE, MASTER_CPU);
loongson2f_setup_window(MASTER_CPU, WINDOW_CPU_PCILO, BONITO_PCILO_BASE,
~(0x0fffffffUL), BONITO_PCILO_BASE, MASTER_PCI);
loongson2f_setup_window(MASTER_PCI, WINDOW_PCI_DDR, PCI_DDR_BASE,
~(DDR_PHYSICAL_SIZE - 1), DDR_PHYSICAL_BASE, MASTER_CPU);
loongson2f_setup_window(MASTER_CPU, WINDOW_CPU_PCIHI, LS2F_PCIHI_BASE,
~((uint64_t)LS2F_PCIHI_SIZE - 1), LS2F_PCIHI_BASE, MASTER_PCI);
loongson2f_setup_window(MASTER_CPU, WINDOW_CPU_DDR, DDR_WINDOW_BASE,
~(DDR_PHYSICAL_SIZE - 1), DDR_PHYSICAL_BASE, MASTER_CPU);
cpu_cpuspeed = loongson2f_cpuspeed;
}
void
loongson2f_setup_window(uint master, uint window, uint64_t base, uint64_t mask,
uint64_t mmap, uint slave)
{
volatile uint64_t *awrreg;
awrreg = (volatile uint64_t *)PHYS_TO_XKPHYS(
LOONGSON_AWR_BASE(master, window), CCA_NC);
*awrreg = base;
(void)*awrreg;
awrreg = (volatile uint64_t *)PHYS_TO_XKPHYS(
LOONGSON_AWR_SIZE(master, window), CCA_NC);
*awrreg = mask;
(void)*awrreg;
awrreg = (volatile uint64_t *)PHYS_TO_XKPHYS(
LOONGSON_AWR_MMAP(master, window), CCA_NC);
*awrreg = mmap | slave;
(void)*awrreg;
}
int
is_memory_range(paddr_t pa, psize_t len, psize_t limit)
{
struct phys_mem_desc *seg;
uint64_t fp, lp;
int i;
fp = atop(pa);
lp = atop(round_page(pa + len));
if (limit != 0 && lp > atop(limit))
return 0;
if (pa < 0x10000000 && loongson_ver >= 0x2f) {
fp += mem_layout[0].mem_first_page - 1;
lp += mem_layout[0].mem_first_page - 1;
}
for (i = 0, seg = mem_layout; i < MAXMEMSEGS; i++, seg++)
if (fp >= seg->mem_first_page && lp <= seg->mem_last_page)
return 1;
return 0;
}
int
loongson2f_cpuspeed(int *freq)
{
uint32_t step, val;
val = REGVAL(LOONGSON_CHIP_CONFIG0);
step = (val & 0x7) + 1;
*freq = ((bootcpu_hwinfo.clock / 8) * step) / 1000000;
return 0;
}
void
loongson2f_setperf(int percent)
{
uint32_t step, val;
step = percent * 8 / 100;
if (step < 2)
step = 2;
val = REGVAL(LOONGSON_CHIP_CONFIG0);
val = (val & ~0x7) | (step - 1);
REGVAL(LOONGSON_CHIP_CONFIG0) = val;
(void)REGVAL(LOONGSON_CHIP_CONFIG0);
}