From 5d10775877dc2115efa43ad76b78818376006e1b Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Wed, 15 Jan 2020 21:02:41 -0700 Subject: [PATCH] Add darp5 firmware --- src/board/system76/darp5/acpi.c | 78 ++++ src/board/system76/darp5/battery.c | 138 +++++++ src/board/system76/darp5/board.mk | 36 ++ src/board/system76/darp5/gctrl.c | 7 + src/board/system76/darp5/gpio.c | 268 ++++++++++++ src/board/system76/darp5/include/board/acpi.h | 9 + .../system76/darp5/include/board/battery.h | 20 + src/board/system76/darp5/include/board/cpu.h | 6 + .../system76/darp5/include/board/gctrl.h | 8 + src/board/system76/darp5/include/board/gpio.h | 51 +++ src/board/system76/darp5/include/board/kbc.h | 15 + .../system76/darp5/include/board/kbscan.h | 13 + .../system76/darp5/include/board/keymap.h | 50 +++ src/board/system76/darp5/include/board/peci.h | 15 + src/board/system76/darp5/include/board/pmc.h | 10 + src/board/system76/darp5/include/board/pnp.h | 6 + .../system76/darp5/include/board/power.h | 6 + src/board/system76/darp5/include/board/ps2.h | 8 + src/board/system76/darp5/include/board/pwm.h | 8 + .../system76/darp5/include/board/scratch.h | 6 + .../system76/darp5/include/board/smbus.h | 8 + src/board/system76/darp5/kbc.c | 253 ++++++++++++ src/board/system76/darp5/kbscan.c | 172 ++++++++ src/board/system76/darp5/keymap.c | 11 + src/board/system76/darp5/keymap/default.c | 22 + src/board/system76/darp5/main.c | 173 ++++++++ src/board/system76/darp5/peci.c | 151 +++++++ src/board/system76/darp5/pmc.c | 108 +++++ src/board/system76/darp5/pnp.c | 43 ++ src/board/system76/darp5/power.c | 382 ++++++++++++++++++ src/board/system76/darp5/ps2.c | 7 + src/board/system76/darp5/pwm.c | 24 ++ src/board/system76/darp5/scratch.c | 99 +++++ .../darp5/scratch/include/scratch/pmc.h | 33 ++ src/board/system76/darp5/scratch/main.c | 101 +++++ src/board/system76/darp5/scratch/pmc.c | 24 ++ src/board/system76/darp5/scratch/scratch.mk | 40 ++ src/board/system76/darp5/scratch/stdio.c | 20 + src/board/system76/darp5/smbus.c | 21 + src/board/system76/darp5/stdio.c | 20 + .../system76/galp3-c/include/board/keymap.h | 4 +- src/board/system76/galp3-c/kbscan.c | 11 - src/board/system76/galp3-c/keymap/darter.c | 188 --------- 43 files changed, 2472 insertions(+), 201 deletions(-) create mode 100644 src/board/system76/darp5/acpi.c create mode 100644 src/board/system76/darp5/battery.c create mode 100644 src/board/system76/darp5/board.mk create mode 100644 src/board/system76/darp5/gctrl.c create mode 100644 src/board/system76/darp5/gpio.c create mode 100644 src/board/system76/darp5/include/board/acpi.h create mode 100644 src/board/system76/darp5/include/board/battery.h create mode 100644 src/board/system76/darp5/include/board/cpu.h create mode 100644 src/board/system76/darp5/include/board/gctrl.h create mode 100644 src/board/system76/darp5/include/board/gpio.h create mode 100644 src/board/system76/darp5/include/board/kbc.h create mode 100644 src/board/system76/darp5/include/board/kbscan.h create mode 100644 src/board/system76/darp5/include/board/keymap.h create mode 100644 src/board/system76/darp5/include/board/peci.h create mode 100644 src/board/system76/darp5/include/board/pmc.h create mode 100644 src/board/system76/darp5/include/board/pnp.h create mode 100644 src/board/system76/darp5/include/board/power.h create mode 100644 src/board/system76/darp5/include/board/ps2.h create mode 100644 src/board/system76/darp5/include/board/pwm.h create mode 100644 src/board/system76/darp5/include/board/scratch.h create mode 100644 src/board/system76/darp5/include/board/smbus.h create mode 100644 src/board/system76/darp5/kbc.c create mode 100644 src/board/system76/darp5/kbscan.c create mode 100644 src/board/system76/darp5/keymap.c create mode 100644 src/board/system76/darp5/keymap/default.c create mode 100644 src/board/system76/darp5/main.c create mode 100644 src/board/system76/darp5/peci.c create mode 100644 src/board/system76/darp5/pmc.c create mode 100644 src/board/system76/darp5/pnp.c create mode 100644 src/board/system76/darp5/power.c create mode 100644 src/board/system76/darp5/ps2.c create mode 100644 src/board/system76/darp5/pwm.c create mode 100644 src/board/system76/darp5/scratch.c create mode 100644 src/board/system76/darp5/scratch/include/scratch/pmc.h create mode 100644 src/board/system76/darp5/scratch/main.c create mode 100644 src/board/system76/darp5/scratch/pmc.c create mode 100644 src/board/system76/darp5/scratch/scratch.mk create mode 100644 src/board/system76/darp5/scratch/stdio.c create mode 100644 src/board/system76/darp5/smbus.c create mode 100644 src/board/system76/darp5/stdio.c delete mode 100644 src/board/system76/galp3-c/keymap/darter.c diff --git a/src/board/system76/darp5/acpi.c b/src/board/system76/darp5/acpi.c new file mode 100644 index 0000000..85d5fda --- /dev/null +++ b/src/board/system76/darp5/acpi.c @@ -0,0 +1,78 @@ +#include +#include +#include +#include +#include + +extern bool lid_wake; + +uint8_t acpi_read(uint8_t addr) { + uint8_t data = 0; + + #define ACPI_8(K, V) \ + case (K): \ + data = (uint8_t)(V); \ + break + + #define ACPI_16(K, V) \ + ACPI_8(K, V); \ + ACPI_8((K) + 1, (V) >> 8) + + #define ACPI_32(K, V) \ + ACPI_16(K, V); \ + ACPI_16((K) + 2, (V) >> 16) + + switch (addr) { + // Lid state and other flags + case 0x03: + if (gpio_get(&LID_SW_N)) { + // Lid is open + data |= 1 << 0; + } + if (lid_wake) { + data |= 1 << 2; + } + break; + + // Handle AC adapter and battery present + case 0x10: + if (!gpio_get(&ACIN_N)) { + // AC adapter connected + data |= 1 << 0; + } + // BAT0 always connected - TODO + data |= 1 << 2; + break; + + ACPI_16(0x16, battery_design_capacity); + ACPI_16(0x1A, battery_full_capacity); + ACPI_16(0x22, battery_design_voltage); + + // Bypass status test in ACPI - TODO + case 0x26: + data |= 1 << 1; + break; + + ACPI_16(0x2A, battery_current); + ACPI_16(0x2E, battery_remaining_capacity); + ACPI_16(0x32, battery_voltage); + + // Set size of flash (from old firmware) + ACPI_8 (0xE5, 0x80); + } + + DEBUG("acpi_read %02X = %02X\n", addr, data); + return data; +} + + +void acpi_write(uint8_t addr, uint8_t data) { + DEBUG("acpi_write %02X = %02X\n", addr, data); + + switch (addr) { + // Lid state and other flags + case 0x03: + lid_wake = (bool)(data & (1 << 2)); + break; + } +} diff --git a/src/board/system76/darp5/battery.c b/src/board/system76/darp5/battery.c new file mode 100644 index 0000000..d107622 --- /dev/null +++ b/src/board/system76/darp5/battery.c @@ -0,0 +1,138 @@ +#include +#include + +int smbus_read(uint8_t address, uint8_t command, uint16_t * data) { + return i2c_get(&I2C_0, address, command, (uint8_t *)data, 2); +} + +int smbus_write(uint8_t address, uint8_t command, uint16_t data) { + return i2c_set(&I2C_0, address, command, (uint8_t *)&data, 2); +} + +// ChargeOption0 flags +// Low Power Mode Enable +#define SBC_EN_LWPWR ((uint16_t)(1 << 15)) +// Watchdog Timer Adjust +#define SBC_WDTMR_ADJ_175S ((uint16_t)(0b11 << 13)) +// Switching Frequency +#define SBC_PWM_FREQ_800KHZ ((uint16_t)(0b01 << 8)) +// IDCHG Amplifier Gain +#define SBC_IDCHC_GAIN ((uint16_t)(1 << 3)) + +int battery_charger_disable(void) { + int res = 0; + + // Set charge option 0 with 175s watchdog + res = smbus_write( + 0x09, + 0x12, + SBC_EN_LWPWR | + SBC_WDTMR_ADJ_175S | + SBC_PWM_FREQ_800KHZ | + SBC_IDCHC_GAIN + ); + + // Disable charge current + res = smbus_write(0x09, 0x14, 0); + if (res < 0) return res; + + // Disable charge voltage + res = smbus_write(0x09, 0x15, 0); + if (res < 0) return res; + + return 0; +} + +int battery_charger_enable(void) { + int res = 0; + + res = battery_charger_disable(); + if (res < 0) return res; + + // Set charge current to ~1.5 A + res = smbus_write(0x09, 0x14, 0x0600); + if (res < 0) return res; + + // Set charge voltage to ~13 V + res = smbus_write(0x09, 0x15, 0x3300); + if (res < 0) return res; + + // Set charge option 0 with watchdog disabled + res = smbus_write( + 0x09, + 0x12, + SBC_EN_LWPWR | + SBC_PWM_FREQ_800KHZ | + SBC_IDCHC_GAIN + ); + + return 0; +} + +uint16_t battery_temp = 0; +uint16_t battery_voltage = 0; +uint16_t battery_current = 0; +uint16_t battery_charge = 0; +uint16_t battery_remaining_capacity = 0; +uint16_t battery_full_capacity = 0; +uint16_t battery_design_capacity = 0; +uint16_t battery_design_voltage = 0; + +void battery_event(void) { + int res = 0; + + #define command(N, V) { \ + res = smbus_read(0x0B, V, &N); \ + if (res < 0) { \ + N = 0; \ + return; \ + } \ + } + + command(battery_temp, 0x08); + command(battery_voltage, 0x09); + command(battery_current, 0x0A); + command(battery_charge, 0x0D); + command(battery_remaining_capacity, 0x0F); + command(battery_full_capacity, 0x10); + command(battery_design_capacity, 0x18); + command(battery_design_voltage, 0x19); + + #undef command +} + +void battery_debug(void) { + uint16_t data = 0; + int res = 0; + + #define command(N, A, V) { \ + DEBUG(#N ": "); \ + res = smbus_read(A, V, &data); \ + if (res < 0) { \ + DEBUG("ERROR %04X\n", -res); \ + } else { \ + DEBUG("%04X\n", data); \ + } \ + } + + DEBUG("Battery:\n"); + command(Temperature, 0x0B, 0x08); + command(Voltage, 0x0B, 0x09); + command(Current, 0x0B, 0x0A); + command(Charge, 0x0B, 0x0D); + + DEBUG("Charger:\n"); + command(ChargeOption0, 0x09, 0x12); + command(ChargeOption1, 0x09, 0x3B); + command(ChargeOption2, 0x09, 0x38); + command(ChargeOption3, 0x09, 0x37); + command(ChargeCurrent, 0x09, 0x14); + command(ChargeVoltage, 0x09, 0x15); + command(DishargeCurrent, 0x09, 0x39); + command(InputCurrent, 0x09, 0x3F); + command(ProchotOption0, 0x09, 0x3C); + command(ProchotOption1, 0x09, 0x3D); + command(ProchotStatus, 0x09, 0x3A); + + #undef command +} diff --git a/src/board/system76/darp5/board.mk b/src/board/system76/darp5/board.mk new file mode 100644 index 0000000..5446927 --- /dev/null +++ b/src/board/system76/darp5/board.mk @@ -0,0 +1,36 @@ +EC=it8587e + +# Add keymap to src +KEYMAP?=default +SRC+=$(BOARD_DIR)/keymap/$(KEYMAP).c + +# Set log level +# 0 - NONE +# 1 - ERROR +# 2 - WARN +# 3 - INFO +# 4 - DEBUG +# 5 - TRACE +CFLAGS+=-DLEVEL=2 + +# Enable I2C debug on 0x76 +CFLAGS+=-DI2C_DEBUGGER=0x76 + +# Add scratch ROM source +SCRATCH_DIR=$(BOARD_DIR)/scratch +SCRATCH_SRC=$(wildcard $(SCRATCH_DIR)/*.c) +SCRATCH_INCLUDE=$(wildcard $(SCRATCH_DIR)/include/scratch/*.h) $(SCRATCH_DIR)/scratch.mk +SCRATCH_CFLAGS=-I$(SCRATCH_DIR)/include +include $(SCRATCH_DIR)/scratch.mk + +# Include scratch header in main firmware +CFLAGS+=-I$(BUILD)/include +INCLUDE+=$(BUILD)/include/scratch.h + +flash: $(BUILD)/ec.rom + cargo build --manifest-path ecflash/Cargo.toml --example flash --release + sudo ecflash/target/release/examples/flash $< + +isp: $(BUILD)/ec.rom + cargo build --manifest-path ecflash/Cargo.toml --example isp --release + sudo ecflash/target/release/examples/isp $< diff --git a/src/board/system76/darp5/gctrl.c b/src/board/system76/darp5/gctrl.c new file mode 100644 index 0000000..d66775f --- /dev/null +++ b/src/board/system76/darp5/gctrl.c @@ -0,0 +1,7 @@ +#include + +void gctrl_init(void) { + SPCTRL1 = 0x03; + BADRSEL = 0; + RSTS = 0x84; +} diff --git a/src/board/system76/darp5/gpio.c b/src/board/system76/darp5/gpio.c new file mode 100644 index 0000000..b8c39da --- /dev/null +++ b/src/board/system76/darp5/gpio.c @@ -0,0 +1,268 @@ +#include +#include + +struct Gpio __code ACIN_N = GPIO(B, 6); +struct Gpio __code AC_PRESENT = GPIO(E, 7); +struct Gpio __code ALL_SYS_PWRGD = GPIO(C, 0); +struct Gpio __code BKL_EN = GPIO(H, 2); +struct Gpio __code BT_EN = GPIO(F, 3); +struct Gpio __code BUF_PLT_RST_N = GPIO(D, 2); +struct Gpio __code CCD_EN = GPIO(G, 0); +struct Gpio __code DD_ON = GPIO(E, 4); +struct Gpio __code EC_EN = GPIO(E, 1); +struct Gpio __code EC_RSMRST_N = GPIO(E, 5); +struct Gpio __code LED_ACIN = GPIO(C, 7); +struct Gpio __code LED_BAT_CHG = GPIO(A, 5); +struct Gpio __code LED_BAT_FULL = GPIO(A, 6); +struct Gpio __code LED_PWR = GPIO(A, 7); +struct Gpio __code LID_SW_N = GPIO(D, 1); +struct Gpio __code PCH_DPWROK_EC = GPIO(A, 3); +struct Gpio __code PCH_PWROK_EC = GPIO(A, 4); +struct Gpio __code PM_CLKRUN_N = GPIO(H, 0); +struct Gpio __code PM_PWROK = GPIO(C, 6); +struct Gpio __code PWR_BTN_N = GPIO(D, 5); +struct Gpio __code PWR_SW_N = GPIO(D, 0); +struct Gpio __code SB_KBCRST_N = GPIO(E, 6); +struct Gpio __code SCI_N = GPIO(D, 4); +struct Gpio __code SLP_SUS_N = GPIO(I, 2); +struct Gpio __code SMI_N = GPIO(D, 3); +struct Gpio __code SUSB_N_PCH = GPIO(H, 6); +struct Gpio __code SUSC_N_PCH = GPIO(H, 1); +struct Gpio __code SUSWARN_N = GPIO(D, 7); +struct Gpio __code SUS_PWR_ACK = GPIO(J, 0); +struct Gpio __code SWI_N = GPIO(E, 0); +struct Gpio __code USB_PWR_EN_N = GPIO(F, 7); +struct Gpio __code VA_EC_EN = GPIO(E, 3); +struct Gpio __code VR_ON = GPIO(H, 4); +struct Gpio __code WLAN_EN = GPIO(H, 5); +struct Gpio __code WLAN_PWR_EN = GPIO(J, 4); + +void gpio_init() { + // Enable LPC reset on GPD2 + GCR = 0x04; + + // Set GPIO data + GPDRA = 0; + GPDRB = (1 << 0); + GPDRC = 0; + GPDRD = (1 << 5) | (1 << 4) | (1 << 3); + GPDRE = 0; + GPDRF = 0xC0; // (1 << 7) | (1 << 6) + GPDRG = 0; + GPDRH = 0; + GPDRI = 0; + GPDRJ = 0; + + // Set GPIO control + // EC_SSD_LED# + GPCRA0 = GPIO_IN; + // KBC_BEEP + GPCRA1 = GPIO_ALT; + // CPU_FAN + GPCRA2 = GPIO_ALT; + // PCH_DPWROK_EC + GPCRA3 = GPIO_IN; + // PCH_PWROK_EC + GPCRA4 = GPIO_OUT; + // LED_BAT_CHG + GPCRA5 = GPIO_OUT | GPIO_UP; + // LED_BAT_FULL + GPCRA6 = GPIO_OUT | GPIO_UP; + // LED_PWR + GPCRA7 = GPIO_OUT | GPIO_UP; + // NC + GPCRB0 = GPIO_OUT | GPIO_UP; + // H_PROCHOT_EC + GPCRB1 = GPIO_OUT | GPIO_UP; + // LAN_WAKEUP# + GPCRB2 = GPIO_IN | GPIO_UP; + // SMC_BAT + GPCRB3 = GPIO_ALT; + // SMD_BAT + GPCRB4 = GPIO_ALT; + // GA20 + GPCRB5 = GPIO_OUT | GPIO_UP; + // AC_IN# + GPCRB6 = GPIO_IN | GPIO_UP; + // FP_RST# + GPCRB7 = GPIO_IN; + // ALL_SYS_PWRGD + GPCRC0 = GPIO_IN; + // SMC_VGA_THERM + GPCRC1 = GPIO_IN | GPIO_UP; + // SMD_VGA_THERM + GPCRC2 = GPIO_IN | GPIO_UP; + // KSO16 (Darter) + GPCRC3 = GPIO_IN; + // CNVI_DET# + GPCRC4 = GPIO_OUT | GPIO_UP; + // KSO17 (Darter) + GPCRC5 = GPIO_IN; + // PM_PWROK + GPCRC6 = GPIO_OUT; + // LED_ACIN + GPCRC7 = GPIO_OUT | GPIO_UP; + // PWR_SW# + GPCRD0 = GPIO_IN | GPIO_UP; + // LID_SW# + GPCRD1 = GPIO_IN | GPIO_UP; + // BUF_PLT_RST# + GPCRD2 = GPIO_ALT; + // SMI# + GPCRD3 = GPIO_IN; + // SCI# + GPCRD4 = GPIO_IN; + // PWR_BTN# + GPCRD5 = GPIO_OUT | GPIO_UP; + // CPU_FANSEN + GPCRD6 = GPIO_IN; + // SUSWARN# + GPCRD7 = GPIO_IN; + // SWI# + GPCRE0 = GPIO_OUT | GPIO_UP; + // EC_EN + GPCRE1 = GPIO_OUT | GPIO_UP; + // PCH_SLP_WLAN#_R + GPCRE2 = GPIO_IN; + // VA_EC_EN + GPCRE3 = GPIO_OUT; + // DD_ON + GPCRE4 = GPIO_OUT | GPIO_DOWN; + // EC_RSMRST# + GPCRE5 = GPIO_OUT; + // SB_KBCRST# + GPCRE6 = GPIO_OUT | GPIO_UP; + // AC_PRESENT / PM_PWROK + GPCRE7 = GPIO_OUT | GPIO_UP; + // 80CLK + GPCRF0 = GPIO_IN; + // USB_CHARGE_EN + GPCRF1 = GPIO_OUT | GPIO_UP; + // 3IN1 + GPCRF2 = GPIO_IN | GPIO_UP; + // BT_EN + GPCRF3 = GPIO_OUT | GPIO_UP; + // TP_CLK + GPCRF4 = GPIO_ALT; + // TP_DATA + GPCRF5 = GPIO_ALT; + // H_PECI + GPCRF6 = GPIO_ALT; + // USB_PWR_EN# + GPCRF7 = GPIO_OUT; + // CCD_EN + GPCRG0 = GPIO_OUT | GPIO_UP; + // 3G_EN + GPCRG1 = GPIO_OUT | GPIO_UP; + // VDD3 + GPCRG2 = GPIO_OUT; + // HSPI_CE# + GPCRG3 = GPIO_ALT; + // HSPI_MSI + GPCRG4 = GPIO_ALT; + // HSPI_MSO + GPCRG5 = GPIO_ALT; + // AIRPLAN_LED# + GPCRG6 = GPIO_OUT | GPIO_UP; + // HCPI_SCLK + GPCRG7 = GPIO_ALT; + // EC_CLKRUN# + GPCRH0 = GPIO_ALT; + // SUSC#_PCH + GPCRH1 = GPIO_IN; + // BKL_EN + GPCRH2 = GPIO_OUT | GPIO_UP; + // NC + GPCRH3 = GPIO_OUT | GPIO_UP; + // VR_ON + GPCRH4 = GPIO_IN; + // WLAN_EN + GPCRH5 = GPIO_OUT | GPIO_UP; + // SUSB#_PCH + GPCRH6 = GPIO_IN; + // Unknown + GPCRH7 = GPIO_IN; + // BAT_DET + GPCRI0 = GPIO_ALT; + // BAT_VOLT + GPCRI1 = GPIO_ALT; + // SLP_SUS# + GPCRI2 = GPIO_IN; + // THERM_VOLT + GPCRI3 = GPIO_ALT; + // TOTAL_CUR + GPCRI4 = GPIO_ALT; + // AZ_RST#_EC + GPCRI5 = GPIO_IN; + // LIGHT_KB_DET# + GPCRI6 = GPIO_IN; + // MODEL_ID + GPCRI7 = GPIO_IN; + // SUS_PWR_ACK + GPCRJ0 = GPIO_IN | GPIO_DOWN; + // KBC_MUTE# + GPCRJ1 = GPIO_IN; + // ME_WE + GPCRJ2 = GPIO_OUT; + // SOC_TYPE + GPCRJ3 = GPIO_IN; + // WLAN_PWR_EN + GPCRJ4 = GPIO_OUT | GPIO_UP; + // KBLIGHT_ADJ + GPCRJ5 = GPIO_OUT; + // 3G_PWR_EN + GPCRJ6 = GPIO_OUT | GPIO_UP; + // NC + GPCRJ7 = GPIO_IN; + // LPC_AD0 + GPCRM0 = GPIO_ALT; + // LPC_AD1 + GPCRM1 = GPIO_ALT; + // LPC_AD2 + GPCRM2 = GPIO_ALT; + // LPC_AD3 + GPCRM3 = GPIO_ALT; + // PCLK_KBC + GPCRM4 = GPIO_ALT; + // LPC_FRAME# + GPCRM5 = GPIO_ALT; + // SERIRQ + GPCRM6 = GPIO_ALT; +} + +#if GPIO_DEBUG +void gpio_debug_bank( + char * bank, + uint8_t data, + uint8_t mirror, + uint8_t pot, + volatile uint8_t * control +) { + for(char i = 0; i < 8; i++) { + DEBUG( + "%s%d:\n\tdata %d\n\tmirror %d\n\tpot %d\n\tcontrol %02X\n", + bank, + i, + (data >> i) & 1, + (mirror >> i) & 1, + (pot >> i) & 1, + *(control + i) + ); + } +} + +void gpio_debug(void) { + #define bank(BANK) gpio_debug_bank(#BANK, GPDR ## BANK, GPDMR ## BANK, GPOT ## BANK, &GPCR ## BANK ## 0) + bank(A); + bank(B); + bank(C); + bank(D); + bank(E); + bank(F); + bank(G); + bank(H); + bank(I); + bank(J); + #undef bank +} +#endif diff --git a/src/board/system76/darp5/include/board/acpi.h b/src/board/system76/darp5/include/board/acpi.h new file mode 100644 index 0000000..4a6df82 --- /dev/null +++ b/src/board/system76/darp5/include/board/acpi.h @@ -0,0 +1,9 @@ +#ifndef _BOARD_ACPI_H +#define _BOARD_ACPI_H + +#include + +uint8_t acpi_read(uint8_t addr); +void acpi_write(uint8_t addr, uint8_t data); + +#endif // _BOARD_ACPI_H diff --git a/src/board/system76/darp5/include/board/battery.h b/src/board/system76/darp5/include/board/battery.h new file mode 100644 index 0000000..fcb9b2d --- /dev/null +++ b/src/board/system76/darp5/include/board/battery.h @@ -0,0 +1,20 @@ +#ifndef _BOARD_BATTERY_H +#define _BOARD_BATTERY_H + +#include + +extern uint16_t battery_temp; +extern uint16_t battery_voltage; +extern uint16_t battery_current; +extern uint16_t battery_charge; +extern uint16_t battery_remaining_capacity; +extern uint16_t battery_full_capacity; +extern uint16_t battery_design_capacity; +extern uint16_t battery_design_voltage; + +int battery_charger_disable(void); +int battery_charger_enable(void); +void battery_event(void); +void battery_debug(void); + +#endif // _BOARD_BATTERY_H diff --git a/src/board/system76/darp5/include/board/cpu.h b/src/board/system76/darp5/include/board/cpu.h new file mode 100644 index 0000000..1ed4f4d --- /dev/null +++ b/src/board/system76/darp5/include/board/cpu.h @@ -0,0 +1,6 @@ +#ifndef _BOARD_CPU_H +#define _BOARD_CPU_H + +#define F_CPU 9200000ULL + +#endif // _BOARD_CPU_H diff --git a/src/board/system76/darp5/include/board/gctrl.h b/src/board/system76/darp5/include/board/gctrl.h new file mode 100644 index 0000000..80eae12 --- /dev/null +++ b/src/board/system76/darp5/include/board/gctrl.h @@ -0,0 +1,8 @@ +#ifndef _BOARD_GCTRL_H +#define _BOARD_GCTRL_H + +#include + +void gctrl_init(void); + +#endif // _BOARD_GCTRL_H diff --git a/src/board/system76/darp5/include/board/gpio.h b/src/board/system76/darp5/include/board/gpio.h new file mode 100644 index 0000000..bb2bc9a --- /dev/null +++ b/src/board/system76/darp5/include/board/gpio.h @@ -0,0 +1,51 @@ +#ifndef _BOARD_GPIO_H +#define _BOARD_GPIO_H + +#include + +#define GPIO_ALT 0x00 +#define GPIO_IN 0x80 +#define GPIO_OUT 0x40 +#define GPIO_UP 0x04 +#define GPIO_DOWN 0x02 + +void gpio_init(void); +void gpio_debug(void); + +extern struct Gpio __code ACIN_N; +extern struct Gpio __code AC_PRESENT; +extern struct Gpio __code ALL_SYS_PWRGD; +extern struct Gpio __code BKL_EN; +extern struct Gpio __code BT_EN; +extern struct Gpio __code BUF_PLT_RST_N; +extern struct Gpio __code CCD_EN; +extern struct Gpio __code DD_ON; +extern struct Gpio __code EC_EN; +extern struct Gpio __code EC_RSMRST_N; +extern struct Gpio __code LED_ACIN; +extern struct Gpio __code LED_BAT_CHG; +extern struct Gpio __code LED_BAT_FULL; +extern struct Gpio __code LED_PWR; +extern struct Gpio __code LID_SW_N; +extern struct Gpio __code PCH_DPWROK_EC; +extern struct Gpio __code PCH_PWROK_EC; +extern struct Gpio __code PM_CLKRUN_N; +extern struct Gpio __code PM_PWROK; +extern struct Gpio __code PWR_BTN_N; +extern struct Gpio __code PWR_SW_N; +extern struct Gpio __code SB_KBCRST_N; +extern struct Gpio __code SCI_N; +extern struct Gpio __code SLP_SUS_N; +extern struct Gpio __code SMI_N; +extern struct Gpio __code SUSB_N_PCH; +extern struct Gpio __code SUSC_N_PCH; +extern struct Gpio __code SUSWARN_N; +extern struct Gpio __code SUS_PWR_ACK; +extern struct Gpio __code SWI_N; +extern struct Gpio __code USB_PWR_EN_N; +extern struct Gpio __code VA_EC_EN; +extern struct Gpio __code VR_ON; +extern struct Gpio __code WLAN_EN; +extern struct Gpio __code WLAN_PWR_EN; + +#endif // _BOARD_GPIO_H diff --git a/src/board/system76/darp5/include/board/kbc.h b/src/board/system76/darp5/include/board/kbc.h new file mode 100644 index 0000000..17765b8 --- /dev/null +++ b/src/board/system76/darp5/include/board/kbc.h @@ -0,0 +1,15 @@ +#ifndef _BOARD_KBC_H +#define _BOARD_KBC_H + +#include + +#include + +extern bool kbc_first; +extern bool kbc_second; + +void kbc_init(void); +bool kbc_scancode(struct Kbc * kbc, uint16_t key, bool pressed); +void kbc_event(struct Kbc * kbc); + +#endif // _BOARD_KBC_H diff --git a/src/board/system76/darp5/include/board/kbscan.h b/src/board/system76/darp5/include/board/kbscan.h new file mode 100644 index 0000000..f9327ad --- /dev/null +++ b/src/board/system76/darp5/include/board/kbscan.h @@ -0,0 +1,13 @@ +#ifndef _BOARD_KBSCAN_H +#define _BOARD_KBSCAN_H + +#include + +#include + +extern bool kbscan_enabled; + +void kbscan_init(void); +void kbscan_event(void); + +#endif // _BOARD_KBSCAN_H diff --git a/src/board/system76/darp5/include/board/keymap.h b/src/board/system76/darp5/include/board/keymap.h new file mode 100644 index 0000000..eacd404 --- /dev/null +++ b/src/board/system76/darp5/include/board/keymap.h @@ -0,0 +1,50 @@ +#ifndef _BOARD_KEYMAP_H +#define _BOARD_KEYMAP_H + +#include + +#define ___ 0 + +// Conversion of physical layout to keyboard matrix +#define LAYOUT( \ + K00, K01, K02, K03, K04, K05, K06, K07, K08, K09, K0A, K0B, K0C, K0D, K0E, K0F, K0G, K0H, K0I, K0J, \ + K10, K11, K12, K13, K14, K15, K16, K17, K18, K19, K1A, K1B, K1C, K1D, K1E, K1F, K1G, K1H, \ + K20, K21, K22, K23, K24, K25, K26, K27, K28, K29, K2A, K2B, K2C, K2D, K2E, K2F, K2G, K2H, \ + K30, K31, K32, K33, K34, K35, K36, K37, K38, K39, K3A, K3B, K3C, K3D, K3E, K3F, \ + K40, K41, K42, K43, K44, K45, K46, K47, K48, K49, K4A, K4B, K4C, K4D, K4E, K4F, K4G, \ + K50, K51, K52, K53, K54, K55, K56, K57, K58, K59, K5A, K5B, K5C \ +) { \ + { ___, ___, ___, ___, ___, ___, K50, K57 }, \ + { ___, ___, ___, ___, ___, ___, K53, K55 }, \ + { ___, ___, ___, ___, ___, ___, K40, K4B }, \ + { K52, ___, ___, ___, ___, ___, ___, K54 }, \ + { K41, K1H, ___, K2F, K4E, ___, ___, ___ }, \ + { K0I, K22, ___, ___, K1E, K3D, K3F, K30 }, \ + { K0J, K1B, K23, K39, ___, ___, K47, ___ }, \ + { K38, K26, K1A, K24, ___, K3A, K20, K00 }, \ + { K5B, K37, K2C, K19, K25, K07, K18, K01 }, \ + { K5C, K34, K36, K02, ___, K4G, K3B, K45 }, \ + { K1F, K48, ___, K2B, K32, K08, K06, K12 }, \ + { K1G, K49, K17, K33, ___, ___, K11, K2A }, \ + { K2D, ___, K31, K4A, ___, K03, K28, K16 }, \ + { ___, K44, K0D, K09, K46, K29, K15, K05 }, \ + { K21, K0A, K2E, K04, K3E, K0E, K0F, K14 }, \ + { K56, K42, K3C, K2H, K27, K2G, K13, K1D }, \ + { K0H, K0G, K43, K4C, K59, K10, K0B, K0C }, \ + { K35, K1C, K4F, K51, K4D, K58, K5A, ___ } \ +} + +// Keymap output pins +#define KM_OUT 18 +// Keymap input pins +#define KM_IN 8 +// Keymap layers (normal, Fn) +#define KM_LAY 2 + +// Keymap +extern uint16_t __code KEYMAP[KM_LAY][KM_OUT][KM_IN]; + +// Get a keycode from the keymap +uint16_t keymap(int output, int input, int layer); + +#endif // _BOARD_KEYMAP_H diff --git a/src/board/system76/darp5/include/board/peci.h b/src/board/system76/darp5/include/board/peci.h new file mode 100644 index 0000000..c447300 --- /dev/null +++ b/src/board/system76/darp5/include/board/peci.h @@ -0,0 +1,15 @@ +#ifndef _BOARD_PECI_H +#define _BOARD_PECI_H + +#include + +extern int16_t peci_offset; +extern int16_t peci_temp; +extern uint8_t peci_duty; +extern uint8_t peci_tcontrol; +extern uint8_t peci_tjmax; + +void peci_init(void); +void peci_event(void); + +#endif // _BOARD_PECI_H diff --git a/src/board/system76/darp5/include/board/pmc.h b/src/board/system76/darp5/include/board/pmc.h new file mode 100644 index 0000000..65ea613 --- /dev/null +++ b/src/board/system76/darp5/include/board/pmc.h @@ -0,0 +1,10 @@ +#ifndef _BOARD_PMC_H +#define _BOARD_PMC_H + +#include + +void pmc_init(void); +bool pmc_sci(struct Pmc * pmc, uint8_t sci); +void pmc_event(struct Pmc * pmc); + +#endif // _BOARD_PMC_H diff --git a/src/board/system76/darp5/include/board/pnp.h b/src/board/system76/darp5/include/board/pnp.h new file mode 100644 index 0000000..53dbb68 --- /dev/null +++ b/src/board/system76/darp5/include/board/pnp.h @@ -0,0 +1,6 @@ +#ifndef _BOARD_PNP_H +#define _BOARD_PNP_H + +void pnp_enable(void); + +#endif // _BOARD_PNP_H diff --git a/src/board/system76/darp5/include/board/power.h b/src/board/system76/darp5/include/board/power.h new file mode 100644 index 0000000..504ed64 --- /dev/null +++ b/src/board/system76/darp5/include/board/power.h @@ -0,0 +1,6 @@ +#ifndef _BOARD_POWER_H +#define _BOARD_POWER_H + +void power_event(void); + +#endif // _BOARD_POWER_H diff --git a/src/board/system76/darp5/include/board/ps2.h b/src/board/system76/darp5/include/board/ps2.h new file mode 100644 index 0000000..34ad6ac --- /dev/null +++ b/src/board/system76/darp5/include/board/ps2.h @@ -0,0 +1,8 @@ +#ifndef _BOARD_PS2_H +#define _BOARD_PS2_H + +#include + +void ps2_init(void); + +#endif // _BOARD_PS2_H diff --git a/src/board/system76/darp5/include/board/pwm.h b/src/board/system76/darp5/include/board/pwm.h new file mode 100644 index 0000000..256fde8 --- /dev/null +++ b/src/board/system76/darp5/include/board/pwm.h @@ -0,0 +1,8 @@ +#ifndef _BOARD_PWM_H +#define _BOARD_PWM_H + +#include + +void pwm_init(void); + +#endif // _BOARD_PWM_H diff --git a/src/board/system76/darp5/include/board/scratch.h b/src/board/system76/darp5/include/board/scratch.h new file mode 100644 index 0000000..797b92e --- /dev/null +++ b/src/board/system76/darp5/include/board/scratch.h @@ -0,0 +1,6 @@ +#ifndef _BOARD_SCRATCH_H +#define _BOARD_SCRATCH_H + +void scratch_trampoline(void); + +#endif // _BOARD_SCRATCH_H diff --git a/src/board/system76/darp5/include/board/smbus.h b/src/board/system76/darp5/include/board/smbus.h new file mode 100644 index 0000000..437844a --- /dev/null +++ b/src/board/system76/darp5/include/board/smbus.h @@ -0,0 +1,8 @@ +#ifndef _BOARD_SMBUS_H +#define _BOARD_SMBUS_H + +#include + +void smbus_init(void); + +#endif // _BOARD_SMBUS_H diff --git a/src/board/system76/darp5/kbc.c b/src/board/system76/darp5/kbc.c new file mode 100644 index 0000000..a76b80b --- /dev/null +++ b/src/board/system76/darp5/kbc.c @@ -0,0 +1,253 @@ +#include +#include +#include +#include +#include + +void kbc_init(void) { + // Disable interrupts + *(KBC.irq) = 0; + *(KBC.control) = 0; +} + +#define KBC_TIMEOUT 10000 + +// System flag +static bool kbc_system = false; +// Enable first port - TODO +bool kbc_first = false; +// Enable second port - TODO +bool kbc_second = false; +// Translate from scancode set 2 to scancode set 1 +// for basically no good reason +static bool kbc_translate = true; + +bool kbc_scancode(struct Kbc * kbc, uint16_t key, bool pressed) { + if (!kbc_first) return true; + if (kbc_translate) { + key = keymap_translate(key); + } + if (!key) return true; + switch (key & 0xFF00) { + case K_E0: + TRACE(" E0\n"); + if (!kbc_keyboard(kbc, 0xE0, KBC_TIMEOUT)) return false; + key &= 0xFF; + // Fall through + case 0x00: + if (!pressed) { + if (kbc_translate) { + key |= 0x80; + } else { + TRACE(" F0\n"); + if (!kbc_keyboard(kbc, 0xF0, KBC_TIMEOUT)) return false; + } + } + TRACE(" %02X\n", key); + if (!kbc_keyboard(kbc, (uint8_t)key, KBC_TIMEOUT)) return false; + break; + } + return true; +} + +enum KbcState { + KBC_STATE_NORMAL, + KBC_STATE_WRITE_CONFIG, + KBC_STATE_SET_LEDS, + KBC_STATE_SCANCODE, + KBC_STATE_WRITE_PORT, + KBC_STATE_FIRST_PORT_OUTPUT, + KBC_STATE_SECOND_PORT_OUTPUT, + KBC_STATE_SECOND_PORT_INPUT, +}; + +void kbc_event(struct Kbc * kbc) { + // TODO: state per KBC (we only have one KBC so low priority) + static enum KbcState state = KBC_STATE_NORMAL; + + uint8_t sts = kbc_status(kbc); + if (sts & KBC_STS_IBF) { + uint8_t data = kbc_read(kbc); + if (sts & KBC_STS_CMD) { + TRACE("kbc cmd: %02X\n", data); + + state = KBC_STATE_NORMAL; + switch (data) { + case 0x20: + TRACE(" read configuration byte\n"); + uint8_t config = *kbc->control & 0x03; + if (kbc_system) { + config |= (1 << 2); + } + if (!kbc_first) { + config |= (1 << 4); + } + if (!kbc_second) { + config |= (1 << 5); + } + if (kbc_translate) { + config |= (1 << 6); + } + kbc_keyboard(kbc, config, KBC_TIMEOUT); + break; + case 0x60: + TRACE(" write configuration byte\n"); + state = KBC_STATE_WRITE_CONFIG; + break; + case 0xA7: + TRACE(" disable second port\n"); + kbc_second = false; + break; + case 0xA8: + TRACE(" enable second port\n"); + kbc_second = true; + break; + case 0xA9: + TRACE(" test second port\n"); + // TODO: communicate with touchpad? + kbc_keyboard(kbc, 0x00, KBC_TIMEOUT); + break; + case 0xAA: + TRACE(" test controller\n"); + // Why not pass the test? + kbc_keyboard(kbc, 0x55, KBC_TIMEOUT); + break; + case 0xAB: + TRACE(" test first port\n"); + // We _ARE_ the keyboard, so everything is good. + kbc_keyboard(kbc, 0x00, KBC_TIMEOUT); + break; + case 0xAD: + TRACE(" disable first port\n"); + kbc_first = false; + break; + case 0xAE: + TRACE(" enable first port\n"); + kbc_first = true; + break; + case 0xD1: + TRACE(" write port byte\n"); + state = KBC_STATE_WRITE_PORT; + break; + case 0xD2: + TRACE(" write first port output\n"); + state = KBC_STATE_FIRST_PORT_OUTPUT; + break; + case 0xD3: + TRACE(" write second port output\n"); + state = KBC_STATE_SECOND_PORT_OUTPUT; + break; + case 0xD4: + TRACE(" write second port input\n"); + state = KBC_STATE_SECOND_PORT_INPUT; + break; + } + } else { + TRACE("kbc data: %02X\n", data); + + switch (state) { + case KBC_STATE_NORMAL: + TRACE(" keyboard command\n"); + switch (data) { + case 0xED: + TRACE(" set leds\n"); + state = KBC_STATE_SET_LEDS; + kbc_keyboard(kbc, 0xFA, KBC_TIMEOUT); + break; + case 0xEE: + TRACE(" echo\n"); + // Hey, this is easy. I like easy commands + kbc_keyboard(kbc, 0xEE, KBC_TIMEOUT); + break; + case 0xF0: + TRACE(" get/set scancode\n"); + state = KBC_STATE_SCANCODE; + kbc_keyboard(kbc, 0xFA, KBC_TIMEOUT); + break; + case 0xF2: + TRACE(" identify keyboard\n"); + if (kbc_keyboard(kbc, 0xFA, KBC_TIMEOUT)) { + if (kbc_keyboard(kbc, 0xAB, KBC_TIMEOUT)) { + kbc_keyboard(kbc, 0x83, KBC_TIMEOUT); + } + } + break; + case 0xF4: + TRACE(" enable scanning\n"); + kbscan_enabled = true; + kbc_keyboard(kbc, 0xFA, KBC_TIMEOUT); + break; + case 0xF5: + TRACE(" disable scanning\n"); + kbscan_enabled = false; + kbc_keyboard(kbc, 0xFA, KBC_TIMEOUT); + break; + case 0xFF: + TRACE(" self test\n"); + if (kbc_keyboard(kbc, 0xFA, KBC_TIMEOUT)) { + // Yep, everything is still good, I promise + kbc_keyboard(kbc, 0xAA, KBC_TIMEOUT); + } + break; + } + break; + case KBC_STATE_WRITE_CONFIG: + TRACE(" write configuration byte\n"); + state = KBC_STATE_NORMAL; + uint8_t control = *kbc->control; + if (data & 1) { + control |= 1; + } else { + control &= ~1; + } + if (data & (1 << 1)) { + control |= (1 << 1); + } else { + control &= ~(1 << 1); + } + kbc_system = (bool)(data & (1 << 2)); + kbc_first = (bool)(!(data & (1 << 4))); + kbc_second = (bool)(!(data & (1 << 5))); + kbc_translate = (bool)(data & (1 << 6)); + *kbc->control = control; + break; + case KBC_STATE_SET_LEDS: + TRACE(" set leds\n"); + state = KBC_STATE_NORMAL; + kbc_keyboard(kbc, 0xFA, KBC_TIMEOUT); + break; + case KBC_STATE_SCANCODE: + TRACE(" get/set scancode\n"); + state = KBC_STATE_NORMAL; + #if LEVEL >= LEVEL_TRACE + switch (data) { + case 0x02: + TRACE(" set scancode set 2\n"); + break; + } + #endif + kbc_keyboard(kbc, 0xFA, KBC_TIMEOUT); + break; + case KBC_STATE_WRITE_PORT: + TRACE(" write port byte\n"); + state = KBC_STATE_NORMAL; + break; + case KBC_STATE_FIRST_PORT_OUTPUT: + TRACE(" write first port output\n"); + state = KBC_STATE_NORMAL; + kbc_keyboard(kbc, data, KBC_TIMEOUT); + break; + case KBC_STATE_SECOND_PORT_OUTPUT: + TRACE(" write second port output\n"); + state = KBC_STATE_NORMAL; + kbc_mouse(kbc, data, KBC_TIMEOUT); + break; + case KBC_STATE_SECOND_PORT_INPUT: + TRACE(" write second port input\n"); + state = KBC_STATE_NORMAL; + ps2_write(&PS2_3, &data, 1); + break; + } + } + } +} diff --git a/src/board/system76/darp5/kbscan.c b/src/board/system76/darp5/kbscan.c new file mode 100644 index 0000000..12af49e --- /dev/null +++ b/src/board/system76/darp5/kbscan.c @@ -0,0 +1,172 @@ +#include + +#include +#include +#include +#include +#include +#include +#include + +bool kbscan_enabled = false; + +void kbscan_init(void) { + KSOCTRL = 0x05; + KSICTRLR = 0x04; + + // Set all outputs to GPIO mode, low, and inputs + KSOL = 0; + KSOLGCTRL = 0xFF; + KSOLGOEN = 0; + KSOH1 = 0; + KSOHGCTRL = 0xFF; + KSOHGOEN = 0; + KSOH2 = 0; + + // Make sure timer 2 is stopped + T2CON = 0; +} + +void kbscan_event(void) { + static uint8_t kbscan_layer = 0; + uint8_t layer = kbscan_layer; + static uint8_t kbscan_last[KM_OUT] = { 0 }; + + // If timer 2 is finished + if (TF2) { + // Stop timer 2 running + TR2 = 0; + // Clear timer 2 finished flag + TF2 = 0; + } + + int i; + for (i = 0; i < KM_OUT; i++) { + // Set current line as output + if (i < 8) { + KSOLGOEN = 0; + KSOLGOEN = 1 << i; + GPCRC3 = GPIO_IN; + GPCRC5 = GPIO_IN; + } else if (i < 16) { + KSOLGOEN = 0; + KSOHGOEN = 1 << (i - 8); + GPCRC3 = GPIO_IN; + GPCRC5 = GPIO_IN; + } else if (i == 16) { + KSOLGOEN = 0; + KSOHGOEN = 0; + GPCRC3 = GPIO_OUT; + GPCRC5 = GPIO_IN; + } else if (i == 17) { + KSOLGOEN = 0; + KSOHGOEN = 0; + GPCRC3 = GPIO_IN; + GPCRC5 = GPIO_OUT; + } + GPDRC &= ~((1 << 3) | (1 << 5)); + + // TODO: figure out optimal delay + delay_ticks(10); + + uint8_t new = ~KSI; + uint8_t last = kbscan_last[i]; + if (new != last) { + int j; + for (j = 0; j < KM_IN; j++) { + bool new_b = new & (1 << j); + bool last_b = last & (1 << j); + if (new_b != last_b) { + // If timer 2 is running + if (TR2) { + // Debounce releases + if (!new_b) { + // Restore bit, so that this release can be handled later + new |= (1 << j); + // Skip processing of release + continue; + } + } else { + // Begin debouncing on press + if (new_b) { + // Run timer 2 for 20 ms + // 65536-(20000 * 69 + 89)/90 = 0xC419 + TH2 = 0xC4; + TL2 = 0x19; + TR2 = 1; + } + } + + uint16_t key = keymap(i, j, kbscan_layer); + DEBUG("KB %d, %d, %d = 0x%04X, %d\n", i, j, kbscan_layer, key, new_b); + if (!key) { + WARN("KB %d, %d, %d missing\n", i, j, kbscan_layer); + } + switch (key & KT_MASK) { + case (KT_FN): + if (new_b) layer = 1; + else layer = 0; + break; + case (KT_SCI): + if (new_b) { + uint8_t sci = (uint8_t)(key & 0xFF); + if (!pmc_sci(&PMC_1, sci)) { + // In the case of ignored SCI, reset bit + new &= ~(1 << j); + } + } + break; + case (KT_NORMAL): + if (kbscan_enabled && key) { + kbc_scancode(&KBC, key, new_b); + } + break; + } + } + } + + kbscan_last[i] = new; + } + } + + if (layer != kbscan_layer) { + //TODO: unpress keys before going to scratch rom + + // Unpress all currently pressed keys + for (i = 0; i < KM_OUT; i++) { + uint8_t new = 0; + uint8_t last = kbscan_last[i]; + if (last) { + int j; + for (j = 0; j < KM_IN; j++) { + bool new_b = new & (1 << j); + bool last_b = last & (1 << j); + if (new_b != last_b) { + uint16_t key = keymap(i, j, kbscan_layer); + DEBUG("KB %d, %d, %d = 0x%04X, %d\n", i, j, kbscan_layer, key, new_b); + switch (key & KT_MASK) { + case (KT_NORMAL): + if (kbscan_enabled && key) { + kbc_scancode(&KBC, key, new_b); + } + break; + } + } + } + } + + kbscan_last[i] = new; + } + + kbscan_layer = layer; + } + + // Reset all lines to inputs + KSOLGOEN = 0; + KSOHGOEN = 0; + GPCRC3 = GPIO_IN; + GPCRC5 = GPIO_IN; + + // TODO: figure out optimal delay + delay_ticks(10); +} diff --git a/src/board/system76/darp5/keymap.c b/src/board/system76/darp5/keymap.c new file mode 100644 index 0000000..74445e5 --- /dev/null +++ b/src/board/system76/darp5/keymap.c @@ -0,0 +1,11 @@ +#include +#include + +uint16_t keymap(int output, int input, int layer) { + if (output < KM_OUT && input < KM_IN && layer < KM_LAY) { + return KEYMAP[layer][output][input]; + } else { + return 0; + } +} + diff --git a/src/board/system76/darp5/keymap/default.c b/src/board/system76/darp5/keymap/default.c new file mode 100644 index 0000000..a41bc46 --- /dev/null +++ b/src/board/system76/darp5/keymap/default.c @@ -0,0 +1,22 @@ +// Default layout + +#include + +uint16_t __code KEYMAP[KM_LAY][KM_OUT][KM_IN] = { +LAYOUT( + K_ESC, K_F1, K_F2, K_F3, K_F4, K_F5, K_F6, K_F7, K_F8, K_F9, K_F10, K_F11, K_F12, 0 /*prtsc*/, K_INSERT, K_DEL, K_HOME, K_END, K_PGUP, K_PGDN, + K_TICK, K_1, K_2, K_3, K_4, K_5, K_6, K_7, K_8, K_9, K_0, K_MINUS, K_EQUALS, K_BKSP, K_NUM_LOCK, K_NUM_SLASH, K_NUM_ASTERISK, K_NUM_MINUS, + K_TAB, K_Q, K_W, K_E, K_R, K_T, K_Y, K_U, K_I, K_O, K_P, K_BRACE_OPEN, K_BRACE_CLOSE, K_BACKSLASH, K_NUM_7, K_NUM_8, K_NUM_9, K_NUM_PLUS, + K_CAPS, K_A, K_S, K_D, K_F, K_G, K_H, K_J, K_K, K_L, K_SEMICOLON, K_QUOTE, K_ENTER, K_NUM_4, K_NUM_5, K_NUM_6, + K_LEFT_SHIFT, K_Z, K_X, K_C, K_V, K_B, K_N, K_M, K_COMMA, K_PERIOD, K_SLASH, K_RIGHT_SHIFT, K_UP, K_NUM_1, K_NUM_2, K_NUM_3, K_NUM_ENTER, + K_LEFT_CTRL, KT_FN, K_LEFT_SUPER, K_LEFT_ALT, K_SPACE, K_RIGHT_ALT, K_APP, K_RIGHT_CTRL, K_LEFT, K_DOWN, K_RIGHT, K_NUM_0, K_NUM_PERIOD +), +LAYOUT( + K_ESC, K_TOUCHPAD, K_F2, K_MUTE, K_F4, K_VOLUME_DOWN, K_VOLUME_UP, K_F7, KT_SCI | SCI_BRIGHTNESS_DOWN, KT_SCI | SCI_BRIGHTNESS_UP, K_F10, KT_SCI | SCI_AIRPLANE_MODE, KT_SCI | SCI_SUSPEND, 0 /*prtsc*/, K_INSERT, K_DEL, K_HOME, K_END, K_PGUP, K_PGDN, + K_PLAY_PAUSE, K_1, K_2, K_3, K_4, K_5, K_6, K_7, K_8, K_9, K_0, K_MINUS, K_EQUALS, K_BKSP, K_NUM_LOCK, K_NUM_SLASH, K_NUM_ASTERISK, K_NUM_MINUS, + K_TAB, K_Q, K_W, K_E, K_R, K_T, K_Y, K_U, K_I, K_O, K_P, K_BRACE_OPEN, K_BRACE_CLOSE, K_BACKSLASH, K_NUM_7, K_NUM_8, K_NUM_9, K_NUM_PLUS, + K_CAPS, K_A, K_S, K_D, K_F, K_G, K_H, K_J, K_K, K_L, K_SEMICOLON, K_QUOTE, K_ENTER, K_NUM_4, K_NUM_5, K_NUM_6, + K_LEFT_SHIFT, K_Z, K_X, K_C, K_V, K_B, K_N, K_M, K_COMMA, K_PERIOD, K_SLASH, K_RIGHT_SHIFT, K_UP, K_NUM_1, K_NUM_2, K_NUM_3, K_NUM_ENTER, + K_LEFT_CTRL, KT_FN, K_LEFT_SUPER, K_LEFT_ALT, K_SPACE, K_RIGHT_ALT, K_APP, K_RIGHT_CTRL, K_LEFT, K_DOWN, K_RIGHT, K_NUM_0, K_NUM_PERIOD +) +}; diff --git a/src/board/system76/darp5/main.c b/src/board/system76/darp5/main.c new file mode 100644 index 0000000..3bc8107 --- /dev/null +++ b/src/board/system76/darp5/main.c @@ -0,0 +1,173 @@ +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +uint8_t main_cycle = 0; + +void external_0(void) __interrupt(0) { + TRACE("external_0\n"); +} + +void timer_0(void) __interrupt(1) { + TRACE("timer_0\n"); +} + +void external_1(void) __interrupt(2) { + TRACE("external_1\n"); +} + +void timer_1(void) __interrupt(3) { + TRACE("timer_1\n"); +} + +void serial(void) __interrupt(4) { + TRACE("serial\n"); +} + +void timer_2(void) __interrupt(5) { + TRACE("timer_2\n"); +} + +void init(void) { + gpio_init(); + gctrl_init(); + kbc_init(); + pmc_init(); + kbscan_init(); + pwm_init(); + smbus_init(); + peci_init(); + + //TODO: INTC +} + +void touchpad_event(struct Ps2 * ps2) { + if (kbc_second) { + *(ps2->control) = 0x07; + } else { + ps2_reset(ps2); + } + + uint8_t status = *(ps2->status); + *(ps2->status) = status; + if (status & (1 << 3)) { + uint8_t data = *(ps2->data); + TRACE("touchpad: %02X\n", data); + kbc_mouse(&KBC, data, 1000); + } +} + +bool lid_wake = false; +void lid_event(void) { + static bool send_sci = true; + static bool last = true; + + // Check if the adapter line goes low + bool new = gpio_get(&LID_SW_N); + // If there has been a change, print + if (new != last) { + DEBUG("Lid "); + if (new) { + DEBUG("open\n"); + + if (lid_wake) { + gpio_set(&SWI_N, false); + + //TODO: find correct delay + delay_ticks(10); + + gpio_set(&SWI_N, true); + + lid_wake = false; + } + } else { + DEBUG("closed\n"); + } + + // Send SCI + send_sci = true; + } + + if (send_sci) { + // Send SCI 0x1B for lid event + if (pmc_sci(&PMC_1, 0x1B)) { + send_sci = false; + } + } + + last = new; +} + +struct Gpio __code LED_SSD_N = GPIO(G, 6); +struct Gpio __code LED_AIRPLANE_N = GPIO(G, 6); + +void main(void) { + init(); + + INFO("\n"); + + // Set the battery full LED (to know our firmware is loading) + gpio_set(&LED_BAT_CHG, true); + +#if GPIO_DEBUG + gpio_debug(); +#endif + + // Allow CPU to boot + gpio_set(&SB_KBCRST_N, true); + // Allow backlight to be turned on + gpio_set(&BKL_EN, true); + // Enable camera + gpio_set(&CCD_EN, true); + // Enable wireless + gpio_set(&BT_EN, true); + gpio_set(&WLAN_EN, true); + gpio_set(&WLAN_PWR_EN, true); + // Enable right USB port + gpio_set(&USB_PWR_EN_N, false); + // Assert SMI#, SCI#, and SWI# + gpio_set(&SCI_N, true); + gpio_set(&SMI_N, true); + gpio_set(&SWI_N, true); + + // Set the battery full LED (to know our firmware is loaded) + gpio_set(&LED_BAT_FULL, true); + INFO("Hello from System76 EC for %s!\n", xstr(__BOARD__)); + + for(main_cycle = 0; ; main_cycle++) { + // Handle power states + power_event(); + // Scans keyboard and sends keyboard packets + kbscan_event(); + // Passes through touchpad packets + touchpad_event(&PS2_3); + // Handle lid close/open + lid_event(); + // Checks for keyboard/mouse packets from host + kbc_event(&KBC); + // Only run the following once out of every 256 loops + if (main_cycle == 0) { + // Updates fan status and temps + peci_event(); + // Updates battery status + battery_event(); + } + // Handles ACPI communication + pmc_event(&PMC_1); + } +} diff --git a/src/board/system76/darp5/peci.c b/src/board/system76/darp5/peci.c new file mode 100644 index 0000000..9289fa3 --- /dev/null +++ b/src/board/system76/darp5/peci.c @@ -0,0 +1,151 @@ +#include + +#include +#include +#include +#include + +// Tjunction = 100C for i7-8565U (and probably the same for all WHL-U) +#define T_JUNCTION 100 + +int16_t peci_offset = 0; +int16_t peci_temp = 0; +uint8_t peci_duty = 0; +uint8_t peci_tcontrol = 0; +uint8_t peci_tjmax = T_JUNCTION; +static bool peci_config_loaded = false; + +#define PECI_TEMP(X) (((int16_t)(X)) << 6) + +void peci_init(void) { + // Allow PECI pin to be used + GCR2 |= (1 << 4); + + // Set frequency to 1MHz + HOCTL2R = 0x01; + // Set VTT to 1V + PADCTLR = 0x02; +} + +// Read tjmax using index 16 of RdPkgConfig +static void peci_config(void) { + // Wait for completion + while (HOSTAR & 1) {} + // Clear status + HOSTAR = HOSTAR; + + // Enable PECI, clearing data fifo's + HOCTLR = (1 << 5) | (1 << 3); + // Set address to default + HOTRADDR = 0x30; + // Set write length + HOWRLR = 5; + // Set read length + HORDLR = 5; + // Set command + HOCMDR = 0xA1; + // Set Host ID ? + HOWRDR = 0x00; + // Set index + HOWRDR = 16; + // Set parameter + HOWRDR = 0; + HOWRDR = 0; + // Start transaction + HOCTLR |= 1; + + // Wait for completion + while (HOSTAR & 1) {} + + if (HOSTAR & (1 << 1)) { + // Use result if finished successfully + + //TODO: check completion code + uint8_t data = HOWRDR; + + // Throw away reserved byte + data = HOWRDR; + // Tead tcontrol for now + peci_tcontrol = HOWRDR; + // Read tjmax + peci_tjmax = HOWRDR; + // Throw away reserved byte + data = HOWRDR; + + peci_config_loaded = true; + } +} + +// PECI information can be found here: https://www.intel.com/content/dam/www/public/us/en/documents/design-guides/core-i7-lga-2011-guide.pdf +void peci_event(void) { + // Wait for completion + while (HOSTAR & 1) {} + // Clear status + HOSTAR = HOSTAR; + + // Enable PECI, clearing data fifo's + HOCTLR = (1 << 5) | (1 << 3); + // Set address to default + HOTRADDR = 0x30; + // Set write length + HOWRLR = 1; + // Set read length + HORDLR = 2; + // Set command + HOCMDR = 1; + // Start transaction + HOCTLR |= 1; + + // Wait for completion + while (HOSTAR & 1) {} + + if (HOSTAR & (1 << 1)) { + // Use result if finished successfully + uint8_t low = HORDDR; + uint8_t high = HORDDR; + peci_offset = ((int16_t)high << 8) | (int16_t)low; + + // TODO: Update max value if possible + // if (!peci_config_loaded) { + // peci_config(); + // } + + // TODO: tjmax + peci_temp = PECI_TEMP(T_JUNCTION) + peci_offset; + + // Set fan based on temp, adapted from + // https://github.com/pop-os/system76-power/blob/master/src/fan.rs#L218 + if (peci_temp >= PECI_TEMP(90)) { + // 90C = 100% + peci_duty = 255; + } else if (peci_temp >= PECI_TEMP(80)) { + // 80C = 50% + peci_duty = 128; + } else if (peci_temp >= PECI_TEMP(75)) { + // 75C = 45% + peci_duty = 115; + } else if (peci_temp >= PECI_TEMP(65)) { + // 65C = 40% + peci_duty = 102; + } else if (peci_temp >= PECI_TEMP(55)) { + // 55C = 35% + peci_duty = 90; + } else if (peci_temp >= PECI_TEMP(45)) { + // 45C = 30% + peci_duty = 77; + } else { + // < 45C = 0% + peci_duty = 0; + } + } else { + // Default to 50% if there is an error + peci_offset = 0; + peci_temp = 0; + peci_duty = 128; + } + + if (peci_duty != DCR2) { + DCR2 = peci_duty; + DEBUG("PECI offset=%d, temp=%d = %d\n", peci_offset, peci_temp, peci_duty); + } +} diff --git a/src/board/system76/darp5/pmc.c b/src/board/system76/darp5/pmc.c new file mode 100644 index 0000000..ee921d5 --- /dev/null +++ b/src/board/system76/darp5/pmc.c @@ -0,0 +1,108 @@ +#include +#include +#include +#include +#include + +void pmc_init(void) { + *(PMC_1.control) = 0x41; + *(PMC_2.control) = 0x41; +} + +#define PMC_TIMEOUT 10000 + +enum PmcState { + PMC_STATE_DEFAULT, + PMC_STATE_ACPI_READ, + PMC_STATE_ACPI_WRITE, + PMC_STATE_ACPI_WRITE_ADDR, +}; + +static uint8_t pmc_sci_queue = 0; + +bool pmc_sci(struct Pmc * pmc, uint8_t sci) { + bool update = pmc_sci_queue == 0; + // Set SCI queue if possible + if (update) pmc_sci_queue = sci; + // Set SCI pending bit + uint8_t sts = pmc_status(pmc); + pmc_set_status(pmc, sts | (1 << 5)); + // Start SCI interrupt + gpio_set(&SCI_N, false); + *(SCI_N.control) = 0x40; + return update; +} + +void pmc_event(struct Pmc * pmc) { + static enum PmcState state = PMC_STATE_DEFAULT; + static uint8_t state_data[2] = {0, 0}; + + uint8_t sts = pmc_status(pmc); + if (sts & PMC_STS_IBF) { + uint8_t data = pmc_read(pmc); + if (sts & PMC_STS_CMD) { + DEBUG("pmc cmd: %02X\n", data); + + state = PMC_STATE_DEFAULT; + switch (data) { + case 0x80: + state = PMC_STATE_ACPI_READ; + break; + case 0x81: + state = PMC_STATE_ACPI_WRITE; + break; + case 0x82: + DEBUG(" burst enable\n"); + // Set burst bit + pmc_set_status(pmc, sts | (1 << 4)); + // Send acknowledgement byte + pmc_write(pmc, 0x90, PMC_TIMEOUT); + break; + case 0x83: + DEBUG(" burst disable\n"); + // Clear burst bit + pmc_set_status(pmc, sts & ~(1 << 4)); + break; + case 0x84: + DEBUG(" SCI queue\n"); + // Clear SCI pending bit + pmc_set_status(pmc, sts & ~(1 << 5)); + // Send SCI queue + pmc_write(pmc, pmc_sci_queue, PMC_TIMEOUT); + // Stop SCI interrupt + *(SCI_N.control) = 0x80; + gpio_set(&SCI_N, true); + // Clear SCI queue + pmc_sci_queue = 0; + break; + + case 0xDC: + DEBUG(" scratch rom\n"); + pmc_write(pmc, 0x33, PMC_TIMEOUT); + scratch_trampoline(); + break; + } + } else { + DEBUG("pmc data: %02X\n", data); + + switch (state) { + case PMC_STATE_ACPI_READ: + state = PMC_STATE_DEFAULT; + uint8_t value = acpi_read(data); + pmc_write(pmc, value, PMC_TIMEOUT); + break; + case PMC_STATE_ACPI_WRITE: + state = PMC_STATE_ACPI_WRITE_ADDR; + state_data[0] = data; + break; + case PMC_STATE_ACPI_WRITE_ADDR: + state = PMC_STATE_DEFAULT; + acpi_write(state_data[0], data); + break; + default: + state = PMC_STATE_DEFAULT; + break; + } + } + } +} diff --git a/src/board/system76/darp5/pnp.c b/src/board/system76/darp5/pnp.c new file mode 100644 index 0000000..c22422f --- /dev/null +++ b/src/board/system76/darp5/pnp.c @@ -0,0 +1,43 @@ +#include + +#include + +volatile uint8_t __xdata __at(0x1200) IHIOA; +volatile uint8_t __xdata __at(0x1201) IHD; +volatile uint8_t __xdata __at(0x1204) IBMAE; +volatile uint8_t __xdata __at(0x1205) IBCTL; +void e2ci_write(uint8_t port, uint8_t data) { + while (IBCTL & ((1 << 2) | (1 << 1))) {} + IHIOA = port; + IHD = data; + IBMAE = 1; + IBCTL = 1; + while (IBCTL & (1 << 2)) {} + IBMAE = 0; + IBCTL = 0; +} + +void pnp_write(uint8_t reg, uint8_t data) { + e2ci_write(0x2E, reg); + e2ci_write(0x2F, data); +} + +void pnp_enable() { + DEBUG("Enable PNP devices\n"); + + // Enable PMC + pnp_write(0x07, 0x11); + pnp_write(0x30, 0x01); + + // Enable KBC keyboard + pnp_write(0x07, 0x06); + pnp_write(0x30, 0x01); + + // Enable KBC mouse + pnp_write(0x07, 0x05); + pnp_write(0x30, 0x01); + + // Enable SWUC + pnp_write(0x07, 0x04); + pnp_write(0x30, 0x01); +} diff --git a/src/board/system76/darp5/power.c b/src/board/system76/darp5/power.c new file mode 100644 index 0000000..6556fe8 --- /dev/null +++ b/src/board/system76/darp5/power.c @@ -0,0 +1,382 @@ +#include + +#include +#include +#include +#include +#include +#include +#include + +// Platform does not currently support Deep Sx +#define DEEP_SX 0 + +extern uint8_t main_cycle; + +// VccRTC stable (55%) to RTCRST# high +#define tPCH01 delay_ms(9) +// VccDSW stable (95%) to RSMRST# high +#define tPCH02 delay_ms(10) +// VccPrimary stable (95%) to RSMRST# high +#define tPCH03 delay_ms(10) +// VccRTC stable (90%) to start of VccDSW voltage ramp +#define tPCH04 delay_ms(9) +// RTCRST# high to DSW_PWROK +#define tPCH05 delay_us(1) +// VccDSW 3.3 stable to VccPrimary 1.05V +#define tPCH06 delay_us(200) +// DSW_PWROK high to RSMRST# high +#define tPCH07 delay_ms(0) +// SLP_S3# de-assertion to PCH_PWROK assertion +#define tPCH08 delay_ms(1) +// SLP_A# high when ASW rails are stable (95%) +#define tPCH09 delay_ms(2, 4, 8, 16) //TODO +// PCH_PWROK low to VCCIO dropping 5% +#define tPCH10 delay_ns(400) +// SLP_SUS# asserting to VccPRIM dropping 5% +#define tPCH11 delay_ns(100) +// RSMRST# asserting to VccPRIM dropping 5% +#define tPCH12 delay_ns(400) +// DSW_PWROK falling to any of VccDSW, VccPRIM dropping 5% +#define tPCH14 delay_ns(400) +// De-assertion of RSMRST# to de-assertion of ESPI_RESET# +#if DEEP_SX + #define tPCH18 delay_us(90) +#else + #define tPCH18 delay_ms(95) +#endif +// DSW_PWROK assertion to SLP_SUS# de-assertion +#define tPCH32 delay_ms(95) +// RSMRST# de-assertion to SUSPWRDNACK valid +#define tPLT01 delay_ms(200) + +// Enable deep sleep well power +void power_on_ds5() { + DEBUG("%02X: power_on_ds5\n", main_cycle); + +#if DEEP_SX + // See Figure 12-18 in Whiskey Lake Platform Design Guide + // | VCCRTC | RTCRST# | VCCDSW_3P3 | DSW_PWROK | + // | tPCH01---------- | | | + // | tPCH04----------------------- | | + // | | tPCH05-------------------------- | + // | | | tPCH02---------------- | + + // tPCH01 and tPCH02 combined make the longest delay + tPCH01; + tPCH02; + + // Deep sleep well is a-ok + gpio_set(PCH_DPWROK_EC, true); + // Wait for deep sleep well to propogate + tPCH32; +#else // DEEP_SX + // See Figure 12-19 in Whiskey Lake Platform Design Guide + // | VCCRTC | RTCRST# | VccPRIM | + // | tPCH01---------- | | + // | tPCH04-------------------- | + + // tPCH04 is the ideal delay + tPCH04; +#endif // DEEP_SX +} + +// Enable S5 power +void power_on_s5() { + DEBUG("%02X: power_on_s5\n", main_cycle); + +#if DEEP_SX + // See Figure 12-18 in Whiskey Lake Platform Design Guide + + // TODO +#else // DEEP_SX + // See Figure 12-19 in Whiskey Lake Platform Design Guide + // TODO - signal timing graph + // See Figure 12-25 in Whiskey Lake Platform Design Guide + // TODO - rail timing graph + + // Enable VCCPRIM_* planes - must be enabled prior to USB power in order to + // avoid leakage + gpio_set(&VA_EC_EN, true); + tPCH06; + + // Enable VDD5 + gpio_set(&DD_ON, true); + + // De-assert SUS_ACK# - TODO is this needed on non-dsx? + gpio_set(&SUS_PWR_ACK, true); + tPCH03; + + // Assert DSW_PWROK + gpio_set(&PCH_DPWROK_EC, true); + + // De-assert RSMRST# + gpio_set(&EC_RSMRST_N, true); + + // Wait for PCH stability + tPCH18; + + // Allow processor to control SUSB# and SUSC# + gpio_set(&EC_EN, true); + + // Wait for SUSPWRDNACK validity + tPLT01; + + // Extra wait - TODO remove + delay_ms(200); +#endif // DEEP_SX +} + +void power_off_s5() { + DEBUG("%02X: power_off_s5\n", main_cycle); + +#if DEEP_SX + // TODO +#else // DEEP_SX + // De-assert SYS_PWROK + gpio_set(&PCH_PWROK_EC, false); + + // De-assert PCH_PWROK + gpio_set(&PM_PWROK, false); + + // Block processor from controlling SUSB# and SUSC# + gpio_set(&EC_EN, false); + + // De-assert RSMRST# + gpio_set(&EC_RSMRST_N, false); + + // Disable VDD5 + gpio_set(&DD_ON, false); + tPCH12; + + // Disable VCCPRIM_* planes + gpio_set(&VA_EC_EN, false); + + // De-assert DSW_PWROK + gpio_set(&PCH_DPWROK_EC, false); + tPCH14; +#endif // DEEP_SX +} + +enum PowerState { + POWER_STATE_DEFAULT, + POWER_STATE_DS5, + POWER_STATE_S5, + POWER_STATE_DS3, + POWER_STATE_S3, + POWER_STATE_S0, +}; + +void power_event(void) { + static enum PowerState state = POWER_STATE_DEFAULT; + + // Always switch to ds5 if EC is running + if (state == POWER_STATE_DEFAULT) { + power_on_ds5(); + state = POWER_STATE_DS5; + } + + // Check if the adapter line goes low + static bool ac_send_sci = true; + static bool ac_last = true; + bool ac_new = gpio_get(&ACIN_N); + if (ac_new != ac_last) { + DEBUG("Power adapter "); + if (ac_new) { + DEBUG("unplugged\n"); + battery_charger_disable(); + } else { + DEBUG("plugged in\n"); + battery_charger_enable(); + } + battery_debug(); + + // Reset main loop cycle to force reading PECI and battery + main_cycle = 0; + + // Send SCI to update AC and battery information + ac_send_sci = true; + } + if (ac_send_sci) { + // Send SCI 0x16 for AC detect event + if (pmc_sci(&PMC_1, 0x16)) { + ac_send_sci = false; + } + } + ac_last = ac_new; + + // Read power switch state + static bool ps_last = true; + bool ps_new = gpio_get(&PWR_SW_N); + if (!ps_new && ps_last) { + // Ensure press is not spurious + delay_ms(10); + if (gpio_get(&PWR_SW_N) != ps_new) { + DEBUG("%02X: Spurious press\n", main_cycle); + ps_new = ps_last; + } else { + DEBUG("%02X: Power switch press\n", main_cycle); + + // Enable S5 power if necessary, before sending PWR_BTN + if (state == POWER_STATE_DS5) { + power_on_s5(); + state = POWER_STATE_S5; + } + } + } + #if LEVEL >= LEVEL_DEBUG + else if (ps_new && !ps_last) { + DEBUG("%02X: Power switch release\n", main_cycle); + } + #endif + ps_last = ps_new; + + // Send power signal to PCH + gpio_set(&PWR_BTN_N, ps_new); + +#if DEEP_SX + //TODO +#else // DEEP_SX + //TODO: set power state as necessary + + // If system power is good + static bool pg_last = false; + bool pg_new = gpio_get(&ALL_SYS_PWRGD); + if (pg_new && !pg_last) { + DEBUG("%02X: ALL_SYS_PWRGD asserted\n", main_cycle); + + //TODO: tPLT04; + + // Allow H_VR_READY to set PCH_PWROK + gpio_set(&PM_PWROK, true); + + // OEM defined delay from ALL_SYS_PWRGD to SYS_PWROK - TODO + delay_ms(10); + + // Assert SYS_PWROK, system can finally perform PLT_RST# and boot + gpio_set(&PCH_PWROK_EC, true); + } else if(!pg_new && pg_last) { + DEBUG("%02X: ALL_SYS_PWRGD de-asserted\n", main_cycle); + + // De-assert SYS_PWROK + gpio_set(&PCH_PWROK_EC, false); + + // De-assert PCH_PWROK + gpio_set(&PM_PWROK, false); + } + pg_last = pg_new; + + static bool rst_last = false; + bool rst_new = gpio_get(&BUF_PLT_RST_N); + #if LEVEL >= LEVEL_DEBUG + if (!rst_new && rst_last) { + DEBUG("%02X: PLT_RST# asserted\n", main_cycle); + } else + #endif + if(rst_new && !rst_last) { + DEBUG("%02X: PLT_RST# de-asserted\n", main_cycle); + + // LPC was just reset, enable PNP devices + pnp_enable(); + //TODO: reset KBC and touchpad states + } + rst_last = rst_new; + + #if LEVEL >= LEVEL_DEBUG + static bool s3_last = false; + bool s3_new = gpio_get(&SUSB_N_PCH); + if (!s3_new && s3_last) { + DEBUG("%02X: SLP_S3# asserted\n", main_cycle); + } else if(s3_new && !s3_last) { + DEBUG("%02X: SLP_S3# de-asserted\n", main_cycle); + } + s3_last = s3_new; + #endif + + static bool s4_last = false; + bool s4_new = gpio_get(&SUSC_N_PCH); + #if LEVEL >= LEVEL_DEBUG + if (!s4_new && s4_last) { + DEBUG("%02X: SLP_S4# asserted\n", main_cycle); + } else if(s4_new && !s4_last) { + DEBUG("%02X: SLP_S4# de-asserted\n", main_cycle); + } + #endif + s4_last = s4_new; + + #if LEVEL >= LEVEL_DEBUG + static bool sus_last = false; + bool sus_new = gpio_get(&SLP_SUS_N); + if (!sus_new && sus_last) { + DEBUG("%02X: SLP_SUS# asserted\n", main_cycle); + } else if (sus_new && !sus_last) { + DEBUG("%02X: SLP_SUS# de-asserted\n", main_cycle); + } + sus_last = sus_new; + #endif + + // EC must keep VccPRIM powered if SUSPWRDNACK is de-asserted low or system + // state is S3 + static bool ack_last = false; + bool ack_new = gpio_get(&SUSWARN_N); + if (ack_new && !ack_last) { + DEBUG("%02X: SUSPWRDNACK asserted\n", main_cycle); + + if (s4_new) { + DEBUG("%02X: entering S3 state\n", main_cycle); + } else if (state == POWER_STATE_S5) { + power_off_s5(); + state = POWER_STATE_DS5; + } + } + #if LEVEL >= LEVEL_DEBUG + else if (!ack_new && ack_last) { + DEBUG("%02X: SUSPWRDNACK de-asserted\n", main_cycle); + } + #endif + ack_last = ack_new; + + if (rst_new) { + // CPU on, green light + gpio_set(&LED_PWR, true); + gpio_set(&LED_ACIN, false); + } else if (s4_new) { + // Suspended, flashing green light + static int8_t suspend_timer = 0; + if (suspend_timer <= 0) { + gpio_set(&LED_PWR, !gpio_get(&LED_PWR)); + // Suspend timer fires every 1 s + suspend_timer = 100; + } + gpio_set(&LED_ACIN, false); + + // If timer 1 is finished + if (TF1) { + // Stop timer 1 running + TR1 = 0; + // Clear timer 1 finished flag + TF1 = 0; + // Decrement suspend timer + suspend_timer -= 1; + } + + // If timer 1 is not running + if (!TR1) { + // Start timer for 10 ms + // 65536-(10000 * 69 + 89)/90 = 0xE20C + TMOD = (TMOD & 0x0F) | 0x10; + TH1 = 0xE2; + TL1 = 0x0C; + TR1 = 1; + } + } else if (!ac_new) { + // AC plugged in, orange light + gpio_set(&LED_PWR, false); + gpio_set(&LED_ACIN, true); + } else { + // CPU off and AC adapter unplugged, no light + gpio_set(&LED_PWR, false); + gpio_set(&LED_ACIN, false); + } +#endif // DEEP_SX +} diff --git a/src/board/system76/darp5/ps2.c b/src/board/system76/darp5/ps2.c new file mode 100644 index 0000000..237e061 --- /dev/null +++ b/src/board/system76/darp5/ps2.c @@ -0,0 +1,7 @@ +#include + +void ps2_init(void) { + ps2_reset(&PS2_1); + ps2_reset(&PS2_2); + ps2_reset(&PS2_3); +} diff --git a/src/board/system76/darp5/pwm.c b/src/board/system76/darp5/pwm.c new file mode 100644 index 0000000..6cd7dda --- /dev/null +++ b/src/board/system76/darp5/pwm.c @@ -0,0 +1,24 @@ +#include + +void pwm_init(void) { + // Set T0CHSEL to TACH0A and T1CHSEL to TACH1A + TSWCTLR = 0; + + // Disable PWM + ZTIER = 0; + + // Set prescalar clock frequency to EC clock + PCFSR = 0b01; + + // Set clock prescaler to 0 + 1 + C0CPRS = 0; + + // Set cycle time to 255 + 1 + CTR0 = 255; + + // Turn off CPU fan (temperature control in peci_event) + DCR2 = 0; + + // Enable PWM + ZTIER = (1 << 1); +} diff --git a/src/board/system76/darp5/scratch.c b/src/board/system76/darp5/scratch.c new file mode 100644 index 0000000..0e59ba3 --- /dev/null +++ b/src/board/system76/darp5/scratch.c @@ -0,0 +1,99 @@ +#include +#include + +#include + +// Include scratch ROM, must be less than 4096 bytes, controlled by makefile +uint8_t __code scratch_rom[] = { + #include +}; + +// Scratch RAM 0, 1, 2, 3, and 4 are 4096 bytes total, located at 0x0000 bytes +volatile uint8_t __xdata __at(0x0000) scratch_ram[4096]; + +volatile uint8_t __xdata __at(0x1040) SCAR0L; +volatile uint8_t __xdata __at(0x1041) SCAR0M; +volatile uint8_t __xdata __at(0x1042) SCAR0H; + +volatile uint8_t __xdata __at(0x1043) SCAR1L; +volatile uint8_t __xdata __at(0x1044) SCAR1M; +volatile uint8_t __xdata __at(0x1045) SCAR1H; + +volatile uint8_t __xdata __at(0x1046) SCAR2L; +volatile uint8_t __xdata __at(0x1047) SCAR2M; +volatile uint8_t __xdata __at(0x1048) SCAR2H; + +volatile uint8_t __xdata __at(0x1049) SCAR3L; +volatile uint8_t __xdata __at(0x104A) SCAR3M; +volatile uint8_t __xdata __at(0x104B) SCAR3H; + +volatile uint8_t __xdata __at(0x104C) SCAR4L; +volatile uint8_t __xdata __at(0x104D) SCAR4M; +volatile uint8_t __xdata __at(0x104E) SCAR4H; + +// Create new segment located at 0x1000, after scratch ROM mapping +static void scratch_start(void) __naked { + __asm + .area SCRATCH (ABS,CODE) + __endasm; + __asm + .org 0x1000 + __endasm; +} + +// Enter or exit scratch ROM +void scratch_trampoline(void) { + // Uses SCAR0, 1, 2, 3, and 4 which are mapped at 0x0000 in data space and are + // 4096 bytes in size. + + if ((SCAR0H == 0x00) || (SCAR1H == 0x00) || (SCAR2H == 0x00) || (SCAR3H == 0x00) || (SCAR4H == 0x00)) { + // Disable scratch RAM mapping + SCAR0H = 0b11; + SCAR1H = 0b11; + SCAR2H = 0b11; + SCAR3H = 0b11; + SCAR4H = 0b11; + } else { + int i; + // Copy scratch ROM + for (i = 0; i < ARRAY_SIZE(scratch_rom) && i < ARRAY_SIZE(scratch_ram); i++) { + scratch_ram[i] = scratch_rom[i]; + } + + // Fill the rest with nop + for (; i < ARRAY_SIZE(scratch_ram); i++) { + scratch_ram[i] = 0x00; + } + + // Set scratch RAM 0 mapping at 0x0000 and enable + SCAR0L = 0x00; + SCAR0M = 0x00; + SCAR0H = 0x00; + // Set scratch RAM 1 mapping at 0x0800 and enable + SCAR1L = 0x00; + SCAR1M = 0x08; + SCAR1H = 0x00; + // Set scratch RAM 2 mapping at 0x0C00 and enable + SCAR2L = 0x00; + SCAR2M = 0x0C; + SCAR2H = 0x00; + // Set scratch RAM 3 mapping at 0x0E00 and enable + SCAR3L = 0x00; + SCAR3M = 0x0E; + SCAR3H = 0x00; + // Set scratch RAM 4 mapping at 0x0F00 and enable + SCAR4L = 0x00; + SCAR4M = 0x0F; + SCAR4H = 0x00; + } + + // Jump to reset function + __asm__("ljmp 0"); +} + +// Finish segment located at 0x1000 +static void scratch_end(void) __naked { + __asm + .area CSEG (REL,CODE) + __endasm; +} diff --git a/src/board/system76/darp5/scratch/include/scratch/pmc.h b/src/board/system76/darp5/scratch/include/scratch/pmc.h new file mode 100644 index 0000000..ca36a16 --- /dev/null +++ b/src/board/system76/darp5/scratch/include/scratch/pmc.h @@ -0,0 +1,33 @@ +#ifndef _EC_PMC_H +#define _EC_PMC_H + +#include +#include + +struct Pmc { + // Status register + volatile uint8_t * status; + // Data out register + volatile uint8_t * data_out; + // Data in register + volatile uint8_t * data_in; + // Control register + volatile uint8_t * control; +}; + +extern struct Pmc __code PMC_1; + +#define PMC_STS_OBF (1 << 0) +#define PMC_STS_IBF (1 << 1) +#define PMC_STS_CMD (1 << 3) + +uint8_t pmc_status(struct Pmc * pmc); +uint8_t pmc_read(struct Pmc * pmc); +bool pmc_write(struct Pmc * pmc, uint8_t data); + +volatile uint8_t __xdata __at(0x1500) PM1STS; +volatile uint8_t __xdata __at(0x1501) PM1DO; +volatile uint8_t __xdata __at(0x1504) PM1DI; +volatile uint8_t __xdata __at(0x1506) PM1CTL; + +#endif // _EC_PMC_H diff --git a/src/board/system76/darp5/scratch/main.c b/src/board/system76/darp5/scratch/main.c new file mode 100644 index 0000000..29eb9ab --- /dev/null +++ b/src/board/system76/darp5/scratch/main.c @@ -0,0 +1,101 @@ +#include +#include +#include + +#include + +volatile uint8_t __xdata __at(0x103B) ECINDAR0; +volatile uint8_t __xdata __at(0x103C) ECINDAR1; +volatile uint8_t __xdata __at(0x103D) ECINDAR2; +volatile uint8_t __xdata __at(0x103E) ECINDAR3; +volatile uint8_t __xdata __at(0x103F) ECINDDR; + +#define FLASH_SPI 0x00000000 +#define FLASH_EMBEDDED 0x40000000 + +static int flash_transaction(uint32_t offset, uint8_t * data, int length, bool read) { + int i; + for (i = 0; i < length; i++, offset++) { + ECINDAR3 = (uint8_t)(offset >> 24); + ECINDAR2 = (uint8_t)(offset >> 16); + ECINDAR1 = (uint8_t)(offset >> 8); + ECINDAR0 = (uint8_t)(offset); + if (read) { + data[i] = ECINDDR; + } else { + ECINDDR = data[i]; + } + } + return i; +} + +enum PmcState { + PMC_STATE_DEFAULT, + PMC_STATE_WRITE, +}; + +static void pmc_event(struct Pmc * pmc) { + static enum PmcState state = PMC_STATE_DEFAULT; + + uint8_t sts = pmc_status(pmc); + if (sts & PMC_STS_IBF) { + uint8_t data = pmc_read(pmc); + if (sts & PMC_STS_CMD) { + printf_tiny("%x\n", data); + switch (state) { + case PMC_STATE_DEFAULT: + switch (data) { + case 0x01: + // Enable follow + ECINDAR3 = 0x0F; + break; + case 0x02: + // Generate high CE# + data = 0; + flash_transaction(0x7FFFFE00, &data, 1, false); + // Fall through + case 0x03: + state = PMC_STATE_WRITE; + break; + case 0x04: + // Read data + flash_transaction(0x7FFFFD00, &data, 1, true); + pmc_write(pmc, data); + printf_tiny("=%x\n", data); + break; + case 0x05: + // Disable follow + ECINDAR3 = 0x00; + break; + case 0xFC: + // Clear processor caches + __asm__("mov 0xf7, #1"); + __asm__("nop"); + __asm__("mov 0xf7, #1"); + __asm__("nop"); + __asm__("mov 0xf7, #1"); + __asm__("nop"); + __asm__("mov 0xf7, #1"); + __asm__("nop"); + // Exit scratch ROM by going through trampoline + __asm__("ljmp 0x1000"); + break; + } + break; + case PMC_STATE_WRITE: + // Write command or data + flash_transaction(0x7FFFFD00, &data, 1, false); + state = PMC_STATE_DEFAULT; + break; + } + } + } +} + +// Main program while running in scratch ROM +void main(void) { + printf_tiny("SCRATCH\n"); + for (;;) { + pmc_event(&PMC_1); + } +} diff --git a/src/board/system76/darp5/scratch/pmc.c b/src/board/system76/darp5/scratch/pmc.c new file mode 100644 index 0000000..7bba10c --- /dev/null +++ b/src/board/system76/darp5/scratch/pmc.c @@ -0,0 +1,24 @@ +#include + +#define PMC(NUM) { \ + .status = &PM ## NUM ## STS, \ + .data_out = &PM ## NUM ## DO, \ + .data_in = &PM ## NUM ## DI, \ + .control = &PM ## NUM ## CTL, \ +} + +struct Pmc __code PMC_1 = PMC(1); + +uint8_t pmc_status(struct Pmc * pmc) { + return *(pmc->status); +} + +uint8_t pmc_read(struct Pmc * pmc) { + return *(pmc->data_in); +} + +bool pmc_write(struct Pmc * pmc, uint8_t data) { + while (pmc_status(pmc) & PMC_STS_OBF) {} + *(pmc->data_out) = data; + return true; +} diff --git a/src/board/system76/darp5/scratch/scratch.mk b/src/board/system76/darp5/scratch/scratch.mk new file mode 100644 index 0000000..981eb02 --- /dev/null +++ b/src/board/system76/darp5/scratch/scratch.mk @@ -0,0 +1,40 @@ +# Enable I2C debugging +SCRATCH_SRC+=\ + src/common/i2c.c \ + src/ec/$(EC)/i2c.c +SCRATCH_INCLUDE+=\ + src/common/include/common/*.h \ + src/ec/$(EC)/include/ec/*.h +SCRATCH_CFLAGS+=\ + -Isrc/common/include \ + -Isrc/ec/$(EC)/include \ + -DI2C_DEBUGGER=0x76 + +SCRATCH_BUILD=$(BUILD)/scratch +SCRATCH_OBJ=$(patsubst src/%.c,$(SCRATCH_BUILD)/%.rel,$(SCRATCH_SRC)) +SCRATCH_CC=\ + sdcc \ + -mmcs51 \ + --model-small \ + --code-size 4096 \ + --Werror + +# Convert from binary file to C header +$(BUILD)/include/scratch.h: $(SCRATCH_BUILD)/scratch.rom + @mkdir -p $(@D) + xxd --include < $< > $@ + +# Convert from Intel Hex file to binary file +$(SCRATCH_BUILD)/scratch.rom: $(SCRATCH_BUILD)/scratch.ihx + @mkdir -p $(@D) + makebin -p < $< > $@ + +# Link object files into Intel Hex file +$(SCRATCH_BUILD)/scratch.ihx: $(SCRATCH_OBJ) + @mkdir -p $(@D) + $(SCRATCH_CC) -o $@ $^ + +# Compile C files into object files +$(SCRATCH_OBJ): $(SCRATCH_BUILD)/%.rel: src/%.c $(SCRATCH_INCLUDE) + @mkdir -p $(@D) + $(SCRATCH_CC) $(SCRATCH_CFLAGS) -o $@ -c $< diff --git a/src/board/system76/darp5/scratch/stdio.c b/src/board/system76/darp5/scratch/stdio.c new file mode 100644 index 0000000..2a552ab --- /dev/null +++ b/src/board/system76/darp5/scratch/stdio.c @@ -0,0 +1,20 @@ +#include + +#ifdef SERIAL_DEBUGGER + #include +#endif + +#ifdef I2C_DEBUGGER + #include +#endif + +int putchar(int c) { + unsigned char byte = (unsigned char)c; +#ifdef SERIAL_DEBUGGER + SBUF = byte; +#endif +#ifdef I2C_DEBUGGER + i2c_send(&I2C_0, I2C_DEBUGGER, &byte, 1); +#endif + return (int)byte; +} diff --git a/src/board/system76/darp5/smbus.c b/src/board/system76/darp5/smbus.c new file mode 100644 index 0000000..c61c31d --- /dev/null +++ b/src/board/system76/darp5/smbus.c @@ -0,0 +1,21 @@ +#include +#include + +void smbus_init(void) { + // 9.2 MHz * 4.7 us = 43.24 + SMB4P7USL = 43; + // 9.2 MHz * 4.0 us = 36.8 + SMB4P0USL = 37; + // 9.2 MHz * 300 ns = 2.76 + SMB300NS = 3; + // 9.2 MHz * 250 ns = 2.3 + SMB250NS = 2; + // 1.024 KHz * 25 ms = 25.6 + SMB25MS = 26; + // 9.2 MHz * 45.3 us = 416.76 (0x01A1) + SMB45P3USL = 0xA1; + SMB45P3USH = 0x01; + + // Set up for i2c usage + i2c_reset(&I2C_0, true); +} diff --git a/src/board/system76/darp5/stdio.c b/src/board/system76/darp5/stdio.c new file mode 100644 index 0000000..2a552ab --- /dev/null +++ b/src/board/system76/darp5/stdio.c @@ -0,0 +1,20 @@ +#include + +#ifdef SERIAL_DEBUGGER + #include +#endif + +#ifdef I2C_DEBUGGER + #include +#endif + +int putchar(int c) { + unsigned char byte = (unsigned char)c; +#ifdef SERIAL_DEBUGGER + SBUF = byte; +#endif +#ifdef I2C_DEBUGGER + i2c_send(&I2C_0, I2C_DEBUGGER, &byte, 1); +#endif + return (int)byte; +} diff --git a/src/board/system76/galp3-c/include/board/keymap.h b/src/board/system76/galp3-c/include/board/keymap.h index 9892796..e24dce1 100644 --- a/src/board/system76/galp3-c/include/board/keymap.h +++ b/src/board/system76/galp3-c/include/board/keymap.h @@ -32,8 +32,8 @@ { K56, ___, K3C, ___, K59, K0C, K4D, K3D } \ } -// Keymap output pins (16 for galago, 18 for darter) -#define KM_OUT 18 +// Keymap output pins +#define KM_OUT 16 // Keymap input pins #define KM_IN 8 // Keymap layers (normal, Fn) diff --git a/src/board/system76/galp3-c/kbscan.c b/src/board/system76/galp3-c/kbscan.c index 12af49e..48892fc 100644 --- a/src/board/system76/galp3-c/kbscan.c +++ b/src/board/system76/galp3-c/kbscan.c @@ -46,25 +46,16 @@ void kbscan_event(void) { if (i < 8) { KSOLGOEN = 0; KSOLGOEN = 1 << i; - GPCRC3 = GPIO_IN; - GPCRC5 = GPIO_IN; } else if (i < 16) { KSOLGOEN = 0; KSOHGOEN = 1 << (i - 8); - GPCRC3 = GPIO_IN; - GPCRC5 = GPIO_IN; } else if (i == 16) { KSOLGOEN = 0; KSOHGOEN = 0; - GPCRC3 = GPIO_OUT; - GPCRC5 = GPIO_IN; } else if (i == 17) { KSOLGOEN = 0; KSOHGOEN = 0; - GPCRC3 = GPIO_IN; - GPCRC5 = GPIO_OUT; } - GPDRC &= ~((1 << 3) | (1 << 5)); // TODO: figure out optimal delay delay_ticks(10); @@ -164,8 +155,6 @@ void kbscan_event(void) { // Reset all lines to inputs KSOLGOEN = 0; KSOHGOEN = 0; - GPCRC3 = GPIO_IN; - GPCRC5 = GPIO_IN; // TODO: figure out optimal delay delay_ticks(10); diff --git a/src/board/system76/galp3-c/keymap/darter.c b/src/board/system76/galp3-c/keymap/darter.c deleted file mode 100644 index 03aec5e..0000000 --- a/src/board/system76/galp3-c/keymap/darter.c +++ /dev/null @@ -1,188 +0,0 @@ -// Default layout - -#include - -#define K(V) {V, V} - -uint16_t __code KEYMAP[KM_OUT][KM_IN][KM_LAY] = { - { // 0 - K(0), // 0 - K(0), // 1 - K(0), // 2 - K(0), // 3 - K(0), // 4 - K(0), // 5 - K(K_LEFT_CTRL), // 6 - K(K_RIGHT_CTRL), // 7 - }, - { // 1 - K(0), // 0 - K(0), // 1 - K(0), // 2 - K(0), // 3 - K(0), // 4 - K(0), // 5 - K(K_LEFT_ALT), // 6 - K(K_RIGHT_ALT), // 7 - }, - { // 2 - K(0), // 0 - K(0), // 1 - K(0), // 2 - K(0), // 3 - K(0), // 4 - K(0), // 5 - K(K_LEFT_SHIFT), // 6 - K(K_RIGHT_SHIFT), // 7 - }, - { // 3 - K(K_LEFT_SUPER), // 0 - K(0), // 1 - K(0), // 2 - K(0), // 3 - K(0), // 4 - K(0), // 5 - K(0), // 6 - K(K_SPACE), // 7 - }, - { // 4 - K(K_Z), // 0 - K(K_NUM_MINUS), // 1 - K(0), // 2 - K(K_NUM_8), // 3 - K(K_NUM_2), // 4 - K(0), // 5 - K(0), // 6 - K(0), // 7 - }, - { // 5 - K(K_PGUP), // 0 - K(K_W), // 1 - K(0), // 2 - K(0), // 3 - K(K_NUM_LOCK), // 4 - K(K_NUM_4), // 5 - K(K_NUM_6), // 6 - K(K_CAPS), // 7 - }, - { // 6 - K(K_PGDN), // 0 - K(K_MINUS), // 1 - K(K_E), // 2 - K(K_L), // 3 - K(0), // 4 - K(0), // 5 - K(K_M), // 6 - K(0), // 7 - }, - { // 7 - K(K_K), // 0 - K(K_Y), // 1 - K(K_0), // 2 - K(K_R), // 3 - K(0), // 4 - K(K_SEMICOLON), // 5 - K(K_TAB), // 6 - K(K_ESC), // 7 - }, - { // 8 - K(K_NUM_0), // 0 - K(K_J), // 1 - K(K_BRACE_CLOSE), // 2 - K(K_9), // 3 - K(K_T), // 4 - K(K_F7), // 5 - K(K_8), // 6 - {K_F1, K_TOUCHPAD}, // 7 - }, - { // 9 - K(K_NUM_PERIOD), // 0 - K(K_F), // 1 - K(K_H), // 2 - K(K_F2), // 3 - K(0), // 4 - K(K_NUM_ENTER), // 5 - K(K_QUOTE), // 6 - K(K_B), // 7 - }, - { // 10 - K(K_NUM_SLASH), // 0 - K(K_COMMA), // 1 - K(0), // 2 - K(K_BRACE_OPEN), // 3 - K(K_S), // 4 - {K_F8, KT_SCI | SCI_BRIGHTNESS_DOWN}, // 5 - {K_F6, K_VOLUME_UP}, // 6 - K(K_2), // 7 - }, - { // 11 - K(K_NUM_ASTERISK), // 0 - K(K_PERIOD), // 1 - K(K_7), // 2 - K(K_D), // 3 - K(0), // 4 - K(0), // 5 - K(K_1), // 6 - K(K_P), // 7 - }, - { // 12 - K(K_BACKSLASH), // 0 - K(0), // 1 - K(K_A), // 2 - K(K_SLASH), // 3 - K(0), // 4 - {K_F3, K_MUTE}, // 5 - K(K_I), // 6 - K(K_6), // 7 - }, - { // 13 - K(0), // 0 - K(K_V), // 1 - K(0 /* PRTSC */), // 2 - {K_F9, KT_SCI | SCI_BRIGHTNESS_UP}, // 3 - K(K_N), // 4 - K(K_O), // 5 - K(K_5), // 6 - {K_F5, K_VOLUME_DOWN}, // 7 - }, - { // 14 - K(K_Q), // 0 - K(K_F10), // 1 - K(K_NUM_7), // 2 - K(K_F4), // 3 - K(K_NUM_5), // 4 - K(K_INSERT), // 5 - K(K_DEL), // 6 - K(K_4), // 7 - }, - { // 15 - K(K_APP), // 0 - K(K_X), // 1 - K(K_ENTER), // 2 - K(K_NUM_PLUS), // 3 - K(K_U), // 4 - K(K_NUM_9), // 5 - K(K_3), // 6 - K(K_BKSP), // 7 - }, - { // 16 - K(K_END), // 0 - K(K_HOME), // 1 - K(K_C), // 2 - K(K_UP), // 3 - K(K_DOWN), // 4 - {K_TICK, K_PLAY_PAUSE}, // 5 - {K_F11, KT_SCI | SCI_AIRPLANE_MODE}, // 6 - {K_F12, KT_SCI | SCI_SUSPEND}, // 7 - }, - { // 17 - K(K_G), // 0 - K(K_EQUALS), // 1 - K(K_NUM_3), // 2 - K(KT_FN), // 3 - K(K_NUM_1), // 4 - K(K_LEFT), // 5 - K(K_RIGHT), // 6 - K(0), // 7 - }, -};