11/*
2- * Copyright (c) 2024 Tenstorrent AI ULC
2+ * Copyright (c) 2025 Tenstorrent AI ULC
33 *
44 * SPDX-License-Identifier: Apache-2.0
55 */
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>
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 */
7374static uint8_t vout_cmd_source = VoutCommand ;
7475static 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
76118static 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. */
89131float 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. */
100144float 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
110156static 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
123168static 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 */
136180static 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. */
151194static 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
199247void 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
217277uint32_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