|
34 | 34 |
|
35 | 35 | #include "fsl_clock.h"
|
36 | 36 | #include "fsl_iomuxc.h"
|
| 37 | +#include "fsl_device_registers.h" |
37 | 38 |
|
38 | 39 | #include "clocks.h"
|
39 | 40 |
|
@@ -335,3 +336,257 @@ void clocks_init(void) {
|
335 | 336 |
|
336 | 337 | CLOCK_EnableClock(kCLOCK_Iomuxc);
|
337 | 338 | }
|
| 339 | + |
| 340 | +/* clockspeed.c |
| 341 | + * http://www.pjrc.com/teensy/ |
| 342 | + * Copyright (c) 2017 PJRC.COM, LLC |
| 343 | + * |
| 344 | + * Permission is hereby granted, free of charge, to any person obtaining a copy |
| 345 | + * of this software and associated documentation files (the "Software"), to deal |
| 346 | + * in the Software without restriction, including without limitation the rights |
| 347 | + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
| 348 | + * copies of the Software, and to permit persons to whom the Software is |
| 349 | + * furnished to do so, subject to the following conditions: |
| 350 | + * |
| 351 | + * The above copyright notice and this permission notice shall be included in |
| 352 | + * all copies or substantial portions of the Software. |
| 353 | + * |
| 354 | + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
| 355 | + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
| 356 | + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
| 357 | + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
| 358 | + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
| 359 | + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN |
| 360 | + * THE SOFTWARE. |
| 361 | + */ |
| 362 | +// Note setarmclock is a port from Teensyduino for the Teensy 4.x written by Paul Stroffgren, |
| 363 | +// A brief explanation of F_CPU_ACTUAL vs F_CPU |
| 364 | +// https://forum.pjrc.com/threads/57236?p=212642&viewfull=1#post212642 |
| 365 | +volatile uint32_t F_CPU_ACTUAL = 396000000; |
| 366 | +volatile uint32_t F_BUS_ACTUAL = 132000000; |
| 367 | + |
| 368 | +// Define these to increase the voltage when attempting overclocking |
| 369 | +
7863
// The frequency step is how quickly to increase voltage per frequency |
| 370 | +// The datasheet says 1600 is the absolute maximum voltage. The hardware |
| 371 | +// can actually create up to 1575. But 1300 is the recommended limit. |
| 372 | +// (earlier versions of the datasheet said 1300 was the absolute max) |
| 373 | +#define OVERCLOCK_STEPSIZE 28000000 |
| 374 | +#define OVERCLOCK_MAX_VOLT 1575 |
| 375 | + |
| 376 | +#define DCDC_REG3 0x40080012 |
| 377 | +#define DCDC_REG0 0x40080000 |
| 378 | +#define DCDC_REG0_STS_DC_OK_L ((uint32_t)(1 << 31)) |
| 379 | +#define CCM_ANALOG_PLL_USB1_ENABLE_L ((uint32_t)(1 << 13)) |
| 380 | +#define CCM_ANALOG_PLL_USB1_POWER_L ((uint32_t)(1 << 12)) |
| 381 | +#define CCM_ANALOG_PLL_USB1_EN_USB_CLKS_L ((uint32_t)(1 << 6)) |
| 382 | +#define CCM_ANALOG_PLL_USB1_LOCK_L ((uint32_t)(1 << 31)) |
| 383 | +#define CCM_CCGR6_DCDC(n) ((uint32_t)(((n) & 0x03) << 6)) |
| 384 | +#define CCM_ANALOG_PLL_ARM_LOCK_L ((uint32_t)(1 << 31)) |
| 385 | +#define CCM_ANALOG_PLL_ARM_BYPASS_L ((uint32_t)(1 << 16)) |
| 386 | +#define CCM_ANALOG_PLL_ARM_ENABLE_L ((uint32_t)(1 << 13)) |
| 387 | +#define CCM_ANALOG_PLL_ARM_POWERDOWN_L ((uint32_t)(1 << 12)) |
| 388 | +#define CCM_CDHIPR_ARM_PODF_BUSY_L ((uint32_t)(1 << 16)) |
| 389 | +#define CCM_CDHIPR_AHB_PODF_BUSY_L ((uint32_t)(1 << 1)) |
| 390 | +#define CCM_CDHIPR_PERIPH_CLK_SEL_BUSY_L ((uint32_t)(1 << 5)) |
| 391 | +#define CCM_CBCDR_PERIPH_CLK_SEL_L ((uint32_t)(1 << 25)) |
| 392 | +#define CCM_CCGR_OFF 0 |
| 393 | +#define CCM_CCGR_ON_RUNONLY 1 |
| 394 | +#define CCM_CCGR_ON 3 |
| 395 | + |
| 396 | +/* Teensyduino Core Library - clockspeed.c |
| 397 | + * http://www.pjrc.com/teensy/ |
| 398 | + * Copyright (c) 2017 PJRC.COM, LLC. |
| 399 | + * |
| 400 | + * Permission is hereby granted, free of charge, to any person obtaining |
| 401 | + * a copy of this software and associated documentation files (the |
| 402 | + * "Software"), to deal in the Software without restriction, including |
| 403 | + * without limitation the rights to use, copy, modify, merge, publish, |
| 404 | + * distribute, sublicense, and/or sell copies of the Software, and to |
| 405 | + * permit persons to whom the Software is furnished to do so, subject to |
| 406 | + * the following conditions: |
| 407 | + * |
| 408 | + * 1. The above copyright notice and this permission notice shall be |
| 409 | + * included in all copies or substantial portions of the Software. |
| 410 | + * |
| 411 | + * 2. If the Software is incorporated into a build system that allows |
| 412 | + * selection among a list of target devices, then similar target |
| 413 | + * devices manufactured by PJRC.COM must be included in the list of |
| 414 | + * target devices and selectable in the same manner. |
| 415 | + * |
| 416 | + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, |
| 417 | + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF |
| 418 | + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND |
| 419 | + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS |
| 420 | + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN |
| 421 | + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN |
| 422 | + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE |
| 423 | + * SOFTWARE. |
| 424 | + */ |
| 425 | + |
| 426 | +// uint32_t set_arm_clock(uint32_t frequency); |
| 427 | + |
| 428 | +// stuff needing wait handshake: |
| 429 | +// CCM_CACRR ARM_PODF |
| 430 | +// CCM_CBCDR PERIPH_CLK_SEL |
| 431 | +// CCM_CBCMR PERIPH2_CLK_SEL |
| 432 | +// CCM_CBCDR AHB_PODF |
| 433 | +// CCM_CBCDR SEMC_PODF |
| 434 | + |
| 435 | +uint32_t setarmclock(uint32_t frequency) { |
| 436 | + uint32_t cbcdr = CCM->CBCDR; // pg 1021 |
| 437 | + uint32_t cbcmr = CCM->CBCMR; // pg 1023 |
| 438 | + uint32_t dcdc = DCDC->REG3; |
| 439 | + |
| 440 | + // compute required voltage |
| 441 | + uint32_t voltage = 1150; // default = 1.15V |
| 442 | + if (frequency > 528000000) { |
| 443 | + voltage = 1250; // 1.25V |
| 444 | + #if defined(OVERCLOCK_STEPSIZE) && defined(OVERCLOCK_MAX_VOLT) |
| 445 | + if (frequency > 600000000) { |
| 446 | + voltage += ((frequency - 600000000) / OVERCLOCK_STEPSIZE) * 25; |
| 447 | + if (voltage > OVERCLOCK_MAX_VOLT) { |
| 448 | + voltage = OVERCLOCK_MAX_VOLT; |
| 449 | + } |
| 450 | + } |
| 451 | + #endif |
| 452 | + } else if (frequency <= 24000000) { |
| 453 | + voltage = 950; // 0.95 |
| 454 | + } |
| 455 | + |
| 456 | + // if voltage needs to increase, do it before switch clock speed |
| 457 | + CCM->CCGR6 |= CCM_CCGR6_DCDC(CCM_CCGR_ON); |
| 458 | + if ((dcdc & ((uint32_t)(0x1F << 0))) < ((uint32_t)(((voltage - 800) / 25) & 0x1F) << 0)) { |
| 459 | + dcdc &= ~((uint32_t)(0x1F << 0)); |
| 460 | + dcdc |= ((uint32_t)(((voltage - 800) / 25) & 0x1F) << 0); |
| 461 | + DCDC->REG3 = dcdc; |
| 462 | + while (!(DCDC->REG0 & DCDC_REG0_STS_DC_OK_L)) { |
| 463 | + ; // wait voltage settling |
| 464 | + } |
| 465 | + } |
| 466 | + |
| 467 | + if (!(cbcdr & CCM_CBCDR_PERIPH_CLK_SEL_L)) { |
| 468 | + const uint32_t need1s = CCM_ANALOG_PLL_USB1_ENABLE_L | CCM_ANALOG_PLL_USB1_POWER_L | |
| 469 | + CCM_ANALOG_PLL_USB1_LOCK_L | CCM_ANALOG_PLL_USB1_EN_USB_CLKS_L; |
| 470 | + uint32_t sel, div; |
| 471 | + if ((CCM_ANALOG->PLL_USB1 & need1s) == need1s) { |
| 472 | + sel = 0; |
| 473 | + div = 3; // divide down to 120 MHz, so IPG is ok even if IPG_PODF=0 |
| 474 | + } else { |
| 475 | + sel = 1; |
| 476 | + div = 0; |
| 477 | + } |
| 478 | + if ((cbcdr & ((uint32_t)(0x07 << 27))) != CCM_CBCDR_PERIPH_CLK2_PODF(div)) { |
| 479 | + // PERIPH_CLK2 divider needs to be changed |
| 480 | + cbcdr &= ~((uint32_t)(0x07 << 27)); |
| 481 | + cbcdr |= CCM_CBCDR_PERIPH_CLK2_PODF(div); |
| 482 | + CCM->CBCDR = cbcdr; |
| 483 | + } |
| 484 | + if ((cbcmr & ((uint32_t)(0x03 << 12))) != CCM_CBCMR_PERIPH_CLK2_SEL(sel)) { |
| 485 | + // PERIPH_CLK2 source select needs to be changed |
| 486 | + cbcmr &= ~((uint32_t)(0x03 << 12)); |
| 487 | + cbcmr |= CCM_CBCMR_PERIPH_CLK2_SEL(sel); |
| 488 | + CCM->CBCMR = cbcmr; |
| 489 | + while (CCM->CDHIPR & ((uint32_t)(1 << 3))) { |
| 490 | + ; // wait |
| 491 | + } |
| 492 | + } |
| 493 | + // switch over to PERIPH_CLK2 |
| 494 | + cbcdr |= ((uint32_t)(1 << 25)); |
| 495 | + CCM->CBCDR = cbcdr; |
| 496 | + while (CCM->CDHIPR & ((uint32_t)(1 << 5))) { |
| 497 | + ; // wait |
| 498 | + } |
| 499 | + } |
| 500 | + |
| 501 | + // TODO: check if PLL2 running, can 352, 396 or 528 can work? (no need for ARM PLL) |
| 502 | + |
| 503 | + // DIV_SELECT: 54-108 = official range 648 to 1296 in 12 MHz steps |
| 504 | + uint32_t div_arm = 1; |
| 505 | + uint32_t div_ahb = 1; |
| 506 | + while (frequency * div_arm * div_ahb < 648000000) { |
| 507 | + if (div_arm < 8) { |
| 508 | + div_arm = div_arm + 1; |
| 509 | + } else { |
| 510 | + if (div_ahb < 5) { |
| 511 | + div_ahb = div_ahb + 1; |
| 512 | + div_arm = 1; |
| 513 | + } else { |
| 514 | + break; |
| 515 | + } |
| 516 | + } |
| 517 | + } |
| 518 | + uint32_t mult = (frequency * div_arm * div_ahb + 6000000) / 12000000; |
| 519 | + if (mult > 108) { |
| 520 | + mult = 108; |
| 521 | + } |
| 522 | + if (mult < 54) { |
| 523 | + mult = 54; |
| 524 | + } |
| 525 | + |
| 526 | + frequency = mult * 12000000 / div_arm / div_ahb; |
| 527 | + |
| 528 | + const uint32_t arm_pll_mask = CCM_ANALOG_PLL_ARM_LOCK_L | CCM_ANALOG_PLL_ARM_BYPASS_L | |
| 529 | + CCM_ANALOG_PLL_ARM_ENABLE_L | CCM_ANALOG_PLL_ARM_POWERDOWN_L | |
| 530 | + CCM_ANALOG_PLL_ARM_DIV_SELECT_MASK; |
| 531 | + if ((CCM_ANALOG->PLL_ARM & arm_pll_mask) != (CCM_ANALOG_PLL_ARM_LOCK_L |
| 532 | + | CCM_ANALOG_PLL_ARM_ENABLE_L | CCM_ANALOG_PLL_ARM_DIV_SELECT(mult))) { |
| 533 | + // printf("ARM PLL needs reconfigure\n"); |
| 534 | + CCM_ANALOG->PLL_ARM = CCM_ANALOG_PLL_ARM_POWERDOWN_L; |
| 535 | + // TODO: delay needed? |
| 536 | + CCM_ANALOG->PLL_ARM = CCM_ANALOG_PLL_ARM_ENABLE_L |
| 537 | + | CCM_ANALOG_PLL_ARM_DIV_SELECT(mult); |
| 538 | + while (!(CCM_ANALOG->PLL_ARM & CCM_ANALOG_PLL_ARM_LOCK_L)) { |
| 539 | + ; // wait for lock |
| 540 | + } |
| 541 | + } |
| 542 | + |
| 543 | + if ((CCM->CACRR & ((uint32_t)(0x07 << 0))) != (div_arm - 1)) { |
| 544 | + CCM->CACRR = CCM_CACRR_ARM_PODF(div_arm - 1); |
| 545 | + while (CCM->CDHIPR & CCM_CDHIPR_ARM_PODF_BUSY_L) { |
| 546 | + ; // wait |
| 547 | + } |
| 548 | + } |
| 549 | + |
| 550 | + if ((cbcdr & ((uint32_t)(0x07 << 10))) != CCM_CBCDR_AHB_PODF(div_ahb - 1)) { |
| 551 | + cbcdr &= ~((uint32_t)(0x07 << 10)); |
| 552 | + cbcdr |= CCM_CBCDR_AHB_PODF(div_ahb - 1); |
| 553 | + CCM->CBCDR = cbcdr; |
| 554 | + while (CCM->CDHIPR & CCM_CDHIPR_AHB_PODF_BUSY_L) { |
| 555 | + ; // wait |
| 556 | + } |
| 557 | + } |
| 558 | + |
| 559 | + uint32_t div_ipg = (frequency + 149999999) / 150000000; |
| 560 | + if (div_ipg > 4) { |
| 561 | + div_ipg = 4; |
| 562 | + } |
| 563 | + if ((cbcdr & ((uint32_t)(0x03 << 8))) != (CCM_CBCDR_IPG_PODF(div_ipg - 1))) { |
| 564 | + cbcdr &= ~((uint32_t)(0x03 << 8)); |
| 565 | + cbcdr |= CCM_CBCDR_IPG_PODF(div_ipg - 1); |
| 566 | + // TODO: how to safely change IPG_PODF ?? |
| 567 | + CCM->CBCDR = cbcdr; |
| 568 | + } |
| 569 | + |
| 570 | + // cbcdr &= ~CCM_CBCDR_PERIPH_CLK_SEL; |
| 571 | + // CCM_CBCDR = cbcdr; // why does this not work at 24 MHz? |
| 572 | + CCM->CBCDR &= ~((uint32_t)(1 << 25)); |
| 573 | + while (CCM->CDHIPR & CCM_CDHIPR_PERIPH_CLK_SEL_BUSY_L) { |
| 574 | + ; // wait |
| 575 | + |
| 576 | + } |
| 577 | + F_CPU_ACTUAL = frequency; |
| 578 | + F_BUS_ACTUAL = frequency / div_ipg; |
| 579 | + // scale_cpu_cycles_to_microseconds = 0xFFFFFFFFu / (uint32_t)(frequency / 1000000u); |
| 580 | + |
| 581 | + // if voltage needs to decrease, do it after switch clock speed |
| 582 | + if ((dcdc & ((uint32_t)(0x1F << 0))) > ((uint32_t)(((voltage - 800) / 25) & 0x1F) << 0)) { |
| 583 | + dcdc &= ~((uint32_t)(0x1F << 0)); |
| 584 | + dcdc |= ((uint32_t)(0x1F << 0)); |
| 585 | + DCDC->REG3 = dcdc; |
| 586 | + while (!(DCDC->REG0 & DCDC_REG0_STS_DC_OK_L)) { |
| 587 | + ; // wait voltage settling |
| 588 | + } |
| 589 | + } |
| 590 | + |
| 591 | + return frequency; |
| 592 | +} |
0 commit comments