1 /* $NetBSD: pxa2x0.c,v 1.24 2021/08/07 16:18:46 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.24 2021/08/07 16:18:46 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 CFARGS(.search = pxaip_search)); 235 } 236 237 static int 238 pxaip_search(device_t parent, cfdata_t cf, const int *ldesc, void *aux) 239 { 240 struct pxaip_softc *sc = device_private(parent); 241 struct pxaip_attach_args aa; 242 243 aa.pxa_iot = sc->sc_bust; 244 aa.pxa_dmat = sc->sc_dmat; 245 aa.pxa_name = cf->cf_name; 246 aa.pxa_addr = cf->cf_loc[PXAIPCF_ADDR]; 247 aa.pxa_size = cf->cf_loc[PXAIPCF_SIZE]; 248 aa.pxa_index = cf->cf_loc[PXAIPCF_INDEX]; 249 aa.pxa_intr = cf->cf_loc[PXAIPCF_INTR]; 250 251 if (config_probe(parent, cf, &aa)) 252 config_attach(parent, cf, &aa, pxaip_print, CFARGS_NONE); 253 254 return 0; 255 } 256 257 static void 258 pxaip_attach_critical(struct pxaip_softc *sc) 259 { 260 struct pxaip_attach_args aa; 261 262 aa.pxa_iot = sc->sc_bust; 263 aa.pxa_dmat = sc->sc_dmat; 264 aa.pxa_name = "pxaintc"; 265 aa.pxa_addr = PXA2X0_INTCTL_BASE; 266 aa.pxa_size = PXA2X0_INTCTL_SIZE; 267 aa.pxa_intr = PXAIPCF_INTR_DEFAULT; 268 if (config_found(sc->sc_dev, &aa, pxaip_print, CFARGS_NONE) == NULL) 269 panic("pxaip_attach_critical: failed to attach INTC!"); 270 271 #if NPXAGPIO > 0 272 aa.pxa_iot = sc->sc_bust; 273 aa.pxa_dmat = sc->sc_dmat; 274 aa.pxa_name = "pxagpio"; 275 aa.pxa_addr = PXA2X0_GPIO_BASE; 276 aa.pxa_size = PXA2X0_GPIO_SIZE; 277 aa.pxa_intr = PXAIPCF_INTR_DEFAULT; 278 if (config_found(sc->sc_dev, &aa, pxaip_print, CFARGS_NONE) == NULL) 279 panic("pxaip_attach_critical: failed to attach GPIO!"); 280 #endif 281 282 #if NPXADMAC > 0 283 aa.pxa_iot = sc->sc_bust; 284 aa.pxa_dmat = sc->sc_dmat; 285 aa.pxa_name = "pxaidmac"; 286 aa.pxa_addr = PXA2X0_DMAC_BASE; 287 aa.pxa_size = PXA2X0_DMAC_SIZE; 288 aa.pxa_intr = PXA2X0_INT_DMA; 289 if (config_found(sc->sc_dev, &aa, pxaip_print, CFARGS_NONE) == NULL) 290 panic("pxaip_attach_critical: failed to attach DMAC!"); 291 #endif 292 } 293 294 static int 295 pxaip_print(void *aux, const char *name) 296 { 297 struct pxaip_attach_args *sa = (struct pxaip_attach_args *)aux; 298 299 if (sa->pxa_addr != PXAIPCF_ADDR_DEFAULT) { 300 aprint_normal(" addr 0x%lx", sa->pxa_addr); 301 if (sa->pxa_size > PXAIPCF_SIZE_DEFAULT) 302 aprint_normal("-0x%lx", sa->pxa_addr + sa->pxa_size-1); 303 } 304 if (sa->pxa_intr != PXAIPCF_INTR_DEFAULT) 305 aprint_normal(" intr %d", sa->pxa_intr); 306 307 return (UNCONF); 308 } 309 310 static inline uint32_t 311 read_clock_counter_xsc1(void) 312 { 313 uint32_t x; 314 __asm volatile("mrc p14, 0, %0, c1, c0, 0" : "=r" (x) ); 315 316 return x; 317 } 318 319 static inline uint32_t 320 read_clock_counter_xsc2(void) 321 { 322 uint32_t x; 323 __asm volatile("mrc p14, 0, %0, c1, c1, 0" : "=r" (x) ); 324 325 return x; 326 } 327 328 static int 329 pxaip_measure_cpuclock(struct pxaip_softc *sc) 330 { 331 uint32_t rtc0, rtc1, start, end; 332 uint32_t pmcr_save; 333 bus_space_handle_t ioh; 334 int irq; 335 int is_xsc2 = CPU_IS_PXA270; 336 #define read_clock_counter() (is_xsc2 ? read_clock_counter_xsc2() : \ 337 read_clock_counter_xsc1()) 338 339 if (bus_space_map(sc->sc_bust, PXA2X0_RTC_BASE, PXA2X0_RTC_SIZE, 0, 340 &ioh)) 341 panic("pxaip_measure_cpuclock: can't map RTC"); 342 343 irq = disable_interrupts(I32_bit|F32_bit); 344 345 if (is_xsc2) { 346 __asm volatile( 347 "mrc p14, 0, %0, c0, c1, 0" : "=r" (pmcr_save)); 348 /* Enable clock counter */ 349 __asm volatile( 350 "mcr p14, 0, %0, c0, c1, 0" : : "r" (PMNC_E|PMNC_C)); 351 } 352 else { 353 __asm volatile( 354 "mrc p14, 0, %0, c0, c0, 0" : "=r" (pmcr_save)); 355 /* Enable clock counter */ 356 __asm volatile( 357 "mcr p14, 0, %0, c0, c0, 0" : : "r" (PMNC_E|PMNC_C)); 358 } 359 360 rtc0 = bus_space_read_4(sc->sc_bust, ioh, RTC_RCNR); 361 /* Wait for next second starts */ 362 while ((rtc1 = bus_space_read_4(sc->sc_bust, ioh, RTC_RCNR)) == rtc0) 363 ; 364 start = read_clock_counter(); 365 while(rtc1 == bus_space_read_4(sc->sc_bust, ioh, RTC_RCNR)) 366 ; /* Wait for 1sec */ 367 end = read_clock_counter(); 368 369 if (is_xsc2) 370 __asm volatile( 371 "mcr p14, 0, %0, c0, c1, 0" : : "r" (pmcr_save)); 372 else 373 __asm volatile( 374 "mcr p14, 0, %0, c0, c0, 0" : : "r" (pmcr_save)); 375 restore_interrupts(irq); 376 377 bus_space_unmap(sc->sc_bust, ioh, PXA2X0_RTC_SIZE); 378 379 return end - start; 380 } 381 382 void 383 pxa2x0_turbo_mode(int f) 384 { 385 __asm volatile("mcr p14, 0, %0, c6, c0, 0" : : "r" (f)); 386 } 387 388 void 389 pxa2x0_probe_sdram(vaddr_t memctl_va, paddr_t *start, paddr_t *size) 390 { 391 uint32_t mdcnfg, dwid, dcac, drac, dnb; 392 int i; 393 394 mdcnfg = *((volatile uint32_t *)(memctl_va + MEMCTL_MDCNFG)); 395 396 /* 397 * Scan all 4 SDRAM banks 398 */ 399 for (i = 0; i < PXA2X0_SDRAM_BANKS; i++) { 400 start[i] = 0; 401 size[i] = 0; 402 403 switch (i) { 404 case 0: 405 case 1: 406 if ((i == 0 && (mdcnfg & MDCNFG_DE0) == 0) || 407 (i == 1 && (mdcnfg & MDCNFG_DE1) == 0)) 408 continue; 409 dwid = mdcnfg >> MDCNFD_DWID01_SHIFT; 410 dcac = mdcnfg >> MDCNFD_DCAC01_SHIFT; 411 drac = mdcnfg >> MDCNFD_DRAC01_SHIFT; 412 dnb = mdcnfg >> MDCNFD_DNB01_SHIFT; 413 break; 414 415 case 2: 416 case 3: 417 if ((i == 2 && (mdcnfg & MDCNFG_DE2) == 0) || 418 (i == 3 && (mdcnfg & MDCNFG_DE3) == 0)) 419 continue; 420 dwid = mdcnfg >> MDCNFD_DWID23_SHIFT; 421 dcac = mdcnfg >> MDCNFD_DCAC23_SHIFT; 422 drac = mdcnfg >> MDCNFD_DRAC23_SHIFT; 423 dnb = mdcnfg >> MDCNFD_DNB23_SHIFT; 424 break; 425 default: 426 panic("pxa2x0_probe_sdram: impossible"); 427 } 428 429 dwid = 2 << (1 - (dwid & MDCNFD_DWID_MASK)); /* 16/32 width */ 430 dcac = 1 << ((dcac & MDCNFD_DCAC_MASK) + 8); /* 8-11 columns */ 431 drac = 1 << ((drac & MDCNFD_DRAC_MASK) + 11); /* 11-13 rows */ 432 dnb = 2 << (dnb & MDCNFD_DNB_MASK); /* # of banks */ 433 434 size[i] = (paddr_t)(dwid * dcac * drac * dnb); 435 start[i] = PXA2X0_SDRAM0_START + (i * PXA2X0_SDRAM_BANK_SIZE); 436 } 437 } 438 439 void 440 pxa2x0_memctl_bootstrap(vaddr_t va) 441 { 442 443 pxamemctl_regs = va; 444 } 445 446 uint32_t 447 pxa2x0_memctl_read(int reg) 448 { 449 struct pxaip_softc *sc; 450 bus_space_tag_t iot; 451 bus_space_handle_t ioh; 452 453 if (__predict_true(pxaip_sc != NULL)) { 454 sc = pxaip_sc; 455 iot = sc->sc_bust; 456 ioh = sc->sc_bush_mem; 457 return (bus_space_read_4(iot, ioh, reg)); 458 } else if (__predict_true(pxamemctl_regs != 0)) { 459 return (MEMCTL_BOOTSTRAP_REG(reg)); 460 } 461 panic("pxa2x0_memctl_read: not bootstrapped"); 462 /*NOTREACHED*/ 463 } 464 465 void 466 pxa2x0_memctl_write(int reg, uint32_t val) 467 { 468 struct pxaip_softc *sc; 469 bus_space_tag_t iot; 470 bus_space_handle_t ioh; 471 472 if (__predict_true(pxaip_sc != NULL)) { 473 sc = pxaip_sc; 474 iot = sc->sc_bust; 475 ioh = sc->sc_bush_mem; 476 bus_space_write_4(iot, ioh, reg, val); 477 } else if (__predict_true(pxamemctl_regs != 0)) { 478 MEMCTL_BOOTSTRAP_REG(reg) = val; 479 } else { 480 panic("pxa2x0_memctl_write: not bootstrapped"); 481 } 482 return; 483 } 484 485 void 486 pxa2x0_clkman_bootstrap(vaddr_t va) 487 { 488 489 pxaclkman_regs = va; 490 } 491 492 void 493 pxa2x0_clkman_config(u_int clk, bool enable) 494 { 495 struct pxaip_softc *sc; 496 bus_space_tag_t iot; 497 bus_space_handle_t ioh; 498 uint32_t rv; 499 500 if (__predict_true(pxaip_sc != NULL)) { 501 sc = pxaip_sc; 502 iot = sc->sc_bust; 503 ioh = sc->sc_bush_clk; 504 505 rv = bus_space_read_4(iot, ioh, CLKMAN_CKEN); 506 rv &= ~clk; 507 if (enable) 508 rv |= clk; 509 bus_space_write_4(iot, ioh, CLKMAN_CKEN, rv); 510 return; 511 } else if (__predict_true(pxaclkman_regs != 0)) { 512 rv = CLKMAN_BOOTSTRAP_REG(CLKMAN_CKEN); 513 rv &= ~clk; 514 if (enable) 515 rv |= clk; 516 CLKMAN_BOOTSTRAP_REG(CLKMAN_CKEN) = rv; 517 return; 518 } 519 panic("pxa2x0_clkman_config: not bootstrapped"); 520 } 521