Home | History | Annotate | Line # | Download | only in loongson
      1 /*	$OpenBSD: loongson2_machdep.c,v 1.11 2011/03/31 20:37:44 miod Exp $	*/
      2 
      3 /*
      4  * Copyright (c) 2009, 2010 Miodrag Vallat.
      5  *
      6  * Permission to use, copy, modify, and distribute this software for any
      7  * purpose with or without fee is hereby granted, provided that the above
      8  * copyright notice and this permission notice appear in all copies.
      9  *
     10  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
     11  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
     12  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
     13  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
     14  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
     15  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
     16  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
     17  */
     18 
     19 #include <sys/param.h>
     20 #include <sys/systm.h>
     21 #include <sys/kernel.h>
     22 #include <sys/proc.h>
     23 #include <sys/sysctl.h>
     24 #include <sys/kcore.h>
     25 
     26 #include <uvm/uvm_extern.h>
     27 
     28 #include <evbmips/loongson/autoconf.h>
     29 #include <evbmips/loongson/loongson_intr.h>
     30 #include <machine/kcore.h>
     31 #include <machine/cpu.h>
     32 #include <mips/pmon/pmon.h>
     33 
     34 #include <mips/bonito/bonitoreg.h>
     35 #include <mips/bonito/bonitovar.h>
     36 
     37 boolean_t is_memory_range(paddr_t, psize_t, psize_t);
     38 static void loongson2f_setup_window(uint, uint, uint64_t, uint64_t, uint64_t, uint);
     39 
     40 /*
     41  * Canonical crossbow assignments on Loongson 2F based designs.
     42  * Might need to move to a per-design header file in the future.
     43  */
     44 
     45 #define	MASTER_CPU		0
     46 #define	MASTER_PCI		1
     47 
     48 #define	WINDOW_CPU_LOW		0
     49 #define	WINDOW_CPU_PCILO	1
     50 #define	WINDOW_CPU_PCIHI	2
     51 #define	WINDOW_CPU_DDR		3
     52 
     53 #define	WINDOW_PCI_DDR		0
     54 
     55 #define	DDR_PHYSICAL_BASE	0x0000000000000000UL	/* memory starts at 0 */
     56 #define	DDR_PHYSICAL_SIZE	0x0000000080000000UL	/* up to 2GB */
     57 #define	DDR_WINDOW_BASE		0x0000000080000000UL	/* mapped at 2GB */
     58 
     59 #define	PCI_RESOURCE_BASE	0x0000000000000000UL
     60 #define	PCI_RESOURCE_SIZE	0x0000000080000000UL
     61 
     62 #define	PCI_DDR_BASE		0x0000000080000000UL	/* PCI->DDR at 2GB */
     63 
     64 /* bonito interrupt mappings */
     65 const struct bonito_irqmap loongson2e_irqmap[BONITO_NDIRECT] = {
     66 	{ "mbox0",	BONITO_INTR_MBOX + 0,	IRQ_F_INT0 },
     67 	{ "mbox1",	BONITO_INTR_MBOX + 1,	IRQ_F_INT0 },
     68 	{ "mbox2",	BONITO_INTR_MBOX + 2,	IRQ_F_INT0 },
     69 	{ "mbox3",	BONITO_INTR_MBOX + 3,	IRQ_F_INT0 },
     70 	{ "dmardy",	BONITO_INTR_MBOX + 4,	IRQ_F_INT0 },
     71 	{ "dmaempty",	BONITO_INTR_MBOX + 5,	IRQ_F_INT0 },
     72 	{ "copyrdy",	BONITO_INTR_MBOX + 6,	IRQ_F_INT0 },
     73 	{ "copyempty",	BONITO_INTR_MBOX + 7,	IRQ_F_INT0 },
     74 	{ "coperr",	BONITO_INTR_MBOX + 8,	IRQ_F_INT1 },
     75 	{ "pciirq",	BONITO_INTR_MBOX + 9,	IRQ_F_INT0 },
     76 	{ "mastererr",	BONITO_INTR_MBOX + 10,	IRQ_F_INT1 },
     77 	{ "systemerr",	BONITO_INTR_MBOX + 11,	IRQ_F_INT1 },
     78 	{ "dramerr",	BONITO_INTR_MBOX + 12,	IRQ_F_INT1 },
     79 	{ "retryerr",	BONITO_INTR_MBOX + 13,	IRQ_F_INT1 },
     80 	{ NULL,		BONITO_INTR_MBOX + 14,	0 },
     81 	{ NULL,		BONITO_INTR_MBOX + 15,	0 },
     82 	{ "gpio0",	BONITO_INTR_GPIO + 0,	IRQ_F_INT0 },
     83 	{ "gpio1",	BONITO_INTR_GPIO + 1,	IRQ_F_INT0 },
     84 	{ "gpio2",	BONITO_INTR_GPIO + 2,	IRQ_F_INT0 },
     85 	{ "gpio3",	BONITO_INTR_GPIO + 3,	IRQ_F_INT0 },
     86 	{ "gpio4",	BONITO_INTR_GPIO + 4,	IRQ_F_INT0 },
     87 	{ "gpio5",	BONITO_INTR_GPIO + 5,	IRQ_F_INT0 },
     88 	{ "gpio6",	BONITO_INTR_GPIO + 6,	IRQ_F_INT0 },
     89 	{ "gpio7",	BONITO_INTR_GPIO + 7,	IRQ_F_INT0 },
     90 	{ "gpio8",	BONITO_INTR_GPIO + 8,	IRQ_F_INT0 },
     91 	{ "gpin0",	BONITO_INTR_GPIN + 0,	IRQ_F_INT0 },
     92 	{ "gpin1",	BONITO_INTR_GPIN + 1,	IRQ_F_INT0 },
     93 	{ "gpin2",	BONITO_INTR_GPIN + 2,	IRQ_F_INT0 },
     94 	{ "gpin3",	BONITO_INTR_GPIN + 3,	IRQ_F_INT0 },
     95 	{ "gpin4",	BONITO_INTR_GPIN + 4,	IRQ_F_INT0 },
     96 	{ "gpin5",	BONITO_INTR_GPIN + 5,	IRQ_F_INT0 },
     97 	{ NULL,		BONITO_INTR_GPIN + 6,	0 },
     98 };
     99 
    100 const struct bonito_irqmap loongson2f_irqmap[BONITO_NDIRECT] = {
    101 	{ "gpio0",	LOONGSON_INTR_GPIO0,	IRQ_F_INT0 },
    102 	{ "gpio1",	LOONGSON_INTR_GPIO1,	IRQ_F_INT0 },
    103 	{ "gpio2",	LOONGSON_INTR_GPIO2,	IRQ_F_INT0 },
    104 	{ "gpio3",	LOONGSON_INTR_GPIO3,	IRQ_F_INT0 },
    105 
    106 	{ "pci inta",	LOONGSON_INTR_PCIA,	IRQ_F_INT0 },
    107 	{ "pci intb",	LOONGSON_INTR_PCIB,	IRQ_F_INT0 },
    108 	{ "pci intc",	LOONGSON_INTR_PCIC,	IRQ_F_INT0 },
    109 	{ "pci intd",	LOONGSON_INTR_PCID,	IRQ_F_INT0 },
    110 
    111 	{ "pci perr",	LOONGSON_INTR_PCI_PARERR, IRQ_F_EDGE|IRQ_F_INT1 },
    112 	{ "pci serr",	LOONGSON_INTR_PCI_SYSERR, IRQ_F_EDGE|IRQ_F_INT1 },
    113 
    114 	{ "denali",	LOONGSON_INTR_DRAM_PARERR, IRQ_F_INT1 },
    115 
    116 	{ "mips int0",	LOONGSON_INTR_INT0,	IRQ_F_INT0 },
    117 	{ "mips int1",	LOONGSON_INTR_INT1,	IRQ_F_INT1 },
    118 	{ "mips int2",	LOONGSON_INTR_INT2,	IRQ_F_INT2 },
    119 	{ "mips int3",	LOONGSON_INTR_INT3,	IRQ_F_INT3 },
    120 };
    121 
    122 /*
    123  * Setup memory mappings for Loongson 2E processors.
    124  */
    125 
    126 void
    127 loongson2e_setup(paddr_t memlo, paddr_t memhi,
    128     vaddr_t vkernstart, vaddr_t vkernend, bus_dma_tag_t t)
    129 {
    130 	if (memhi > ((DDR_PHYSICAL_SIZE - BONITO_PCIHI_BASE) >> 20)) {
    131 		pmon_printf("WARNING! %d MB of memory will not be used",
    132 		    memhi - ((DDR_PHYSICAL_SIZE - BONITO_PCIHI_BASE) >> 20));
    133 		memhi = (DDR_PHYSICAL_SIZE - BONITO_PCIHI_BASE) >> 20;
    134 	}
    135 
    136 	physmem = btoc(memlo + memhi);
    137 
    138 	/* do NOT stomp on exception area */
    139 	/* mips_page_physload() will skip the kernel */
    140 	mem_clusters[0].start = DDR_PHYSICAL_BASE;
    141 	mem_clusters[0].size = memlo;
    142 	mem_cluster_cnt = 1;
    143 
    144 	if (memhi != 0) {
    145 		mem_clusters[1].start = BONITO_PCIHI_BASE;
    146 		mem_clusters[1].size = memhi;
    147 		mem_cluster_cnt = 2;
    148 	}
    149 
    150 	t->_wbase = PCI_DDR_BASE;
    151 	t->_bounce_alloc_lo = DDR_PHYSICAL_BASE;
    152 	t->_bounce_alloc_hi = DDR_PHYSICAL_BASE + DDR_PHYSICAL_SIZE;
    153 }
    154 
    155 /*
    156  * Setup memory mappings for Loongson 2F processors.
    157  */
    158 
    159 void
    160 loongson2f_setup(paddr_t memlo, paddr_t memhi,
    161     vaddr_t vkernstart, vaddr_t vkernend, bus_dma_tag_t t)
    162 {
    163 	/*
    164 	 * Because we'll only set up a 2GB window for the PCI bus to
    165 	 * access local memory, we'll limit ourselves to 2GB of usable
    166 	 * memory as well.
    167 	 *
    168 	 * Note that this is a bad justification for this; it should be
    169 	 * possible to setup a 1GB PCI space / 3GB memory access window,
    170 	 * and use bounce buffers if physmem > 3GB; but at the moment
    171 	 * there is no need to solve this problem until Loongson 2F-based
    172 	 * hardware with more than 2GB of memory is commonly encountered.
    173 	 *
    174 	 * Also note that, despite the crossbar window registers being
    175 	 * 64-bit wide, the upper 32-bit always read back as zeroes, so
    176 	 * it is dubious whether it is possible to use more than a 4GB
    177 	 * address space... and thus more than 2GB of physical memory.
    178 	 */
    179 
    180 	physmem = btoc(memlo + memhi);
    181 	if (physmem > btoc(DDR_PHYSICAL_SIZE)) {
    182 		pmon_printf("WARNING! %d MB of memory will not be used",
    183 		    (physmem >> 20) - (DDR_PHYSICAL_SIZE >> 20));
    184 		memhi = DDR_PHYSICAL_SIZE - btoc(256 << 20);
    185 	}
    186 
    187 	physmem = btoc(memlo + memhi);
    188 
    189 	/*
    190 	 * PMON configures the system with only the low 256MB of memory
    191 	 * accessible.
    192 	 *
    193 	 * We need to reprogram the address windows in order to be able to
    194 	 * access the whole memory, both by the local processor and by the
    195 	 * PCI bus.
    196 	 *
    197 	 * To make our life easier, we'll setup the memory as a contiguous
    198 	 * range starting at 2GB, and take into account the fact that the
    199 	 * first 256MB are also aliased at address zero (which is where the
    200 	 * kernel is loaded, really).
    201 	 */
    202 
    203 	if (memhi != 0 ) {
    204 		/* do NOT stomp on exception area */
    205 		/* also make sure to skip the kernel */
    206 		const paddr_t kernend = MIPS_KSEG0_TO_PHYS(round_page(vkernend));
    207 		mem_clusters[0].start = DDR_WINDOW_BASE + kernend;
    208 		mem_clusters[0].size = (memlo + memhi - kernend);
    209 		t->_wbase = PCI_DDR_BASE;
    210 		t->_bounce_alloc_lo = DDR_WINDOW_BASE;
    211 		t->_bounce_alloc_hi = DDR_WINDOW_BASE + DDR_PHYSICAL_SIZE;
    212 		mem_cluster_cnt = 1;
    213 	} else {
    214 		/* do NOT stomp on exception area */
    215 		/* mips_page_physload() will skip the kernel */
    216 		mem_clusters[0].start = DDR_PHYSICAL_BASE + PAGE_SIZE;
    217 		mem_clusters[0].size = (memlo + memhi - PAGE_SIZE - PAGE_SIZE);
    218 		t->_wbase = PCI_DDR_BASE;
    219 		t->_bounce_alloc_lo = DDR_PHYSICAL_BASE;
    220 		t->_bounce_alloc_hi = DDR_PHYSICAL_BASE + DDR_PHYSICAL_SIZE;
    221 		mem_cluster_cnt = 1;
    222 	}
    223 
    224 	/*
    225 	 * Allow access to memory beyond 256MB, by programming the
    226 	 * Loongson 2F address window registers.
    227 	 * This also makes sure PCI->DDR accesses can use a contiguous
    228 	 * area regardless of the actual memory size.
    229 	 */
    230 
    231 	/*
    232 	 * Master #0 (cpu) window #0 allows access to the low 256MB
    233 	 * of memory at address zero onwards.
    234 	 * This window is inherited from PMON; we set it up just in case.
    235 	 */
    236 	loongson2f_setup_window(MASTER_CPU, WINDOW_CPU_LOW, DDR_PHYSICAL_BASE,
    237 	    ~(0x0fffffffUL), DDR_PHYSICAL_BASE, MASTER_CPU);
    238 
    239 	/*
    240 	 * Master #0 (cpu) window #1 allows access to the ``low'' PCI
    241 	 * space (from 0x10000000 to 0x1fffffff).
    242 	 * This window is inherited from PMON; we set it up just in case.
    243 	 */
    244 	loongson2f_setup_window(MASTER_CPU, WINDOW_CPU_PCILO, BONITO_PCILO_BASE,
    245 	    ~(0x0fffffffUL), BONITO_PCILO_BASE, MASTER_PCI);
    246 
    247 	/*
    248 	 * Master #1 (PCI) window #0 allows access to the memory space
    249 	 * by PCI devices at addresses 0x80000000 onwards.
    250 	 * This window is inherited from PMON, but its mask might be too
    251 	 * restrictive (256MB) so we make sure it matches our needs.
    252 	 */
    253 	loongson2f_setup_window(MASTER_PCI, WINDOW_PCI_DDR, PCI_DDR_BASE,
    254 	    ~(DDR_PHYSICAL_SIZE - 1), DDR_PHYSICAL_BASE, MASTER_CPU);
    255 
    256 	/*
    257 	 * Master #0 (CPU) window #2 allows access to a subset of the ``high''
    258 	 * PCI space (from 0x40000000 to 0x7fffffff only).
    259 	 */
    260 	loongson2f_setup_window(MASTER_CPU, WINDOW_CPU_PCIHI, LS2F_PCIHI_BASE,
    261 	    ~((uint64_t)LS2F_PCIHI_SIZE - 1), LS2F_PCIHI_BASE, MASTER_PCI);
    262 
    263 	/*
    264 	 * Master #0 (CPU) window #3 allows access to the whole memory space
    265 	 * at addresses 0x80000000 onwards.
    266 	 */
    267 	loongson2f_setup_window(MASTER_CPU, WINDOW_CPU_DDR, DDR_WINDOW_BASE,
    268 	    ~(DDR_PHYSICAL_SIZE - 1), DDR_PHYSICAL_BASE, MASTER_CPU);
    269 
    270 }
    271 
    272 /*
    273  * Setup a window in the Loongson2F crossbar.
    274  */
    275 
    276 static void
    277 loongson2f_setup_window(uint master, uint window, uint64_t base, uint64_t mask,
    278     uint64_t mmap, uint slave)
    279 {
    280 	volatile uint64_t *awrreg;
    281 
    282 	awrreg = (volatile uint64_t *)MIPS_PHYS_TO_XKPHYS(CCA_UNCACHED,
    283 	    LOONGSON_AWR_BASE(master, window));
    284 	*awrreg = base;
    285 	(void)*awrreg;
    286 
    287 	awrreg = (volatile uint64_t *)MIPS_PHYS_TO_XKPHYS(CCA_UNCACHED,
    288 	    LOONGSON_AWR_SIZE(master, window));
    289 	*awrreg = mask;
    290 	(void)*awrreg;
    291 
    292 	awrreg = (volatile uint64_t *)MIPS_PHYS_TO_XKPHYS(CCA_UNCACHED,
    293 	    LOONGSON_AWR_MMAP(master, window));
    294 	*awrreg = mmap | slave;
    295 	(void)*awrreg;
    296 }
    297 
    298 /*
    299  * Return whether a given physical address points to managed memory.
    300  * (used by /dev/mem)
    301  */
    302 
    303 boolean_t
    304 is_memory_range(paddr_t pa, psize_t len, psize_t limit)
    305 {
    306 	uint64_t fp, lp;
    307 	int i;
    308 
    309 	fp = atop(pa);
    310 	lp = atop(round_page(pa + len));
    311 
    312 	if (limit != 0 && lp > atop(limit))
    313 		return FALSE;
    314 
    315 	/*
    316 	 * Allow access to the low 256MB aliased region on 2F systems,
    317 	 * if we are accessing memory at 2GB onwards.
    318 	 */
    319 	if (pa < 0x10000000 && loongson_ver >= 0x2f) {
    320 		fp += btoc(mem_clusters[0].start);
    321 		lp += btoc(mem_clusters[0].start);
    322 	}
    323 
    324 	for (i = 0; i < VM_PHYSSEG_MAX; i++)
    325 		if (fp >= btoc(mem_clusters[i].start) &&
    326 		    lp <= btoc(mem_clusters[i].start + mem_clusters[i].size))
    327 			return TRUE;
    328 
    329 	return FALSE;
    330 }
    331