blob: ff041587445cf63302143243333aad548d9ccc98 [file] [log] [blame]
shalan0d14e6e2020-08-31 16:50:48 +02001module mprj_ctrl_wb #(
2 parameter BASE_ADR = 32'h 2300_0000,
Tim Edwards04ba17f2020-10-02 22:27:50 -04003 parameter DATA = 8'h 00,
4 parameter XFER = 8'h 04,
5 parameter CONFIG = 8'h 08,
shalan0d14e6e2020-08-31 16:50:48 +02006 parameter IO_PADS = 32, // Number of IO control registers
Tim Edwards9eda80d2020-10-08 21:36:44 -04007 parameter PWR_PADS = 32 // Number of power control registers
shalan0d14e6e2020-08-31 16:50:48 +02008)(
9 input wb_clk_i,
10 input wb_rst_i,
11
12 input [31:0] wb_dat_i,
13 input [31:0] wb_adr_i,
14 input [3:0] wb_sel_i,
15 input wb_cyc_i,
16 input wb_stb_i,
17 input wb_we_i,
18
19 output [31:0] wb_dat_o,
20 output wb_ack_o,
21
Tim Edwards04ba17f2020-10-02 22:27:50 -040022 // Output is to serial loader
23 output serial_clock,
24 output serial_resetn,
25 output serial_data_out,
shalan0d14e6e2020-08-31 16:50:48 +020026
Tim Edwards04ba17f2020-10-02 22:27:50 -040027 // Read/write data to each GPIO pad from management SoC
Tim Edwards44bab472020-10-04 22:09:54 -040028 input [IO_PADS-1:0] mgmt_gpio_in,
Tim Edwardsca2f3182020-10-06 10:05:11 -040029 output [IO_PADS-1:0] mgmt_gpio_out
Tim Edwards04ba17f2020-10-02 22:27:50 -040030);
shalan0d14e6e2020-08-31 16:50:48 +020031 wire resetn;
32 wire valid;
33 wire ready;
34 wire [3:0] iomem_we;
35
36 assign resetn = ~wb_rst_i;
37 assign valid = wb_stb_i && wb_cyc_i;
38
39 assign iomem_we = wb_sel_i & {4{wb_we_i}};
40 assign wb_ack_o = ready;
41
42 mprj_ctrl #(
43 .BASE_ADR(BASE_ADR),
Tim Edwards04ba17f2020-10-02 22:27:50 -040044 .DATA(DATA),
45 .CONFIG(CONFIG),
46 .XFER(XFER),
47 .IO_PADS(IO_PADS),
Tim Edwardsc18c4742020-10-03 11:26:39 -040048 .PWR_PADS(PWR_PADS)
shalan0d14e6e2020-08-31 16:50:48 +020049 ) mprj_ctrl (
50 .clk(wb_clk_i),
51 .resetn(resetn),
52 .iomem_addr(wb_adr_i),
53 .iomem_valid(valid),
Tim Edwardsc18c4742020-10-03 11:26:39 -040054 .iomem_wstrb(iomem_we[1:0]),
shalan0d14e6e2020-08-31 16:50:48 +020055 .iomem_wdata(wb_dat_i),
56 .iomem_rdata(wb_dat_o),
57 .iomem_ready(ready),
Tim Edwards04ba17f2020-10-02 22:27:50 -040058
59 .serial_clock(serial_clock),
60 .serial_resetn(serial_resetn),
61 .serial_data_out(serial_data_out),
Tim Edwards44bab472020-10-04 22:09:54 -040062 // .mgmt_gpio_io(mgmt_gpio_io)
63 .mgmt_gpio_in(mgmt_gpio_in),
Tim Edwardsca2f3182020-10-06 10:05:11 -040064 .mgmt_gpio_out(mgmt_gpio_out)
shalan0d14e6e2020-08-31 16:50:48 +020065 );
66
67endmodule
68
69module mprj_ctrl #(
70 parameter BASE_ADR = 32'h 2300_0000,
Tim Edwards04ba17f2020-10-02 22:27:50 -040071 parameter DATA = 8'h 00,
72 parameter XFER = 8'h 04,
73 parameter CONFIG = 8'h 08,
shalan0d14e6e2020-08-31 16:50:48 +020074 parameter IO_PADS = 32,
Tim Edwardsc18c4742020-10-03 11:26:39 -040075 parameter PWR_PADS = 32,
Tim Edwards44bab472020-10-04 22:09:54 -040076 parameter IO_CTRL_BITS = 13,
Tim Edwardsc18c4742020-10-03 11:26:39 -040077 parameter PWR_CTRL_BITS = 1
shalan0d14e6e2020-08-31 16:50:48 +020078)(
79 input clk,
80 input resetn,
81
82 input [31:0] iomem_addr,
83 input iomem_valid,
Tim Edwardsc18c4742020-10-03 11:26:39 -040084 input [1:0] iomem_wstrb,
shalan0d14e6e2020-08-31 16:50:48 +020085 input [31:0] iomem_wdata,
shalan0d14e6e2020-08-31 16:50:48 +020086 output reg [31:0] iomem_rdata,
87 output reg iomem_ready,
88
Tim Edwards04ba17f2020-10-02 22:27:50 -040089 output serial_clock,
90 output serial_resetn,
91 output serial_data_out,
Tim Edwards44bab472020-10-04 22:09:54 -040092 input [IO_PADS-1:0] mgmt_gpio_in,
Tim Edwardsca2f3182020-10-06 10:05:11 -040093 output [IO_PADS-1:0] mgmt_gpio_out
shalan0d14e6e2020-08-31 16:50:48 +020094);
Tim Edwardsc18c4742020-10-03 11:26:39 -040095
Tim Edwards44bab472020-10-04 22:09:54 -040096`define IDLE 2'b00
97`define START 2'b01
98`define XBYTE 2'b10
99`define LOAD 2'b11
Tim Edwardsc18c4742020-10-03 11:26:39 -0400100
Tim Edwards9eda80d2020-10-08 21:36:44 -0400101 localparam IO_WORDS = 1 + (IO_PADS / 32);
102 localparam PWR_WORDS = 1 + (PWR_PADS / 32);
103
104 localparam IO_BASE_ADR = (BASE_ADR | CONFIG) + ((IO_WORDS + PWR_WORDS - 2) * 4);
105 localparam PWR_BASE_ADR = IO_BASE_ADR + (IO_PADS * 4);
Tim Edwards44bab472020-10-04 22:09:54 -0400106 localparam OEB = 1; // Offset of output enable in shift register.
107 localparam INP_DIS = 3; // Offset of input disable in shift register.
Tim Edwards9eda80d2020-10-08 21:36:44 -0400108 localparam XFER_ADJ = XFER + ((IO_WORDS + PWR_WORDS - 2) * 4);
shalan0d14e6e2020-08-31 16:50:48 +0200109
Tim Edwards89f09242020-10-05 15:17:34 -0400110 reg [IO_CTRL_BITS-1:0] io_ctrl[IO_PADS-1:0]; // I/O control, 1 word per gpio pad
111 reg [PWR_CTRL_BITS-1:0] pwr_ctrl[PWR_PADS-1:0]; // Power control, 1 word per power pad
Tim Edwardsca2f3182020-10-06 10:05:11 -0400112 reg [IO_PADS-1:0] mgmt_gpio_outr; // I/O write data, 1 bit per gpio pad
113 wire [IO_PADS-1:0] mgmt_gpio_out; // I/O write data output when input disabled
Tim Edwards04ba17f2020-10-02 22:27:50 -0400114 reg xfer_ctrl; // Transfer control (1 bit)
shalan0d14e6e2020-08-31 16:50:48 +0200115
Tim Edwards9eda80d2020-10-08 21:36:44 -0400116 wire [IO_WORDS-1:0] io_data_sel; // wishbone selects
Tim Edwards04ba17f2020-10-02 22:27:50 -0400117 wire xfer_sel;
Tim Edwards9eda80d2020-10-08 21:36:44 -0400118 wire [IO_PADS-1:0] io_ctrl_sel;
119 wire [PWR_PADS-1:0] pwr_ctrl_sel;
Tim Edwards44bab472020-10-04 22:09:54 -0400120 wire [IO_PADS-1:0] mgmt_gpio_in;
Tim Edwards04ba17f2020-10-02 22:27:50 -0400121
Tim Edwards9eda80d2020-10-08 21:36:44 -0400122 assign xfer_sel = (iomem_addr[7:0] == XFER_ADJ);
Tim Edwards04ba17f2020-10-02 22:27:50 -0400123
shalan0d14e6e2020-08-31 16:50:48 +0200124 genvar i;
Tim Edwards9eda80d2020-10-08 21:36:44 -0400125
126 generate
127 for (i=0; i<IO_WORDS; i=i+1) begin
128 assign io_data_sel[i] = (iomem_addr[7:0] == (DATA + i*4));
129 end
130 endgenerate
131
shalan0d14e6e2020-08-31 16:50:48 +0200132 generate
133 for (i=0; i<IO_PADS; i=i+1) begin
Tim Edwards04ba17f2020-10-02 22:27:50 -0400134 assign io_ctrl_sel[i] = (iomem_addr[7:0] == (IO_BASE_ADR[7:0] + i*4));
Tim Edwardsca2f3182020-10-06 10:05:11 -0400135 assign mgmt_gpio_out[i] = (io_ctrl[i][INP_DIS] == 1'b1) ?
136 mgmt_gpio_outr[i] : 1'bz;
shalan0d14e6e2020-08-31 16:50:48 +0200137 end
138 endgenerate
139
140 generate
Tim Edwardsc18c4742020-10-03 11:26:39 -0400141 for (i=0; i<PWR_PADS; i=i+1) begin
shalan0d14e6e2020-08-31 16:50:48 +0200142 assign pwr_ctrl_sel[i] = (iomem_addr[7:0] == (PWR_BASE_ADR[7:0] + i*4));
143 end
144 endgenerate
145
Tim Edwards9eda80d2020-10-08 21:36:44 -0400146 // I/O transfer of xfer bit. Also handles iomem_ready signal.
Tim Edwards04ba17f2020-10-02 22:27:50 -0400147
148 always @(posedge clk) begin
149 if (!resetn) begin
150 xfer_ctrl <= 0;
Tim Edwards04ba17f2020-10-02 22:27:50 -0400151 end else begin
152 iomem_ready <= 0;
Tim Edwardsc18c4742020-10-03 11:26:39 -0400153 if (iomem_valid && !iomem_ready && iomem_addr[31:8] == BASE_ADR[31:8]) begin
Tim Edwards04ba17f2020-10-02 22:27:50 -0400154 iomem_ready <= 1'b 1;
155
Tim Edwards9eda80d2020-10-08 21:36:44 -0400156 if (xfer_sel) begin
Tim Edwards251e0df2020-10-05 11:02:12 -0400157 iomem_rdata <= {31'd0, busy};
158 if (iomem_wstrb[0]) xfer_ctrl <= iomem_wdata[0];
Tim Edwards04ba17f2020-10-02 22:27:50 -0400159 end
Tim Edwards251e0df2020-10-05 11:02:12 -0400160 end else begin
161 xfer_ctrl <= 1'b0; // Immediately self-resetting
Tim Edwards04ba17f2020-10-02 22:27:50 -0400162 end
163 end
164 end
165
Tim Edwards9eda80d2020-10-08 21:36:44 -0400166 // I/O transfer of gpio data to/from user project region under management
167 // SoC control
168
169 `define wtop (((i+1)*32 > IO_PADS) ? IO_PADS-1 : (i+1)*32-1)
170 `define wbot (i*32)
171 `define rtop (`wtop - `wbot + 1)
172
173 generate
174 for (i=0; i<IO_WORDS; i=i+1) begin
175 always @(posedge clk) begin
176 if (!resetn) begin
177 mgmt_gpio_outr[`wtop:`wbot] <= 'd0;
178 end else begin
179 if (iomem_valid && !iomem_ready && iomem_addr[31:8] ==
180 BASE_ADR[31:8]) begin
181 if (io_data_sel[i]) begin
182 iomem_rdata[`rtop:0] <= mgmt_gpio_in[`wtop:`wbot];
183 if (iomem_wstrb[0]) begin
184 mgmt_gpio_outr[`wtop:`wbot] <= iomem_wdata[`rtop:0];
185 end
186 end
187 end
188 end
189 end
190 end
191 endgenerate
192
shalan0d14e6e2020-08-31 16:50:48 +0200193 generate
194 for (i=0; i<IO_PADS; i=i+1) begin
195 always @(posedge clk) begin
196 if (!resetn) begin
Tim Edwards251e0df2020-10-05 11:02:12 -0400197 // NOTE: This initialization must match the defaults passed
198 // to the control blocks. Specifically, 0x1801 is for a
199 // bidirectional pad, and 0x0403 is for a simple input pad
200 if (i < 2) begin
201 io_ctrl[i] <= 'h1801;
202 end else begin
203 io_ctrl[i] <= 'h0403;
204 end
shalan0d14e6e2020-08-31 16:50:48 +0200205 end else begin
shalan0d14e6e2020-08-31 16:50:48 +0200206 if (iomem_valid && !iomem_ready && iomem_addr[31:8] == BASE_ADR[31:8]) begin
shalan0d14e6e2020-08-31 16:50:48 +0200207 if (io_ctrl_sel[i]) begin
Tim Edwardsc18c4742020-10-03 11:26:39 -0400208 iomem_rdata <= io_ctrl[i];
209 // NOTE: Byte-wide write to io_ctrl is prohibited
shalan0d14e6e2020-08-31 16:50:48 +0200210 if (iomem_wstrb[0])
Tim Edwardsc18c4742020-10-03 11:26:39 -0400211 io_ctrl[i] <= iomem_wdata[IO_CTRL_BITS-1:0];
shalan0d14e6e2020-08-31 16:50:48 +0200212 end
213 end
214 end
215 end
216 end
217 endgenerate
218
219 generate
Tim Edwardsc18c4742020-10-03 11:26:39 -0400220 for (i=0; i<PWR_PADS; i=i+1) begin
shalan0d14e6e2020-08-31 16:50:48 +0200221 always @(posedge clk) begin
222 if (!resetn) begin
Tim Edwardsc18c4742020-10-03 11:26:39 -0400223 pwr_ctrl[i] <= 'd0;
shalan0d14e6e2020-08-31 16:50:48 +0200224 end else begin
shalan0d14e6e2020-08-31 16:50:48 +0200225 if (iomem_valid && !iomem_ready && iomem_addr[31:8] == BASE_ADR[31:8]) begin
shalan0d14e6e2020-08-31 16:50:48 +0200226 if (pwr_ctrl_sel[i]) begin
Tim Edwardsc18c4742020-10-03 11:26:39 -0400227 iomem_rdata <= pwr_ctrl[i];
shalan0d14e6e2020-08-31 16:50:48 +0200228 if (iomem_wstrb[0])
Tim Edwardsc18c4742020-10-03 11:26:39 -0400229 pwr_ctrl[i] <= iomem_wdata[PWR_CTRL_BITS-1:0];
shalan0d14e6e2020-08-31 16:50:48 +0200230 end
231 end
232 end
233 end
234 end
235 endgenerate
236
Tim Edwards04ba17f2020-10-02 22:27:50 -0400237 reg [3:0] xfer_count;
238 reg [5:0] pad_count;
239 reg [1:0] xfer_state;
240 reg serial_clock;
241 reg serial_resetn;
Tim Edwards04ba17f2020-10-02 22:27:50 -0400242
Tim Edwardsc18c4742020-10-03 11:26:39 -0400243 // NOTE: Ignoring power control bits for now. . . need to revisit.
244 // Depends on how the power pads are arranged among the GPIO, and
245 // whether or not switching will be internal and under the control
246 // of the SoC.
Tim Edwards04ba17f2020-10-02 22:27:50 -0400247
Tim Edwardsc18c4742020-10-03 11:26:39 -0400248 reg [IO_CTRL_BITS-1:0] serial_data_staging;
249
Tim Edwards251e0df2020-10-05 11:02:12 -0400250 wire serial_data_out;
251 wire busy;
252
253 assign serial_data_out = serial_data_staging[IO_CTRL_BITS-1];
254 assign busy = (xfer_state != `IDLE);
255
Tim Edwardsc18c4742020-10-03 11:26:39 -0400256 always @(posedge clk or negedge resetn) begin
Tim Edwards04ba17f2020-10-02 22:27:50 -0400257 if (resetn == 1'b0) begin
258
Tim Edwards44bab472020-10-04 22:09:54 -0400259 xfer_state <= `IDLE;
Tim Edwards04ba17f2020-10-02 22:27:50 -0400260 xfer_count <= 4'd0;
Tim Edwards251e0df2020-10-05 11:02:12 -0400261 pad_count <= IO_PADS;
Tim Edwards04ba17f2020-10-02 22:27:50 -0400262 serial_resetn <= 1'b0;
263 serial_clock <= 1'b0;
Tim Edwards04ba17f2020-10-02 22:27:50 -0400264
265 end else begin
266
Tim Edwards44bab472020-10-04 22:09:54 -0400267 if (xfer_state == `IDLE) begin
Tim Edwards251e0df2020-10-05 11:02:12 -0400268 pad_count <= IO_PADS;
269 serial_resetn <= 1'b1;
Tim Edwards44bab472020-10-04 22:09:54 -0400270 serial_clock <= 1'b0;
271 if (xfer_ctrl == 1'b1) begin
272 xfer_state <= `START;
273 end
274 end else if (xfer_state == `START) begin
Tim Edwards04ba17f2020-10-02 22:27:50 -0400275 serial_resetn <= 1'b1;
276 serial_clock <= 1'b0;
277 xfer_count <= 6'd0;
Tim Edwards251e0df2020-10-05 11:02:12 -0400278 pad_count <= pad_count - 1;
279 xfer_state <= `XBYTE;
280 serial_data_staging <= io_ctrl[pad_count - 1];
Tim Edwards04ba17f2020-10-02 22:27:50 -0400281 end else if (xfer_state == `XBYTE) begin
282 serial_resetn <= 1'b1;
283 serial_clock <= ~serial_clock;
284 if (serial_clock == 1'b0) begin
Tim Edwards251e0df2020-10-05 11:02:12 -0400285 if (xfer_count == IO_CTRL_BITS - 1) begin
286 if (pad_count == 0) begin
287 xfer_state <= `LOAD;
288 end else begin
289 xfer_state <= `START;
290 end
Tim Edwards04ba17f2020-10-02 22:27:50 -0400291 end else begin
292 xfer_count <= xfer_count + 1;
293 end
294 end else begin
Tim Edwardsc18c4742020-10-03 11:26:39 -0400295 serial_data_staging <= {serial_data_staging[IO_CTRL_BITS-2:0], 1'b0};
Tim Edwards04ba17f2020-10-02 22:27:50 -0400296 end
297 end else if (xfer_state == `LOAD) begin
298 xfer_count <= xfer_count + 1;
299
300 /* Load sequence: Raise clock for final data shift in;
301 * Pulse reset low while clock is high
302 * Set clock back to zero.
303 * Return to idle mode.
304 */
305 if (xfer_count == 4'd0) begin
306 serial_clock <= 1'b1;
307 serial_resetn <= 1'b1;
308 end else if (xfer_count == 4'd1) begin
309 serial_clock <= 1'b1;
310 serial_resetn <= 1'b0;
311 end else if (xfer_count == 4'd2) begin
312 serial_clock <= 1'b1;
313 serial_resetn <= 1'b1;
314 end else if (xfer_count == 4'd3) begin
315 serial_resetn <= 1'b1;
316 serial_clock <= 1'b0;
Tim Edwards44bab472020-10-04 22:09:54 -0400317 xfer_state <= `IDLE;
Tim Edwards04ba17f2020-10-02 22:27:50 -0400318 end
319 end
320 end
321 end
322
323endmodule