Re: Redboot for FSL TWRK70F120M with Linux kernel booting

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]




On Wed, Mar 14, 2012 at 2:44 PM, Ilija Kocho <ilijak@xxxxxxxxxxx> wrote:
> Hi Linh
>
>
>
> On 14.03.2012 05:39, Linh Nguyễn wrote:
>> Hi all,
>>
>> Does anyone successful porting Redboot for TWRK70F120M hardware board?
>> I have edited HAL of TWRK60N512 to use as TWRK70F120M. It can run but
>> I don't now how to add SDRAM of K70 into linker file and use it.
>> Attached files are linker file that I edited to use SDRAM, I have
>> initialized PLL0 and PLL1 then DDR registers. I can access SDRAM by
>> hard address (like 0x70001000). But when I load a binary file into
>> SDRAM, it shown the warrning as bellow:
>> <code>
>> RedBoot> load -r -v -h 10.207.215.87 -m tftp -b 0x70008000 Image
>> Specified address (0x70008000) is not believed to be in RAM - continue (y/n)? y
>> </code>
>>
>> If you have any ideas about the problems, please let me know :).
>
> You need to report this memory to RedBoot. Look for
> cyg_plf_memory_segment() in twr_k60n512_misc.c (or whatever name you
> have given to this file).
I have done this before. (twr_k70f120m_misc.c attached.)

Can you take a look at the file and show me my mistake :). Or please
share me your linker config & memory segment () that you configure for
DRAM.
>
>> If anyone have ported Redboot to K70 or successful in using SDRAM
>> please share me :).
> Thank you for your offer.
> I am working on K70 port, everything essential seem to work (including
> FPU) but I have problem initializing PLL1. I have read the errata but it
> still doesn't work for me. Is there any trick?
>
> Also when trying to initialize DDR registers the chip freezes, I guess
> that it is because PLL1 is not working but maybe I need to enable
> something else than DDRAM clock.
> Can you send me the clock and DDR initialization sequence you are using?

