Skip to content

Commit d523a21

Browse files
oohalstewartsmith
authored andcommitted
p8-i2c: Remove force reset
Force reset was added as an attempt to work around some issues with TPM devices locking up their I2C bus. In that particular case the problem was that the device would hold the SCL line down permanently due to a device firmware bug. The force reset doesn't actually do anything to alleviate the situation here, it just happens to reset the internal master state enough to make the I2C driver appear to work until something tries to access the bus again. On P9 systems with secure boot enabled there is the added problem of the "diagostic mode" not being supported on I2C masters A,B,C and D. Diagnostic mode allows the SCL and SDA lines to be driven directly by software. Without this force reset is impossible to implement. This patch removes the force reset functionality entirely since: a) it doesn't do what it's supposed to, and b) it's butt ugly code Additionally, turn p8_i2c_reset_engine() into p8_i2c_reset_port(). There's no need to reset every port on a master in response to an error that occurred on a specific port. Signed-off-by: Oliver O'Halloran <[email protected]> Signed-off-by: Stewart Smith <[email protected]> (cherry picked from commit 49656a1) Signed-off-by: Stewart Smith <[email protected]>
1 parent 652c0dd commit d523a21

File tree

1 file changed

+38
-135
lines changed

1 file changed

+38
-135
lines changed

hw/p8-i2c.c

+38-135
Original file line numberDiff line numberDiff line change
@@ -516,151 +516,54 @@ static void p8_i2c_translate_error(struct i2c_request *req, uint64_t status)
516516
req->result = OPAL_I2C_TIMEOUT;
517517
}
518518

