1 /* SPDX-License-Identifier: GPL-2.0-only */
3 #include <console/console.h>
4 #include <device/device.h>
5 #include <device/pnp.h>
6 #include <ec/acpi/ec.h>
8 #include <pc80/mc146818rtc.h>
12 #include "option_table.h"
16 uint16_t ec_get_version(void)
18 return (ec_read(ECRAM_MAJOR_VERSION
) << 8) | ec_read(ECRAM_MINOR_VERSION
);
21 static uint8_t get_cmos_value(uint32_t bit
, uint32_t length
)
23 uint32_t byte
, byte_bit
;
26 byte
= bit
/ 8; // find the byte where the data starts
27 byte_bit
= bit
% 8; // find the bit in the byte where the data starts
29 uchar
= cmos_read(byte
); // load the byte
30 uchar
>>= byte_bit
; // shift the bits to byte align
31 // clear unspecified bits
32 return uchar
& ((1U << length
) - 1);
35 static uint8_t get_ec_value_from_option(const char *name
,
39 uint32_t cmos_start_bit
,
44 if (cmos_start_bit
!= UINT_MAX
)
45 index
= get_cmos_value(cmos_start_bit
, cmos_length
);
47 index
= get_uint_option(name
, fallback
);
49 if (index
>= lut_size
)
54 static uint16_t ec_get_chip_id(unsigned int port
)
56 return pnp_read_index(port
, NUVOTON_CHIPID
);
59 static void merlin_init(struct device
*dev
)
65 * The address/data IO port pair for the Nuvoton EC are configurable
66 * through the EC domain and are fixed by the EC's firmware blob. If
67 * the value(s) passed through the "dev" structure don't match the
68 * expected values then output severe warnings.
70 if (dev
->path
.pnp
.port
!= NUVOTON_FIXED_ADDR
) {
71 printk(BIOS_ERR
, "NUVOTON: Incorrect ports defined in devicetree.cb.\n");
72 printk(BIOS_ERR
, "NUVOTON: Serious operational issues will arise.\n");
76 const uint16_t chip_id
= ec_get_chip_id(dev
->path
.pnp
.port
);
78 if (chip_id
!= NUVOTON_CHIPID_VAL
) {
79 printk(BIOS_ERR
, "NUVOTON: Expected chip ID 0x%04x, but got 0x%04x instead.\n",
80 NUVOTON_CHIPID_VAL
, chip_id
);
85 * Restore settings from CMOS into EC RAM:
98 * Keyboard Backlight Timeout
100 * Setting: kbl_timeout
102 * Values: 30 Seconds, 1 Minute, 3 Minutes, 5 Minutes, Never
103 * Default: 30 Seconds
106 const uint8_t kbl_timeout
[] = {
114 ec_write(ECRAM_KBL_TIMEOUT
,
115 get_ec_value_from_option("kbl_timeout",
118 ARRAY_SIZE(kbl_timeout
),
125 * Setting: fn_ctrl_swap
127 * Values: Enabled, Disabled
131 const uint8_t fn_ctrl_swap
[] = {
136 ec_write(ECRAM_FN_CTRL_REVERSE
,
137 get_ec_value_from_option("fn_ctrl_swap",
140 ARRAY_SIZE(fn_ctrl_swap
),
145 * Maximum Charge Level
147 * Setting: max_charge
149 * Values: 60%, 80%, 100%
153 const uint8_t max_charge
[] = {
159 if (CONFIG(EC_STARLABS_MAX_CHARGE
))
160 ec_write(ECRAM_MAX_CHARGE
,
161 get_ec_value_from_option("max_charge",
164 ARRAY_SIZE(max_charge
),
171 * Setting: fast_charge
173 * Values: Normal, Fast
177 const uint8_t fast_charge
[] = {
182 if (CONFIG(EC_STARLABS_FAST_CHARGE
))
183 ec_write(ECRAM_FAST_CHARGE
,
184 get_ec_value_from_option("fast_charge",
187 ARRAY_SIZE(fast_charge
),
196 * Values: Quiet, Normal, Aggressive
200 const uint8_t fan_mode
[] = {
206 if (CONFIG(EC_STARLABS_FAN
))
207 ec_write(ECRAM_FAN_MODE
,
208 get_ec_value_from_option("fan_mode",
211 ARRAY_SIZE(fan_mode
),
218 * Setting: fn_lock_state
220 * Values: Locked, Unlocked
224 #ifdef CMOS_VLEN_fn_lock_state
225 const uint8_t fn_lock_state
[] = {
230 ec_write(ECRAM_FN_LOCK_STATE
,
231 get_ec_value_from_option("fn_lock_state",
234 ARRAY_SIZE(fn_lock_state
),
235 CMOS_VSTART_fn_lock_state
,
236 CMOS_VLEN_fn_lock_state
));
242 * Setting: trackpad_state
244 * Values: Enabled, Disabled
248 #ifdef CMOS_VSTART_trackpad_state
249 const uint8_t trackpad_state
[] = {
254 ec_write(ECRAM_TRACKPAD_STATE
,
255 get_ec_value_from_option("trackpad_state",
258 ARRAY_SIZE(trackpad_state
),
259 CMOS_VSTART_trackpad_state
,
260 CMOS_VLEN_trackpad_state
));
264 * Keyboard Backlight Brightness
266 * Setting: kbl_brightness
268 * Values: Off, Low, High / Off, On
272 #ifdef CMOS_VSTART_kbl_brightness
273 const uint8_t kbl_brightness
[] = {
280 ec_write(ECRAM_KBL_BRIGHTNESS
,
281 get_ec_value_from_option("kbl_brightness",
282 CONFIG(EC_STARLABS_KBL_LEVELS
) ? 2 : 0,
284 ARRAY_SIZE(kbl_brightness
),
285 CMOS_VSTART_kbl_brightness
,
286 CMOS_VLEN_kbl_brightness
));
292 * Keyboard Backlight State
299 * Note: Always enable, as the brightness level of `off` disables it.
303 ec_write(ECRAM_KBL_STATE
, KBL_ENABLED
);
306 static struct device_operations ops
= {
308 .read_resources
= noop_read_resources
,
309 .set_resources
= noop_set_resources
,
312 static struct pnp_info pnp_dev_info
[] = {
313 /* System Wake-Up Control (SWUC) */
314 { NULL
, NUVOTON_MSWC
, PNP_IO0
| PNP_IRQ0
, 0xfff0, },
315 /* KBC / Mouse Interface */
316 { NULL
, NUVOTON_KBCM
, PNP_IRQ0
, },
317 /* KBC / Keyboard Interface */
318 { NULL
, NUVOTON_KBCK
, PNP_IO0
| PNP_IO1
| PNP_IRQ0
, 0x07ff, 0x07ff, },
319 /* Shared Memory / Flash Interface (SMFI) */
320 { NULL
, NUVOTON_SHM
, PNP_IO0
| PNP_IRQ0
, 0xfff0, },
321 /* Power Management I/F Channel 1 (PMC1) */
322 { NULL
, NUVOTON_PM1
, PNP_IO0
| PNP_IO1
| PNP_IRQ0
, 0x07ff, 0x07ff, },
323 /* Power Management I/F Channel 2 (PMC2) */
324 { NULL
, NUVOTON_PM2
, PNP_IO0
| PNP_IO1
| PNP_IO2
| PNP_IRQ0
, 0x07fc,
326 /* Power Management I/F Channel 3 (PMC3) */
327 { NULL
, NUVOTON_PM3
, PNP_IO0
| PNP_IO1
| PNP_IRQ0
, 0x07ff, 0x07ff, },
328 /* Extended Shared Memory (ESHM) */
329 { NULL
, NUVOTON_ESHM
},
330 /* Power Management I/F Channel 4 (PMC4) */
331 { NULL
, NUVOTON_PM4
, PNP_IO0
| PNP_IO1
| PNP_IRQ0
, 0x07ff, 0x07ff, },
334 static void enable_dev(struct device
*dev
)
336 pnp_enable_devices(dev
, &ops
, ARRAY_SIZE(pnp_dev_info
), pnp_dev_info
);
339 struct chip_operations ec_starlabs_merlin_ops
= {
340 .name
= "NUVOTON EC",
341 .enable_dev
= enable_dev