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 128struct 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 */ 137static int pxaip_match(device_t, cfdata_t, void *); 138static void pxaip_attach(device_t, device_t, void *); 139static int pxaip_search(device_t, cfdata_t, const int *, void *); 140static void pxaip_attach_critical(struct pxaip_softc *); 141static int pxaip_print(void *, const char *); 142 143static 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 */ 156CFATTACH_DECL_NEW(pxaip, sizeof(struct pxaip_softc), 157 pxaip_match, pxaip_attach, NULL, NULL); 158 159static struct pxaip_softc *pxaip_sc; 160static vaddr_t pxamemctl_regs; 161#define MEMCTL_BOOTSTRAP_REG(reg) \ 162 (*((volatile uint32_t *)(pxamemctl_regs + (reg)))) 163static vaddr_t pxaclkman_regs; 164#define CLKMAN_BOOTSTRAP_REG(reg) \ 165 (*((volatile uint32_t *)(pxaclkman_regs + (reg)))) 166 167static int 168pxaip_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 191static void 192pxaip_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 237static int 238pxaip_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 257static void 258pxaip_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 294static int 295pxaip_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 310static inline uint32_t 311read_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 319static inline uint32_t 320read_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 328static int 329pxaip_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 382void 383pxa2x0_turbo_mode(int f) 384{ 385 __asm volatile("mcr p14, 0, %0, c6, c0, 0" : : "r" (f)); 386} 387 388void 389pxa2x0_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 439void 440pxa2x0_memctl_bootstrap(vaddr_t va) 441{ 442 443 pxamemctl_regs = va; 444} 445 446uint32_t 447pxa2x0_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 465void 466pxa2x0_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 485void 486pxa2x0_clkman_bootstrap(vaddr_t va) 487{ 488 489 pxaclkman_regs = va; 490} 491 492void 493pxa2x0_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