From b2c401063dcb61031eaf127d36ed97b31bdd0fc7 Mon Sep 17 00:00:00 2001 From: Jeff Chase Date: Thu, 13 Aug 2020 22:14:27 -0400 Subject: endeavour: add pse host command This will allow userspace to turn PoE ports off and on. BUG=b:163786867 TEST=manual BRANCH=none Change-Id: Ib9716c5ebc6806f79c8cf85843b93d8c1ff0cba3 Signed-off-by: Jeff Chase Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/ec/+/2354544 Reviewed-by: Ting Shen --- board/endeavour/pse.c | 96 +++++++++++++++++++++++++++++++++++++++++++++++---- include/ec_commands.h | 27 +++++++++++++++ 2 files changed, 116 insertions(+), 7 deletions(-) diff --git a/board/endeavour/pse.c b/board/endeavour/pse.c index ad481b46da..cce1a104b1 100644 --- a/board/endeavour/pse.c +++ b/board/endeavour/pse.c @@ -12,6 +12,7 @@ #include "console.h" #include "ec_commands.h" #include "hooks.h" +#include "host_command.h" #include "i2c.h" #include "string.h" #include "timer.h" @@ -20,10 +21,13 @@ #define LTC4291_I2C_ADDR 0x2C #define LTC4291_REG_SUPEVN_COR 0x0B +#define LTC4291_REG_STATPWR 0x10 #define LTC4291_REG_STATPIN 0x11 #define LTC4291_REG_OPMD 0x12 #define LTC4291_REG_DISENA 0x13 #define LTC4291_REG_DETENA 0x14 +#define LTC4291_REG_DETPB 0x18 +#define LTC4291_REG_PWRPB 0x19 #define LTC4291_REG_RSTPB 0x1A #define LTC4291_REG_ID 0x1B #define LTC4291_REG_DEVID 0x43 @@ -31,10 +35,16 @@ #define LTC4291_REG_HPMD2 0x4B #define LTC4291_REG_HPMD3 0x50 #define LTC4291_REG_HPMD4 0x55 +#define LTC4291_REG_LPWRPB 0x6E #define LTC4291_FLD_STATPIN_AUTO BIT(0) #define LTC4291_FLD_RSTPB_RSTALL BIT(4) +#define LTC4291_STATPWR_ON_PORT(port) (0x01 << (port)) +#define LTC4291_DETENA_EN_PORT(port) (0x11 << (port)) +#define LTC4291_DETPB_EN_PORT(port) (0x11 << (port)) +#define LTC4291_PWRPB_OFF_PORT(port) (0x10 << (port)) + #define LTC4291_OPMD_AUTO 0xFF #define LTC4291_DISENA_ALL 0x0F #define LTC4291_DETENA_ALL 0xFF @@ -43,7 +53,9 @@ #define LTC4291_HPMD_MIN 0x00 #define LTC4291_HPMD_MAX 0xA8 -#define LTC4291_RESET_DELAY_US 20000 +#define LTC4291_PORT_MAX 4 + +#define LTC4291_RESET_DELAY_US (20 * MSEC) #define I2C_PSE_READ(reg, data) \ i2c_read8(I2C_PORT_PSE, LTC4291_I2C_ADDR, LTC4291_REG_##reg, (data)) @@ -80,6 +92,18 @@ static int pse_port_hpmd[4] = { LTC4291_HPMD_MIN, }; +static int pse_port_enable(int port) +{ + /* Enable detection and classification */ + return I2C_PSE_WRITE(DETPB, LTC4291_DETPB_EN_PORT(port)); +} + +static int pse_port_disable(int port) +{ + /* Request power off (this also disables detection/classification) */ + return I2C_PSE_WRITE(PWRPB, LTC4291_PWRPB_OFF_PORT(port)); +} + static int pse_init_worker(void) { timestamp_t deadline; @@ -117,7 +141,7 @@ static int pse_init_worker(void) return err; /* Set maximum power each port is allowed to allocate. */ - for (port = 0; port < 4; port++) { + for (port = 0; port < LTC4291_PORT_MAX; port++) { err = pse_write_hpmd(port, pse_port_hpmd[port]); if (err != 0) return err; @@ -164,18 +188,76 @@ static int command_pse(int argc, char **argv) return EC_ERROR_PARAM_COUNT; port = atoi(argv[1]); - if (port < 1 || port > 4) + if (port < 0 || port >= LTC4291_PORT_MAX) return EC_ERROR_PARAM1; if (!strncmp(argv[2], "off", 3)) - return EC_ERROR_UNIMPLEMENTED; + return pse_port_disable(port); + else if (!strncmp(argv[2], "on", 2)) + return pse_port_enable(port); else if (!strncmp(argv[2], "min", 3)) - return pse_write_hpmd(port - 1, LTC4291_HPMD_MIN); + return pse_write_hpmd(port, LTC4291_HPMD_MIN); else if (!strncmp(argv[2], "max", 3)) - return pse_write_hpmd(port - 1, LTC4291_HPMD_MAX); + return pse_write_hpmd(port, LTC4291_HPMD_MAX); else return EC_ERROR_PARAM2; } DECLARE_CONSOLE_COMMAND(pse, command_pse, - " ", + " ", "Set PSE port power"); + +static int ec_command_pse_status(int port, uint8_t *status) +{ + int detena, statpwr; + int err; + + err = I2C_PSE_READ(DETENA, &detena); + if (err != 0) + return err; + + err = I2C_PSE_READ(STATPWR, &statpwr); + if (err != 0) + return err; + + if ((detena & LTC4291_DETENA_EN_PORT(port)) == 0) + *status = EC_PSE_STATUS_DISABLED; + else if ((statpwr & LTC4291_STATPWR_ON_PORT(port)) == 0) + *status = EC_PSE_STATUS_ENABLED; + else + *status = EC_PSE_STATUS_POWERED; + + return 0; +} + +static enum ec_status ec_command_pse(struct host_cmd_handler_args *args) +{ + const struct ec_params_pse *p = args->params; + int err = 0; + + if (p->port >= LTC4291_PORT_MAX) + return EC_RES_INVALID_PARAM; + + switch (p->cmd) { + case EC_PSE_STATUS: { + struct ec_response_pse_status *r = args->response; + + args->response_size = sizeof(*r); + err = ec_command_pse_status(p->port, &r->status); + break; + } + case EC_PSE_ENABLE: + err = pse_port_enable(p->port); + break; + case EC_PSE_DISABLE: + err = pse_port_disable(p->port); + break; + default: + return EC_RES_INVALID_PARAM; + } + + if (err) + return EC_RES_ERROR; + + return EC_RES_SUCCESS; +} +DECLARE_HOST_COMMAND(EC_CMD_PSE, ec_command_pse, EC_VER_MASK(0)); diff --git a/include/ec_commands.h b/include/ec_commands.h index b1b583abdb..edc0d8010f 100644 --- a/include/ec_commands.h +++ b/include/ec_commands.h @@ -5133,6 +5133,33 @@ struct __ec_align4 ec_response_ec_codec_wov_read_audio_shm { uint32_t len; }; +/*****************************************************************************/ +/* Commands for PoE PSE controller */ + +#define EC_CMD_PSE 0x00C0 + +enum ec_pse_subcmd { + EC_PSE_STATUS = 0x0, + EC_PSE_ENABLE = 0x1, + EC_PSE_DISABLE = 0x2, + EC_PSE_SUBCMD_COUNT, +}; + +struct __ec_align1 ec_params_pse { + uint8_t cmd; /* enum ec_pse_subcmd */ + uint8_t port; /* PSE port */ +}; + +enum ec_pse_status { + EC_PSE_STATUS_DISABLED = 0x0, + EC_PSE_STATUS_ENABLED = 0x1, + EC_PSE_STATUS_POWERED = 0x2, +}; + +struct __ec_align1 ec_response_pse_status { + uint8_t status; /* enum ec_pse_status */ +}; + /*****************************************************************************/ /* System commands */ -- cgit v1.2.1