519-
static void p8_i2c_force_reset(struct p8_i2c_master *master)
519+
static int p8_i2c_reset_port(struct p8_i2c_master_port *p)
520520
{
521-
struct p8_i2c_master_port *p;
522-
uint64_t mode;
523-
int rc;
521+
struct p8_i2c_master *master = p->master;
522+
int reset_loops, rc;
523+
uint64_t status;
524524

525-
/* Reset the i2c engine */
526-
rc = xscom_write(master->chip_id, master->xscom_base +
527-
I2C_RESET_I2C_REG, 0);
528-
if (rc) {
529-
log_simple_error(&e_info(OPAL_RC_I2C_RESET), "I2C: Failed "
530-
"to reset the i2c engine\n");
531-
return;
532-
}
533-
time_wait_us_nopoll(10);
534-
/* Reset port busy */
535-
rc = xscom_write(master->chip_id, master->xscom_base +
536-
I2C_PORT_BUSY_REG, 0x8000000000000000ULL);
525+
/* FIXME: this should per per-port rather than per-master */
526+
master->state = state_error;
527+
528+
/*
529+
* Put the master into enhanced STOP mode when recovering the
530+
* port. This causes the master to send additional STOP conditions
531+
* to work around some particularly stupid I2C devices and it's
532+
* required on secure I2C masters since they will not send a bare
533+
* stop condition.
534+
*/
535+
rc = p8_i2c_prog_mode(p, true);
537536
if (rc) {
538-
log_simple_error(&e_info(OPAL_RC_I2C_RESET), "I2C: Failed "
539-
"to reset port busy on i2c engine\n");
540-
return;
537+
log_simple_error(&e_info(OPAL_RC_I2C_RESET),
538+
"I2C: Failed to enable enhanced mode\n");
539+
return -1;
541540
}
542-
time_wait_us_nopoll(10);
543-
list_for_each(&master->ports, p, link) {
544-
mode = 0;
545-
mode = SETFIELD(I2C_MODE_PORT_NUM, mode, p->port_num);
546-
mode = SETFIELD(I2C_MODE_BIT_RATE_DIV, mode, p->bit_rate_div);
547-
mode |= I2C_MODE_DIAGNOSTIC;
548-
rc = xscom_write(master->chip_id,
549-
master->xscom_base + I2C_MODE_REG,
550-
mode);
551-
if (rc)
552-
prlog(PR_ERR, "I2C: Failed to write the MODE_REG\n");
553-
554-
time_wait_us_nopoll(10);
555-
rc = xscom_write(master->chip_id,
556-
master->xscom_base + I2C_RESET_S_SCL_REG,
557-
0);
558-
if (rc)
559-
prlog(PR_ERR, "I2C: Failed to reset S_SCL\n");
560-
561-
time_wait_us_nopoll(10);
562-
rc = xscom_write(master->chip_id,
563-
master->xscom_base + I2C_SET_S_SCL_REG,
564-
0);
565-
if (rc)
566-
prlog(PR_ERR, "I2C: Failed to set S_SCL\n");
567-
568-
/* Manually reset */
569-
time_wait_us_nopoll(10);
570-
rc = xscom_write(master->chip_id,
571-
master->xscom_base + I2C_RESET_S_SCL_REG,
572-
0);
573-
if (rc)
574-
prlog(PR_ERR, "I2C: sendStop: fail reset S_SCL\n");
575541

576-
time_wait_us_nopoll(10);
577-
rc = xscom_write(master->chip_id,
578-
master->xscom_base + I2C_RESET_S_SDA_REG,
579-
0);
580-
if (rc)
581-
prlog(PR_ERR, "I2C: sendStop: fail reset S_SDA\n");
542+
rc = xscom_write(master->chip_id, master->xscom_base +
543+
I2C_CMD_REG, I2C_CMD_WITH_STOP);
544+
if (rc)
545+
goto err;
582546

583-
time_wait_us_nopoll(10);
584-
rc = xscom_write(master->chip_id,
585-
master->xscom_base + I2C_SET_S_SCL_REG,
586-
0);
587-
if (rc)
588-
prlog(PR_ERR, "I2C: sendStop: fail set S_SCL\n");
547+
/* Wait for COMMAND COMPLETE */
548+
for (reset_loops = 0; reset_loops < 10; reset_loops++) {
549+
time_wait_ms(10);
589550

590-
time_wait_us_nopoll(10);
591-
rc = xscom_write(master->chip_id,
592-
master->xscom_base + I2C_SET_S_SDA_REG,
593-
0);
551+
rc = xscom_read(master->chip_id,
552+
master->xscom_base + I2C_STAT_REG,
553+
&status);
594554
if (rc)
595-
prlog(PR_ERR, "I2C: sendStop: fail set 2 S_SDA\n");
555+
goto err;
596556

597-
mode ^= I2C_MODE_DIAGNOSTIC;
598-
time_wait_us_nopoll(10);
599-
rc = xscom_write(master->chip_id,
600-
master->xscom_base + I2C_MODE_REG,
601-
mode);
602-
if (rc)
603-
prlog(PR_ERR, "I2C: Failed to write the MODE_REG\n");
557+
if (status & I2C_STAT_CMD_COMP)
558+
break;
604559
}
605-
}
606-
607-
static int p8_i2c_reset_engine(struct p8_i2c_master *master)
608-
{
609-
struct p8_i2c_master_port *p;
610-
int reset_loops;
611-
int rc;
612-
uint64_t status;
613560

614-
list_for_each(&master->ports, p, link) {
615-
/*
616-
* Reset each port by issuing a STOP command to slave.
617-
*
618-
* Reprogram the mode register with 'enhanced bit' set
619-
*/
620-
rc = p8_i2c_prog_mode(p, true);
621-
if (rc) {
622-
log_simple_error(&e_info(OPAL_RC_I2C_RESET),
623-
"I2C: Failed to program the MODE_REG\n");
624-
return -1;
625-
}
626-
627-
/* Send an immediate stop */
628-
master->state = state_error;
629-
rc = xscom_write(master->chip_id, master->xscom_base +
630-
I2C_CMD_REG, I2C_CMD_WITH_STOP);
631-
if (rc) {
632-
log_simple_error(&e_info(OPAL_RC_I2C_RESET),
633-
"I2C: Failed to issue immediate STOP\n");
634-
return -1;
635-
}
636-
637-
/* Wait for COMMAND COMPLETE */
638-
reset_loops = 0;
639-
do {
640-
rc = xscom_read(master->chip_id,
641-
master->xscom_base + I2C_STAT_REG,
642-
&status);
643-
if (rc) {
644-
log_simple_error(&e_info(OPAL_RC_I2C_TRANSFER),
645-
"I2C: Failed to read the STAT_REG\n");
646-
return -1;
647-
}
648-
if (! (status & I2C_STAT_CMD_COMP)) {
649-
time_wait_ms(10);
650-
if (reset_loops++ == 5) {
651-
prlog(PR_WARNING, "I2C: Retrying reset, with force!\n");
652-
p8_i2c_force_reset(master);
653-
continue;
654-
}
655-
if (reset_loops == 10) {
656-
log_simple_error(&e_info(OPAL_RC_I2C_TRANSFER),
657-
"I2C: Failed to recover i2c engine\n");
658-
break;
659-
}
660-
}
661-
} while (! (status & I2C_STAT_CMD_COMP));
662-
}
663-
return 0;
561+
if (status & I2C_STAT_CMD_COMP)
562+
return 0;
563+
err:
564+
prerror("I2C: Failed to reset c%de%dp%d\n",
565+
master->chip_id, master->engine_id, p->port_num);
566+
return -1;
664567
}
665568

666569
static void p8_i2c_status_error(struct p8_i2c_master_port *port,
@@ -699,7 +602,7 @@ static void p8_i2c_status_error(struct p8_i2c_master_port *port,
699602
*/
700603
p8_i2c_complete_request(master, req, req->result);
701604
} else {
702-
if (p8_i2c_reset_engine(master))
605+
if (p8_i2c_reset_port(port))
703606
goto exit;
704607
/* Enable the interrupt */
705608
p8_i2c_enable_irqs(master);

0 commit comments

Comments
 (0)