Tim Edwards | 04ba17f | 2020-10-02 22:27:50 -0400 | [diff] [blame^] | 1 | /* |
| 2 | *--------------------------------------------------------------------- |
| 3 | * This block interfaces between the sky130_fd_io GPIOv2 pad, the |
| 4 | * caravel management area, and the user project area. |
| 5 | * |
| 6 | * The management area has ultimate control over the setting of the |
| 7 | * pad, and can modify all core-voltage inputs to the pad and monitor |
| 8 | * the output. |
| 9 | * |
| 10 | * The user project will rely on the management SoC startup program |
| 11 | * to configure each I/O pad to a fixed configuration except for |
| 12 | * the output enable which remains under user control. |
| 13 | * |
| 14 | * This module is bit-sliced. Instantiate once for each GPIO pad. |
| 15 | * |
| 16 | *--------------------------------------------------------------------- |
| 17 | */ |
| 18 | |
| 19 | /* |
| 20 | *--------------------------------------------------------------------- |
| 21 | * |
| 22 | * This module instantiates a shift register chain that passes through |
| 23 | * each gpio cell. These are connected end-to-end around the padframe |
| 24 | * periphery. The purpose is to avoid a massive number of control |
| 25 | * wires between the digital core and I/O, passing through the user area. |
| 26 | * |
| 27 | * See mprj_ctrl.v for the module that registers the data for each |
| 28 | * I/O and drives the input to the shift register. |
| 29 | * |
| 30 | *--------------------------------------------------------------------- |
| 31 | */ |
| 32 | |
| 33 | module gpio_control_block #( |
| 34 | parameter PAD_CTRL_BITS = 13 |
| 35 | ) ( |
| 36 | // Management Soc-facing signals |
| 37 | input resetn, // Global reset |
| 38 | input serial_clock, |
| 39 | |
| 40 | inout mgmt_gpio_io, // Management to/from pad |
| 41 | |
| 42 | // Serial data chain for pad configuration |
| 43 | input serial_data_in, |
| 44 | output serial_data_out, |
| 45 | |
| 46 | // User-facing signals |
| 47 | input user_gpio_out, // User space to pad |
| 48 | input user_gpio_outenb, // Output enable (user) |
| 49 | output user_gpio_in, // Pad to user space |
| 50 | |
| 51 | // Pad-facing signals (Pad GPIOv2) |
| 52 | output pad_gpio_holdover, |
| 53 | output pad_gpio_slow_sel, |
| 54 | output pad_gpio_vtrip_sel, |
| 55 | output pad_gpio_inenb, |
| 56 | output pad_gpio_ib_mode_sel, |
| 57 | output pad_gpio_ana_en, |
| 58 | output pad_gpio_ana_sel, |
| 59 | output pad_gpio_ana_pol, |
| 60 | output [2:0] pad_gpio_dm, |
| 61 | output pad_gpio_outenb, |
| 62 | output pad_gpio_out, |
| 63 | input pad_gpio_in |
| 64 | ); |
| 65 | |
| 66 | /* Parameters defining the bit offset of each function in the chain */ |
| 67 | localparam MGMT_EN = 0; |
| 68 | localparam OEB = 1; |
| 69 | localparam HLDH = 2; |
| 70 | localparam ENH = 3; |
| 71 | localparam INP_DIS = 4; |
| 72 | localparam MOD_SEL = 5; |
| 73 | localparam AN_EN = 6; |
| 74 | localparam AN_SEL = 7; |
| 75 | localparam AN_POL = 8; |
| 76 | localparam SLOW = 9; |
| 77 | localparam TRIP = 10; |
| 78 | localparam DM = 11; |
| 79 | |
| 80 | /* Internally registered signals */ |
| 81 | reg mgmt_ena; // Enable management SoC to access pad |
| 82 | reg gpio_holdover; |
| 83 | reg gpio_slow_sel; |
| 84 | reg gpio_vtrip_sel; |
| 85 | reg gpio_inenb; |
| 86 | reg gpio_ib_mode_sel; |
| 87 | reg gpio_outenb; |
| 88 | reg [2:0] gpio_dm; |
| 89 | reg gpio_ana_en; |
| 90 | reg gpio_ana_sel; |
| 91 | reg gpio_ana_pol; |
| 92 | |
| 93 | /* Derived output values */ |
| 94 | wire pad_gpio_holdover; |
| 95 | wire pad_gpio_slow_sel; |
| 96 | wire pad_gpio_vtrip_sel; |
| 97 | wire pad_gpio_inenb; |
| 98 | wire pad_gpio_ib_mode_sel; |
| 99 | wire pad_gpio_ana_en; |
| 100 | wire pad_gpio_ana_sel; |
| 101 | wire pad_gpio_ana_pol; |
| 102 | wire [2:0] pad_gpio_dm; |
| 103 | wire pad_gpio_outenb; |
| 104 | wire pad_gpio_out; |
| 105 | wire pad_gpio_in; |
| 106 | |
| 107 | /* Serial shift for the above (latched) values */ |
| 108 | reg [PAD_CTRL_BITS-1:0] shift_register; |
| 109 | |
| 110 | /* Utilize reset and clock to encode a load operation */ |
| 111 | wire load_data; |
| 112 | wire int_reset; |
| 113 | |
| 114 | /* Create internal reset and load signals from input reset and clock */ |
| 115 | assign serial_data_out = shift_register[PAD_CTRL_BITS-1]; |
| 116 | assign int_reset = (~resetn) & (~serial_clock); |
| 117 | assign load_data = (~resetn) & serial_clock; |
| 118 | |
| 119 | always @(posedge serial_clock or posedge int_reset) begin |
| 120 | if (int_reset == 1'b1) begin |
| 121 | /* Clear shift register */ |
| 122 | shift_register <= 'd0; |
| 123 | end else begin |
| 124 | /* Shift data in */ |
| 125 | shift_register <= {shift_register[PAD_CTRL_BITS-2:0], serial_data_in}; |
| 126 | end |
| 127 | end |
| 128 | |
| 129 | always @(posedge load_data or posedge int_reset) begin |
| 130 | if (int_reset == 1'b1) begin |
| 131 | /* Initial state on reset: Pad set to management input */ |
| 132 | mgmt_ena <= 1'b0; |
| 133 | gpio_holdover <= 1'b0; // All signals latched in hold mode |
| 134 | gpio_slow_sel <= 1'b0; // Fast slew rate |
| 135 | gpio_vtrip_sel <= 1'b0; // CMOS mode |
| 136 | gpio_ib_mode_sel <= 1'b0; // CMOS mode |
| 137 | gpio_inenb <= 1'b0; // Input enabled |
| 138 | gpio_outenb <= 1'b1; // Output disabled |
| 139 | gpio_dm <= 3'b001; // Configured as input only |
| 140 | gpio_ana_en <= 1'b0; // Digital enabled |
| 141 | gpio_ana_sel <= 1'b0; // Don't-care when gpio_ana_en = 0 |
| 142 | gpio_ana_pol <= 1'b0; // Don't-care when gpio_ana_en = 0 |
| 143 | end else begin |
| 144 | /* Load data */ |
| 145 | mgmt_ena <= shift_register[MGMT_EN]; |
| 146 | gpio_outenb <= shift_register[OEB]; |
| 147 | gpio_holdover <= shift_register[HLDH]; |
| 148 | gpio_inenb <= shift_register[INP_DIS]; |
| 149 | gpio_ib_mode_sel <= shift_register[MOD_SEL]; |
| 150 | gpio_ana_en <= shift_register[AN_EN]; |
| 151 | gpio_ana_sel <= shift_register[AN_SEL]; |
| 152 | gpio_ana_pol <= shift_register[AN_POL]; |
| 153 | gpio_slow_sel <= shift_register[SLOW]; |
| 154 | gpio_vtrip_sel <= shift_register[TRIP]; |
| 155 | gpio_dm <= shift_register[DM+2:DM]; |
| 156 | |
| 157 | end |
| 158 | end |
| 159 | |
| 160 | /* These pad configuration signals are static and do not change */ |
| 161 | /* after setup. */ |
| 162 | |
| 163 | assign pad_gpio_holdover = gpio_holdover; |
| 164 | assign pad_gpio_slow_sel = gpio_slow_sel; |
| 165 | assign pad_gpio_vtrip_sel = gpio_vtrip_sel; |
| 166 | assign pad_gpio_ib_mode_sel = gpio_ib_mode_sel; |
| 167 | assign pad_gpio_ana_en = gpio_ana_en; |
| 168 | assign pad_gpio_ana_sel = gpio_ana_sel; |
| 169 | assign pad_gpio_ana_pol = gpio_ana_pol; |
| 170 | assign pad_gpio_dm = gpio_dm; |
| 171 | assign pad_gpio_inenb = gpio_inenb; |
| 172 | |
| 173 | /* Implement pad control behavior depending on state of mgmt_ena */ |
| 174 | |
| 175 | /* If pad is configured for input and dm[2:1] is 01, then pad is */ |
| 176 | /* configured as pull-up or pull-down depending on dm[0], and to */ |
| 177 | /* set the pullup or pulldown condition, the pad output bit must */ |
| 178 | /* be set to the opposite state of dm[0]. */ |
| 179 | /* dm[0] = 0 is pull-down; dm[0] = 1 is pull-up. */ |
| 180 | /* Otherwise, the output |
| 181 | |
| 182 | assign pad_gpio_out = (mgmt_ena) ? mgmt_gpio_io : |
| 183 | (((gpio_dm[2:1] == 2'b01) && (gpio_inenb == 1'b0)) ? |
| 184 | ~gpio_dm[0] : user_gpio_out); |
| 185 | |
| 186 | /* When under user control, gpio_outenb = 1 means that the pad is */ |
| 187 | /* configured as input, and the user outenb is unused. Otherwise, */ |
| 188 | /* the pad outenb signal is controlled by the user. */ |
| 189 | |
| 190 | assign pad_gpio_outenb = (mgmt_ena) ? gpio_outenb : |
| 191 | ((gpio_outenb == 1) ? 1'b1 : user_gpio_outenb); |
| 192 | |
| 193 | /* User gpio_in is grounded when the management controls the pad */ |
| 194 | assign user_gpio_in = (mgmt_ena) ? 1'b0 : pad_gpio_in; |
| 195 | |
| 196 | /* Management I/O line is set from the pad when the pad is */ |
| 197 | /* configured for input. */ |
| 198 | assign mgmt_gpio_io = (gpio_inenb == 0) ? pad_gpio_in : 1'bz; |
| 199 | |
| 200 | endmodule |