1 /* $NetBSD: pxa2x0.c,v 1.17 2008/05/03 23:06:06 martin 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.17 2008/05/03 23:06:06 martin 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 <machine/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 struct device 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(struct device *, struct cfdata *, void *); 138 static void pxaip_attach(struct device *, struct device *, void *); 139 static int pxaip_search(struct device *, struct cfdata *, 140 const int *, void *); 141 static void pxaip_attach_critical(struct pxaip_softc *); 142 static int pxaip_print(void *, const char *); 143 144 static int pxaip_measure_cpuclock(struct pxaip_softc *); 145 146 #if defined(CPU_XSCALE_PXA250) && defined(CPU_XSCALE_PXA270) 147 # define SUPPORTED_CPU "PXA250 and PXA270" 148 #elif defined(CPU_XSCALE_PXA250) 149 # define SUPPORTED_CPU "PXA250" 150 #elif defined(CPU_XSCALE_PXA270) 151 # define SUPPORTED_CPU "PXA270" 152 #else 153 # define SUPPORTED_CPU "none of PXA2xx" 154 #endif 155 156 /* attach structures */ 157 CFATTACH_DECL(pxaip, sizeof(struct pxaip_softc), 158 pxaip_match, pxaip_attach, NULL, NULL); 159 160 static struct pxaip_softc *pxaip_sc; 161 static vaddr_t pxamemctl_regs; 162 #define MEMCTL_BOOTSTRAP_REG(reg) \ 163 (*((volatile uint32_t *)(pxamemctl_regs + (reg)))) 164 static vaddr_t pxaclkman_regs; 165 #define CLKMAN_BOOTSTRAP_REG(reg) \ 166 (*((volatile uint32_t *)(pxaclkman_regs + (reg)))) 167 168 static int 169 pxaip_match(struct device *parent, struct cfdata *match, void *aux) 170 { 171 172 #if !defined(CPU_XSCALE_PXA270) 173 if (__CPU_IS_PXA270) 174 goto bad_config; 175 #endif 176 177 #if !defined(CPU_XSCALE_PXA250) 178 if (__CPU_IS_PXA250) 179 goto bad_config; 180 #endif 181 182 return 1; 183 184 #if defined(CPU_XSCALE_PXA250) + defined(CPU_XSCALE_PXA270) != 2 185 bad_config: 186 aprint_error("Kernel is configured for %s, but CPU is %s\n", 187 SUPPORTED_CPU, __CPU_IS_PXA270 ? "PXA270" : "PXA250"); 188 return 0; 189 #endif 190 } 191 192 static void 193 pxaip_attach(struct device *parent, struct device *self, void *aux) 194 { 195 struct pxaip_softc *sc = (struct pxaip_softc *)self; 196 int cpuclock; 197 198 pxaip_sc = sc; 199 sc->sc_bust = &pxa2x0_bs_tag; 200 sc->sc_dmat = &pxa2x0_bus_dma_tag; 201 202 aprint_normal(": PXA2x0 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", self->dv_xname, 218 cpuclock/1000, cpuclock%1000 ); 219 220 aprint_normal("%s: kernel is configured for " SUPPORTED_CPU 221 ", cpu type is %s\n", 222 self->dv_xname, 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_ia(pxaip_search, self, "pxaip", sc); 234 } 235 236 static int 237 pxaip_search(struct device *parent, struct cfdata *cf, 238 const int *ldesc, void *aux) 239 { 240 struct pxaip_softc *sc = aux; 241 struct pxaip_attach_args aa; 242 243 aa.pxa_iot = sc->sc_bust; 244 aa.pxa_dmat = sc->sc_dmat; 245 aa.pxa_addr = cf->cf_loc[PXAIPCF_ADDR]; 246 aa.pxa_size = cf->cf_loc[PXAIPCF_SIZE]; 247 aa.pxa_index = cf->cf_loc[PXAIPCF_INDEX]; 248 aa.pxa_intr = cf->cf_loc[PXAIPCF_INTR]; 249 250 if (config_match(parent, cf, &aa)) 251 config_attach(parent, cf, &aa, pxaip_print); 252 253 return 0; 254 } 255 256 static void 257 pxaip_attach_critical(struct pxaip_softc *sc) 258 { 259 struct pxaip_attach_args aa; 260 261 aa.pxa_iot = sc->sc_bust; 262 aa.pxa_dmat = sc->sc_dmat; 263 aa.pxa_addr = PXA2X0_INTCTL_BASE; 264 aa.pxa_size = PXA2X0_INTCTL_SIZE; 265 aa.pxa_intr = PXAIPCF_INTR_DEFAULT; 266 if (config_found(&sc->sc_dev, &aa, pxaip_print) == NULL) 267 panic("pxaip_attach_critical: failed to attach INTC!"); 268 269 #if NPXAGPIO > 0 270 aa.pxa_iot = sc->sc_bust; 271 aa.pxa_dmat = sc->sc_dmat; 272 aa.pxa_addr = PXA2X0_GPIO_BASE; 273 aa.pxa_size = PXA2X0_GPIO_SIZE; 274 aa.pxa_intr = PXAIPCF_INTR_DEFAULT; 275 if (config_found(&sc->sc_dev, &aa, pxaip_print) == NULL) 276 panic("pxaip_attach_critical: failed to attach GPIO!"); 277 #endif 278 279 #if NPXADMAC > 0 280 aa.pxa_iot = sc->sc_bust; 281 aa.pxa_dmat = sc->sc_dmat; 282 aa.pxa_addr = PXA2X0_DMAC_BASE; 283 aa.pxa_size = PXA2X0_DMAC_SIZE; 284 aa.pxa_intr = PXA2X0_INT_DMA; 285 if (config_found(&sc->sc_dev, &aa, pxaip_print) == NULL) 286 panic("pxaip_attach_critical: failed to attach DMAC!"); 287 #endif 288 } 289 290 static int 291 pxaip_print(void *aux, const char *name) 292 { 293 struct pxaip_attach_args *sa = (struct pxaip_attach_args*)aux; 294 295 if (sa->pxa_addr != PXAIPCF_ADDR_DEFAULT) { 296 aprint_normal(" addr 0x%lx", sa->pxa_addr); 297 if (sa->pxa_size > PXAIPCF_SIZE_DEFAULT) 298 aprint_normal("-0x%lx", sa->pxa_addr + sa->pxa_size-1); 299 } 300 if (sa->pxa_intr != PXAIPCF_INTR_DEFAULT) 301 aprint_normal(" intr %d", sa->pxa_intr); 302 303 return (UNCONF); 304 } 305 306 static inline uint32_t 307 read_clock_counter_xsc1(void) 308 { 309 uint32_t x; 310 __asm volatile("mrc p14, 0, %0, c1, c0, 0" : "=r" (x) ); 311 312 return x; 313 } 314 315 static inline uint32_t 316 read_clock_counter_xsc2(void) 317 { 318 uint32_t x; 319 __asm volatile("mrc p14, 0, %0, c1, c1, 0" : "=r" (x) ); 320 321 return x; 322 } 323 324 static int 325 pxaip_measure_cpuclock(struct pxaip_softc *sc) 326 { 327 uint32_t rtc0, rtc1, start, end; 328 uint32_t pmcr_save; 329 bus_space_handle_t ioh; 330 int irq; 331 int is_xsc2 = CPU_IS_PXA270; 332 #define read_clock_counter() (is_xsc2 ? read_clock_counter_xsc2() : \ 333 read_clock_counter_xsc1()) 334 335 if (bus_space_map(sc->sc_bust, PXA2X0_RTC_BASE, PXA2X0_RTC_SIZE, 0, 336 &ioh)) 337 panic("pxaip_measure_cpuclock: can't map RTC"); 338 339 irq = disable_interrupts(I32_bit|F32_bit); 340 341 if (is_xsc2) { 342 __asm volatile( 343 "mrc p14, 0, %0, c0, c1, 0" : "=r" (pmcr_save)); 344 /* Enable clock counter */ 345 __asm volatile( 346 "mcr p14, 0, %0, c0, c1, 0" : : "r" (PMNC_E|PMNC_C)); 347 } 348 else { 349 __asm volatile( 350 "mrc p14, 0, %0, c0, c0, 0" : "=r" (pmcr_save)); 351 /* Enable clock counter */ 352 __asm volatile( 353 "mcr p14, 0, %0, c0, c0, 0" : : "r" (PMNC_E|PMNC_C)); 354 } 355 356 rtc0 = bus_space_read_4(sc->sc_bust, ioh, RTC_RCNR); 357 /* Wait for next second starts */ 358 while ((rtc1 = bus_space_read_4(sc->sc_bust, ioh, RTC_RCNR)) == rtc0) 359 ; 360 start = read_clock_counter(); 361 while(rtc1 == bus_space_read_4(sc->sc_bust, ioh, RTC_RCNR)) 362 ; /* Wait for 1sec */ 363 end = read_clock_counter(); 364 365 if (is_xsc2) 366 __asm volatile( 367 "mcr p14, 0, %0, c0, c1, 0" : : "r" (pmcr_save)); 368 else 369 __asm volatile( 370 "mcr p14, 0, %0, c0, c0, 0" : : "r" (pmcr_save)); 371 restore_interrupts(irq); 372 373 bus_space_unmap(sc->sc_bust, ioh, PXA2X0_RTC_SIZE); 374 375 return end - start; 376 } 377 378 void 379 pxa2x0_turbo_mode(int f) 380 { 381 __asm volatile("mcr p14, 0, %0, c6, c0, 0" : : "r" (f)); 382 } 383 384 void 385 pxa2x0_probe_sdram(vaddr_t memctl_va, paddr_t *start, paddr_t *size) 386 { 387 u_int32_t mdcnfg, dwid, dcac, drac, dnb; 388 int i; 389 390 mdcnfg = *((volatile u_int32_t *)(memctl_va + MEMCTL_MDCNFG)); 391 392 /* 393 * Scan all 4 SDRAM banks 394 */ 395 for (i = 0; i < PXA2X0_SDRAM_BANKS; i++) { 396 start[i] = 0; 397 size[i] = 0; 398 399 switch (i) { 400 case 0: 401 case 1: 402 if ((i == 0 && (mdcnfg & MDCNFG_DE0) == 0) || 403 (i == 1 && (mdcnfg & MDCNFG_DE1) == 0)) 404 continue; 405 dwid = mdcnfg >> MDCNFD_DWID01_SHIFT; 406 dcac = mdcnfg >> MDCNFD_DCAC01_SHIFT; 407 drac = mdcnfg >> MDCNFD_DRAC01_SHIFT; 408 dnb = mdcnfg >> MDCNFD_DNB01_SHIFT; 409 break; 410 411 case 2: 412 case 3: 413 if ((i == 2 && (mdcnfg & MDCNFG_DE2) == 0) || 414 (i == 3 && (mdcnfg & MDCNFG_DE3) == 0)) 415 continue; 416 dwid = mdcnfg >> MDCNFD_DWID23_SHIFT; 417 dcac = mdcnfg >> MDCNFD_DCAC23_SHIFT; 418 drac = mdcnfg >> MDCNFD_DRAC23_SHIFT; 419 dnb = mdcnfg >> MDCNFD_DNB23_SHIFT; 420 break; 421 default: 422 panic("pxa2x0_probe_sdram: impossible"); 423 } 424 425 dwid = 2 << (1 - (dwid & MDCNFD_DWID_MASK)); /* 16/32 width */ 426 dcac = 1 << ((dcac & MDCNFD_DCAC_MASK) + 8); /* 8-11 columns */ 427 drac = 1 << ((drac & MDCNFD_DRAC_MASK) + 11); /* 11-13 rows */ 428 dnb = 2 << (dnb & MDCNFD_DNB_MASK); /* # of banks */ 429 430 size[i] = (paddr_t)(dwid * dcac * drac * dnb); 431 start[i] = PXA2X0_SDRAM0_START + (i * PXA2X0_SDRAM_BANK_SIZE); 432 } 433 } 434 435 void 436 pxa2x0_memctl_bootstrap(vaddr_t va) 437 { 438 439 pxamemctl_regs = va; 440 } 441 442 uint32_t 443 pxa2x0_memctl_read(int reg) 444 { 445 struct pxaip_softc *sc; 446 bus_space_tag_t iot; 447 bus_space_handle_t ioh; 448 449 if (__predict_true(pxaip_sc != NULL)) { 450 sc = pxaip_sc; 451 iot = sc->sc_bust; 452 ioh = sc->sc_bush_mem; 453 return (bus_space_read_4(iot, ioh, reg)); 454 } else if (__predict_true(pxamemctl_regs != 0)) { 455 return (MEMCTL_BOOTSTRAP_REG(reg)); 456 } 457 panic("pxa2x0_memctl_read: not bootstrapped"); 458 /*NOTREACHED*/ 459 } 460 461 void 462 pxa2x0_memctl_write(int reg, uint32_t val) 463 { 464 struct pxaip_softc *sc; 465 bus_space_tag_t iot; 466 bus_space_handle_t ioh; 467 468 if (__predict_true(pxaip_sc != NULL)) { 469 sc = pxaip_sc; 470 iot = sc->sc_bust; 471 ioh = sc->sc_bush_mem; 472 bus_space_write_4(iot, ioh, reg, val); 473 } else if (__predict_true(pxamemctl_regs != 0)) { 474 MEMCTL_BOOTSTRAP_REG(reg) = val; 475 } else { 476 panic("pxa2x0_memctl_write: not bootstrapped"); 477 } 478 return; 479 } 480 481 void 482 pxa2x0_clkman_bootstrap(vaddr_t va) 483 { 484 485 pxaclkman_regs = va; 486 } 487 488 void 489 pxa2x0_clkman_config(u_int clk, bool enable) 490 { 491 struct pxaip_softc *sc; 492 bus_space_tag_t iot; 493 bus_space_handle_t ioh; 494 uint32_t rv; 495 496 if (__predict_true(pxaip_sc != NULL)) { 497 sc = pxaip_sc; 498 iot = sc->sc_bust; 499 ioh = sc->sc_bush_clk; 500 501 rv = bus_space_read_4(iot, ioh, CLKMAN_CKEN); 502 rv &= ~clk; 503 if (enable) 504 rv |= clk; 505 bus_space_write_4(iot, ioh, CLKMAN_CKEN, rv); 506 return; 507 } else if (__predict_true(pxaclkman_regs != 0)) { 508 rv = CLKMAN_BOOTSTRAP_REG(CLKMAN_CKEN); 509 rv &= ~clk; 510 if (enable) 511 rv |= clk; 512 CLKMAN_BOOTSTRAP_REG(CLKMAN_CKEN) = rv; 513 return; 514 } 515 panic("pxa2x0_clkman_config: not bootstrapped"); 516 } 517