Statistics
| Branch: | Tag: | Revision:

root / firmware / zpu / lib / clocks.c @ 22ed61f9

History | View | Annotate | Download (6.89 KB)

1
/* -*- c++ -*- */
2
/*
3
 * Copyright 2008 Free Software Foundation, Inc.
4
 *
5
 * This program is free software: you can redistribute it and/or modify
6
 * it under the terms of the GNU General Public License as published by
7
 * the Free Software Foundation, either version 3 of the License, or
8
 * (at your option) any later version.
9
 *
10
 * This program is distributed in the hope that it will be useful,
11
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13
 * GNU General Public License for more details.
14
 *
15
 * You should have received a copy of the GNU General Public License
16
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
17
 */
18

    
19
#ifdef HAVE_CONFIG_H
20
#include <config.h>
21
#endif
22
#include <clocks.h>
23

    
24
#include "memory_map.h"
25
#include "ad9510.h"
26
#include "spi.h"
27
#include "u2_init.h"
28

    
29
//USRP2PLUS clocks:
30
//Clock 0: testclk
31
//Clock 1: FPGA clk
32
//Clock 2: ADC clk
33
//Clock 3: DAC clk
34
//Clock 4: SER clk
35
//Clock 5: TX dboard clk
36
//Clock 6: EXP clk
37
//Clock 7: RX dboard clk
38

    
39
//TODO: should have enough brains to init the FPGA clock for USRP2+. all others are suspect.
40
//note that without EEPROM support u2_hw_rev_major is going to be incorrect.
41

    
42
void 
43
clocks_init(void)
44
{
45
  // Set up basic clocking functions in AD9510
46
  ad9510_write_reg(0x45, 0x01); // CLK2 drives distribution
47

    
48
  //enable the 100MHz clock output to the FPGA for 50MHz CPU clock
49
  clocks_enable_fpga_clk(true, 1);
50

    
51
  spi_wait();
52

    
53
  // Set up PLL for 10 MHz reference
54
  // Reg 4, A counter, Don't Care
55
//  ad9510_write_reg(0x05, 0x00);  // Reg 5, B counter MSBs, 0
56
//  ad9510_write_reg(0x06, 0x05);  // Reg 6, B counter LSBs, 5
57
  // Reg 7, Loss of reference detect, doesn't work yet, 0
58
//  ad9510_write_reg(0x5A, 0x01); // Update Regs
59

    
60
  // Primary clock configuration
61
//  clocks_mimo_config(MC_WE_DONT_LOCK);
62

    
63

    
64
  //wait for the clock to stabilize
65
  while(!clocks_lock_detect());
66

    
67
  //issue a reset to the DCM so it locks up to the new freq
68
  output_regs->clk_ctrl |= CLK_RESET;
69

    
70
  // Set up other clocks
71
  //clocks_enable_test_clk(false, 0);
72
  //clocks_enable_tx_dboard(false, 0);
73
  //clocks_enable_rx_dboard(false, 0);
74
//  clocks_enable_eth_phyclk(false, 0); //PHY clk is separate now (u2r4, u2p)
75

    
76
  // Enable clock to ADCs and DACs
77
  //clocks_enable_dac_clk(true, 1);
78
  //clocks_enable_adc_clk(true, 1);
79
}
80

    
81
/*
82
void
83
clocks_mimo_config(int flags)
84
{
85
  if (flags & _MC_WE_LOCK){
86
    // Reg 8, Charge pump on, dig lock det, positive PFD, 47
87
    ad9510_write_reg(0x08, 0x47);
88
  }
89
  else {
90
    // Reg 8, Charge pump off, dig lock det, positive PFD
91
    ad9510_write_reg(0x08, 0x00);
92
  }
93
  
94
  // Reg 9, Charge pump current, 0x40=3mA, 0x00=650uA
95
  ad9510_write_reg(0x09, 0x00);
96
  // Reg A, Prescaler of 2, everything normal 04
97
  ad9510_write_reg(0x0A, 0x04);
98
  // Reg B, R Div MSBs, 0
99
  ad9510_write_reg(0x0B, 0x00);
100
  // Reg C, R Div LSBs, 1
101
  ad9510_write_reg(0x0C, 0x01);
102
  // Reg D, Antibacklash, Digital lock det, 0
103

104
  ad9510_write_reg(0x5A, 0x01); // Update Regs
105

106
  spi_wait();
107
  
108
  // Allow for clock switchover
109
  // The below masks include 0x10, which issues a reset to the DCM.  
110
  if (flags & _MC_WE_LOCK){                // WE LOCK
111
    if (flags & _MC_MIMO_CLK_INPUT) {
112
      // Turn on ref output and choose the MIMO connector
113
      output_regs->clk_ctrl = 0x15;  
114
    }
115
    else {
116
      // turn on ref output and choose the SMA
117
      output_regs->clk_ctrl = 0x1C; 
118
    }
119
  }
120
  else {                                // WE DONT LOCK
121
    // Disable both ext clk inputs
122
    output_regs->clk_ctrl = 0x10;
123
  }
124

125
  // Do we drive a clock onto the MIMO connector?
126
//  if (flags & MC_PROVIDE_CLK_TO_MIMO)
127
//    clocks_enable_clkexp_out(true,10);
128
//  else
129
//    clocks_enable_clkexp_out(false,0); 
130
}
131
*/
132

    
133
bool 
134
clocks_lock_detect()
135
{
136
    return (pic_regs->pending & PIC_CLKSTATUS);
137
}
138

    
139
int inline
140
clocks_gen_div(int divisor)
141
{
142
  int L,H;
143
  L = (divisor>>1)-1;
144
  H = divisor-L-2;
145
  return (L<<4)|H;
146
}
147

    
148
#define CLOCK_OUT_EN 0x08
149
#define CLOCK_OUT_DIS_CMOS 0x01
150
#define CLOCK_OUT_DIS_PECL 0x02
151
#define CLOCK_DIV_DIS 0x80
152
#define CLOCK_DIV_EN 0x00
153

    
154
#define CLOCK_MODE_PECL 1
155
#define CLOCK_MODE_LVDS 2
156
#define CLOCK_MODE_CMOS 3
157

    
158
//CHANGED: set to PECL for default behavior
159
void 
160
clocks_enable_XXX_clk(bool enable, int divisor, int reg_en, int reg_div, int mode)
161
{
162
  int enable_word, div_word, div_en_word;
163

    
164
  switch(mode) {
165
  case CLOCK_MODE_LVDS :
166
    enable_word = enable ? 0x02 : 0x03;
167
    break;
168
  case CLOCK_MODE_CMOS :
169
    enable_word = enable ? 0x08 : 0x09;
170
    break;
171
  case CLOCK_MODE_PECL :
172
        default:
173
    enable_word = enable ? 0x08 : 0x0A;
174
    break;
175
  }
176
  if(enable && (divisor>1)) {
177
    div_word = clocks_gen_div(divisor);
178
    div_en_word = CLOCK_DIV_EN;
179
  }
180
  else {
181
    div_word = 0;
182
    div_en_word = CLOCK_DIV_DIS;
183
  }
184

    
185
  ad9510_write_reg(reg_en,enable_word); // Output en/dis
186
  ad9510_write_reg(reg_div,div_word); // Set divisor
187
  ad9510_write_reg(reg_div+1,div_en_word); // Enable or Bypass Divider
188
  ad9510_write_reg(0x5A, 0x01);  // Update Regs
189
}
190

    
191
// Clock 0
192
/*void
193
clocks_enable_test_clk(bool enable, int divisor)
194
{
195
  clocks_enable_XXX_clk(enable,divisor,0x3C,0x48,CLOCK_MODE_PECL);
196
}*/
197

    
198
// Clock 1
199
void
200
clocks_enable_fpga_clk(bool enable, int divisor)
201
{
202
  clocks_enable_XXX_clk(enable,divisor,0x3D,0x4A,CLOCK_MODE_PECL);
203
}
204
/*
205
// Clock 2 on Rev 3, Clock 5 on Rev 4, Clock 6 on USRP2+
206
void
207
clocks_enable_clkexp_out(bool enable, int divisor)
208
{
209
  if(u2_hw_rev_major == 3)
210
    clocks_enable_XXX_clk(enable,divisor,0x3E,0x4C,CLOCK_MODE_PECL);
211
  else if(u2_hw_rev_major == 4) {
212
    ad9510_write_reg(0x34,0x00);  // Turn on fine delay
213
    ad9510_write_reg(0x35,0x00);  // Set Full Scale to nearly 10ns
214
    ad9510_write_reg(0x36,0x1c);  // Set fine delay.  0x20 is midscale
215
    clocks_enable_XXX_clk(enable,divisor,0x41,0x52,CLOCK_MODE_LVDS);
216
  }
217
        else if(u2_hw_rev_major == 10) {
218
                ad9510_write_reg(0x34, 0x00);
219
                ad9510_write_reg(0x35, 0x00);
220
                ad9510_write_reg(0x36, 0x1C);
221
                clocks_enable_XXX_clk(enable, divisor, 0x42, 0x52, CLOCK_MODE_LVDS);
222
        }
223
  else
224
    putstr("ERR (clocks_enable_clkexp_out): Invalid hw rev, don't know what to do!\n");
225
}
226
*/
227
/*
228
// Clock 5 on Rev 3, none (was 2) on Rev 4, none on USRP2+
229
void
230
clocks_enable_eth_phyclk(bool enable, int divisor)
231
{
232
  if(u2_hw_rev_major == 3)
233
    clocks_enable_XXX_clk(enable,divisor,0x41,0x52,CLOCK_MODE_LVDS);
234
  else if(u2_hw_rev_major == 4)
235
    clocks_enable_XXX_clk(enable,divisor,0x3E,0x4C,CLOCK_MODE_PECL);
236
  else
237
    putstr("(clocks_enable_eth_phyclk): no eth PHY clock or invalid hw rev\n"); //not really an error
238
}
239
*/
240
// Clock 3
241
/*void
242
clocks_enable_dac_clk(bool enable, int divisor)
243
{
244
  clocks_enable_XXX_clk(enable,divisor,0x3F,0x4E,CLOCK_MODE_PECL);
245
}*/
246

    
247
// Clock 4
248
/*void
249
clocks_enable_adc_clk(bool enable, int divisor)
250
{
251
  clocks_enable_XXX_clk(enable,divisor,0x40,0x50,CLOCK_MODE_LVDS);
252
}*/
253

    
254
// Clock 6
255
/*void
256
clocks_enable_tx_dboard(bool enable, int divisor)
257
{
258
  clocks_enable_XXX_clk(enable,divisor,0x42,0x54,CLOCK_MODE_CMOS);
259
}*/
260

    
261
// Clock 7
262
/*void
263
clocks_enable_rx_dboard(bool enable, int divisor)
264
{
265
  clocks_enable_XXX_clk(enable,divisor,0x43,0x56,CLOCK_MODE_CMOS);
266
}*/