| /* SPDX-License-Identifier: GPL-2.0-only */ |
| |
| #include <assert.h> |
| #include <arch/io.h> |
| #include <device/pnp.h> |
| #include <device/pnp_ops.h> |
| #include <superio/conf_mode.h> |
| #include <types.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--; |
| } |
| } |