Macros can be confusing on their own; hiding commas make things worse. This can sometimes be downright misleading. A "good" example would be the code in soc/intel/xeon_sp/spr/chip.c: CHIP_NAME("Intel SapphireRapids-SP").enable_dev = chip_enable_dev, This appears as CHIP_NAME() being some struct when in fact these are defining 2 separate members of the same struct. It was decided to remove this macro altogether, as it does not do anything special and incurs a maintenance burden. Change-Id: Iaed6dfb144bddcf5c43634b0c955c19afce388f0 Signed-off-by: Nicholas Sudsgaard <devel+coreboot@nsudsgaard.com> Reviewed-on: https://review.coreboot.org/c/coreboot/+/80239 Reviewed-by: Yidi Lin <yidilin@google.com> Reviewed-by: Felix Singer <service+coreboot-gerrit@felixsinger.de> Reviewed-by: Jakub Czapiga <czapiga@google.com> Tested-by: build bot (Jenkins) <no-reply@coreboot.org> Reviewed-by: Matt DeVillier <matt.devillier@amd.corp-partner.google.com>
137 lines
3.2 KiB
C
137 lines
3.2 KiB
C
/* SPDX-License-Identifier: GPL-2.0-only */
|
|
|
|
#include <arch/io.h>
|
|
#include <console/console.h>
|
|
#include <device/device.h>
|
|
#include <device/pnp.h>
|
|
#include <option.h>
|
|
#include <pc80/keyboard.h>
|
|
#include <stdint.h>
|
|
#include "mec5035.h"
|
|
|
|
static const u16 MAILBOX_INDEX = 0x910;
|
|
static const u16 MAILBOX_DATA = MAILBOX_INDEX + 1;
|
|
|
|
static inline u8 __get_mailbox_register(u8 index)
|
|
{
|
|
outb(index + 0x10, MAILBOX_INDEX);
|
|
return inb(MAILBOX_DATA);
|
|
}
|
|
|
|
static inline void __set_mailbox_register(u8 index, u8 data)
|
|
{
|
|
outb(index + 0x10, MAILBOX_INDEX);
|
|
outb(data, MAILBOX_DATA);
|
|
}
|
|
|
|
static void wait_ec(void)
|
|
{
|
|
u8 busy;
|
|
do {
|
|
outb(0, MAILBOX_INDEX);
|
|
busy = inb(MAILBOX_DATA);
|
|
} while (busy);
|
|
}
|
|
|
|
|
|
static enum cb_err read_mailbox_regs(u8 *data, u8 start, u8 count)
|
|
{
|
|
if (start + count >= NUM_REGISTERS) {
|
|
printk(BIOS_ERR, "%s: Invalid start or count argument.\n", __func__);
|
|
return CB_ERR_ARG;
|
|
}
|
|
|
|
while (count--) {
|
|
*data = __get_mailbox_register(start);
|
|
data++;
|
|
start++;
|
|
}
|
|
|
|
return CB_SUCCESS;
|
|
}
|
|
|
|
static enum cb_err write_mailbox_regs(const u8 *data, u8 start, u8 count)
|
|
{
|
|
if (start + count >= NUM_REGISTERS) {
|
|
printk(BIOS_ERR, "%s: Invalid start or count argument.\n", __func__);
|
|
return CB_ERR_ARG;
|
|
}
|
|
|
|
while (count--) {
|
|
__set_mailbox_register(start, *data);
|
|
data++;
|
|
start++;
|
|
}
|
|
|
|
return CB_SUCCESS;
|
|
}
|
|
|
|
static void ec_command(u8 cmd)
|
|
{
|
|
outb(0, MAILBOX_INDEX);
|
|
outb(cmd, MAILBOX_DATA);
|
|
wait_ec();
|
|
}
|
|
|
|
u8 mec5035_mouse_touchpad(u8 setting)
|
|
{
|
|
u8 buf[15] = {0};
|
|
write_mailbox_regs(&setting, 2, 1);
|
|
ec_command(CMD_MOUSE_TP);
|
|
/* The vendor firmware reads 15 bytes starting at index 1, presumably
|
|
to get some sort of return code. Though I don't know for sure if
|
|
this is the case. Assume the first byte is the return code. */
|
|
read_mailbox_regs(buf, 1, 15);
|
|
return buf[0];
|
|
}
|
|
|
|
void mec5035_control_radio(enum ec_radio_dev dev, enum ec_radio_state state)
|
|
{
|
|
/* From LPC traces and userspace testing with other values,
|
|
the second byte has to be 2 for an unknown reason. */
|
|
u8 buf[RADIO_CTRL_NUM_ARGS] = {(u8)dev, 2, (u8)state};
|
|
write_mailbox_regs(buf, 2, RADIO_CTRL_NUM_ARGS);
|
|
ec_command(CMD_RADIO_CTRL);
|
|
}
|
|
|
|
void mec5035_early_init(void)
|
|
{
|
|
/* If this isn't sent the EC shuts down the system after about 15
|
|
seconds, flashing a pattern on the keyboard LEDs corresponding
|
|
to "processor failure" according to Dell service manuals. */
|
|
ec_command(CMD_CPU_OK);
|
|
}
|
|
|
|
static void mec5035_init(struct device *dev)
|
|
{
|
|
/* Unconditionally use this argument for now as this setting
|
|
is probably the most sensible default out of the 3 choices. */
|
|
mec5035_mouse_touchpad(TP_PS2_MOUSE);
|
|
|
|
pc_keyboard_init(NO_AUX_DEVICE);
|
|
|
|
mec5035_control_radio(RADIO_WLAN, get_uint_option("wlan", RADIO_ON));
|
|
mec5035_control_radio(RADIO_WWAN, get_uint_option("wwan", RADIO_ON));
|
|
mec5035_control_radio(RADIO_BT, get_uint_option("bluetooth", RADIO_ON));
|
|
}
|
|
|
|
static struct device_operations ops = {
|
|
.init = mec5035_init,
|
|
.read_resources = noop_read_resources,
|
|
.set_resources = noop_set_resources
|
|
};
|
|
|
|
static struct pnp_info pnp_dev_info[] = {
|
|
{ NULL, 0, 0, 0, }
|
|
};
|
|
|
|
static void mec5035_enable(struct device *dev)
|
|
{
|
|
pnp_enable_devices(dev, &ops, ARRAY_SIZE(pnp_dev_info), pnp_dev_info);
|
|
}
|
|
|
|
struct chip_operations ec_dell_mec5035_ops = {
|
|
.name = "MEC5035 EC",
|
|
.enable_dev = mec5035_enable,
|
|
};
|