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