* [PATCH v8 0/4] i2c: npcm: read/write operation, checkpatch
@ 2024-12-19 9:08 Tyrone Ting
2024-12-19 9:08 ` [PATCH v8 1/4] i2c: npcm: Modify timeout evaluation mechanism Tyrone Ting
` (4 more replies)
0 siblings, 5 replies; 7+ messages in thread
From: Tyrone Ting @ 2024-12-19 9:08 UTC (permalink / raw)
To: avifishman70, tmaimon77, tali.perry1, venture, yuenn,
benjaminfair, andi.shyti, andriy.shevchenko, wsa, rand.sec96,
wsa+renesas, warp5tw, tali.perry, Avi.Fishman, tomer.maimon,
KWLIU, JJLIU0, kfting
Cc: openbmc, linux-i2c, linux-kernel
This patchset includes the following fixes:
- Enable the target functionality in the interrupt handling routine
when the i2c transfer is about to finish.
- Correct the read/write operation procedure.
- Introduce a software flag to handle the bus error (BER) condition
which is not caused by the i2c transfer.
- Modify timeout calculation.
- Assign the client address earlier logically.
- Use an i2c frequency table for the frequency parameters assignment.
- Coding style fix.
The NPCM I2C driver is tested on NPCM750 and NPCM845 evaluation boards.
Addressed comments from:
- Paul Menzel : https://lore.kernel.org/lkml/67d34216-e98b-43d9-afd1-
2e73ffb71968@molgen.mpg.de/
- Andi Shyti : https://lore.kernel.org/lkml/cexpymszobfl7676acibp474e
q3qx242ppo22wrbjepxhufkvt@w4ptnmfjx7yo/
- Tali Perry : https://lore.kernel.org/lkml/CAHb3i=uT+Zx8m4hAF1M2yjCn
=a5sDBn2wJajWdCm79syuy97Ag@mail.gmail.com/
Changes since version 7:
- Modify the commit title for better description.
- Modify i2c address assignment.
Changes since version 6:
- Modify code comments.
- Remove redundant code check.
- Remove i2c address mask.
Changes since version 5:
- Correct "EAGAIN" to "-EAGAIN" in the commit message.
- Configure the bus->dest_addr by calling i2c_8bit_addr_from_msg()
and remove the I2C_M_RD flag when calling i2c_recover_bus().
- Fix the commit message which meets a too small wrapping limit.
Changes since version 4:
- Add more description for the codes.
- Modify the term "function" to "function()" in the commit message
and code comments.
Changes since version 3:
- Remove "Bug fixes" in the cover letter title.
- Modify the term "function" to "func()" in the commit message and
code comments.
- Correct the coding style.
Changes since version 2:
- Add more explanations in the commit message and code modification.
- Use lower character names for declarations.
- Remove Fixes tags in commits which are not to fix bugs.
Changes since version 1:
- Restore the npcm_i2caddr array length to fix the smatch warning.
- Remove unused variables.
- Handle the condition where scl_table_cnt reaches to the maximum value.
- Fix the checkpatch warning.
Charles Boyer (1):
i2c: npcm: Enable slave in eob interrupt
Tyrone Ting (3):
i2c: npcm: Modify timeout evaluation mechanism
i2c: npcm: Assign client address earlier for `i2c_recover_bus()`
i2c: npcm: use i2c frequency table
drivers/i2c/busses/i2c-npcm7xx.c | 427 +++++++++++++++++++++++--------
1 file changed, 326 insertions(+), 101 deletions(-)
base-commit: 663bff1ddfe4ecbba3bcf4a74646bb388b1ad5b2
--
2.34.1
^ permalink raw reply [flat|nested] 7+ messages in thread* [PATCH v8 1/4] i2c: npcm: Modify timeout evaluation mechanism 2024-12-19 9:08 [PATCH v8 0/4] i2c: npcm: read/write operation, checkpatch Tyrone Ting @ 2024-12-19 9:08 ` Tyrone Ting 2024-12-19 9:08 ` [PATCH v8 2/4] i2c: npcm: Assign client address earlier for `i2c_recover_bus()` Tyrone Ting ` (3 subsequent siblings) 4 siblings, 0 replies; 7+ messages in thread From: Tyrone Ting @ 2024-12-19 9:08 UTC (permalink / raw) To: avifishman70, tmaimon77, tali.perry1, venture, yuenn, benjaminfair, andi.shyti, andriy.shevchenko, wsa, rand.sec96, wsa+renesas, warp5tw, tali.perry, Avi.Fishman, tomer.maimon, KWLIU, JJLIU0, kfting Cc: openbmc, linux-i2c, linux-kernel From: Tyrone Ting <kfting@nuvoton.com> The users want to connect a lot of masters on the same bus. This timeout is used to determine the time it takes to take bus ownership. The transactions are very long, so waiting 35ms is not enough. Increase the timeout and treat it as the total timeout, including retries. The total timeout is 2 seconds now. The i2c core layer will have chances to retry to call the i2c driver transfer function if the i2c driver reports that the bus is busy and returns -EAGAIN. Signed-off-by: Tyrone Ting <kfting@nuvoton.com> Reviewed-by: Tali Perry <tali.perry1@gmail.com> --- drivers/i2c/busses/i2c-npcm7xx.c | 24 +++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/drivers/i2c/busses/i2c-npcm7xx.c b/drivers/i2c/busses/i2c-npcm7xx.c index 482a0074d448..c96a25d37c14 100644 --- a/drivers/i2c/busses/i2c-npcm7xx.c +++ b/drivers/i2c/busses/i2c-npcm7xx.c @@ -2132,19 +2132,12 @@ static int npcm_i2c_master_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, } } - /* - * Adaptive TimeOut: estimated time in usec + 100% margin: - * 2: double the timeout for clock stretching case - * 9: bits per transaction (including the ack/nack) - */ - timeout_usec = (2 * 9 * USEC_PER_SEC / bus->bus_freq) * (2 + nread + nwrite); - timeout = max_t(unsigned long, bus->adap.timeout, usecs_to_jiffies(timeout_usec)); if (nwrite >= 32 * 1024 || nread >= 32 * 1024) { dev_err(bus->dev, "i2c%d buffer too big\n", bus->num); return -EINVAL; } - time_left = jiffies + timeout + 1; + time_left = jiffies + bus->adap.timeout / bus->adap.retries + 1; do { /* * we must clear slave address immediately when the bus is not @@ -2192,6 +2185,14 @@ static int npcm_i2c_master_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, if (npcm_i2c_master_start_xmit(bus, slave_addr, nwrite, nread, write_data, read_data, read_PEC, read_block)) { + /* + * Adaptive TimeOut: estimated time in usec + 100% margin: + * 2: double the timeout for clock stretching case + * 9: bits per transaction (including the ack/nack) + */ + timeout_usec = (2 * 9 * USEC_PER_SEC / bus->bus_freq) * (2 + nread + nwrite); + timeout = max_t(unsigned long, bus->adap.timeout / bus->adap.retries, + usecs_to_jiffies(timeout_usec)); time_left = wait_for_completion_timeout(&bus->cmd_complete, timeout); @@ -2317,7 +2318,12 @@ static int npcm_i2c_probe_bus(struct platform_device *pdev) adap = &bus->adap; adap->owner = THIS_MODULE; adap->retries = 3; - adap->timeout = msecs_to_jiffies(35); + /* + * The users want to connect a lot of masters on the same bus. + * This timeout is used to determine the time it takes to take bus ownership. + * The transactions are very long, so waiting 35ms is not enough. + */ + adap->timeout = 2 * HZ; adap->algo = &npcm_i2c_algo; adap->quirks = &npcm_i2c_quirks; adap->algo_data = bus; -- 2.34.1 ^ permalink raw reply related [flat|nested] 7+ messages in thread
* [PATCH v8 2/4] i2c: npcm: Assign client address earlier for `i2c_recover_bus()` 2024-12-19 9:08 [PATCH v8 0/4] i2c: npcm: read/write operation, checkpatch Tyrone Ting 2024-12-19 9:08 ` [PATCH v8 1/4] i2c: npcm: Modify timeout evaluation mechanism Tyrone Ting @ 2024-12-19 9:08 ` Tyrone Ting 2024-12-19 9:08 ` [PATCH v8 3/4] i2c: npcm: use i2c frequency table Tyrone Ting ` (2 subsequent siblings) 4 siblings, 0 replies; 7+ messages in thread From: Tyrone Ting @ 2024-12-19 9:08 UTC (permalink / raw) To: avifishman70, tmaimon77, tali.perry1, venture, yuenn, benjaminfair, andi.shyti, andriy.shevchenko, wsa, rand.sec96, wsa+renesas, warp5tw, tali.perry, Avi.Fishman, tomer.maimon, KWLIU, JJLIU0, kfting Cc: openbmc, linux-i2c, linux-kernel From: Tyrone Ting <kfting@nuvoton.com> Store the client address earlier since it might get called in the i2c_recover_bus() logic flow at the early stage of npcm_i2c_master_xfer(). Signed-off-by: Tyrone Ting <kfting@nuvoton.com> Reviewed-by: Tali Perry <tali.perry1@gmail.com> --- drivers/i2c/busses/i2c-npcm7xx.c | 23 +++++++++++++++++------ 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/drivers/i2c/busses/i2c-npcm7xx.c b/drivers/i2c/busses/i2c-npcm7xx.c index c96a25d37c14..760608fdd075 100644 --- a/drivers/i2c/busses/i2c-npcm7xx.c +++ b/drivers/i2c/busses/i2c-npcm7xx.c @@ -2035,7 +2035,7 @@ static irqreturn_t npcm_i2c_bus_irq(int irq, void *dev_id) } static bool npcm_i2c_master_start_xmit(struct npcm_i2c *bus, - u8 slave_addr, u16 nwrite, u16 nread, + u16 nwrite, u16 nread, u8 *write_data, u8 *read_data, bool use_PEC, bool use_read_block) { @@ -2043,7 +2043,6 @@ static bool npcm_i2c_master_start_xmit(struct npcm_i2c *bus, bus->cmd_err = -EBUSY; return false; } - bus->dest_addr = slave_addr << 1; bus->wr_buf = write_data; bus->wr_size = nwrite; bus->wr_ind = 0; @@ -2086,7 +2085,6 @@ static int npcm_i2c_master_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, unsigned long time_left, flags; u16 nwrite, nread; u8 *write_data, *read_data; - u8 slave_addr; unsigned long timeout; bool read_block = false; bool read_PEC = false; @@ -2099,7 +2097,6 @@ static int npcm_i2c_master_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, } msg0 = &msgs[0]; - slave_addr = msg0->addr; if (msg0->flags & I2C_M_RD) { /* read */ nwrite = 0; write_data = NULL; @@ -2155,6 +2152,21 @@ static int npcm_i2c_master_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, } while (time_is_after_jiffies(time_left) && bus_busy); + /* + * Store the address early in a global position to ensure it is + * accessible for a potential call to i2c_recover_bus(). + * + * Since the transfer might be a read operation, remove the I2C_M_RD flag + * from the bus->dest_addr for the i2c_recover_bus() call later. + * + * The i2c_recover_bus() uses the address in a write direction to recover + * the i2c bus if some error condition occurs. + * + * Remove the I2C_M_RD flag from the address since npcm_i2c_master_start_xmit() + * handles the read/write operation internally. + */ + bus->dest_addr = i2c_8bit_addr_from_msg(msg0) & ~I2C_M_RD; + /* * Check the BER (bus error) state, when ber_state is true, it means that the module * detects the bus error which is caused by some factor like that the electricity @@ -2172,7 +2184,6 @@ static int npcm_i2c_master_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, } npcm_i2c_init_params(bus); - bus->dest_addr = slave_addr; bus->msgs = msgs; bus->msgs_num = num; bus->cmd_err = 0; @@ -2182,7 +2193,7 @@ static int npcm_i2c_master_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, npcm_i2c_int_enable(bus, true); - if (npcm_i2c_master_start_xmit(bus, slave_addr, nwrite, nread, + if (npcm_i2c_master_start_xmit(bus, nwrite, nread, write_data, read_data, read_PEC, read_block)) { /* -- 2.34.1 ^ permalink raw reply related [flat|nested] 7+ messages in thread
* [PATCH v8 3/4] i2c: npcm: use i2c frequency table 2024-12-19 9:08 [PATCH v8 0/4] i2c: npcm: read/write operation, checkpatch Tyrone Ting 2024-12-19 9:08 ` [PATCH v8 1/4] i2c: npcm: Modify timeout evaluation mechanism Tyrone Ting 2024-12-19 9:08 ` [PATCH v8 2/4] i2c: npcm: Assign client address earlier for `i2c_recover_bus()` Tyrone Ting @ 2024-12-19 9:08 ` Tyrone Ting 2024-12-19 9:08 ` [PATCH v8 4/4] i2c: npcm: Enable slave in eob interrupt Tyrone Ting 2024-12-26 0:52 ` [PATCH v8 0/4] i2c: npcm: read/write operation, checkpatch Andi Shyti 4 siblings, 0 replies; 7+ messages in thread From: Tyrone Ting @ 2024-12-19 9:08 UTC (permalink / raw) To: avifishman70, tmaimon77, tali.perry1, venture, yuenn, benjaminfair, andi.shyti, andriy.shevchenko, wsa, rand.sec96, wsa+renesas, warp5tw, tali.perry, Avi.Fishman, tomer.maimon, KWLIU, JJLIU0, kfting Cc: openbmc, linux-i2c, linux-kernel From: Tyrone Ting <kfting@nuvoton.com> Modify i2c frequency from table parameters for NPCM i2c modules. Supported frequencies are: 1. 100KHz 2. 400KHz 3. 1MHz The original equations were tested on a variety of chips and base clocks. Since we added devices that use higher frequencies of the module we saw that there is a mismatch between the equation and the actual results on the bus itself, measured on scope. Meanwhile, the equations were not accurate to begin with. They are an approximation of the ideal value. The ideal value is calculated per frequency of the core module. So instead of using the equations we did an optimization per module frequency, verified on a device. Most of the work was focused on the rise time of the SCL and SDA, which depends on external load of the bus and PU. Different PCB designs, or specifically to this case: the number and type of targets on the bus, impact the required values for the timing registers. Users can recalculate the numbers for each bus and get an even better optimization, but our users chose not to. We manually picked values per frequency that match the entire valid range of targets (from 1 to max number). Then we check against the AMR described in SMB spec and make sure that none of the values is exceeding. This process was led by the chip architect and included a lot of testing. Signed-off-by: Tyrone Ting <kfting@nuvoton.com> Reviewed-by: Tali Perry <tali.perry1@gmail.com> --- drivers/i2c/busses/i2c-npcm7xx.c | 374 ++++++++++++++++++++++++------- 1 file changed, 288 insertions(+), 86 deletions(-) diff --git a/drivers/i2c/busses/i2c-npcm7xx.c b/drivers/i2c/busses/i2c-npcm7xx.c index 760608fdd075..1aae1a8a8055 100644 --- a/drivers/i2c/busses/i2c-npcm7xx.c +++ b/drivers/i2c/busses/i2c-npcm7xx.c @@ -263,6 +263,265 @@ static const int npcm_i2caddr[I2C_NUM_OWN_ADDR] = { #define I2C_FREQ_MIN_HZ 10000 #define I2C_FREQ_MAX_HZ I2C_MAX_FAST_MODE_PLUS_FREQ +struct smb_timing_t { + u32 core_clk; + u8 hldt; + u8 dbcnt; + u16 sclfrq; + u8 scllt; + u8 sclht; + bool fast_mode; +}; + +static struct smb_timing_t smb_timing_100khz[] = { + { + .core_clk = 100000000, .hldt = 0x2A, .dbcnt = 0x4, + .sclfrq = 0xFB, .scllt = 0x0, .sclht = 0x0, + .fast_mode = false, + }, + { + .core_clk = 62500000, .hldt = 0x2A, .dbcnt = 0x1, + .sclfrq = 0x9D, .scllt = 0x0, .sclht = 0x0, + .fast_mode = false, + }, + { + .core_clk = 50000000, .hldt = 0x2A, .dbcnt = 0x1, + .sclfrq = 0x7E, .scllt = 0x0, .sclht = 0x0, + .fast_mode = false, + }, + { + .core_clk = 48000000, .hldt = 0x2A, .dbcnt = 0x1, + .sclfrq = 0x79, .scllt = 0x0, .sclht = 0x0, + .fast_mode = false, + }, + { + .core_clk = 40000000, .hldt = 0x2A, .dbcnt = 0x1, + .sclfrq = 0x65, .scllt = 0x0, .sclht = 0x0, + .fast_mode = false, + }, + { + .core_clk = 30000000, .hldt = 0x2A, .dbcnt = 0x1, + .sclfrq = 0x4C, .scllt = 0x0, .sclht = 0x0, + .fast_mode = false, + }, + { + .core_clk = 29000000, .hldt = 0x2A, .dbcnt = 0x1, + .sclfrq = 0x49, .scllt = 0x0, .sclht = 0x0, + .fast_mode = false, + }, + { + .core_clk = 26000000, .hldt = 0x2A, .dbcnt = 0x1, + .sclfrq = 0x42, .scllt = 0x0, .sclht = 0x0, + .fast_mode = false, + }, + { + .core_clk = 25000000, .hldt = 0x2A, .dbcnt = 0x1, + .sclfrq = 0x3F, .scllt = 0x0, .sclht = 0x0, + .fast_mode = false, + }, + { + .core_clk = 24000000, .hldt = 0x2A, .dbcnt = 0x1, + .sclfrq = 0x3D, .scllt = 0x0, .sclht = 0x0, + .fast_mode = false, + }, + { + .core_clk = 20000000, .hldt = 0x2A, .dbcnt = 0x1, + .sclfrq = 0x33, .scllt = 0x0, .sclht = 0x0, + .fast_mode = false, + }, + { + .core_clk = 16180000, .hldt = 0x2A, .dbcnt = 0x1, + .sclfrq = 0x29, .scllt = 0x0, .sclht = 0x0, + .fast_mode = false, + }, + { + .core_clk = 15000000, .hldt = 0x23, .dbcnt = 0x1, + .sclfrq = 0x26, .scllt = 0x0, .sclht = 0x0, + .fast_mode = false, + }, + { + .core_clk = 13000000, .hldt = 0x1D, .dbcnt = 0x1, + .sclfrq = 0x21, .scllt = 0x0, .sclht = 0x0, + .fast_mode = false, + }, + { + .core_clk = 12000000, .hldt = 0x1B, .dbcnt = 0x1, + .sclfrq = 0x1F, .scllt = 0x0, .sclht = 0x0, + .fast_mode = false, + }, + { + .core_clk = 10000000, .hldt = 0x18, .dbcnt = 0x1, + .sclfrq = 0x1A, .scllt = 0x0, .sclht = 0x0, + .fast_mode = false, + }, + { + .core_clk = 9000000, .hldt = 0x16, .dbcnt = 0x1, + .sclfrq = 0x17, .scllt = 0x0, .sclht = 0x0, + .fast_mode = false, + }, + { + .core_clk = 8090000, .hldt = 0x14, .dbcnt = 0x1, + .sclfrq = 0x15, .scllt = 0x0, .sclht = 0x0, + .fast_mode = false, + }, + { + .core_clk = 7500000, .hldt = 0x7, .dbcnt = 0x1, + .sclfrq = 0x13, .scllt = 0x0, .sclht = 0x0, + .fast_mode = false, + }, + { + .core_clk = 6500000, .hldt = 0xE, .dbcnt = 0x1, + .sclfrq = 0x11, .scllt = 0x0, .sclht = 0x0, + .fast_mode = false, + }, + { + .core_clk = 4000000, .hldt = 0x9, .dbcnt = 0x1, + .sclfrq = 0xB, .scllt = 0x0, .sclht = 0x0, + .fast_mode = false, + }, +}; + +static struct smb_timing_t smb_timing_400khz[] = { + { + .core_clk = 100000000, .hldt = 0x2A, .dbcnt = 0x3, + .sclfrq = 0x0, .scllt = 0x47, .sclht = 0x35, + .fast_mode = true, + }, + { + .core_clk = 62500000, .hldt = 0x2A, .dbcnt = 0x2, + .sclfrq = 0x0, .scllt = 0x2C, .sclht = 0x22, + .fast_mode = true, + }, + { + .core_clk = 50000000, .hldt = 0x21, .dbcnt = 0x1, + .sclfrq = 0x0, .scllt = 0x24, .sclht = 0x1B, + .fast_mode = true, + }, + { + .core_clk = 48000000, .hldt = 0x1E, .dbcnt = 0x1, + .sclfrq = 0x0, .scllt = 0x24, .sclht = 0x19, + .fast_mode = true, + }, + { + .core_clk = 40000000, .hldt = 0x1B, .dbcnt = 0x1, + .sclfrq = 0x0, .scllt = 0x1E, .sclht = 0x14, + .fast_mode = true, + }, + { + .core_clk = 33000000, .hldt = 0x15, .dbcnt = 0x1, + .sclfrq = 0x0, .scllt = 0x19, .sclht = 0x11, + .fast_mode = true, + }, + { + .core_clk = 30000000, .hldt = 0x15, .dbcnt = 0x1, + .sclfrq = 0x0, .scllt = 0x19, .sclht = 0xD, + .fast_mode = true, + }, + { + .core_clk = 29000000, .hldt = 0x11, .dbcnt = 0x1, + .sclfrq = 0x0, .scllt = 0x15, .sclht = 0x10, + .fast_mode = true, + }, + { + .core_clk = 26000000, .hldt = 0x10, .dbcnt = 0x1, + .sclfrq = 0x0, .scllt = 0x13, .sclht = 0xE, + .fast_mode = true, + }, + { + .core_clk = 25000000, .hldt = 0xF, .dbcnt = 0x1, + .sclfrq = 0x0, .scllt = 0x13, .sclht = 0xD, + .fast_mode = true, + }, + { + .core_clk = 24000000, .hldt = 0xD, .dbcnt = 0x1, + .sclfrq = 0x0, .scllt = 0x12, .sclht = 0xD, + .fast_mode = true, + }, + { + .core_clk = 20000000, .hldt = 0xB, .dbcnt = 0x1, + .sclfrq = 0x0, .scllt = 0xF, .sclht = 0xA, + .fast_mode = true, + }, + { + .core_clk = 16180000, .hldt = 0xA, .dbcnt = 0x1, + .sclfrq = 0x0, .scllt = 0xC, .sclht = 0x9, + .fast_mode = true, + }, + { + .core_clk = 15000000, .hldt = 0x9, .dbcnt = 0x1, + .sclfrq = 0x0, .scllt = 0xB, .sclht = 0x8, + .fast_mode = true, + }, + { + .core_clk = 13000000, .hldt = 0x7, .dbcnt = 0x1, + .sclfrq = 0x0, .scllt = 0xA, .sclht = 0x7, + .fast_mode = true, + }, + { + .core_clk = 12000000, .hldt = 0x7, .dbcnt = 0x1, + .sclfrq = 0x0, .scllt = 0xA, .sclht = 0x6, + .fast_mode = true, + }, + { + .core_clk = 10000000, .hldt = 0x6, .dbcnt = 0x1, + .sclfrq = 0x0, .scllt = 0x8, .sclht = 0x5, + .fast_mode = true, + }, +}; + +static struct smb_timing_t smb_timing_1000khz[] = { + { + .core_clk = 100000000, .hldt = 0x15, .dbcnt = 0x4, + .sclfrq = 0x0, .scllt = 0x1C, .sclht = 0x15, + .fast_mode = true, + }, + { + .core_clk = 62500000, .hldt = 0xF, .dbcnt = 0x3, + .sclfrq = 0x0, .scllt = 0x11, .sclht = 0xE, + .fast_mode = true, + }, + { + .core_clk = 50000000, .hldt = 0xA, .dbcnt = 0x2, + .sclfrq = 0x0, .scllt = 0xE, .sclht = 0xB, + .fast_mode = true, + }, + { + .core_clk = 48000000, .hldt = 0x9, .dbcnt = 0x2, + .sclfrq = 0x0, .scllt = 0xD, .sclht = 0xB, + .fast_mode = true, + }, + { + .core_clk = 41000000, .hldt = 0x9, .dbcnt = 0x2, + .sclfrq = 0x0, .scllt = 0xC, .sclht = 0x9, + .fast_mode = true, + }, + { + .core_clk = 40000000, .hldt = 0x8, .dbcnt = 0x2, + .sclfrq = 0x0, .scllt = 0xB, .sclht = 0x9, + .fast_mode = true, + }, + { + .core_clk = 33000000, .hldt = 0x7, .dbcnt = 0x1, + .sclfrq = 0x0, .scllt = 0xA, .sclht = 0x7, + .fast_mode = true, + }, + { + .core_clk = 25000000, .hldt = 0x4, .dbcnt = 0x1, + .sclfrq = 0x0, .scllt = 0x7, .sclht = 0x6, + .fast_mode = true, + }, + { + .core_clk = 24000000, .hldt = 0x7, .dbcnt = 0x1, + .sclfrq = 0x0, .scllt = 0x8, .sclht = 0x5, + .fast_mode = true, + }, + { + .core_clk = 20000000, .hldt = 0x4, .dbcnt = 0x1, + .sclfrq = 0x0, .scllt = 0x6, .sclht = 0x4, + .fast_mode = true, + }, +}; + struct npcm_i2c_data { u8 fifo_size; u32 segctl_init_val; @@ -1805,102 +2064,45 @@ static void npcm_i2c_recovery_init(struct i2c_adapter *_adap) */ static int npcm_i2c_init_clk(struct npcm_i2c *bus, u32 bus_freq_hz) { - u32 k1 = 0; - u32 k2 = 0; - u8 dbnct = 0; - u32 sclfrq = 0; - u8 hldt = 7; + struct smb_timing_t *smb_timing; + u8 scl_table_cnt = 0, table_size = 0; u8 fast_mode = 0; - u32 src_clk_khz; - u32 bus_freq_khz; - src_clk_khz = bus->apb_clk / 1000; - bus_freq_khz = bus_freq_hz / 1000; bus->bus_freq = bus_freq_hz; - /* 100KHz and below: */ - if (bus_freq_hz <= I2C_MAX_STANDARD_MODE_FREQ) { - sclfrq = src_clk_khz / (bus_freq_khz * 4); - - if (sclfrq < SCLFRQ_MIN || sclfrq > SCLFRQ_MAX) - return -EDOM; - - if (src_clk_khz >= 40000) - hldt = 17; - else if (src_clk_khz >= 12500) - hldt = 15; - else - hldt = 7; - } - - /* 400KHz: */ - else if (bus_freq_hz <= I2C_MAX_FAST_MODE_FREQ) { - sclfrq = 0; + switch (bus_freq_hz) { + case I2C_MAX_STANDARD_MODE_FREQ: + smb_timing = smb_timing_100khz; + table_size = ARRAY_SIZE(smb_timing_100khz); + break; + case I2C_MAX_FAST_MODE_FREQ: + smb_timing = smb_timing_400khz; + table_size = ARRAY_SIZE(smb_timing_400khz); fast_mode = I2CCTL3_400K_MODE; - - if (src_clk_khz < 7500) - /* 400KHZ cannot be supported for core clock < 7.5MHz */ - return -EDOM; - - else if (src_clk_khz >= 50000) { - k1 = 80; - k2 = 48; - hldt = 12; - dbnct = 7; - } - - /* Master or Slave with frequency > 25MHz */ - else if (src_clk_khz > 25000) { - hldt = clk_coef(src_clk_khz, 300) + 7; - k1 = clk_coef(src_clk_khz, 1600); - k2 = clk_coef(src_clk_khz, 900); - } - } - - /* 1MHz: */ - else if (bus_freq_hz <= I2C_MAX_FAST_MODE_PLUS_FREQ) { - sclfrq = 0; + break; + case I2C_MAX_FAST_MODE_PLUS_FREQ: + smb_timing = smb_timing_1000khz; + table_size = ARRAY_SIZE(smb_timing_1000khz); fast_mode = I2CCTL3_400K_MODE; - - /* 1MHZ cannot be supported for core clock < 24 MHz */ - if (src_clk_khz < 24000) - return -EDOM; - - k1 = clk_coef(src_clk_khz, 620); - k2 = clk_coef(src_clk_khz, 380); - - /* Core clk > 40 MHz */ - if (src_clk_khz > 40000) { - /* - * Set HLDT: - * SDA hold time: (HLDT-7) * T(CLK) >= 120 - * HLDT = 120/T(CLK) + 7 = 120 * FREQ(CLK) + 7 - */ - hldt = clk_coef(src_clk_khz, 120) + 7; - } else { - hldt = 7; - dbnct = 2; - } + break; + default: + return -EINVAL; } - /* Frequency larger than 1 MHz is not supported */ - else - return -EINVAL; + for (scl_table_cnt = 0; scl_table_cnt < table_size; scl_table_cnt++) + if (bus->apb_clk >= smb_timing[scl_table_cnt].core_clk) + break; - if (bus_freq_hz >= I2C_MAX_FAST_MODE_FREQ) { - k1 = round_up(k1, 2); - k2 = round_up(k2 + 1, 2); - if (k1 < SCLFRQ_MIN || k1 > SCLFRQ_MAX || - k2 < SCLFRQ_MIN || k2 > SCLFRQ_MAX) - return -EDOM; - } + if (scl_table_cnt == table_size) + return -EINVAL; /* write sclfrq value. bits [6:0] are in I2CCTL2 reg */ - iowrite8(FIELD_PREP(I2CCTL2_SCLFRQ6_0, sclfrq & 0x7F), + iowrite8(FIELD_PREP(I2CCTL2_SCLFRQ6_0, smb_timing[scl_table_cnt].sclfrq & 0x7F), bus->reg + NPCM_I2CCTL2); /* bits [8:7] are in I2CCTL3 reg */ - iowrite8(fast_mode | FIELD_PREP(I2CCTL3_SCLFRQ8_7, (sclfrq >> 7) & 0x3), + iowrite8(FIELD_PREP(I2CCTL3_SCLFRQ8_7, (smb_timing[scl_table_cnt].sclfrq >> 7) & 0x3) | + fast_mode, bus->reg + NPCM_I2CCTL3); /* Select Bank 0 to access NPCM_I2CCTL4/NPCM_I2CCTL5 */ @@ -1912,13 +2114,13 @@ static int npcm_i2c_init_clk(struct npcm_i2c *bus, u32 bus_freq_hz) * k1 = 2 * SCLLT7-0 -> Low Time = k1 / 2 * k2 = 2 * SCLLT7-0 -> High Time = k2 / 2 */ - iowrite8(k1 / 2, bus->reg + NPCM_I2CSCLLT); - iowrite8(k2 / 2, bus->reg + NPCM_I2CSCLHT); + iowrite8(smb_timing[scl_table_cnt].scllt, bus->reg + NPCM_I2CSCLLT); + iowrite8(smb_timing[scl_table_cnt].sclht, bus->reg + NPCM_I2CSCLHT); - iowrite8(dbnct, bus->reg + NPCM_I2CCTL5); + iowrite8(smb_timing[scl_table_cnt].dbcnt, bus->reg + NPCM_I2CCTL5); } - iowrite8(hldt, bus->reg + NPCM_I2CCTL4); + iowrite8(smb_timing[scl_table_cnt].hldt, bus->reg + NPCM_I2CCTL4); /* Return to Bank 1, and stay there by default: */ npcm_i2c_select_bank(bus, I2C_BANK_1); -- 2.34.1 ^ permalink raw reply related [flat|nested] 7+ messages in thread
* [PATCH v8 4/4] i2c: npcm: Enable slave in eob interrupt 2024-12-19 9:08 [PATCH v8 0/4] i2c: npcm: read/write operation, checkpatch Tyrone Ting ` (2 preceding siblings ...) 2024-12-19 9:08 ` [PATCH v8 3/4] i2c: npcm: use i2c frequency table Tyrone Ting @ 2024-12-19 9:08 ` Tyrone Ting 2024-12-26 0:52 ` [PATCH v8 0/4] i2c: npcm: read/write operation, checkpatch Andi Shyti 4 siblings, 0 replies; 7+ messages in thread From: Tyrone Ting @ 2024-12-19 9:08 UTC (permalink / raw) To: avifishman70, tmaimon77, tali.perry1, venture, yuenn, benjaminfair, andi.shyti, andriy.shevchenko, wsa, rand.sec96, wsa+renesas, warp5tw, tali.perry, Avi.Fishman, tomer.maimon, KWLIU, JJLIU0, kfting Cc: openbmc, linux-i2c, linux-kernel, Charles Boyer, Vivekanand Veeracholan From: Charles Boyer <Charles.Boyer@fii-usa.com> Nuvoton slave enable was in user space API call master_xfer, so it is subject to delays from the OS scheduler. If the BMC is not enabled for slave mode in time for master to send response, then it will NAK the address match. Then the PLDM request timeout occurs. If the slave enable is moved to the EOB interrupt service routine, then the BMC can be ready in slave mode by the time it needs to receive a response. Signed-off-by: Charles Boyer <Charles.Boyer@fii-usa.com> Signed-off-by: Vivekanand Veeracholan <vveerach@google.com> Signed-off-by: Tyrone Ting <kfting@nuvoton.com> Reviewed-by: Tali Perry <tali.perry1@gmail.com> --- drivers/i2c/busses/i2c-npcm7xx.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/i2c/busses/i2c-npcm7xx.c b/drivers/i2c/busses/i2c-npcm7xx.c index 1aae1a8a8055..3ca08b8ef8af 100644 --- a/drivers/i2c/busses/i2c-npcm7xx.c +++ b/drivers/i2c/busses/i2c-npcm7xx.c @@ -1925,6 +1925,12 @@ static int npcm_i2c_int_master_handler(struct npcm_i2c *bus) (FIELD_GET(NPCM_I2CCST3_EO_BUSY, ioread8(bus->reg + NPCM_I2CCST3)))) { npcm_i2c_irq_handle_eob(bus); +#if IS_ENABLED(CONFIG_I2C_SLAVE) + /* reenable slave if it was enabled */ + if (bus->slave) + iowrite8(bus->slave->addr | NPCM_I2CADDR_SAEN, + bus->reg + NPCM_I2CADDR1); +#endif return 0; } -- 2.34.1 ^ permalink raw reply related [flat|nested] 7+ messages in thread
* Re: [PATCH v8 0/4] i2c: npcm: read/write operation, checkpatch 2024-12-19 9:08 [PATCH v8 0/4] i2c: npcm: read/write operation, checkpatch Tyrone Ting ` (3 preceding siblings ...) 2024-12-19 9:08 ` [PATCH v8 4/4] i2c: npcm: Enable slave in eob interrupt Tyrone Ting @ 2024-12-26 0:52 ` Andi Shyti 2024-12-27 5:09 ` Tyrone Ting 4 siblings, 1 reply; 7+ messages in thread From: Andi Shyti @ 2024-12-26 0:52 UTC (permalink / raw) To: Tyrone Ting Cc: avifishman70, tmaimon77, tali.perry1, venture, yuenn, benjaminfair, andriy.shevchenko, wsa, rand.sec96, wsa+renesas, tali.perry, Avi.Fishman, tomer.maimon, KWLIU, JJLIU0, kfting, openbmc, linux-i2c, linux-kernel Hi Tyrone, > Charles Boyer (1): > i2c: npcm: Enable slave in eob interrupt > > Tyrone Ting (3): > i2c: npcm: Modify timeout evaluation mechanism > i2c: npcm: Assign client address earlier for `i2c_recover_bus()` > i2c: npcm: use i2c frequency table merged to i2c/i2c-host. Thanks, Andi ^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH v8 0/4] i2c: npcm: read/write operation, checkpatch 2024-12-26 0:52 ` [PATCH v8 0/4] i2c: npcm: read/write operation, checkpatch Andi Shyti @ 2024-12-27 5:09 ` Tyrone Ting 0 siblings, 0 replies; 7+ messages in thread From: Tyrone Ting @ 2024-12-27 5:09 UTC (permalink / raw) To: Andi Shyti Cc: avifishman70, tmaimon77, tali.perry1, venture, yuenn, benjaminfair, andriy.shevchenko, wsa, rand.sec96, wsa+renesas, tali.perry, Avi.Fishman, tomer.maimon, KWLIU, JJLIU0, kfting, openbmc, linux-i2c, linux-kernel Hi Andi: Thanks for the help and guidance from you and other reviewers alone the way. Thank you again. Andi Shyti <andi.shyti@kernel.org> 於 2024年12月26日 週四 上午8:52寫道: > > Hi Tyrone, > > > Charles Boyer (1): > > i2c: npcm: Enable slave in eob interrupt > > > > Tyrone Ting (3): > > i2c: npcm: Modify timeout evaluation mechanism > > i2c: npcm: Assign client address earlier for `i2c_recover_bus()` > > i2c: npcm: use i2c frequency table > > merged to i2c/i2c-host. > > Thanks, > Andi Thank you. Regards, Tyrone ^ permalink raw reply [flat|nested] 7+ messages in thread
end of thread, other threads:[~2024-12-27 5:09 UTC | newest] Thread overview: 7+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2024-12-19 9:08 [PATCH v8 0/4] i2c: npcm: read/write operation, checkpatch Tyrone Ting 2024-12-19 9:08 ` [PATCH v8 1/4] i2c: npcm: Modify timeout evaluation mechanism Tyrone Ting 2024-12-19 9:08 ` [PATCH v8 2/4] i2c: npcm: Assign client address earlier for `i2c_recover_bus()` Tyrone Ting 2024-12-19 9:08 ` [PATCH v8 3/4] i2c: npcm: use i2c frequency table Tyrone Ting 2024-12-19 9:08 ` [PATCH v8 4/4] i2c: npcm: Enable slave in eob interrupt Tyrone Ting 2024-12-26 0:52 ` [PATCH v8 0/4] i2c: npcm: read/write operation, checkpatch Andi Shyti 2024-12-27 5:09 ` Tyrone Ting
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox