1 /* $NetBSD: pxa2x0.c,v 1.23 2021/04/24 23:36:29 thorpej Exp $ */ 2 3 /* 4 * Copyright (c) 2002, 2005 Genetec Corporation. All rights reserved. 5 * Written by Hiroyuki Bessho for Genetec Corporation. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. All advertising materials mentioning features or use of this software 16 * must display the following acknowledgement: 17 * This product includes software developed for the NetBSD Project by 18 * Genetec Corporation. 19 * 4. The name of Genetec Corporation may not be used to endorse or 20 * promote products derived from this software without specific prior 21 * written permission. 22 * 23 * THIS SOFTWARE IS PROVIDED BY GENETEC CORPORATION ``AS IS'' AND 24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 25 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 26 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GENETEC CORPORATION 27 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 28 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 29 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 30 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 31 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 32 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 33 * POSSIBILITY OF SUCH DAMAGE. 34 * 35 * 36 * Autoconfiguration support for the Intel PXA2[15]0 application 37 * processor. This code is derived from arm/sa11x0/sa11x0.c 38 */ 39 40 /*- 41 * Copyright (c) 2001, The NetBSD Foundation, Inc. All rights reserved. 42 * 43 * This code is derived from software contributed to The NetBSD Foundation 44 * by IWAMOTO Toshihiro and Ichiro FUKUHARA. 45 * 46 * Redistribution and use in source and binary forms, with or without 47 * modification, are permitted provided that the following conditions 48 * are met: 49 * 1. Redistributions of source code must retain the above copyright 50 * notice, this list of conditions and the following disclaimer. 51 * 2. Redistributions in binary form must reproduce the above copyright 52 * notice, this list of conditions and the following disclaimer in the 53 * documentation and/or other materials provided with the distribution. 54 * 55 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 56 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 57 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 58 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 59 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 60 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 61 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 62 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 63 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 64 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 65 * POSSIBILITY OF SUCH DAMAGE. 66 */ 67 /*- 68 * Copyright (c) 1999 69 * Shin Takemura and PocketBSD Project. All rights reserved. 70 * 71 * Redistribution and use in source and binary forms, with or without 72 * modification, are permitted provided that the following conditions 73 * are met: 74 * 1. Redistributions of source code must retain the above copyright 75 * notice, this list of conditions and the following disclaimer. 76 * 2. Redistributions in binary form must reproduce the above copyright 77 * notice, this list of conditions and the following disclaimer in the 78 * documentation and/or other materials provided with the distribution. 79 * 3. All advertising materials mentioning features or use of this software 80 * must display the following acknowledgement: 81 * This product includes software developed by the PocketBSD project 82 * and its contributors. 83 * 4. Neither the name of the project nor the names of its contributors 84 * may be used to endorse or promote products derived from this software 85 * without specific prior written permission. 86 * 87 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 88 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 89 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 90 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 91 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 92 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 93 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 94 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 95 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 96 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 97 * SUCH DAMAGE. 98 * 99 */ 100 101 #include <sys/cdefs.h> 102 __KERNEL_RCSID(0, "$NetBSD: pxa2x0.c,v 1.23 2021/04/24 23:36:29 thorpej Exp $"); 103 104 #include "pxaintc.h" 105 #include "pxagpio.h" 106 #if 0 107 #include "pxadmac.h" /* Not yet */ 108 #endif 109 110 #include "locators.h" 111 112 #include <sys/param.h> 113 #include <sys/systm.h> 114 #include <sys/device.h> 115 #include <sys/kernel.h> 116 #include <sys/reboot.h> 117 118 #include <machine/cpu.h> 119 #include <sys/bus.h> 120 121 #include <arm/cpufunc.h> 122 #include <arm/mainbus/mainbus.h> 123 #include <arm/xscale/pxa2x0cpu.h> 124 #include <arm/xscale/pxa2x0reg.h> 125 #include <arm/xscale/pxa2x0var.h> 126 #include <arm/xscale/xscalereg.h> 127 128 struct pxaip_softc { 129 device_t sc_dev; 130 bus_space_tag_t sc_bust; 131 bus_dma_tag_t sc_dmat; 132 bus_space_handle_t sc_bush_clk; 133 bus_space_handle_t sc_bush_mem; 134 }; 135 136 /* prototypes */ 137 static int pxaip_match(device_t, cfdata_t, void *); 138 static void pxaip_attach(device_t, device_t, void *); 139 static int pxaip_search(device_t, cfdata_t, const int *, void *); 140 static void pxaip_attach_critical(struct pxaip_softc *); 141 static int pxaip_print(void *, const char *); 142 143 static int pxaip_measure_cpuclock(struct pxaip_softc *); 144 145 #if defined(CPU_XSCALE_PXA250) && defined(CPU_XSCALE_PXA270) 146 # define SUPPORTED_CPU "PXA250 and PXA270" 147 #elif defined(CPU_XSCALE_PXA250) 148 # define SUPPORTED_CPU "PXA250" 149 #elif defined(CPU_XSCALE_PXA270) 150 # define SUPPORTED_CPU "PXA270" 151 #else 152 # define SUPPORTED_CPU "none of PXA2xx" 153 #endif 154 155 /* attach structures */ 156 CFATTACH_DECL_NEW(pxaip, sizeof(struct pxaip_softc), 157 pxaip_match, pxaip_attach, NULL, NULL); 158 159 static struct pxaip_softc *pxaip_sc; 160 static vaddr_t pxamemctl_regs; 161 #define MEMCTL_BOOTSTRAP_REG(reg) \ 162 (*((volatile uint32_t *)(pxamemctl_regs + (reg)))) 163 static vaddr_t pxaclkman_regs; 164 #define CLKMAN_BOOTSTRAP_REG(reg) \ 165 (*((volatile uint32_t *)(pxaclkman_regs + (reg)))) 166 167 static int 168 pxaip_match(device_t parent, cfdata_t match, void *aux) 169 { 170 171 #if !defined(CPU_XSCALE_PXA270) 172 if (__CPU_IS_PXA270) 173 goto bad_config; 174 #endif 175 176 #if !defined(CPU_XSCALE_PXA250) 177 if (__CPU_IS_PXA250) 178 goto bad_config; 179 #endif 180 181 return 1; 182 183 #if defined(CPU_XSCALE_PXA250) + defined(CPU_XSCALE_PXA270) != 2 184 bad_config: 185 aprint_error("Kernel is configured for %s, but CPU is %s\n", 186 SUPPORTED_CPU, __CPU_IS_PXA270 ? "PXA270" : "PXA250"); 187 return 0; 188 #endif 189 } 190 191 static void 192 pxaip_attach(device_t parent, device_t self, void *aux) 193 { 194 struct pxaip_softc *sc = device_private(self); 195 int cpuclock; 196 197 pxaip_sc = sc; 198 sc->sc_dev = self; 199 sc->sc_bust = &pxa2x0_bs_tag; 200 sc->sc_dmat = &pxa2x0_bus_dma_tag; 201 202 aprint_normal(": Onchip Peripheral Bus\n"); 203 204 if (bus_space_map(sc->sc_bust, PXA2X0_CLKMAN_BASE, PXA2X0_CLKMAN_SIZE, 205 0, &sc->sc_bush_clk)) 206 panic("pxaip_attach: failed to map CLKMAN"); 207 208 if (bus_space_map(sc->sc_bust, PXA2X0_MEMCTL_BASE, PXA2X0_MEMCTL_SIZE, 209 0, &sc->sc_bush_mem)) 210 panic("pxaip_attach: failed to map MEMCTL"); 211 212 /* 213 * Calculate clock speed 214 * This takes 2 secs at most. 215 */ 216 cpuclock = pxaip_measure_cpuclock(sc) / 1000; 217 printf("%s: CPU clock = %d.%03d MHz\n", device_xname(self), 218 cpuclock/1000, cpuclock%1000 ); 219 220 aprint_normal("%s: kernel is configured for " SUPPORTED_CPU 221 ", cpu type is %s\n", 222 device_xname(self), 223 __CPU_IS_PXA270 ? "PXA270" : "PXA250"); 224 225 /* 226 * Attach critical devices 227 */ 228 pxaip_attach_critical(sc); 229 230 /* 231 * Attach all other devices 232 */ 233 config_search(self, NULL, 234 CFARG_SEARCH, pxaip_search, 235 CFARG_EOL); 236 } 237 238 static int 239 pxaip_search(device_t parent, cfdata_t cf, const int *ldesc, void *aux) 240 { 241 struct pxaip_softc *sc = device_private(parent); 242 struct pxaip_attach_args aa; 243 244 aa.pxa_iot = sc->sc_bust; 245 aa.pxa_dmat = sc->sc_dmat; 246 aa.pxa_name = cf->cf_name; 247 aa.pxa_addr = cf->cf_loc[PXAIPCF_ADDR]; 248 aa.pxa_size = cf->cf_loc[PXAIPCF_SIZE]; 249 aa.pxa_index = cf->cf_loc[PXAIPCF_INDEX]; 250 aa.pxa_intr = cf->cf_loc[PXAIPCF_INTR]; 251 252 if (config_probe(parent, cf, &aa)) 253 config_attach(parent, cf, &aa, pxaip_print, CFARG_EOL); 254 255 return 0; 256 } 257 258 static void 259 pxaip_attach_critical(struct pxaip_softc *sc) 260 { 261 struct pxaip_attach_args aa; 262 263 aa.pxa_iot = sc->sc_bust; 264 aa.pxa_dmat = sc->sc_dmat; 265 aa.pxa_name = "pxaintc"; 266 aa.pxa_addr = PXA2X0_INTCTL_BASE; 267 aa.pxa_size = PXA2X0_INTCTL_SIZE; 268 aa.pxa_intr = PXAIPCF_INTR_DEFAULT; 269 if (config_found(sc->sc_dev, &aa, pxaip_print, CFARG_EOL) == NULL) 270 panic("pxaip_attach_critical: failed to attach INTC!"); 271 272 #if NPXAGPIO > 0 273 aa.pxa_iot = sc->sc_bust; 274 aa.pxa_dmat = sc->sc_dmat; 275 aa.pxa_name = "pxagpio"; 276 aa.pxa_addr = PXA2X0_GPIO_BASE; 277 aa.pxa_size = PXA2X0_GPIO_SIZE; 278 aa.pxa_intr = PXAIPCF_INTR_DEFAULT; 279 if (config_found(sc->sc_dev, &aa, pxaip_print, CFARG_EOL) == NULL) 280 panic("pxaip_attach_critical: failed to attach GPIO!"); 281 #endif 282 283 #if NPXADMAC > 0 284 aa.pxa_iot = sc->sc_bust; 285 aa.pxa_dmat = sc->sc_dmat; 286 aa.pxa_name = "pxaidmac"; 287 aa.pxa_addr = PXA2X0_DMAC_BASE; 288 aa.pxa_size = PXA2X0_DMAC_SIZE; 289 aa.pxa_intr = PXA2X0_INT_DMA; 290 if (config_found(sc->sc_dev, &aa, pxaip_print, CFARG_EOL) == NULL) 291 panic("pxaip_attach_critical: failed to attach DMAC!"); 292 #endif 293 } 294 295 static int 296 pxaip_print(void *aux, const char *name) 297 { 298 struct pxaip_attach_args *sa = (struct pxaip_attach_args *)aux; 299 300 if (sa->pxa_addr != PXAIPCF_ADDR_DEFAULT) { 301 aprint_normal(" addr 0x%lx", sa->pxa_addr); 302 if (sa->pxa_size > PXAIPCF_SIZE_DEFAULT) 303 aprint_normal("-0x%lx", sa->pxa_addr + sa->pxa_size-1); 304 } 305 if (sa->pxa_intr != PXAIPCF_INTR_DEFAULT) 306 aprint_normal(" intr %d", sa->pxa_intr); 307 308 return (UNCONF); 309 } 310 311 static inline uint32_t 312 read_clock_counter_xsc1(void) 313 { 314 uint32_t x; 315 __asm volatile("mrc p14, 0, %0, c1, c0, 0" : "=r" (x) ); 316 317 return x; 318 } 319 320 static inline uint32_t 321 read_clock_counter_xsc2(void) 322 { 323 uint32_t x; 324 __asm volatile("mrc p14, 0, %0, c1, c1, 0" : "=r" (x) ); 325 326 return x; 327 } 328 329 static int 330 pxaip_measure_cpuclock(struct pxaip_softc *sc) 331 { 332 uint32_t rtc0, rtc1, start, end; 333 uint32_t pmcr_save; 334 bus_space_handle_t ioh; 335 int irq; 336 int is_xsc2 = CPU_IS_PXA270; 337 #define read_clock_counter() (is_xsc2 ? read_clock_counter_xsc2() : \ 338 read_clock_counter_xsc1()) 339 340 if (bus_space_map(sc->sc_bust, PXA2X0_RTC_BASE, PXA2X0_RTC_SIZE, 0, 341 &ioh)) 342 panic("pxaip_measure_cpuclock: can't map RTC"); 343 344 irq = disable_interrupts(I32_bit|F32_bit); 345 346 if (is_xsc2) { 347 __asm volatile( 348 "mrc p14, 0, %0, c0, c1, 0" : "=r" (pmcr_save)); 349 /* Enable clock counter */ 350 __asm volatile( 351 "mcr p14, 0, %0, c0, c1, 0" : : "r" (PMNC_E|PMNC_C)); 352 } 353 else { 354 __asm volatile( 355 "mrc p14, 0, %0, c0, c0, 0" : "=r" (pmcr_save)); 356 /* Enable clock counter */ 357 __asm volatile( 358 "mcr p14, 0, %0, c0, c0, 0" : : "r" (PMNC_E|PMNC_C)); 359 } 360 361 rtc0 = bus_space_read_4(sc->sc_bust, ioh, RTC_RCNR); 362 /* Wait for next second starts */ 363 while ((rtc1 = bus_space_read_4(sc->sc_bust, ioh, RTC_RCNR)) == rtc0) 364 ; 365 start = read_clock_counter(); 366 while(rtc1 == bus_space_read_4(sc->sc_bust, ioh, RTC_RCNR)) 367 ; /* Wait for 1sec */ 368 end = read_clock_counter(); 369 370 if (is_xsc2) 371 __asm volatile( 372 "mcr p14, 0, %0, c0, c1, 0" : : "r" (pmcr_save)); 373 else 374 __asm volatile( 375 "mcr p14, 0, %0, c0, c0, 0" : : "r" (pmcr_save)); 376 restore_interrupts(irq); 377 378 bus_space_unmap(sc->sc_bust, ioh, PXA2X0_RTC_SIZE); 379 380 return end - start; 381 } 382 383 void 384 pxa2x0_turbo_mode(int f) 385 { 386 __asm volatile("mcr p14, 0, %0, c6, c0, 0" : : "r" (f)); 387 } 388 389 void 390 pxa2x0_probe_sdram(vaddr_t memctl_va, paddr_t *start, paddr_t *size) 391 { 392 uint32_t mdcnfg, dwid, dcac, drac, dnb; 393 int i; 394 395 mdcnfg = *((volatile uint32_t *)(memctl_va + MEMCTL_MDCNFG)); 396 397 /* 398 * Scan all 4 SDRAM banks 399 */ 400 for (i = 0; i < PXA2X0_SDRAM_BANKS; i++) { 401 start[i] = 0; 402 size[i] = 0; 403 404 switch (i) { 405 case 0: 406 case 1: 407 if ((i == 0 && (mdcnfg & MDCNFG_DE0) == 0) || 408 (i == 1 && (mdcnfg & MDCNFG_DE1) == 0)) 409 continue; 410 dwid = mdcnfg >> MDCNFD_DWID01_SHIFT; 411 dcac = mdcnfg >> MDCNFD_DCAC01_SHIFT; 412 drac = mdcnfg >> MDCNFD_DRAC01_SHIFT; 413 dnb = mdcnfg >> MDCNFD_DNB01_SHIFT; 414 break; 415 416 case 2: 417 case 3: 418 if ((i == 2 && (mdcnfg & MDCNFG_DE2) == 0) || 419 (i == 3 && (mdcnfg & MDCNFG_DE3) == 0)) 420 continue; 421 dwid = mdcnfg >> MDCNFD_DWID23_SHIFT; 422 dcac = mdcnfg >> MDCNFD_DCAC23_SHIFT; 423 drac = mdcnfg >> MDCNFD_DRAC23_SHIFT; 424 dnb = mdcnfg >> MDCNFD_DNB23_SHIFT; 425 break; 426 default: 427 panic("pxa2x0_probe_sdram: impossible"); 428 } 429 430 dwid = 2 << (1 - (dwid & MDCNFD_DWID_MASK)); /* 16/32 width */ 431 dcac = 1 << ((dcac & MDCNFD_DCAC_MASK) + 8); /* 8-11 columns */ 432 drac = 1 << ((drac & MDCNFD_DRAC_MASK) + 11); /* 11-13 rows */ 433 dnb = 2 << (dnb & MDCNFD_DNB_MASK); /* # of banks */ 434 435 size[i] = (paddr_t)(dwid * dcac * drac * dnb); 436 start[i] = PXA2X0_SDRAM0_START + (i * PXA2X0_SDRAM_BANK_SIZE); 437 } 438 } 439 440 void 441 pxa2x0_memctl_bootstrap(vaddr_t va) 442 { 443 444 pxamemctl_regs = va; 445 } 446 447 uint32_t 448 pxa2x0_memctl_read(int reg) 449 { 450 struct pxaip_softc *sc; 451 bus_space_tag_t iot; 452 bus_space_handle_t ioh; 453 454 if (__predict_true(pxaip_sc != NULL)) { 455 sc = pxaip_sc; 456 iot = sc->sc_bust; 457 ioh = sc->sc_bush_mem; 458 return (bus_space_read_4(iot, ioh, reg)); 459 } else if (__predict_true(pxamemctl_regs != 0)) { 460 return (MEMCTL_BOOTSTRAP_REG(reg)); 461 } 462 panic("pxa2x0_memctl_read: not bootstrapped"); 463 /*NOTREACHED*/ 464 } 465 466 void 467 pxa2x0_memctl_write(int reg, uint32_t val) 468 { 469 struct pxaip_softc *sc; 470 bus_space_tag_t iot; 471 bus_space_handle_t ioh; 472 473 if (__predict_true(pxaip_sc != NULL)) { 474 sc = pxaip_sc; 475 iot = sc->sc_bust; 476 ioh = sc->sc_bush_mem; 477 bus_space_write_4(iot, ioh, reg, val); 478 } else if (__predict_true(pxamemctl_regs != 0)) { 479 MEMCTL_BOOTSTRAP_REG(reg) = val; 480 } else { 481 panic("pxa2x0_memctl_write: not bootstrapped"); 482 } 483 return; 484 } 485 486 void 487 pxa2x0_clkman_bootstrap(vaddr_t va) 488 { 489 490 pxaclkman_regs = va; 491 } 492 493 void 494 pxa2x0_clkman_config(u_int clk, bool enable) 495 { 496 struct pxaip_softc *sc; 497 bus_space_tag_t iot; 498 bus_space_handle_t ioh; 499 uint32_t rv; 500 501 if (__predict_true(pxaip_sc != NULL)) { 502 sc = pxaip_sc; 503 iot = sc->sc_bust; 504 ioh = sc->sc_bush_clk; 505 506 rv = bus_space_read_4(iot, ioh, CLKMAN_CKEN); 507 rv &= ~clk; 508 if (enable) 509 rv |= clk; 510 bus_space_write_4(iot, ioh, CLKMAN_CKEN, rv); 511 return; 512 } else if (__predict_true(pxaclkman_regs != 0)) { 513 rv = CLKMAN_BOOTSTRAP_REG(CLKMAN_CKEN); 514 rv &= ~clk; 515 if (enable) 516 rv |= clk; 517 CLKMAN_BOOTSTRAP_REG(CLKMAN_CKEN) = rv; 518 return; 519 } 520 panic("pxa2x0_clkman_config: not bootstrapped"); 521 } 522