shalan | 0d14e6e | 2020-08-31 16:50:48 +0200 | [diff] [blame] | 1 | module mprj_ctrl_wb #( |
| 2 | parameter BASE_ADR = 32'h 2300_0000, |
Tim Edwards | 04ba17f | 2020-10-02 22:27:50 -0400 | [diff] [blame^] | 3 | parameter DATA = 8'h 00, |
| 4 | parameter XFER = 8'h 04, |
| 5 | parameter CONFIG = 8'h 08, |
shalan | 0d14e6e | 2020-08-31 16:50:48 +0200 | [diff] [blame] | 6 | 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 Edwards | 04ba17f | 2020-10-02 22:27:50 -0400 | [diff] [blame^] | 22 | // Output is to serial loader |
| 23 | output serial_clock, |
| 24 | output serial_resetn, |
| 25 | output serial_data_out, |
shalan | 0d14e6e | 2020-08-31 16:50:48 +0200 | [diff] [blame] | 26 | |
Tim Edwards | 04ba17f | 2020-10-02 22:27:50 -0400 | [diff] [blame^] | 27 | // Read/write data to each GPIO pad from management SoC |
| 28 | inout [IO_PADS-1:0] mgmt_gpio_io |
| 29 | ); |
shalan | 0d14e6e | 2020-08-31 16:50:48 +0200 | [diff] [blame] | 30 | 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 Edwards | 04ba17f | 2020-10-02 22:27:50 -0400 | [diff] [blame^] | 43 | .DATA(DATA), |
| 44 | .CONFIG(CONFIG), |
| 45 | .XFER(XFER), |
| 46 | .IO_PADS(IO_PADS), |
shalan | 0d14e6e | 2020-08-31 16:50:48 +0200 | [diff] [blame] | 47 | .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 Edwards | 04ba17f | 2020-10-02 22:27:50 -0400 | [diff] [blame^] | 57 | |
| 58 | .serial_clock(serial_clock), |
| 59 | .serial_resetn(serial_resetn), |
| 60 | .serial_data_out(serial_data_out), |
| 61 | .mgmt_gpio_io(mgmt_gpio_io) |
shalan | 0d14e6e | 2020-08-31 16:50:48 +0200 | [diff] [blame] | 62 | ); |
| 63 | |
| 64 | endmodule |
| 65 | |
| 66 | module mprj_ctrl #( |
| 67 | parameter BASE_ADR = 32'h 2300_0000, |
Tim Edwards | 04ba17f | 2020-10-02 22:27:50 -0400 | [diff] [blame^] | 68 | parameter DATA = 8'h 00, |
| 69 | parameter XFER = 8'h 04, |
| 70 | parameter CONFIG = 8'h 08, |
shalan | 0d14e6e | 2020-08-31 16:50:48 +0200 | [diff] [blame] | 71 | 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, |
shalan | 0d14e6e | 2020-08-31 16:50:48 +0200 | [diff] [blame] | 81 | output reg [31:0] iomem_rdata, |
| 82 | output reg iomem_ready, |
| 83 | |
Tim Edwards | 04ba17f | 2020-10-02 22:27:50 -0400 | [diff] [blame^] | 84 | output serial_clock, |
| 85 | output serial_resetn, |
| 86 | output serial_data_out, |
| 87 | inout [IO_PADS-1:0] mgmt_gpio_io |
shalan | 0d14e6e | 2020-08-31 16:50:48 +0200 | [diff] [blame] | 88 | ); |
| 89 | |
Tim Edwards | 04ba17f | 2020-10-02 22:27:50 -0400 | [diff] [blame^] | 90 | 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. |
shalan | 0d14e6e | 2020-08-31 16:50:48 +0200 | [diff] [blame] | 93 | |
Tim Edwards | 04ba17f | 2020-10-02 22:27:50 -0400 | [diff] [blame^] | 94 | 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) |
shalan | 0d14e6e | 2020-08-31 16:50:48 +0200 | [diff] [blame] | 98 | |
Tim Edwards | 04ba17f | 2020-10-02 22:27:50 -0400 | [diff] [blame^] | 99 | wire [IO_PADS-1:0] io_ctrl_sel; // wishbone selects |
shalan | 0d14e6e | 2020-08-31 16:50:48 +0200 | [diff] [blame] | 100 | wire [PWR_CTRL-1:0] pwr_ctrl_sel; |
Tim Edwards | 04ba17f | 2020-10-02 22:27:50 -0400 | [diff] [blame^] | 101 | 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; |
shalan | 0d14e6e | 2020-08-31 16:50:48 +0200 | [diff] [blame] | 112 | |
| 113 | genvar i; |
| 114 | generate |
| 115 | for (i=0; i<IO_PADS; i=i+1) begin |
Tim Edwards | 04ba17f | 2020-10-02 22:27:50 -0400 | [diff] [blame^] | 116 | 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; |
shalan | 0d14e6e | 2020-08-31 16:50:48 +0200 | [diff] [blame] | 119 | 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 Edwards | 04ba17f | 2020-10-02 22:27:50 -0400 | [diff] [blame^] | 128 | // 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 | |
shalan | 0d14e6e | 2020-08-31 16:50:48 +0200 | [diff] [blame] | 153 | 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 |
shalan | 0d14e6e | 2020-08-31 16:50:48 +0200 | [diff] [blame] | 159 | if (iomem_valid && !iomem_ready && iomem_addr[31:8] == BASE_ADR[31:8]) begin |
shalan | 0d14e6e | 2020-08-31 16:50:48 +0200 | [diff] [blame] | 160 | 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 |
shalan | 0d14e6e | 2020-08-31 16:50:48 +0200 | [diff] [blame] | 186 | if (iomem_valid && !iomem_ready && iomem_addr[31:8] == BASE_ADR[31:8]) begin |
shalan | 0d14e6e | 2020-08-31 16:50:48 +0200 | [diff] [blame] | 187 | 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 Edwards | 04ba17f | 2020-10-02 22:27:50 -0400 | [diff] [blame^] | 207 | // 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 | |
| 221 | endmodule |
| 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 | |
| 236 | module 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 | |
| 325 | endmodule |