ec/starlabs/merlin: Add support for Nuvoton EC's

Support was created for the NPCE9m5x series, using version 1.1
of the datasheet. The specific model tested was the NPCE985P/G,
on the StarLite Mk IV with version 1.00 of the EC firmware.

Signed-off-by: Sean Rhodes <sean@starlabs.systems>
Change-Id: Ib66baf1e88f5d548ce955dffa00c9b88255b2f95
Reviewed-on: https://review.coreboot.org/c/coreboot/+/62702
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
Reviewed-by: Angel Pons <th3fanbus@gmail.com>
Reviewed-by: Paul Menzel <paulepanter@mailbox.org>
This commit is contained in:
Sean Rhodes 2022-03-09 08:23:29 +00:00 committed by Felix Held
parent 6082ee5281
commit 78342989c4
4 changed files with 322 additions and 7 deletions

View File

@ -1,5 +1,11 @@
## SPDX-License-Identifier: GPL-2.0-only
config EC_STARLABS_NUVOTON
bool
select EC_ACPI
help
Interface to Nuvoton embedded controller principally in Star Labs notebooks.
config EC_STARLABS_ITE
bool
select EC_ACPI
@ -33,21 +39,21 @@ config EC_STARLABS_ITE_BIN_PATH
config EC_STARLABS_KBL_LEVELS
bool
default n
depends on EC_STARLABS_ITE
depends on EC_STARLABS_ITE || EC_STARLABS_NUVOTON
help
Select if the mainboard supports multiple levels of brightness for the keyboard.
config EC_STARLABS_FAN
bool
default n
depends on EC_STARLABS_ITE
depends on EC_STARLABS_ITE || EC_STARLABS_NUVOTON
help
Select if the mainboard has a fan.
config EC_STARLABS_MAX_CHARGE
bool
default n
depends on EC_STARLABS_ITE
depends on EC_STARLABS_ITE || EC_STARLABS_NUVOTON
help
Select if the mainboard supports limiting the maximum charge of the battery.

View File

@ -26,3 +26,12 @@ warn_no_ite_fw:
endif
endif
endif
ifeq ($(CONFIG_EC_STARLABS_NUVOTON),y)
EC_VARIANT_DIR := $(call strip_quotes, $(CONFIG_EC_VARIANT_DIR))
CPPFLAGS_common += -I$(src)/ec/starlabs/merlin/variants/$(EC_VARIANT_DIR)
all-y += nuvoton.c
endif

View File

@ -1,19 +1,20 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* EC communication interface for ITE Embedded Controller.
* EC communication interface for Embedded Controller.
*/
#ifndef _EC_STARLABS_ITE_H
#define _EC_STARLABS_ITE_H
#ifndef _EC_STARLABS_EC_H
#define _EC_STARLABS_EC_H
/*
* Define the expected value of the PNP base address that is fixed through
* the BADRSEL register controlled within the EC domain by the EC Firmware.
*/
#define ITE_FIXED_ADDR 0x4e
#define NUVOTON_FIXED_ADDR 0x4e
/* Logical device number (LDN) assignments. */
/* Logical device number (LDN) assignments for ITE. */
#define ITE_SP1 0x01 /* Serial Port 1 (UART) */
#define ITE_SP2 0x02 /* Serial Port 2 (UART) */
#define ITE_SWUC 0x04 /* System Wake-Up Control (SWUC) */
@ -30,9 +31,21 @@
#define ITE_PMC4 0x18 /* Power Management I/F Channel 4 (PMC4) */
#define ITE_PMC5 0x19 /* Power Management I/F Channel 5 (PMC5) */
/* Logical device number (LDN) assignments for Nuvoton. */
#define NUVOTON_MSWC 0x04 /* Mobile System Wake-Up Control (MSWC) */
#define NUVOTON_KBCM 0x05 /* KBC / Mouse Interface */
#define NUVOTON_KBCK 0x06 /* KBC / Keyboard Interface */
#define NUVOTON_SHM 0x0f /* Shared Memory (SHM) */
#define NUVOTON_PM1 0x11 /* Power Management I/F Channel 1 (PM1) */
#define NUVOTON_PM2 0x12 /* Power Management I/F Channel 2 (PM2) */
#define NUVOTON_PM3 0x17 /* Power Management I/F Channel 3 (PM3) */
#define NUVOTON_ESHM 0x1d /* Extended Shared Memory (ESHM) */
#define NUVOTON_PM4 0x1e /* Power Management I/F Channel 3 (PM4) */
/* Host domain registers. */
#define ITE_CHIPID1 0x20 /* Device ID register 1 */
#define ITE_CHIPID2 0x21 /* Device ID register 2 */
#define NUVOTON_CHIPID 0x27 /* Device ID register */
/* EC RAM common offsets */
#define ECRAM_MAJOR_VERSION 0x00

