summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJeff Chase <jnchase@google.com>2020-05-08 06:12:43 -0400
committerCommit Bot <commit-bot@chromium.org>2020-05-14 01:58:53 +0000
commit02ee9d00ac31e6ef36bbc8f378dc319143dccd03 (patch)
treec21f3339e0b2b9557b488e4fe517a05b74ba4fec
parentffa5571e4d7de4dc96ba36f5069e3ff150bde071 (diff)
downloadchrome-ec-02ee9d00ac31e6ef36bbc8f378dc319143dccd03.tar.gz
endeavour: add pse init
Endeavour has an onboard PoE PSE controller. This change initializes the controller and sets per port maximum power. BRANCH=none BUG=b:155863756 TEST=build + boot, various pse commands Change-Id: I1505917f6fac8a569f40102162b0d036e8079a36 Signed-off-by: Jeff Chase <jnchase@google.com> Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/ec/+/2189562 Reviewed-by: Joe Tessler <jrt@chromium.org> Reviewed-by: Aseda Aboagye <aaboagye@chromium.org> Commit-Queue: Aseda Aboagye <aaboagye@chromium.org>
-rw-r--r--board/endeavour/board.c2
-rw-r--r--board/endeavour/board.h2
-rw-r--r--board/endeavour/build.mk1
-rw-r--r--board/endeavour/pse.c181
4 files changed, 184 insertions, 2 deletions
diff --git a/board/endeavour/board.c b/board/endeavour/board.c
index 128b3b4280..8a40c6b7b7 100644
--- a/board/endeavour/board.c
+++ b/board/endeavour/board.c
@@ -86,7 +86,7 @@ const struct mft_t mft_channels[] = {
BUILD_ASSERT(ARRAY_SIZE(mft_channels) == MFT_CH_COUNT);
const struct i2c_port_t i2c_ports[] = {
- {"poe", I2C_PORT_POE, 400, GPIO_I2C0_0_SCL, GPIO_I2C0_0_SDA},
+ {"pse", I2C_PORT_PSE, 400, GPIO_I2C0_0_SCL, GPIO_I2C0_0_SDA},
{"eeprom", I2C_PORT_EEPROM, 400, GPIO_I2C0_1_SCL, GPIO_I2C0_1_SDA},
{"pmic", I2C_PORT_PMIC, 400, GPIO_I2C2_SCL, GPIO_I2C2_SDA},
{"thermal", I2C_PORT_THERMAL, 400, GPIO_I2C3_SCL, GPIO_I2C3_SDA},
diff --git a/board/endeavour/board.h b/board/endeavour/board.h
index 19395732c1..29ca1316f9 100644
--- a/board/endeavour/board.h
+++ b/board/endeavour/board.h
@@ -88,7 +88,7 @@
#define NPCX_TACH_SEL2 1 /* 0:GPIO40/73 1:GPIO93/A6 as TACH */
/* I2C ports */
-#define I2C_PORT_POE NPCX_I2C_PORT0_0
+#define I2C_PORT_PSE NPCX_I2C_PORT0_0
#define I2C_PORT_EEPROM NPCX_I2C_PORT0_1
#define I2C_PORT_PMIC NPCX_I2C_PORT2
#define I2C_PORT_THERMAL NPCX_I2C_PORT3
diff --git a/board/endeavour/build.mk b/board/endeavour/build.mk
index b5915c43a8..20f3f4d02c 100644
--- a/board/endeavour/build.mk
+++ b/board/endeavour/build.mk
@@ -11,3 +11,4 @@ CHIP_VARIANT:=npcx5m6g
board-y=board.o
board-y+=led.o
+board-y+=pse.o
diff --git a/board/endeavour/pse.c b/board/endeavour/pse.c
new file mode 100644
index 0000000000..c4484d257c
--- /dev/null
+++ b/board/endeavour/pse.c
@@ -0,0 +1,181 @@
+/* Copyright 2020 The Chromium OS Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+/*
+ * The LTC4291 is a power over ethernet (PoE) power sourcing equipment (PSE)
+ * controller.
+ */
+
+#include "common.h"
+#include "console.h"
+#include "ec_commands.h"
+#include "hooks.h"
+#include "i2c.h"
+#include "string.h"
+#include "timer.h"
+#include "util.h"
+
+#define LTC4291_I2C_ADDR 0x2C
+
+#define LTC4291_REG_SUPEVN_COR 0x0B
+#define LTC4291_REG_STATPIN 0x11
+#define LTC4291_REG_OPMD 0x12
+#define LTC4291_REG_DISENA 0x13
+#define LTC4291_REG_DETENA 0x14
+#define LTC4291_REG_RSTPB 0x1A
+#define LTC4291_REG_ID 0x1B
+#define LTC4291_REG_DEVID 0x43
+#define LTC4291_REG_HPMD1 0x46
+#define LTC4291_REG_HPMD2 0x4B
+#define LTC4291_REG_HPMD3 0x50
+#define LTC4291_REG_HPMD4 0x55
+
+#define LTC4291_FLD_STATPIN_AUTO BIT(0)
+#define LTC4291_FLD_RSTPB_RSTALL BIT(4)
+
+#define LTC4291_OPMD_AUTO 0xFF
+#define LTC4291_DISENA_ALL 0x0F
+#define LTC4291_DETENA_ALL 0xFF
+#define LTC4291_ID 0x64
+#define LTC4291_DEVID 0x38
+#define LTC4291_HPMD_MIN 0x00
+#define LTC4291_HPMD_MAX 0xA8
+
+#define LTC4291_RESET_DELAY_MS 10
+
+#define I2C_PSE_READ(reg, data) \
+ i2c_read8(I2C_PORT_PSE, LTC4291_I2C_ADDR, LTC4291_REG_##reg, (data))
+
+#define I2C_PSE_WRITE(reg, data) \
+ i2c_write8(I2C_PORT_PSE, LTC4291_I2C_ADDR, LTC4291_REG_##reg, (data))
+
+#define CPRINTS(format, args...) cprints(CC_SYSTEM, format, ## args)
+
+static int pse_write_hpmd(int port, int val)
+{
+ switch (port) {
+ case 0:
+ return I2C_PSE_WRITE(HPMD1, val);
+ case 1:
+ return I2C_PSE_WRITE(HPMD2, val);
+ case 2:
+ return I2C_PSE_WRITE(HPMD3, val);
+ case 3:
+ return I2C_PSE_WRITE(HPMD4, val);
+ default:
+ return EC_ERROR_INVAL;
+ }
+}
+
+/*
+ * Port 1: 100W
+ * Port 2-4: 15W
+ */
+static int pse_port_hpmd[4] = {
+ LTC4291_HPMD_MAX,
+ LTC4291_HPMD_MIN,
+ LTC4291_HPMD_MIN,
+ LTC4291_HPMD_MIN,
+};
+
+static int pse_init_worker(void)
+{
+ int err, id, devid, statpin, port;
+
+ err = I2C_PSE_WRITE(RSTPB, LTC4291_FLD_RSTPB_RSTALL);
+ if (err != 0)
+ return err;
+
+ msleep(LTC4291_RESET_DELAY_MS);
+
+ err = I2C_PSE_READ(ID, &id);
+ if (err != 0)
+ return err;
+
+ err = I2C_PSE_READ(DEVID, &devid);
+ if (err != 0)
+ return err;
+
+ if (id != LTC4291_ID || devid != LTC4291_DEVID)
+ return EC_ERROR_INVAL;
+
+ err = I2C_PSE_READ(STATPIN, &statpin);
+ if (err != 0)
+ return err;
+
+ /*
+ * We don't want to supply power until we've had a chance to set the
+ * limits.
+ */
+ if (statpin & LTC4291_FLD_STATPIN_AUTO)
+ CPRINTS("WARN: PSE reset in AUTO mode");
+
+ err = I2C_PSE_WRITE(OPMD, LTC4291_OPMD_AUTO);
+ if (err != 0)
+ return err;
+
+ /* Set maximum power each port is allowed to allocate. */
+ for (port = 0; port < 4; port++) {
+ err = pse_write_hpmd(port, pse_port_hpmd[port]);
+ if (err != 0)
+ return err;
+ }
+
+ err = I2C_PSE_WRITE(DISENA, LTC4291_DISENA_ALL);
+ if (err != 0)
+ return err;
+
+ err = I2C_PSE_WRITE(DETENA, LTC4291_DETENA_ALL);
+ if (err != 0)
+ return err;
+
+ return 0;
+}
+
+static void pse_init(void)
+{
+ int err;
+
+ err = pse_init_worker();
+ if (err != 0)
+ CPRINTS("PSE init failed: %d", err);
+ else
+ CPRINTS("PSE init done");
+}
+DECLARE_HOOK(HOOK_INIT, pse_init, HOOK_PRIO_INIT_I2C);
+
+static int command_pse(int argc, char **argv)
+{
+ int port;
+
+ /*
+ * TODO(b/156399232): endeavour: PSE controller reset by PLTRST
+ *
+ * Initialization does not reliably work after reset because the device
+ * is held in reset by the AP. Running this command after boot finishes
+ * always succeeds. Remove once the reset signal changes.
+ */
+ if (!strncmp(argv[1], "init", 4))
+ return pse_init_worker();
+
+ if (argc != 3)
+ return EC_ERROR_PARAM_COUNT;
+
+ port = atoi(argv[1]);
+ if (port < 1 || port > 4)
+ return EC_ERROR_PARAM1;
+
+ if (!strncmp(argv[2], "off", 3))
+ return EC_ERROR_UNIMPLEMENTED;
+ else if (!strncmp(argv[2], "min", 3))
+ return pse_write_hpmd(port - 1, LTC4291_HPMD_MIN);
+ else if (!strncmp(argv[2], "max", 3))
+ return pse_write_hpmd(port - 1, LTC4291_HPMD_MAX);
+ else
+ return EC_ERROR_PARAM2;
+}
+DECLARE_CONSOLE_COMMAND(pse, command_pse,
+ "<port# 1-4> <off | min | max>",
+ "Set PSE port power");