/* Revision: 3.4.0 */

/******************************************************************************
* Copyright 1998-2022 NetBurner, Inc.  ALL RIGHTS RESERVED
*
*    Permission is hereby granted to purchasers of NetBurner Hardware to use or
*    modify this computer program for any use as long as the resultant program
*    is only executed on NetBurner provided hardware.
*
*    No other rights to use this program or its derivatives in part or in
*    whole are granted.
*
*    It may be possible to license this or other NetBurner software for use on
*    non-NetBurner Hardware. Contact sales@Netburner.com for more information.
*
*    NetBurner makes no representation or warranties with respect to the
*    performance of this computer program, and specifically disclaims any
*    responsibility for any damages, special or consequential, connected with
*    the use of this program.
*
* NetBurner
* 16855 W Bernardo Dr
* San Diego, CA 92127
* www.netburner.com
******************************************************************************/

/*
PCKx are controlled via registers PMC_SCER, PMC_SCDR and PMC_SCSR.
PCKx can be enabled and/or disabled via PMC_SCER and PMC_SCDR. Three PCKx can be used.
PMC_SCSR indicates which PCKx is enabled. By default all PCKx are disabled.
PMC_PCKx registers are used to configure PCKx.
PMC_PCKx.CSS is used to select the PCKx divider source. Several clock options are available:

0 SLOW_CLK  SLCK is selected
1 MAIN_CLK  MAINCK is selected
2 PLLA_CLK  PLLACK is selected
3 UPLL_CLK  UPLLCKDIV is selected
4 MCK       MCK is selected
5 AUDIO_CLK AUDIOPLLCLK is selected

SLCK is the default clock source.

PMC_PCKx.PRES is used to control the PCKx prescaler. It is possible to choose between different
values (1 to 256). PCKx output is prescaler input divided by PRES. By default, the PRES value is cleared
which means that PCKx is equal to Slow clock.

Once PMC_PCKx has been configured, the corresponding PCKx must be enabled and the user must
wait for PMC_SR.PCKRDYx to be set. This can be done either by polling PMC_SR.PCKRDYx or by
waiting for the interrupt line to be raised if the associated interrupt source (PCKRDYx) has been enabled
in PMC_IER. All parameters in PMC_PCKx can be programmed in a single write operation.

If the PMC_PCKx.CSS and PMC_PCKx.PRES parameters are to be modified, the corresponding PCKx
must be disabled first. The parameters can then be modified. Once this has been done, the user must reenable
PCKx and wait for the PCKRDYx bit to be set.


*/



// Contains Progammable Clock (0-7) prescaler (0-255) and clock source (CSS)
//__IO uint32_t PMC_PCK[7];     /**< \brief (Pmc Offset: 0x0040) Programmable Clock 0 Register */


//Bits 8, 9, 10, 11, 12, 13, 14, 15 – PCKRDY Programmable Clock Ready Status
//Value Description
//  0 Programmable Clock x is not ready.
//  1 Programmable Clock x is ready.
//__I  uint32_t PMC_SR;         /**< \brief (Pmc Offset: 0x0068) Status Register */



