coreboot
coreboot is an Open Source project aimed at replacing the proprietary BIOS found in most computers.
h8.c
Go to the documentation of this file.
1 /* SPDX-License-Identifier: GPL-2.0-only */
2 
3 #include <acpi/acpi.h>
4 #include <console/console.h>
5 #include <device/device.h>
6 #include <device/pnp.h>
7 #include <ec/acpi/ec.h>
8 #include <string.h>
9 #include <smbios.h>
10 #include <option.h>
11 #include <pc80/keyboard.h>
12 #include <types.h>
13 
14 #include "h8.h"
15 #include "chip.h"
16 
18 {
21 }
22 
23 /* Controls radio-off pin in WLAN MiniPCIe slot. */
24 void h8_wlan_enable(int on)
25 {
26  if (on)
27  ec_set_bit(0x3a, 5);
28  else
29  ec_clr_bit(0x3a, 5);
30 }
31 
32 /* Controls radio-off pin in UWB MiniPCIe slot. */
33 static void h8_uwb_enable(int on)
34 {
35  if (on)
36  ec_set_bit(0x31, 2);
37  else
38  ec_clr_bit(0x31, 2);
39 }
40 
41 static void h8_fn_ctrl_swap(int on)
42 {
43  if (on)
44  ec_set_bit(0xce, 4);
45  else
46  ec_clr_bit(0xce, 4);
47 }
48 
49 enum battery {
52 };
53 
54 /* h8 charge priority. Defines if primary or secondary
55  * battery is charged first.
56  * Because NVRAM is complete the otherway around as this register,
57  * it's inverted by if
58  */
60 {
61  if (battery == PRIMARY_BATTERY)
62  ec_clr_bit(0x0, 4);
63  else
64  ec_set_bit(0x0, 4);
65 }
66 
67 static void h8_sticky_fn(int on)
68 {
69  if (on)
70  ec_set_bit(0x0, 3);
71  else
72  ec_clr_bit(0x0, 3);
73 }
74 
75 static void f1_to_f12_as_primary(int on)
76 {
77  if (on)
78  ec_set_bit(0x3b, 3);
79  else
80  ec_clr_bit(0x3b, 3);
81 }
82 
83 static void h8_log_ec_version(void)
84 {
85  char ecfw[17];
86  u8 len;
87  u16 fwvh, fwvl;
88 
89  len = h8_build_id_and_function_spec_version(ecfw, sizeof ecfw - 1);
90  ecfw[len] = 0;
91 
92  fwvh = ec_read(0xe9);
93  fwvl = ec_read(0xe8);
94 
95  printk(BIOS_INFO, "H8: EC Firmware ID %s, Version %d.%d%d%c\n", ecfw,
96  fwvh >> 4, fwvh & 0x0f, fwvl >> 4, 0x41 + (fwvl & 0xf));
97 }
98 
99 void h8_set_audio_mute(int mute)
100 {
101  if (mute)
102  ec_set_bit(0x3a, 0);
103  else
104  ec_clr_bit(0x3a, 0);
105 }
106 
107 void h8_enable_event(int event)
108 {
109  if (event < 0 || event > 127)
110  return;
111 
112  ec_set_bit(0x10 + (event >> 3), event & 7);
113 }
114 
115 void h8_disable_event(int event)
116 {
117  if (event < 0 || event > 127)
118  return;
119 
120  ec_clr_bit(0x10 + (event >> 3), event & 7);
121 }
122 
124 {
125  u8 val;
126 
127  switch (on) {
128  case UAO_OFF:
130  // Clear bits 0,2,3
133  break;
134 
135  case UAO_AC_AND_BATTERY:
137  val |= H8_USB_ALWAYS_ON_ENABLE; // Set bit 0
138  val &= ~H8_USB_ALWAYS_ON_AC_ONLY; // Clear bits 2 and 3
140  break;
141 
142  case UAO_AC_ONLY:
144  // Set bits 0,2,3
147  break;
148  }
149 }
150 
151 void h8_usb_power_enable(int onoff)
152 {
153  if (onoff)
154  ec_set_bit(0x3b, 4);
155  else
156  ec_clr_bit(0x3b, 4);
157 }
158 
160 {
161  return ec_read(H8_STATUS1) & 0x5 ? 0 : 1;
162 }
163 
165 {
166  u8 i, c;
167  char str[16 + 1]; /* 16 ASCII chars + \0 */
168 
169  /* Build ID */
170  for (i = 0; i < 8; i++) {
171  c = ec_read(0xf0 + i);
172  if (c < 0x20 || c > 0x7f) {
173  i = snprintf(str, sizeof(str), "*INVALID");
174  break;
175  }
176  str[i] = c;
177  }
178 
179  /* EC firmware function specification version */
180  i += snprintf(str + i, sizeof(str) - i, "-%u.%u", ec_read(0xef), ec_read(0xeb));
181 
182  i = MIN(buf_len, i);
183  memcpy(buf, str, i);
184 
185  return i;
186 }
187 
188 #if CONFIG(GENERATE_SMBIOS_TABLES)
189 static void h8_smbios_strings(struct device *dev, struct smbios_type11 *t)
190 {
191  char tpec[] = "IBM ThinkPad Embedded Controller -[ ]-";
192 
194 
195  t->count = smbios_add_string(t->eos, tpec);
196 }
197 #endif
198 
199 static void h8_init(struct device *dev)
200 {
202 }
203 
204 #if CONFIG(HAVE_ACPI_TABLES)
205 static const char *h8_acpi_name(const struct device *dev)
206 {
207  return "EC";
208 }
209 #endif
210 
211 struct device_operations h8_dev_ops = {
212 #if CONFIG(GENERATE_SMBIOS_TABLES)
213  .get_smbios_strings = h8_smbios_strings,
214 #endif
215 #if CONFIG(HAVE_ACPI_TABLES)
216  .acpi_fill_ssdt = h8_ssdt_generator,
217  .acpi_name = h8_acpi_name,
218 #endif
219  .init = h8_init,
220 };
221 
222 void __weak h8_mb_init(void){ /* NOOP */ }
223 
224 static void h8_enable(struct device *dev)
225 {
226  struct ec_lenovo_h8_config *conf = dev->chip_info;
227  u8 val;
228  u8 beepmask0, beepmask1, reg8;
229 
230  dev->ops = &h8_dev_ops;
231 
234 
235  /* Always enable I/O range 0x1600-0x160f and thermal management */
236  reg8 = conf->config0;
237  reg8 |= H8_CONFIG0_SMM_H8_ENABLE;
238  reg8 |= H8_CONFIG0_TC_ENABLE;
239  ec_write(H8_CONFIG0, reg8);
240 
241  reg8 = conf->config1;
242  if (conf->has_keyboard_backlight) {
243  /* Default to both backlights */
244  reg8 = (reg8 & 0xf3) | ((get_uint_option("backlight", 0) & 0x3) << 2);
245  }
246  ec_write(H8_CONFIG1, reg8);
247  ec_write(H8_CONFIG2, conf->config2);
248  ec_write(H8_CONFIG3, conf->config3);
249 
250  beepmask0 = conf->beepmask0;
251  beepmask1 = conf->beepmask1;
252 
253  if (conf->has_power_management_beeps) {
254  if (get_uint_option("power_management_beeps", 1) == 0) {
255  beepmask0 = 0x00;
256  beepmask1 = 0x00;
257  }
258  }
259 
260  if (conf->has_power_management_beeps) {
261  if (get_uint_option("low_battery_beep", 1))
262  beepmask0 |= 2;
263  else
264  beepmask0 &= ~2;
265  }
266 
269 
270  /* silence sounds in queue */
271  ec_write(H8_SOUND_REPEAT, 0x00);
272  ec_write(H8_SOUND_REG, 0x00);
273 
274  ec_write(0x10, conf->event0_enable);
275  ec_write(0x11, conf->event1_enable);
276  ec_write(0x12, conf->event2_enable);
277  ec_write(0x13, conf->event3_enable);
278  ec_write(0x14, conf->event4_enable);
279  ec_write(0x15, conf->event5_enable);
280  ec_write(0x16, conf->event6_enable);
281  ec_write(0x17, conf->event7_enable);
282  ec_write(0x18, conf->event8_enable);
283  ec_write(0x19, conf->event9_enable);
284  ec_write(0x1a, conf->eventa_enable);
285  ec_write(0x1b, conf->eventb_enable);
286  ec_write(0x1c, conf->eventc_enable);
287  ec_write(0x1d, conf->eventd_enable);
288  ec_write(0x1e, conf->evente_enable);
289  ec_write(0x1f, conf->eventf_enable);
290 
292 
293  h8_usb_always_on_enable(get_uint_option("usb_always_on", 0));
294 
295  h8_wlan_enable(get_uint_option("wlan", 1));
296 
299 
300  unsigned int volume = get_uint_option("volume", ~0);
301  if (volume <= 0xff && !acpi_is_wakeup_s3())
302  ec_write(H8_VOLUME_CONTROL, volume);
303 
304  val = (CONFIG(H8_SUPPORT_BT_ON_WIFI) || h8_has_bdc(dev)) &&
307 
308  val = h8_has_wwan(dev) && h8_wwan_nv_enable();
310 
311  if (conf->has_uwb)
312  h8_uwb_enable(get_uint_option("uwb", 1));
313 
314  h8_fn_ctrl_swap(get_uint_option("fn_ctrl_swap", 0));
315 
316  h8_sticky_fn(get_uint_option("sticky_fn", 0));
317 
318  if (CONFIG(H8_HAS_PRIMARY_FN_KEYS))
319  f1_to_f12_as_primary(get_uint_option("f1_to_f12_as_primary", 1));
320 
322 
324  h8_mb_init();
325 }
326 
328  CHIP_NAME("Lenovo H8 EC")
329  .enable_dev = h8_enable,
330 };
static int acpi_is_wakeup_s3(void)
Definition: acpi.h:9
void * memcpy(void *dest, const void *src, size_t n)
Definition: memcpy.c:7
int smbios_add_string(u8 *start, const char *str)
Definition: smbios.c:40
bool h8_has_bdc(const struct device *dev)
Definition: bluetooth.c:27
bool h8_bluetooth_nv_enable(void)
Definition: bluetooth.c:49
void h8_bluetooth_enable(int on)
Definition: bluetooth.c:16
#define MIN(a, b)
Definition: helpers.h:37
#define printk(level,...)
Definition: stdlib.h:16
@ CONFIG
Definition: dsi_common.h:201
void ec_set_bit(u8 addr, u8 bit)
Definition: ec.c:133
u8 ec_read(u8 addr)
Definition: ec.c:107
void ec_clr_bit(u8 addr, u8 bit)
Definition: ec.c:138
void ec_clear_out_queue(void)
Definition: ec.c:92
int ec_write(u8 addr, u8 data)
Definition: ec.c:115
static void h8_sticky_fn(int on)
Definition: h8.c:67
void h8_enable_event(int event)
Definition: h8.c:107
static void h8_log_ec_version(void)
Definition: h8.c:83
struct device_operations h8_dev_ops
Definition: h8.c:211
void h8_usb_power_enable(int onoff)
Definition: h8.c:151
void h8_trackpoint_enable(int on)
Definition: h8.c:17
static void h8_enable(struct device *dev)
Definition: h8.c:224
battery
Definition: h8.c:49
@ SECONDARY_BATTERY
Definition: h8.c:50
@ PRIMARY_BATTERY
Definition: h8.c:51
void h8_wlan_enable(int on)
Definition: h8.c:24
static void h8_charge_priority(enum battery battery)
Definition: h8.c:59
static void h8_uwb_enable(int on)
Definition: h8.c:33
static void h8_init(struct device *dev)
Definition: h8.c:199
void __weak h8_mb_init(void)
Definition: h8.c:222
static void h8_fn_ctrl_swap(int on)
Definition: h8.c:41
void h8_usb_always_on_enable(enum usb_always_on on)
Definition: h8.c:123
int h8_ultrabay_device_present(void)
Definition: h8.c:159
u8 h8_build_id_and_function_spec_version(char *buf, u8 buf_len)
Definition: h8.c:164
void h8_set_audio_mute(int mute)
Definition: h8.c:99
void h8_disable_event(int event)
Definition: h8.c:115
struct chip_operations ec_lenovo_h8_ops
Definition: h8.c:327
static void f1_to_f12_as_primary(int on)
Definition: h8.c:75
#define H8_TRACKPOINT_OFF
Definition: h8.h:68
#define H8_CONFIG1
Definition: h8.h:50
#define H8_VOLUME_CONTROL
Definition: h8.h:94
#define H8_SOUND_ENABLE0
Definition: h8.h:61
void h8_wwan_enable(int on)
Definition: wwan.c:14
#define H8_FAN_CONTROL
Definition: h8.h:91
#define H8_FAN_CONTROL_AUTO
Definition: h8.h:92
bool h8_has_wwan(const struct device *dev)
Definition: wwan.c:25
#define H8_CONFIG0_TC_ENABLE
Definition: h8.h:48
#define H8_CONFIG0_SMM_H8_ENABLE
Definition: h8.h:47
#define H8_SOUND_REPEAT
Definition: h8.h:64
#define H8_USB_ALWAYS_ON_AC_ONLY
Definition: h8.h:89
#define H8_CONFIG2
Definition: h8.h:54
#define H8_CONFIG0
Definition: h8.h:44
bool h8_wwan_nv_enable(void)
Definition: wwan.c:47
#define H8_CONFIG3
Definition: h8.h:59
#define H8_SOUND_REG
Definition: h8.h:63
#define H8_USB_ALWAYS_ON_ENABLE
Definition: h8.h:88
#define H8_TRACKPOINT_CTRL
Definition: h8.h:66
usb_always_on
Definition: h8.h:9
@ UAO_OFF
Definition: h8.h:10
@ UAO_AC_ONLY
Definition: h8.h:12
@ UAO_AC_AND_BATTERY
Definition: h8.h:11
#define H8_SOUND_ENABLE1
Definition: h8.h:62
#define H8_STATUS1
Definition: h8.h:131
#define H8_TRACKPOINT_ON
Definition: h8.h:69
#define H8_USB_ALWAYS_ON
Definition: h8.h:87
void h8_ssdt_generator(const struct device *dev)
Definition: ssdt.c:24
#define CHIP_NAME(X)
Definition: device.h:32
uint8_t pc_keyboard_init(uint8_t probe_aux)
Definition: keyboard.c:229
#define NO_AUX_DEVICE
Definition: keyboard.h:6
#define BIOS_INFO
BIOS_INFO - Expected events.
Definition: loglevel.h:113
static uint8_t * buf
Definition: uart.c:7
unsigned int get_uint_option(const char *name, const unsigned int fallback)
Definition: option.c:116
const struct smm_save_state_ops *legacy_ops __weak
Definition: save_state.c:8
uint16_t u16
Definition: stdint.h:48
uint8_t u8
Definition: stdint.h:45
Definition: device.h:107
struct device_operations * ops
Definition: device.h:143
DEVTREE_CONST void * chip_info
Definition: device.h:164
u8 has_power_management_beeps
Definition: chip.h:33
u8 has_keyboard_backlight
Definition: chip.h:32
u8 eos[2]
Definition: smbios.h:815
u8 val
Definition: sys.c:300
#define c(value, pmcreg, dst_bits)
int snprintf(char *buf, size_t size, const char *fmt,...)
Note: This file is only for POSIX compatibility, and is meant to be chain-included via string....
Definition: vsprintf.c:35