blob: 035e756f547122dccc2a542eeb53bba2b2e788f6 [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 Edwardsc18c4742020-10-03 11:26:39 -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,
29 output [IO_PADS-1:0] mgmt_gpio_out,
30 output [IO_PADS-1:0] mgmt_gpio_outz,
31 output [IO_PADS-1:0] mgmt_gpio_oeb // Only JTAG and SDO connected
Tim Edwards04ba17f2020-10-02 22:27:50 -040032);
shalan0d14e6e2020-08-31 16:50:48 +020033 wire resetn;
34 wire valid;
35 wire ready;
36 wire [3:0] iomem_we;
37
38 assign resetn = ~wb_rst_i;
39 assign valid = wb_stb_i && wb_cyc_i;
40
41 assign iomem_we = wb_sel_i & {4{wb_we_i}};
42 assign wb_ack_o = ready;
43
44 mprj_ctrl #(
45 .BASE_ADR(BASE_ADR),
Tim Edwards04ba17f2020-10-02 22:27:50 -040046 .DATA(DATA),
47 .CONFIG(CONFIG),
48 .XFER(XFER),
49 .IO_PADS(IO_PADS),
Tim Edwardsc18c4742020-10-03 11:26:39 -040050 .PWR_PADS(PWR_PADS)
shalan0d14e6e2020-08-31 16:50:48 +020051 ) mprj_ctrl (
52 .clk(wb_clk_i),
53 .resetn(resetn),
54 .iomem_addr(wb_adr_i),
55 .iomem_valid(valid),
Tim Edwardsc18c4742020-10-03 11:26:39 -040056 .iomem_wstrb(iomem_we[1:0]),
shalan0d14e6e2020-08-31 16:50:48 +020057 .iomem_wdata(wb_dat_i),
58 .iomem_rdata(wb_dat_o),
59 .iomem_ready(ready),
Tim Edwards04ba17f2020-10-02 22:27:50 -040060
61 .serial_clock(serial_clock),
62 .serial_resetn(serial_resetn),
63 .serial_data_out(serial_data_out),
Tim Edwards44bab472020-10-04 22:09:54 -040064 // .mgmt_gpio_io(mgmt_gpio_io)
65 .mgmt_gpio_in(mgmt_gpio_in),
66 .mgmt_gpio_out(mgmt_gpio_out),
67 .mgmt_gpio_outz(mgmt_gpio_outz),
68 .mgmt_gpio_oeb(mgmt_gpio_oeb)
shalan0d14e6e2020-08-31 16:50:48 +020069 );
70
71endmodule
72
73module mprj_ctrl #(
74 parameter BASE_ADR = 32'h 2300_0000,
Tim Edwards04ba17f2020-10-02 22:27:50 -040075 parameter DATA = 8'h 00,
76 parameter XFER = 8'h 04,
77 parameter CONFIG = 8'h 08,
shalan0d14e6e2020-08-31 16:50:48 +020078 parameter IO_PADS = 32,
Tim Edwardsc18c4742020-10-03 11:26:39 -040079 parameter PWR_PADS = 32,
Tim Edwards44bab472020-10-04 22:09:54 -040080 parameter IO_CTRL_BITS = 13,
Tim Edwardsc18c4742020-10-03 11:26:39 -040081 parameter PWR_CTRL_BITS = 1
shalan0d14e6e2020-08-31 16:50:48 +020082)(
83 input clk,
84 input resetn,
85
86 input [31:0] iomem_addr,
87 input iomem_valid,
Tim Edwardsc18c4742020-10-03 11:26:39 -040088 input [1:0] iomem_wstrb,
shalan0d14e6e2020-08-31 16:50:48 +020089 input [31:0] iomem_wdata,
shalan0d14e6e2020-08-31 16:50:48 +020090 output reg [31:0] iomem_rdata,
91 output reg iomem_ready,
92
Tim Edwards04ba17f2020-10-02 22:27:50 -040093 output serial_clock,
94 output serial_resetn,
95 output serial_data_out,
Tim Edwards44bab472020-10-04 22:09:54 -040096 input [IO_PADS-1:0] mgmt_gpio_in,
97 output [IO_PADS-1:0] mgmt_gpio_out,
98 output [IO_PADS-1:0] mgmt_gpio_outz,
99 output [IO_PADS-1:0] mgmt_gpio_oeb
shalan0d14e6e2020-08-31 16:50:48 +0200100);
Tim Edwardsc18c4742020-10-03 11:26:39 -0400101
Tim Edwards44bab472020-10-04 22:09:54 -0400102`define IDLE 2'b00
103`define START 2'b01
104`define XBYTE 2'b10
105`define LOAD 2'b11
Tim Edwardsc18c4742020-10-03 11:26:39 -0400106
Tim Edwards04ba17f2020-10-02 22:27:50 -0400107 localparam IO_BASE_ADR = (BASE_ADR | CONFIG);
108 localparam PWR_BASE_ADR = (BASE_ADR | CONFIG) + IO_PADS*4;
Tim Edwards44bab472020-10-04 22:09:54 -0400109 localparam OEB = 1; // Offset of output enable in shift register.
110 localparam INP_DIS = 3; // Offset of input disable in shift register.
shalan0d14e6e2020-08-31 16:50:48 +0200111
Tim Edwards89f09242020-10-05 15:17:34 -0400112 reg [IO_CTRL_BITS-1:0] io_ctrl[IO_PADS-1:0]; // I/O control, 1 word per gpio pad
113 reg [PWR_CTRL_BITS-1:0] pwr_ctrl[PWR_PADS-1:0]; // Power control, 1 word per power pad
Tim Edwards44bab472020-10-04 22:09:54 -0400114 reg [IO_PADS-1:0] mgmt_gpio_out; // I/O write data, 1 bit per gpio pad
115 wire [IO_PADS-1:0] mgmt_gpio_outz; // I/O write data output when input disabled
116 wire [IO_PADS-1:0] mgmt_gpio_oeb;
Tim Edwards04ba17f2020-10-02 22:27:50 -0400117 reg xfer_ctrl; // Transfer control (1 bit)
shalan0d14e6e2020-08-31 16:50:48 +0200118
Tim Edwards04ba17f2020-10-02 22:27:50 -0400119 wire [IO_PADS-1:0] io_ctrl_sel; // wishbone selects
Tim Edwardsc18c4742020-10-03 11:26:39 -0400120 wire [PWR_PADS-1:0] pwr_ctrl_sel;
Tim Edwards04ba17f2020-10-02 22:27:50 -0400121 wire io_data_sel;
122 wire xfer_sel;
Tim Edwards44bab472020-10-04 22:09:54 -0400123 wire [IO_PADS-1:0] mgmt_gpio_in;
Tim Edwards04ba17f2020-10-02 22:27:50 -0400124
125 assign xfer_sel = (iomem_addr[7:0] == XFER);
126 assign io_data_sel = (iomem_addr[7:0] == DATA);
127
shalan0d14e6e2020-08-31 16:50:48 +0200128 genvar i;
129 generate
130 for (i=0; i<IO_PADS; i=i+1) begin
Tim Edwards04ba17f2020-10-02 22:27:50 -0400131 assign io_ctrl_sel[i] = (iomem_addr[7:0] == (IO_BASE_ADR[7:0] + i*4));
Tim Edwards44bab472020-10-04 22:09:54 -0400132 // OEB is both tranferred by serial chain and output; that way
133 // each pad can selectively choose whether to have a dedicated
134 // signal for OEB, or to use it as a static configuration bit.
Tim Edwards89f09242020-10-05 15:17:34 -0400135 assign mgmt_gpio_oeb[i] = io_ctrl[i][OEB];
136 assign mgmt_gpio_outz[i] = (io_ctrl[i][INP_DIS] == 1'b1) ?
Tim Edwards44bab472020-10-04 22:09:54 -0400137 mgmt_gpio_out[i] : 1'bz;
shalan0d14e6e2020-08-31 16:50:48 +0200138 end
139 endgenerate
140
141 generate
Tim Edwardsc18c4742020-10-03 11:26:39 -0400142 for (i=0; i<PWR_PADS; i=i+1) begin
shalan0d14e6e2020-08-31 16:50:48 +0200143 assign pwr_ctrl_sel[i] = (iomem_addr[7:0] == (PWR_BASE_ADR[7:0] + i*4));
144 end
145 endgenerate
146
Tim Edwards04ba17f2020-10-02 22:27:50 -0400147 // I/O transfer of xfer bit and gpio data to/from user project region under
148 // management SoC control
149
150 always @(posedge clk) begin
151 if (!resetn) begin
152 xfer_ctrl <= 0;
153 mgmt_gpio_out <= 'd0;
154 end else begin
155 iomem_ready <= 0;
Tim Edwardsc18c4742020-10-03 11:26:39 -0400156 if (iomem_valid && !iomem_ready && iomem_addr[31:8] == BASE_ADR[31:8]) begin
Tim Edwards04ba17f2020-10-02 22:27:50 -0400157 iomem_ready <= 1'b 1;
158
159 if (io_data_sel) begin
160 iomem_rdata <= mgmt_gpio_in;
Tim Edwards44bab472020-10-04 22:09:54 -0400161 if (iomem_wstrb[0]) begin
162 mgmt_gpio_out[IO_PADS-1:0] <= iomem_wdata[IO_PADS-1:0];
163 end
Tim Edwards04ba17f2020-10-02 22:27:50 -0400164
165 end else if (xfer_sel) begin
Tim Edwards251e0df2020-10-05 11:02:12 -0400166 iomem_rdata <= {31'd0, busy};
167 if (iomem_wstrb[0]) xfer_ctrl <= iomem_wdata[0];
Tim Edwards04ba17f2020-10-02 22:27:50 -0400168 end
Tim Edwards251e0df2020-10-05 11:02:12 -0400169 end else begin
170 xfer_ctrl <= 1'b0; // Immediately self-resetting
Tim Edwards04ba17f2020-10-02 22:27:50 -0400171 end
172 end
173 end
174
shalan0d14e6e2020-08-31 16:50:48 +0200175 generate
176 for (i=0; i<IO_PADS; i=i+1) begin
177 always @(posedge clk) begin
178 if (!resetn) begin
Tim Edwards251e0df2020-10-05 11:02:12 -0400179 // NOTE: This initialization must match the defaults passed
180 // to the control blocks. Specifically, 0x1801 is for a
181 // bidirectional pad, and 0x0403 is for a simple input pad
182 if (i < 2) begin
183 io_ctrl[i] <= 'h1801;
184 end else begin
185 io_ctrl[i] <= 'h0403;
186 end
shalan0d14e6e2020-08-31 16:50:48 +0200187 end else begin
shalan0d14e6e2020-08-31 16:50:48 +0200188 if (iomem_valid && !iomem_ready && iomem_addr[31:8] == BASE_ADR[31:8]) begin
shalan0d14e6e2020-08-31 16:50:48 +0200189 if (io_ctrl_sel[i]) begin
Tim Edwardsc18c4742020-10-03 11:26:39 -0400190 iomem_rdata <= io_ctrl[i];
191 // NOTE: Byte-wide write to io_ctrl is prohibited
shalan0d14e6e2020-08-31 16:50:48 +0200192 if (iomem_wstrb[0])
Tim Edwardsc18c4742020-10-03 11:26:39 -0400193 io_ctrl[i] <= iomem_wdata[IO_CTRL_BITS-1:0];
shalan0d14e6e2020-08-31 16:50:48 +0200194 end
195 end
196 end
197 end
198 end
199 endgenerate
200
201 generate
Tim Edwardsc18c4742020-10-03 11:26:39 -0400202 for (i=0; i<PWR_PADS; i=i+1) begin
shalan0d14e6e2020-08-31 16:50:48 +0200203 always @(posedge clk) begin
204 if (!resetn) begin
Tim Edwardsc18c4742020-10-03 11:26:39 -0400205 pwr_ctrl[i] <= 'd0;
shalan0d14e6e2020-08-31 16:50:48 +0200206 end else begin
shalan0d14e6e2020-08-31 16:50:48 +0200207 if (iomem_valid && !iomem_ready && iomem_addr[31:8] == BASE_ADR[31:8]) begin
shalan0d14e6e2020-08-31 16:50:48 +0200208 if (pwr_ctrl_sel[i]) begin
Tim Edwardsc18c4742020-10-03 11:26:39 -0400209 iomem_rdata <= pwr_ctrl[i];
shalan0d14e6e2020-08-31 16:50:48 +0200210 if (iomem_wstrb[0])
Tim Edwardsc18c4742020-10-03 11:26:39 -0400211 pwr_ctrl[i] <= iomem_wdata[PWR_CTRL_BITS-1:0];
shalan0d14e6e2020-08-31 16:50:48 +0200212 end
213 end
214 end
215 end
216 end
217 endgenerate
218
Tim Edwards04ba17f2020-10-02 22:27:50 -0400219 reg [3:0] xfer_count;
220 reg [5:0] pad_count;
221 reg [1:0] xfer_state;
222 reg serial_clock;
223 reg serial_resetn;
Tim Edwards04ba17f2020-10-02 22:27:50 -0400224
Tim Edwardsc18c4742020-10-03 11:26:39 -0400225 // NOTE: Ignoring power control bits for now. . . need to revisit.
226 // Depends on how the power pads are arranged among the GPIO, and
227 // whether or not switching will be internal and under the control
228 // of the SoC.
Tim Edwards04ba17f2020-10-02 22:27:50 -0400229
Tim Edwardsc18c4742020-10-03 11:26:39 -0400230 reg [IO_CTRL_BITS-1:0] serial_data_staging;
231
Tim Edwards251e0df2020-10-05 11:02:12 -0400232 wire serial_data_out;
233 wire busy;
234
235 assign serial_data_out = serial_data_staging[IO_CTRL_BITS-1];
236 assign busy = (xfer_state != `IDLE);
237
Tim Edwardsc18c4742020-10-03 11:26:39 -0400238 always @(posedge clk or negedge resetn) begin
Tim Edwards04ba17f2020-10-02 22:27:50 -0400239 if (resetn == 1'b0) begin
240
Tim Edwards44bab472020-10-04 22:09:54 -0400241 xfer_state <= `IDLE;
Tim Edwards04ba17f2020-10-02 22:27:50 -0400242 xfer_count <= 4'd0;
Tim Edwards251e0df2020-10-05 11:02:12 -0400243 pad_count <= IO_PADS;
Tim Edwards04ba17f2020-10-02 22:27:50 -0400244 serial_resetn <= 1'b0;
245 serial_clock <= 1'b0;
Tim Edwards04ba17f2020-10-02 22:27:50 -0400246
247 end else begin
248
Tim Edwards44bab472020-10-04 22:09:54 -0400249 if (xfer_state == `IDLE) begin
Tim Edwards251e0df2020-10-05 11:02:12 -0400250 pad_count <= IO_PADS;
251 serial_resetn <= 1'b1;
Tim Edwards44bab472020-10-04 22:09:54 -0400252 serial_clock <= 1'b0;
253 if (xfer_ctrl == 1'b1) begin
254 xfer_state <= `START;
255 end
256 end else if (xfer_state == `START) begin
Tim Edwards04ba17f2020-10-02 22:27:50 -0400257 serial_resetn <= 1'b1;
258 serial_clock <= 1'b0;
259 xfer_count <= 6'd0;
Tim Edwards251e0df2020-10-05 11:02:12 -0400260 pad_count <= pad_count - 1;
261 xfer_state <= `XBYTE;
262 serial_data_staging <= io_ctrl[pad_count - 1];
Tim Edwards04ba17f2020-10-02 22:27:50 -0400263 end else if (xfer_state == `XBYTE) begin
264 serial_resetn <= 1'b1;
265 serial_clock <= ~serial_clock;
266 if (serial_clock == 1'b0) begin
Tim Edwards251e0df2020-10-05 11:02:12 -0400267 if (xfer_count == IO_CTRL_BITS - 1) begin
268 if (pad_count == 0) begin
269 xfer_state <= `LOAD;
270 end else begin
271 xfer_state <= `START;
272 end
Tim Edwards04ba17f2020-10-02 22:27:50 -0400273 end else begin
274 xfer_count <= xfer_count + 1;
275 end
276 end else begin
Tim Edwardsc18c4742020-10-03 11:26:39 -0400277 serial_data_staging <= {serial_data_staging[IO_CTRL_BITS-2:0], 1'b0};
Tim Edwards04ba17f2020-10-02 22:27:50 -0400278 end
279 end else if (xfer_state == `LOAD) begin
280 xfer_count <= xfer_count + 1;
281
282 /* Load sequence: Raise clock for final data shift in;
283 * Pulse reset low while clock is high
284 * Set clock back to zero.
285 * Return to idle mode.
286 */
287 if (xfer_count == 4'd0) begin
288 serial_clock <= 1'b1;
289 serial_resetn <= 1'b1;
290 end else if (xfer_count == 4'd1) begin
291 serial_clock <= 1'b1;
292 serial_resetn <= 1'b0;
293 end else if (xfer_count == 4'd2) begin
294 serial_clock <= 1'b1;
295 serial_resetn <= 1'b1;
296 end else if (xfer_count == 4'd3) begin
297 serial_resetn <= 1'b1;
298 serial_clock <= 1'b0;
Tim Edwards44bab472020-10-04 22:09:54 -0400299 xfer_state <= `IDLE;
Tim Edwards04ba17f2020-10-02 22:27:50 -0400300 end
301 end
302 end
303 end
304
305endmodule