blob: 0f385de928e657af81b5c1e9a54b4c846a48f453 [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
Ahmed Ghazy22d29d62020-10-28 03:42:02 +02006 parameter IOCONFIG = 8'h 20
shalan0d14e6e2020-08-31 16:50:48 +02007)(
8 input wb_clk_i,
9 input wb_rst_i,
10
11 input [31:0] wb_dat_i,
12 input [31:0] wb_adr_i,
13 input [3:0] wb_sel_i,
14 input wb_cyc_i,
15 input wb_stb_i,
16 input wb_we_i,
17
18 output [31:0] wb_dat_o,
19 output wb_ack_o,
20
Tim Edwards04ba17f2020-10-02 22:27:50 -040021 // Output is to serial loader
22 output serial_clock,
23 output serial_resetn,
24 output serial_data_out,
shalan0d14e6e2020-08-31 16:50:48 +020025
Tim Edwards496a08a2020-10-26 15:44:51 -040026 // Pass state of OEB bit on SDO and JTAG back to the core
27 // so that the function can be overridden for management output
28 output sdo_oenb_state,
29 output jtag_oenb_state,
30
Tim Edwards04ba17f2020-10-02 22:27:50 -040031 // Read/write data to each GPIO pad from management SoC
Ahmed Ghazy22d29d62020-10-28 03:42:02 +020032 input [`MPRJ_IO_PADS-1:0] mgmt_gpio_in,
33 output [`MPRJ_IO_PADS-1:0] mgmt_gpio_out,
Tim Edwardsba328902020-10-27 15:03:22 -040034
35 // Write data to power controls
Ahmed Ghazy22d29d62020-10-28 03:42:02 +020036 output [`MPRJ_PWR_PADS-1:0] pwr_ctrl_out
Tim Edwards04ba17f2020-10-02 22:27:50 -040037);
shalan0d14e6e2020-08-31 16:50:48 +020038 wire resetn;
39 wire valid;
40 wire ready;
41 wire [3:0] iomem_we;
42
43 assign resetn = ~wb_rst_i;
44 assign valid = wb_stb_i && wb_cyc_i;
45
46 assign iomem_we = wb_sel_i & {4{wb_we_i}};
47 assign wb_ack_o = ready;
48
49 mprj_ctrl #(
50 .BASE_ADR(BASE_ADR),
Tim Edwards04ba17f2020-10-02 22:27:50 -040051 .XFER(XFER),
Tim Edwardsba328902020-10-27 15:03:22 -040052 .PWRDATA(PWRDATA),
53 .IODATA(IODATA),
Ahmed Ghazy22d29d62020-10-28 03:42:02 +020054 .IOCONFIG(IOCONFIG)
shalan0d14e6e2020-08-31 16:50:48 +020055 ) mprj_ctrl (
56 .clk(wb_clk_i),
57 .resetn(resetn),
58 .iomem_addr(wb_adr_i),
59 .iomem_valid(valid),
Tim Edwardsc18c4742020-10-03 11:26:39 -040060 .iomem_wstrb(iomem_we[1:0]),
shalan0d14e6e2020-08-31 16:50:48 +020061 .iomem_wdata(wb_dat_i),
62 .iomem_rdata(wb_dat_o),
63 .iomem_ready(ready),
Tim Edwards04ba17f2020-10-02 22:27:50 -040064
65 .serial_clock(serial_clock),
66 .serial_resetn(serial_resetn),
67 .serial_data_out(serial_data_out),
Tim Edwards496a08a2020-10-26 15:44:51 -040068 .sdo_oenb_state(sdo_oenb_state),
69 .jtag_oenb_state(jtag_oenb_state),
Tim Edwards44bab472020-10-04 22:09:54 -040070 // .mgmt_gpio_io(mgmt_gpio_io)
71 .mgmt_gpio_in(mgmt_gpio_in),
Tim Edwardsca2f3182020-10-06 10:05:11 -040072 .mgmt_gpio_out(mgmt_gpio_out)
shalan0d14e6e2020-08-31 16:50:48 +020073 );
74
75endmodule
76
77module mprj_ctrl #(
Tim Edwardsba328902020-10-27 15:03:22 -040078 parameter BASE_ADR = 32'h 2300_0000,
79 parameter XFER = 8'h 00,
80 parameter PWRDATA = 8'h 04,
81 parameter IODATA = 8'h 08,
82 parameter IOCONFIG = 8'h 20,
Tim Edwardsba328902020-10-27 15:03:22 -040083 parameter IO_CTRL_BITS = 13
shalan0d14e6e2020-08-31 16:50:48 +020084)(
85 input clk,
86 input resetn,
87
88 input [31:0] iomem_addr,
89 input iomem_valid,
Tim Edwardsc18c4742020-10-03 11:26:39 -040090 input [1:0] iomem_wstrb,
shalan0d14e6e2020-08-31 16:50:48 +020091 input [31:0] iomem_wdata,
shalan0d14e6e2020-08-31 16:50:48 +020092 output reg [31:0] iomem_rdata,
93 output reg iomem_ready,
94
Tim Edwards04ba17f2020-10-02 22:27:50 -040095 output serial_clock,
96 output serial_resetn,
97 output serial_data_out,
Tim Edwards496a08a2020-10-26 15:44:51 -040098 output sdo_oenb_state,
99 output jtag_oenb_state,
Ahmed Ghazy22d29d62020-10-28 03:42:02 +0200100 input [`MPRJ_IO_PADS-1:0] mgmt_gpio_in,
101 output [`MPRJ_IO_PADS-1:0] mgmt_gpio_out
shalan0d14e6e2020-08-31 16:50:48 +0200102);
Tim Edwardsc18c4742020-10-03 11:26:39 -0400103
Tim Edwards44bab472020-10-04 22:09:54 -0400104`define IDLE 2'b00
105`define START 2'b01
106`define XBYTE 2'b10
107`define LOAD 2'b11
Tim Edwardsc18c4742020-10-03 11:26:39 -0400108
Ahmed Ghazy22d29d62020-10-28 03:42:02 +0200109 localparam IO_WORDS = (`MPRJ_IO_PADS % 32 != 0) + (`MPRJ_IO_PADS / 32);
Tim Edwards9eda80d2020-10-08 21:36:44 -0400110
Tim Edwardsba328902020-10-27 15:03:22 -0400111 localparam IO_BASE_ADR = (BASE_ADR | IOCONFIG);
112
Tim Edwards44bab472020-10-04 22:09:54 -0400113 localparam OEB = 1; // Offset of output enable in shift register.
114 localparam INP_DIS = 3; // Offset of input disable in shift register.
shalan0d14e6e2020-08-31 16:50:48 +0200115
Ahmed Ghazy22d29d62020-10-28 03:42:02 +0200116 reg [IO_CTRL_BITS-1:0] io_ctrl[`MPRJ_IO_PADS-1:0]; // I/O control, 1 word per gpio pad
117 reg [`MPRJ_IO_PADS-1:0] mgmt_gpio_outr; // I/O write data, 1 bit per gpio pad
118 wire [`MPRJ_IO_PADS-1:0] mgmt_gpio_out; // I/O write data output when input disabled
119 reg [`MPRJ_PWR_PADS-1:0] pwr_ctrl_out; // Power write data, 1 bit per power pad
Tim Edwardsba328902020-10-27 15:03:22 -0400120 reg xfer_ctrl; // Transfer control (1 bit)
shalan0d14e6e2020-08-31 16:50:48 +0200121
Tim Edwards9eda80d2020-10-08 21:36:44 -0400122 wire [IO_WORDS-1:0] io_data_sel; // wishbone selects
Tim Edwardsba328902020-10-27 15:03:22 -0400123 wire pwr_data_sel;
Tim Edwards04ba17f2020-10-02 22:27:50 -0400124 wire xfer_sel;
Ahmed Ghazy22d29d62020-10-28 03:42:02 +0200125 wire [`MPRJ_IO_PADS-1:0] io_ctrl_sel;
Tim Edwards0445c082020-10-27 20:53:54 -0400126 wire [31:0] iomem_rdata_pre;
Tim Edwardsba328902020-10-27 15:03:22 -0400127
Ahmed Ghazy22d29d62020-10-28 03:42:02 +0200128 wire [`MPRJ_IO_PADS-1:0] mgmt_gpio_in;
Tim Edwards04ba17f2020-10-02 22:27:50 -0400129
Tim Edwards496a08a2020-10-26 15:44:51 -0400130 wire sdo_oenb_state, jtag_oenb_state;
131
132 // JTAG and housekeeping SDO are normally controlled by their respective
133 // modules with OEB set to the default 1 value. If configured for an
134 // additional output by setting the OEB bit low, then pass this information
135 // back to the core so that the default signals can be overridden.
136
137 assign jtag_oenb_state = io_ctrl[0][OEB];
138 assign sdo_oenb_state = io_ctrl[1][OEB];
139
Ahmed Ghazy22d29d62020-10-28 03:42:02 +0200140 `define wtop (((i+1)*32 > `MPRJ_IO_PADS) ? `MPRJ_IO_PADS-1 : (i+1)*32-1)
Tim Edwards0445c082020-10-27 20:53:54 -0400141 `define wbot (i*32)
142 `define rtop (`wtop - `wbot)
Tim Edwards04ba17f2020-10-02 22:27:50 -0400143
shalan0d14e6e2020-08-31 16:50:48 +0200144 genvar i;
Tim Edwards9eda80d2020-10-08 21:36:44 -0400145
Tim Edwards0445c082020-10-27 20:53:54 -0400146 // Assign selection bits per address
147
148 assign xfer_sel = (iomem_addr[7:0] == XFER);
149 assign pwr_data_sel = (iomem_addr[7:0] == PWRDATA);
150
Tim Edwards9eda80d2020-10-08 21:36:44 -0400151 generate
152 for (i=0; i<IO_WORDS; i=i+1) begin
Tim Edwardsba328902020-10-27 15:03:22 -0400153 assign io_data_sel[i] = (iomem_addr[7:0] == (IODATA + i*4));
Tim Edwards9eda80d2020-10-08 21:36:44 -0400154 end
Tim Edwards9eda80d2020-10-08 21:36:44 -0400155
Ahmed Ghazy22d29d62020-10-28 03:42:02 +0200156 for (i=0; i<`MPRJ_IO_PADS; i=i+1) begin
Tim Edwards04ba17f2020-10-02 22:27:50 -0400157 assign io_ctrl_sel[i] = (iomem_addr[7:0] == (IO_BASE_ADR[7:0] + i*4));
Tim Edwardsca2f3182020-10-06 10:05:11 -0400158 assign mgmt_gpio_out[i] = (io_ctrl[i][INP_DIS] == 1'b1) ?
159 mgmt_gpio_outr[i] : 1'bz;
shalan0d14e6e2020-08-31 16:50:48 +0200160 end
161 endgenerate
162
Tim Edwards0445c082020-10-27 20:53:54 -0400163 // Set selection and iomem_rdata_pre
164
165 assign selected = xfer_sel || pwr_data_sel || (|io_data_sel) || (|io_ctrl_sel);
166
167 assign iomem_rdata_pre = (selected == 0) ? 0 :
168 (xfer_sel) ? {31'b0, busy} :
169 (pwr_data_sel) ? pwr_ctrl_out :
170 'bz;
171
172 generate
173 for (i=0; i<IO_WORDS; i=i+1) begin
174 assign iomem_rdata_pre = (io_data_sel[i]) ? mgmt_gpio_in[`wtop:`wbot] : 'bz;
175 end
176
Ahmed Ghazy22d29d62020-10-28 03:42:02 +0200177 for (i=0; i<`MPRJ_IO_PADS; i=i+1) begin
Tim Edwards0445c082020-10-27 20:53:54 -0400178 assign iomem_rdata_pre = (io_ctrl_sel[i]) ? io_ctrl[i] : 'bz;
179 end
180 endgenerate
181
182 // General I/O transfer
183
184 always @(posedge clk) begin
185 if (!resetn) begin
186 iomem_rdata <= 0;
187 iomem_ready <= 0;
188 end else begin
189 iomem_ready <= 0;
190 if (iomem_valid && !iomem_ready && iomem_addr[31:8] == BASE_ADR[31:8]) begin
191 iomem_ready <= 1'b 1;
192
193 if (selected) begin
194 iomem_rdata <= iomem_rdata_pre;
195 end
196 end
197 end
198 end
199
200 // I/O write of xfer bit. Also handles iomem_ready signal and power data.
Tim Edwards04ba17f2020-10-02 22:27:50 -0400201
202 always @(posedge clk) begin
203 if (!resetn) begin
204 xfer_ctrl <= 0;
Tim Edwardsba328902020-10-27 15:03:22 -0400205 pwr_ctrl_out <= 0;
Tim Edwards04ba17f2020-10-02 22:27:50 -0400206 end else begin
207 iomem_ready <= 0;
Tim Edwardsc18c4742020-10-03 11:26:39 -0400208 if (iomem_valid && !iomem_ready && iomem_addr[31:8] == BASE_ADR[31:8]) begin
Tim Edwards9eda80d2020-10-08 21:36:44 -0400209 if (xfer_sel) begin
Tim Edwards251e0df2020-10-05 11:02:12 -0400210 if (iomem_wstrb[0]) xfer_ctrl <= iomem_wdata[0];
Tim Edwardsba328902020-10-27 15:03:22 -0400211 end else if (pwr_data_sel) begin
Ahmed Ghazy22d29d62020-10-28 03:42:02 +0200212 if (iomem_wstrb[0]) pwr_ctrl_out <= iomem_wdata[`MPRJ_PWR_PADS-1:0];
Tim Edwards04ba17f2020-10-02 22:27:50 -0400213 end
Tim Edwards251e0df2020-10-05 11:02:12 -0400214 end else begin
215 xfer_ctrl <= 1'b0; // Immediately self-resetting
Tim Edwards04ba17f2020-10-02 22:27:50 -0400216 end
217 end
218 end
219
Tim Edwards9eda80d2020-10-08 21:36:44 -0400220 // I/O transfer of gpio data to/from user project region under management
221 // SoC control
222
Tim Edwards9eda80d2020-10-08 21:36:44 -0400223 generate
224 for (i=0; i<IO_WORDS; i=i+1) begin
225 always @(posedge clk) begin
226 if (!resetn) begin
227 mgmt_gpio_outr[`wtop:`wbot] <= 'd0;
228 end else begin
229 if (iomem_valid && !iomem_ready && iomem_addr[31:8] ==
230 BASE_ADR[31:8]) begin
231 if (io_data_sel[i]) begin
Tim Edwards9eda80d2020-10-08 21:36:44 -0400232 if (iomem_wstrb[0]) begin
233 mgmt_gpio_outr[`wtop:`wbot] <= iomem_wdata[`rtop:0];
234 end
235 end
236 end
237 end
238 end
239 end
Tim Edwards9eda80d2020-10-08 21:36:44 -0400240
Ahmed Ghazy22d29d62020-10-28 03:42:02 +0200241 for (i=0; i<`MPRJ_IO_PADS; i=i+1) begin
shalan0d14e6e2020-08-31 16:50:48 +0200242 always @(posedge clk) begin
243 if (!resetn) begin
Tim Edwards251e0df2020-10-05 11:02:12 -0400244 // NOTE: This initialization must match the defaults passed
Tim Edwards496a08a2020-10-26 15:44:51 -0400245 // to the control blocks. Specifically, 0x1803 is for a
Tim Edwards251e0df2020-10-05 11:02:12 -0400246 // bidirectional pad, and 0x0403 is for a simple input pad
247 if (i < 2) begin
Tim Edwards496a08a2020-10-26 15:44:51 -0400248 io_ctrl[i] <= 'h1803;
Tim Edwards251e0df2020-10-05 11:02:12 -0400249 end else begin
250 io_ctrl[i] <= 'h0403;
251 end
shalan0d14e6e2020-08-31 16:50:48 +0200252 end else begin
Tim Edwardsba328902020-10-27 15:03:22 -0400253 if (iomem_valid && !iomem_ready &&
254 iomem_addr[31:8] == BASE_ADR[31:8]) begin
shalan0d14e6e2020-08-31 16:50:48 +0200255 if (io_ctrl_sel[i]) begin
Tim Edwardsc18c4742020-10-03 11:26:39 -0400256 // NOTE: Byte-wide write to io_ctrl is prohibited
shalan0d14e6e2020-08-31 16:50:48 +0200257 if (iomem_wstrb[0])
Tim Edwardsc18c4742020-10-03 11:26:39 -0400258 io_ctrl[i] <= iomem_wdata[IO_CTRL_BITS-1:0];
shalan0d14e6e2020-08-31 16:50:48 +0200259 end
260 end
261 end
262 end
263 end
264 endgenerate
265
Tim Edwards04ba17f2020-10-02 22:27:50 -0400266 reg [3:0] xfer_count;
267 reg [5:0] pad_count;
268 reg [1:0] xfer_state;
269 reg serial_clock;
270 reg serial_resetn;
Tim Edwards04ba17f2020-10-02 22:27:50 -0400271
Tim Edwardsc18c4742020-10-03 11:26:39 -0400272 reg [IO_CTRL_BITS-1:0] serial_data_staging;
273
Tim Edwards251e0df2020-10-05 11:02:12 -0400274 wire serial_data_out;
275 wire busy;
276
277 assign serial_data_out = serial_data_staging[IO_CTRL_BITS-1];
278 assign busy = (xfer_state != `IDLE);
279
Tim Edwardsc18c4742020-10-03 11:26:39 -0400280 always @(posedge clk or negedge resetn) begin
Tim Edwards04ba17f2020-10-02 22:27:50 -0400281 if (resetn == 1'b0) begin
282
Tim Edwards44bab472020-10-04 22:09:54 -0400283 xfer_state <= `IDLE;
Tim Edwards04ba17f2020-10-02 22:27:50 -0400284 xfer_count <= 4'd0;
Ahmed Ghazy22d29d62020-10-28 03:42:02 +0200285 pad_count <= `MPRJ_IO_PADS;
Tim Edwards04ba17f2020-10-02 22:27:50 -0400286 serial_resetn <= 1'b0;
287 serial_clock <= 1'b0;
Tim Edwards04ba17f2020-10-02 22:27:50 -0400288
289 end else begin
290
Tim Edwards44bab472020-10-04 22:09:54 -0400291 if (xfer_state == `IDLE) begin
Ahmed Ghazy22d29d62020-10-28 03:42:02 +0200292 pad_count <= `MPRJ_IO_PADS;
Tim Edwards251e0df2020-10-05 11:02:12 -0400293 serial_resetn <= 1'b1;
Tim Edwards44bab472020-10-04 22:09:54 -0400294 serial_clock <= 1'b0;
295 if (xfer_ctrl == 1'b1) begin
296 xfer_state <= `START;
297 end
298 end else if (xfer_state == `START) begin
Tim Edwards04ba17f2020-10-02 22:27:50 -0400299 serial_resetn <= 1'b1;
300 serial_clock <= 1'b0;
301 xfer_count <= 6'd0;
Tim Edwards251e0df2020-10-05 11:02:12 -0400302 pad_count <= pad_count - 1;
303 xfer_state <= `XBYTE;
304 serial_data_staging <= io_ctrl[pad_count - 1];
Tim Edwards04ba17f2020-10-02 22:27:50 -0400305 end else if (xfer_state == `XBYTE) begin
306 serial_resetn <= 1'b1;
307 serial_clock <= ~serial_clock;
308 if (serial_clock == 1'b0) begin
Tim Edwards251e0df2020-10-05 11:02:12 -0400309 if (xfer_count == IO_CTRL_BITS - 1) begin
310 if (pad_count == 0) begin
311 xfer_state <= `LOAD;
312 end else begin
313 xfer_state <= `START;
314 end
Tim Edwards04ba17f2020-10-02 22:27:50 -0400315 end else begin
316 xfer_count <= xfer_count + 1;
317 end
318 end else begin
Tim Edwardsc18c4742020-10-03 11:26:39 -0400319 serial_data_staging <= {serial_data_staging[IO_CTRL_BITS-2:0], 1'b0};
Tim Edwards04ba17f2020-10-02 22:27:50 -0400320 end
321 end else if (xfer_state == `LOAD) begin
322 xfer_count <= xfer_count + 1;
323
324 /* Load sequence: Raise clock for final data shift in;
325 * Pulse reset low while clock is high
326 * Set clock back to zero.
327 * Return to idle mode.
328 */
329 if (xfer_count == 4'd0) begin
330 serial_clock <= 1'b1;
331 serial_resetn <= 1'b1;
332 end else if (xfer_count == 4'd1) begin
333 serial_clock <= 1'b1;
334 serial_resetn <= 1'b0;
335 end else if (xfer_count == 4'd2) begin
336 serial_clock <= 1'b1;
337 serial_resetn <= 1'b1;
338 end else if (xfer_count == 4'd3) begin
339 serial_resetn <= 1'b1;
340 serial_clock <= 1'b0;
Tim Edwards44bab472020-10-04 22:09:54 -0400341 xfer_state <= `IDLE;
Tim Edwards04ba17f2020-10-02 22:27:50 -0400342 end
343 end
344 end
345 end
346
347endmodule