1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
|
//
// Copyright 2021 Ettus Research, A National Instruments Brand
//
// SPDX-License-Identifier: LGPL-3.0-or-later
//
// Module: x4xx_gpio_atr
//
// Description:
//
// This module controls the behavior of a GPIO bus of arbitrary width
// based on the current ATR state. The radio state is determined by
// combining the TX and RX states of each rf channel in the radio in
// the following order: {tx_rf1, rx_rf1, tx_rf0, rx_rf0}
//
// Parameters:
//
// REG_BASE : Base address to use for registers.
// REG_SIZE : Register space size.
// WIDTH : Number of GPIO lines controlled by this block.
//
module x4xx_gpio_atr #(
parameter REG_BASE = 0,
parameter REG_SIZE = 'h20,
parameter WIDTH = 32
) (
// Slave ctrlport interface
input wire ctrlport_clk,
input wire ctrlport_rst,
input wire s_ctrlport_req_wr,
input wire s_ctrlport_req_rd,
input wire [19:0] s_ctrlport_req_addr,
input wire [31:0] s_ctrlport_req_data,
output reg s_ctrlport_resp_ack = 1'b0,
output reg [ 1:0] s_ctrlport_resp_status = 2'b00,
output reg [31:0] s_ctrlport_resp_data = {32 {1'bX}},
// Run state signals that indicate tx and rx operation
input wire [3:0] db_state,
// GPIO control signals
input wire [WIDTH-1:0] gpio_in, //GPIO input state
output reg [WIDTH-1:0] gpio_out = {WIDTH {1'b0}}, //GPIO output state
output reg [WIDTH-1:0] gpio_ddr = {WIDTH {1'b0}} //GPIO direction (0=input, 1=output)
);
`include "../../lib/rfnoc/core/ctrlport.vh"
`include "regmap/gpio_atr_regmap_utils.vh"
reg [WIDTH-1:0] in_atr_state [15:0];
initial begin
in_atr_state[0] = {WIDTH {1'b0}};
in_atr_state[1] = {WIDTH {1'b0}};
in_atr_state[2] = {WIDTH {1'b0}};
in_atr_state[3] = {WIDTH {1'b0}};
in_atr_state[4] = {WIDTH {1'b0}};
in_atr_state[5] = {WIDTH {1'b0}};
in_atr_state[6] = {WIDTH {1'b0}};
in_atr_state[7] = {WIDTH {1'b0}};
in_atr_state[8] = {WIDTH {1'b0}};
in_atr_state[9] = {WIDTH {1'b0}};
in_atr_state[10] = {WIDTH {1'b0}};
in_atr_state[11] = {WIDTH {1'b0}};
in_atr_state[12] = {WIDTH {1'b0}};
in_atr_state[13] = {WIDTH {1'b0}};
in_atr_state[14] = {WIDTH {1'b0}};
in_atr_state[15] = {WIDTH {1'b0}};
end
reg [WIDTH-1:0] ddr_reg, atr_disable, gpio_sw_rb = {WIDTH {1'b0}};
reg [WIDTH-1:0] ogpio, igpio = {WIDTH {1'b0}};
reg [WIDTH-1:0] classic_atr_select = {WIDTH {1'b0}};
// DB state/Classic ATR selector
reg atr_mode = 1'b0;
genvar state;
//---------------------------------------------------------------------------
// Control interface handling
//---------------------------------------------------------------------------
// Check that address is within this module's range.
wire address_in_range = (s_ctrlport_req_addr >= REG_BASE) && (s_ctrlport_req_addr < REG_BASE + REG_SIZE);
// Check that address is targeting an ATR state.
wire address_is_atr = (s_ctrlport_req_addr >= REG_BASE + ATR_STATE(0)) && (s_ctrlport_req_addr <= REG_BASE + ATR_STATE(15));
// Decode the ATR state being addressed.
wire [3:0]atr_address = s_ctrlport_req_addr[5:2];
always @ (posedge ctrlport_clk) begin
if (ctrlport_rst) begin
s_ctrlport_resp_ack <= 1'b0;
s_ctrlport_resp_data <= {32 {1'bX}};
s_ctrlport_resp_status <= 2'b00;
ddr_reg <= {WIDTH {1'b0}};
atr_disable <= {WIDTH {1'b0}};
classic_atr_select <= {WIDTH {1'b0}};
atr_mode <= 1'b0;
in_atr_state[0] <= {WIDTH {1'b0}};
in_atr_state[1] <= {WIDTH {1'b0}};
in_atr_state[2] <= {WIDTH {1'b0}};
in_atr_state[3] <= {WIDTH {1'b0}};
in_atr_state[4] <= {WIDTH {1'b0}};
in_atr_state[5] <= {WIDTH {1'b0}};
in_atr_state[6] <= {WIDTH {1'b0}};
in_atr_state[7] <= {WIDTH {1'b0}};
in_atr_state[8] <= {WIDTH {1'b0}};
in_atr_state[9] <= {WIDTH {1'b0}};
in_atr_state[10] <= {WIDTH {1'b0}};
in_atr_state[11] <= {WIDTH {1'b0}};
in_atr_state[12] <= {WIDTH {1'b0}};
in_atr_state[13] <= {WIDTH {1'b0}};
in_atr_state[14] <= {WIDTH {1'b0}};
in_atr_state[15] <= {WIDTH {1'b0}};
end else begin
// Write registers
if (s_ctrlport_req_wr) begin
// Acknowledge by default
s_ctrlport_resp_ack <= 1'b1;
s_ctrlport_resp_data <= {CTRLPORT_DATA_W {1'b0}};
s_ctrlport_resp_status <= CTRL_STS_OKAY;
// Address ATR state writes
if(address_is_atr) begin
in_atr_state[atr_address][GPIO_STATE_A_MSB:GPIO_STATE_A] <= s_ctrlport_req_data[GPIO_STATE_A_MSB:GPIO_STATE_A];
in_atr_state[atr_address][GPIO_STATE_B_MSB:GPIO_STATE_B] <= s_ctrlport_req_data[GPIO_STATE_B_MSB:GPIO_STATE_B];
end else begin
// Address writes to the rest of the register space
case (s_ctrlport_req_addr)
REG_BASE + ATR_OPTION_REGISTRER: begin
atr_mode <= s_ctrlport_req_data[ATR_OPTION];
end
REG_BASE + CLASSIC_ATR_CONFIG: begin
classic_atr_select[RF_SELECT_A_MSB:RF_SELECT_A] <= s_ctrlport_req_data[RF_SELECT_A_MSB:RF_SELECT_A];
classic_atr_select[RF_SELECT_B_MSB:RF_SELECT_B] <= s_ctrlport_req_data[RF_SELECT_B_MSB:RF_SELECT_B];
end
REG_BASE + GPIO_DIR: begin
ddr_reg[GPIO_DIR_A_MSB:GPIO_DIR_A] <= s_ctrlport_req_data[GPIO_DIR_A_MSB:GPIO_DIR_A];
ddr_reg[GPIO_DIR_B_MSB:GPIO_DIR_B] <= s_ctrlport_req_data[GPIO_DIR_B_MSB:GPIO_DIR_B];
end
REG_BASE + GPIO_DISABLED: begin
atr_disable[GPIO_DISABLED_A_MSB:GPIO_DISABLED_A] <= s_ctrlport_req_data[GPIO_DISABLED_A_MSB:GPIO_DISABLED_A];
atr_disable[GPIO_DISABLED_B_MSB:GPIO_DISABLED_B] <= s_ctrlport_req_data[GPIO_DISABLED_B_MSB:GPIO_DISABLED_B];
end
// No register implementation for provided address
default: begin
// Acknowledge and provide error status if address is in range
if (address_in_range) begin
s_ctrlport_resp_status <= CTRL_STS_CMDERR;
// No response if out of range
end else begin
s_ctrlport_resp_ack <= 1'b0;
end
end
endcase
end
// Read registers
end else if (s_ctrlport_req_rd) begin
// Acknowledge by default
s_ctrlport_resp_ack <= 1'b1;
s_ctrlport_resp_data <= {CTRLPORT_DATA_W {1'b0}};
s_ctrlport_resp_status <= CTRL_STS_OKAY;
// Address ATR state reads
if(address_is_atr) begin
s_ctrlport_resp_data[GPIO_STATE_A_MSB:GPIO_STATE_A] <= in_atr_state[atr_address][GPIO_STATE_A_MSB:GPIO_STATE_A];
s_ctrlport_resp_data[GPIO_STATE_B_MSB:GPIO_STATE_B] <= in_atr_state[atr_address][GPIO_STATE_B_MSB:GPIO_STATE_B];
end else begin
// Address reads to the rest of the register space
case (s_ctrlport_req_addr)
REG_BASE + ATR_OPTION_REGISTRER: begin
s_ctrlport_resp_data[ATR_OPTION] <= atr_mode;
end
REG_BASE + CLASSIC_ATR_CONFIG: begin
s_ctrlport_resp_data[RF_SELECT_A_MSB:RF_SELECT_A] <= classic_atr_select[RF_SELECT_A_MSB:RF_SELECT_A];
s_ctrlport_resp_data[RF_SELECT_B_MSB:RF_SELECT_B] <= classic_atr_select[RF_SELECT_B_MSB:RF_SELECT_B];
end
REG_BASE + GPIO_DIR: begin
s_ctrlport_resp_data[GPIO_DIR_A_MSB:GPIO_DIR_A] <= ddr_reg[GPIO_DIR_A_MSB:GPIO_DIR_A];
s_ctrlport_resp_data[GPIO_DIR_B_MSB:GPIO_DIR_B] <= ddr_reg[GPIO_DIR_B_MSB:GPIO_DIR_B];
end
REG_BASE + GPIO_DISABLED: begin
s_ctrlport_resp_data[GPIO_DISABLED_A_MSB:GPIO_DISABLED_A] <= atr_disable[GPIO_DISABLED_A_MSB:GPIO_DISABLED_A];
s_ctrlport_resp_data[GPIO_DISABLED_B_MSB:GPIO_DISABLED_B] <= atr_disable[GPIO_DISABLED_B_MSB:GPIO_DISABLED_B];
end
REG_BASE + GPIO_IN: begin
s_ctrlport_resp_data[GPIO_IN_A_MSB:GPIO_IN_A] <= gpio_sw_rb[GPIO_IN_A_MSB:GPIO_IN_A];
s_ctrlport_resp_data[GPIO_IN_B_MSB:GPIO_IN_B] <= gpio_sw_rb[GPIO_IN_B_MSB:GPIO_IN_B];
end
// No register implementation for provided address
default: begin
// Acknowledge and provide error status if address is in range
if (address_in_range) begin
s_ctrlport_resp_status <= CTRL_STS_CMDERR;
// No response if out of range
end else begin
s_ctrlport_resp_ack <= 1'b0;
end
end
endcase
end
end else begin
s_ctrlport_resp_ack <= 1'b0;
end
end
end
genvar i;
//Pipeline for easier timing closure
reg [ 3:0] db_state_d = 4'b0;
reg atr_mode_d = 1'b0;
reg [WIDTH-1:0] classic_atr_select_d = {WIDTH {1'b0}};
always @(posedge ctrlport_clk) begin
db_state_d <= db_state;
atr_mode_d <= atr_mode;
classic_atr_select_d <= classic_atr_select;
end
generate
for (i=0; i<WIDTH; i=i+1) begin: gpio_mux_gen
//ATR selection MUX
// Classic ATR
always @(posedge ctrlport_clk) begin
if(atr_mode_d) begin
if (atr_disable[i]) begin
// ATR state 0 for RF 0 and ATR state 4 for RF1
ogpio[i] <= in_atr_state[classic_atr_select_d[i]*4][i];
end else begin
if (classic_atr_select_d[i]) begin // RF 1
ogpio[i] <= in_atr_state[db_state_d[3:2] + 4][i];
end else begin // RF 0
ogpio[i] <= in_atr_state[db_state_d[1:0]][i];
end
end
end else begin // Use DB state
if (atr_disable[i]) begin
ogpio[i] <= in_atr_state[0][i];
end else begin
ogpio[i] <= in_atr_state[db_state_d][i];
end
end
end
end
endgenerate
//Pipeline input, output and direction
always @(posedge ctrlport_clk)
gpio_out <= ogpio;
always @(posedge ctrlport_clk)
igpio <= gpio_in;
always @(posedge ctrlport_clk)
gpio_ddr <= ddr_reg;
//Generate software readback state
generate
for (i=0; i<WIDTH; i=i+1) begin: gpio_rb_gen
always @(posedge ctrlport_clk)
gpio_sw_rb[i] <= gpio_ddr[i] ? gpio_out[i] : igpio[i];
end
endgenerate
endmodule
//XmlParse xml_on
//<regmap name="GPIO_ATR_REGMAP" readablestrobes="false" generatevhdl="true" ettusguidelines="true">
// <group name="GPIO_ATR_REGS">
// <info>
// Describes the behavior of GPIO lines when controlled by the ATR state.
// </info>
//
// <regtype name="GPIO_ATR_STATE" size="32">
// <info>Holds a single bit setting for GPIO lines in both ports for a particular ATR sate</info>
// <bitfield name="GPIO_STATE_A" range="0..11" initialvalue="0"/>
// <bitfield name="GPIO_STATE_B" range="16..27" initialvalue="0"/>
// </regtype>
//
// <register name="ATR_STATE" typename="GPIO_ATR_STATE" offset="0x00" count="16" options="--step 4">
// <info>
// Describes GPIO behavior for the different ATR states. When @.ATR_OPTION
// is set to use the DB states, TX and RX states for RF0 and RF1 are
// combined to create a single vector. This creates 16 different
// combinations, each with its own register. When @.ATR_OPTION is set to
// classic ATR, offsets 0x00-0x03 in this register group will be driven
// in accordance with the state of RF0, and offsets 0x04-0x07 will be
// driven in accordance with the state of RF1.
// CLASSIC ATR MAPPING: Idle[RF0:0x00; RF1:0x04], RX[RF0:0x01; RF1:0x05],
// TX[RF0:0x02; RF1:0x06], FDX[RF0:0x03; RF1:0x07]
// </info>
// </register>
// <register name="ATR_OPTION_REGISTRER" offset="0x44" size="32">
// <info>
// Controls whether GPIO lines use the TX and RX state of an RF channel
// (Classic ATR) or the daughterboard state the selector for the
// @.GPIO_ATR_STATE.
// </info>
// <bitfield name="ATR_OPTION" range="0" initialvalue="0">
// <info>
// Sets the scheme in which RF states in the radio will control GPIO
// lines. 0 = DB state is used. RF states are combined and the
// GPIO state is driven based on all 16 @.GPIO_ATR_STATE registers.
// 1 = Each RF channel has its separate ATR state(Classic ATR).
// Use register @.CLASSIC_ATR_CONFIG to indicate the RF channel
// to which each GPIO line responds to.
// </info>
// </bitfield>
// </register>
// <register name="CLASSIC_ATR_CONFIG" offset="0x40" size="32">
// <info>
// Controls the RF state mapping of each GPIO line when classic
// ATR mode is active.
// </info>
// <bitfield name="RF_SELECT_A" range="0..11" initialvalue="0">
// <info>
// Set which RF channel's state to reflect in the pins for
// HDMI connector A when @.ATR_OPTION is set to classic ATR.
// Controlled in a per-pin basis.
// 0 = RF0 State(GPIO_ATR_STATE 0x00-0x03)
// 1 = RF1 State(GPIO_ATR_STATE 0x04-0x07)
// </info>
// </bitfield>
// <bitfield name="RF_SELECT_B" range="16..27" initialvalue="0">
// <info>
// Set which RF channel's state to reflect in the pins of
// HDMI connector B when @.ATR_OPTION is set to classic ATR.
// Controlled in a per-pin basis.
// 0 = RF0 State(GPIO_ATR_STATE 0x00-0x03)
// 1 = RF1 State(GPIO_ATR_STATE 0x04-0x07)
// </info>
// </bitfield>
// </register>
// <register name="GPIO_DIR" offset="0x48" size="32">
// <info>
// Controls the direction of each GPIO signal when controlled by the radio state.
// 0 = GPIO pin set to input. 1 = GPIO pin set to output
// </info>
// <bitfield name="GPIO_DIR_A" range="0..11" initialvalue="0"/>
// <bitfield name="GPIO_DIR_B" range="16..27" initialvalue="0"/>
// </register>
// <register name="GPIO_DISABLED" offset="0x4C" size="32">
// <info>
// Disable ATR Control. DB state 0 will be reflected regardless of the ATR state.
// </info>
// <bitfield name="GPIO_DISABLED_A" range="0..11" initialvalue="0"/>
// <bitfield name="GPIO_DISABLED_B" range="16..27" initialvalue="0"/>
// </register>
// <register name="GPIO_IN" offset="0x50" size="32">
// <info>
// Reflects the logic state of each GPIO input.
// </info>
// <bitfield name="GPIO_IN_A" range="0..11" initialvalue="0"/>
// <bitfield name="GPIO_IN_B" range="16..27" initialvalue="0"/>
// </register>
// </group>
//</regmap>
//XmlParse xml_off
|