diff options
author | Denis Brockus <dbrockus@chromium.org> | 2020-01-29 09:30:33 -0700 |
---|---|---|
committer | Commit Bot <commit-bot@chromium.org> | 2020-01-31 19:49:22 +0000 |
commit | a0d6b40c49c7615cddded5e6811a550468eba7b2 (patch) | |
tree | 366c24995d70676a58aa1668d121016588649889 /driver | |
parent | d1824490d69fb45ad00856496e06d8f253778a71 (diff) | |
download | chrome-ec-a0d6b40c49c7615cddded5e6811a550468eba7b2.tar.gz |
ps8802: fix redriver configuration
in driver
Added software IN_HPD control
Added compile time optional debug
in board specific tune function in usb_retimer
Added gain control
Added display lane control
NOTE: PS8802 has reserved register bits that are
being used internally, so be cautious just hitting
these with 0, i.e. use field update to set a
value to retain the old reserved fields
BUG=b:146394157
BRANCH=none
TEST=verify USB-C1 DP and USB connections
Change-Id: I0b539df15fade509058492d6ab73a7b3ca9181df
Signed-off-by: Denis Brockus <dbrockus@chromium.org>
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/ec/+/2031646
Reviewed-by: Edward Hill <ecgh@chromium.org>
Diffstat (limited to 'driver')
-rw-r--r-- | driver/retimer/ps8802.c | 145 | ||||
-rw-r--r-- | driver/retimer/ps8802.h | 88 |
2 files changed, 210 insertions, 23 deletions
diff --git a/driver/retimer/ps8802.c b/driver/retimer/ps8802.c index cb8b179bc0..6c7f2b5244 100644 --- a/driver/retimer/ps8802.c +++ b/driver/retimer/ps8802.c @@ -13,22 +13,84 @@ #include "timer.h" #include "usb_mux.h" +#define PS8802_DEBUG 0 #define PS8802_I2C_WAKE_DELAY 500 -static int ps8802_i2c_read(int port, int offset, int *data) +int ps8802_i2c_read(int port, int page, int offset, int *data) { - return i2c_read8(usb_retimers[port].i2c_port, - usb_retimers[port].i2c_addr_flags, - offset, data); + int rv; + + rv = i2c_read8(usb_retimers[port].i2c_port, + usb_retimers[port].i2c_addr_flags + page, + offset, data); + + if (PS8802_DEBUG) + ccprintf("%s(%d:0x%02X, 0x%02X) => 0x%02X\n", __func__, + usb_retimers[port].i2c_port, + usb_retimers[port].i2c_addr_flags + page, + offset, *data); + + return rv; } -static int ps8802_i2c_write(int port, int offset, int data) +int ps8802_i2c_write(int port, int page, int offset, int data) { + if (PS8802_DEBUG) + ccprintf("%s(%d:0x%02X, 0x%02X, 0x%02X)\n", __func__, + usb_retimers[port].i2c_port, + usb_retimers[port].i2c_addr_flags + page, + offset, data); + return i2c_write8(usb_retimers[port].i2c_port, - usb_retimers[port].i2c_addr_flags, + usb_retimers[port].i2c_addr_flags + page, offset, data); } +int ps8802_i2c_write16(int port, int page, int offset, int data) +{ + if (PS8802_DEBUG) + ccprintf("%s(%d:0x%02X, 0x%02X, 0x%04X)\n", __func__, + usb_retimers[port].i2c_port, + usb_retimers[port].i2c_addr_flags + page, + offset, data); + + return i2c_write16(usb_retimers[port].i2c_port, + usb_retimers[port].i2c_addr_flags + page, + offset, data); +} + +int ps8802_i2c_field_update8(int port, int page, int offset, + uint8_t field_mask, uint8_t set_value) +{ + if (PS8802_DEBUG) + ccprintf("%s(%d:0x%02X, 0x%02X, 0x%02X, 0x%02X)\n", __func__, + usb_retimers[port].i2c_port, + usb_retimers[port].i2c_addr_flags + page, + offset, field_mask, set_value); + + return i2c_field_update8(usb_retimers[port].i2c_port, + usb_retimers[port].i2c_addr_flags + page, + offset, + field_mask, + set_value); +} + +int ps8802_i2c_field_update16(int port, int page, int offset, + uint16_t field_mask, uint16_t set_value) +{ + if (PS8802_DEBUG) + ccprintf("%s(%d:0x%02X, 0x%02X, 0x%04X, 0x%04X)\n", __func__, + usb_retimers[port].i2c_port, + usb_retimers[port].i2c_addr_flags + page, + offset, field_mask, set_value); + + return i2c_field_update16(usb_retimers[port].i2c_port, + usb_retimers[port].i2c_addr_flags + page, + offset, + field_mask, + set_value); +} + /* * If PS8802 is in I2C standby mode, wake it up by reading PS8802_REG_MODE. * From Application Note: 1) Activate by reading any Page 2 register. 2) Wait @@ -41,7 +103,10 @@ static int ps8802_i2c_wake(int port) /* If in standby, first read will fail, second should succeed. */ for (int i = 0; i < 2; i++) { - rv = ps8802_i2c_read(port, PS8802_REG_MODE, &data); + rv = ps8802_i2c_read(port, + PS8802_REG_PAGE2, + PS8802_REG2_MODE, + &data); if (rv == EC_SUCCESS) return rv; @@ -71,25 +136,80 @@ static int ps8802_set_mux(int port, mux_state_t mux_state) { int val = (PS8802_MODE_DP_REG_CONTROL | PS8802_MODE_USB_REG_CONTROL - | PS8802_MODE_FLIP_REG_CONTROL); + | PS8802_MODE_FLIP_REG_CONTROL + | PS8802_MODE_IN_HPD_REG_CONTROL); int rv; if (chipset_in_state(CHIPSET_STATE_HARD_OFF)) return (mux_state == USB_PD_MUX_NONE) ? EC_SUCCESS : EC_ERROR_NOT_POWERED; + /* Make sure the PS8802 is awake */ rv = ps8802_i2c_wake(port); if (rv) return rv; + if (PS8802_DEBUG) + ccprintf("%s(%d, 0x%02X) %s %s %s\n", + __func__, port, mux_state, + (mux_state & USB_PD_MUX_USB_ENABLED) ? "USB" : "", + (mux_state & USB_PD_MUX_DP_ENABLED) ? "DP" : "", + (mux_state & USB_PD_MUX_POLARITY_INVERTED) + ? "FLIP" : ""); + + /* Set the mode and flip */ if (mux_state & USB_PD_MUX_USB_ENABLED) val |= PS8802_MODE_USB_ENABLE; if (mux_state & USB_PD_MUX_DP_ENABLED) - val |= PS8802_MODE_DP_ENABLE; + val |= PS8802_MODE_DP_ENABLE | PS8802_MODE_IN_HPD_ENABLE; if (mux_state & USB_PD_MUX_POLARITY_INVERTED) val |= PS8802_MODE_FLIP_ENABLE; - return ps8802_i2c_write(port, PS8802_REG_MODE, val); + rv = ps8802_i2c_write(port, + PS8802_REG_PAGE2, + PS8802_REG2_MODE, + val); + if (rv) + return rv; + + /* Board specific retimer mux tuning */ + if (usb_retimers[port].tune) { + rv = usb_retimers[port].tune(port, mux_state); + if (rv) + return rv; + } + + if (PS8802_DEBUG) { + int tx_status; + int rx_status; + + rv = ps8802_i2c_read(port, + PS8802_REG_PAGE0, + PS8802_REG0_TX_STATUS, + &tx_status); + if (rv) + return rv; + + rv = ps8802_i2c_read(port, + PS8802_REG_PAGE0, + PS8802_REG0_RX_STATUS, + &rx_status); + if (rv) + return rv; + + ccprintf("%s: tx:channel %snormal %s10Gbps\n", + __func__, + (tx_status & PS8802_STATUS_NORMAL_OPERATION) + ? "" : "NOT-", + (tx_status & PS8802_STATUS_10_GBPS) ? "" : "NON-"); + ccprintf("%s: rx:channel %snormal %s10Gbps\n", + __func__, + (rx_status & PS8802_STATUS_NORMAL_OPERATION) + ? "" : "NOT-", + (rx_status & PS8802_STATUS_10_GBPS) ? "" : "NON-"); + } + + return rv; } static int ps8802_get_mux(int port, mux_state_t *mux_state) @@ -106,7 +226,10 @@ static int ps8802_get_mux(int port, mux_state_t *mux_state) if (rv) return rv; - rv = ps8802_i2c_read(port, PS8802_REG_MODE, &val); + rv = ps8802_i2c_read(port, + PS8802_REG_PAGE2, + PS8802_REG2_MODE, + &val); if (rv) return rv; diff --git a/driver/retimer/ps8802.h b/driver/retimer/ps8802.h index f7f30d3be9..a54e714b9b 100644 --- a/driver/retimer/ps8802.h +++ b/driver/retimer/ps8802.h @@ -11,23 +11,87 @@ /* * PS8802 uses 7-bit I2C addresses 0x08 to 0x17 (ADDR=L). * Page 0 = 0x08, Page 1 = 0x09, Page 2 = 0x0A. - * We only need to read and write the Mode Selection register in Page 2. */ -#define PS8802_I2C_ADDR_FLAGS 0x0A - -#define PS8802_REG_MODE 0x06 -#define PS8802_MODE_DP_REG_CONTROL BIT(7) -#define PS8802_MODE_DP_ENABLE BIT(6) -#define PS8802_MODE_USB_REG_CONTROL BIT(5) -#define PS8802_MODE_USB_ENABLE BIT(4) -#define PS8802_MODE_FLIP_REG_CONTROL BIT(3) -#define PS8802_MODE_FLIP_ENABLE BIT(2) -#define PS8802_MODE_IN_HPD_REG_CONTROL BIT(1) -#define PS8802_MODE_IN_HPD_ENABLE BIT(0) +#define PS8802_I2C_ADDR_FLAGS 0x08 + +/* + * PAGE 0 Register Definitions + */ +#define PS8802_REG_PAGE0 0x00 + +#define PS8802_REG0_TX_STATUS 0x72 +#define PS8802_REG0_RX_STATUS 0x76 +#define PS8802_STATUS_NORMAL_OPERATION BIT(7) +#define PS8802_STATUS_10_GBPS BIT(5) + +/* + * PAGE 1 Register Definitions + */ +#define PS8802_REG_PAGE1 0x01 + +#define PS8802_REG1_LINK_BW_SET 0x10 +#define PS8802_LINK_BW_SET_1_62_GBPS 0x06 +#define PS8802_LINK_BW_SET_2_7_GBPS 0x0A +#define PS8802_LINK_BW_SET_5_4_GBPS 0x14 +#define PS8802_LINK_BW_SET_8_1_GBPS 0x1E + +#define PS8802_REG1_LANE_COUNT_SET 0x11 +#define PS8802_LANE_COUNT_SET_1_LANE 0x01 +#define PS8802_LANE_COUNT_SET_2_LANE 0x02 +#define PS8802_LANE_COUNT_SET_4_LANE 0x04 +#define PS8802_LANE_COUNT_SET_MASK 0x1F + +/* + * PAGE 2 Register Definitions + */ +#define PS8802_REG_PAGE2 0x02 + +#define PS8802_REG2_USB_SSEQ_LEVEL 0x02 +#define PS8802_REG2_USB_CEQ_LEVEL 0x04 +#define PS8802_USBEQ_LEVEL_UP_12DB (0x0000 | 0x0003) +#define PS8802_USBEQ_LEVEL_UP_13DB (0x0400 | 0x0007) +#define PS8802_USBEQ_LEVEL_UP_16DB (0x0C00 | 0x000F) +#define PS8802_USBEQ_LEVEL_UP_17DB (0x1C00 | 0x001F) +#define PS8802_USBEQ_LEVEL_UP_18DB (0x3C00 | 0x003F) +#define PS8802_USBEQ_LEVEL_UP_19DB (0x7C00 | 0x007F) +#define PS8802_USBEQ_LEVEL_UP_20DB (0xFC00 | 0x00FF) +#define PS8802_USBEQ_LEVEL_UP_23DB (0xFD00 | 0x01FF) +#define PS8802_USBEQ_LEVEL_UP_MASK 0xFDFF + +#define PS8802_REG2_MODE 0x06 +#define PS8802_MODE_DP_REG_CONTROL BIT(7) +#define PS8802_MODE_DP_ENABLE BIT(6) +#define PS8802_MODE_USB_REG_CONTROL BIT(5) +#define PS8802_MODE_USB_ENABLE BIT(4) +#define PS8802_MODE_FLIP_REG_CONTROL BIT(3) +#define PS8802_MODE_FLIP_ENABLE BIT(2) +#define PS8802_MODE_IN_HPD_REG_CONTROL BIT(1) +#define PS8802_MODE_IN_HPD_ENABLE BIT(0) + +#define PS8802_REG2_DPEQ_LEVEL 0x07 +#define PS8802_DPEQ_LEVEL_UP_9DB 0x00 +#define PS8802_DPEQ_LEVEL_UP_11DB 0x01 +#define PS8802_DPEQ_LEVEL_UP_12DB 0x02 +#define PS8802_DPEQ_LEVEL_UP_14DB 0x03 +#define PS8802_DPEQ_LEVEL_UP_17DB 0x04 +#define PS8802_DPEQ_LEVEL_UP_18DB 0x05 +#define PS8802_DPEQ_LEVEL_UP_19DB 0x06 +#define PS8802_DPEQ_LEVEL_UP_20DB 0x07 +#define PS8802_DPEQ_LEVEL_UP_21DB 0x08 +#define PS8802_DPEQ_LEVEL_UP_MASK 0x0F + extern const struct usb_mux_driver ps8802_usb_mux_driver; extern const struct usb_retimer_driver ps8802_usb_retimer; int ps8802_detect(int port); +int ps8802_i2c_read(int port, int page, int offset, int *data); +int ps8802_i2c_write(int port, int page, int offset, int data); +int ps8802_i2c_write16(int port, int page, int offset, int data); +int ps8802_i2c_field_update8(int port, int page, int offset, + uint8_t field_mask, uint8_t set_value); +int ps8802_i2c_field_update16(int port, int page, int offset, + uint16_t field_mask, uint16_t set_value); + #endif /* __CROS_EC_USB_RETIMER_PS8802_H */ |