blob: 3abd22796b37603676a9bd1f6cf1eb6a021eee12 [file] [log] [blame]
Tim Edwards04ba17f2020-10-02 22:27:50 -04001//-------------------------------------
2// SPI controller for Caravel (PicoSoC)
3//-------------------------------------
4// Written by Tim Edwards
5// efabless, inc. September 27, 2020
6//-------------------------------------
7
8`include "caravel_spi_slave.v"
9
10//-----------------------------------------------------------
11// This is a standalone slave SPI for the caravel chip that is
12// intended to be independent of the picosoc and independent
13// of all IP blocks except the power-on-reset. This SPI has
14// register outputs controlling the functions that critically
15// affect operation of the picosoc and so cannot be accessed
16// from the picosoc itself. This includes the PLL enables
17// and trim, and the crystal oscillator enable. It also has
18// a general reset for the picosoc, an IRQ input, a bypass for
19// the entire crystal oscillator and PLL chain, the
20// manufacturer and product IDs and product revision number.
21// To be independent of the 1.8V regulator, the slave SPI is
22// synthesized with the 3V digital library and runs off of
23// the 3V supply.
24//
25// This module is designed to be decoupled from the chip
26// padframe and redirected to the wishbone bus under
27// register control from the management SoC, such that the
28// contents can be accessed from the management core via the
29// SPI master.
30//
31//-----------------------------------------------------------
32
33//------------------------------------------------------------
34// Caravel defined registers:
35// Register 0: SPI status and control (unused & reserved)
36// Register 1 and 2: Manufacturer ID (0x0456) (readonly)
37// Register 3: Product ID (= 2) (readonly)
38// Register 4-7: Mask revision (readonly) --- Externally programmed
39// with via programming. Via programmed with a script to match
40// each customer ID.
41//
42// Register 8: PLL enable (1 bit)
43// Register 9: PLL bypass (1 bit)
44// Register 10: IRQ (1 bit)
45// Register 11: reset (1 bit)
46// Register 12: trap (1 bit) (readonly)
47// Register 13-16: PLL trim (26 bits)
48// Register 17: PLL output select (3 bits)
49// Register 18: PLL divider (5 bits)
50//------------------------------------------------------------
51
52module caravel_spi(
53`ifdef LVS
54 vdd, vss,
55`endif
56 RSTB, SCK, SDI, CSB, SDO, sdo_enb,
57 mgmt_sck, mgmt_sdi, mgmt_csb, mgmt_sdo,
58 pll_dco_ena, pll_div, pll_sel,
59 pll_trim, pll_bypass, irq, reset, trap,
60 mask_rev_in, pass_thru_reset,
61 pass_thru_mgmt_sck, pass_thru_mgmt_csb,
62 pass_thru_mgmt_sdi, pass_thru_mgmt_sdo,
63 pass_thru_user_sck, pass_thru_user_csb,
64 pass_thru_user_sdi, pass_thru_user_sdo
65);
66
67`ifdef LVS
68 inout vdd; // 3.3V supply
69 inout vss; // common ground
70`endif
71
72 input RSTB; // from padframe
73
74 input SCK; // from padframe
75 input SDI; // from padframe
76 input CSB; // from padframe
77 output SDO; // to padframe
78 output sdo_enb; // to padframe
79
80 input mgmt_sck; // from management SoC
81 input mgmt_sdi; // from management SoC
82 input mgmt_csb; // from management SoC
83 output mgmt_sdo; // to management SoC
84
85 output pll_dco_ena;
86 output [4:0] pll_div;
87 output [2:0] pll_sel;
88 output [25:0] pll_trim;
89 output pll_bypass;
90 output irq;
91 output reset;
92 input trap;
93 input [31:0] mask_rev_in; // metal programmed; 3.3V domain
94
95 // Pass-through programming mode for management area SPI flash
96 output pass_thru_reset;
97 output pass_thru_mgmt_sck;
98 output pass_thru_mgmt_csb;
99 output pass_thru_mgmt_sdi;
100 input pass_thru_mgmt_sdo;
101
102 // Pass-through programming mode for user area SPI flash
103 output pass_thru_user_sck;
104 output pass_thru_user_csb;
105 output pass_thru_user_sdi;
106 input pass_thru_user_sdo;
107
108 reg [25:0] pll_trim;
109 reg [4:0] pll_div;
110 reg [2:0] pll_sel;
111 reg pll_dco_ena;
112 reg pll_bypass;
113 reg reset_reg;
114 reg irq;
115
116 wire [7:0] odata;
117 wire [7:0] idata;
118 wire [7:0] iaddr;
119
120 wire trap;
121 wire rdstb;
122 wire wrstb;
123 wire pass_thru_mgmt; // Mode detected by spi_slave
124 wire pass_thru_mgmt_delay;
125 wire pass_thru_user; // Mode detected by spi_slave
126 wire pass_thru_user_delay;
127
128 // Connect to management SoC SPI master when mgmt_csb is low
129
130 wire loc_sck;
131 wire loc_csb;
132 wire loc_sdi;
133 wire loc_sdo;
134 wire loc_sdoenb;
135
136 assign loc_csb = (mgmt_csb == 1'b0) ? 1'b0 : CSB;
137 assign loc_sck = (mgmt_csb == 1'b0) ? mgmt_sck : SCK;
138 assign loc_sdi = (mgmt_csb == 1'b0) ? mgmt_sdi : SDI;
139
140 assign mgmt_sdo = (mgmt_csb == 1'b0) ? loc_sdo : 1'b0;
141 assign sdo_enb = (mgmt_csb == 1'b0) ? 1'b1 : loc_sdoenb;
142
143 // Pass-through mode handling
144
145 assign pass_thru_mgmt_csb = ~pass_thru_mgmt_delay;
146 assign pass_thru_mgmt_sck = pass_thru_mgmt ? SCK : 1'b0;
147 assign pass_thru_mgmt_sdi = pass_thru_mgmt ? SDI : 1'b0;
148
149 assign pass_thru_user_csb = ~pass_thru_user_delay;
150 assign pass_thru_user_sck = pass_thru_user ? SCK : 1'b0;
151 assign pass_thru_user_sdi = pass_thru_user ? SDI : 1'b0;
152
153 assign SDO = pass_thru_mgmt ? pass_thru_mgmt_sdo :
154 pass_thru_user ? pass_thru_user_sdo : loc_sdo;
155 assign reset = pass_thru_reset ? 1'b1 : reset_reg;
156
157 // Instantiate the SPI slave module
158
159 caravel_spi_slave U1 (
160 .reset(~RSTB),
161 .SCK(loc_sck),
162 .SDI(loc_sdi),
163 .CSB(loc_csb),
164 .SDO(loc_sdo),
165 .sdoenb(loc_sdoenb),
166 .idata(odata),
167 .odata(idata),
168 .oaddr(iaddr),
169 .rdstb(rdstb),
170 .wrstb(wrstb),
171 .pass_thru_mgmt(pass_thru_mgmt),
172 .pass_thru_mgmt_delay(pass_thru_mgmt_delay),
173 .pass_thru_user(pass_thru_user),
174 .pass_thru_user_delay(pass_thru_user_delay),
175 .pass_thru_reset(pass_thru_reset)
176 );
177
178 wire [11:0] mfgr_id;
179 wire [7:0] prod_id;
180 wire [31:0] mask_rev;
181
182 assign mfgr_id = 12'h456; // Hard-coded
183 assign prod_id = 8'h10; // Hard-coded
184 assign mask_rev = mask_rev_in; // Copy in to out.
185
186 // Send register contents to odata on SPI read command
187 // All values are 1-4 bits and no shadow registers are required.
188
189 assign odata =
190 (iaddr == 8'h00) ? 8'h00 : // SPI status (fixed)
191 (iaddr == 8'h01) ? {4'h0, mfgr_id[11:8]} : // Manufacturer ID (fixed)
192 (iaddr == 8'h02) ? mfgr_id[7:0] : // Manufacturer ID (fixed)
193 (iaddr == 8'h03) ? prod_id : // Product ID (fixed)
194 (iaddr == 8'h04) ? mask_rev[31:24] : // Mask rev (metal programmed)
195 (iaddr == 8'h05) ? mask_rev[23:16] : // Mask rev (metal programmed)
196 (iaddr == 8'h06) ? mask_rev[15:8] : // Mask rev (metal programmed)
197 (iaddr == 8'h07) ? mask_rev[7:0] : // Mask rev (metal programmed)
198
199 (iaddr == 8'h08) ? {7'b0000000, pll_dco_ena} :
200 (iaddr == 8'h09) ? {7'b0000000, pll_bypass} :
201 (iaddr == 8'h0a) ? {7'b0000000, irq} :
202 (iaddr == 8'h0b) ? {7'b0000000, reset} :
203 (iaddr == 8'h0c) ? {7'b0000000, trap} :
204 (iaddr == 8'h0d) ? pll_trim[7:0] :
205 (iaddr == 8'h0e) ? pll_trim[15:8] :
206 (iaddr == 8'h0f) ? pll_trim[23:16] :
207 (iaddr == 8'h10) ? {6'b000000, pll_trim[25:24]} :
208 (iaddr == 8'h11) ? {5'b00000, pll_sel} :
209 (iaddr == 8'h12) ? {3'b000, pll_div} :
210 8'h00; // Default
211
212 // Register mapping and I/O to slave module
213
214 always @(posedge SCK or negedge RSTB) begin
215 if (RSTB == 1'b0) begin
216 // Set trim for PLL at (almost) slowest rate (~90MHz). However,
217 // pll_trim[12] must be set to zero for proper startup.
218 pll_trim <= 26'b11111111111110111111111111;
219 pll_sel <= 3'b000;
220 pll_div <= 5'b00100; // Default divide-by-8
221 pll_dco_ena <= 1'b1; // Default free-running PLL
222 pll_bypass <= 1'b1; // NOTE: Default bypass mode (don't use PLL)
223 irq <= 1'b0;
224 reset_reg <= 1'b0;
225 end else if (wrstb == 1'b1) begin
226 case (iaddr)
227 8'h08: begin
228 pll_dco_ena <= idata[0];
229 end
230 8'h09: begin
231 pll_bypass <= idata[0];
232 end
233 8'h0a: begin
234 irq <= idata[0];
235 end
236 8'h0b: begin
237 reset_reg <= idata[0];
238 end
239 // Register 0xc is read-only
240 8'h0d: begin
241 pll_trim[7:0] <= idata;
242 end
243 8'h0e: begin
244 pll_trim[15:8] <= idata;
245 end
246 8'h0f: begin
247 pll_trim[23:16] <= idata;
248 end
249 8'h10: begin
250 pll_trim[25:24] <= idata[1:0];
251 end
252 8'h11: begin
253 pll_sel <= idata[2:0];
254 end
255 8'h12: begin
256 pll_div <= idata[4:0];
257 end
258 endcase // (iaddr)
259 end
260 end
261endmodule // caravel_spi