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