blob: 2942b2744e6f5cc6dd8bc959e12717b98fcecaaf [file] [log] [blame]
Tim Edwards44bab472020-10-04 22:09:54 -04001//-------------------------------------
2// SPI controller for Caravel (PicoSoC)
3//-------------------------------------
4// Written by Tim Edwards
5// efabless, inc. September 27, 2020
6//-------------------------------------
7
8//-----------------------------------------------------------
9// This is a standalone slave SPI for the caravel chip that is
10// intended to be independent of the picosoc and independent
11// of all IP blocks except the power-on-reset. This SPI has
12// register outputs controlling the functions that critically
13// affect operation of the picosoc and so cannot be accessed
14// from the picosoc itself. This includes the PLL enables
15// and trim, and the crystal oscillator enable. It also has
16// a general reset for the picosoc, an IRQ input, a bypass for
17// the entire crystal oscillator and PLL chain, the
18// manufacturer and product IDs and product revision number.
19// To be independent of the 1.8V regulator, the slave SPI is
20// synthesized with the 3V digital library and runs off of
21// the 3V supply.
22//
23// This module is designed to be decoupled from the chip
24// padframe and redirected to the wishbone bus under
25// register control from the management SoC, such that the
26// contents can be accessed from the management core via the
27// SPI master.
28//
29//-----------------------------------------------------------
30
31//------------------------------------------------------------
32// Caravel defined registers:
33// Register 0: SPI status and control (unused & reserved)
34// Register 1 and 2: Manufacturer ID (0x0456) (readonly)
Tim Edwards81153202020-10-09 19:57:04 -040035// Register 3: Product ID (= 16) (readonly)
Tim Edwards44bab472020-10-04 22:09:54 -040036// Register 4-7: Mask revision (readonly) --- Externally programmed
37// with via programming. Via programmed with a script to match
38// each customer ID.
39//
Tim Edwards3245e2f2020-10-10 14:02:11 -040040// Register 8: PLL enables (2 bits)
Tim Edwards44bab472020-10-04 22:09:54 -040041// Register 9: PLL bypass (1 bit)
42// Register 10: IRQ (1 bit)
43// Register 11: reset (1 bit)
44// Register 12: trap (1 bit) (readonly)
45// Register 13-16: PLL trim (26 bits)
Tim Edwards3245e2f2020-10-10 14:02:11 -040046// Register 17: PLL output divider (3 bits)
47// Register 18: PLL feedback divider (5 bits)
Tim Edwards44bab472020-10-04 22:09:54 -040048//------------------------------------------------------------
49
50module housekeeping_spi(
51`ifdef LVS
52 vdd, vss,
53`endif
54 RSTB, SCK, SDI, CSB, SDO, sdo_enb,
Tim Edwards3245e2f2020-10-10 14:02:11 -040055 pll_ena, pll_dco_ena, pll_div, pll_sel,
Tim Edwards7a8cbb12020-10-12 11:32:11 -040056 pll90_sel, pll_trim, pll_bypass, irq, reset,
57 trap, mask_rev_in, pass_thru_reset,
Tim Edwards44bab472020-10-04 22:09:54 -040058 pass_thru_mgmt_sck, pass_thru_mgmt_csb,
59 pass_thru_mgmt_sdi, pass_thru_mgmt_sdo,
60 pass_thru_user_sck, pass_thru_user_csb,
61 pass_thru_user_sdi, pass_thru_user_sdo
62);
63
64`ifdef LVS
65 inout vdd; // 3.3V supply
66 inout vss; // common ground
67`endif
68
69 input RSTB; // from padframe
70
71 input SCK; // from padframe
72 input SDI; // from padframe
73 input CSB; // from padframe
74 output SDO; // to padframe
75 output sdo_enb; // to padframe
76
Tim Edwards3245e2f2020-10-10 14:02:11 -040077 output pll_ena;
Tim Edwards44bab472020-10-04 22:09:54 -040078 output pll_dco_ena;
79 output [4:0] pll_div;
80 output [2:0] pll_sel;
Tim Edwards7a8cbb12020-10-12 11:32:11 -040081 output [2:0] pll90_sel;
Tim Edwards44bab472020-10-04 22:09:54 -040082 output [25:0] pll_trim;
83 output pll_bypass;
84 output irq;
85 output reset;
86 input trap;
87 input [31:0] mask_rev_in; // metal programmed; 3.3V domain
88
89 // Pass-through programming mode for management area SPI flash
90 output pass_thru_reset;
91 output pass_thru_mgmt_sck;
92 output pass_thru_mgmt_csb;
93 output pass_thru_mgmt_sdi;
94 input pass_thru_mgmt_sdo;
95
96 // Pass-through programming mode for user area SPI flash
97 output pass_thru_user_sck;
98 output pass_thru_user_csb;
99 output pass_thru_user_sdi;
100 input pass_thru_user_sdo;
101
102 reg [25:0] pll_trim;
103 reg [4:0] pll_div;
104 reg [2:0] pll_sel;
Tim Edwards7a8cbb12020-10-12 11:32:11 -0400105 reg [2:0] pll90_sel;
Tim Edwards44bab472020-10-04 22:09:54 -0400106 reg pll_dco_ena;
Tim Edwards3245e2f2020-10-10 14:02:11 -0400107 reg pll_ena;
Tim Edwards44bab472020-10-04 22:09:54 -0400108 reg pll_bypass;
109 reg reset_reg;
110 reg irq;
111
112 wire [7:0] odata;
113 wire [7:0] idata;
114 wire [7:0] iaddr;
115
116 wire trap;
117 wire rdstb;
118 wire wrstb;
119 wire pass_thru_mgmt; // Mode detected by spi_slave
120 wire pass_thru_mgmt_delay;
121 wire pass_thru_user; // Mode detected by spi_slave
122 wire pass_thru_user_delay;
Tim Edwards44bab472020-10-04 22:09:54 -0400123 wire loc_sdo;
Tim Edwards44bab472020-10-04 22:09:54 -0400124
Tim Edwards856b0922020-10-09 16:30:22 -0400125 // Pass-through mode handling. Signals may only be applied when the
126 // core processor is in reset.
Tim Edwards44bab472020-10-04 22:09:54 -0400127
Tim Edwards856b0922020-10-09 16:30:22 -0400128 assign pass_thru_mgmt_csb = reset ? ~pass_thru_mgmt_delay : 1'bz;
129 assign pass_thru_mgmt_sck = reset ? (pass_thru_mgmt ? SCK : 1'b0) : 1'bz;
130 assign pass_thru_mgmt_sdi = reset ? (pass_thru_mgmt ? SDI : 1'b0) : 1'bz;
Tim Edwards44bab472020-10-04 22:09:54 -0400131
Tim Edwards856b0922020-10-09 16:30:22 -0400132 assign pass_thru_user_csb = reset ? ~pass_thru_user_delay : 1'bz;
133 assign pass_thru_user_sck = reset ? (pass_thru_user ? SCK : 1'b0) : 1'bz;
134 assign pass_thru_user_sdi = reset ? (pass_thru_user ? SDI : 1'b0) : 1'bz;
Tim Edwards44bab472020-10-04 22:09:54 -0400135
136 assign SDO = pass_thru_mgmt ? pass_thru_mgmt_sdo :
137 pass_thru_user ? pass_thru_user_sdo : loc_sdo;
138 assign reset = pass_thru_reset ? 1'b1 : reset_reg;
139
140 // Instantiate the SPI slave module
141
142 housekeeping_spi_slave U1 (
143 .reset(~RSTB),
Tim Edwardsca2f3182020-10-06 10:05:11 -0400144 .SCK(SCK),
145 .SDI(SDI),
146 .CSB(CSB),
Tim Edwards44bab472020-10-04 22:09:54 -0400147 .SDO(loc_sdo),
Tim Edwardsca2f3182020-10-06 10:05:11 -0400148 .sdoenb(sdo_enb),
Tim Edwards44bab472020-10-04 22:09:54 -0400149 .idata(odata),
150 .odata(idata),
151 .oaddr(iaddr),
152 .rdstb(rdstb),
153 .wrstb(wrstb),
154 .pass_thru_mgmt(pass_thru_mgmt),
155 .pass_thru_mgmt_delay(pass_thru_mgmt_delay),
156 .pass_thru_user(pass_thru_user),
157 .pass_thru_user_delay(pass_thru_user_delay),
158 .pass_thru_reset(pass_thru_reset)
159 );
160
161 wire [11:0] mfgr_id;
162 wire [7:0] prod_id;
163 wire [31:0] mask_rev;
164
165 assign mfgr_id = 12'h456; // Hard-coded
166 assign prod_id = 8'h10; // Hard-coded
167 assign mask_rev = mask_rev_in; // Copy in to out.
168
169 // Send register contents to odata on SPI read command
170 // All values are 1-4 bits and no shadow registers are required.
171
172 assign odata =
173 (iaddr == 8'h00) ? 8'h00 : // SPI status (fixed)
174 (iaddr == 8'h01) ? {4'h0, mfgr_id[11:8]} : // Manufacturer ID (fixed)
175 (iaddr == 8'h02) ? mfgr_id[7:0] : // Manufacturer ID (fixed)
176 (iaddr == 8'h03) ? prod_id : // Product ID (fixed)
177 (iaddr == 8'h04) ? mask_rev[31:24] : // Mask rev (metal programmed)
178 (iaddr == 8'h05) ? mask_rev[23:16] : // Mask rev (metal programmed)
179 (iaddr == 8'h06) ? mask_rev[15:8] : // Mask rev (metal programmed)
180 (iaddr == 8'h07) ? mask_rev[7:0] : // Mask rev (metal programmed)
181
Tim Edwardsef2b68d2020-10-11 17:00:44 -0400182 (iaddr == 8'h08) ? {6'b000000, pll_dco_ena, pll_ena} :
Tim Edwards44bab472020-10-04 22:09:54 -0400183 (iaddr == 8'h09) ? {7'b0000000, pll_bypass} :
184 (iaddr == 8'h0a) ? {7'b0000000, irq} :
185 (iaddr == 8'h0b) ? {7'b0000000, reset} :
186 (iaddr == 8'h0c) ? {7'b0000000, trap} :
187 (iaddr == 8'h0d) ? pll_trim[7:0] :
188 (iaddr == 8'h0e) ? pll_trim[15:8] :
189 (iaddr == 8'h0f) ? pll_trim[23:16] :
190 (iaddr == 8'h10) ? {6'b000000, pll_trim[25:24]} :
Tim Edwards7a8cbb12020-10-12 11:32:11 -0400191 (iaddr == 8'h11) ? {2'b00, pll90_sel, pll_sel} :
Tim Edwards44bab472020-10-04 22:09:54 -0400192 (iaddr == 8'h12) ? {3'b000, pll_div} :
193 8'h00; // Default
194
195 // Register mapping and I/O to slave module
196
197 always @(posedge SCK or negedge RSTB) begin
198 if (RSTB == 1'b0) begin
199 // Set trim for PLL at (almost) slowest rate (~90MHz). However,
200 // pll_trim[12] must be set to zero for proper startup.
201 pll_trim <= 26'b11111111111110111111111111;
Tim Edwards3245e2f2020-10-10 14:02:11 -0400202 pll_sel <= 3'b010; // Default output divider divide-by-2
Tim Edwards7a8cbb12020-10-12 11:32:11 -0400203 pll90_sel <= 3'b010; // Default secondary output divider divide-by-2
Tim Edwards3245e2f2020-10-10 14:02:11 -0400204 pll_div <= 5'b00100; // Default feedback divider divide-by-8
Tim Edwards44bab472020-10-04 22:09:54 -0400205 pll_dco_ena <= 1'b1; // Default free-running PLL
Tim Edwards3245e2f2020-10-10 14:02:11 -0400206 pll_ena <= 1'b0; // Default PLL turned off
207 pll_bypass <= 1'b1; // Default bypass mode (don't use PLL)
Tim Edwards44bab472020-10-04 22:09:54 -0400208 irq <= 1'b0;
209 reset_reg <= 1'b0;
210 end else if (wrstb == 1'b1) begin
211 case (iaddr)
212 8'h08: begin
Tim Edwards3245e2f2020-10-10 14:02:11 -0400213 pll_ena <= idata[0];
214 pll_dco_ena <= idata[1];
Tim Edwards44bab472020-10-04 22:09:54 -0400215 end
216 8'h09: begin
217 pll_bypass <= idata[0];
218 end
219 8'h0a: begin
220 irq <= idata[0];
221 end
222 8'h0b: begin
223 reset_reg <= idata[0];
224 end
225 // Register 0xc is read-only
226 8'h0d: begin
227 pll_trim[7:0] <= idata;
228 end
229 8'h0e: begin
230 pll_trim[15:8] <= idata;
231 end
232 8'h0f: begin
233 pll_trim[23:16] <= idata;
234 end
235 8'h10: begin
236 pll_trim[25:24] <= idata[1:0];
237 end
238 8'h11: begin
239 pll_sel <= idata[2:0];
Tim Edwards7a8cbb12020-10-12 11:32:11 -0400240 pll90_sel <= idata[5:3];
Tim Edwards44bab472020-10-04 22:09:54 -0400241 end
242 8'h12: begin
243 pll_div <= idata[4:0];
244 end
245 endcase // (iaddr)
246 end
247 end
248endmodule // housekeeping_spi
249
250//------------------------------------------------------
251// housekeeping_spi_slave.v
252//------------------------------------------------------
253// General purpose SPI slave module for the Caravel chip
254//------------------------------------------------------
255// Written by Tim Edwards
256// efabless, inc., September 28, 2020
257//------------------------------------------------
258// This file is distributed free and open source
259//------------------------------------------------
260
261// SCK --- Clock input
262// SDI --- Data input
263// SDO --- Data output
264// CSB --- Chip select (sense negative)
265// idata --- Data from chip to transmit out, in 8 bits
266// odata --- Input data to chip, in 8 bits
267// addr --- Decoded address to upstream circuits
268// rdstb --- Read strobe, tells upstream circuit to supply next byte to idata
269// wrstb --- Write strobe, tells upstream circuit to latch odata.
270
271// Data format (general purpose):
272// 8 bit format
273// 1st byte: Command word (see below)
274// 2nd byte: Address word (register 0 to 255)
275// 3rd byte: Data word (value 0 to 255)
276
277// Command format:
278// 00000000 No operation
279// 10000000 Write until CSB raised
280// 01000000 Read until CSB raised
281// 11000000 Simultaneous read/write until CSB raised
282// 11000100 Pass-through read/write to management area flash SPI until CSB raised
Tim Edwardsb78e1c12020-10-09 11:51:48 -0400283// 11000010 Pass-through read/write to user area flash SPI until CSB raised
Tim Edwards44bab472020-10-04 22:09:54 -0400284// wrnnn000 Read/write as above, for nnn = 1 to 7 bytes, then terminate
285
286// Lower three bits are reserved for future use.
287// All serial bytes are read and written msb first.
288
289// Fixed control and status registers
290
291// Address 0 is reserved and contains flags for SPI mode. This is
292// currently undefined and is always value 0.
293// Address 1 is reserved and contains manufacturer ID low 8 bits.
294// Address 2 is reserved and contains manufacturer ID high 4 bits.
295// Address 3 is reserved and contains product ID (8 bits).
296// Addresses 4 to 7 are reserved and contain the mask ID (32 bits).
297// Addresses 8 to 255 are available for general purpose use.
298
299`define COMMAND 3'b000
300`define ADDRESS 3'b001
301`define DATA 3'b010
302`define USERPASS 3'b100
303`define MGMTPASS 3'b101
304
305module housekeeping_spi_slave(reset, SCK, SDI, CSB, SDO,
306 sdoenb, idata, odata, oaddr, rdstb, wrstb,
307 pass_thru_mgmt, pass_thru_mgmt_delay,
308 pass_thru_user, pass_thru_user_delay, pass_thru_reset);
309
310 input reset;
311 input SCK;
312 input SDI;
313 input CSB;
314 output SDO;
315 output sdoenb;
316 input [7:0] idata;
317 output [7:0] odata;
318 output [7:0] oaddr;
319 output rdstb;
320 output wrstb;
321 output pass_thru_mgmt;
322 output pass_thru_mgmt_delay;
323 output pass_thru_user;
324 output pass_thru_user_delay;
325 output pass_thru_reset;
326
327 reg [7:0] addr;
328 reg wrstb;
329 reg rdstb;
330 reg sdoenb;
331 reg [2:0] state;
332 reg [2:0] count;
333 reg writemode;
334 reg readmode;
335 reg [2:0] fixed;
336 wire [7:0] odata;
337 reg [6:0] predata;
338 wire [7:0] oaddr;
339 reg [7:0] ldata;
340 reg pass_thru_mgmt;
341 reg pass_thru_mgmt_delay;
342 reg pre_pass_thru_mgmt;
343 reg pass_thru_user;
344 reg pass_thru_user_delay;
345 reg pre_pass_thru_user;
346 wire csb_reset;
347
348 assign odata = {predata, SDI};
349 assign oaddr = (state == `ADDRESS) ? {addr[6:0], SDI} : addr;
350 assign SDO = ldata[7];
351 assign csb_reset = CSB | reset;
352 assign pass_thru_reset = pass_thru_mgmt_delay | pre_pass_thru_mgmt;
353
354 // Readback data is captured on the falling edge of SCK so that
355 // it is guaranteed valid at the next rising edge.
356 always @(negedge SCK or posedge csb_reset) begin
357 if (csb_reset == 1'b1) begin
358 wrstb <= 1'b0;
359 ldata <= 8'b00000000;
360 sdoenb <= 1'b1;
361 end else begin
362
363 // After CSB low, 1st SCK starts command
364
365 if (state == `DATA) begin
366 if (readmode == 1'b1) begin
367 sdoenb <= 1'b0;
368 if (count == 3'b000) begin
369 ldata <= idata;
370 end else begin
371 ldata <= {ldata[6:0], 1'b0}; // Shift out
372 end
373 end else begin
374 sdoenb <= 1'b1;
375 end
376
377 // Apply write strobe on SCK negative edge on the next-to-last
378 // data bit so that it updates data on the rising edge of SCK
379 // on the last data bit.
380
381 if (count == 3'b111) begin
382 if (writemode == 1'b1) begin
383 wrstb <= 1'b1;
384 end
385 end else begin
386 wrstb <= 1'b0;
387 end
388 end else if (state == `MGMTPASS || state == `USERPASS) begin
389 wrstb <= 1'b0;
390 sdoenb <= 1'b0;
391 end else begin
392 wrstb <= 1'b0;
393 sdoenb <= 1'b1;
394 end // ! state `DATA
395 end // ! csb_reset
396 end // always @ ~SCK
397
398 always @(posedge SCK or posedge csb_reset) begin
399 if (csb_reset == 1'b1) begin
400 // Default state on reset
401 addr <= 8'h00;
402 rdstb <= 1'b0;
403 predata <= 7'b0000000;
404 state <= `COMMAND;
405 count <= 3'b000;
406 readmode <= 1'b0;
407 writemode <= 1'b0;
408 fixed <= 3'b000;
409 pass_thru_mgmt <= 1'b0;
410 pass_thru_mgmt_delay <= 1'b0;
411 pre_pass_thru_mgmt <= 1'b0;
412 pass_thru_user = 1'b0;
413 pass_thru_user_delay <= 1'b0;
414 pre_pass_thru_user <= 1'b0;
415 end else begin
416 // After csb_reset low, 1st SCK starts command
417 if (state == `COMMAND) begin
418 rdstb <= 1'b0;
419 count <= count + 1;
420 if (count == 3'b000) begin
421 writemode <= SDI;
422 end else if (count == 3'b001) begin
423 readmode <= SDI;
424 end else if (count < 3'b101) begin
425 fixed <= {fixed[1:0], SDI};
Tim Edwardsb78e1c12020-10-09 11:51:48 -0400426 end else if (count == 3'b101) begin
427 pre_pass_thru_mgmt <= SDI;
428 end else if (count == 3'b110) begin
429 pre_pass_thru_user <= SDI;
Tim Edwards44bab472020-10-04 22:09:54 -0400430 pass_thru_mgmt_delay <= pre_pass_thru_mgmt;
Tim Edwards44bab472020-10-04 22:09:54 -0400431 end else if (count == 3'b111) begin
Tim Edwardsb78e1c12020-10-09 11:51:48 -0400432 pass_thru_user_delay <= pre_pass_thru_user;
Tim Edwards44bab472020-10-04 22:09:54 -0400433 if (pre_pass_thru_mgmt == 1'b1) begin
434 state <= `MGMTPASS;
435 pre_pass_thru_mgmt <= 1'b0;
436 end else if (pre_pass_thru_user == 1'b1) begin
437 state <= `USERPASS;
438 pre_pass_thru_user <= 1'b0;
439 end else begin
440 state <= `ADDRESS;
441 end
442 end
443 end else if (state == `ADDRESS) begin
444 count <= count + 1;
445 addr <= {addr[6:0], SDI};
446 if (count == 3'b111) begin
447 if (readmode == 1'b1) begin
448 rdstb <= 1'b1;
449 end
450 state <= `DATA;
451 end else begin
452 rdstb <= 1'b0;
453 end
454 end else if (state == `DATA) begin
455 predata <= {predata[6:0], SDI};
456 count <= count + 1;
457 if (count == 3'b111) begin
458 if (fixed == 3'b001) begin
459 state <= `COMMAND;
460 end else if (fixed != 3'b000) begin
461 fixed <= fixed - 1;
462 addr <= addr + 1; // Auto increment address (fixed)
463 end else begin
464 addr <= addr + 1; // Auto increment address (streaming)
465 end
466 end else begin
467 rdstb <= 1'b0;
468 end
Tim Edwardsb78e1c12020-10-09 11:51:48 -0400469 end else if (state == `MGMTPASS) begin
470 pass_thru_mgmt <= 1'b1;
471 end else if (state == `USERPASS) begin
472 pass_thru_user <= 1'b1;
473 end // ! state `DATA | `MGMTPASS | `USERPASS
Tim Edwards44bab472020-10-04 22:09:54 -0400474 end // ! csb_reset
475 end // always @ SCK
476
477endmodule // housekeeping_spi_slave