blob: 961b29a3f9b1735d753a216097a03f573c2f2c51 [file] [log] [blame]
shalan0d14e6e2020-08-31 16:50:48 +02001module mprj_ctrl_wb #(
Tim Edwardsba328902020-10-27 15:03:22 -04002 parameter BASE_ADR = 32'h 2300_0000,
3 parameter XFER = 8'h 00,
4 parameter PWRDATA = 8'h 04,
5 parameter IODATA = 8'h 08, // One word per 32 IOs
6 parameter IOCONFIG = 8'h 20,
7 parameter IO_PADS = 32, // Number of IO control registers (may be > 32)
8 parameter PWR_PADS = 32 // Number of power control registers (always < 32)
shalan0d14e6e2020-08-31 16:50:48 +02009)(
10 input wb_clk_i,
11 input wb_rst_i,
12
13 input [31:0] wb_dat_i,
14 input [31:0] wb_adr_i,
15 input [3:0] wb_sel_i,
16 input wb_cyc_i,
17 input wb_stb_i,
18 input wb_we_i,
19
20 output [31:0] wb_dat_o,
21 output wb_ack_o,
22
Tim Edwards04ba17f2020-10-02 22:27:50 -040023 // Output is to serial loader
24 output serial_clock,
25 output serial_resetn,
26 output serial_data_out,
shalan0d14e6e2020-08-31 16:50:48 +020027
Tim Edwards496a08a2020-10-26 15:44:51 -040028 // Pass state of OEB bit on SDO and JTAG back to the core
29 // so that the function can be overridden for management output
30 output sdo_oenb_state,
31 output jtag_oenb_state,
32
Tim Edwards04ba17f2020-10-02 22:27:50 -040033 // Read/write data to each GPIO pad from management SoC
Tim Edwards44bab472020-10-04 22:09:54 -040034 input [IO_PADS-1:0] mgmt_gpio_in,
Tim Edwardsba328902020-10-27 15:03:22 -040035 output [IO_PADS-1:0] mgmt_gpio_out,
36
37 // Write data to power controls
38 output [PWR_PADS-1:0] pwr_ctrl_out
Tim Edwards04ba17f2020-10-02 22:27:50 -040039);
shalan0d14e6e2020-08-31 16:50:48 +020040 wire resetn;
41 wire valid;
42 wire ready;
43 wire [3:0] iomem_we;
44
45 assign resetn = ~wb_rst_i;
46 assign valid = wb_stb_i && wb_cyc_i;
47
48 assign iomem_we = wb_sel_i & {4{wb_we_i}};
49 assign wb_ack_o = ready;
50
51 mprj_ctrl #(
52 .BASE_ADR(BASE_ADR),
Tim Edwards04ba17f2020-10-02 22:27:50 -040053 .XFER(XFER),
Tim Edwardsba328902020-10-27 15:03:22 -040054 .PWRDATA(PWRDATA),
55 .IODATA(IODATA),
56 .IOCONFIG(IOCONFIG),
Tim Edwards04ba17f2020-10-02 22:27:50 -040057 .IO_PADS(IO_PADS),
Tim Edwardsc18c4742020-10-03 11:26:39 -040058 .PWR_PADS(PWR_PADS)
shalan0d14e6e2020-08-31 16:50:48 +020059 ) mprj_ctrl (
60 .clk(wb_clk_i),
61 .resetn(resetn),
62 .iomem_addr(wb_adr_i),
63 .iomem_valid(valid),
Tim Edwardsc18c4742020-10-03 11:26:39 -040064 .iomem_wstrb(iomem_we[1:0]),
shalan0d14e6e2020-08-31 16:50:48 +020065 .iomem_wdata(wb_dat_i),
66 .iomem_rdata(wb_dat_o),
67 .iomem_ready(ready),
Tim Edwards04ba17f2020-10-02 22:27:50 -040068
69 .serial_clock(serial_clock),
70 .serial_resetn(serial_resetn),
71 .serial_data_out(serial_data_out),
Tim Edwards496a08a2020-10-26 15:44:51 -040072 .sdo_oenb_state(sdo_oenb_state),
73 .jtag_oenb_state(jtag_oenb_state),
Tim Edwards44bab472020-10-04 22:09:54 -040074 // .mgmt_gpio_io(mgmt_gpio_io)
75 .mgmt_gpio_in(mgmt_gpio_in),
Tim Edwardsca2f3182020-10-06 10:05:11 -040076 .mgmt_gpio_out(mgmt_gpio_out)
shalan0d14e6e2020-08-31 16:50:48 +020077 );
78
79endmodule
80
81module mprj_ctrl #(
Tim Edwardsba328902020-10-27 15:03:22 -040082 parameter BASE_ADR = 32'h 2300_0000,
83 parameter XFER = 8'h 00,
84 parameter PWRDATA = 8'h 04,
85 parameter IODATA = 8'h 08,
86 parameter IOCONFIG = 8'h 20,
87 parameter IO_PADS = 32,
88 parameter PWR_PADS = 32,
89 parameter IO_CTRL_BITS = 13
shalan0d14e6e2020-08-31 16:50:48 +020090)(
91 input clk,
92 input resetn,
93
94 input [31:0] iomem_addr,
95 input iomem_valid,
Tim Edwardsc18c4742020-10-03 11:26:39 -040096 input [1:0] iomem_wstrb,
shalan0d14e6e2020-08-31 16:50:48 +020097 input [31:0] iomem_wdata,
shalan0d14e6e2020-08-31 16:50:48 +020098 output reg [31:0] iomem_rdata,
99 output reg iomem_ready,
100
Tim Edwards04ba17f2020-10-02 22:27:50 -0400101 output serial_clock,
102 output serial_resetn,
103 output serial_data_out,
Tim Edwards496a08a2020-10-26 15:44:51 -0400104 output sdo_oenb_state,
105 output jtag_oenb_state,
Tim Edwards44bab472020-10-04 22:09:54 -0400106 input [IO_PADS-1:0] mgmt_gpio_in,
Tim Edwardsca2f3182020-10-06 10:05:11 -0400107 output [IO_PADS-1:0] mgmt_gpio_out
shalan0d14e6e2020-08-31 16:50:48 +0200108);
Tim Edwardsc18c4742020-10-03 11:26:39 -0400109
Tim Edwards44bab472020-10-04 22:09:54 -0400110`define IDLE 2'b00
111`define START 2'b01
112`define XBYTE 2'b10
113`define LOAD 2'b11
Tim Edwardsc18c4742020-10-03 11:26:39 -0400114
Ahmed Ghazy0b6219d2020-10-26 15:43:57 +0200115 localparam IO_WORDS = (IO_PADS % 32 != 0) + (IO_PADS / 32);
Tim Edwards9eda80d2020-10-08 21:36:44 -0400116
Tim Edwardsba328902020-10-27 15:03:22 -0400117 localparam IO_BASE_ADR = (BASE_ADR | IOCONFIG);
118
Tim Edwards44bab472020-10-04 22:09:54 -0400119 localparam OEB = 1; // Offset of output enable in shift register.
120 localparam INP_DIS = 3; // Offset of input disable in shift register.
shalan0d14e6e2020-08-31 16:50:48 +0200121
Tim Edwardsba328902020-10-27 15:03:22 -0400122 reg [IO_CTRL_BITS-1:0] io_ctrl[IO_PADS-1:0]; // I/O control, 1 word per gpio pad
123 reg [IO_PADS-1:0] mgmt_gpio_outr; // I/O write data, 1 bit per gpio pad
Tim Edwardsca2f3182020-10-06 10:05:11 -0400124 wire [IO_PADS-1:0] mgmt_gpio_out; // I/O write data output when input disabled
Tim Edwardsba328902020-10-27 15:03:22 -0400125 reg [PWR_PADS-1:0] pwr_ctrl_out; // Power write data, 1 bit per power pad
126 reg xfer_ctrl; // Transfer control (1 bit)
shalan0d14e6e2020-08-31 16:50:48 +0200127
Tim Edwards9eda80d2020-10-08 21:36:44 -0400128 wire [IO_WORDS-1:0] io_data_sel; // wishbone selects
Tim Edwardsba328902020-10-27 15:03:22 -0400129 wire pwr_data_sel;
Tim Edwards04ba17f2020-10-02 22:27:50 -0400130 wire xfer_sel;
Tim Edwards9eda80d2020-10-08 21:36:44 -0400131 wire [IO_PADS-1:0] io_ctrl_sel;
Tim Edwards0445c082020-10-27 20:53:54 -0400132 wire [31:0] iomem_rdata_pre;
Tim Edwardsba328902020-10-27 15:03:22 -0400133
Tim Edwards44bab472020-10-04 22:09:54 -0400134 wire [IO_PADS-1:0] mgmt_gpio_in;
Tim Edwards04ba17f2020-10-02 22:27:50 -0400135
Tim Edwards496a08a2020-10-26 15:44:51 -0400136 wire sdo_oenb_state, jtag_oenb_state;
137
138 // JTAG and housekeeping SDO are normally controlled by their respective
139 // modules with OEB set to the default 1 value. If configured for an
140 // additional output by setting the OEB bit low, then pass this information
141 // back to the core so that the default signals can be overridden.
142
143 assign jtag_oenb_state = io_ctrl[0][OEB];
144 assign sdo_oenb_state = io_ctrl[1][OEB];
145
Tim Edwards0445c082020-10-27 20:53:54 -0400146 `define wtop (((i+1)*32 > IO_PADS) ? IO_PADS-1 : (i+1)*32-1)
147 `define wbot (i*32)
148 `define rtop (`wtop - `wbot)
Tim Edwards04ba17f2020-10-02 22:27:50 -0400149
shalan0d14e6e2020-08-31 16:50:48 +0200150 genvar i;
Tim Edwards9eda80d2020-10-08 21:36:44 -0400151
Tim Edwards0445c082020-10-27 20:53:54 -0400152 // Assign selection bits per address
153
154 assign xfer_sel = (iomem_addr[7:0] == XFER);
155 assign pwr_data_sel = (iomem_addr[7:0] == PWRDATA);
156
Tim Edwards9eda80d2020-10-08 21:36:44 -0400157 generate
158 for (i=0; i<IO_WORDS; i=i+1) begin
Tim Edwardsba328902020-10-27 15:03:22 -0400159 assign io_data_sel[i] = (iomem_addr[7:0] == (IODATA + i*4));
Tim Edwards9eda80d2020-10-08 21:36:44 -0400160 end
Tim Edwards9eda80d2020-10-08 21:36:44 -0400161
shalan0d14e6e2020-08-31 16:50:48 +0200162 for (i=0; i<IO_PADS; i=i+1) begin
Tim Edwards04ba17f2020-10-02 22:27:50 -0400163 assign io_ctrl_sel[i] = (iomem_addr[7:0] == (IO_BASE_ADR[7:0] + i*4));
Tim Edwardsca2f3182020-10-06 10:05:11 -0400164 assign mgmt_gpio_out[i] = (io_ctrl[i][INP_DIS] == 1'b1) ?
165 mgmt_gpio_outr[i] : 1'bz;
shalan0d14e6e2020-08-31 16:50:48 +0200166 end
167 endgenerate
168
Tim Edwards0445c082020-10-27 20:53:54 -0400169 // Set selection and iomem_rdata_pre
170
171 assign selected = xfer_sel || pwr_data_sel || (|io_data_sel) || (|io_ctrl_sel);
172
173 assign iomem_rdata_pre = (selected == 0) ? 0 :
174 (xfer_sel) ? {31'b0, busy} :
175 (pwr_data_sel) ? pwr_ctrl_out :
176 'bz;
177
178 generate
179 for (i=0; i<IO_WORDS; i=i+1) begin
180 assign iomem_rdata_pre = (io_data_sel[i]) ? mgmt_gpio_in[`wtop:`wbot] : 'bz;
181 end
182
183 for (i=0; i<IO_PADS; i=i+1) begin
184 assign iomem_rdata_pre = (io_ctrl_sel[i]) ? io_ctrl[i] : 'bz;
185 end
186 endgenerate
187
188 // General I/O transfer
189
190 always @(posedge clk) begin
191 if (!resetn) begin
192 iomem_rdata <= 0;
193 iomem_ready <= 0;
194 end else begin
195 iomem_ready <= 0;
196 if (iomem_valid && !iomem_ready && iomem_addr[31:8] == BASE_ADR[31:8]) begin
197 iomem_ready <= 1'b 1;
198
199 if (selected) begin
200 iomem_rdata <= iomem_rdata_pre;
201 end
202 end
203 end
204 end
205
206 // I/O write of xfer bit. Also handles iomem_ready signal and power data.
Tim Edwards04ba17f2020-10-02 22:27:50 -0400207
208 always @(posedge clk) begin
209 if (!resetn) begin
210 xfer_ctrl <= 0;
Tim Edwardsba328902020-10-27 15:03:22 -0400211 pwr_ctrl_out <= 0;
Tim Edwards04ba17f2020-10-02 22:27:50 -0400212 end else begin
213 iomem_ready <= 0;
Tim Edwardsc18c4742020-10-03 11:26:39 -0400214 if (iomem_valid && !iomem_ready && iomem_addr[31:8] == BASE_ADR[31:8]) begin
Tim Edwards9eda80d2020-10-08 21:36:44 -0400215 if (xfer_sel) begin
Tim Edwards251e0df2020-10-05 11:02:12 -0400216 if (iomem_wstrb[0]) xfer_ctrl <= iomem_wdata[0];
Tim Edwardsba328902020-10-27 15:03:22 -0400217 end else if (pwr_data_sel) begin
Tim Edwardsba328902020-10-27 15:03:22 -0400218 if (iomem_wstrb[0]) pwr_ctrl_out <= iomem_wdata[PWR_PADS-1:0];
Tim Edwards04ba17f2020-10-02 22:27:50 -0400219 end
Tim Edwards251e0df2020-10-05 11:02:12 -0400220 end else begin
221 xfer_ctrl <= 1'b0; // Immediately self-resetting
Tim Edwards04ba17f2020-10-02 22:27:50 -0400222 end
223 end
224 end
225
Tim Edwards9eda80d2020-10-08 21:36:44 -0400226 // I/O transfer of gpio data to/from user project region under management
227 // SoC control
228
Tim Edwards9eda80d2020-10-08 21:36:44 -0400229 generate
230 for (i=0; i<IO_WORDS; i=i+1) begin
231 always @(posedge clk) begin
232 if (!resetn) begin
233 mgmt_gpio_outr[`wtop:`wbot] <= 'd0;
234 end else begin
235 if (iomem_valid && !iomem_ready && iomem_addr[31:8] ==
236 BASE_ADR[31:8]) begin
237 if (io_data_sel[i]) begin
Tim Edwards9eda80d2020-10-08 21:36:44 -0400238 if (iomem_wstrb[0]) begin
239 mgmt_gpio_outr[`wtop:`wbot] <= iomem_wdata[`rtop:0];
240 end
241 end
242 end
243 end
244 end
245 end
Tim Edwards9eda80d2020-10-08 21:36:44 -0400246
shalan0d14e6e2020-08-31 16:50:48 +0200247 for (i=0; i<IO_PADS; i=i+1) begin
248 always @(posedge clk) begin
249 if (!resetn) begin
Tim Edwards251e0df2020-10-05 11:02:12 -0400250 // NOTE: This initialization must match the defaults passed
Tim Edwards496a08a2020-10-26 15:44:51 -0400251 // to the control blocks. Specifically, 0x1803 is for a
Tim Edwards251e0df2020-10-05 11:02:12 -0400252 // bidirectional pad, and 0x0403 is for a simple input pad
253 if (i < 2) begin
Tim Edwards496a08a2020-10-26 15:44:51 -0400254 io_ctrl[i] <= 'h1803;
Tim Edwards251e0df2020-10-05 11:02:12 -0400255 end else begin
256 io_ctrl[i] <= 'h0403;
257 end
shalan0d14e6e2020-08-31 16:50:48 +0200258 end else begin
Tim Edwardsba328902020-10-27 15:03:22 -0400259 if (iomem_valid && !iomem_ready &&
260 iomem_addr[31:8] == BASE_ADR[31:8]) begin
shalan0d14e6e2020-08-31 16:50:48 +0200261 if (io_ctrl_sel[i]) begin
Tim Edwardsc18c4742020-10-03 11:26:39 -0400262 // NOTE: Byte-wide write to io_ctrl is prohibited
shalan0d14e6e2020-08-31 16:50:48 +0200263 if (iomem_wstrb[0])
Tim Edwardsc18c4742020-10-03 11:26:39 -0400264 io_ctrl[i] <= iomem_wdata[IO_CTRL_BITS-1:0];
shalan0d14e6e2020-08-31 16:50:48 +0200265 end
266 end
267 end
268 end
269 end
270 endgenerate
271
Tim Edwards04ba17f2020-10-02 22:27:50 -0400272 reg [3:0] xfer_count;
273 reg [5:0] pad_count;
274 reg [1:0] xfer_state;
275 reg serial_clock;
276 reg serial_resetn;
Tim Edwards04ba17f2020-10-02 22:27:50 -0400277
Tim Edwardsc18c4742020-10-03 11:26:39 -0400278 reg [IO_CTRL_BITS-1:0] serial_data_staging;
279
Tim Edwards251e0df2020-10-05 11:02:12 -0400280 wire serial_data_out;
281 wire busy;
282
283 assign serial_data_out = serial_data_staging[IO_CTRL_BITS-1];
284 assign busy = (xfer_state != `IDLE);
285
Tim Edwardsc18c4742020-10-03 11:26:39 -0400286 always @(posedge clk or negedge resetn) begin
Tim Edwards04ba17f2020-10-02 22:27:50 -0400287 if (resetn == 1'b0) begin
288
Tim Edwards44bab472020-10-04 22:09:54 -0400289 xfer_state <= `IDLE;
Tim Edwards04ba17f2020-10-02 22:27:50 -0400290 xfer_count <= 4'd0;
Tim Edwards251e0df2020-10-05 11:02:12 -0400291 pad_count <= IO_PADS;
Tim Edwards04ba17f2020-10-02 22:27:50 -0400292 serial_resetn <= 1'b0;
293 serial_clock <= 1'b0;
Tim Edwards04ba17f2020-10-02 22:27:50 -0400294
295 end else begin
296
Tim Edwards44bab472020-10-04 22:09:54 -0400297 if (xfer_state == `IDLE) begin
Tim Edwards251e0df2020-10-05 11:02:12 -0400298 pad_count <= IO_PADS;
299 serial_resetn <= 1'b1;
Tim Edwards44bab472020-10-04 22:09:54 -0400300 serial_clock <= 1'b0;
301 if (xfer_ctrl == 1'b1) begin
302 xfer_state <= `START;
303 end
304 end else if (xfer_state == `START) begin
Tim Edwards04ba17f2020-10-02 22:27:50 -0400305 serial_resetn <= 1'b1;
306 serial_clock <= 1'b0;
307 xfer_count <= 6'd0;
Tim Edwards251e0df2020-10-05 11:02:12 -0400308 pad_count <= pad_count - 1;
309 xfer_state <= `XBYTE;
310 serial_data_staging <= io_ctrl[pad_count - 1];
Tim Edwards04ba17f2020-10-02 22:27:50 -0400311 end else if (xfer_state == `XBYTE) begin
312 serial_resetn <= 1'b1;
313 serial_clock <= ~serial_clock;
314 if (serial_clock == 1'b0) begin
Tim Edwards251e0df2020-10-05 11:02:12 -0400315 if (xfer_count == IO_CTRL_BITS - 1) begin
316 if (pad_count == 0) begin
317 xfer_state <= `LOAD;
318 end else begin
319 xfer_state <= `START;
320 end
Tim Edwards04ba17f2020-10-02 22:27:50 -0400321 end else begin
322 xfer_count <= xfer_count + 1;
323 end
324 end else begin
Tim Edwardsc18c4742020-10-03 11:26:39 -0400325 serial_data_staging <= {serial_data_staging[IO_CTRL_BITS-2:0], 1'b0};
Tim Edwards04ba17f2020-10-02 22:27:50 -0400326 end
327 end else if (xfer_state == `LOAD) begin
328 xfer_count <= xfer_count + 1;
329
330 /* Load sequence: Raise clock for final data shift in;
331 * Pulse reset low while clock is high
332 * Set clock back to zero.
333 * Return to idle mode.
334 */
335 if (xfer_count == 4'd0) begin
336 serial_clock <= 1'b1;
337 serial_resetn <= 1'b1;
338 end else if (xfer_count == 4'd1) begin
339 serial_clock <= 1'b1;
340 serial_resetn <= 1'b0;
341 end else if (xfer_count == 4'd2) begin
342 serial_clock <= 1'b1;
343 serial_resetn <= 1'b1;
344 end else if (xfer_count == 4'd3) begin
345 serial_resetn <= 1'b1;
346 serial_clock <= 1'b0;
Tim Edwards44bab472020-10-04 22:09:54 -0400347 xfer_state <= `IDLE;
Tim Edwards04ba17f2020-10-02 22:27:50 -0400348 end
349 end
350 end
351 end
352
353endmodule