Commit b088f445 authored by Mattia Rizzi's avatar Mattia Rizzi Committed by Grzegorz Daniluk

Functions and configuration to dialogue with the external AD9516

parent 780ed522
......@@ -20,6 +20,7 @@
#include "board.h"
#include "syscon.h"
#include "gpio-wrs.h"
#include "ext-board.h"
#include "rt_ipc.h"
......@@ -75,17 +76,13 @@ struct ad9516_reg {
#define CS_PLL 0 /* AD9516 on SPI CS0 */
static void *oc_spi_base;
static int oc_spi_init(void *base_addr)
{
oc_spi_base = base_addr;
writel(100, oc_spi_base + SPI_REG_DIVIDER);
writel(100, base_addr + SPI_REG_DIVIDER);
return 0;
}
static int oc_spi_txrx(int ss, int nbits, uint32_t in, uint32_t *out)
static int oc_spi_txrx(void *base, int ss, int nbits, uint32_t in, uint32_t *out)
{
uint32_t rval;
......@@ -94,17 +91,17 @@ static int oc_spi_txrx(int ss, int nbits, uint32_t in, uint32_t *out)
writel(SPI_CTRL_ASS | SPI_CTRL_CHAR_LEN(nbits)
| SPI_CTRL_TXNEG,
oc_spi_base + SPI_REG_CTRL);
base + SPI_REG_CTRL);
writel(in, oc_spi_base + SPI_REG_TX0);
writel((1 << ss), oc_spi_base + SPI_REG_SS);
writel(in, base + SPI_REG_TX0);
writel((1 << ss), base + SPI_REG_SS);
writel(SPI_CTRL_ASS | SPI_CTRL_CHAR_LEN(nbits)
| SPI_CTRL_TXNEG | SPI_CTRL_GO_BSY,
oc_spi_base + SPI_REG_CTRL);
base + SPI_REG_CTRL);
while(readl(oc_spi_base + SPI_REG_CTRL) & SPI_CTRL_GO_BSY)
while(readl(base + SPI_REG_CTRL) & SPI_CTRL_GO_BSY)
;
*out = readl(oc_spi_base + SPI_REG_RX0);
*out = readl(base + SPI_REG_RX0);
return 0;
}
......@@ -113,39 +110,39 @@ static int oc_spi_txrx(int ss, int nbits, uint32_t in, uint32_t *out)
* "reg" is 12 bits, "val" is 8 bits, but both are better used as int
*/
static void ad9516_write_reg(int reg, int val)
static void ad9516_write_reg(void *base, int reg, int val)
{
oc_spi_txrx(CS_PLL, 24, (reg << 8) | val, NULL);
oc_spi_txrx(base, CS_PLL, 24, (reg << 8) | val, NULL);
}
static int ad9516_read_reg(int reg)
static int ad9516_read_reg(void *base, int reg)
{
uint32_t rval;
oc_spi_txrx(CS_PLL, 24, (reg << 8) | (1 << 23), &rval);
oc_spi_txrx(base, CS_PLL, 24, (reg << 8) | (1 << 23), &rval);
return rval & 0xff;
}
static void ad9516_load_regset(const struct ad9516_reg *regs, int n_regs, int commit)
static void ad9516_load_regset(void *base, const struct ad9516_reg *regs, int n_regs, int commit)
{
int i;
for(i=0; i<n_regs; i++)
ad9516_write_reg(regs[i].reg, regs[i].val);
ad9516_write_reg(base, regs[i].reg, regs[i].val);
if(commit)
ad9516_write_reg(0x232, 1);
ad9516_write_reg(base, 0x232, 1);
}
static void ad9516_wait_lock(void)
static void ad9516_wait_lock(void *base)
{
while ((ad9516_read_reg(0x1f) & 1) == 0);
while ((ad9516_read_reg(base, 0x1f) & 1) == 0);
}
#define SECONDARY_DIVIDER 0x100
static int ad9516_set_output_divider(int output, int ratio, int phase_offset)
static int ad9516_set_output_divider(void *spi_base, int output, int ratio, int phase_offset)
{
uint8_t lcycles = (ratio/2) - 1;
uint8_t hcycles = (ratio - (ratio / 2)) - 1;
......@@ -158,12 +155,12 @@ static int ad9516_set_output_divider(int output, int ratio, int phase_offset)
if(ratio == 1) /* bypass the divider */
{
uint8_t div_ctl = ad9516_read_reg(base + 1);
ad9516_write_reg(base + 1, div_ctl | (1<<7) | (phase_offset & 0xf));
uint8_t div_ctl = ad9516_read_reg(spi_base, base + 1);
ad9516_write_reg(spi_base, base + 1, div_ctl | (1<<7) | (phase_offset & 0xf));
} else {
uint8_t div_ctl = ad9516_read_reg(base + 1);
ad9516_write_reg(base + 1, (div_ctl & (~(1<<7))) | (phase_offset & 0xf)); /* disable bypass bit */
ad9516_write_reg(base, (lcycles << 4) | hcycles);
uint8_t div_ctl = ad9516_read_reg(spi_base, base + 1);
ad9516_write_reg(spi_base, base + 1, (div_ctl & (~(1<<7))) | (phase_offset & 0xf)); /* disable bypass bit */
ad9516_write_reg(spi_base, base, (lcycles << 4) | hcycles);
}
} else { /* LVDS/CMOS outputs */
......@@ -174,16 +171,16 @@ static int ad9516_set_output_divider(int output, int ratio, int phase_offset)
if(!secondary)
{
if(ratio == 1) /* bypass the divider 1 */
ad9516_write_reg(base + 3, ad9516_read_reg(base + 3) | 0x10);
ad9516_write_reg(spi_base, base + 3, ad9516_read_reg(spi_base, base + 3) | 0x10);
else {
ad9516_write_reg(base, (lcycles << 4) | hcycles);
ad9516_write_reg(base + 1, phase_offset & 0xf);
ad9516_write_reg(spi_base, base, (lcycles << 4) | hcycles);
ad9516_write_reg(spi_base, base + 1, phase_offset & 0xf);
}
} else {
if(ratio == 1) /* bypass the divider 2 */
ad9516_write_reg(base + 3, ad9516_read_reg(base + 3) | 0x20);
ad9516_write_reg(spi_base, base + 3, ad9516_read_reg(spi_base, base + 3) | 0x20);
else {
ad9516_write_reg(base + 2, (lcycles << 4) | hcycles);
ad9516_write_reg(spi_base, base + 2, (lcycles << 4) | hcycles);
// ad9516_write_reg(base + 1, phase_offset & 0xf);
}
......@@ -191,33 +188,45 @@ static int ad9516_set_output_divider(int output, int ratio, int phase_offset)
}
/* update */
ad9516_write_reg(0x232, 0x0);
ad9516_write_reg(0x232, 0x1);
ad9516_write_reg(0x232, 0x0);
ad9516_write_reg(spi_base, 0x232, 0x0);
ad9516_write_reg(spi_base, 0x232, 0x1);
ad9516_write_reg(spi_base, 0x232, 0x0);
return 0;
}
static int ad9516_set_vco_divider(int ratio) /* Sets the VCO divider (2..6) or 0 to enable static output */
static int ad9516_set_vco_divider(void *spi_base, int ratio) /* Sets the VCO divider (2..6) or 0 to enable static output */
{
if(ratio == 0)
ad9516_write_reg(0x1e0, 0x5); /* static mode */
ad9516_write_reg(spi_base, 0x1e0, 0x5); /* static mode */
else
ad9516_write_reg(0x1e0, (ratio-2));
ad9516_write_reg(0x232, 0x1);
ad9516_write_reg(spi_base, 0x1e0, (ratio-2));
ad9516_write_reg(spi_base, 0x232, 0x1);
ad9516_write_reg(spi_base, 0x232, 0x0);
return 0;
}
static void ad9516_sync_outputs(void)
static void ad9516_sync_outputs(void *spi_base)
{
/* VCO divider: static mode */
ad9516_write_reg(0x1E0, 0x7);
ad9516_write_reg(0x232, 0x1);
ad9516_write_reg(spi_base, 0x1E0, 0x7);
ad9516_write_reg(spi_base, 0x232, 0x1);
/* Sync the outputs when they're inactive to avoid +-1 cycle uncertainity */
ad9516_write_reg(0x230, 1);
ad9516_write_reg(0x232, 1);
ad9516_write_reg(0x230, 0);
ad9516_write_reg(0x232, 1);
ad9516_write_reg(spi_base, 0x230, 1);
ad9516_write_reg(spi_base, 0x232, 1);
ad9516_write_reg(spi_base, 0x230, 0);
ad9516_write_reg(spi_base, 0x232, 1);
ad9516_write_reg(spi_base, 0x232, 0x0);
}
int ext_ad9516_locked (void)
{
if ((ad9516_read_reg((void *)BASE_SPI_EXT_BOARD, 0x1f) & 1))
return 1;
return 0;
}
int ad9516_init(int scb_version)
......@@ -225,6 +234,8 @@ int ad9516_init(int scb_version)
pp_printf("Initializing AD9516 PLL...\n");
oc_spi_init((void *)BASE_SPI);
void *spi_base = (void *)BASE_SPI;
gpio_out(GPIO_SYS_CLK_SEL, 0); /* switch to the standby reference clock, since the PLL is off after reset */
......@@ -235,30 +246,31 @@ int ad9516_init(int scb_version)
timer_delay(10);
/* Use unidirectional SPI mode */
ad9516_write_reg(0x000, 0x99);
ad9516_write_reg(spi_base, 0x000, 0x99);
/* Check the presence of the chip */
if (ad9516_read_reg(0x3) != 0xc3) {
if (ad9516_read_reg(spi_base, 0x3) != 0xc3) {
pp_printf("Error: AD9516 PLL not responding.\n");
return -1;
}
if( scb_version >= 34) //New SCB v3.4. 10MHz Output.
ad9516_load_regset(ad9516_base_config_34, ARRAY_SIZE(ad9516_base_config_34), 0);
ad9516_load_regset(spi_base, ad9516_base_config_34, ARRAY_SIZE(ad9516_base_config_34), 0);
else //Old one
ad9516_load_regset(ad9516_base_config_33, ARRAY_SIZE(ad9516_base_config_33), 0);
ad9516_load_regset(spi_base, ad9516_base_config_33, ARRAY_SIZE(ad9516_base_config_33), 0);
ad9516_load_regset(ad9516_ref_tcxo, ARRAY_SIZE(ad9516_ref_tcxo), 1);
ad9516_wait_lock();
ad9516_load_regset(spi_base, ad9516_ref_tcxo, ARRAY_SIZE(ad9516_ref_tcxo), 1);
ad9516_wait_lock(spi_base);
ad9516_sync_outputs();
ad9516_sync_outputs(spi_base);
if( scb_version >= 34) { //New SCB v3.4. 10MHz Output.
ad9516_set_output_divider(2, 4, 0); // OUT2. 187.5 MHz. - not anymore
ad9516_set_output_divider(3, 4, 0); // OUT3. 187.5 MHz. - not anymore
ad9516_set_output_divider(spi_base, 2, 4, 0); // OUT2. 187.5 MHz. - not anymore
ad9516_set_output_divider(spi_base, 3, 4, 0); // OUT3. 187.5 MHz. - not anymore
ad9516_set_output_divider(4, 1, 0); // OUT4. 500 MHz.
ad9516_set_output_divider(spi_base, 4, 1, 0); // OUT4. 500 MHz.
ad9516_set_output_divider(spi_base, 9, 20,0);
/*The following PLL outputs have been configured through the ad9516_base_config_34 register,
* so it doesn't need to replicate the configuration:
......@@ -271,13 +283,13 @@ int ad9516_init(int scb_version)
} else { //Old one
ad9516_set_output_divider(9, 4, 0); /* AUX/SWCore = 187.5 MHz */ //not needed anymore
ad9516_set_output_divider(7, 8, 0); /* REF = 62.5 MHz */
ad9516_set_output_divider(4, 8, 0); /* GTX = 62.5 MHz */
ad9516_set_output_divider(spi_base, 9, 4, 0); /* AUX/SWCore = 187.5 MHz */ //not needed anymore
ad9516_set_output_divider(spi_base, 7, 8, 0); /* REF = 62.5 MHz */
ad9516_set_output_divider(spi_base, 4, 8, 0); /* GTX = 62.5 MHz */
}
ad9516_sync_outputs();
ad9516_set_vco_divider(3);
ad9516_sync_outputs(spi_base);
ad9516_set_vco_divider(spi_base, 3);
pp_printf("AD9516 locked.\n");
......@@ -288,6 +300,40 @@ int ad9516_init(int scb_version)
return 0;
}
int ext_ad9516_init (void) {
pp_printf("Initializing external AD9516 PLL...\n");
oc_spi_init((void *)BASE_SPI_EXT_BOARD);
void *spi_base = (void *)BASE_SPI_EXT_BOARD;
/* reset the PLL */
gpio_out(GPIO_EXT_PLL_RESET_N, 0);
timer_delay(10);
gpio_out(GPIO_EXT_PLL_RESET_N, 1);
timer_delay(10);
/* Use unidirectional SPI mode */
ad9516_write_reg((void *)spi_base, 0x000, 0x99);
/* Check the presence of the chip */
if (ad9516_read_reg((void *)spi_base, 0x3) != 0xc3) {
pp_printf("Error: External AD9516 PLL not responding.\n");
return -1;
}
ad9516_write_reg(spi_base, 0x018, 0x0); // reset VCO calibration
ad9516_write_reg(spi_base, 0x232, 0x0);
ad9516_write_reg(spi_base, 0x232, 0x1);
ad9516_write_reg(spi_base, 0x232, 0x0);
ad9516_set_vco_divider(spi_base, 3);
ad9516_load_regset(spi_base, ad9516_ext_base_config, ARRAY_SIZE(ad9516_ext_base_config), 1);
ad9516_set_output_divider(spi_base, 6, 8, 0); // OUT6. 62.5MHz
ad9516_set_output_divider(spi_base, 8, 20, 0); // OUT6. 62.5MHz
return 0;
}
int rts_debug_command(int command, int value)
{
......@@ -296,13 +342,13 @@ int rts_debug_command(int command, int value)
case RTS_DEBUG_ENABLE_SERDES_CLOCKS:
if(value)
{
ad9516_write_reg(0xf4, 0x08); // OUT4 enabled
ad9516_write_reg(0x232, 0x0);
ad9516_write_reg(0x232, 0x1);
ad9516_write_reg((void *)BASE_SPI, 0xf4, 0x08); // OUT4 enabled
ad9516_write_reg((void *)BASE_SPI, 0x232, 0x0);
ad9516_write_reg((void *)BASE_SPI, 0x232, 0x1);
} else {
ad9516_write_reg(0xf4, 0x0a); // OUT4 power-down, no serdes clock
ad9516_write_reg(0x232, 0x0);
ad9516_write_reg(0x232, 0x1);
ad9516_write_reg((void *)BASE_SPI, 0xf4, 0x0a); // OUT4 power-down, no serdes clock
ad9516_write_reg((void *)BASE_SPI, 0x232, 0x0);
ad9516_write_reg((void *)BASE_SPI, 0x232, 0x1);
}
break;
}
......
......@@ -78,7 +78,7 @@ const struct ad9516_reg ad9516_base_config_34[] = {
{0x0003, 0xC3},
{0x0004, 0x00},
{0x0010, 0x7C},
{0x0011, 0x05},
{0x0011, 0x04},
{0x0012, 0x00},
{0x0013, 0x0C},
{0x0014, 0x12},
......@@ -143,10 +143,85 @@ const struct ad9516_reg ad9516_base_config_34[] = {
{0x0231, 0x00},
};
/* Configuration for the SCB version greater than or equal 3.4: Base + 6, 7, 8, 9 outputs*/
const struct ad9516_reg ad9516_ext_base_config[] = {
{0x0000, 0x99},
{0x0001, 0x00},
{0x0002, 0x10},
{0x0003, 0xC3},
{0x0004, 0x00},
{0x0010, 0x4C},
{0x0011, 0x00},
{0x0012, 0x00},
{0x0013, 0x06},
{0x0014, 0x12},
{0x0015, 0x00},
{0x0016, 0x04},
{0x0017, 0x00},
{0x0018, 0x07},
{0x0019, 0x00},
{0x001A, 0x00},
{0x001B, 0x00},
{0x001C, 0x01},
{0x001D, 0x00},
{0x001E, 0x00},
{0x001F, 0x0E},
{0x00A0, 0x01},
{0x00A1, 0x00},
{0x00A2, 0x00},
{0x00A3, 0x01},
{0x00A4, 0x00},
{0x00A5, 0x00},
{0x00A6, 0x01},
{0x00A7, 0x00},
{0x00A8, 0x00},
{0x00A9, 0x01},
{0x00AA, 0x00},
{0x00AB, 0x00},
{0x00F0, 0x0A},
{0x00F1, 0x0A},
{0x00F2, 0x0A},
{0x00F3, 0x0A},
{0x00F4, 0x08},
{0x00F5, 0x08},
// The following registers configure the PLL outputs from 6 to 9.
{0x0140, 0x42},
{0x0141, 0x42},
{0x0142, 0x08},
{0x0143, 0x4E},
{0x0190, 0x55},
{0x0191, 0x00},
{0x0192, 0x00},
{0x0193, 0x11},
{0x0194, 0x00},
{0x0195, 0x00},
{0x0196, 0x10},
{0x0197, 0x00},
{0x0198, 0x00},
{0x0199, 0x33},
{0x019A, 0x00},
{0x019B, 0x11},
{0x019C, 0x20},
{0x019D, 0x00},
{0x019E, 0x33},
{0x019F, 0x00},
{0x01A0, 0x11},
{0x01A1, 0x20},
{0x01A2, 0x00},
{0x01A3, 0x00},
//
{0x01E0, 0x01},
{0x01E1, 0x02},
{0x0230, 0x00},
{0x0231, 0x00},
};
/* Config for 25 MHz VCTCXO reference (RDiv = 5, use REF1) */
const struct ad9516_reg ad9516_ref_tcxo[] = {
{0x0011, 0x05},
{0x0012, 0x00}, /* RDiv = 5 */
{0x0011, 0x04},
{0x0012, 0x00}, /* RDiv = 4 */
{0x001C, 0x06} /* Use REF1 */
};
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment