1 /* SPDX-License-Identifier: GPL-2.0-only */
4 #include <console/console.h>
5 #include <device/device.h>
6 #include <device/pnp.h>
8 #include <pc80/keyboard.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)
31 outb(0, MAILBOX_INDEX
);
32 busy
= inb(MAILBOX_DATA
);
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__
);
45 *data
= __get_mailbox_register(start
);
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__
);
61 __set_mailbox_register(start
, *data
);
69 static void ec_command(enum mec5035_cmd cmd
)
71 outb(0, MAILBOX_INDEX
);
72 outb((u8
)cmd
, MAILBOX_DATA
);
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);
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
[] = {
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
,