Skip to content

Commit e23163a

Browse files
committed
lib: tenstorrent: bh_arc: regulator: replace bh_arc i2c with zephyr i2c
Replace the old bh_arc I2C library with upstream Zephyr I2C driver. Signed-off-by: Alex Apostolu <aapostolu@tenstorrent.com>
1 parent 3c59849 commit e23163a

File tree

1 file changed

+105
-42
lines changed

1 file changed

+105
-42
lines changed

lib/tenstorrent/bh_arc/regulator.c

Lines changed: 105 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2024 Tenstorrent AI ULC
2+
* Copyright (c) 2025 Tenstorrent AI ULC
33
*
44
* SPDX-License-Identifier: Apache-2.0
55
*/
@@ -14,6 +14,7 @@
1414
#include <math.h> /* for ldexp */
1515
#include <float.h> /* for FLT_MAX */
1616
#include <stdint.h>
17+
#include <string.h> /* for memcpy */
1718

1819
#include <tenstorrent/smc_msg.h>
1920
#include <tenstorrent/msgqueue.h>
@@ -23,13 +24,13 @@
2324
#include <zephyr/kernel.h>
2425
#include <zephyr/logging/log.h>
2526
#include <zephyr/drivers/misc/bh_fwtable.h>
27+
#include <zephyr/drivers/i2c.h>
28+
#include <zephyr/drivers/i2c/i2c_dw.h>
29+
#include <zephyr/devicetree.h>
2630

2731
#define LINEAR_FORMAT_CONSTANT (1 << 9)
2832
#define SCALE_LOOP 0.335f
2933

30-
/* I2C constants */
31-
#define PMBUS_MST_ID 1
32-
3334
/* PMBus Spec constants */
3435
#define MFR_CTRL_OPS 0xD2
3536
#define MFR_CTRL_OPS_DATA_BYTE_SIZE 1
@@ -72,6 +73,47 @@ LOG_MODULE_REGISTER(regulator);
7273
/* The default value is the regulator default */
7374
static uint8_t vout_cmd_source = VoutCommand;
7475
static const struct device *const fwtable_dev = DEVICE_DT_GET(DT_NODELABEL(fwtable));
76+
static const struct device *const i2c1_dev = DEVICE_DT_GET(DT_NODELABEL(i2c1));
77+
78+
/* I2C Read-Modify-Write-Verify helper function */
79+
static uint32_t i2c_rmwv(uint16_t slave_addr, uint16_t command, uint32_t command_byte_size,
80+
const uint8_t *p_data, const uint8_t *p_mask, uint32_t data_byte_size)
81+
{
82+
uint8_t buffer[data_byte_size];
83+
uint8_t cmd = (uint8_t)command;
84+
int ret;
85+
86+
ret = i2c_write_read(i2c1_dev, slave_addr, &cmd, command_byte_size, buffer, data_byte_size);
87+
if (ret != 0) {
88+
return ret;
89+
}
90+
91+
for (uint32_t i = 0; i < data_byte_size; i++) {
92+
buffer[i] = (buffer[i] & ~p_mask[i]) | (p_data[i] & p_mask[i]);
93+
}
94+
95+
uint8_t cmd_data[command_byte_size + data_byte_size];
96+
97+
memcpy(cmd_data, &command, command_byte_size);
98+
memcpy(cmd_data + command_byte_size, buffer, data_byte_size);
99+
ret = i2c_write(i2c1_dev, cmd_data, sizeof(cmd_data), slave_addr);
100+
if (ret != 0) {
101+
return ret;
102+
}
103+
104+
ret = i2c_write_read(i2c1_dev, slave_addr, &cmd, command_byte_size, buffer, data_byte_size);
105+
if (ret != 0) {
106+
return ret;
107+
}
108+
109+
for (uint32_t i = 0; i < data_byte_size; i++) {
110+
if ((buffer[i] & p_mask[i]) != (p_data[i] & p_mask[i])) {
111+
return -EIO;
112+
}
113+
}
114+
115+
return 0;
116+
}
75117