//#define PMC_SCER_PCK0 (0x1u << 8) /**< \brief (PMC_SCER) Programmable Clock 0 Output Enable */
//#define PMC_SCER_PCK1 (0x1u << 9) /**< \brief (PMC_SCER) Programmable Clock 1 Output Enable */
//
//#define PMC_SCDR_PCK0 (0x1u << 8) /**< \brief (PMC_SCDR) Programmable Clock 0 Output Disable */
//#define PMC_SCDR_PCK1 (0x1u << 9) /**< \brief (PMC_SCDR) Programmable Clock 1 Output Disable */
//
//#define PMC_SCSR_PCK0 (0x1u << 8) /**< \brief (PMC_SCSR) Programmable Clock 0 Output Status */
//#define PMC_SCSR_PCK1 (0x1u << 9) /**< \brief (PMC_SCSR) Programmable Clock 1 Output Status */
//
//
//// Programmable Clock 0 Register
//#define PMC_PCK_CSS(value) ((PMC_PCK_CSS_Msk & ((value) << PMC_PCK_CSS_Pos)))
//#define   PMC_PCK_CSS_SLOW_CLK (0x0u << 0) /**< \brief (PMC_PCK[7]) Slow Clock is selected */
//#define   PMC_PCK_CSS_MAIN_CLK (0x1u << 0) /**< \brief (PMC_PCK[7]) Main Clock is selected */
//#define   PMC_PCK_CSS_PLLA_CLK (0x2u << 0) /**< \brief (PMC_PCK[7]) PLLA Clock is selected */
//#define   PMC_PCK_CSS_UPLL_CLK (0x3u << 0) /**< \brief (PMC_PCK[7]) Divided UPLL Clock is selected */
//#define   PMC_PCK_CSS_MCK (0x4u << 0) /**< \brief (PMC_PCK[7]) Master Clock is selected */
//
//#define PMC_PCK_PRES_Pos 4
//#define PMC_PCK_PRES_Msk (0xffu << PMC_PCK_PRES_Pos) /**< \brief (PMC_PCK[7]) Programmable Clock Prescaler */
//#define PMC_PCK_PRES(value) ((PMC_PCK_PRES_Msk & ((value) << PMC_PCK_PRES_Pos)))  // programmable clock 0 prescaler



#include <init.h>
#include <nbrtos.h>
#include <system.h>
#include <sim.h>

const char *AppName = "MODM7AE70 Programmable Clock";


/*
 * Display Programmable Clock (PMC) Registers
 *
 * PMC_SCER and PMC_SCDR are write only
 *
 *
 *
 *
 *
 */
void displayRegistersPMC()
{

    /*
    Bits 11:4 – PRES[7:0] Programmable Clock Prescaler
    Value Description
        0–255 Selected clock is divided by PRES+1.

    Bits 2:0 – CSS[2:0] Programmable Clock Source Selection
    Value Name Description
        0 SLOW_CLK SLCK is selected
        1 MAIN_CLK MAINCK is selected
        2 PLLA_CLK PLLACK is selected
        3 UPLL_CLK UPLLCKDIV is selected
        4 MCK MCK is selected
        5 AUDIO_CLK AUDIOPLLCLK is selected
    */
    printf("PMC PCK0: 0x%08lx\r\n", PMC->PMC_PCK[0]);   // PCK register
    printf("PMC PCK1: 0x%08lx\r\n", PMC->PMC_PCK[1]);   // PCK register
    printf("PMC SR:   0x%08lx\r\n", PMC->PMC_SR);       // PCK register

    /*
    Bits 8, 9, 10, 11, 12, 13, 14, 15 – PCK Programmable Clock x Output Status
    Value Description
        0 The corresponding Programmable Clock output is disabled.
        1 The corresponding Programmable Clock output is enabled.
    */
    printf("PMC SCSR: 0x%08lx\r\n", PMC->PMC_SCSR);     // PCK enable register

    printf("\r\n");
}


/*
 *  Main entry point for the example
 */
void UserMain(void *pd)
{
    init();        // Initialize network stack
    //Enable system diagnostics. Probably should remove for production code.
    EnableSystemDiagnostics();
    StartHttp();   // Start web server, default port 80
    WaitForActiveNetwork(TICKS_PER_SECOND * 5);

    iprintf("PMC Application: %s\r\nNNDK Revision: %s\r\n", AppName, GetReleaseTag());


    printf("\r\nPMC Resisters at reset: \r\n");
    displayRegistersPMC();
    printf("\r\n");

    printf("\r\nEnable PCK0\r\n");
    PMC->PMC_SCER |= PMC_SCER_PCK0;     // Enable PCK0 output in enable register
    PMC->PMC_SCER |= PMC_SCER_PCK1;     // Enable PCK1 output in enable register

    displayRegistersPMC();
    printf("\r\n");

    while (1)
    {
        OSTimeDly(TICKS_PER_SECOND);
    }
}
