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