Skip to content

Commit 2c4c18b

Browse files
committed
[i2c,testutils] Move i2c testutils to DT API
Signed-off-by: Robert Schilling <[email protected]>
1 parent 1aa2571 commit 2c4c18b

File tree

2 files changed

+86
-124
lines changed

2 files changed

+86
-124
lines changed

sw/device/lib/testing/BUILD

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -212,6 +212,7 @@ cc_library(
212212
hdrs = ["i2c_testutils.h"],
213213
target_compatible_with = [OPENTITAN_CPU],
214214
deps = [
215+
"//hw/top:dt",
215216
"//hw/top:i2c_c_regs",
216217
"//sw/device/lib/dif:i2c",
217218
"//sw/device/lib/dif:pinmux",
@@ -626,7 +627,6 @@ cc_library(
626627
TESTUTILS_EXCEPTIONS = [
627628
"aes",
628629
"csrng",
629-
"i2c",
630630
"uart",
631631
"rstmgr",
632632
]

sw/device/lib/testing/i2c_testutils.c

Lines changed: 85 additions & 123 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@
88
#include <stdbool.h>
99
#include <stdint.h>
1010

11+
#include "hw/top/dt/dt_i2c.h"
12+
#include "hw/top/dt/dt_pinmux.h"
1113
#include "sw/device/lib/base/mmio.h"
1214
#include "sw/device/lib/dif/dif_i2c.h"
1315
#include "sw/device/lib/dif/dif_pinmux.h"
@@ -18,7 +20,6 @@
1820
#include "sw/device/lib/testing/test_framework/check.h"
1921

2022
#include "hw/top/i2c_regs.h" // Generated.
21-
#include "hw/top_earlgrey/sw/autogen/top_earlgrey.h"
2223

2324
#define MODULE_ID MAKE_MODULE_ID('i', 'i', 't')
2425

@@ -35,126 +36,78 @@ static const dif_i2c_fmt_flags_t kDefaultFlags = {.start = false,
3536
.suppress_nak_irq = false};
3637

3738
/**
38-
* Define an i2c pinmux configuration.
39+
* Get the I2C instance from index.
40+
*
41+
* @param i2c_idx I2C index (0-based).
42+
* @return I2C DT instance, or kDtI2cCount if invalid.
3943
*/
40-
typedef struct i2c_pinmux_pins {
41-
pinmux_testutils_peripheral_pin_t sda;
42-
pinmux_testutils_peripheral_pin_t scl;
43-
} i2c_pinmux_pins_t;
44-
45-
/**
46-
* Define an i2c pinmux configuration.
47-
*/
48-
typedef struct i2c_platform_pins {
49-
pinmux_testutils_mio_pin_t sda;
50-
pinmux_testutils_mio_pin_t scl;
51-
} i2c_platform_pins_t;
52-
53-
/**
54-
* This table store the pins of all i2c instances of Earlgrey.
55-
* This is used to connect i2c instances to mio pins based on the platform.
56-
*/
57-
static const i2c_pinmux_pins_t kI2cPinmuxPins[] = {
58-
// I2C0.
59-
{.sda =
60-
{
61-
.peripheral_in = kTopEarlgreyPinmuxPeripheralInI2c0Sda,
62-
.outsel = kTopEarlgreyPinmuxOutselI2c0Sda,
63-
},
64-
.scl =
65-
{
66-
.peripheral_in = kTopEarlgreyPinmuxPeripheralInI2c0Scl,
67-
.outsel = kTopEarlgreyPinmuxOutselI2c0Scl,
68-
}},
69-
// I2C1.
70-
{.sda =
71-
{
72-
.peripheral_in = kTopEarlgreyPinmuxPeripheralInI2c1Sda,
73-
.outsel = kTopEarlgreyPinmuxOutselI2c1Sda,
74-
},
75-
.scl =
76-
{
77-
.peripheral_in = kTopEarlgreyPinmuxPeripheralInI2c1Scl,
78-
.outsel = kTopEarlgreyPinmuxOutselI2c1Scl,
79-
}},
80-
// I2C2.
81-
{.sda =
82-
{
83-
.peripheral_in = kTopEarlgreyPinmuxPeripheralInI2c2Sda,
84-
.outsel = kTopEarlgreyPinmuxOutselI2c2Sda,
85-
},
86-
.scl =
87-
{
88-
.peripheral_in = kTopEarlgreyPinmuxPeripheralInI2c2Scl,
89-
.outsel = kTopEarlgreyPinmuxOutselI2c2Scl,
90-
}},
91-
};
44+
static dt_i2c_t get_i2c_instance(uint8_t i2c_idx) {
45+
if (i2c_idx >= kDtI2cCount) {
46+
return kDtI2cCount;
47+
}
48+
return (dt_i2c_t)i2c_idx;
49+
}
9250

9351
/**
94-
* Map the combination of platform and I2C ID to pins for SCL and SDA.
52+
* Get the appropriate pads for an I2C instance and platform based on the
53+
* platform. This replicates the original behavior with different mappings for
54+
* different platforms.
55+
*
56+
* @param i2c_dt I2C DT instance.
57+
* @param platform The platform to connect the I2C to.
58+
* @param sda_pad Output parameter for SDA pad.
59+
* @param scl_pad Output parameter for SCL pad.
60+
* @return OK_STATUS if successful, error status otherwise.
9561
*/
96-
static status_t map_platform_to_pins(i2c_pinmux_platform_id_t platform,
97-
uint8_t i2c_id,
98-
i2c_platform_pins_t *pins) {
99-
TRY_CHECK(pins != NULL);
62+
static status_t get_i2c_pads_for_platform(dt_i2c_t i2c_dt,
63+
i2c_pinmux_platform_id_t platform,
64+
dt_pad_t *sda_pad,
65+
dt_pad_t *scl_pad) {
66+
#if defined(OPENTITAN_IS_DARJEELING)
67+
// Darjeeling only has I2C0 and uses dedicated pads
68+
if (i2c_dt != kDtI2c0) {
69+
return INVALID_ARGUMENT();
70+
}
71+
*sda_pad = kDtPadI2c0Sda;
72+
*scl_pad = kDtPadI2c0Scl;
73+
#elif defined(OPENTITAN_IS_EARLGREY) || defined(OPENTITAN_IS_ENGLISHBREAKFAST)
74+
// For Earlgrey and EnglishBreakfast platforms
10075
switch (platform) {
10176
case I2cPinmuxPlatformIdHyper310: // CW310 HyperDebug
102-
*pins =
103-
(i2c_platform_pins_t){.sda =
104-
{
105-
.mio_out = kTopEarlgreyPinmuxMioOutIoa7,
106-
.insel = kTopEarlgreyPinmuxInselIoa7,
107-
},
108-
.scl = {
109-
.mio_out = kTopEarlgreyPinmuxMioOutIoa8,
110-
.insel = kTopEarlgreyPinmuxInselIoa8,
111-
}};
77+
*sda_pad = kDtPadIoa7;
78+
*scl_pad = kDtPadIoa8;
11279
break;
11380
case I2cPinmuxPlatformIdDvsim: // DV
11481
// In DV, there's one agent for each I2C instance, with a fixed set of
11582
// muxed pins.
116-
switch (i2c_id) {
117-
case 0: // I2C0 uses the same pins as CW310 HyperDebug
118-
TRY(map_platform_to_pins(I2cPinmuxPlatformIdHyper310, i2c_id, pins));
83+
switch (i2c_dt) {
84+
case kDtI2c0: // I2C0 uses the same pins as CW310 HyperDebug
85+
*sda_pad = kDtPadIoa7;
86+
*scl_pad = kDtPadIoa8;
11987
break;
120-
case 1:
121-
*pins = (i2c_platform_pins_t){
122-
.sda =
123-
{
124-
.mio_out = kTopEarlgreyPinmuxMioOutIob10,
125-
.insel = kTopEarlgreyPinmuxInselIob10,
126-
},
127-
.scl =
128-
{
129-
.mio_out = kTopEarlgreyPinmuxMioOutIob9,
130-
.insel = kTopEarlgreyPinmuxInselIob9,
131-
},
132-
};
88+
case kDtI2c1:
89+
*sda_pad = kDtPadIob10;
90+
*scl_pad = kDtPadIob9;
13391
break;
134-
case 2: // I2C2 uses the same pins as CW310 PMOD
135-
TRY(map_platform_to_pins(I2cPinmuxPlatformIdCw310Pmod, i2c_id, pins));
92+
case kDtI2c2: // I2C2 uses the same pins as CW310 PMOD
93+
*sda_pad = kDtPadIob12;
94+
*scl_pad = kDtPadIob11;
13695
break;
13796
default:
138-
TRY_CHECK(false, "invalid i2c_id: %0d", i2c_id);
139-
break;
97+
return INVALID_ARGUMENT();
14098
}
14199
break;
142100
case I2cPinmuxPlatformIdCw310Pmod: // CW310 PMOD
143-
*pins = (i2c_platform_pins_t){
144-
.sda =
145-
{
146-
.mio_out = kTopEarlgreyPinmuxMioOutIob12,
147-
.insel = kTopEarlgreyPinmuxInselIob12,
148-
},
149-
.scl = {
150-
.mio_out = kTopEarlgreyPinmuxMioOutIob11,
151-
.insel = kTopEarlgreyPinmuxInselIob11,
152-
}};
101+
*sda_pad = kDtPadIob12;
102+
*scl_pad = kDtPadIob11;
153103
break;
154104
default:
155-
TRY_CHECK(false, "invalid platform: %0d", platform);
156-
break;
105+
return INVALID_ARGUMENT();
157106
}
107+
#else
108+
return UNIMPLEMENTED();
109+
#endif
110+
158111
return OK_STATUS();
159112
}
160113

@@ -344,34 +297,43 @@ status_t i2c_testutils_target_check_write(const dif_i2c_t *i2c,
344297

345298
status_t i2c_testutils_select_pinmux(const dif_pinmux_t *pinmux, uint8_t i2c_id,
346299
i2c_pinmux_platform_id_t platform) {
347-
TRY_CHECK(
348-
platform < I2cPinmuxPlatformIdCount && i2c_id < ARRAYSIZE(kI2cPinmuxPins),
349-
"Index out of bounds");
350-
i2c_platform_pins_t platform_pins;
351-
TRY(map_platform_to_pins(platform, i2c_id, &platform_pins));
352-
// Configure sda pin.
353-
TRY(dif_pinmux_input_select(pinmux, kI2cPinmuxPins[i2c_id].sda.peripheral_in,
354-
platform_pins.sda.insel));
355-
TRY(dif_pinmux_output_select(pinmux, platform_pins.sda.mio_out,
356-
kI2cPinmuxPins[i2c_id].sda.outsel));
357-
358-
// Configure scl pin.
359-
TRY(dif_pinmux_input_select(pinmux, kI2cPinmuxPins[i2c_id].scl.peripheral_in,
360-
platform_pins.scl.insel));
361-
TRY(dif_pinmux_output_select(pinmux, platform_pins.scl.mio_out,
362-
kI2cPinmuxPins[i2c_id].scl.outsel));
300+
TRY_CHECK(platform < I2cPinmuxPlatformIdCount, "Platform out of bounds");
301+
302+
dt_i2c_t i2c_dt = get_i2c_instance(i2c_id);
303+
TRY_CHECK(i2c_dt < kDtI2cCount, "I2C index out of bounds");
304+
305+
// Get peripheral I/O descriptions for SDA and SCL
306+
dt_periph_io_t sda_periph_io = dt_i2c_periph_io(i2c_dt, kDtI2cPeriphIoSda);
307+
dt_periph_io_t scl_periph_io = dt_i2c_periph_io(i2c_dt, kDtI2cPeriphIoScl);
308+
309+
// Get the appropriate pads for this I2C instance and platform
310+
dt_pad_t sda_pad, scl_pad;
311+
TRY(get_i2c_pads_for_platform(i2c_dt, platform, &sda_pad, &scl_pad));
312+
313+
// Connect SDA and SCL using pinmux testutils
314+
TRY(pinmux_testutils_connect(pinmux, sda_periph_io, kDtPeriphIoDirInout,
315+
sda_pad));
316+
TRY(pinmux_testutils_connect(pinmux, scl_periph_io, kDtPeriphIoDirInout,
317+
scl_pad));
318+
363319
return OK_STATUS();
364320
}
365321

366322
status_t i2c_testutils_detach_pinmux(const dif_pinmux_t *pinmux,
367323
uint8_t i2c_id) {
368-
// Configure sda pin.
369-
TRY(dif_pinmux_input_select(pinmux, kI2cPinmuxPins[i2c_id].sda.peripheral_in,
370-
kTopEarlgreyPinmuxInselConstantZero));
324+
dt_i2c_t i2c_dt = get_i2c_instance(i2c_id);
325+
TRY_CHECK(i2c_dt < kDtI2cCount, "I2C index out of bounds");
326+
327+
// Get peripheral I/O descriptions for SDA and SCL
328+
dt_periph_io_t sda_periph_io = dt_i2c_periph_io(i2c_dt, kDtI2cPeriphIoSda);
329+
dt_periph_io_t scl_periph_io = dt_i2c_periph_io(i2c_dt, kDtI2cPeriphIoScl);
330+
331+
// Disconnect SDA and SCL inputs by connecting to constant zero
332+
TRY(pinmux_testutils_connect(pinmux, sda_periph_io, kDtPeriphIoDirIn,
333+
kDtPadConstantZero));
334+
TRY(pinmux_testutils_connect(pinmux, scl_periph_io, kDtPeriphIoDirIn,
335+
kDtPadConstantZero));
371336

372-
// Configure scl pin.
373-
TRY(dif_pinmux_input_select(pinmux, kI2cPinmuxPins[i2c_id].scl.peripheral_in,
374-
kTopEarlgreyPinmuxInselConstantZero));
375337
return OK_STATUS();
376338
}
377339

0 commit comments

Comments
 (0)