mb/starlabs/starlite_adl: Configure CNVi Bluetooth I2S GPIOs
[coreboot.git] / src / ec / dell / mec5035 / mec5035.c
blobdffbb7960cfd50d22c709a5b0c7051e0ea4eece0
1 /* SPDX-License-Identifier: GPL-2.0-only */
3 #include <arch/io.h>
4 #include <console/console.h>
5 #include <device/device.h>
6 #include <device/pnp.h>
7 #include <option.h>
8 #include <pc80/keyboard.h>
9 #include <stdint.h>
10 #include "mec5035.h"
12 static const u16 MAILBOX_INDEX = 0x910;
13 static const u16 MAILBOX_DATA = MAILBOX_INDEX + 1;
15 static inline u8 __get_mailbox_register(u8 index)
17 outb(index + 0x10, MAILBOX_INDEX);
18 return inb(MAILBOX_DATA);
21 static inline void __set_mailbox_register(u8 index, u8 data)
23 outb(index + 0x10, MAILBOX_INDEX);
24 outb(data, MAILBOX_DATA);
27 static void wait_ec(void)
29 u8 busy;
30 do {
31 outb(0, MAILBOX_INDEX);
32 busy = inb(MAILBOX_DATA);
33 } while (busy);
37 static enum cb_err read_mailbox_regs(u8 *data, u8 start, u8 count)
39 if (start + count >= NUM_REGISTERS) {
40 printk(BIOS_ERR, "%s: Invalid start or count argument.\n", __func__);
41 return CB_ERR_ARG;
44 while (count--) {
45 *data = __get_mailbox_register(start);
46 data++;
47 start++;
50 return CB_SUCCESS;
53 static enum cb_err write_mailbox_regs(const u8 *data, u8 start, u8 count)
55 if (start + count >= NUM_REGISTERS) {
56 printk(BIOS_ERR, "%s: Invalid start or count argument.\n", __func__);
57 return CB_ERR_ARG;
60 while (count--) {
61 __set_mailbox_register(start, *data);
62 data++;
63 start++;
66 return CB_SUCCESS;
69 static void ec_command(enum mec5035_cmd cmd)
71 outb(0, MAILBOX_INDEX);
72 outb((u8)cmd, MAILBOX_DATA);
73 wait_ec();
76 u8 mec5035_mouse_touchpad(enum ec_mouse_setting setting)
78 u8 buf[15] = {(u8)setting};
79 write_mailbox_regs(buf, 2, 1);
80 ec_command(CMD_MOUSE_TP);
81 /* The vendor firmware reads 15 bytes starting at index 1, presumably
82 to get some sort of return code. Though I don't know for sure if
83 this is the case. Assume the first byte is the return code. */
84 read_mailbox_regs(buf, 1, 15);
85 return buf[0];
88 void mec5035_control_radio(enum ec_radio_dev dev, enum ec_radio_state state)
90 /* From LPC traces and userspace testing with other values,
91 the second byte has to be 2 for an unknown reason. */
92 u8 buf[RADIO_CTRL_NUM_ARGS] = {(u8)dev, 2, (u8)state};
93 write_mailbox_regs(buf, 2, RADIO_CTRL_NUM_ARGS);
94 ec_command(CMD_RADIO_CTRL);
97 void mec5035_early_init(void)
99 /* If this isn't sent the EC shuts down the system after about 15
100 seconds, flashing a pattern on the keyboard LEDs corresponding
101 to "processor failure" according to Dell service manuals. */
102 ec_command(CMD_CPU_OK);
105 static void mec5035_init(struct device *dev)
107 /* Unconditionally use this argument for now as this setting
108 is probably the most sensible default out of the 3 choices. */
109 mec5035_mouse_touchpad(TP_PS2_MOUSE);
111 pc_keyboard_init(NO_AUX_DEVICE);
113 mec5035_control_radio(RADIO_WLAN, get_uint_option("wlan", RADIO_ON));
114 mec5035_control_radio(RADIO_WWAN, get_uint_option("wwan", RADIO_ON));
115 mec5035_control_radio(RADIO_BT, get_uint_option("bluetooth", RADIO_ON));
118 static struct device_operations ops = {
119 .init = mec5035_init,
120 .read_resources = noop_read_resources,
121 .set_resources = noop_set_resources
124 static struct pnp_info pnp_dev_info[] = {
125 { NULL, 0, 0, 0, }
128 static void mec5035_enable(struct device *dev)
130 pnp_enable_devices(dev, &ops, ARRAY_SIZE(pnp_dev_info), pnp_dev_info);
133 struct chip_operations ec_dell_mec5035_ops = {
134 .name = "MEC5035 EC",
135 .enable_dev = mec5035_enable,