blob: 8970c41cae96a9edb7d6f53f21d17536966eaa7f [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
28 inout [IO_PADS-1:0] mgmt_gpio_io
29);
shalan0d14e6e2020-08-31 16:50:48 +020030 wire resetn;
31 wire valid;
32 wire ready;
33 wire [3:0] iomem_we;
34
35 assign resetn = ~wb_rst_i;
36 assign valid = wb_stb_i && wb_cyc_i;
37
38 assign iomem_we = wb_sel_i & {4{wb_we_i}};
39 assign wb_ack_o = ready;
40
41 mprj_ctrl #(
42 .BASE_ADR(BASE_ADR),
Tim Edwards04ba17f2020-10-02 22:27:50 -040043 .DATA(DATA),
44 .CONFIG(CONFIG),
45 .XFER(XFER),
46 .IO_PADS(IO_PADS),
Tim Edwardsc18c4742020-10-03 11:26:39 -040047 .PWR_PADS(PWR_PADS)
shalan0d14e6e2020-08-31 16:50:48 +020048 ) mprj_ctrl (
49 .clk(wb_clk_i),
50 .resetn(resetn),
51 .iomem_addr(wb_adr_i),
52 .iomem_valid(valid),
Tim Edwardsc18c4742020-10-03 11:26:39 -040053 .iomem_wstrb(iomem_we[1:0]),
shalan0d14e6e2020-08-31 16:50:48 +020054 .iomem_wdata(wb_dat_i),
55 .iomem_rdata(wb_dat_o),
56 .iomem_ready(ready),
Tim Edwards04ba17f2020-10-02 22:27:50 -040057
58 .serial_clock(serial_clock),
59 .serial_resetn(serial_resetn),
60 .serial_data_out(serial_data_out),
61 .mgmt_gpio_io(mgmt_gpio_io)
shalan0d14e6e2020-08-31 16:50:48 +020062 );
63
64endmodule
65
66module mprj_ctrl #(
67 parameter BASE_ADR = 32'h 2300_0000,
Tim Edwards04ba17f2020-10-02 22:27:50 -040068 parameter DATA = 8'h 00,
69 parameter XFER = 8'h 04,
70 parameter CONFIG = 8'h 08,
shalan0d14e6e2020-08-31 16:50:48 +020071 parameter IO_PADS = 32,
Tim Edwardsc18c4742020-10-03 11:26:39 -040072 parameter PWR_PADS = 32,
73 parameter IO_CTRL_BITS = 14,
74 parameter PWR_CTRL_BITS = 1
shalan0d14e6e2020-08-31 16:50:48 +020075)(
76 input clk,
77 input resetn,
78
79 input [31:0] iomem_addr,
80 input iomem_valid,
Tim Edwardsc18c4742020-10-03 11:26:39 -040081 input [1:0] iomem_wstrb,
shalan0d14e6e2020-08-31 16:50:48 +020082 input [31:0] iomem_wdata,
shalan0d14e6e2020-08-31 16:50:48 +020083 output reg [31:0] iomem_rdata,
84 output reg iomem_ready,
85
Tim Edwards04ba17f2020-10-02 22:27:50 -040086 output serial_clock,
87 output serial_resetn,
88 output serial_data_out,
89 inout [IO_PADS-1:0] mgmt_gpio_io
shalan0d14e6e2020-08-31 16:50:48 +020090);
Tim Edwardsc18c4742020-10-03 11:26:39 -040091
92`define START 2'b00
93`define XBYTE 2'b01
94`define LOAD 2'b10
95
Tim Edwards04ba17f2020-10-02 22:27:50 -040096 localparam IO_BASE_ADR = (BASE_ADR | CONFIG);
97 localparam PWR_BASE_ADR = (BASE_ADR | CONFIG) + IO_PADS*4;
98 localparam OEB = 1; // Offset of OEB in shift register block.
shalan0d14e6e2020-08-31 16:50:48 +020099
Tim Edwardsc18c4742020-10-03 11:26:39 -0400100 reg [IO_CTRL_BITS-1:0] io_ctrl [IO_PADS-1:0]; // I/O control, 1 word per gpio pad
101 reg [PWR_CTRL_BITS-1:0] pwr_ctrl [PWR_PADS-1:0];// Power control, 1 word per power pad
Tim Edwards04ba17f2020-10-02 22:27:50 -0400102 reg [IO_PADS-1:0] mgmt_gpio_out; // I/O read/write data, 1 bit per gpio pad
103 reg xfer_ctrl; // Transfer control (1 bit)
shalan0d14e6e2020-08-31 16:50:48 +0200104
Tim Edwards04ba17f2020-10-02 22:27:50 -0400105 wire [IO_PADS-1:0] io_ctrl_sel; // wishbone selects
Tim Edwardsc18c4742020-10-03 11:26:39 -0400106 wire [PWR_PADS-1:0] pwr_ctrl_sel;
Tim Edwards04ba17f2020-10-02 22:27:50 -0400107 wire io_data_sel;
108 wire xfer_sel;
109
110 assign xfer_sel = (iomem_addr[7:0] == XFER);
111 assign io_data_sel = (iomem_addr[7:0] == DATA);
112
113 // Direction of mgmt_gpio_io depends on the value of io_ctrl pad bit 1 (OEB)
114 // if OEB = 0 then mgmt_gpio_out --> mgmt_gpio_io; if OEB = 1 then
115 // mgmt_gpio_io --> mgmt_gpio_in. mgmt_gpio_in is always a copy of mgmt_gpio_io.
116
117 assign mgmt_gpio_in = mgmt_gpio_io;
shalan0d14e6e2020-08-31 16:50:48 +0200118
119 genvar i;
120 generate
121 for (i=0; i<IO_PADS; i=i+1) begin
Tim Edwards04ba17f2020-10-02 22:27:50 -0400122 assign io_ctrl_sel[i] = (iomem_addr[7:0] == (IO_BASE_ADR[7:0] + i*4));
Tim Edwardsc18c4742020-10-03 11:26:39 -0400123 assign mgmt_gpio_io[i] = (io_ctrl[0][i] + OEB == 1'b0) ?
Tim Edwards04ba17f2020-10-02 22:27:50 -0400124 mgmt_gpio_out[i] : 1'bz;
shalan0d14e6e2020-08-31 16:50:48 +0200125 end
126 endgenerate
127
128 generate
Tim Edwardsc18c4742020-10-03 11:26:39 -0400129 for (i=0; i<PWR_PADS; i=i+1) begin
shalan0d14e6e2020-08-31 16:50:48 +0200130 assign pwr_ctrl_sel[i] = (iomem_addr[7:0] == (PWR_BASE_ADR[7:0] + i*4));
131 end
132 endgenerate
133
Tim Edwards04ba17f2020-10-02 22:27:50 -0400134 // I/O transfer of xfer bit and gpio data to/from user project region under
135 // management SoC control
136
137 always @(posedge clk) begin
138 if (!resetn) begin
139 xfer_ctrl <= 0;
140 mgmt_gpio_out <= 'd0;
141 end else begin
142 iomem_ready <= 0;
Tim Edwardsc18c4742020-10-03 11:26:39 -0400143 if (iomem_valid && !iomem_ready && iomem_addr[31:8] == BASE_ADR[31:8]) begin
Tim Edwards04ba17f2020-10-02 22:27:50 -0400144 iomem_ready <= 1'b 1;
145
146 if (io_data_sel) begin
147 iomem_rdata <= mgmt_gpio_in;
148 mgmt_gpio_out <= 'd0;
149 if (iomem_wstrb[0]) mgmt_gpio_out[IO_PADS-1:0] <= iomem_wdata[IO_PADS-1:0];
150
151 end else if (xfer_sel) begin
152 iomem_rdata <= {31'd0, xfer_ctrl};
153 if (iomem_wstrb[0]) xfer_ctrl <= iomem_wdata[1:0];
154 end
155 end
156 end
157 end
158
shalan0d14e6e2020-08-31 16:50:48 +0200159 generate
160 for (i=0; i<IO_PADS; i=i+1) begin
161 always @(posedge clk) begin
162 if (!resetn) begin
Tim Edwardsc18c4742020-10-03 11:26:39 -0400163 // NOTE: This needs to be set to the specific bit sequence
164 // that initializes every I/O pad to the appropriate state on
165 // startup.
166 io_ctrl[i] <= 'd0;
shalan0d14e6e2020-08-31 16:50:48 +0200167 end else begin
shalan0d14e6e2020-08-31 16:50:48 +0200168 if (iomem_valid && !iomem_ready && iomem_addr[31:8] == BASE_ADR[31:8]) begin
shalan0d14e6e2020-08-31 16:50:48 +0200169 if (io_ctrl_sel[i]) begin
Tim Edwardsc18c4742020-10-03 11:26:39 -0400170 iomem_rdata <= io_ctrl[i];
171 // NOTE: Byte-wide write to io_ctrl is prohibited
shalan0d14e6e2020-08-31 16:50:48 +0200172 if (iomem_wstrb[0])
Tim Edwardsc18c4742020-10-03 11:26:39 -0400173 io_ctrl[i] <= iomem_wdata[IO_CTRL_BITS-1:0];
shalan0d14e6e2020-08-31 16:50:48 +0200174 end
175 end
176 end
177 end
178 end
179 endgenerate
180
181 generate
Tim Edwardsc18c4742020-10-03 11:26:39 -0400182 for (i=0; i<PWR_PADS; i=i+1) begin
shalan0d14e6e2020-08-31 16:50:48 +0200183 always @(posedge clk) begin
184 if (!resetn) begin
Tim Edwardsc18c4742020-10-03 11:26:39 -0400185 pwr_ctrl[i] <= 'd0;
shalan0d14e6e2020-08-31 16:50:48 +0200186 end else begin
shalan0d14e6e2020-08-31 16:50:48 +0200187 if (iomem_valid && !iomem_ready && iomem_addr[31:8] == BASE_ADR[31:8]) begin
shalan0d14e6e2020-08-31 16:50:48 +0200188 if (pwr_ctrl_sel[i]) begin
Tim Edwardsc18c4742020-10-03 11:26:39 -0400189 iomem_rdata <= pwr_ctrl[i];
shalan0d14e6e2020-08-31 16:50:48 +0200190 if (iomem_wstrb[0])
Tim Edwardsc18c4742020-10-03 11:26:39 -0400191 pwr_ctrl[i] <= iomem_wdata[PWR_CTRL_BITS-1:0];
shalan0d14e6e2020-08-31 16:50:48 +0200192 end
193 end
194 end
195 end
196 end
197 endgenerate
198
Tim Edwards04ba17f2020-10-02 22:27:50 -0400199 reg [3:0] xfer_count;
200 reg [5:0] pad_count;
201 reg [1:0] xfer_state;
202 reg serial_clock;
203 reg serial_resetn;
204 reg serial_data_out;
Tim Edwards04ba17f2020-10-02 22:27:50 -0400205
Tim Edwardsc18c4742020-10-03 11:26:39 -0400206 // NOTE: Ignoring power control bits for now. . . need to revisit.
207 // Depends on how the power pads are arranged among the GPIO, and
208 // whether or not switching will be internal and under the control
209 // of the SoC.
Tim Edwards04ba17f2020-10-02 22:27:50 -0400210
Tim Edwardsc18c4742020-10-03 11:26:39 -0400211 reg [IO_CTRL_BITS-1:0] serial_data_staging;
212
213 always @(posedge clk or negedge resetn) begin
Tim Edwards04ba17f2020-10-02 22:27:50 -0400214 if (resetn == 1'b0) begin
215
216 xfer_state <= `START;
217 xfer_count <= 4'd0;
218 pad_count <= 6'd0;
219 serial_resetn <= 1'b0;
220 serial_clock <= 1'b0;
221 serial_data_out <= 1'b0;
222
223 end else begin
224
225 if (xfer_state == `START) begin
226 serial_resetn <= 1'b1;
227 serial_clock <= 1'b0;
228 xfer_count <= 6'd0;
Tim Edwardsc18c4742020-10-03 11:26:39 -0400229 if (pad_count == IO_PADS) begin
Tim Edwards04ba17f2020-10-02 22:27:50 -0400230 xfer_state <= `LOAD;
231 end else begin
232 pad_count <= pad_count + 1;
233 xfer_state <= `XBYTE;
Tim Edwardsc18c4742020-10-03 11:26:39 -0400234 serial_data_staging <= io_ctrl[pad_count];
Tim Edwards04ba17f2020-10-02 22:27:50 -0400235 end
236 end else if (xfer_state == `XBYTE) begin
237 serial_resetn <= 1'b1;
238 serial_clock <= ~serial_clock;
239 if (serial_clock == 1'b0) begin
Tim Edwardsc18c4742020-10-03 11:26:39 -0400240 if (xfer_count == IO_CTRL_BITS) begin
Tim Edwards04ba17f2020-10-02 22:27:50 -0400241 xfer_state <= `START;
242 end else begin
243 xfer_count <= xfer_count + 1;
244 end
245 end else begin
Tim Edwardsc18c4742020-10-03 11:26:39 -0400246 serial_data_staging <= {serial_data_staging[IO_CTRL_BITS-2:0], 1'b0};
247 serial_data_out <= serial_data_staging[IO_CTRL_BITS-1];
Tim Edwards04ba17f2020-10-02 22:27:50 -0400248 end
249 end else if (xfer_state == `LOAD) begin
250 xfer_count <= xfer_count + 1;
251
252 /* Load sequence: Raise clock for final data shift in;
253 * Pulse reset low while clock is high
254 * Set clock back to zero.
255 * Return to idle mode.
256 */
257 if (xfer_count == 4'd0) begin
258 serial_clock <= 1'b1;
259 serial_resetn <= 1'b1;
260 end else if (xfer_count == 4'd1) begin
261 serial_clock <= 1'b1;
262 serial_resetn <= 1'b0;
263 end else if (xfer_count == 4'd2) begin
264 serial_clock <= 1'b1;
265 serial_resetn <= 1'b1;
266 end else if (xfer_count == 4'd3) begin
267 serial_resetn <= 1'b1;
268 serial_clock <= 1'b0;
269 xfer_state <= `START;
270 end
271 end
272 end
273 end
274
275endmodule