Hello Yuji Sasaki,
I'd like you to do a code review. Please visit
https://review.coreboot.org/c/coreboot/+/32692
to review the following change.
Change subject: drivers/i2c: Add LP5562 LED driver
......................................................................
drivers/i2c: Add LP5562 LED driver
Add LP5562 LED driver in Coreboot.
BUG=b:116352348
TEST=Apply board support for LP5562 LED driver, build coreboot.
Signed-off-by: Yuji Sasaki <sasakiy(a)chromium.org>
Change-Id: I0206dc6bfd367a258af88ab61e0928e32e9aa60f
---
A src/drivers/i2c/Kconfig
A src/drivers/i2c/Makefile.inc
A src/drivers/i2c/lp5562/Kconfig
A src/drivers/i2c/lp5562/Makefile.inc
A src/drivers/i2c/lp5562/led_lp5562.c
A src/drivers/i2c/lp5562/led_lp5562.h
A src/drivers/i2c/lp5562/led_lp5562_programs.c
A src/drivers/i2c/lp5562/led_lp5562_programs.h
8 files changed, 863 insertions(+), 0 deletions(-)
git pull ssh://review.coreboot.org:29418/coreboot refs/changes/92/32692/1
diff --git a/src/drivers/i2c/Kconfig b/src/drivers/i2c/Kconfig
new file mode 100644
index 0000000..47b79e6
--- /dev/null
+++ b/src/drivers/i2c/Kconfig
@@ -0,0 +1,28 @@
+source src/drivers/i2c/adm1026/Kconfig
+source src/drivers/i2c/adm1027/Kconfig
+source src/drivers/i2c/adt7463/Kconfig
+source src/drivers/i2c/at24rf08c/Kconfig
+source src/drivers/i2c/ck505/Kconfig
+source src/drivers/i2c/da7219/Kconfig
+source src/drivers/i2c/designware/Kconfig
+source src/drivers/i2c/generic/Kconfig
+source src/drivers/i2c/hid/Kconfig
+source src/drivers/i2c/i2cmux/Kconfig
+source src/drivers/i2c/i2cmux2/Kconfig
+source src/drivers/i2c/lm63/Kconfig
+source src/drivers/i2c/lm96000/Kconfig
+source src/drivers/i2c/lp5562/Kconfig
+source src/drivers/i2c/max98373/Kconfig
+source src/drivers/i2c/max98927/Kconfig
+source src/drivers/i2c/nau8825/Kconfig
+source src/drivers/i2c/nct7802y/Kconfig
+source src/drivers/i2c/pca9538/Kconfig
+source src/drivers/i2c/pcf8523/Kconfig
+source src/drivers/i2c/rt5663/Kconfig
+source src/drivers/i2c/rtd2132/Kconfig
+source src/drivers/i2c/rx6110sa/Kconfig
+source src/drivers/i2c/sx9310/Kconfig
+source src/drivers/i2c/tpm/Kconfig
+source src/drivers/i2c/w83793/Kconfig
+source src/drivers/i2c/w83795/Kconfig
+source src/drivers/i2c/ww_ring/Kconfig
diff --git a/src/drivers/i2c/Makefile.inc b/src/drivers/i2c/Makefile.inc
new file mode 100644
index 0000000..7b5ae0c
--- /dev/null
+++ b/src/drivers/i2c/Makefile.inc
@@ -0,0 +1,28 @@
+subdirs-y += adm1026
+subdirs-y += adm1027
+subdirs-y += adt7463
+subdirs-y += at24rf08c
+subdirs-y += ck505
+subdirs-y += da7219
+subdirs-y += designware
+subdirs-y += generic
+subdirs-y += hid
+subdirs-y += i2cmux
+subdirs-y += i2cmux2
+subdirs-y += lm63
+subdirs-y += lm96000
+subdirs-y += lp5562
+subdirs-y += max98373
+subdirs-y += max98927
+subdirs-y += nau8825
+subdirs-y += nct7802y
+subdirs-y += pca9538
+subdirs-y += pcf8523
+subdirs-y += rt5663
+subdirs-y += rtd2132
+subdirs-y += rx6110sa
+subdirs-y += sx9310
+subdirs-y += tpm
+subdirs-y += w83793
+subdirs-y += w83795
+subdirs-y += ww_ring
diff --git a/src/drivers/i2c/lp5562/Kconfig b/src/drivers/i2c/lp5562/Kconfig
new file mode 100644
index 0000000..cd7041a
--- /dev/null
+++ b/src/drivers/i2c/lp5562/Kconfig
@@ -0,0 +1,2 @@
+config DRIVERS_I2C_LED_LP5562
+ bool
diff --git a/src/drivers/i2c/lp5562/Makefile.inc b/src/drivers/i2c/lp5562/Makefile.inc
new file mode 100644
index 0000000..bfdb408
--- /dev/null
+++ b/src/drivers/i2c/lp5562/Makefile.inc
@@ -0,0 +1,5 @@
+verstage-$(CONFIG_DRIVERS_I2C_LED_LP5562) += led_lp5562.c
+verstage-$(CONFIG_DRIVERS_I2C_LED_LP5562) += led_lp5562_programs.c
+
+ramstage-$(CONFIG_DRIVERS_I2C_LED_LP5562) += led_lp5562.c
+ramstage-$(CONFIG_DRIVERS_I2C_LED_LP5562) += led_lp5562_programs.c
diff --git a/src/drivers/i2c/lp5562/led_lp5562.c b/src/drivers/i2c/lp5562/led_lp5562.c
new file mode 100644
index 0000000..6eafee3
--- /dev/null
+++ b/src/drivers/i2c/lp5562/led_lp5562.c
@@ -0,0 +1,430 @@
+/*
+ * Copyright (C) 2019 Google, Inc.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+/*
+ * This is a driver for the TI LP5562 (http://www.ti.com/product/lp5562),
+ * driving a tri-color LED.
+ *
+ * The only connection between the LED and the main board is an i2c bus.
+ *
+ * This driver imitates a depthcharge display device. On initialization the
+ * driver sets up the controllers to prepare them to accept programs to run.
+ *
+ * When a certain vboot state needs to be indicated, the program for that
+ * state is loaded into the controllers, resulting in the state appropriate
+ * LED behavior.
+ */
+
+#include <console/console.h>
+#include <delay.h>
+#include <device/i2c_simple.h>
+#include <string.h>
+
+#include "drivers/i2c/lp5562/led_lp5562_programs.h"
+
+/* Key lp5562 registers. */
+#define LP5562_ENABLE_REG 0x00
+#define LP5562_OPMODE_REG 0x01
+#define LP5562_PWMREG_B 0x02
+#define LP5562_PWMREG_G 0x03
+#define LP5562_PWMREG_R 0x04
+#define LP5562_CURRENT_B 0x05
+#define LP5562_CURRENT_G 0x06
+#define LP5562_CURRENT_R 0x07
+#define LP5562_CONFIG_REG 0x08
+#define LP5562_ENGINE1_PC 0x09
+#define LP5562_ENGINE2_PC 0x0a
+#define LP5562_ENGINE3_PC 0x0b
+#define LP5562_STATUS_REG 0x0c
+#define LP5562_RESET_REG 0x0d
+#define LP5562_PWMREG_W 0x0e
+#define LP5562_CURRENT_W 0x0f
+#define LP5562_LED_MAP_REG 0x70
+#define LP5562_PROG_MEM_ENG1 0x10
+#define LP5562_PROG_MEM_ENG2 0x30
+#define LP5562_PROG_MEM_ENG3 0x50
+
+/* LP5562 ENABLE REG fields. */
+#define LP5562_ENABLE_LOG_EN 0x80
+#define LP5562_ENABLE_CHIP_EN 0x40
+#define LP5562_ENABLE_EXEC_HOLD 0x00
+#define LP5562_ENABLE_EXEC_STEP 0x01
+#define LP5562_ENABLE_EXEC_RUN 0x02
+#define LP5562_ENABLE_EXEC_MASK 0x03
+#define LP5562_ENABLE_ENG1_SHIFT 4
+#define LP5562_ENABLE_ENG2_SHIFT 2
+#define LP5562_ENABLE_ENG3_SHIFT 0
+#define LP5562_ENABLE_ALL_MASK 0x3f
+#define LP5562_ENABLE_ALL_HOLD 0x00
+#define LP5562_ENABLE_ALL_RUN 0x2a
+
+/* LP5562 OPMODE REG fields. */
+#define LP5562_OPMODE_DISABLED 0x00
+#define LP5562_OPMODE_LOAD 0x01
+#define LP5562_OPMODE_RUN 0x02
+#define LP5562_OPMODE_DIRECT 0x03
+#define LP5562_OPMODE_MASK 0x03
+#define LP5562_OPMODE_ENG1_SHIFT 4
+#define LP5562_OPMODE_ENG2_SHIFT 2
+#define LP5562_OPMODE_ENG3_SHIFT 0
+#define LP5562_OPMODE_ALL_DISABLE 0x00
+#define LP5562_OPMODE_ALL_LOAD 0x15
+#define LP5562_OPMODE_ALL_RUN 0x2a
+
+/*
+ * LP5562_ENABLE_REG, default value
+ */
+#define LP5562_ENABLE_REG_DEFAULT (LP5562_ENABLE_CHIP_EN)
+
+/*
+ * LP5562_CONFIG_REG, default value
+ * PWM_HF=0(256Hz)
+ * PWRSAVE_EN=0 (Disable)
+ * CLKDET_EN/INT_CLK_EN=1 (Internal Clock)
+ */
+#define LP5562_CONFIG_REG_DEFAULT 0x03
+
+/*
+ * LP5562_LED_MAP_REG, default value
+ * B:ENG1, G:ENG2, R:ENG3
+ */
+#define LP5562_LED_MAP_REG_DEFAULT 0x39
+
+/* LP5562 Current default value, applies to all four of them */
+#define LP5562_CRT_CTRL_DEFAULT 0xaf
+
+/* Goes into LP5562_RESET_REG to reset the chip. */
+#define LP5562_RESET_VALUE 0xff
+
+/*
+ * The controller has 96 bytes of SRAM for code/data, availabe as three 32 byte
+ * pages.
+ */
+#define LP5562_PROG_PAGE_SIZE 32
+#define LP5562_PROG_PAGES 3
+#define LP5562_MAX_PROG_SIZE LP5562_PROG_PAGE_SIZE
+
+/*
+ * Structure to cache data relevant to accessing one controller. I2c interface
+ * to use, device address on the i2c bus and a data buffer for write
+ * transactions. The most bytes sent at a time is the register address plus
+ * the program page size.
+ */
+typedef struct {
+ unsigned i2c_bus;
+ uint8_t dev_addr;
+ uint8_t data_buffer[LP5562_PROG_PAGE_SIZE + 1];
+} TiLp5562;
+
+static void led_lp5562_init(unsigned i2c_bus);
+
+/* Controller descriptors. */
+static TiLp5562 lp5562s[LED_LP5562_NUM_LED_CONTROLLERS];
+
+/*
+ * i2c transfer function for the driver. To keep things simple, the function
+ * repeats the transfer, if the first attempt fails. This is OK with the
+ * controller and makes it easier to handle errors.
+ *
+ * Note that the reset register accesses are expected to fail on writes, but
+ * due to a bug in the ipq806x i2c controller, the error is reported on the
+ * following read attempt.
+ *
+ * To work around this the driver writes and then reads the reset register,
+ * the transfer function ignores errors when accessing the reset register.
+ */
+static int ledc_transfer(TiLp5562 *ledc, struct i2c_msg *segs,
+ int seg_count, int reset)
+{
+ int rv, max_attempts = 2;
+
+ while (max_attempts--) {
+ rv = i2c_transfer(ledc->i2c_bus, segs, seg_count);
+
+ /* Accessing reset regsiter is expected to fail. */
+ if (!rv || reset)
+ break;
+ }
+
+ if (rv) {
+ if (!reset)
+ printk(BIOS_WARNING,
+ "%s: dev %#x, reg %#x, %s transaction error.\n",
+ __func__, segs->slave, segs->buf[0],
+ seg_count == 1 ? "write" : "read");
+ else
+ rv = 0;
+ }
+
+ return rv;
+}
+
+/*
+ * The controller is programmed to autoincrement on writes, so up to page size
+ * bytes can be transmitted in one write transaction.
+ */
+static int ledc_write(TiLp5562 *ledc, uint8_t start_addr,
+ const uint8_t *data, unsigned count)
+{
+ struct i2c_msg seg;
+
+ if (count > (sizeof(ledc->data_buffer) - 1)) {
+ printk(BIOS_WARNING, "%s: transfer size too large (%d bytes)\n",
+ __func__, count);
+ return -1;
+ }
+
+ memcpy(ledc->data_buffer + 1, data, count);
+ ledc->data_buffer[0] = start_addr;
+
+ seg.flags = 0;
+ seg.slave = ledc->dev_addr;
+ seg.buf = ledc->data_buffer;
+ seg.len = count + 1;
+
+ return ledc_transfer(ledc, &seg, 1, start_addr == LP5562_RESET_REG);
+}
+
+/* To keep things simple, read is limited to one byte at a time. */
+static int ledc_read(TiLp5562 *ledc, uint8_t addr, uint8_t *data)
+{
+ struct i2c_msg seg[2];
+
+ seg[0].flags = 0;
+ seg[0].slave = ledc->dev_addr;
+ seg[0].buf = &addr;
+ seg[0].len = 1;
+
+ seg[1].flags = I2C_M_RD;
+ seg[1].slave = ledc->dev_addr;
+ seg[1].buf = data;
+ seg[1].len = 1;
+
+ return ledc_transfer(ledc, seg, ARRAY_SIZE(seg),
+ addr == LP5562_RESET_REG);
+}
+
+/*
+ * Reset transaction is expected to result in a failing i2c command. But even
+ * before trying it, read the reset register, which is supposed to always
+ * return 0. If this fails - there is no lp5562 at this address.
+ *
+ * Return 0 on success, -1 on failure to detect controller.
+ */
+static int ledc_reset(TiLp5562 *ledc)
+{
+ uint8_t data;
+
+ data = ~0;
+ ledc_read(ledc, LP5562_RESET_REG, &data);
+ if (data) {
+ printk(BIOS_WARNING,
+ "LED_LP5562: no controller found at address %#2.2x\n",
+ ledc->dev_addr);
+ return -1;
+ }
+
+ data = LP5562_RESET_VALUE;
+ ledc_write(ledc, LP5562_RESET_REG, &data, 1);
+
+ /*
+ * This read is not necessary for the chip reset, but is required to
+ * work around the i2c driver bug where the missing ACK on the last
+ * byte of the write transaction is ignored, but the next transaction
+ * fails.
+ */
+ ledc_read(ledc, LP5562_RESET_REG, &data);
+ return 0;
+}
+
+/*
+ * Write a program into the internal lp5562 memory.
+ */
+static void ledc_write_program(TiLp5562 *ledc, uint8_t load_addr,
+ const uint8_t *program, unsigned count)
+{
+ if (count > LP5562_MAX_PROG_SIZE) {
+ printk(BIOS_WARNING,
+ "%s: program of size %#x does not fit at addr %#x\n",
+ __func__, count, load_addr);
+ return;
+ }
+ ledc_write(ledc, load_addr, program, count);
+}
+
+static void ledc_write_enable(TiLp5562 *ledc, uint8_t value)
+{
+ ledc_write(ledc, LP5562_ENABLE_REG, &value, 1);
+ udelay(500); /* Must wait longer than 488usec */
+}
+
+static void ledc_write_opmode(TiLp5562 *ledc, uint8_t value)
+{
+ ledc_write(ledc, LP5562_OPMODE_REG, &value, 1);
+ udelay(160); /* Must wait longer than 153usec */
+}
+
+/* Run an lp5562 program on a controller. */
+static void ledc_run_program(TiLp5562 *ledc,
+ const TiLp5562Program *program_desc)
+{
+ int i;
+ uint8_t data;
+ uint8_t enable_reg;
+ uint8_t load_addr;
+
+ /* All engines on hold. */
+ ledc_read(ledc, LP5562_ENABLE_REG, &enable_reg);
+ enable_reg &= ~LP5562_ENABLE_ALL_MASK;
+ enable_reg |= LP5562_ENABLE_CHIP_EN;
+ enable_reg |= LP5562_ENABLE_ALL_HOLD;
+ ledc_write_enable(ledc, enable_reg);
+
+ /* All engines in LOAD mode. */
+ ledc_write_opmode(ledc, LP5562_OPMODE_ALL_LOAD);
+
+ /* Inject program code for each engine and start address */
+ load_addr = LP5562_PROG_MEM_ENG1;
+ for (i = 0; i < LED_LP5562_NUM_OF_ENGINES; i++) {
+ ledc_write_program(ledc, load_addr,
+ program_desc->engine_program[i].program_text,
+ program_desc->engine_program[i].program_size);
+ data = program_desc->engine_program[i].engine_start_addr;
+ ledc_write(ledc, LP5562_ENGINE1_PC + i, &data, 1);
+ udelay(160); /* Must wait longer than 153usec */
+ load_addr += LP5562_PROG_PAGE_SIZE;
+ }
+
+ /* All engines on run. */
+ ledc_write_opmode(ledc, LP5562_OPMODE_ALL_RUN);
+
+ enable_reg &= ~LP5562_ENABLE_ALL_MASK;
+ enable_reg |= LP5562_ENABLE_ALL_RUN;
+ ledc_write_enable(ledc, enable_reg);
+}
+
+/*
+ * Initialize a controller to a state were it is ready to accept programs, and
+ * try to confirm that we are in fact talking to a lp5562
+ */
+static int ledc_init_validate(TiLp5562 *ledc)
+{
+ uint8_t data;
+ int i;
+
+ if (ledc_reset(ledc))
+ return -1;
+
+ /* Enable the chip, keep engines in hold state. */
+ ledc_write_enable(ledc, LP5562_ENABLE_REG_DEFAULT | LP5562_ENABLE_ALL_HOLD);
+
+ data = LP5562_CONFIG_REG_DEFAULT;
+ ledc_write(ledc, LP5562_CONFIG_REG, &data, 1);
+
+ data = LP5562_LED_MAP_REG_DEFAULT;
+ ledc_write(ledc, LP5562_LED_MAP_REG, &data, 1);
+
+ /*
+ * All four current control registers are supposed to return the same
+ * value at reset.
+ */
+ for (i = 0; i < 4; i++) {
+ uint8_t reg = (i < 3) ? LP5562_CURRENT_B + i : LP5562_CURRENT_W;
+ ledc_read(ledc, reg, &data);
+ if (data != LP5562_CRT_CTRL_DEFAULT) {
+ printk(BIOS_WARNING,
+ "%s: read %#2.2x from register %#x\n", __func__,
+ data, reg);
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+/*
+ * Find a program matching screen type, and run it on both controllers, if
+ * found.
+ */
+int led_lp5562_display_pattern(unsigned i2c_bus, enum display_pattern pattern)
+{
+ static int initted;
+ const Led5562StateProg *led_prog;
+
+ if (!initted) {
+ led_lp5562_init(i2c_bus);
+ initted = 1;
+ }
+
+ /* Last entry does not have any actual programs defined. */
+ for (led_prog = led_lp5562_state_programs; led_prog->programs[0]; led_prog++)
+ if (led_prog->led_pattern == pattern) {
+ int j;
+
+ /*
+ * First stop all running programs to avoid
+ * inerference between the controllers.
+ */
+ for (j = 0; j < LED_LP5562_NUM_LED_CONTROLLERS; j++) {
+ if (!lp5562s[j].dev_addr)
+ continue;
+ ledc_write_opmode
+ (lp5562s + j,
+ LP5562_OPMODE_ALL_DISABLE);
+ }
+
+ for (j = 0; j < LED_LP5562_NUM_LED_CONTROLLERS; j++) {
+ if (!lp5562s[j].dev_addr)
+ continue;
+ ledc_run_program(lp5562s + j,
+ led_prog->programs[j]);
+ }
+ return 0;
+ }
+
+ printk(BIOS_WARNING, "%s: did not find program for pattern %d\n",
+ __func__, pattern);
+
+ return -1;
+}
+
+#define LP5562_I2C_BASE_ADDR 0x30
+
+static void led_lp5562_init(unsigned i2c_bus)
+{
+ TiLp5562 *ledc;
+ int i, count = 0;
+
+ for (i = 0, ledc = lp5562s;
+ i < LED_LP5562_NUM_LED_CONTROLLERS;
+ i++, ledc++) {
+
+ ledc->i2c_bus = i2c_bus;
+ ledc->dev_addr = LP5562_I2C_BASE_ADDR + i;
+
+ if (!ledc_init_validate(ledc))
+ count++;
+ else
+ ledc->dev_addr = 0; /* Mark disabled. */
+ }
+
+ printk(BIOS_INFO, "LED_LP5562: initialized %d out of %d\n", count, i);
+ if (count != i) {
+ if (count)
+ printk(BIOS_WARNING,
+ "LED_LP5562: will keep going anyway\n");
+ else
+ printk(BIOS_WARNING,
+ "LED_LP5562: LED ring not present\n");
+ }
+}
diff --git a/src/drivers/i2c/lp5562/led_lp5562.h b/src/drivers/i2c/lp5562/led_lp5562.h
new file mode 100644
index 0000000..3c202eb
--- /dev/null
+++ b/src/drivers/i2c/lp5562/led_lp5562.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2019 Google, Inc.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __SRC_DRIVERS_VIDEO_LED_LP5562__H__
+#define __SRC_DRIVERS_VIDEO_LED_LP5562__H__
+
+/*
+ * Different types of display patterns to be shown by the LED while
+ * contrlled by coreboot.
+ */
+enum display_pattern {
+ LED_ALL_OFF, /* Turn the LEDs off. */
+ LED_RECOVERY_PUSHED, /* Recovery button push detected on start up. */
+ LED_WIPEOUT_REQUEST, /* Held long enough for wipout request. */
+ LED_RECOVERY_REQUEST, /* Held long enough for recovery request. */
+ LED_NORMAL_BOOT /* No buttons pressed, normal boot sequence. */
+};
+/*
+ * led_lp5562_display_pattern
+ *
+ * Display pattern on the ring LEDs.
+ */
+int led_lp5562_display_pattern(unsigned i2c_bus, enum display_pattern pattern);
+
+#endif
diff --git a/src/drivers/i2c/lp5562/led_lp5562_programs.c b/src/drivers/i2c/lp5562/led_lp5562_programs.c
new file mode 100644
index 0000000..f322f6a
--- /dev/null
+++ b/src/drivers/i2c/lp5562/led_lp5562_programs.c
@@ -0,0 +1,273 @@
+/*
+ * Copyright (C) 2019 Google, Inc.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+/*
+ * This is a driver for the TI LP5562 (http://www.ti.com/product/lp5562),
+ * driving a tri-color LED.
+ *
+ * The only connection between the LED and the main board is an i2c bus.
+ *
+ * This driver imitates a depthcharge display device. On initialization the
+ * driver sets up the controllers to prepare them to accept programs to run.
+ *
+ * When a certain vboot state needs to be indicated, the program for that
+ * state is loaded into the controllers, resulting in the state appropriate
+ * LED behavior.
+ */
+
+#include "drivers/i2c/lp5562/led_lp5562_programs.h"
+
+/****************************************************************
+ * LED ring program definitions for different patterns.
+ *
+ * Comments below are real lp5562 source code, they are compiled using
+ * lasm.exe, the TI tool available from their Web site (search for lp5562)
+ * and running only on Windows :P.
+ *
+ * Different hex dumps are results of tweaking the source code parameters to
+ * achieve desirable LED ring behavior. It is possible to use just one code
+ * dump and replace certain values in the body to achieve different behaviour
+ * with the same basic dump, but keeping track of location to tweak with every
+ * code change would be quite tedious.
+ */
+
+/*
+ * Solid LED display, the arguments of the set_pwm commands set intensity and
+ * color of the display:
+
+ 1 00 .ENGINE1(R)
+ 2 00 4080 set_pwm 128
+ 3 01 C000 end
+ 4
+ 5 10 .ENGINE2(G)
+ 6 10 4080 set_pwm 128
+ 7 11 C000 end
+ 8
+ 9 20 .ENGINE3(B)
+ 10 20 4080 set_pwm 128
+ 11 21 C000 end
+*/
+
+/* RGB set to 000000, resulting in all LEDs off. */
+static const uint8_t solid_00_text[] = {
+ 0x40, 0x00, 0xc0, 0x00
+};
+
+/* Rgb set to 128, resulting in a brightish white color. */
+static const uint8_t solid_80_text[] = {
+ 0x40, 0x80, 0xc0, 0x00
+};
+
+static const TiLp5562Program solid_000000_program = {
+ {
+ { /* Engine1:Blue */
+ solid_00_text,
+ sizeof(solid_00_text),
+ 0,
+ },
+ { /* Engine2:Green */
+ solid_00_text,
+ sizeof(solid_00_text),
+ 0,
+ },
+ { /* Engine3:Red */
+ solid_00_text,
+ sizeof(solid_00_text),
+ 0,
+ },
+ }
+};
+
+static const TiLp5562Program solid_808080_program = {
+ {
+ { /* Engine1:Blue */
+ solid_80_text,
+ sizeof(solid_80_text),
+ 0,
+ },
+ { /* Engine2:Green */
+ solid_80_text,
+ sizeof(solid_80_text),
+ 0,
+ },
+ { /* Engine3:Red */
+ solid_80_text,
+ sizeof(solid_80_text),
+ 0,
+ },
+ }
+};
+
+/*
+ 1 00 .ENGINE1(B)
+ 2 00 E200 trigger w3
+ 3 01 409B set_pwm 155
+ 4 02 E200 trigger w3
+ 5 03 4000 set_pwm 0
+ 6 04 0000 gotostart
+ 7
+ 8 10 .ENGINE2(G)
+ 9 10 E200 trigger w3
+ 10 11 4032 set_pwm 50
+ 11 12 E200 trigger w3
+ 12 13 4000 set_pwm 0
+ 13 14 0000 gotostart
+ 14
+ 15 20 .ENGINE3(R)
+ 16 20 E006 trigger s21
+ 17 21 4001 set_pwm 1
+ 18 22 5300 wait 300
+ 19 23 E006 trigger s21
+ 20 24 4000 set_pwm 0
+ 21 25 5300 wait 300
+ 22 26 0000 gotostart
+*/
+
+static const uint8_t blink_wipeout1_b_text[] = {
+ 0xe2, 0x00, 0x40, 155, 0xe2, 0x00, 0x40, 0,
+ 0x00, 0x00,
+};
+
+static const uint8_t blink_wipeout1_g_text[] = {
+ 0xe2, 0x00, 0x40, 50, 0xe2, 0x00, 0x40, 0,
+ 0x00, 0x00,
+};
+
+static const uint8_t blink_wipeout1_r_text[] = {
+ 0xe0, 0x06, 0x40, 1, 0x53, 0x00, 0xe0, 0x06,
+ 0x40, 0, 0x53, 0x00, 0x00, 0x00
+};
+
+static const TiLp5562Program blink_wipeout1_program = {
+ {
+ {
+ blink_wipeout1_b_text,
+ sizeof(blink_wipeout1_b_text),
+ 0,
+ },
+ {
+ blink_wipeout1_g_text,
+ sizeof(blink_wipeout1_g_text),
+ 0,
+ },
+ {
+ blink_wipeout1_r_text,
+ sizeof(blink_wipeout1_r_text),
+ 0,
+ },
+ }
+};
+
+static const uint8_t blink_recovery1_b_text[] = {
+ 0xe2, 0x00, 0x40, 10, 0xe2, 0x00, 0x40, 0,
+ 0x00, 0x00,
+};
+
+static const uint8_t blink_recovery1_g_text[] = {
+ 0xe2, 0x00, 0x40, 100, 0xe2, 0x00, 0x40, 0,
+ 0x00, 0x00,
+};
+
+static const uint8_t blink_recovery1_r_text[] = {
+ 0xe0, 0x06, 0x40, 255, 0x53, 0x00, 0xe0, 0x06,
+ 0x40, 0, 0x53, 0x00, 0x00, 0x00
+};
+
+static const TiLp5562Program blink_recovery1_program = {
+ {
+ {
+ blink_recovery1_b_text,
+ sizeof(blink_wipeout1_b_text),
+ 0,
+ },
+ {
+ blink_recovery1_g_text,
+ sizeof(blink_wipeout1_g_text),
+ 0,
+ },
+ {
+ blink_recovery1_r_text,
+ sizeof(blink_wipeout1_r_text),
+ 0,
+ },
+ }
+};
+
+/*
+ * fade_in1.src
+ *
+ 1 00 .ENGINE1(B)
+ 2 00 4000 set_pwm 0
+ 3 01 E200 trigger w3
+ 4 02 1B4C ramp 1000, 77 # ramp up to 155 for 2 seconds
+ 5 03 1A4D ramp 1000, 78
+ 6 04 C000 end
+ 7
+ 8 10 .ENGINE2(G)
+ 9 10 4000 set_pwm 0
+ 10 11 E200 trigger w3
+ 11 12 4318 ramp 1000, 25 # ramp up to 50 for 2 seconds
+ 12 13 4318 ramp 1000, 25
+ 13 14 C000 end
+ 14
+ 15 20 .ENGINE3(R)
+ 16 20 E006 trigger s21
+ 17 21 4001 set_pwm 1
+ 18 22 E006 trigger s21
+ 19 23 C000 end
+*/
+
+static const uint8_t fade_in1_b_text[] = {
+ 0x40, 0, 0xe2, 0x00, 0x1b, 0x4c, 0x1a, 0x4d,
+ 0xc0, 0x00
+};
+static const uint8_t fade_in1_g_text[] = {
+ 0x40, 0, 0xe2, 0x00, 0x43, 0x18, 0x43, 0x18,
+ 0xc0, 0x00
+};
+static const uint8_t fade_in1_r_text[] = {
+ 0xe0, 0x06, 0x40, 1, 0xe0, 0x06, 0x00
+};
+
+static const TiLp5562Program fade_in1_program = {
+ {
+ {
+ fade_in1_b_text,
+ sizeof(fade_in1_b_text),
+ 0,
+ },
+ {
+ fade_in1_g_text,
+ sizeof(fade_in1_g_text),
+ 0,
+ },
+ {
+ fade_in1_r_text,
+ sizeof(fade_in1_r_text),
+ 0,
+ },
+ }
+};
+
+const Led5562StateProg led_lp5562_state_programs[] = {
+ /*
+ * for test purposes the blank screen program is set to blinking, will
+ * be changed soon.
+ */
+ {LED_ALL_OFF, {&solid_000000_program} },
+ {LED_RECOVERY_PUSHED, {&solid_808080_program} },
+ {LED_WIPEOUT_REQUEST, {&blink_wipeout1_program} },
+ {LED_RECOVERY_REQUEST, {&blink_recovery1_program} },
+ {LED_NORMAL_BOOT, {&fade_in1_program} },
+ {}, /* Empty record to mark the end of the table. */
+};
diff --git a/src/drivers/i2c/lp5562/led_lp5562_programs.h b/src/drivers/i2c/lp5562/led_lp5562_programs.h
new file mode 100644
index 0000000..e5373c0
--- /dev/null
+++ b/src/drivers/i2c/lp5562/led_lp5562_programs.h
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2019 Google, Inc.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+/*
+ * This is a driver for the TI LP5562 (http://www.ti.com/product/lp5562),
+ * driving a tri-color LED.
+ *
+ * The only connection between the LED and the main board is an i2c bus.
+ *
+ * This driver imitates a depthcharge display device. On initialization the
+ * driver sets up the controllers to prepare them to accept programs to run.
+ *
+ * When a certain vboot state needs to be indicated, the program for that
+ * state is loaded into the controllers, resulting in the state appropriate
+ * LED behavior.
+ */
+
+#ifndef __THIRD_PARTY_COREBOOT_SRC_DRIVERS_I2C_LED_LP5562_LED_LP5562_PROGRAMS_H__
+#define __THIRD_PARTY_COREBOOT_SRC_DRIVERS_I2C_LED_LP5562_LED_LP5562_PROGRAMS_H__
+
+#include <stdint.h>
+#include "drivers/i2c/lp5562/led_lp5562.h"
+
+/* There are threee independent engines/cores in the controller. */
+#define LED_LP5562_NUM_OF_ENGINES 3
+
+/* Number of LP5562 controllers on this implementation */
+#define LED_LP5562_NUM_LED_CONTROLLERS 1
+
+/*
+ * Structure to describe an lp5562 program: pointer to the text of the
+ * program, its size for each engines, and start address relative to
+ * each engine program memory. Program memory address for each engine is
+ * fixed on LP5562.
+ */
+typedef struct {
+ struct {
+ const uint8_t *program_text;
+ uint8_t program_size;
+ uint8_t engine_start_addr;
+ } engine_program[LED_LP5562_NUM_OF_ENGINES];
+} TiLp5562Program;
+
+/* A structure to bind controller programs to a vboot state. */
+typedef struct {
+ enum display_pattern led_pattern;
+ const TiLp5562Program *programs[LED_LP5562_NUM_LED_CONTROLLERS];
+} Led5562StateProg;
+
+extern const Led5562StateProg led_lp5562_state_programs[];
+
+#endif
--
To view, visit https://review.coreboot.org/c/coreboot/+/32692
To unsubscribe, or for help writing mail filters, visit https://review.coreboot.org/settings
Gerrit-Project: coreboot
Gerrit-Branch: master
Gerrit-Change-Id: I0206dc6bfd367a258af88ab61e0928e32e9aa60f
Gerrit-Change-Number: 32692
Gerrit-PatchSet: 1
Gerrit-Owner: SANTHOSH JANARDHANA HASSAN <sahassan(a)google.com>
Gerrit-Reviewer: Yuji Sasaki <sasakiy(a)chromium.org>
Gerrit-MessageType: newchange
SANTHOSH JANARDHANA HASSAN has uploaded this change for review. ( https://review.coreboot.org/c/coreboot/+/31426
Change subject: google/mistrtal: Add board ID API.
......................................................................
google/mistrtal: Add board ID API.
BUG=None
TEST=Verified GPIO assignment and board ID values.
BRANCH=None
Change-Id: Ic81b41f799c7bfc47a0daee705db1c01cd0af1a3
Signed-off-by: Santhosh Hassan <sahassan(a)google.com>
---
M src/mainboard/google/mistral/Makefile.inc
A src/mainboard/google/mistral/boardid.c
2 files changed, 49 insertions(+), 0 deletions(-)
git pull ssh://review.coreboot.org:29418/coreboot refs/changes/26/31426/1
diff --git a/src/mainboard/google/mistral/Makefile.inc b/src/mainboard/google/mistral/Makefile.inc
index e9013af..ae418f2 100644
--- a/src/mainboard/google/mistral/Makefile.inc
+++ b/src/mainboard/google/mistral/Makefile.inc
@@ -3,6 +3,7 @@
bootblock-y += chromeos.c
bootblock-y += bootblock.c
+verstage-y += boardid.c
verstage-y += memlayout.ld
verstage-y += chromeos.c
verstage-y += verstage.c
@@ -10,7 +11,9 @@
romstage-y += memlayout.ld
romstage-y += chromeos.c
romstage-y += romstage.c
+romstage-y += boardid.c
+ramstage-y += boardid.c
ramstage-y += memlayout.ld
ramstage-y += chromeos.c
ramstage-y += mainboard.c
diff --git a/src/mainboard/google/mistral/boardid.c b/src/mainboard/google/mistral/boardid.c
new file mode 100644
index 0000000..f20960c
--- /dev/null
+++ b/src/mainboard/google/mistral/boardid.c
@@ -0,0 +1,46 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright 2018 Google LLC
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <boardid.h>
+#include <gpio.h>
+#include <console/console.h>
+#include <stdlib.h>
+
+/*
+ * Mistral boards dedicate to the board ID three GPIOs in ternary mode: 105, 106
+ * and 107.
+ */
+
+static uint32_t board_id_val = UNDEFINED_STRAPPING_ID;
+
+static uint32_t get_board_id(void)
+{
+ uint32_t bid;
+ const gpio_t pins[] = {[2] = GPIO(107), [1] = GPIO(106), [0] = GPIO(105)};
+
+ bid = gpio_binary_first_base3_value(pins, ARRAY_SIZE(pins));
+ printk(BIOS_INFO, "Board ID %d\n", bid);
+
+ return bid;
+}
+
+uint32_t board_id(void)
+{
+ if (board_id_val == UNDEFINED_STRAPPING_ID)
+ board_id_val = get_board_id();
+
+ return board_id_val;
+}
+
--
To view, visit https://review.coreboot.org/c/coreboot/+/31426
To unsubscribe, or for help writing mail filters, visit https://review.coreboot.org/settings
Gerrit-Project: coreboot
Gerrit-Branch: master
Gerrit-Change-Id: Ic81b41f799c7bfc47a0daee705db1c01cd0af1a3
Gerrit-Change-Number: 31426
Gerrit-PatchSet: 1
Gerrit-Owner: SANTHOSH JANARDHANA HASSAN <sahassan(a)google.com>
Gerrit-MessageType: newchange
Hello SANTHOSH JANARDHANA HASSAN,
I'd like you to do a code review. Please visit
https://review.coreboot.org/c/coreboot/+/32272
to review the following change.
Change subject: mb/google/mistral: Ignore REC switch if TPM isn't ready
......................................................................
mb/google/mistral: Ignore REC switch if TPM isn't ready
The recovery button's state is cached in the TPM, but on first boot Cr50
isn't ready yet for this task, which leads to a reboot further down the
road (to get TPM up).
To not confuse matters further, only act on the recovery button if the
TPM is in fact able to cache the state.
BUG=b:129878075
BRANCH=none
TEST=recovery button is only read on second boot
Change-Id: I1ad2c148be4cbdbb2afa05c46c483d89855e1959
Signed-off-by: Patrick Georgi <pgeorgi(a)google.com>
---
M src/mainboard/google/mistral/chromeos.c
1 file changed, 3 insertions(+), 0 deletions(-)
git pull ssh://review.coreboot.org:29418/coreboot refs/changes/72/32272/1
diff --git a/src/mainboard/google/mistral/chromeos.c b/src/mainboard/google/mistral/chromeos.c
index 9b69a4f..e0306b16 100644
--- a/src/mainboard/google/mistral/chromeos.c
+++ b/src/mainboard/google/mistral/chromeos.c
@@ -72,6 +72,9 @@
gpio_t rec_sw;
static enum switch_state saved_state = not_probed;
+ if (is_tpm_detected() == 0)
+ return saved_state;
+
if (saved_state != not_probed)
return saved_state;
--
To view, visit https://review.coreboot.org/c/coreboot/+/32272
To unsubscribe, or for help writing mail filters, visit https://review.coreboot.org/settings
Gerrit-Project: coreboot
Gerrit-Branch: master
Gerrit-Change-Id: I1ad2c148be4cbdbb2afa05c46c483d89855e1959
Gerrit-Change-Number: 32272
Gerrit-PatchSet: 1
Gerrit-Owner: Patrick Georgi <pgeorgi(a)google.com>
Gerrit-Reviewer: SANTHOSH JANARDHANA HASSAN <sahassan(a)google.com>
Gerrit-MessageType: newchange
Yuji Sasaki has uploaded this change for review. ( https://review.coreboot.org/c/coreboot/+/32904
Change subject: TEMP: NOT FOR REVIEW: google/mistral: Limit FDR detection for verstage
......................................................................
TEMP: NOT FOR REVIEW: google/mistral: Limit FDR detection for verstage
FDR switch detection and LED state change must only be functional
when called in verstage. get_recovery_mode_switch() is called from
ramstage as part of elog function but this is informational
purpose, should not affecting LED state and boot mode.
This CL is adding #if directives to limit FDR detection for
verstage. When get_recovery_mode_switch() is called from other
stages, it just return current FDR switch state but do not change
LED state or boot mode.
BUG=b:131622855
TEST=Build and run on DUT, keep pushing FDR switch and power on,
verify it do not fall into secondary FDR detection loop in ramstage
after "recovery requested" in verstage.
Signed-off-by: Yuji Sasaki <sasakiy(a)chromium.org>
Change-Id: Ib034acca2bcf39728e58b468e69e74620b086a10
---
M src/mainboard/google/mistral/chromeos.c
1 file changed, 19 insertions(+), 0 deletions(-)
git pull ssh://review.coreboot.org:29418/coreboot refs/changes/04/32904/1
diff --git a/src/mainboard/google/mistral/chromeos.c b/src/mainboard/google/mistral/chromeos.c
index f220151..8873edd 100644
--- a/src/mainboard/google/mistral/chromeos.c
+++ b/src/mainboard/google/mistral/chromeos.c
@@ -67,6 +67,11 @@
wipeout_req
};
+/*
+ * FDR switch detection and LED state change is only functional
+ * when called in verstage.
+ */
+#if defined(__VERSTAGE__)
static void display_pattern(int pattern)
{
led_lp5562_display_pattern(BLSP_QUP_ID_1, pattern);
@@ -130,6 +135,20 @@
return saved_state;
}
+/*
+ * get_recovery_mode_switch is called from ramstage as part of
+ * elog function, but this is informational purpose to show current
+ * FDR switch state, should not affecting LED and boot mode.
+ */
+#else // defined(__VERSTAGE)
+static enum switch_state get_rec_sw_state(void)
+{
+ gpio_t rec_sw = GPIO_REC_STATE;
+ int sampled_value = !gpio_get(rec_sw);
+ return sampled_value ? recovery_req : no_req;
+}
+#endif // defined(__VERSTAGE)
+
int get_recovery_mode_switch(void)
{
return get_rec_sw_state() == recovery_req;
--
To view, visit https://review.coreboot.org/c/coreboot/+/32904
To unsubscribe, or for help writing mail filters, visit https://review.coreboot.org/settings
Gerrit-Project: coreboot
Gerrit-Branch: master
Gerrit-Change-Id: Ib034acca2bcf39728e58b468e69e74620b086a10
Gerrit-Change-Number: 32904
Gerrit-PatchSet: 1
Gerrit-Owner: Yuji Sasaki <sasakiy(a)chromium.org>
Gerrit-MessageType: newchange