About clock and DDRAM initialization I follow Kinetis 120MHz bare
metal sample code from Freescale site
(https://www.freescale.com/webapp/Download?colCode=KINETIS_120MHZ_SC&prodCode=K70_120&appType=license&location=null&fpsp=1&Parent_nodeId=1326817898002720905982&Parent_pageType=product&Parent_nodeId=1326817898002720905982&Parent_pageType=product).

kinetis_clocking.c attached contains my PLL0 & PLL1 initialization
sequences. My source code is hard-code for K70 only, so it can't build
for another board. You can find MK70F12.h in the package with link
above.

>
> Regards
>
> Ilija
>

Thanks & Regards,
Linh Nguyen.
//==========================================================================
//
//      twr_k70f120m_misc.c
//
//      Cortex-M4 TWR-K70F120M EVAL HAL functions
//
//==========================================================================
// ####ECOSGPLCOPYRIGHTBEGIN####                                            
// -------------------------------------------                              
// This file is part of eCos, the Embedded Configurable Operating System.   
// Copyright (C) 2011 Free Software Foundation, Inc.                        
//
// eCos is free software; you can redistribute it and/or modify it under    
// the terms of the GNU General Public License as published by the Free     
// Software Foundation; either version 2 or (at your option) any later      
// version.                                                                 
//
// eCos is distributed in the hope that it will be useful, but WITHOUT      
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or    
// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License    
// for more details.                                                        
//
// You should have received a copy of the GNU General Public License        
// along with eCos; if not, write to the Free Software Foundation, Inc.,    
// 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.            
//
// As a special exception, if other files instantiate templates or use      
// macros or inline functions from this file, or you compile this file      
// and link it with other works to produce a work based on this file,       
// this file does not by itself cause the resulting work to be covered by   
// the GNU General Public License. However the source code for this file    
// must still be made available in accordance with section (3) of the GNU   
// General Public License v2.                                               
//
// This exception does not invalidate any other reasons why a work based    
// on this file might be covered by the GNU General Public License.         
// -------------------------------------------                              
// ####ECOSGPLCOPYRIGHTEND####                                              
//==========================================================================
//#####DESCRIPTIONBEGIN####
//
// Author(s):      ilijak
// Contributor(s):
// Date:           2011-02-05
// Description:
//
//####DESCRIPTIONEND####
//
//==========================================================================

#include <pkgconf/hal.h>
#include <pkgconf/hal_cortexm.h>
#include <pkgconf/hal_cortexm_kinetis.h>
#include <pkgconf/hal_cortexm_kinetis_twr_k70f120m.h>
#ifdef CYGPKG_KERNEL
#include <pkgconf/kernel.h>
#endif

#include <cyg/infra/diag.h>
#include <cyg/infra/cyg_type.h>
#include <cyg/infra/cyg_trac.h>         // tracing macros
#include <cyg/infra/cyg_ass.h>          // assertion macros

#include <cyg/hal/hal_arch.h>           // HAL header
#include <cyg/hal/hal_intr.h>           // HAL header
#include <cyg/hal/MK70F12.h>			// BOARD header

static inline void hal_gpio_init(void);

// DATA and BSS locations
__externC cyg_uint32 __ram_data_start;
__externC cyg_uint32 __ram_data_end;
__externC cyg_uint32 __rom_data_start;
__externC cyg_uint32 __sram_data_start;
__externC cyg_uint32 __sram_data_end;
__externC cyg_uint32 __srom_data_start;
__externC cyg_uint32 __bss_start;
__externC cyg_uint32 __bss_end;


//==========================================================================
// System init
//
// This is run to set up the basic system, including GPIO setting,
// clock feeds, power supply, and memory initialization. This code
// runs before the DATA is copied from ROM and the BSS cleared, hence
// it cannot make use of static variables or data tables.

__externC void CYGOPT_HAL_KINETIS_MISC_FLASH_SECTION_ATTR
hal_system_init( void )
{
#if defined(CYG_HAL_STARTUP_ROM) || defined(CYG_HAL_STARTUP_SRAM)
    hal_wdog_disable();
    hal_gpio_init();
#endif
#if defined(CYG_HAL_STARTUP_SRAM) && !defined(CYGHWR_HAL_CORTEXM_KINETIS_SRAM_UNIFIED)
    // Note: For CYG_HAL_STARTUP_SRAM, the SRAM_L bank simulates ROM
    // Relocate data from ROM to RAM
    {
        register cyg_uint32 *ram_p, *rom_p;
        for( ram_p = &__ram_data_start, rom_p = &__rom_data_start;
             ram_p < &__ram_data_end;
             ram_p++, rom_p++ )
            *ram_p = *rom_p;
    }

    // Relocate data from ROM to SRAM
    {
        register cyg_uint32 *ram_p, *sram_p;
        for( ram_p = &__sram_data_start, sram_p = &__srom_data_start;
             ram_p < &__sram_data_end;
             ram_p++, sram_p++ )
            *ram_p = *sram_p;
    }
#endif
}

//===========================================================================
// hal_gpio_init
//===========================================================================
static inline void CYGOPT_HAL_KINETIS_MISC_FLASH_SECTION_ATTR
hal_gpio_init(void)
{
    cyghwr_hal_kinetis_sim_t *sim_p = CYGHWR_HAL_KINETIS_SIM_P;
    cyghwr_hal_kinetis_mpu_t *mpu_p = CYGHWR_HAL_KINETIS_MPU_P;

    // Enable clocks on all ports.
    sim_p->scgc1 = CYGHWR_HAL_KINETIS_SIM_SCGC1_ALL_M;
    sim_p->scgc2 = CYGHWR_HAL_KINETIS_SIM_SCGC2_ALL_M;
    sim_p->scgc3 = CYGHWR_HAL_KINETIS_SIM_SCGC3_ALL_M;
    sim_p->scgc4 = CYGHWR_HAL_KINETIS_SIM_SCGC4_ALL_M;
    sim_p->scgc5 = CYGHWR_HAL_KINETIS_SIM_SCGC5_ALL_M;
    sim_p->scgc6 = CYGHWR_HAL_KINETIS_SIM_SCGC6_ALL_M;
    sim_p->scgc7 = CYGHWR_HAL_KINETIS_SIM_SCGC7_ALL_M;

    // Disable MPU
    MPU_CESR = 0;
	
	// Set MUX for LEDs
	PORTA_PCR10 |= PORT_PCR_MUX(MUX_ALT1);
	PORTA_PCR11 |= PORT_PCR_MUX(MUX_ALT1); 
	PORTA_PCR28 |= PORT_PCR_MUX(MUX_ALT1); 
	PORTA_PCR29 |= PORT_PCR_MUX(MUX_ALT1);
	
	// Set output direction for LEDs
	PTA_BASE_PTR->PDDR |= (1 << 10) | (1 << 11) | (1 << 28) | (1 << 29);
	
	// Set initial value for LEDs
	PTA_BASE_PTR->PCOR |= (1 << 10) | (1 << 11) | (1 << 28) | (1 << 29);
}



//==========================================================================

__externC void hal_platform_init( void )
{
}

//==========================================================================

#ifdef CYGDBG_HAL_DEBUG_GDB_INCLUDE_STUBS

#include CYGHWR_MEMORY_LAYOUT_H

//--------------------------------------------------------------------------
// Accesses to areas not backed by real devices or memory can cause
// the CPU to hang.
//
// The following table defines the memory areas that GDB is allowed to
// touch. All others are disallowed.
// This table needs to be kept up to date with the set of memory areas
// that are available on the board.

static struct {
    CYG_ADDRESS         start;          // Region start address
    CYG_ADDRESS         end;            // End address (last byte)
} hal_data_access[] =
{
    { CYGMEM_REGION_ram,        CYGMEM_REGION_ram+CYGMEM_REGION_ram_SIZE-1      },      // Main RAM
#ifdef CYGMEM_REGION_sram
    { CYGMEM_REGION_sram,       CYGMEM_REGION_sram+CYGMEM_REGION_sram_SIZE-1    },      // On-chip SRAM
#endif
#ifdef CYGMEM_REGION_dram
	{ CYGMEM_REGION_dram,        CYGMEM_REGION_dram+CYGMEM_REGION_dram_SIZE-1      },      // External SDRAM
#endif
#ifdef CYGMEM_REGION_flash
    { CYGMEM_REGION_flash,      CYGMEM_REGION_flash+CYGMEM_REGION_flash_SIZE-1  },      // On-chip flash
#endif
#ifdef CYGMEM_REGION_rom
    { CYGMEM_REGION_rom,        CYGMEM_REGION_rom+CYGMEM_REGION_rom_SIZE-1      },      // External flash
#endif
    { 0xE0000000,               0x00000000-1                                    },      // Cortex-M peripherals
    { 0x40000000,               0x60000000-1                                    },      // Chip specific peripherals
};

__externC int cyg_hal_stub_permit_data_access( CYG_ADDRESS addr, cyg_uint32 count )
{
    int i;
    for( i = 0; i < sizeof(hal_data_access)/sizeof(hal_data_access[0]); i++ ) {
        if( (addr >= hal_data_access[i].start) &&
            (addr+count) <= hal_data_access[i].end)
            return true;
    }
    return false;
}

#endif // CYGDBG_HAL_DEBUG_GDB_INCLUDE_STUBS

//==========================================================================

#ifdef CYGPKG_REDBOOT
#include <redboot.h>
#include CYGHWR_MEMORY_LAYOUT_H

//--------------------------------------------------------------------------
// Memory layout
//
// We report the on-chip SRAM and external SRAM.

void
cyg_plf_memory_segment(int seg, unsigned char **start, unsigned char **end)
{
    switch (seg) {
    case 0:
        *start = (unsigned char *)CYGMEM_REGION_ram;
        *end = (unsigned char *)(CYGMEM_REGION_ram + CYGMEM_REGION_ram_SIZE);
        break;
#ifdef CYGMEM_REGION_sram
    case 1:
        *start = (unsigned char *)CYGMEM_REGION_sram;
        *end = (unsigned char *)(CYGMEM_REGION_sram + CYGMEM_REGION_sram_SIZE);
        break;
#endif
#ifdef CYGMEM_REGION_dram
#ifndef CYGMEM_REGION_sram
	case 1:
#else
	case 2:
#endif
		*start = (unsigned char *)CYGMEM_REGION_dram;
		*end = (unsigned char *)(CYGMEM_REGION_dram + CYGMEM_REGION_dram_SIZE);
		break;
#endif
    default:
        *start = *end = NO_MEMORY;
        break;
    }
} // cyg_plf_memory_segment()

#endif // CYGPKG_REDBOOT


//==========================================================================
// EOF twr_k70f120m_misc.c
//==========================================================================
//
//      kinetis_clocking.c
//
//      Cortex-M Kinetis HAL functions
//
//==========================================================================
// ####ECOSGPLCOPYRIGHTBEGIN####                                            
// -------------------------------------------                              
// This file is part of eCos, the Embedded Configurable Operating System.   
// Copyright (C) 2010 Free Software Foundation, Inc.                        
//
// eCos is free software; you can redistribute it and/or modify it under    
// the terms of the GNU General Public License as published by the Free     
// Software Foundation; either version 2 or (at your option) any later      
// version.                                                                 
//
// eCos is distributed in the hope that it will be useful, but WITHOUT      
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or    
// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License    
// for more details.                                                        
//
// You should have received a copy of the GNU General Public License        
// along with eCos; if not, write to the Free Software Foundation, Inc.,    
// 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.            
//
// As a special exception, if other files instantiate templates or use      
// macros or inline functions from this file, or you compile this file      
// and link it with other works to produce a work based on this file,       
// this file does not by itself cause the resulting work to be covered by   
// the GNU General Public License. However the source code for this file    
// must still be made available in accordance with section (3) of the GNU   
// General Public License v2.                                               
//
// This exception does not invalidate any other reasons why a work based    
// on this file might be covered by the GNU General Public License.         
// -------------------------------------------                              
// ####ECOSGPLCOPYRIGHTEND####                                              
//==========================================================================
//#####DESCRIPTIONBEGIN####
//
// Author(s):    Ilija kocho <ilijak@xxxxxxxxxxx>
// Date:         2011-10-19
// Description:
//
//####DESCRIPTIONEND####
//
//========================================================================

#include <pkgconf/hal.h>
#include <pkgconf/hal_cortexm.h>
#include <pkgconf/hal_cortexm_kinetis.h>
#ifdef CYGPKG_KERNEL
#include <pkgconf/kernel.h>
#endif

#include <cyg/infra/diag.h>
#include <cyg/infra/cyg_type.h>
#include <cyg/infra/cyg_trac.h>         // tracing macros
#include <cyg/infra/cyg_ass.h>          // assertion macros

#include <cyg/hal/cortexm_endian.h>
#include <cyg/hal/hal_arch.h>           // HAL header
#include <cyg/hal/hal_intr.h>           // HAL header
#include <cyg/hal/hal_if.h>             // HAL header

#include <cyg/io/ser_freescale_uart.h>

#include <cyg/hal/MK70F12.h>


// Constants for use in pll_init
#define NO_OSCINIT 0
#define OSCINIT 1

#define OSC_0 0
#define OSC_1 1

#define LOW_POWER 0
#define HIGH_GAIN 1

#define CANNED_OSC  0
#define CRYSTAL 1

#define PLL_0 0
#define PLL_1 1

#define PLL_ONLY 0
#define MCGOUT 1
/*
 * Input Clock Info
 */
#define CLK0_FREQ_HZ        50000000
#define CLK0_TYPE           CANNED_OSC

#define CLK1_FREQ_HZ        12000000
#define CLK1_TYPE           CRYSTAL
#define ASYNCH_MODE    /* PLL1 is source for MCGCLKOUT and DDR controller */

#define PLL0_PRDIV      5
#define PLL0_VDIV       24

#define PLL1_PRDIV      5
#define PLL1_VDIV       30

//===========================================================================
// Forward declarations
//===========================================================================

cyg_uint32 hal_cortexm_systick_clock;
cyg_uint32 hal_kinetis_sysclk;
cyg_uint32 hal_kinetis_busclk;

cyg_uint32 hal_get_cpu_clock(void);

//void hal_start_main_clock(void);
void hal_set_clock_dividers(void);
#ifdef CYGHWR_HAL_CORTEXM_KINETIS_RTC
void hal_start_rtc_clock(void);
#endif
void fb_clk_init(void);
void twr_ddr2_script_init(void);
int pll_init(unsigned char init_osc, unsigned char osc_select, int crystal_val, unsigned char hgo_val, unsigned char erefs_val, unsigned char pll_select, signed char prdiv_val, signed char vdiv_val, unsigned char mcgout_select);
//==========================================================================
// Setup up system clocks
//
// Set up clocks from configuration. In the future this should be extended so
// that clock rates can be changed at runtime.

void CYGOPT_HAL_KINETIS_MISC_FLASH_SECTION_ATTR
hal_start_clocks( void )
{
    int mcg_clk_hz, pll_1_clk_khz;
    SIM_MemMapPtr sim_p = SIM_BASE_PTR;
#ifdef CYGHWR_HAL_CORTEXM_KINETIS_TRACE_CLKOUT
    PORT_MemMapPtr port_p = PORTA_BASE_PTR;
#endif
#if !defined(CYG_HAL_STARTUP_RAM)
# ifdef CYGHWR_HAL_CORTEXM_KINETIS_RTC
    // Real Time Clock
    hal_start_rtc_clock();
# endif
    // Main clock - MCG
//    hal_start_main_clock();
    hal_set_clock_dividers();
    /* Initialize PLL0 */
    /* PLL0 will be the source for MCG CLKOUT so the core, system, FlexBus, and flash clocks are derived from it */
    mcg_clk_hz = pll_init(OSCINIT, /* Initialize the oscillator circuit */
            OSC_0, /* Use CLKIN0 as the input clock */
            CLK0_FREQ_HZ, /* CLKIN0 frequency */
            LOW_POWER, /* Set the oscillator for low power mode */
            CLK0_TYPE, /* Crystal or canned oscillator clock input */
            PLL_0, /* PLL to initialize, in this case PLL0 */
            PLL0_PRDIV, /* PLL predivider value */
            PLL0_VDIV, /* PLL multiplier */
            MCGOUT); /* Use the output from this PLL as the MCGOUT */

    /* Check the value returned from pll_init() to make sure there wasn't an error */
    if (mcg_clk_hz < 0x100)
        while (1)
            ;

    /* Initialize PLL1 */
    /* PLL1 will be the source for the DDR controller, but NOT the MCGOUT */
    pll_1_clk_khz = (pll_init(NO_OSCINIT, /* Don't init the osc circuit, already done */
            OSC_0, /* Use CLKIN0 as the input clock */
            CLK0_FREQ_HZ, /* CLKIN0 frequency */
            LOW_POWER, /* Set the oscillator for low power mode */
            CLK0_TYPE, /* Crystal or canned oscillator clock input */
            PLL_1, /* PLL to initialize, in this case PLL1 */
            PLL1_PRDIV, /* PLL predivider value */
            PLL1_VDIV, /* PLL multiplier */
            PLL_ONLY) / 1000); /* Don't use the output from this PLL as the MCGOUT */

    /* Check the value returned from pll_init() to make sure there wasn't an error */
    if ((pll_1_clk_khz * 1000) < 0x100)
        while (1)
            ;
    fb_clk_init();

    /* Initialize the DDR if the project option if defined */
    twr_ddr2_script_init();
#endif
    hal_kinetis_sysclk=hal_get_cpu_clock();
	// Write sysclk into DRAM memory
    * (cyg_uint32 *)(0x08001234) = hal_kinetis_sysclk;
	hal_kinetis_busclk=hal_kinetis_sysclk /
          CYGHWR_HAL_CORTEXM_KINETIS_CLKDIV_PER_BUS;
	//Write busclk into DRAM memory
	* (cyg_uint32 *)(0x08001238) = hal_kinetis_busclk;
    hal_cortexm_systick_clock=hal_kinetis_sysclk;
    // Trace clock
#ifdef CYGHWR_HAL_CORTEXM_KINETIS_TRACECLK_CORE
    sim_p->SOPT2 |= SIM_SOPT2_TRACECLKSEL_MASK;
#else
    sim_p->SOPT2 &= ~SIM_SOPT2_TRACECLKSEL_MASK;
#endif
#ifdef CYGHWR_HAL_CORTEXM_KINETIS_TRACE_CLKOUT
    port_p->PCR[6] = PORT_PCR_MUX(0x7);
#endif
}


#define MCG_WAIT_WHILE(_condition_) do{}while(_condition_)

// Setup MCG
// Note: Currently only PBE mode is supported and tested.

//void CYGOPT_HAL_KINETIS_MISC_FLASH_SECTION_ATTR
//hal_start_main_clock(void)
//{
//    MCG_MemMapPtr mcg_p = MCG_BASE_PTR;
//#if defined CYGOPT_HAL_CORTEXM_KINETIS_MCG_MCGOUTCLK_PLL ||\
//    defined CYGOPT_HAL_CORTEXM_KINETIS_MCG_REF_EXT_IS_RTC
//    SIM_MemMapPtr sim_p = SIM_BASE_PTR;
//#endif
//#ifdef CYGOPT_HAL_CORTEXM_KINETIS_MCG_REF_EXT
//# if defined CYGOPT_HAL_CORTEXM_KINETIS_MCG_REF_EXT_IS_XTAL || \
//    defined CYGOPT_HAL_CORTEXM_KINETIS_MCG_REF_EXT_IS_OSC
//    volatile cyg_uint8 *osc_cr_p = CYGHWR_HAL_KINETIS_OSC_CR_P;
//# endif
//
//# ifdef CYGOPT_HAL_CORTEXM_KINETIS_MCG_REF_EXT_IS_XTAL
//    // Set the main oscillator
//    *osc_cr_p = CYGHWR_HAL_CORTEXM_KINETIS_OSC_CAP / 2;
//# elif defined CYGOPT_HAL_CORTEXM_KINETIS_MCG_REF_EXT_IS_OSC
//    // Select exteranal oscillator
//    *osc_cr_p = CYGHWR_HAL_KINETIS_OSC_CR_ERCLKEN_M |
//          CYGHWR_HAL_KINETIS_OSC_CR_EREFSTEN_M;
//# endif // CYGOPT_HAL_CORTEXM_KINETIS_MCG_REF_EXT_IS_XTAL
//
//# ifdef CYGOPT_HAL_CORTEXM_KINETIS_MCG_REF_EXT_IS_RTC
//    // Select RTC clock source for MCG reference
//    sim_p->sopt2 |= CYGHWR_HAL_KINETIS_SIM_SOPT2_MCGCLKSEL_M;
//# endif // CYGOPT_HAL_CORTEXM_KINETIS_MCG_REF_EXT_IS_RTC
//#endif // CYGOPT_HAL_CORTEXM_KINETIS_MCG_REF_EXT
//
//#if defined(CYGOPT_HAL_CORTEXM_KINETIS_MCG_MCGOUTCLK_PLL) || \
//     defined(CYGOPT_HAL_CORTEXM_KINETIS_MCG_MCGOUTCLK_FLL) || \
//     defined(CYGOPT_HAL_CORTEXM_KINETIS_MCG_MCGOUTCLK_EXT_REFCLK)
//    // Enter FBE mode
//    mcg_p->C2 = MCG_C2_RANGE(
//                    CYGNUM_HAL_CORTEXM_KINETIS_MCG_REF_FREQ_RANGE)
//# ifdef CYGOPT_HAL_CORTEXM_KINETIS_MCG_REF_EXT_IS_XTAL
//          | CYGHWR_HAL_KINETIS_MCG_C2_EREFS_M | CYGHWR_HAL_KINETIS_MCG_C2_HGO_M
//# endif // CYGOPT_HAL_CORTEXM_KINETIS_MCG_REF_EXT_IS_XTAL
//          ;
//    mcg_p->C1 = MCG_C1_FRDIV(
//        CYGNUM_HAL_CORTEXM_KINETIS_MCG_REF_FRDIV_REG)
//# if defined(CYGOPT_HAL_CORTEXM_KINETIS_MCG_MCGOUTCLK_PLL) || \
//      defined(CYGOPT_HAL_CORTEXM_KINETIS_MCG_MCGOUTCLK_EXT_REFCLK)
//        |MCG_C1_CLKS(CYGHWR_HAL_KINETIS_MCG_C1_CLKS_EXT_REF)
//# endif // CYGOPT_HAL_CORTEXM_KINETIS_MCG_MCGOUTCLK_PLL
//        ;
//
//# ifdef CYGOPT_HAL_CORTEXM_KINETIS_MCG_REF_EXT_IS_XTAL
//    // Wait for oscillator start up
//    MCG_WAIT_WHILE(!(mcg_p->status & CYGHWR_HAL_KINETIS_MCG_S_OSCINIT_M));
//# endif
//# ifdef CYGOPT_HAL_CORTEXM_KINETIS_MCG_REF_EXT
//    // Wait for reference clock to switch to external reference
//    MCG_WAIT_WHILE(mcg_p->status & CYGHWR_HAL_KINETIS_MCG_S_IREFST_M);
//    // Wait for status flags update
//    MCG_WAIT_WHILE((mcg_p->status & CYGHWR_HAL_KINETIS_MCG_S_CLKST_M) !=
//#  if defined(CYGOPT_HAL_CORTEXM_KINETIS_MCG_MCGOUTCLK_PLL) || \
//defined(CYGOPT_HAL_CORTEXM_KINETIS_MCG_MCGOUTCLK_EXT_REFCLK)
//            CYGHWR_HAL_KINETIS_MCG_S_CLKST_EXT
//#  else
//            CYGHWR_HAL_KINETIS_MCG_S_CLKST_FLL
//#  endif
//            );
//# endif //  CYGOPT_HAL_CORTEXM_KINETIS_MCG_REF_EXT
//    // Set peripheral dividers before switching to high frequency.
//    hal_set_clock_dividers();
//# ifdef CYGOPT_HAL_CORTEXM_KINETIS_MCG_MCGOUTCLK_FLL
//    // Configure FLL
//    mcg_p->c4 = (mcg_p->c4 & 0x1f) |
//          (CYGNUM_HAL_CORTEXM_MCG_DCO_DMX32 |
//           CYGHWR_HAL_KINETIS_MCG_C4_DRST_DRS(
//               CYGNUM_HAL_CORTEXM_MCG_DCO_DRST_DRS));
//
//# endif // CYGOPT_HAL_CORTEXM_KINETIS_MCG_MCGOUTCLK_FLL
//# ifdef CYGOPT_HAL_CORTEXM_KINETIS_MCG_MCGOUTCLK_PLL
//    // Configure PLL and enter PBE mode
//    mcg_p->C5 = MCG_C5_PRDIV(
//          CYGOPT_HAL_CORTEXM_KINETIS_MCGOUT_PLL_PRDIV-1) |
//          CYGHWR_HAL_KINETIS_MCG_C5_PLLSTEN_M;
//    mcg_p->C6 = MCG_C6_VDIV(
//          CYGOPT_HAL_CORTEXM_KINETIS_MCGOUT_PLL_VDIV-16);
//
//    // Switch to PBE mode
//    mcg_p->C6 |=  MCG_C6_PLLS_MASK;
//
//    MCG_WAIT_WHILE((mcg_p->S & MCG_S_CLKST_MASK) !=
//            MCG_S_CLKST(2));
//    MCG_WAIT_WHILE(!(mcg_p->S & MCG_S_PLLST_MASK));
//    MCG_WAIT_WHILE(!(mcg_p->S & MCG_S_LOCK_MASK));
//
//    // Enter PEE mode
//    mcg_p->C1 &= ~MCG_C1_CLKS_MASK;
//    MCG_WAIT_WHILE((mcg_p->S & MCG_S_CLKST_MASK) !=
//            MCG_S_CLKST(3));
//# endif // CYGOPT_HAL_CORTEXM_KINETIS_MCG_MCGOUTCLK_PLL
//# if defined(CYGOPT_HAL_CORTEXM_KINETIS_MCG_MCGOUTCLK_PLL) || \
//     defined(CYGOPT_HAL_CORTEXM_KINETIS_MCG_MCGOUTCLK_EXT_REFCLK)
//    sim_p->SOPT2 |= SIM_SOPT2_PLLFLLSEL_MASK;
//# endif
//
//#endif // defined(CYGOPT_HAL_CORTEXM_KINETIS_MCG_MCGOUTCLK_PLL) ||
//       // defined(CYGOPT_HAL_CORTEXM_KINETIS_MCG_MCGOUTCLK_FLL) ||
//       // defined(CYGOPT_HAL_CORTEXM_KINETIS_MCG_MCGOUTCLK_EXT_REFCLK)
//}

cyg_uint32 CYGOPT_HAL_KINETIS_MISC_FLASH_SECTION_ATTR
hal_get_cpu_clock(void)
{
    cyg_uint32 freq;
#ifdef CYGOPT_HAL_CORTEXM_KINETIS_MCG_MCGOUTCLK_PLL
    MCG_MemMapPtr mcg_p = MCG_BASE_PTR;

    freq = CYGNUM_HAL_CORTEXM_KINETIS_MCG_FLL_PLL_REF_FREQ /
          ((mcg_p->C5 & MCG_C5_PRDIV_MASK)+1) *
          ((mcg_p->C6 & MCG_C6_VDIV_MASK)+16) / 2;
#elif defined(CYGOPT_HAL_CORTEXM_KINETIS_MCG_MCGOUTCLK_FLL)
    freq = CYGNUM_HAL_CORTEXM_KINETIS_MCG_FLL_FREQ_AV;
#elif defined(CYGOPT_HAL_CORTEXM_KINETIS_MCG_MCGOUTCLK_EXT_REFCLK)
    freq = CYGOPT_HAL_CORTEXM_KINETIS_MCGOUT_EXT_RC;
#else // ifdef CYGOPT_HAL_CORTEXM_KINETIS_MCG_MCGOUTCLK_none
#endif // CYGOPT_HAL_CORTEXM_KINETIS_MCG_MCGOUTCLK_end

    return freq;
}

void CYGOPT_HAL_KINETIS_MISC_FLASH_SECTION_ATTR
hal_set_clock_dividers(void)
{
    SIM_MemMapPtr sim_p = SIM_BASE_PTR;

    sim_p->CLKDIV1 = SIM_CLKDIV1_OUTDIV1(0) |
            SIM_CLKDIV1_OUTDIV2(
                CYGHWR_HAL_CORTEXM_KINETIS_CLKDIV_PER_BUS-1)  |
                SIM_CLKDIV1_OUTDIV3(
                CYGHWR_HAL_CORTEXM_KINETIS_CLKDIV_FLEX_BUS-1) |
                SIM_CLKDIV1_OUTDIV4(
                CYGHWR_HAL_CORTEXM_KINETIS_CLKDIV_FLASH-1);

    sim_p->CLKDIV2 = SIM_CLKDIV2_USBFSDIV(
                          CYGHWR_HAL_CORTEXM_KINETIS_USBCLK_DIV-1) |
                          (CYGHWR_HAL_CORTEXM_KINETIS_USBCLK_FRAC==2 ?
                                  SIM_CLKDIV2_USBHSFRAC_MASK : 0);
}

#ifdef CYGHWR_HAL_CORTEXM_KINETIS_RTC
void CYGOPT_HAL_KINETIS_MISC_FLASH_SECTION_ATTR
hal_start_rtc_clock(void)
{
    RTC_MemMapPtr rtc_p = RTC_BASE_PTR;

    rtc_p->IER=0; // Disable RTC interrupts

    //Start RTC clock if not already started
    if(!(rtc_p->CR & 1 << RTC_CR_OSCE_SHIFT)){
        rtc_p->CR = 1 << RTC_CR_OSCE_SHIFT |
              CYGHWR_HAL_CORTEXM_KINETIS_RTC_OSC_CAP;
# ifdef CYGOPT_HAL_CORTEXM_KINETIS_MCG_REF_EXT_IS_RTC
        {
            volatile cyg_uint32 busycnt;
            for(busycnt=1000000; busycnt; busycnt--)
                __asm__ volatile ("nop\n");
        }
# endif // CYGOPT_HAL_CORTEXM_KINETIS_MCG_REF_EXT_IS_RTC
    }
}
#endif


//==========================================================================
// UART baud rate
//
// Set the baud rate divider of a UART based on the requested rate and
// the current clock settings.


void  CYGOPT_HAL_KINETIS_MISC_FLASH_SECTION_ATTR
hal_freescale_uart_setbaud(cyg_uint32 uart_p, cyg_uint32 baud)
{
    cyg_uint32 sbr, brfa;
    cyg_uint32 regval;

    switch(uart_p) {
    case CYGADDR_IO_SERIAL_FREESCALE_UART0_BASE:
    case CYGADDR_IO_SERIAL_FREESCALE_UART1_BASE:
        sbr = hal_kinetis_sysclk/(16*baud);
        break;
    case CYGADDR_IO_SERIAL_FREESCALE_UART2_BASE:
    case CYGADDR_IO_SERIAL_FREESCALE_UART3_BASE:
    case CYGADDR_IO_SERIAL_FREESCALE_UART4_BASE:
    case CYGADDR_IO_SERIAL_FREESCALE_UART5_BASE:
        sbr = hal_kinetis_busclk/(16*baud);
        break;
    default:
        sbr=0;
        break;
    }
    if(sbr) {
        HAL_READ_UINT8(uart_p + CYGHWR_DEV_FREESCALE_UART_BDH, regval);
        regval &= 0xE0;
        regval |= sbr >> 8;
        HAL_WRITE_UINT8(uart_p + CYGHWR_DEV_FREESCALE_UART_BDH, regval);
        HAL_WRITE_UINT8(uart_p + CYGHWR_DEV_FREESCALE_UART_BDL, (sbr & 0xFF));
        brfa = (((32*hal_kinetis_busclk)/(16*baud))-(32*sbr));
        HAL_READ_UINT8(uart_p + CYGHWR_DEV_FREESCALE_UART_C4, regval);
        regval &= 0xE0;
        regval |= brfa & 0x1f;
        HAL_WRITE_UINT8(uart_p + CYGHWR_DEV_FREESCALE_UART_C4, regval);
    }
}

/*********************************************************************************************/
/* Functon name : pll_init
 *
 * Mode transition: Option to move from FEI to PEE mode or to just initialize the PLL
 *
 * This function initializess either PLL0 or PLL1. Either OSC0 or OSC1 can be selected for the
 * reference clock source. The oscillators can be configured to use a crystal or take in an
 * external square wave clock.
 * NOTE : This driver does not presently (as of Sept 9 2011) support the use of OSC1 as the
 * reference clock for the MCGOUT clock used for the system clocks.
 * The PLL outputs a PLLCLK and PLLCLK2X. PLLCLK2X is the actual PLL frequency and PLLCLK is
 * half this frequency. PLLCLK is used for MCGOUT and is also typically used by the
 * peripherals that can select the PLL as a clock source. So the PLL frequency generated will
 * be twice the desired frequency.
 * Using the function parameter names the PLL frequency is calculated as follows:
 * PLL freq = ((crystal_val / prdiv_val) * vdiv_val)
 * Refer to the readme file in the mcg driver directory for examples of pll_init configurations.
 * All parameters must be provided, for example crystal_val must be provided even if the
 * oscillator associated with that parameter is already initialized.
 * The various passed parameters are checked to ensure they are within the allowed range. If any
 * of these checks fail the driver will exit and return a fail/error code. An error code will
 * also be returned if any error occurs during the PLL initialization sequence. Refer to the
 * readme file in the mcg driver directory for a list of all these codes.
 *
 * Parameters: init_osc    - 0 if oscillator does not need to be initialized, non-zero if the
 *                           oscillator needs to be configured.
 *             osc_select  - 0 to select OSC0, non-zero to select OSC1.
 *             crystal_val - external clock frequency in Hz either from a crystal or square
 *                           wave clock source
 *             hgo_val     - selects whether low power or high gain mode is selected
 *                           for the crystal oscillator. This has no meaning if an
 *                           external clock is used.
 *             erefs_val   - selects external clock (=0) or crystal osc (=1)
 *             pll_select  - 0 to select PLL0, non-zero to select PLL1.
 *             prdiv_val   - value to divide the external clock source by to create the desired
 *                           PLL reference clock frequency
 *             vdiv_val    - value to multiply the PLL reference clock frequency by
 *             mcgout_select  - 0 if the PLL is just to be enabled, non-zero if the PLL is used
 *                              to provide the MCGOUT clock for the system.
 *
 * Return value : PLL frequency (Hz) divided by 2 or error code
 */

int pll_init(unsigned char init_osc, unsigned char osc_select, int crystal_val, unsigned char hgo_val, unsigned char erefs_val, unsigned char pll_select, signed char prdiv_val, signed char vdiv_val, unsigned char mcgout_select)
{
  unsigned char frdiv_val;
  unsigned char temp_reg;
  unsigned char prdiv, vdiv;
  short i;
  int ref_freq;
  int pll_freq;

  // If using the PLL as MCG_OUT must check if the MCG is in FEI mode first
  if (mcgout_select)
  {
    // check if in FEI mode
    if (!((((MCG_S & MCG_S_CLKST_MASK) >> MCG_S_CLKST_SHIFT) == 0x0) && // check CLKS mux has selcted FLL output
        (MCG_S & MCG_S_IREFST_MASK) &&                                  // check FLL ref is internal ref clk
        (!(MCG_S & MCG_S_PLLST_MASK))))                                 // check PLLS mux has selected FLL
    {
      return 0x1;                                                     // return error code
    }
  } // if (mcgout_select)

  // Check if OSC1 is being used as a reference for the MCGOUT PLL
  // This requires a more complicated MCG configuration.
  // At this time (Sept 8th 2011) this driver does not support this option
  if (osc_select && mcgout_select)
  {
    return 0x80; // Driver does not support using OSC1 as the PLL reference for the system clock on MCGOUT
  }

  // check external frequency is less than the maximum frequency
  if  (crystal_val > 60000000) {return 0x21;}

  // check crystal frequency is within spec. if crystal osc is being used as PLL ref
  if (erefs_val)
  {
    if ((crystal_val < 8000000) || (crystal_val > 32000000)) {return 0x22;} // return 1 if one of the available crystal options is not available
  }

  // make sure HGO will never be greater than 1. Could return an error instead if desired.
  if (hgo_val > 0)
  {
    hgo_val = 1; // force hgo_val to 1 if > 0
  }

  // Check PLL divider settings are within spec.
  if ((prdiv_val < 1) || (prdiv_val > 8)) {return 0x41;}
  if ((vdiv_val < 16) || (vdiv_val > 47)) {return 0x42;}

  // Check PLL reference clock frequency is within spec.
  ref_freq = crystal_val / prdiv_val;
  if ((ref_freq < 8000000) || (ref_freq > 32000000)) {return 0x43;}

  // Check PLL output frequency is within spec.
  pll_freq = (crystal_val / prdiv_val) * vdiv_val;
  if ((pll_freq < 180000000) || (pll_freq > 360000000)) {return 0x45;}

  // Determine if oscillator needs to be set up
  if (init_osc)
  {
    // Check if the oscillator needs to be configured
    if (!osc_select)
    {
      // configure the MCG_C2 register
      // the RANGE value is determined by the external frequency. Since the RANGE parameter affects the FRDIV divide value
      // it still needs to be set correctly even if the oscillator is not being used

      temp_reg = MCG_C2;
      temp_reg &= ~(MCG_C2_RANGE_MASK | MCG_C2_HGO_MASK | MCG_C2_EREFS_MASK); // clear fields before writing new values

      if (crystal_val <= 8000000)
      {
        temp_reg |= (MCG_C2_RANGE(1) | (hgo_val << MCG_C2_HGO_SHIFT) | (erefs_val << MCG_C2_EREFS_SHIFT));
      }
      else
      {
        // On rev. 1.0 of silicon there is an issue where the the input bufferd are enabled when JTAG is connected.
        // This has the affect of sometimes preventing the oscillator from running. To keep the oscillator amplitude
        // low, RANGE = 2 should not be used. This should be removed when fixed silicon is available.
        //temp_reg |= (MCG_C2_RANGE(2) | (hgo_val << MCG_C2_HGO_SHIFT) | (erefs_val << MCG_C2_EREFS_SHIFT));
        temp_reg |= (MCG_C2_RANGE(1) | (hgo_val << MCG_C2_HGO_SHIFT) | (erefs_val << MCG_C2_EREFS_SHIFT));
      }
      MCG_C2 = temp_reg;
    }
    else
    {
      // configure the MCG_C10 register
      // the RANGE value is determined by the external frequency. Since the RANGE parameter affects the FRDIV divide value
      // it still needs to be set correctly even if the oscillator is not being used
      temp_reg = MCG_C10;
      temp_reg &= ~(MCG_C10_RANGE2_MASK | MCG_C10_HGO2_MASK | MCG_C10_EREFS2_MASK); // clear fields before writing new values
      if (crystal_val <= 8000000)
      {
        temp_reg |= MCG_C10_RANGE2(1) | (hgo_val << MCG_C10_HGO2_SHIFT) | (erefs_val << MCG_C10_EREFS2_SHIFT);
      }
      else
      {
        // On rev. 1.0 of silicon there is an issue where the the input bufferd are enabled when JTAG is connected.
        // This has the affect of sometimes preventing the oscillator from running. To keep the oscillator amplitude
        // low, RANGE = 2 should not be used. This should be removed when fixed silicon is available.
        //temp_reg |= MCG_C10_RANGE2(2) | (hgo_val << MCG_C10_HGO2_SHIFT) | (erefs_val << MCG_C10_EREFS2_SHIFT);
        temp_reg |= MCG_C10_RANGE2(1) | (hgo_val << MCG_C10_HGO2_SHIFT) | (erefs_val << MCG_C10_EREFS2_SHIFT);
      }
      MCG_C10 = temp_reg;
    } // if (!osc_select)
  } // if (init_osc)

  if (mcgout_select)
  {
    // determine FRDIV based on reference clock frequency
    // since the external frequency has already been checked only the maximum frequency for each FRDIV value needs to be compared here.
    if (crystal_val <= 1250000) {frdiv_val = 0;}
    else if (crystal_val <= 2500000) {frdiv_val = 1;}
    else if (crystal_val <= 5000000) {frdiv_val = 2;}
    else if (crystal_val <= 10000000) {frdiv_val = 3;}
    else if (crystal_val <= 20000000) {frdiv_val = 4;}
    else {frdiv_val = 5;}

    // Select external oscillator and Reference Divider and clear IREFS to start ext osc
    // If IRCLK is required it must be enabled outside of this driver, existing state will be maintained
    // CLKS=2, FRDIV=frdiv_val, IREFS=0, IRCLKEN=0, IREFSTEN=0
    temp_reg = MCG_C1;
    temp_reg &= ~(MCG_C1_CLKS_MASK | MCG_C1_FRDIV_MASK | MCG_C1_IREFS_MASK); // Clear values in these fields
    temp_reg = MCG_C1_CLKS(2) | MCG_C1_FRDIV(frdiv_val); // Set the required CLKS and FRDIV values
    MCG_C1 = temp_reg;

    // if the external oscillator is used need to wait for OSCINIT to set
    if (erefs_val)
    {
      for (i = 0 ; i < 10000 ; i++)
      {
        if (MCG_S & MCG_S_OSCINIT_MASK) break; // jump out early if OSCINIT sets before loop finishes
      }
      if (!(MCG_S & MCG_S_OSCINIT_MASK)) return 0x23; // check bit is really set and return with error if not set
    }

    // wait for Reference clock Status bit to clear
    for (i = 0 ; i < 2000 ; i++)
    {
      if (!(MCG_S & MCG_S_IREFST_MASK)) break; // jump out early if IREFST clears before loop finishes
    }
    if (MCG_S & MCG_S_IREFST_MASK) return 0x11; // check bit is really clear and return with error if not set

    // Wait for clock status bits to show clock source is ext ref clk
    for (i = 0 ; i < 2000 ; i++)
    {
      if (((MCG_S & MCG_S_CLKST_MASK) >> MCG_S_CLKST_SHIFT) == 0x2) break; // jump out early if CLKST shows EXT CLK slected before loop finishes
    }
    if (((MCG_S & MCG_S_CLKST_MASK) >> MCG_S_CLKST_SHIFT) != 0x2) return 0x1A; // check EXT CLK is really selected and return with error if not

    // Now in FBE
    // It is recommended that the clock monitor is enabled when using an external clock as the clock source/reference.
    // It is enabled here but can be removed if this is not required.
    MCG_C6 |= MCG_C6_CME_MASK;

    // Select which PLL to enable
    if (!pll_select)
    {
      // Configure PLL0
      // Ensure OSC0 is selected as the reference clock
      MCG_C5 &= ~MCG_C5_PLLREFSEL_MASK;
      //Select PLL0 as the source of the PLLS mux
      MCG_C11 &= ~MCG_C11_PLLCS_MASK;
      // Configure MCG_C5
      // If the PLL is to run in STOP mode then the PLLSTEN bit needs to be OR'ed in here or in user code.
      temp_reg = MCG_C5;
      temp_reg &= ~MCG_C5_PRDIV_MASK;
      temp_reg |= MCG_C5_PRDIV(prdiv_val - 1);    //set PLL ref divider
      MCG_C5 = temp_reg;

      // Configure MCG_C6
      // The PLLS bit is set to enable the PLL, MCGOUT still sourced from ext ref clk
      // The loss of lock interrupt can be enabled by seperately OR'ing in the LOLIE bit in MCG_C6
      temp_reg = MCG_C6; // store present C6 value
      temp_reg &= ~MCG_C6_VDIV_MASK; // clear VDIV settings
      temp_reg |= MCG_C6_PLLS_MASK | MCG_C6_VDIV(vdiv_val - 16); // write new VDIV and enable PLL
      MCG_C6 = temp_reg; // update MCG_C6

      // wait for PLLST status bit to set
      for (i = 0 ; i < 2000 ; i++)
      {
        if (MCG_S & MCG_S_PLLST_MASK) break; // jump out early if PLLST sets before loop finishes
      }
      if (!(MCG_S & MCG_S_PLLST_MASK)) return 0x16; // check bit is really set and return with error if not set

      // Wait for LOCK bit to set
      for (i = 0 ; i < 2000 ; i++)
      {
        if (MCG_S & MCG_S_LOCK_MASK) break; // jump out early if LOCK sets before loop finishes
      }
      if (!(MCG_S & MCG_S_LOCK_MASK)) return 0x44; // check bit is really set and return with error if not set

      // Use actual PLL settings to calculate PLL frequency
      prdiv = ((MCG_C5 & MCG_C5_PRDIV_MASK) + 1);
      vdiv = ((MCG_C6 & MCG_C6_VDIV_MASK) + 16);
    }
    else
    {
      // Configure PLL1
      // Ensure OSC0 is selected as the reference clock
      MCG_C11 &= ~MCG_C11_PLLREFSEL2_MASK;
      //Select PLL1 as the source of the PLLS mux
      MCG_C11 |= MCG_C11_PLLCS_MASK;
      // Configure MCG_C11
      // If the PLL is to run in STOP mode then the PLLSTEN2 bit needs to be OR'ed in here or in user code.
      temp_reg = MCG_C11;
      temp_reg &= ~MCG_C11_PRDIV2_MASK;
      temp_reg |= MCG_C11_PRDIV2(prdiv_val - 1);    //set PLL ref divider
      MCG_C11 = temp_reg;

      // Configure MCG_C12
      // The PLLS bit is set to enable the PLL, MCGOUT still sourced from ext ref clk
      // The loss of lock interrupt can be enabled by seperately OR'ing in the LOLIE2 bit in MCG_C12
      temp_reg = MCG_C12; // store present C12 value
      temp_reg &= ~MCG_C12_VDIV2_MASK; // clear VDIV settings
      temp_reg |=  MCG_C12_VDIV2(vdiv_val - 16); // write new VDIV and enable PLL
      MCG_C12 = temp_reg; // update MCG_C12
      // Enable PLL by setting PLLS bit
      MCG_C6 |= MCG_C6_PLLS_MASK;

      // wait for PLLCST status bit to set
      for (i = 0 ; i < 2000 ; i++)
      {
        if (MCG_S2 & MCG_S2_PLLCST_MASK) break; // jump out early if PLLST sets before loop finishes
      }
      if (!(MCG_S2 & MCG_S2_PLLCST_MASK)) return 0x17; // check bit is really set and return with error if not set

      // wait for PLLST status bit to set
      for (i = 0 ; i < 2000 ; i++)
      {
        if (MCG_S & MCG_S_PLLST_MASK) break; // jump out early if PLLST sets before loop finishes
      }
      if (!(MCG_S & MCG_S_PLLST_MASK)) return 0x16; // check bit is really set and return with error if not set

      // Wait for LOCK bit to set
      for (i = 0 ; i < 2000 ; i++)
      {
        if (MCG_S2 & MCG_S2_LOCK2_MASK) break; // jump out early if LOCK sets before loop finishes
      }
      if (!(MCG_S2 & MCG_S2_LOCK2_MASK)) return 0x44; // check bit is really set and return with error if not set

      // Use actual PLL settings to calculate PLL frequency
      prdiv = ((MCG_C11 & MCG_C11_PRDIV2_MASK) + 1);
      vdiv = ((MCG_C12 & MCG_C12_VDIV2_MASK) + 16);
    } // if (!pll_select)

    // now in PBE

    MCG_C1 &= ~MCG_C1_CLKS_MASK; // clear CLKS to switch CLKS mux to select PLL as MCG_OUT

    // Wait for clock status bits to update
    for (i = 0 ; i < 2000 ; i++)
    {
      if (((MCG_S & MCG_S_CLKST_MASK) >> MCG_S_CLKST_SHIFT) == 0x3) break; // jump out early if CLKST = 3 before loop finishes
    }
    if (((MCG_S & MCG_S_CLKST_MASK) >> MCG_S_CLKST_SHIFT) != 0x3) return 0x1B; // check CLKST is set correctly and return with error if not

    // Now in PEE
  }
  else
  {
    // Setup PLL for peripheral only use
    if (pll_select)
    {
      // Setup and enable PLL1
      // Select ref source
      if (osc_select)
      {
        MCG_C11 |= MCG_C11_PLLREFSEL2_MASK; // Set select bit to choose OSC1
      }
      else
      {
        MCG_C11 &= ~MCG_C11_PLLREFSEL2_MASK; // Clear select bit to choose OSC0
      }
      // Configure MCG_C11
      // If the PLL is to run in STOP mode then the PLLSTEN2 bit needs to be OR'ed in here or in user code.
      temp_reg = MCG_C11;
      temp_reg &= ~MCG_C11_PRDIV2_MASK;
      temp_reg |= MCG_C11_PRDIV2(prdiv_val - 1);    //set PLL ref divider
      MCG_C11 = temp_reg;

      // Configure MCG_C12
      // The loss of lock interrupt can be enabled by seperately OR'ing in the LOLIE2 bit in MCG_C12
      temp_reg = MCG_C12; // store present C12 value
      temp_reg &= ~MCG_C12_VDIV2_MASK; // clear VDIV settings
      temp_reg |=  MCG_C12_VDIV2(vdiv_val - 16); // write new VDIV and enable PLL
      MCG_C12 = temp_reg; // update MCG_C12
      // Now enable the PLL
      MCG_C11 |= MCG_C11_PLLCLKEN2_MASK; // Set PLLCLKEN2 to enable PLL1

      // Wait for LOCK bit to set
      for (i = 0 ; i < 2000 ; i++)
      {
        if (MCG_S2 & MCG_S2_LOCK2_MASK) break; // jump out early if LOCK sets before loop finishes
      }
      if (!(MCG_S2 & MCG_S2_LOCK2_MASK)) return 0x44; // check bit is really set and return with error if not set

      // Use actual PLL settings to calculate PLL frequency
      prdiv = ((MCG_C11 & MCG_C11_PRDIV2_MASK) + 1);
      vdiv = ((MCG_C12 & MCG_C12_VDIV2_MASK) + 16);
    }
    else
    {
      // Setup and enable PLL0
      // Select ref source
      if (osc_select)
      {
        MCG_C5 |= MCG_C5_PLLREFSEL_MASK; // Set select bit to choose OSC1
      }
      else
      {
        MCG_C5 &= ~MCG_C5_PLLREFSEL_MASK; // Clear select bit to choose OSC0
      }
      // Configure MCG_C5
      // If the PLL is to run in STOP mode then the PLLSTEN bit needs to be OR'ed in here or in user code.
      temp_reg = MCG_C5;
      temp_reg &= ~MCG_C5_PRDIV_MASK;
      temp_reg |= MCG_C5_PRDIV(prdiv_val - 1);    //set PLL ref divider
      MCG_C5 = temp_reg;

      // Configure MCG_C6
      // The loss of lock interrupt can be enabled by seperately OR'ing in the LOLIE bit in MCG_C6
      temp_reg = MCG_C6; // store present C6 value
      temp_reg &= ~MCG_C6_VDIV_MASK; // clear VDIV settings
      temp_reg |=  MCG_C6_VDIV(vdiv_val - 16); // write new VDIV and enable PLL
      MCG_C6 = temp_reg; // update MCG_C6
      // Now enable the PLL
      MCG_C5 |= MCG_C5_PLLCLKEN_MASK; // Set PLLCLKEN to enable PLL0

      // Wait for LOCK bit to set
      for (i = 0 ; i < 2000 ; i++)
      {
        if (MCG_S & MCG_S_LOCK_MASK) break; // jump out early if LOCK sets before loop finishes
      }
      if (!(MCG_S & MCG_S_LOCK_MASK)) return 0x44; // check bit is really set and return with error if not set

      // Use actual PLL settings to calculate PLL frequency
      prdiv = ((MCG_C5 & MCG_C5_PRDIV_MASK) + 1);
      vdiv = ((MCG_C6 & MCG_C6_VDIV_MASK) + 16);
    } // if (pll_select)

  } // if (mcgout_select)

  return (((crystal_val / prdiv) * vdiv) / 2); //MCGOUT equals PLL output frequency/2
} // pll_init

/********************************************************************/
void fb_clk_init(void)
{
    /* Enable the clock to the FlexBus module */
        SIM_SCGC7 |= SIM_SCGC7_FLEXBUS_MASK;

    /* Enable the FB_CLKOUT function on PTC3 (alt5 function) */
    PORTC_PCR3 = ( PORT_PCR_MUX(0x5));
}

void twr_ddr2_script_init(void)
{
    /* Enable DDR controller clock */
    SIM_SCGC3 |= SIM_SCGC3_DDR_MASK;

    /* Enable DDR pads and set slew rate */
    SIM_MCR |= 0xC4;   // bits were left out of the manual so there isn't a macro right now

    DDR_RCR |= DDR_RCR_RST_MASK;

    * (cyg_uint32 *)(0x400Ae1ac) = 0x01030203;

    DDR_CR00 = 0x00000400;
    DDR_CR02 = 0x02000031;
    DDR_CR03 = 0x02020506;
    DDR_CR04 = 0x06090202;
    DDR_CR05 = 0x02020302;
    DDR_CR06 = 0x02904002;
    DDR_CR07 = 0x01000303;
    DDR_CR08 = 0x05030201;
    DDR_CR09 = 0x020000c8;
    DDR_CR10 = 0x03003207;
    DDR_CR11 = 0x01000000;
    DDR_CR12 = 0x04920031;
    DDR_CR13 = 0x00000005;
    DDR_CR14 = 0x00C80002;
    DDR_CR15 = 0x00000032;
    DDR_CR16 = 0x00000001;
    DDR_CR20 = 0x00030300;
    DDR_CR21 = 0x00040232;
    DDR_CR22 = 0x00000000;
    DDR_CR23 = 0x00040302;
    DDR_CR25 = 0x0A010201;
    DDR_CR26 = 0x0101FFFF;
    DDR_CR27 = 0x01010101;
    DDR_CR28 = 0x00000003;
    DDR_CR29 = 0x00000000;
    DDR_CR30 = 0x00000001;
    DDR_CR34 = 0x02020101;
    DDR_CR36 = 0x01010201;
    DDR_CR37 = 0x00000200;
    DDR_CR38 = 0x00200000;
    DDR_CR39 = 0x01010020;
    DDR_CR40 = 0x00002000;
    DDR_CR41 = 0x01010020;
    DDR_CR42 = 0x00002000;
    DDR_CR43 = 0x01010020;
    DDR_CR44 = 0x00000000;
    DDR_CR45 = 0x03030303;
    DDR_CR46 = 0x02006401;
    DDR_CR47 = 0x01020202;
    DDR_CR48 = 0x01010064;
    DDR_CR49 = 0x00020101;
    DDR_CR50 = 0x00000064;
    DDR_CR52 = 0x02000602;
    DDR_CR53 = 0x03c80000;
    DDR_CR54 = 0x03c803c8;
    DDR_CR55 = 0x03c803c8;
    DDR_CR56 = 0x020303c8;
    DDR_CR57 = 0x01010002;

    __asm__ volatile ("nop\n");

    DDR_CR00 |= 0x00000001;

    while ((DDR_CR30 & 0x400) != 0x400);

    MCM_CR |= MCM_CR_DDRSIZE(1);
}
//==========================================================================
// EOF kinetis_clocking.c
-- 
Before posting, please read the FAQ: http://ecos.sourceware.org/fom/ecos
and search the list archive: http://ecos.sourceware.org/ml/ecos-discuss

[Linux Embedded]     [U-Boot V2]     [Linux Kernel]     [Linux MIPS]     [Linux ARM]     [Linux for the Blind]     [Linux Resources]     [Photo]     [Yosemite]     [ISDN Cause Codes]     [ECOS Home]

Add to Google Powered by Linux