summaryrefslogtreecommitdiff
path: root/src/mainboard/asrock/imb-1222/superio.c
diff options
context:
space:
mode:
authorMaxim Polyakov <max.senia.poliak@gmail.com>2024-06-17 22:22:14 +0300
committerFelix Singer <service+coreboot-gerrit@felixsinger.de>2024-11-07 03:18:00 +0000
commitc1caa33a2de16c0ffc2061467c66297f347a65f2 (patch)
treeda6f15a05dc84ad730a8b2552ffd9505536b3d13 /src/mainboard/asrock/imb-1222/superio.c
parent1d9bddf1632ccbb7ffd5d92c4608c3065df72c0f (diff)
mb/asrock: Add Asrock Industrial IMB-1222 motherboard
ASRock IMB-1222 Intel Comet Lake-S Q470E industrial thin mini-ITX motherboard [1]. Working: - Dual Channel DDR4 2933/2666/2400 MHz; - Intel UHD Graphics (VGA Option ROM, libgfxinit, GOP driver); - DP (both), HDMI; - PCIe x16 Slot (Gen3); - SATA ports; - USB 2.0 ports; - USB 3.2 ports; - M.2 Key-E 2230 slot for Wireless (PCIe x1, USB 2.0 and CNVi); - M.2 Key-B 3042/3052 slot for 4G/5G modem (PCIe x1); - M.2 Key-M 2242/2260/2280 for SSD/NVMe (PCIE x4, SATA3); - LAN1 Intel I225LM/I225V, 10/100/1000/2500 Mbps; - LAN2 Intel I219LM, 10/100/1000 Mbps; - Realtek ALC887 HD Audio (line-out, mic-in); - COM 1/2/3/4 ports; - onboard speaker; - HWM/FANs control (fintek f81966); - S3 suspend and wake; - TPM; - disabling ME with me_cleaner [2]; Payload: - Linux as payload; - LinuxBoot; - SeaBIOS; - edk2 [3]. Bootable OS: - Ubuntu 22.04 (Linux 6.5.0-15-generic); - Ubuntu 24.04 (Linux 6.8.0-41-generic); - Microsoft Windows 10 Pro (10.0.19045.4780, 22H2 2022); - Andoid 13, Bliss OS x86_64 (16.9.7, Linux 6.1.112-gloria-xanmod1). Unknown/untested: - USB3.0 in M.2 Key-B 3042/3052 slot; - eDP/LVDS; - PCIe riser cards; - SPDIF. There is no schematic/boardview, reverse engineering only. This port is based on system76/bonw14 because it has a similar topology. [1] https://web.archive.org/web/20220924171403/https:// www.asrockind.com/en-gb/IMB-1222 [2] XutaxKamay's me_cleaner fork, https://github.com/XutaxKamay/me_cleaner, v1.2-9-gf20532d [3] MrChromebox's edk2 fork, https://github.com/mrchromebox/edk2 uefipayload_2408 branch Change-Id: Id2b4c903546f9174b5e7dd26e54a0c5aaa09e1f8 Signed-off-by: Maxim Polyakov <max.senia.poliak@gmail.com> Reviewed-on: https://review.coreboot.org/c/coreboot/+/83107 Reviewed-by: Felix Singer <service+coreboot-gerrit@felixsinger.de> Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
Diffstat (limited to 'src/mainboard/asrock/imb-1222/superio.c')
-rw-r--r--src/mainboard/asrock/imb-1222/superio.c215
1 files changed, 215 insertions, 0 deletions
diff --git a/src/mainboard/asrock/imb-1222/superio.c b/src/mainboard/asrock/imb-1222/superio.c
new file mode 100644
index 0000000000..2827392ee1
--- /dev/null
+++ b/src/mainboard/asrock/imb-1222/superio.c
@@ -0,0 +1,215 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+#include <device/pnp.h>
+#include <mainboard/superio.h>
+#include <superio/hwm5_conf.h>
+#include <superio/fintek/common/fintek.h>
+
+/* TODO: move this code to superio/fintek driver */
+#define SIO_PORT 0x2e
+#define SIO_HWM_BASE 0x290
+#define SIO_DEV(n) PNP_DEV(SIO_PORT, SIO_LDN_##n)
+
+/* Fintek F81966 Logical Device Numbers (LDN) */
+#define SIO_LDN_GLOBAL 0x00
+#define SIO_LDN_LPT 0x03
+#define SIO_LDN_HWMON 0x04
+#define SIO_LDN_KBC 0x05
+#define SIO_LDN_GPIO 0x06
+#define SIO_LDN_WDT 0x07
+#define SIO_LDN_PME_ACPI_ERP 0x0a
+#define SIO_LDN_SPI 0x0f
+#define SIO_LDN_UART1 0x10
+#define SIO_LDN_UART2 0x11
+#define SIO_LDN_UART3 0x12
+#define SIO_LDN_UART4 0x13
+#define SIO_LDN_UART5 0x14
+#define SIO_LDN_UART6 0x15
+
+#define SIO_REG(i, v) {.idx = i, .val = v}
+#define SIO_ESEL(i, v, m) {.extra_selector = true, .idx = i, .val = v, .mask = m}
+#define SIO_LDN(n) {.idx = 0x07, .val = SIO_LDN_##n}
+#define SIO_LDN_EN(v) {.idx = 0x30, .val = v}
+/* f81966 Port Select (27h): BANK_PROG_SEL[3-2] CLK_TUNE_PROG_EN[0] */
+#define SIO_ESEL_27H(bank, en) { \
+ .extra_selector = true, \
+ .idx = 0x27, \
+ .mask = 0xf2, \
+ .val = esel_27h_##bank | esel_27h_clk_tune_##en, \
+ }
+/* f81966 Fan Fault Time Register (9Fh): FAN_PROG_SEL[7] */
+#define SIO_ESEL_9FH(bank) { \
+ .extra_selector = true, \
+ .idx = 0x9f, \
+ .mask = 0x7f, \
+ .val = esel_9fh_fan_prog_##bank, \
+ }
+/* PWM duty-cycle */
+#define PWM_DC(x) (((x << 8) - x) / 100)
+
+enum esel_27h_bank_prog_sel {
+ esel_27h_bank0 = 0 << 2,
+ esel_27h_bank1 = 1 << 2,
+ esel_27h_bank2 = 2 << 2,
+ esel_27h_bank3 = 3 << 2,
+};
+enum esel_27h_clk_tune {
+ esel_27h_clk_tune_dis = 0,
+ esel_27h_clk_tune_en = 1,
+};
+
+enum esel_9fh_fan_prog {
+ esel_9fh_fan_prog_bank0 = 0 << 7,
+ esel_9fh_fan_prog_bank1 = 1 << 7,
+};
+
+struct sio_reg {
+ bool extra_selector;
+ uint8_t idx;
+ uint8_t val;
+ uint8_t mask;
+};
+
+static const struct sio_reg ldn_reg_tbl[] = {
+ SIO_LDN(GLOBAL),
+ SIO_REG(0x27, 0x80), /* disable 0x80 port */
+ SIO_REG(0x2d, 0x2e), /* enable KB/Mouse wakeup, 2.8/2.5V hysteresis */
+ SIO_ESEL_27H(bank0, dis),
+ SIO_REG(0x29, 0xf0), /* set UART fn pins, TTL level */
+ SIO_REG(0x2a, 0x45), /* GPIO[10]->LED_VSB, GPIO[11]->LED_VCC */
+ SIO_REG(0x2c, 0xe3), /* en GPIO 00,01 */
+ SIO_ESEL_27H(bank2, dis),
+ SIO_REG(0x2b, 0x03), /* select pin 54 as SCL */
+ SIO_REG(0x2c, 0x01), /* GPIO[20]->ALERT# */
+ SIO_ESEL_27H(bank3, dis),
+ SIO_REG(0x28, 0x59), /* PLL_CNT = (256*48) / 89 = 138 */
+ SIO_ESEL_27H(bank0, en),
+ /*
+ * - GPIO[90]->LDRQ#, GPIO[91]->KBRST#, GPIO[92]->GA20, GPIO[93]->MDATA,
+ * - GPIO[94]->MCLK, GPIO[95]->FANIN1, GPIO[96]->FANIN2, GPIO[97]->SLCT
+ */
+ SIO_REG(0x2c, 0x00),
+ SIO_ESEL_27H(bank0, dis),
+
+ SIO_LDN(GPIO),
+ SIO_REG(0x60, 0x02),
+ SIO_REG(0x61, 0x80), /* base address */
+ SIO_REG(0xe0, 0x10), /* GPIO[14]->output mode */
+ SIO_REG(0xe3, 0x10), /* GPIO[14]->is push pull in output mode */
+ SIO_REG(0xe6, 0x10), /* GPIO[14]->SMI event will set if input is changed */
+ SIO_REG(0x80, 0xe0), /* GPIO[75,76,77]->is in output mode */
+ SIO_REG(0x81, 0xe0), /* GPIO[75,76,77]=1 */
+ SIO_REG(0x88, 0x01), /* GPIO[80]->is in output mode */
+ SIO_REG(0x89, 0x01), /* GPIO[80]=1 */
+ SIO_REG(0x8e, 0xff), /* GPIO[80,81,82,83,84,85,86,87]->use SMI event */
+ SIO_LDN_EN(0x01), /* enable GPIO I/O ports */
+
+ SIO_LDN(HWMON),
+ SIO_REG(0x60, SIO_HWM_BASE >> 8),
+ SIO_REG(0x61, SIO_HWM_BASE & 0xff),
+ SIO_LDN_EN(0x01), /* enable hardware monitor */
+
+ SIO_LDN(UART1),
+ SIO_REG(0xf6, 0x23), /* 128-byte FIFO, FIFO threshold will be 4X of RXFTHR */
+ SIO_LDN_EN(0x01),
+
+ SIO_LDN(UART2),
+ SIO_REG(0xf6, 0x23),
+ SIO_LDN_EN(0x01),
+
+ SIO_LDN(UART3),
+ SIO_REG(0xf6, 0x23),
+ SIO_LDN_EN(0x01),
+
+ SIO_LDN(UART4),
+ SIO_REG(0xf6, 0x23),
+ SIO_LDN_EN(0x01),
+};
+
+static const struct sio_reg hwm_reg_tbl[] = {
+ SIO_REG(0x07, 0x4a), /* MXM address */
+ SIO_REG(0x0a, 0x01), /* enable PECI access */
+ SIO_REG(0x0c, 0x64), /* TCC Temperature : CPU_TEMP = TCC_TEMP + PECI Reading */
+ SIO_REG(0x0f, 0x20), /* digital rate selector (Reserved for Fintek use only) */
+ SIO_REG(0x6b, 0x00), /* TEMP[1,2] is connected to a thermistor */
+ SIO_ESEL_9FH(bank0),
+ /*
+ * - FAN[1]->open drain, output PWM mode to control Intel 4-wire fans;
+ * - FAN[2]->push pull, output PWM mode to control fans;
+ * - FAN[3]->use linear fan application circuit to control speed by power terminal
+ */
+ SIO_REG(0x94, 0x12),
+ SIO_REG(0x9b, 0x1f), /* FAN[1,2]->duty update rate 20Hz */
+ SIO_ESEL_9FH(bank1),
+ SIO_REG(0x9b, 0x55), /* direct load enable for manual duty mode */
+ SIO_ESEL_9FH(bank0),
+
+ SIO_REG(0xa3, 0x75), /* FAN[1] expect PWM duty */
+ SIO_REG(0xa6, 70), /* VT[1] boundary 1 temperature */
+ SIO_REG(0xa7, 65), /* VT[1] boundary 2 temperature */
+ SIO_REG(0xa8, 55), /* VT[1] boundary 3 temperature */
+ SIO_REG(0xa9, 45), /* VT[1] boundary 4 temperature */
+ SIO_REG(0xaa, PWM_DC(100)), /* FAN[1] segment 1 speed count */
+ SIO_REG(0xab, PWM_DC(85)), /* FAN[1] segment 2 speed count */
+ SIO_REG(0xac, PWM_DC(70)), /* FAN[1] segment 3 speed count */
+ SIO_REG(0xad, PWM_DC(60)), /* FAN[1] segment 4 speed count */
+ SIO_REG(0xae, PWM_DC(50)), /* FAN[1] segment 5 speed count */
+ /*
+ * - FAN[1] follows PECI temperature;
+ * - FAN[1] duty will directly jump to the value of FAN1_SEG2;
+ * - FAN[1] duty will directly jump to the value of FAN1_SEG1;
+ * - enable the interpolation of the fan expect table;
+ * - [0,0,0]: 23.5 KHz;
+ */
+ SIO_REG(0xaf, 0x1c),
+ SIO_REG(0xb3, 0x75), /* FAN[2] expect PWM duty */
+ SIO_REG(0xb6, 70), /* VT[2] boundary 1 temperature */
+ SIO_REG(0xb7, 65), /* VT[2] boundary 2 temperature */
+ SIO_REG(0xb8, 55), /* VT[2] boundary 3 temperature */
+ SIO_REG(0xb9, 45), /* VT[2] boundary 4 temperature */
+ SIO_REG(0xba, PWM_DC(100)), /* FAN[2] segment 1 speed count 0xff */
+ SIO_REG(0xbb, PWM_DC(85)), /* FAN[2] segment 2 speed count 0xd9 */
+ SIO_REG(0xbc, PWM_DC(70)), /* FAN[2] segment 3 speed count 0xb2 */
+ SIO_REG(0xbd, PWM_DC(60)), /* FAN[2] segment 4 speed count 0x99 */
+ SIO_REG(0xbe, PWM_DC(50)), /* FAN[2] segment 5 speed count 0x75 */
+ /*
+ * - FAN[2] follows PECI temperature;
+ * - FAN[2] duty will directly jump to the value of FAN2_SEG2;
+ * - FAN[2] duty will directly jump to the value of FAN2_SEG1;
+ * - enable the interpolation of the fan expect table;
+ * - [0,0,0]: 23.5 KHz;
+ */
+ SIO_REG(0xbf, 0x1c),
+};
+
+static inline u8 sio_read(bool is_hwm, uint8_t idx)
+{
+ return is_hwm ? pnp_read_hwm5_index(SIO_HWM_BASE, idx) : pnp_read_index(SIO_PORT, idx);
+}
+
+static inline void sio_write(bool is_hwm, uint8_t idx, uint8_t val)
+{
+ is_hwm ? pnp_write_hwm5_index(SIO_HWM_BASE, idx, val) : pnp_write_index(SIO_PORT, idx, val);
+}
+
+static void sio_regs_setup(const struct sio_reg reg[], int size, bool is_hwm)
+{
+ for (int i = 0; i < size; i++) {
+ uint8_t val = reg[i].val;
+ if (reg[i].extra_selector) {
+ val = sio_read(is_hwm, reg[i].idx);
+ val &= reg[i].mask;
+ val |= reg[i].val;
+ }
+ sio_write(is_hwm, reg[i].idx, val);
+ }
+}
+
+void mainboard_superio_init(void)
+{
+ pnp_enter_conf_state(SIO_DEV(GLOBAL));
+ sio_regs_setup(ldn_reg_tbl, sizeof(ldn_reg_tbl)/sizeof(struct sio_reg), false);
+ pnp_exit_conf_state(SIO_DEV(GLOBAL));
+
+ sio_regs_setup(hwm_reg_tbl, sizeof(hwm_reg_tbl)/sizeof(struct sio_reg), true);
+}