blob: 37c27c86ae72f7d3456eae986f6e0297ecb6bb6f [file] [log] [blame]
agorararmard6c766a82020-12-10 18:13:12 +02001// SPDX-FileCopyrightText: 2020 Efabless Corporation
agorararmarde5780bf2020-12-09 21:27:56 +00002//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
agorararmardafa96ea2020-12-09 23:37:31 +020014// SPDX-License-Identifier: Apache-2.0
agorararmarde5780bf2020-12-09 21:27:56 +000015
Matt Venn08cd6eb2020-11-16 12:01:14 +010016`default_nettype none
Tim Edwards44bab472020-10-04 22:09:54 -040017//-------------------------------------
18// SPI controller for Caravel (PicoSoC)
19//-------------------------------------
20// Written by Tim Edwards
21// efabless, inc. September 27, 2020
22//-------------------------------------
23
24//-----------------------------------------------------------
25// This is a standalone slave SPI for the caravel chip that is
26// intended to be independent of the picosoc and independent
27// of all IP blocks except the power-on-reset. This SPI has
28// register outputs controlling the functions that critically
29// affect operation of the picosoc and so cannot be accessed
30// from the picosoc itself. This includes the PLL enables
31// and trim, and the crystal oscillator enable. It also has
32// a general reset for the picosoc, an IRQ input, a bypass for
33// the entire crystal oscillator and PLL chain, the
34// manufacturer and product IDs and product revision number.
35// To be independent of the 1.8V regulator, the slave SPI is
36// synthesized with the 3V digital library and runs off of
37// the 3V supply.
38//
39// This module is designed to be decoupled from the chip
40// padframe and redirected to the wishbone bus under
41// register control from the management SoC, such that the
42// contents can be accessed from the management core via the
43// SPI master.
44//
45//-----------------------------------------------------------
46
47//------------------------------------------------------------
48// Caravel defined registers:
49// Register 0: SPI status and control (unused & reserved)
50// Register 1 and 2: Manufacturer ID (0x0456) (readonly)
Tim Edwards81153202020-10-09 19:57:04 -040051// Register 3: Product ID (= 16) (readonly)
Tim Edwards44bab472020-10-04 22:09:54 -040052// Register 4-7: Mask revision (readonly) --- Externally programmed
53// with via programming. Via programmed with a script to match
54// each customer ID.
55//
Tim Edwards3245e2f2020-10-10 14:02:11 -040056// Register 8: PLL enables (2 bits)
Tim Edwards44bab472020-10-04 22:09:54 -040057// Register 9: PLL bypass (1 bit)
58// Register 10: IRQ (1 bit)
59// Register 11: reset (1 bit)
60// Register 12: trap (1 bit) (readonly)
61// Register 13-16: PLL trim (26 bits)
Tim Edwards3245e2f2020-10-10 14:02:11 -040062// Register 17: PLL output divider (3 bits)
63// Register 18: PLL feedback divider (5 bits)
Tim Edwards44bab472020-10-04 22:09:54 -040064//------------------------------------------------------------
65
66module housekeeping_spi(
Manar61dce922020-11-10 19:26:28 +020067`ifdef USE_POWER_PINS
Tim Edwards44bab472020-10-04 22:09:54 -040068 vdd, vss,
69`endif
70 RSTB, SCK, SDI, CSB, SDO, sdo_enb,
Tim Edwards3245e2f2020-10-10 14:02:11 -040071 pll_ena, pll_dco_ena, pll_div, pll_sel,
Tim Edwards7a8cbb12020-10-12 11:32:11 -040072 pll90_sel, pll_trim, pll_bypass, irq, reset,
73 trap, mask_rev_in, pass_thru_reset,
Tim Edwards44bab472020-10-04 22:09:54 -040074 pass_thru_mgmt_sck, pass_thru_mgmt_csb,
75 pass_thru_mgmt_sdi, pass_thru_mgmt_sdo,
76 pass_thru_user_sck, pass_thru_user_csb,
77 pass_thru_user_sdi, pass_thru_user_sdo
78);
79
Manar61dce922020-11-10 19:26:28 +020080`ifdef USE_POWER_PINS
Tim Edwards44bab472020-10-04 22:09:54 -040081 inout vdd; // 3.3V supply
82 inout vss; // common ground
83`endif
84
85 input RSTB; // from padframe
86
87 input SCK; // from padframe
88 input SDI; // from padframe
89 input CSB; // from padframe
90 output SDO; // to padframe
91 output sdo_enb; // to padframe
92
Tim Edwards3245e2f2020-10-10 14:02:11 -040093 output pll_ena;
Tim Edwards44bab472020-10-04 22:09:54 -040094 output pll_dco_ena;
95 output [4:0] pll_div;
96 output [2:0] pll_sel;
Tim Edwards7a8cbb12020-10-12 11:32:11 -040097 output [2:0] pll90_sel;
Tim Edwards44bab472020-10-04 22:09:54 -040098 output [25:0] pll_trim;
99 output pll_bypass;
100 output irq;
101 output reset;
102 input trap;
103 input [31:0] mask_rev_in; // metal programmed; 3.3V domain
104
105 // Pass-through programming mode for management area SPI flash
106 output pass_thru_reset;
107 output pass_thru_mgmt_sck;
108 output pass_thru_mgmt_csb;
109 output pass_thru_mgmt_sdi;
110 input pass_thru_mgmt_sdo;
111
112 // Pass-through programming mode for user area SPI flash
113 output pass_thru_user_sck;
114 output pass_thru_user_csb;
115 output pass_thru_user_sdi;
116 input pass_thru_user_sdo;
117
118 reg [25:0] pll_trim;
119 reg [4:0] pll_div;
120 reg [2:0] pll_sel;
Tim Edwards7a8cbb12020-10-12 11:32:11 -0400121 reg [2:0] pll90_sel;
Tim Edwards44bab472020-10-04 22:09:54 -0400122 reg pll_dco_ena;
Tim Edwards3245e2f2020-10-10 14:02:11 -0400123 reg pll_ena;
Tim Edwards44bab472020-10-04 22:09:54 -0400124 reg pll_bypass;
125 reg reset_reg;
126 reg irq;
127
128 wire [7:0] odata;
129 wire [7:0] idata;
130 wire [7:0] iaddr;
131
132 wire trap;
133 wire rdstb;
134 wire wrstb;
135 wire pass_thru_mgmt; // Mode detected by spi_slave
136 wire pass_thru_mgmt_delay;
137 wire pass_thru_user; // Mode detected by spi_slave
138 wire pass_thru_user_delay;
Tim Edwards44bab472020-10-04 22:09:54 -0400139 wire loc_sdo;
Tim Edwards44bab472020-10-04 22:09:54 -0400140
Tim Edwards856b0922020-10-09 16:30:22 -0400141 // Pass-through mode handling. Signals may only be applied when the
142 // core processor is in reset.
Tim Edwards44bab472020-10-04 22:09:54 -0400143
Tim Edwards856b0922020-10-09 16:30:22 -0400144 assign pass_thru_mgmt_csb = reset ? ~pass_thru_mgmt_delay : 1'bz;
145 assign pass_thru_mgmt_sck = reset ? (pass_thru_mgmt ? SCK : 1'b0) : 1'bz;
146 assign pass_thru_mgmt_sdi = reset ? (pass_thru_mgmt ? SDI : 1'b0) : 1'bz;
Tim Edwards44bab472020-10-04 22:09:54 -0400147
Tim Edwards856b0922020-10-09 16:30:22 -0400148 assign pass_thru_user_csb = reset ? ~pass_thru_user_delay : 1'bz;
149 assign pass_thru_user_sck = reset ? (pass_thru_user ? SCK : 1'b0) : 1'bz;
150 assign pass_thru_user_sdi = reset ? (pass_thru_user ? SDI : 1'b0) : 1'bz;
Tim Edwards44bab472020-10-04 22:09:54 -0400151
152 assign SDO = pass_thru_mgmt ? pass_thru_mgmt_sdo :
153 pass_thru_user ? pass_thru_user_sdo : loc_sdo;
154 assign reset = pass_thru_reset ? 1'b1 : reset_reg;
155
156 // Instantiate the SPI slave module
157
158 housekeeping_spi_slave U1 (
159 .reset(~RSTB),
Tim Edwardsca2f3182020-10-06 10:05:11 -0400160 .SCK(SCK),
161 .SDI(SDI),
162 .CSB(CSB),
Tim Edwards44bab472020-10-04 22:09:54 -0400163 .SDO(loc_sdo),
Tim Edwardsca2f3182020-10-06 10:05:11 -0400164 .sdoenb(sdo_enb),
Tim Edwards44bab472020-10-04 22:09:54 -0400165 .idata(odata),
166 .odata(idata),
167 .oaddr(iaddr),
168 .rdstb(rdstb),
169 .wrstb(wrstb),
170 .pass_thru_mgmt(pass_thru_mgmt),
171 .pass_thru_mgmt_delay(pass_thru_mgmt_delay),
172 .pass_thru_user(pass_thru_user),
173 .pass_thru_user_delay(pass_thru_user_delay),
174 .pass_thru_reset(pass_thru_reset)
175 );
176
177 wire [11:0] mfgr_id;
178 wire [7:0] prod_id;
179 wire [31:0] mask_rev;
180
181 assign mfgr_id = 12'h456; // Hard-coded
182 assign prod_id = 8'h10; // Hard-coded
183 assign mask_rev = mask_rev_in; // Copy in to out.
184
185 // Send register contents to odata on SPI read command
186 // All values are 1-4 bits and no shadow registers are required.
187
188 assign odata =
189 (iaddr == 8'h00) ? 8'h00 : // SPI status (fixed)
190 (iaddr == 8'h01) ? {4'h0, mfgr_id[11:8]} : // Manufacturer ID (fixed)
191 (iaddr == 8'h02) ? mfgr_id[7:0] : // Manufacturer ID (fixed)
192 (iaddr == 8'h03) ? prod_id : // Product ID (fixed)
193 (iaddr == 8'h04) ? mask_rev[31:24] : // Mask rev (metal programmed)
194 (iaddr == 8'h05) ? mask_rev[23:16] : // Mask rev (metal programmed)
195 (iaddr == 8'h06) ? mask_rev[15:8] : // Mask rev (metal programmed)
196 (iaddr == 8'h07) ? mask_rev[7:0] : // Mask rev (metal programmed)
197
Tim Edwardsef2b68d2020-10-11 17:00:44 -0400198 (iaddr == 8'h08) ? {6'b000000, pll_dco_ena, pll_ena} :
Tim Edwards44bab472020-10-04 22:09:54 -0400199 (iaddr == 8'h09) ? {7'b0000000, pll_bypass} :
200 (iaddr == 8'h0a) ? {7'b0000000, irq} :
201 (iaddr == 8'h0b) ? {7'b0000000, reset} :
202 (iaddr == 8'h0c) ? {7'b0000000, trap} :
203 (iaddr == 8'h0d) ? pll_trim[7:0] :
204 (iaddr == 8'h0e) ? pll_trim[15:8] :
205 (iaddr == 8'h0f) ? pll_trim[23:16] :
206 (iaddr == 8'h10) ? {6'b000000, pll_trim[25:24]} :
Tim Edwards7a8cbb12020-10-12 11:32:11 -0400207 (iaddr == 8'h11) ? {2'b00, pll90_sel, pll_sel} :
Tim Edwards44bab472020-10-04 22:09:54 -0400208 (iaddr == 8'h12) ? {3'b000, pll_div} :
209 8'h00; // Default
210
211 // Register mapping and I/O to slave module
212
213 always @(posedge SCK or negedge RSTB) begin
214 if (RSTB == 1'b0) begin
215 // Set trim for PLL at (almost) slowest rate (~90MHz). However,
216 // pll_trim[12] must be set to zero for proper startup.
217 pll_trim <= 26'b11111111111110111111111111;
Tim Edwards3245e2f2020-10-10 14:02:11 -0400218 pll_sel <= 3'b010; // Default output divider divide-by-2
Tim Edwards7a8cbb12020-10-12 11:32:11 -0400219 pll90_sel <= 3'b010; // Default secondary output divider divide-by-2
Tim Edwards3245e2f2020-10-10 14:02:11 -0400220 pll_div <= 5'b00100; // Default feedback divider divide-by-8
Tim Edwards44bab472020-10-04 22:09:54 -0400221 pll_dco_ena <= 1'b1; // Default free-running PLL
Tim Edwards3245e2f2020-10-10 14:02:11 -0400222 pll_ena <= 1'b0; // Default PLL turned off
223 pll_bypass <= 1'b1; // Default bypass mode (don't use PLL)
Tim Edwards44bab472020-10-04 22:09:54 -0400224 irq <= 1'b0;
225 reset_reg <= 1'b0;
226 end else if (wrstb == 1'b1) begin
227 case (iaddr)
228 8'h08: begin
Tim Edwards3245e2f2020-10-10 14:02:11 -0400229 pll_ena <= idata[0];
230 pll_dco_ena <= idata[1];
Tim Edwards44bab472020-10-04 22:09:54 -0400231 end
232 8'h09: begin
233 pll_bypass <= idata[0];
234 end
235 8'h0a: begin
236 irq <= idata[0];
237 end
238 8'h0b: begin
239 reset_reg <= idata[0];
240 end
241 // Register 0xc is read-only
242 8'h0d: begin
243 pll_trim[7:0] <= idata;
244 end
245 8'h0e: begin
246 pll_trim[15:8] <= idata;
247 end
248 8'h0f: begin
249 pll_trim[23:16] <= idata;
250 end
251 8'h10: begin
252 pll_trim[25:24] <= idata[1:0];
253 end
254 8'h11: begin
255 pll_sel <= idata[2:0];
Tim Edwards7a8cbb12020-10-12 11:32:11 -0400256 pll90_sel <= idata[5:3];
Tim Edwards44bab472020-10-04 22:09:54 -0400257 end
258 8'h12: begin
259 pll_div <= idata[4:0];
260 end
261 endcase // (iaddr)
262 end
263 end
264endmodule // housekeeping_spi
265
266//------------------------------------------------------
267// housekeeping_spi_slave.v
268//------------------------------------------------------
269// General purpose SPI slave module for the Caravel chip
270//------------------------------------------------------
271// Written by Tim Edwards
272// efabless, inc., September 28, 2020
273//------------------------------------------------
274// This file is distributed free and open source
275//------------------------------------------------
276
277// SCK --- Clock input
278// SDI --- Data input
279// SDO --- Data output
280// CSB --- Chip select (sense negative)
281// idata --- Data from chip to transmit out, in 8 bits
282// odata --- Input data to chip, in 8 bits
283// addr --- Decoded address to upstream circuits
284// rdstb --- Read strobe, tells upstream circuit to supply next byte to idata
285// wrstb --- Write strobe, tells upstream circuit to latch odata.
286
287// Data format (general purpose):
288// 8 bit format
289// 1st byte: Command word (see below)
290// 2nd byte: Address word (register 0 to 255)
291// 3rd byte: Data word (value 0 to 255)
292
293// Command format:
294// 00000000 No operation
295// 10000000 Write until CSB raised
296// 01000000 Read until CSB raised
297// 11000000 Simultaneous read/write until CSB raised
298// 11000100 Pass-through read/write to management area flash SPI until CSB raised
Tim Edwardsb78e1c12020-10-09 11:51:48 -0400299// 11000010 Pass-through read/write to user area flash SPI until CSB raised
Tim Edwards44bab472020-10-04 22:09:54 -0400300// wrnnn000 Read/write as above, for nnn = 1 to 7 bytes, then terminate
301
302// Lower three bits are reserved for future use.
303// All serial bytes are read and written msb first.
304
305// Fixed control and status registers
306
307// Address 0 is reserved and contains flags for SPI mode. This is
308// currently undefined and is always value 0.
309// Address 1 is reserved and contains manufacturer ID low 8 bits.
310// Address 2 is reserved and contains manufacturer ID high 4 bits.
311// Address 3 is reserved and contains product ID (8 bits).
312// Addresses 4 to 7 are reserved and contain the mask ID (32 bits).
313// Addresses 8 to 255 are available for general purpose use.
314
315`define COMMAND 3'b000
316`define ADDRESS 3'b001
317`define DATA 3'b010
318`define USERPASS 3'b100
319`define MGMTPASS 3'b101
320
321module housekeeping_spi_slave(reset, SCK, SDI, CSB, SDO,
322 sdoenb, idata, odata, oaddr, rdstb, wrstb,
323 pass_thru_mgmt, pass_thru_mgmt_delay,
324 pass_thru_user, pass_thru_user_delay, pass_thru_reset);
325
326 input reset;
327 input SCK;
328 input SDI;
329 input CSB;
330 output SDO;
331 output sdoenb;
332 input [7:0] idata;
333 output [7:0] odata;
334 output [7:0] oaddr;
335 output rdstb;
336 output wrstb;
337 output pass_thru_mgmt;
338 output pass_thru_mgmt_delay;
339 output pass_thru_user;
340 output pass_thru_user_delay;
341 output pass_thru_reset;
342
343 reg [7:0] addr;
344 reg wrstb;
345 reg rdstb;
346 reg sdoenb;
347 reg [2:0] state;
348 reg [2:0] count;
349 reg writemode;
350 reg readmode;
351 reg [2:0] fixed;
352 wire [7:0] odata;
353 reg [6:0] predata;
354 wire [7:0] oaddr;
355 reg [7:0] ldata;
356 reg pass_thru_mgmt;
357 reg pass_thru_mgmt_delay;
358 reg pre_pass_thru_mgmt;
359 reg pass_thru_user;
360 reg pass_thru_user_delay;
361 reg pre_pass_thru_user;
362 wire csb_reset;
363
364 assign odata = {predata, SDI};
365 assign oaddr = (state == `ADDRESS) ? {addr[6:0], SDI} : addr;
366 assign SDO = ldata[7];
367 assign csb_reset = CSB | reset;
368 assign pass_thru_reset = pass_thru_mgmt_delay | pre_pass_thru_mgmt;
369
370 // Readback data is captured on the falling edge of SCK so that
371 // it is guaranteed valid at the next rising edge.
372 always @(negedge SCK or posedge csb_reset) begin
373 if (csb_reset == 1'b1) begin
374 wrstb <= 1'b0;
375 ldata <= 8'b00000000;
376 sdoenb <= 1'b1;
377 end else begin
378
379 // After CSB low, 1st SCK starts command
380
381 if (state == `DATA) begin
382 if (readmode == 1'b1) begin
383 sdoenb <= 1'b0;
384 if (count == 3'b000) begin
385 ldata <= idata;
386 end else begin
387 ldata <= {ldata[6:0], 1'b0}; // Shift out
388 end
389 end else begin
390 sdoenb <= 1'b1;
391 end
392
393 // Apply write strobe on SCK negative edge on the next-to-last
394 // data bit so that it updates data on the rising edge of SCK
395 // on the last data bit.
396
397 if (count == 3'b111) begin
398 if (writemode == 1'b1) begin
399 wrstb <= 1'b1;
400 end
401 end else begin
402 wrstb <= 1'b0;
403 end
404 end else if (state == `MGMTPASS || state == `USERPASS) begin
405 wrstb <= 1'b0;
406 sdoenb <= 1'b0;
407 end else begin
408 wrstb <= 1'b0;
409 sdoenb <= 1'b1;
410 end // ! state `DATA
411 end // ! csb_reset
412 end // always @ ~SCK
413
414 always @(posedge SCK or posedge csb_reset) begin
415 if (csb_reset == 1'b1) begin
416 // Default state on reset
417 addr <= 8'h00;
418 rdstb <= 1'b0;
419 predata <= 7'b0000000;
420 state <= `COMMAND;
421 count <= 3'b000;
422 readmode <= 1'b0;
423 writemode <= 1'b0;
424 fixed <= 3'b000;
425 pass_thru_mgmt <= 1'b0;
426 pass_thru_mgmt_delay <= 1'b0;
427 pre_pass_thru_mgmt <= 1'b0;
428 pass_thru_user = 1'b0;
429 pass_thru_user_delay <= 1'b0;
430 pre_pass_thru_user <= 1'b0;
431 end else begin
432 // After csb_reset low, 1st SCK starts command
433 if (state == `COMMAND) begin
434 rdstb <= 1'b0;
435 count <= count + 1;
436 if (count == 3'b000) begin
437 writemode <= SDI;
438 end else if (count == 3'b001) begin
439 readmode <= SDI;
440 end else if (count < 3'b101) begin
441 fixed <= {fixed[1:0], SDI};
Tim Edwardsb78e1c12020-10-09 11:51:48 -0400442 end else if (count == 3'b101) begin
443 pre_pass_thru_mgmt <= SDI;
444 end else if (count == 3'b110) begin
445 pre_pass_thru_user <= SDI;
Tim Edwards44bab472020-10-04 22:09:54 -0400446 pass_thru_mgmt_delay <= pre_pass_thru_mgmt;
Tim Edwards44bab472020-10-04 22:09:54 -0400447 end else if (count == 3'b111) begin
Tim Edwardsb78e1c12020-10-09 11:51:48 -0400448 pass_thru_user_delay <= pre_pass_thru_user;
Tim Edwards44bab472020-10-04 22:09:54 -0400449 if (pre_pass_thru_mgmt == 1'b1) begin
450 state <= `MGMTPASS;
451 pre_pass_thru_mgmt <= 1'b0;
452 end else if (pre_pass_thru_user == 1'b1) begin
453 state <= `USERPASS;
454 pre_pass_thru_user <= 1'b0;
455 end else begin
456 state <= `ADDRESS;
457 end
458 end
459 end else if (state == `ADDRESS) begin
460 count <= count + 1;
461 addr <= {addr[6:0], SDI};
462 if (count == 3'b111) begin
463 if (readmode == 1'b1) begin
464 rdstb <= 1'b1;
465 end
466 state <= `DATA;
467 end else begin
468 rdstb <= 1'b0;
469 end
470 end else if (state == `DATA) begin
471 predata <= {predata[6:0], SDI};
472 count <= count + 1;
473 if (count == 3'b111) begin
474 if (fixed == 3'b001) begin
475 state <= `COMMAND;
476 end else if (fixed != 3'b000) begin
477 fixed <= fixed - 1;
478 addr <= addr + 1; // Auto increment address (fixed)
479 end else begin
480 addr <= addr + 1; // Auto increment address (streaming)
481 end
482 end else begin
483 rdstb <= 1'b0;
484 end
Tim Edwardsb78e1c12020-10-09 11:51:48 -0400485 end else if (state == `MGMTPASS) begin
486 pass_thru_mgmt <= 1'b1;
487 end else if (state == `USERPASS) begin
488 pass_thru_user <= 1'b1;
489 end // ! state `DATA | `MGMTPASS | `USERPASS
Tim Edwards44bab472020-10-04 22:09:54 -0400490 end // ! csb_reset
491 end // always @ SCK
492
493endmodule // housekeeping_spi_slave
Tim Edwards581068f2020-11-19 12:45:25 -0500494`default_nettype wire