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,247 @@ 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
+ // 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
+ {
437
+ uint32_t cbcdr = CCM -> CBCDR ; // pg 1021
438
+ uint32_t cbcmr = CCM -> CBCMR ; // pg 1023
439
+ uint32_t dcdc = DCDC -> REG3 ;
440
+
441
+ // compute required voltage
442
+ uint32_t voltage = 1150 ; // default = 1.15V
443
+ if (frequency > 528000000 ) {
444
+ voltage = 1250 ; // 1.25V
445
+ #if defined(OVERCLOCK_STEPSIZE ) && defined(OVERCLOCK_MAX_VOLT )
446
+ if (frequency > 600000000 ) {
447
+ voltage += ((frequency - 600000000 ) / OVERCLOCK_STEPSIZE ) * 25 ;
448
+ if (voltage > OVERCLOCK_MAX_VOLT ) voltage = OVERCLOCK_MAX_VOLT ;
449
+ }
450
+ #endif
451
+ } else if (frequency <= 24000000 ) {
452
+ voltage = 950 ; // 0.95
453
+ }
454
+
455
+ // if voltage needs to increase, do it before switch clock speed
456
+ CCM -> CCGR6 |= CCM_CCGR6_DCDC (CCM_CCGR_ON );
457
+ if ((dcdc & ((uint32_t )(0x1F << 0 ))) < ((uint32_t )(((voltage - 800 ) / 25 ) & 0x1F ) << 0 )) {
458
+ //printf("Increasing voltage to %u mV\n", voltage);
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 )) ; // wait voltage settling
463
+ }
464
+
465
+ if (!(cbcdr & CCM_CBCDR_PERIPH_CLK_SEL_L )) {
466
+ //printf("need to switch to alternate clock during reconfigure of ARM PLL\n");
467
+ const uint32_t need1s = CCM_ANALOG_PLL_USB1_ENABLE_L | CCM_ANALOG_PLL_USB1_POWER_L |
468
+ CCM_ANALOG_PLL_USB1_LOCK_L | CCM_ANALOG_PLL_USB1_EN_USB_CLKS_L ;
469
+ uint32_t sel , div ;
470
+ if ((CCM_ANALOG -> PLL_USB1 & need1s ) == need1s ) {
471
+ //printf("USB PLL is running, so we can use 120 MHz\n");
472
+ sel = 0 ;
473
+ div = 3 ; // divide down to 120 MHz, so IPG is ok even if IPG_PODF=0
474
+ } else {
475
+ //printf("USB PLL is off, use 24 MHz crystal\n");
476
+ sel = 1 ;
477
+ div = 0 ;
478
+ }
479
+ if ((cbcdr & ((uint32_t )(0x07 << 27 ))) != CCM_CBCDR_PERIPH_CLK2_PODF (div )) {
480
+ // PERIPH_CLK2 divider needs to be changed
481
+ cbcdr &= ~((uint32_t )(0x07 << 27 ));
482
+ cbcdr |= CCM_CBCDR_PERIPH_CLK2_PODF (div );
483
+ CCM -> CBCDR = cbcdr ;
484
+ }
485
+ if ((cbcmr & ((uint32_t )(0x03 << 12 ))) != CCM_CBCMR_PERIPH_CLK2_SEL (sel )) {
486
+ // PERIPH_CLK2 source select needs to be changed
487
+ cbcmr &= ~((uint32_t )(0x03 << 12 ));
488
+ cbcmr |= CCM_CBCMR_PERIPH_CLK2_SEL (sel );
489
+ CCM -> CBCMR = cbcmr ;
490
+ while (CCM -> CDHIPR & ((uint32_t )(1 <<3 ))) ; // wait
491
+ }
492
+ // switch over to PERIPH_CLK2
493
+ cbcdr |= ((uint32_t )(1 <<25 ));
494
+ CCM -> CBCDR = cbcdr ;
495
+ while (CCM -> CDHIPR & ((uint32_t )(1 <<5 ))) ; // wait
496
+ } else {
497
+ //printf("already running from PERIPH_CLK2, safe to mess with ARM PLL\n");
498
+ }
499
+
500
+ // TODO: check if PLL2 running, can 352, 396 or 528 can work? (no need for ARM PLL)
501
+
502
+ // DIV_SELECT: 54-108 = official range 648 to 1296 in 12 MHz steps
503
+ uint32_t div_arm = 1 ;
504
+ uint32_t div_ahb = 1 ;
505
+ while (frequency * div_arm * div_ahb < 648000000 ) {
506
+ if (div_arm < 8 ) {
507
+ div_arm = div_arm + 1 ;
508
+ } else {
509
+ if (div_ahb < 5 ) {
510
+ div_ahb = div_ahb + 1 ;
511
+ div_arm = 1 ;
512
+ } else {
513
+ break ;
514
+ }
515
+ }
516
+ }
517
+ uint32_t mult = (frequency * div_arm * div_ahb + 6000000 ) / 12000000 ;
518
+ if (mult > 108 ) mult = 108 ;
519
+ if (mult < 54 ) mult = 54 ;
520
+ //printf("Freq: 12 MHz * %u / %u / %u\n", mult, div_arm, div_ahb);
521
+ frequency = mult * 12000000 / div_arm / div_ahb ;
522
+
523
+ //printf("ARM PLL=%x\n", CCM_ANALOG->PLL_ARM);
524
+ const uint32_t arm_pll_mask = CCM_ANALOG_PLL_ARM_LOCK_L | CCM_ANALOG_PLL_ARM_BYPASS_L |
525
+ CCM_ANALOG_PLL_ARM_ENABLE_L | CCM_ANALOG_PLL_ARM_POWERDOWN_L |
526
+ CCM_ANALOG_PLL_ARM_DIV_SELECT_MASK ;
527
+ if ((CCM_ANALOG -> PLL_ARM & arm_pll_mask ) != (CCM_ANALOG_PLL_ARM_LOCK_L
528
+ | CCM_ANALOG_PLL_ARM_ENABLE_L | CCM_ANALOG_PLL_ARM_DIV_SELECT (mult ))) {
529
+ //printf("ARM PLL needs reconfigure\n");
530
+ CCM_ANALOG -> PLL_ARM = CCM_ANALOG_PLL_ARM_POWERDOWN_L ;
531
+ // TODO: delay needed?
532
+ CCM_ANALOG -> PLL_ARM = CCM_ANALOG_PLL_ARM_ENABLE_L
533
+ | CCM_ANALOG_PLL_ARM_DIV_SELECT (mult );
534
+ while (!(CCM_ANALOG -> PLL_ARM & CCM_ANALOG_PLL_ARM_LOCK_L )) ; // wait for lock
535
+ //printf("ARM PLL=%x\n", CCM_ANALOG->PLL_ARM);
536
+ } else {
537
+ //printf("ARM PLL already running at required frequency\n");
538
+ }
539
+
540
+ if ((CCM -> CACRR & ((uint32_t )(0x07 << 0 ))) != (div_arm - 1 )) {
541
+ CCM -> CACRR = CCM_CACRR_ARM_PODF (div_arm - 1 );
542
+ while (CCM -> CDHIPR & CCM_CDHIPR_ARM_PODF_BUSY_L ) ; // wait
543
+ }
544
+
545
+ if ((cbcdr & ((uint32_t )(0x07 << 10 ))) != CCM_CBCDR_AHB_PODF (div_ahb - 1 )) {
546
+ cbcdr &= ~((uint32_t )(0x07 << 10 ));
547
+ cbcdr |= CCM_CBCDR_AHB_PODF (div_ahb - 1 );
548
+ CCM -> CBCDR = cbcdr ;
549
+ while (CCM -> CDHIPR & CCM_CDHIPR_AHB_PODF_BUSY_L ); // wait
550
+ }
551
+
552
+ uint32_t div_ipg = (frequency + 149999999 ) / 150000000 ;
553
+ if (div_ipg > 4 ) div_ipg = 4 ;
554
+ if ((cbcdr & ((uint32_t )(0x03 << 8 ))) != (CCM_CBCDR_IPG_PODF (div_ipg - 1 ))) {
555
+ cbcdr &= ~((uint32_t )(0x03 << 8 ));
556
+ cbcdr |= CCM_CBCDR_IPG_PODF (div_ipg - 1 );
557
+ // TODO: how to safely change IPG_PODF ??
558
+ CCM -> CBCDR = cbcdr ;
559
+ }
560
+
561
+ //cbcdr &= ~CCM_CBCDR_PERIPH_CLK_SEL;
562
+ //CCM_CBCDR = cbcdr; // why does this not work at 24 MHz?
563
+ CCM -> CBCDR &= ~((uint32_t )(1 <<25 ));
564
+ while (CCM -> CDHIPR & CCM_CDHIPR_PERIPH_CLK_SEL_BUSY_L ) ; // wait
565
+
566
+ F_CPU_ACTUAL = frequency ;
567
+ F_BUS_ACTUAL = frequency / div_ipg ;
568
+ //scale_cpu_cycles_to_microseconds = 0xFFFFFFFFu / (uint32_t)(frequency / 1000000u);
569
+
570
+ //printf("New Frequency: ARM=%u, IPG=%u\n", frequency, frequency / div_ipg);
571
+
572
+ // if voltage needs to decrease, do it after switch clock speed
573
+ if ((dcdc & ((uint32_t )(0x1F << 0 ))) > ((uint32_t )(((voltage - 800 ) / 25 ) & 0x1F ) << 0 )) {
574
+ //printf("Decreasing voltage to %u mV\n", voltage);
575
+ dcdc &= ~((uint32_t )(0x1F << 0 ));
576
+ dcdc |= ((uint32_t )(0x1F << 0 ));
577
+ DCDC -> REG3 = dcdc ;
578
+ while (!(DCDC -> REG0 & DCDC_REG0_STS_DC_OK_L )) ; // wait voltage settling
579
+ }
580
+
581
+ return frequency ;
582
+ }
0 commit comments