View File

@ -0,0 +1,287 @@
/* SPDX-License-Identifier: GPL-2.0-only */
#include <console/console.h>
#include <device/device.h>
#include <device/pnp.h>
#include <ec/acpi/ec.h>
#include <option.h>
#include <pc80/keyboard.h>
#include "ec.h"
#include "ecdefs.h"
uint16_t ec_get_version(void)
{
return (ec_read(ECRAM_MAJOR_VERSION) << 8) | ec_read(ECRAM_MINOR_VERSION);
}
static uint8_t get_ec_value_from_option(const char *name,
unsigned int fallback,
const uint8_t *lut,
size_t lut_size)
{
unsigned int index = get_uint_option(name, fallback);
if (index >= lut_size)
index = fallback;
return lut[index];
}
static uint16_t ec_get_chip_id(unsigned int port)
{
return pnp_read_index(port, NUVOTON_CHIPID);
}
static void merlin_init(struct device *dev)
{
if (!dev->enabled)
return;
/*
* The address/data IO port pair for the Nuvoton EC are configurable
* through the EC domain and are fixed by the EC's firmware blob. If
* the value(s) passed through the "dev" structure don't match the
* expected values then output severe warnings.
*/
if (dev->path.pnp.port != NUVOTON_FIXED_ADDR) {
printk(BIOS_ERR, "NUVOTON: Incorrect ports defined in devicetree.cb.\n");
printk(BIOS_ERR, "NUVOTON: Serious operational issues will arise.\n");
return;
}
const uint16_t chip_id = ec_get_chip_id(dev->path.pnp.port);
if (chip_id != NUVOTON_CHIPID_VAL) {
printk(BIOS_ERR, "NUVOTON: Expected chip ID 0x%04x, but got 0x%04x instead.\n",
NUVOTON_CHIPID_VAL, chip_id);
return;
}
pc_keyboard_init(NO_AUX_DEVICE);
/*
* Restore settings from CMOS into EC RAM:
*
* kbl_timeout
* fn_ctrl_swap
* max_charge
* fan_mode
* fn_lock_state
* trackpad_state
* kbl_brightness
* kbl_state
*/
/*
* Keyboard Backlight Timeout
*
* Setting: kbl_timeout
*
* Values: 30 Seconds, 1 Minute, 3 Minutes, 5 Minutes, Never
* Default: 30 Seconds
*
*/
const uint8_t kbl_timeout[] = {
SEC_30,
MIN_1,
MIN_3,
MIN_5,
NEVER
};
ec_write(ECRAM_KBL_TIMEOUT,
get_ec_value_from_option("kbl_timeout",
0,
kbl_timeout,
ARRAY_SIZE(kbl_timeout)));
/*
* Fn Ctrl Reverse
*
* Setting: fn_ctrl_swap
*
* Values: Enabled, Disabled
* Default: Disabled
*
*/
const uint8_t fn_ctrl_swap[] = {
FN_CTRL,
CTRL_FN
};
ec_write(ECRAM_FN_CTRL_REVERSE,
get_ec_value_from_option("fn_ctrl_swap",
1,
fn_ctrl_swap,
ARRAY_SIZE(fn_ctrl_swap)));
/*
* Maximum Charge Level
*
* Setting: max_charge
*
* Values: 60%, 80%, 100%
* Default: 100%
*
*/
const uint8_t max_charge[] = {
CHARGE_100,
CHARGE_80,
CHARGE_60
};
if (CONFIG(EC_STARLABS_MAX_CHARGE))
ec_write(ECRAM_MAX_CHARGE,
get_ec_value_from_option("max_charge",
0,
max_charge,
ARRAY_SIZE(max_charge)));
/*
* Fan Mode
*
* Setting: fan_mode
*
* Values: Quiet, Normal, Aggressive
* Default: Normal
*
*/
const uint8_t fan_mode[] = {
FAN_NORMAL,
FAN_AGGRESSIVE,
FAN_QUIET
};
if (CONFIG(EC_STARLABS_FAN))
ec_write(ECRAM_FAN_MODE,
get_ec_value_from_option("fan_mode",
0,
fan_mode,
ARRAY_SIZE(fan_mode)));
/*
* Function Lock
*
* Setting: fn_lock_state
*
* Values: Locked, Unlocked
* Default: Locked
*
*/
const uint8_t fn_lock_state[] = {
UNLOCKED,
LOCKED
};
ec_write(ECRAM_FN_LOCK_STATE,
get_ec_value_from_option("fn_lock_state",
1,
fn_lock_state,
ARRAY_SIZE(fn_lock_state)));
/*
* Trackpad State
*
* Setting: trackpad_state
*
* Values: Enabled, Disabled
* Default: Enabled
*
*/
const uint8_t trackpad_state[] = {
TRACKPAD_ENABLED,
TRACKPAD_DISABLED
};
ec_write(ECRAM_TRACKPAD_STATE,
get_ec_value_from_option("trackpad_state",
0,
trackpad_state,
ARRAY_SIZE(trackpad_state)));
/*
* Keyboard Backlight Brightness
*
* Setting: kbl_brightness
*
* Values: Off, Low, High / Off, On
* Default: Low
*
*/
const uint8_t kbl_brightness[] = {
KBL_ON,
KBL_OFF,
KBL_LOW,
KBL_HIGH
};
if (CONFIG(EC_STARLABS_KBL_LEVELS))
ec_write(ECRAM_KBL_BRIGHTNESS,
get_ec_value_from_option("kbl_brightness",
2,
kbl_brightness,
ARRAY_SIZE(kbl_brightness)));
else
ec_write(ECRAM_KBL_BRIGHTNESS,
get_ec_value_from_option("kbl_brightness",
0,
kbl_brightness,
ARRAY_SIZE(kbl_brightness)));
/*
* Keyboard Backlight State
*
* Setting: kbl_state
*
* Values: Off, On
* Default: On
*
*/
const uint8_t kbl_state[] = {
KBL_DISABLED,
KBL_ENABLED
};
ec_write(ECRAM_KBL_STATE,
get_ec_value_from_option("kbl_state",
1,
kbl_state,
ARRAY_SIZE(kbl_state)));
}
static struct device_operations ops = {
.init = merlin_init,
.read_resources = noop_read_resources,
.set_resources = noop_set_resources,
};
static struct pnp_info pnp_dev_info[] = {
/* System Wake-Up Control (SWUC) */
{ NULL, NUVOTON_MSWC, PNP_IO0 | PNP_IRQ0, 0xfff0, },
/* KBC / Mouse Interface */
{ NULL, NUVOTON_KBCM, PNP_IRQ0, },
/* KBC / Keyboard Interface */
{ NULL, NUVOTON_KBCK, PNP_IO0 | PNP_IO1 | PNP_IRQ0, 0x07ff, 0x07ff, },
/* Shared Memory / Flash Interface (SMFI) */
{ NULL, NUVOTON_SHM, PNP_IO0 | PNP_IRQ0, 0xfff0, },
/* Power Management I/F Channel 1 (PMC1) */
{ NULL, NUVOTON_PM1, PNP_IO0 | PNP_IO1 | PNP_IRQ0, 0x07ff, 0x07ff, },
/* Power Management I/F Channel 2 (PMC2) */
{ NULL, NUVOTON_PM2, PNP_IO0 | PNP_IO1 | PNP_IO2 | PNP_IRQ0, 0x07fc,
0x07fc, 0xfff0, },
/* Power Management I/F Channel 3 (PMC3) */
{ NULL, NUVOTON_PM3, PNP_IO0 | PNP_IO1 | PNP_IRQ0, 0x07ff, 0x07ff, },
/* Extended Shared Memory (ESHM) */
{ NULL, NUVOTON_ESHM },
/* Power Management I/F Channel 4 (PMC4) */
{ NULL, NUVOTON_PM4, PNP_IO0 | PNP_IO1 | PNP_IRQ0, 0x07ff, 0x07ff, },
};
static void enable_dev(struct device *dev)
{
pnp_enable_devices(dev, &ops, ARRAY_SIZE(pnp_dev_info), pnp_dev_info);
}
struct chip_operations ec_starlabs_merlin_ops = {
CHIP_NAME("NUVOTON EC")
.enable_dev = enable_dev
};