/* * Copyright 2012 Michael Ossmann * Copyright 2012 Jared Boone * * This file is part of HackRF. * * This program 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. * * This program 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 this program; see the file COPYING. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, * Boston, MA 02110-1301, USA. */ #include "hackrf_core.h" #include "si5351c.h" #include #include #include #include #include #ifdef JELLYBEAN void delay(uint32_t duration) { uint32_t i; for (i = 0; i < duration; i++) __asm__("nop"); } /* clock startup for Jellybean with Lemondrop attached */ void cpu_clock_init(void) { i2c0_init(); si5351c_disable_all_outputs(); si5351c_disable_oeb_pin_control(); si5351c_power_down_all_clocks(); si5351c_set_crystal_configuration(); si5351c_enable_xo_and_ms_fanout(); si5351c_configure_pll_sources_for_xtal(); si5351c_configure_pll1_multisynth(); /* MS0/CLK0 is the source for the MAX2837 clock input. */ si5351c_configure_multisynth(0, 2048, 0, 1, 0); /* 40MHz */ /* MS0/CLK1 is the source for the MAX5864 codec. */ si5351c_configure_multisynth(1, 4608, 0, 1, 2); /* 10MHz */ /* MS0/CLK2 is the source for the CPLD codec clock (same as CLK1). */ si5351c_configure_multisynth(2, 4608, 0, 1, 2); /* 10MHz */ /* MS0/CLK3 is the source for the SGPIO clock. */ si5351c_configure_multisynth(3, 4608, 0, 1, 1); /* 20MHz */ /* MS4/CLK4 is the source for the LPC43xx microcontroller. */ si5351c_configure_multisynth(4, 8021, 0, 3, 0); /* 12MHz */ /* MS5/CLK5 is the source for the RFFC5071 mixer. */ si5351c_configure_multisynth(5, 1536, 0, 1, 0); /* 50MHz */ si5351c_configure_clock_control(); si5351c_enable_clock_outputs(); //FIXME disable I2C /* * 12MHz clock is entering LPC XTAL1/OSC input now. * Set up PLL1 to run from XTAL1 input. */ //FIXME a lot of the details here should be in a CGU driver /* configure xtal oscillator for external clock input signal */ CGU_XTAL_OSC_CTRL |= CGU_XTAL_OSC_CTRL_BYPASS; /* set xtal oscillator to low frequency mode */ CGU_XTAL_OSC_CTRL &= ~CGU_XTAL_OSC_CTRL_HF; /* power on the oscillator and wait until stable */ CGU_XTAL_OSC_CTRL &= ~CGU_XTAL_OSC_CTRL_ENABLE; /* use XTAL_OSC as clock source for BASE_M4_CLK (CPU) */ CGU_BASE_M4_CLK = ((CGU_SRC_XTAL << CGU_BASE_CLK_SEL_SHIFT)); /* use XTAL_OSC as clock source for APB1 */ CGU_BASE_APB1_CLK = (CGU_BASE_CLK_AUTOBLOCK | (CGU_SRC_XTAL << CGU_BASE_CLK_SEL_SHIFT)); /* use XTAL_OSC as clock source for PLL1 */ CGU_PLL1_CTRL = (CGU_PLL1_CTRL_AUTOBLOCK | (CGU_SRC_XTAL << CGU_PLL1_CTRL_CLK_SEL_SHIFT)); /* configure PLL1 to produce 204 MHz clock from 12 MHz XTAL_OSC */ /* not sure why, but it doesn't work without the following line */ CGU_PLL1_CTRL &= ~(CGU_PLL1_CTRL_BYPASS | CGU_PLL1_CTRL_FBSEL | CGU_PLL1_CTRL_DIRECT | CGU_PLL1_CTRL_DIRECT | (0x3 << CGU_PLL1_CTRL_PSEL_SHIFT) | (0x3 << CGU_PLL1_CTRL_NSEL_SHIFT) | (0xFF << CGU_PLL1_CTRL_MSEL_SHIFT)); CGU_PLL1_CTRL |= (CGU_PLL1_CTRL_FBSEL | CGU_PLL1_CTRL_DIRECT | (0 << CGU_PLL1_CTRL_PSEL_SHIFT) | (0 << CGU_PLL1_CTRL_NSEL_SHIFT) | (16 << CGU_PLL1_CTRL_MSEL_SHIFT)); /* power on PLL1 and wait until stable */ CGU_PLL1_CTRL &= ~CGU_PLL1_CTRL_PD; while (!(CGU_PLL1_STAT & CGU_PLL1_STAT_LOCK)); /* use PLL1 as clock source for BASE_M4_CLK (CPU) */ CGU_BASE_M4_CLK = ((CGU_SRC_PLL1 << CGU_BASE_CLK_SEL_SHIFT)); /* use XTAL_OSC as clock source for PLL0USB */ CGU_PLL0USB_CTRL = (CGU_PLL0USB_CTRL_PD | CGU_PLL0USB_CTRL_AUTOBLOCK | (CGU_SRC_XTAL << CGU_PLL0USB_CTRL_CLK_SEL_SHIFT)); while (CGU_PLL0USB_STAT & CGU_PLL0USB_STAT_LOCK); /* configure PLL0USB to produce 480 MHz clock from 12 MHz XTAL_OSC */ CGU_PLL0USB_MDIV = ((0x07FFA << CGU_PLL0USB_MDIV_MDEC_SHIFT) | (0x0B << CGU_PLL0USB_SELP_MDEC_SHIFT) | (0x10 << CGU_PLL0USB_SELI_MDEC_SHIFT) | (0x0 << CGU_PLL0USB_SELR_MDEC_SHIFT)); CGU_PLL0USB_NP_DIV = (98 << CGU_PLL0USB_NP_DIV_PDEC_SHIFT) | (514 << CGU_PLL0USB_NP_DIV_NDEC_SHIFT); CGU_PLL0USB_CTRL |= (CGU_PLL0USB_CTRL_PD | CGU_PLL0USB_CTRL_DIRECTI | CGU_PLL0USB_CTRL_DIRECTO | CGU_PLL0USB_CTRL_CLKEN); /* power on PLL0USB and wait until stable */ CGU_PLL0USB_CTRL &= ~CGU_PLL0USB_CTRL_PD; while (!(CGU_PLL0USB_STAT & CGU_PLL0USB_STAT_LOCK)); /* use PLL0USB as clock source for USB0 */ CGU_BASE_USB0_CLK = (CGU_BASE_CLK_AUTOBLOCK | (CGU_SRC_PLL0USB << CGU_BASE_CLK_SEL_SHIFT)); } void ssp1_init(void) { /* * Configure CS_AD pin to keep the MAX5864 SPI disabled while we use the * SPI bus for the MAX2837. FIXME: this should probably be somewhere else. */ scu_pinmux(SCU_AD_CS, SCU_GPIO_FAST); GPIO_SET(PORT_AD_CS) = PIN_AD_CS; GPIO_DIR(PORT_AD_CS) |= PIN_AD_CS; scu_pinmux(SCU_XCVR_CS, SCU_GPIO_FAST); GPIO_SET(PORT_XCVR_CS) = PIN_XCVR_CS; GPIO_DIR(PORT_XCVR_CS) |= PIN_XCVR_CS; /* Configure SSP1 Peripheral (to be moved later in SSP driver) */ scu_pinmux(SCU_SSP1_MISO, (SCU_SSP_IO | SCU_CONF_FUNCTION5)); scu_pinmux(SCU_SSP1_MOSI, (SCU_SSP_IO | SCU_CONF_FUNCTION5)); scu_pinmux(SCU_SSP1_SCK, (SCU_SSP_IO | SCU_CONF_FUNCTION1)); } void ssp1_set_mode_max2837(void) { /* FIXME speed up once everything is working reliably */ const uint8_t serial_clock_rate = 32; const uint8_t clock_prescale_rate = 128; ssp_init(SSP1_NUM, SSP_DATA_16BITS, SSP_FRAME_SPI, SSP_CPOL_0_CPHA_0, serial_clock_rate, clock_prescale_rate, SSP_MODE_NORMAL, SSP_MASTER, SSP_SLAVE_OUT_ENABLE); } void ssp1_set_mode_max5864(void) { /* FIXME speed up once everything is working reliably */ const uint8_t serial_clock_rate = 32; const uint8_t clock_prescale_rate = 128; ssp_init(SSP1_NUM, SSP_DATA_8BITS, SSP_FRAME_SPI, SSP_CPOL_0_CPHA_0, serial_clock_rate, clock_prescale_rate, SSP_MODE_NORMAL, SSP_MASTER, SSP_SLAVE_OUT_ENABLE); } void pin_setup(void) { /* Release CPLD JTAG pins */ scu_pinmux(SCU_PINMUX_CPLD_TDO, SCU_GPIO_NOPULL | SCU_CONF_FUNCTION4); scu_pinmux(SCU_PINMUX_CPLD_TCK, SCU_GPIO_NOPULL | SCU_CONF_FUNCTION0); scu_pinmux(SCU_PINMUX_CPLD_TMS, SCU_GPIO_NOPULL | SCU_CONF_FUNCTION0); scu_pinmux(SCU_PINMUX_CPLD_TDI, SCU_GPIO_NOPULL | SCU_CONF_FUNCTION0); GPIO_DIR(PORT_CPLD_TDO) &= ~PIN_CPLD_TDO; GPIO_DIR(PORT_CPLD_TCK) &= ~PIN_CPLD_TCK; GPIO_DIR(PORT_CPLD_TMS) &= ~PIN_CPLD_TMS; GPIO_DIR(PORT_CPLD_TDI) &= ~PIN_CPLD_TDI; /* Configure SCU Pin Mux as GPIO */ scu_pinmux(SCU_PINMUX_LED1, SCU_GPIO_FAST); scu_pinmux(SCU_PINMUX_LED2, SCU_GPIO_FAST); scu_pinmux(SCU_PINMUX_LED3, SCU_GPIO_FAST); scu_pinmux(SCU_PINMUX_EN1V8, SCU_GPIO_FAST); scu_pinmux(SCU_PINMUX_BOOT0, SCU_GPIO_FAST); scu_pinmux(SCU_PINMUX_BOOT1, SCU_GPIO_FAST); scu_pinmux(SCU_PINMUX_BOOT2, SCU_GPIO_FAST); scu_pinmux(SCU_PINMUX_BOOT3, SCU_GPIO_FAST); /* Configure all GPIO as Input (safe state) */ GPIO0_DIR = 0; GPIO1_DIR = 0; GPIO2_DIR = 0; GPIO3_DIR = 0; GPIO4_DIR = 0; GPIO5_DIR = 0; GPIO6_DIR = 0; GPIO7_DIR = 0; /* Configure GPIO2[1/2/8] (P4_1/2 P6_12) as output. */ GPIO2_DIR |= (PIN_LED1 | PIN_LED2 | PIN_LED3); /* GPIO3[6] on P6_10 as output. */ GPIO3_DIR |= PIN_EN1V8; /* Configure SSP1 Peripheral (to be moved later in SSP driver) */ scu_pinmux(SCU_SSP1_MISO, (SCU_SSP_IO | SCU_CONF_FUNCTION5)); scu_pinmux(SCU_SSP1_MOSI, (SCU_SSP_IO | SCU_CONF_FUNCTION5)); scu_pinmux(SCU_SSP1_SCK, (SCU_SSP_IO | SCU_CONF_FUNCTION1)); scu_pinmux(SCU_SSP1_SSEL, (SCU_SSP_IO | SCU_CONF_FUNCTION1)); } void enable_1v8_power(void) { gpio_set(PORT_EN1V8, PIN_EN1V8); } #endif