summaryrefslogtreecommitdiff
path: root/src/superio/smsc/sch5545/sch5545_emi.c
diff options
context:
space:
mode:
authorMichał Żygowski <michal.zygowski@3mdeb.com>2020-04-13 20:51:32 +0200
committerMichał Żygowski <michal.zygowski@3mdeb.com>2020-05-16 17:37:29 +0000
commitfba08308f086d7b77f95554df094288fd55903d1 (patch)
treebbe7381c3b59178f9e830632755ee5dc27e91f53 /src/superio/smsc/sch5545/sch5545_emi.c
parent6191b85f8770ed807a5954339aef6c99609d7660 (diff)
downloadcoreboot-fba08308f086d7b77f95554df094288fd55903d1.tar.xz
superio/smsc/sch5545: add support for SMSC SCH5545
The SMSC SCH5545 is very similar to the publicly available datasheet for the SCH5627. TEST=use PS2 keyboard and mouse, serial port, runtime registers and Embedded Memory Interface on Dell Optiplex 9010 Signed-off-by: Michał Żygowski <michal.zygowski@3mdeb.com> Change-Id: If8a60d5802675f09b08014ed583d2d8afa29fc04 Reviewed-on: https://review.coreboot.org/c/coreboot/+/40350 Reviewed-by: Felix Held <felix-coreboot@felixheld.de> Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
Diffstat (limited to 'src/superio/smsc/sch5545/sch5545_emi.c')
-rw-r--r--src/superio/smsc/sch5545/sch5545_emi.c214
1 files changed, 214 insertions, 0 deletions
diff --git a/src/superio/smsc/sch5545/sch5545_emi.c b/src/superio/smsc/sch5545/sch5545_emi.c
new file mode 100644
index 0000000000..2bb150c69b
--- /dev/null
+++ b/src/superio/smsc/sch5545/sch5545_emi.c
@@ -0,0 +1,214 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+#include <assert.h>
+#include <arch/io.h>
+#include <device/pnp.h>
+#include <device/pnp_def.h>
+#include <device/pnp_ops.h>
+#include <superio/conf_mode.h>
+
+#include "sch5545.h"
+#include "sch5545_emi.h"
+
+static uint16_t emi_bar;
+
+#ifdef __SIMPLE_DEVICE__
+static void sch5545_enter_conf_state(pnp_devfn_t dev)
+{
+ unsigned int port = dev >> 8;
+ outb(0x55, port);
+}
+
+static void sch5545_exit_conf_state(pnp_devfn_t dev)
+{
+ unsigned int port = dev >> 8;
+ outb(0xaa, port);
+}
+#endif
+
+uint16_t sch5545_read_emi_bar(uint8_t sio_port)
+{
+ uint16_t bar;
+
+#ifdef __SIMPLE_DEVICE__
+ pnp_devfn_t lpcif = PNP_DEV(sio_port, SCH5545_LDN_LPC);
+ sch5545_enter_conf_state(lpcif);
+#else
+ struct device *lpcif = dev_find_slot_pnp(sio_port, SCH5545_LDN_LPC);
+ if (!lpcif)
+ return 0;
+ pnp_enter_conf_mode_55(lpcif);
+#endif
+ pnp_set_logical_device(lpcif);
+
+ bar = pnp_read_config(lpcif, SCH5545_BAR_EM_IF + 2);
+ bar |= pnp_read_config(lpcif, SCH5545_BAR_EM_IF + 3) << 8;
+
+#ifdef __SIMPLE_DEVICE__
+ sch5545_exit_conf_state(lpcif);
+#else
+ pnp_exit_conf_mode_aa(lpcif);
+#endif
+ return bar;
+}
+
+void sch5545_emi_init(uint8_t sio_port)
+{
+ emi_bar = sch5545_read_emi_bar(sio_port);
+ assert(emi_bar != 0);
+}
+
+void sch5545_emi_ec2h_mailbox_clear(void)
+{
+ sch5545_emi_ec2h_mbox_write(sch5545_emi_ec2h_mbox_read());
+}
+
+void sch5545_emi_disable_interrupts(void)
+{
+ sch5545_emi_set_int_mask(0);
+}
+
+void sch5545_emi_h2ec_mbox_write(uint8_t mbox_message)
+{
+ outb(mbox_message, emi_bar + SCH5545_EMI_HOST_TO_EC_MAILBOX);
+}
+
+uint8_t sch5545_emi_h2ec_mbox_read(void)
+{
+ return inb(emi_bar + SCH5545_EMI_HOST_TO_EC_MAILBOX);
+}
+
+void sch5545_emi_ec2h_mbox_write(uint8_t mbox_message)
+{
+ outb(mbox_message, emi_bar + SCH5545_EMI_EC_TO_HOST_MAILBOX);
+}
+
+uint8_t sch5545_emi_ec2h_mbox_read(void)
+{
+ return inb(emi_bar + SCH5545_EMI_EC_TO_HOST_MAILBOX);
+}
+
+void sch5545_emi_set_int_mask(uint16_t mask)
+{
+ outw(mask, emi_bar + SCH5545_EMI_INT_MASK);
+}
+
+void sch5545_emi_set_int_mask_low(uint8_t mask)
+{
+ outb(mask, emi_bar + SCH5545_EMI_INT_MASK);
+}
+
+void sch5545_emi_set_int_mask_high(uint8_t mask)
+{
+ outb(mask, emi_bar + SCH5545_EMI_INT_MASK + 1);
+}
+
+uint8_t sch5545_emi_get_int_mask_low(void)
+{
+ return inb(emi_bar + SCH5545_EMI_INT_MASK);
+}
+
+uint8_t sch5545_emi_get_int_mask_high(void)
+{
+ return inb(emi_bar + SCH5545_EMI_INT_MASK + 1);
+}
+
+uint16_t sch5545_emi_get_int_mask(void)
+{
+ return inw(emi_bar + SCH5545_EMI_INT_MASK);
+}
+
+void sch5545_emi_set_int_src_low(uint8_t int_src)
+{
+ outb(int_src, emi_bar + SCH5545_EMI_INT_SOURCE);
+}
+
+void sch5545_emi_set_int_src_high(uint8_t int_src)
+{
+ outb(int_src, emi_bar + SCH5545_EMI_INT_SOURCE + 1);
+}
+
+uint8_t sch5545_emi_get_int_src_low(void)
+{
+ return inb(emi_bar + SCH5545_EMI_INT_SOURCE);
+}
+
+uint8_t sch5545_emi_get_int_src_high(void)
+{
+ return inb(emi_bar + SCH5545_EMI_INT_SOURCE + 1);
+}
+uint16_t sch5545_emi_get_int_src(void)
+{
+ return inw(emi_bar + SCH5545_EMI_INT_SOURCE);
+}
+
+void sch5545_emi_set_int_src(uint16_t int_src)
+{
+ outw(int_src, emi_bar + SCH5545_EMI_INT_SOURCE);
+}
+
+void sch5545_emi_set_ec_addr(uint16_t addr)
+{
+ outw(addr, emi_bar + SCH5545_EMI_EC_ADDR);
+}
+
+uint16_t sch5545_emi_read_ec_addr(void)
+{
+ return inw(emi_bar + SCH5545_EMI_EC_ADDR);
+}
+
+void sch5545_emi_ec_write8(uint16_t addr, uint8_t data)
+{
+ sch5545_emi_set_ec_addr((addr & 0xfffc) | EMI_EC_8BIT_ACCESS);
+ outb(data, emi_bar + SCH5545_EMI_EC_DATA + (addr & 3));
+}
+
+void sch5545_emi_ec_write16(uint16_t addr, uint16_t data)
+{
+ sch5545_emi_set_ec_addr((addr & 0xfffc) | EMI_EC_16BIT_ACCESS);
+ outw(data, emi_bar + SCH5545_EMI_EC_DATA + (addr & 2));
+}
+
+void sch5545_emi_ec_write32(uint16_t addr, uint32_t data)
+{
+ sch5545_emi_set_ec_addr((addr & 0xfffc) | EMI_EC_32BIT_ACCESS);
+ outl(data, emi_bar + SCH5545_EMI_EC_DATA);
+}
+
+void sch5545_emi_ec_write32_bulk(uint16_t addr, const uint32_t *buffer, size_t len)
+{
+ sch5545_emi_set_ec_addr((addr & 0xfffc) | EMI_EC_32BIT_AUTO_ACCESS);
+
+ while (len > 0) {
+ outl(*(buffer++), emi_bar + SCH5545_EMI_EC_DATA);
+ len--;
+ }
+}
+
+uint8_t sch5545_emi_ec_read8(uint16_t addr)
+{
+ sch5545_emi_set_ec_addr((addr & 0xfffc) | EMI_EC_8BIT_ACCESS);
+ return inb(emi_bar + SCH5545_EMI_EC_DATA + (addr & 3));
+}
+
+uint16_t sch5545_emi_ec_read16(uint16_t addr)
+{
+ sch5545_emi_set_ec_addr((addr & 0xfffc) | EMI_EC_16BIT_ACCESS);
+ return inw(emi_bar + SCH5545_EMI_EC_DATA + (addr & 2));
+}
+
+uint32_t sch5545_emi_ec_read32(uint16_t addr)
+{
+ sch5545_emi_set_ec_addr((addr & 0xfffc) | EMI_EC_32BIT_ACCESS);
+ return inb(emi_bar + SCH5545_EMI_EC_DATA);
+}
+
+void sch5545_emi_ec_read32_bulk(uint16_t addr, uint32_t *buffer, size_t len)
+{
+ sch5545_emi_set_ec_addr((addr & 0xfffc) | EMI_EC_32BIT_AUTO_ACCESS);
+
+ while (len > 0) {
+ *(buffer++) = inl(emi_bar + SCH5545_EMI_EC_DATA);
+ len--;
+ }
+}