76118
static float ConvertLinear11ToFloat(uint16_t value)
77119
{
@@ -88,73 +130,79 @@ static float ConvertLinear11ToFloat(uint16_t value)
88130
/* The function returns the core current in A. */
89131
float GetVcoreCurrent(void)
90132
{
91-
I2CInit(I2CMst, P0V8_VCORE_ADDR, I2CFastMode, PMBUS_MST_ID);
92133
uint16_t iout;
134+
uint8_t cmd = READ_IOUT;
135+
136+
if (i2c_write_read(i2c1_dev, P0V8_VCORE_ADDR, &cmd, 1, (uint8_t *)&iout, 2) != 0) {
137+
return 0.0f;
138+
}
93139

94-
I2CReadBytes(PMBUS_MST_ID, READ_IOUT, PMBUS_CMD_BYTE_SIZE, (uint8_t *)&iout,
95-
READ_IOUT_DATA_BYTE_SIZE, PMBUS_FLIP_BYTES);
96140
return ConvertLinear11ToFloat(iout);
97141
}
98142

99143
/* The function returns the core power in W. */
100144
float GetVcorePower(void)
101145
{
102-
I2CInit(I2CMst, P0V8_VCORE_ADDR, I2CFastMode, PMBUS_MST_ID);
103146
uint16_t pout;
147+
uint8_t cmd = READ_POUT;
148+
149+
if (i2c_write_read(i2c1_dev, P0V8_VCORE_ADDR, &cmd, 1, (uint8_t *)&pout, 2) != 0) {
150+
return 0.0f;
151+
}
104152

105-
I2CReadBytes(PMBUS_MST_ID, READ_POUT, PMBUS_CMD_BYTE_SIZE, (uint8_t *)&pout,
106-
READ_POUT_DATA_BYTE_SIZE, PMBUS_FLIP_BYTES);
107153
return ConvertLinear11ToFloat(pout);
108154
}
109155

110156
static void set_max20730(uint32_t slave_addr, uint32_t voltage_in_mv, float rfb1, float rfb2)
111157
{
112-
I2CInit(I2CMst, slave_addr, I2CFastMode, PMBUS_MST_ID);
113158
float vref = voltage_in_mv / (1 + rfb1 / rfb2);
114159
uint16_t vout_cmd = vref * LINEAR_FORMAT_CONSTANT * 0.001f;
160+
uint8_t cmd_data[3] = {VOUT_COMMAND, (uint8_t)vout_cmd, (uint8_t)(vout_cmd >> 8)};
115161

116-
I2CWriteBytes(PMBUS_MST_ID, VOUT_COMMAND, PMBUS_CMD_BYTE_SIZE, (uint8_t *)&vout_cmd,
117-
VOUT_COMMAND_DATA_BYTE_SIZE);
162+
i2c_write(i2c1_dev, cmd_data, sizeof(cmd_data), slave_addr);
118163

119164
/* delay to flush i2c transaction and voltage change */
120-
WaitUs(250);
165+
k_busy_wait(250);
121166
}
122167

123168
static void set_mpm3695(uint32_t slave_addr, uint32_t voltage_in_mv, float rfb1, float rfb2)
124169
{
125-
I2CInit(I2CMst, slave_addr, I2CFastMode, PMBUS_MST_ID);
126170
uint16_t vout_cmd = voltage_in_mv * 0.5f / SCALE_LOOP / (1 + rfb1 / rfb2);
171+
uint8_t cmd_data[3] = {VOUT_COMMAND, (uint8_t)vout_cmd, (uint8_t)(vout_cmd >> 8)};
127172

128-
I2CWriteBytes(PMBUS_MST_ID, VOUT_COMMAND, PMBUS_CMD_BYTE_SIZE, (uint8_t *)&vout_cmd,
129-
VOUT_COMMAND_DATA_BYTE_SIZE);
173+
i2c_write(i2c1_dev, cmd_data, sizeof(cmd_data), slave_addr);
130174

131175
/* delay to flush i2c transaction and voltage change */
132-
WaitUs(250);
176+
k_busy_wait(250);
133177
}
134178

135179
/* Set MAX20816 voltage using I2C, MAX20816 is used for Vcore and Vcorem */
136180
static void i2c_set_max20816(uint32_t slave_addr, uint32_t voltage_in_mv)
137181
{
138-
I2CInit(I2CMst, slave_addr, I2CFastMode, PMBUS_MST_ID);
139182
uint16_t vout_cmd = 2 * voltage_in_mv;
183+
uint8_t cmd_data[3] = {VOUT_COMMAND, (uint8_t)vout_cmd, (uint8_t)(vout_cmd >> 8)};
140184

141-
I2CWriteBytes(PMBUS_MST_ID, VOUT_COMMAND, PMBUS_CMD_BYTE_SIZE, (uint8_t *)&vout_cmd,
142-
VOUT_COMMAND_DATA_BYTE_SIZE);
185+
i2c_write(i2c1_dev, cmd_data, sizeof(cmd_data), slave_addr);
143186

144187
/* 100us to flush the tx of i2c + 150us to cover voltage switch from 0.65V to 0.95V with
145188
* 50us of margin
146189
*/
147-
WaitUs(250);
190+
k_busy_wait(250);
148191
}
149192

150193
/* Returns MAX20816 output volage in mV. */
151194
static float i2c_get_max20816(uint32_t slave_addr)
152195
{
153-
I2CInit(I2CMst, slave_addr, I2CFastMode, PMBUS_MST_ID);
154196
uint16_t vout_cmd = 0;
197+
uint8_t cmd = READ_VOUT;
198+
int ret;
155199

156-
I2CReadBytes(PMBUS_MST_ID, READ_VOUT, PMBUS_CMD_BYTE_SIZE, (uint8_t *)&vout_cmd,
157-
READ_VOUT_DATA_BYTE_SIZE, PMBUS_FLIP_BYTES);
200+
ret = i2c_write_read(i2c1_dev, slave_addr, &cmd, sizeof(cmd), (uint8_t *)&vout_cmd,
201+
sizeof(vout_cmd));
202+
if (ret != 0) {
203+
LOG_ERR("I2C read failed: %d", ret);
204+
return 0.0f;
205+
}
158206

159207
return vout_cmd * 0.5f;
160208
}
@@ -198,29 +246,47 @@ void set_gddr_vddr(PcbType board_type, uint32_t voltage_in_mv)
198246

199247
void SwitchVoutControl(VoltageCmdSource source)
200248
{
201-
I2CInit(I2CMst, P0V8_VCORE_ADDR, I2CFastMode, PMBUS_MST_ID);
202249
OperationBits operation;
250+
uint8_t cmd = OPERATION;
251+
int ret;
252+
253+
ret = i2c_write_read(i2c1_dev, P0V8_VCORE_ADDR, &cmd, 1, (uint8_t *)&operation,
254+
sizeof(operation));
255+
if (ret != 0) {
256+
LOG_ERR("I2C read operation register failed: %d", ret);
257+
return;
258+
}
203259

204-
I2CReadBytes(PMBUS_MST_ID, OPERATION, PMBUS_CMD_BYTE_SIZE, (uint8_t *)&operation,
205-
OPERATION_DATA_BYTE_SIZE, PMBUS_FLIP_BYTES);
206260
operation.transition_control =
207261
1; /* copy vout command when control is passed from AVSBus to PMBus */
208262
operation.voltage_command_source = source;
209-
I2CWriteBytes(PMBUS_MST_ID, OPERATION, PMBUS_CMD_BYTE_SIZE, (uint8_t *)&operation,
210-
OPERATION_DATA_BYTE_SIZE);
263+
264+
uint8_t cmd_data[2] = {cmd, *(uint8_t *)&operation};
265+
266+
ret = i2c_write(i2c1_dev, cmd_data, sizeof(cmd_data), P0V8_VCORE_ADDR);
267+
if (ret != 0) {
268+
LOG_ERR("I2C write operation register failed: %d", ret);
269+
return;
270+
}
211271

212272
/* 100us to flush the tx of i2c */
213-
WaitUs(100);
273+
k_busy_wait(100);
214274
vout_cmd_source = source;
215275
}
216276

217277
uint32_t RegulatorInit(PcbType board_type)
218278
{
279+
if (!device_is_ready(i2c1_dev)) {
280+
return -ENODEV;
281+
}
282+
219283
uint32_t aggregate_i2c_errors = 0;
220284
uint32_t i2c_error = 0;
221285

222286
const BoardRegulatorsConfig *regulators_config = NULL;
223287

288+
i2c_dw_register_recover_bus_cb(i2c1_dev, tt_bh_i2c_recover_bus, i2c1_dev);
289+
224290
if (board_type == PcbTypeP150) {
225291
regulators_config = &p150_regulators_config;
226292
} else if (board_type == PcbTypeP300) {
@@ -240,32 +306,29 @@ uint32_t RegulatorInit(PcbType board_type)
240306
const RegulatorConfig *regulator_config =
241307
regulators_config->regulator_config + i;
242308

243-
I2CInit(I2CMst, regulator_config->address, I2CFastMode, PMBUS_MST_ID);
244-
245309
for (uint32_t j = 0; j < regulator_config->count; j++) {
246310
const RegulatorData *regulator_data =
247311
&regulator_config->regulator_data[j];
248312

249313
LOG_DBG("Regulator %#x init on cmd %#x", regulator_config->address,
250314
regulator_data->cmd);
251315

252-
i2c_error = I2CRMWV(PMBUS_MST_ID, regulator_data->cmd,
253-
PMBUS_CMD_BYTE_SIZE, regulator_data->data,
254-
regulator_data->mask, regulator_data->size);
316+
i2c_error = i2c_rmwv(regulator_config->address, regulator_data->cmd,
317+
PMBUS_CMD_BYTE_SIZE, regulator_data->data,
318+
regulator_data->mask, regulator_data->size);
255319

256320
if (i2c_error) {
257321
LOG_WRN("Regulator %#x init retried on cmd %#x "
258322
"with error %#x",
259323
regulator_config->address, regulator_data->cmd,
260324
i2c_error);
261325

262-
/* First, try a bus recovery */
263-
I2CRecoverBus(PMBUS_MST_ID);
326+
i2c_recover_bus(i2c1_dev);
264327
/* Retry once */
265-
i2c_error =
266-
I2CRMWV(PMBUS_MST_ID, regulator_data->cmd,
267-
PMBUS_CMD_BYTE_SIZE, regulator_data->data,
268-
regulator_data->mask, regulator_data->size);
328+
i2c_error = i2c_rmwv(
329+
regulator_config->address, regulator_data->cmd,
330+
PMBUS_CMD_BYTE_SIZE, regulator_data->data,
331+
regulator_data->mask, regulator_data->size);
269332
if (i2c_error) {
270333
LOG_ERR("Regulator init failed on cmd %#x "
271334
"with error %#x",

0 commit comments

Comments
 (0)