Exemple #1
0
/*
 * System clock settings
 */
static __inline__ void clock_setup(void)
{
#if (HAS_HYB_XTAL)
	/* Apply factory settings for Crystal Oscillator stabilization
	 * These settings adjust the trimming value and the counter value
	 * for the Crystal Oscillator */
	QM_SCSS_CCU->osc0_cfg1 &= ~OSC0_CFG1_OSC0_FADJ_XTAL_MASK;
	QM_SCSS_CCU->osc0_cfg1 |=
	    (OSC0_CFG1_OSC0_FADJ_XTAL_DEFAULT << OSC0_CFG1_OSC0_FADJ_XTAL_OFFS);
	QM_SCSS_CCU->osc0_cfg0 &= ~OSC0_CFG0_OSC0_XTAL_COUNT_VALUE_MASK;
	QM_SCSS_CCU->osc0_cfg0 |= (OSC0_CFG0_OSC0_XTAL_COUNT_VALUE_DEFAULT
				   << OSC0_CFG0_OSC0_XTAL_COUNT_VALUE_OFFS);
#endif /* HAS_HYB_XTAL */

	/*
	 * Switch to each silicon oscillator to set up trim data
	 * This sets up the trim codes for the first boot.
	 * This consists of computing the trim code if not available
	 * in non volatile memory and write this results in flash.
	 *
	 * This step is only performed if the shadow region
	 * is not populated.
	 * We rely on the 32MHz trim code to be shadowed to
	 * consider the region populated.
	 *
	 * This can be modified if this policy does not match your
	 * specific requirements.
	 */
	if ((QM_FLASH_DATA_TRIM_CODE->osc_trim_32mhz &
	     QM_FLASH_TRIM_PRESENT_MASK) != QM_FLASH_TRIM_PRESENT) {
		boot_clk_trim_code_setup();
	}

	/* Switch to 32MHz silicon oscillator */
	boot_clk_hyb_set_mode(CLK_SYS_HYB_OSC_32MHZ, CLK_SYS_DIV_1);
	clk_trim_apply(QM_FLASH_DATA_TRIM_CODE->osc_trim_32mhz);
}
Exemple #2
0
int clk_sys_set_mode(const clk_sys_mode_t mode, const clk_sys_div_t div)
{
	QM_CHECK(div <= CLK_SYS_DIV_NUM, -EINVAL);
	QM_CHECK(mode <= CLK_SYS_CRYSTAL_OSC, -EINVAL);
	uint16_t trim = 0;

	/* Store system ticks per us */
	uint32_t sys_ticks_per_us = 1;

	/*
	 * Get current settings, clear the clock divisor bits, and clock divider
	 * enable bit.
	 */
	uint32_t ccu_sys_clk_ctl =
	    QM_SCSS_CCU->ccu_sys_clk_ctl & CLK_SYS_CLK_DIV_DEF_MASK;

	/*
	 * Steps:
	 * 1. Enable the new oscillator and wait for it to stabilise.
	 * 2. Switch to the new oscillator
	 *    Note on registers:
	 *    - QM_OSC0_MODE_SEL:
	 *       - asserted: it switches to external crystal oscillator
	 *       - not asserted: it switches to silicon oscillator
	 *     - QM_CCU_SYS_CLK_SEL:
	 *       - asserted: it switches to hybrid (silicon or external)
	 *                   oscillator
	 *       - not asserted: it switches to RTC oscillator
	 * 3. Hybrid oscillator only: apply sysclk divisor
	 * 4. Disable mutually exclusive clock sources. For internal silicon
	 *    oscillator is disables the external crystal oscillator and vice
	 *    versa.
	 */
	switch (mode) {
	case CLK_SYS_HYB_OSC_32MHZ:
	case CLK_SYS_HYB_OSC_16MHZ:
	case CLK_SYS_HYB_OSC_8MHZ:
	case CLK_SYS_HYB_OSC_4MHZ:
		/* Calculate the system clock ticks per microsecond
		 * and get the shadowed trim code from the Data Region of Flash.
		 */
		if (CLK_SYS_HYB_OSC_32MHZ == mode) {
			sys_ticks_per_us = SYS_TICKS_PER_US_32MHZ / BIT(div);
			trim = QM_FLASH_DATA_TRIM_CODE->osc_trim_32mhz;
		} else if (CLK_SYS_HYB_OSC_16MHZ == mode) {
			sys_ticks_per_us = SYS_TICKS_PER_US_16MHZ / BIT(div);
			trim = QM_FLASH_DATA_TRIM_CODE->osc_trim_16mhz;
		} else if (CLK_SYS_HYB_OSC_8MHZ == mode) {
			sys_ticks_per_us = SYS_TICKS_PER_US_8MHZ / BIT(div);
			trim = QM_FLASH_DATA_TRIM_CODE->osc_trim_8mhz;
		} else {
			sys_ticks_per_us = SYS_TICKS_PER_US_4MHZ / BIT(div);
			trim = QM_FLASH_DATA_TRIM_CODE->osc_trim_4mhz;
		}
		/*
		 * Apply trim code for the selected mode if this has been
		 * written in the soc_data section.
		 * This is performed in rom on the first boot for each
		 * available frequency.
		 * If not present, something went wrong and trim code
		 * will not be applied.
		 */
		if ((trim & QM_FLASH_TRIM_PRESENT_MASK) ==
		    QM_FLASH_TRIM_PRESENT) {
			clk_trim_apply(trim);
		}
		/* Select the silicon oscillator frequency */
		QM_SCSS_CCU->osc0_cfg1 &= ~OSC0_CFG1_SI_FREQ_SEL_MASK;
		QM_SCSS_CCU->osc0_cfg1 |= (mode << OSC0_CFG1_SI_FREQ_SEL_OFFS);
		/* Enable the silicon oscillator */
		QM_SCSS_CCU->osc0_cfg1 |= QM_OSC0_EN_SI_OSC;
		/* Wait for the oscillator to lock */
		while (!(QM_SCSS_CCU->osc0_stat1 & QM_OSC0_LOCK_SI)) {
		};
		/* Switch to silicon oscillator mode */
		QM_SCSS_CCU->osc0_cfg1 &= ~QM_OSC0_MODE_SEL;
		/* Set the system clock divider */
		QM_SCSS_CCU->ccu_sys_clk_ctl =
		    ccu_sys_clk_ctl | QM_CCU_SYS_CLK_SEL |
		    (div << QM_CCU_SYS_CLK_DIV_OFFSET);
		/* Disable the crystal oscillator */
		QM_SCSS_CCU->osc0_cfg1 &= ~QM_OSC0_EN_CRYSTAL;
		break;

	case CLK_SYS_RTC_OSC:
		/* The RTC oscillator is on by hardware default */
		ccu_sys_clk_ctl |=
		    (QM_CCU_RTC_CLK_EN | (div << QM_CCU_SYS_CLK_DIV_OFFSET));

		QM_SCSS_CCU->ccu_sys_clk_ctl =
		    (ccu_sys_clk_ctl & ~(QM_CCU_SYS_CLK_SEL));
		break;

	case CLK_SYS_CRYSTAL_OSC:
		QM_SCSS_CCU->osc0_cfg1 |= QM_OSC0_EN_CRYSTAL;
		sys_ticks_per_us = SYS_TICKS_PER_US_XTAL / BIT(div);
		while (!(QM_SCSS_CCU->osc0_stat1 & QM_OSC0_LOCK_XTAL)) {
		};
		QM_SCSS_CCU->osc0_cfg1 |= QM_OSC0_MODE_SEL;
		QM_SCSS_CCU->ccu_sys_clk_ctl =
		    ccu_sys_clk_ctl | QM_CCU_SYS_CLK_SEL |
		    (div << QM_CCU_SYS_CLK_DIV_OFFSET);
		QM_SCSS_CCU->osc0_cfg1 &= ~QM_OSC0_EN_SI_OSC;
		break;
	}

	QM_SCSS_CCU->ccu_sys_clk_ctl |= QM_CCU_SYS_CLK_DIV_EN;
	ticks_per_us = (sys_ticks_per_us > 0 ? sys_ticks_per_us : 1);

	return 0;
}