blob: 66250cbeff4c2f302c111e40c8e47c4ab36cbbce [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
7 parameter PWR_CTRL = 32 // Number of power control registers
8)(
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),
shalan0d14e6e2020-08-31 16:50:48 +020047 .PWR_CTRL(PWR_CTRL)
48 ) mprj_ctrl (
49 .clk(wb_clk_i),
50 .resetn(resetn),
51 .iomem_addr(wb_adr_i),
52 .iomem_valid(valid),
53 .iomem_wstrb(iomem_we),
54 .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,
72 parameter PWR_CTRL = 32
73)(
74 input clk,
75 input resetn,
76
77 input [31:0] iomem_addr,
78 input iomem_valid,
79 input [3:0] iomem_wstrb,
80 input [31:0] iomem_wdata,
shalan0d14e6e2020-08-31 16:50:48 +020081 output reg [31:0] iomem_rdata,
82 output reg iomem_ready,
83
Tim Edwards04ba17f2020-10-02 22:27:50 -040084 output serial_clock,
85 output serial_resetn,
86 output serial_data_out,
87 inout [IO_PADS-1:0] mgmt_gpio_io
shalan0d14e6e2020-08-31 16:50:48 +020088);
89
Tim Edwards04ba17f2020-10-02 22:27:50 -040090 localparam IO_BASE_ADR = (BASE_ADR | CONFIG);
91 localparam PWR_BASE_ADR = (BASE_ADR | CONFIG) + IO_PADS*4;
92 localparam OEB = 1; // Offset of OEB in shift register block.
shalan0d14e6e2020-08-31 16:50:48 +020093
Tim Edwards04ba17f2020-10-02 22:27:50 -040094 reg [IO_PADS*32-1:0] io_ctrl; // I/O control, 1 word per gpio pad
95 reg [PWR_CTRL*32-1:0] pwr_ctrl; // Power control, 1 word per power pad
96 reg [IO_PADS-1:0] mgmt_gpio_out; // I/O read/write data, 1 bit per gpio pad
97 reg xfer_ctrl; // Transfer control (1 bit)
shalan0d14e6e2020-08-31 16:50:48 +020098
Tim Edwards04ba17f2020-10-02 22:27:50 -040099 wire [IO_PADS-1:0] io_ctrl_sel; // wishbone selects
shalan0d14e6e2020-08-31 16:50:48 +0200100 wire [PWR_CTRL-1:0] pwr_ctrl_sel;
Tim Edwards04ba17f2020-10-02 22:27:50 -0400101 wire io_data_sel;
102 wire xfer_sel;
103
104 assign xfer_sel = (iomem_addr[7:0] == XFER);
105 assign io_data_sel = (iomem_addr[7:0] == DATA);
106
107 // Direction of mgmt_gpio_io depends on the value of io_ctrl pad bit 1 (OEB)
108 // if OEB = 0 then mgmt_gpio_out --> mgmt_gpio_io; if OEB = 1 then
109 // mgmt_gpio_io --> mgmt_gpio_in. mgmt_gpio_in is always a copy of mgmt_gpio_io.
110
111 assign mgmt_gpio_in = mgmt_gpio_io;
shalan0d14e6e2020-08-31 16:50:48 +0200112
113 genvar i;
114 generate
115 for (i=0; i<IO_PADS; i=i+1) begin
Tim Edwards04ba17f2020-10-02 22:27:50 -0400116 assign io_ctrl_sel[i] = (iomem_addr[7:0] == (IO_BASE_ADR[7:0] + i*4));
117 assign mgmt_gpio_io[i] = (io_ctrl[i*32] + OEB == 1'b0) ?
118 mgmt_gpio_out[i] : 1'bz;
shalan0d14e6e2020-08-31 16:50:48 +0200119 end
120 endgenerate
121
122 generate
123 for (i=0; i<PWR_CTRL; i=i+1) begin
124 assign pwr_ctrl_sel[i] = (iomem_addr[7:0] == (PWR_BASE_ADR[7:0] + i*4));
125 end
126 endgenerate
127
Tim Edwards04ba17f2020-10-02 22:27:50 -0400128 // I/O transfer of xfer bit and gpio data to/from user project region under
129 // management SoC control
130
131 always @(posedge clk) begin
132 if (!resetn) begin
133 xfer_ctrl <= 0;
134 mgmt_gpio_out <= 'd0;
135 end else begin
136 iomem_ready <= 0;
137 if (iomem_valid && !iomem_ready && iomem_addr[31:8] == BASE_ADDR[31:8]) begin
138 iomem_ready <= 1'b 1;
139
140 if (io_data_sel) begin
141 iomem_rdata <= mgmt_gpio_in;
142 mgmt_gpio_out <= 'd0;
143 if (iomem_wstrb[0]) mgmt_gpio_out[IO_PADS-1:0] <= iomem_wdata[IO_PADS-1:0];
144
145 end else if (xfer_sel) begin
146 iomem_rdata <= {31'd0, xfer_ctrl};
147 if (iomem_wstrb[0]) xfer_ctrl <= iomem_wdata[1:0];
148 end
149 end
150 end
151 end
152
shalan0d14e6e2020-08-31 16:50:48 +0200153 generate
154 for (i=0; i<IO_PADS; i=i+1) begin
155 always @(posedge clk) begin
156 if (!resetn) begin
157 io_ctrl[i*32+: 32] <= 0;
158 end else begin
shalan0d14e6e2020-08-31 16:50:48 +0200159 if (iomem_valid && !iomem_ready && iomem_addr[31:8] == BASE_ADR[31:8]) begin
shalan0d14e6e2020-08-31 16:50:48 +0200160 if (io_ctrl_sel[i]) begin
161 iomem_rdata <= io_ctrl[i*32+: 32];
162 if (iomem_wstrb[0])
163 io_ctrl[(i+1)*32-1-24:i*32] <= iomem_wdata[7:0];
164
165 if (iomem_wstrb[1])
166 io_ctrl[(i+1)*32-1-16:i*32+8] <= iomem_wdata[15:8];
167
168 if (iomem_wstrb[2])
169 io_ctrl[(i+1)*32-1-8:i*32+16] <= iomem_wdata[23:16];
170
171 if (iomem_wstrb[3])
172 io_ctrl[(i+1)*32-1:i*32+24] <= iomem_wdata[31:24];
173 end
174 end
175 end
176 end
177 end
178 endgenerate
179
180 generate
181 for (i=0; i<PWR_CTRL; i=i+1) begin
182 always @(posedge clk) begin
183 if (!resetn) begin
184 pwr_ctrl[i*32+: 32] <= 0;
185 end else begin
shalan0d14e6e2020-08-31 16:50:48 +0200186 if (iomem_valid && !iomem_ready && iomem_addr[31:8] == BASE_ADR[31:8]) begin
shalan0d14e6e2020-08-31 16:50:48 +0200187 if (pwr_ctrl_sel[i]) begin
188 iomem_rdata <= pwr_ctrl[i*32+: 32];
189 if (iomem_wstrb[0])
190 pwr_ctrl[(i+1)*32-1-24:i*32] <= iomem_wdata[7:0];
191
192 if (pwr_ctrl_sel[1])
193 pwr_ctrl[(i+1)*32-1-16:i*32+8] <= iomem_wdata[15:8];
194
195 if (pwr_ctrl_sel[2])
196 pwr_ctrl[(i+1)*32-1-8:i*32+16] <= iomem_wdata[23:16];
197
198 if (pwr_ctrl_sel[3])
199 pwr_ctrl[(i+1)*32-1:i*32+24] <= iomem_wdata[31:24];
200 end
201 end
202 end
203 end
204 end
205 endgenerate
206
Tim Edwards04ba17f2020-10-02 22:27:50 -0400207 // Instantiate the GPIO transfer circuit
208
209 gpio_transfer_data #(
210 .NUM_GPIO_PADS(IO_PADS),
211 .PAD_CTRL_BITS(14)
212 ) gpio_xfer (
213 .resetn(resetn),
214 .clock(clk),
215 .pad_configure(io_ctrl),
216 .serial_clock(serial_clock),
217 .serial_resetn(serial_resetn),
218 .serial_data_out(serial_data_out)
219 );
220
221endmodule
222
223/*
224 *----------------------------------------------------
225 *
226 * This module initiates a write to the shift register
227 * chain from registered data in the processor core.
228 *
229 *----------------------------------------------------
230 */
231
232`define START 2'b00
233`define XBYTE 2'b01
234`define LOAD 2'b10
235
236module gpio_transfer_data #(
237 parameter NUM_GPIO_PADS = 32,
238 parameter PAD_CTRL_BITS = 13
239) (
240 input resetn,
241 input clock,
242 input [NUM_GPIO_PADS*PAD_CTRL_BITS-1:0] pad_configure,
243
244 output serial_clock,
245 output serial_resetn,
246 output serial_data_out
247);
248 reg [3:0] xfer_count;
249 reg [5:0] pad_count;
250 reg [1:0] xfer_state;
251 reg serial_clock;
252 reg serial_resetn;
253 reg serial_data_out;
254 reg [PAD_CTRL_BITS-1:0] serial_data_staging;
255
256 integer i;
257
258 always @(posedge clock or negedge resetn) begin
259 if (resetn == 1'b0) begin
260
261 xfer_state <= `START;
262 xfer_count <= 4'd0;
263 pad_count <= 6'd0;
264 serial_resetn <= 1'b0;
265 serial_clock <= 1'b0;
266 serial_data_out <= 1'b0;
267
268 end else begin
269
270 if (xfer_state == `START) begin
271 serial_resetn <= 1'b1;
272 serial_clock <= 1'b0;
273 xfer_count <= 6'd0;
274 if (pad_count == NUM_GPIO_PADS) begin
275 xfer_state <= `LOAD;
276 end else begin
277 pad_count <= pad_count + 1;
278 xfer_state <= `XBYTE;
279
280 for (i=0; i < NUM_GPIO_PADS; i = i + 1) begin
281 if (pad_count == i)
282 serial_data_staging <=
283 pad_configure[(i+1)*PAD_CTRL_BITS-1 : i*PAD_CTRL_BITS];
284 end
285 end
286 end else if (xfer_state == `XBYTE) begin
287 serial_resetn <= 1'b1;
288 serial_clock <= ~serial_clock;
289 if (serial_clock == 1'b0) begin
290 if (xfer_count == PAD_CTRL_BITS) begin
291 xfer_state <= `START;
292 end else begin
293 xfer_count <= xfer_count + 1;
294 end
295 end else begin
296 serial_data_staging <= {serial_data_staging[PAD_CTRL_BITS-2:0], 1'b0};
297 serial_data_out <= serial_data_staging[PAD_CTRL_BITS-1];
298 end
299 end else if (xfer_state == `LOAD) begin
300 xfer_count <= xfer_count + 1;
301
302 /* Load sequence: Raise clock for final data shift in;
303 * Pulse reset low while clock is high
304 * Set clock back to zero.
305 * Return to idle mode.
306 */
307 if (xfer_count == 4'd0) begin
308 serial_clock <= 1'b1;
309 serial_resetn <= 1'b1;
310 end else if (xfer_count == 4'd1) begin
311 serial_clock <= 1'b1;
312 serial_resetn <= 1'b0;
313 end else if (xfer_count == 4'd2) begin
314 serial_clock <= 1'b1;
315 serial_resetn <= 1'b1;
316 end else if (xfer_count == 4'd3) begin
317 serial_resetn <= 1'b1;
318 serial_clock <= 1'b0;
319 xfer_state <= `START;
320 end
321 end
322 end
323 end
324
325endmodule