linux/arch/e2k/boot/bios/io.c

624 lines
14 KiB
C

#include "pci.h"
#include <asm/types.h>
#include <asm/e2k_api.h>
#include <asm/head.h>
#include "../boot_io.h"
#undef DEBUG_IO
#undef DebugIO
#define DEBUG_IO 0
#define DebugIO if (DEBUG_IO) rom_printk
#undef DEBUG_IOH
#undef DebugIOH
#define DEBUG_IOH 0
#define DebugIOH if (DEBUG_IOH) rom_printk
#ifdef CONFIG_E2K_SIC
#define es2_domain_pci_conf_base(domain) (ES2_PCICFG_AREA_PHYS_BASE + \
ES2_PCICFG_AREA_SIZE * ((unsigned long) domain))
#define e2s_domain_pci_conf_base(domain) (E2S_PCICFG_AREA_PHYS_BASE + \
E2S_PCICFG_AREA_SIZE * ((unsigned long) domain))
#define e8c_domain_pci_conf_base(domain) (E8C_PCICFG_AREA_PHYS_BASE + \
E8C_PCICFG_AREA_SIZE * ((unsigned long) domain))
#define e1cp_domain_pci_conf_base(domain) (E1CP_PCICFG_AREA_PHYS_BASE)
#define e8c2_domain_pci_conf_base(domain) (E8C2_PCICFG_AREA_PHYS_BASE + \
E8C2_PCICFG_AREA_SIZE * ((unsigned long) domain))
#define e12c_domain_pci_conf_base(domain) (E12C_PCICFG_AREA_PHYS_BASE + \
E12C_PCICFG_AREA_SIZE * ((unsigned long) domain))
#define e16c_domain_pci_conf_base(domain) (E16C_PCICFG_AREA_PHYS_BASE + \
E16C_PCICFG_AREA_SIZE * ((unsigned long) domain))
#define e2c3_domain_pci_conf_base(domain) (E2C3_PCICFG_AREA_PHYS_BASE + \
E2C3_PCICFG_AREA_SIZE * ((unsigned long) domain))
static inline unsigned long bios_get_domain_pci_conf_base(unsigned int domain)
{
unsigned long conf_base;
#if defined(CONFIG_ES2)
conf_base = es2_domain_pci_conf_base(domain);
#elif defined(CONFIG_E2S)
conf_base = e2s_domain_pci_conf_base(domain);
#elif defined(CONFIG_E8C)
conf_base = e8c_domain_pci_conf_base(domain);
#elif defined(CONFIG_E8C2)
conf_base = e8c2_domain_pci_conf_base(domain);
#elif defined(CONFIG_E12C)
conf_base = e12c_domain_pci_conf_base(domain);
#elif defined(CONFIG_E16C)
conf_base = e16c_domain_pci_conf_base(domain);
#elif defined(CONFIG_E2C3)
conf_base = e2c3_domain_pci_conf_base(domain);
#else
#error "Invalid e2k machine type"
#endif /* CONFIG_E3S */
return (conf_base);
}
unsigned char bios_conf_inb(int domain, unsigned char bus, unsigned long port)
{
unsigned char byte;
unsigned long conf_base;
conf_base = bios_get_domain_pci_conf_base(domain);
port = conf_base + port;
byte = NATIVE_READ_MAS_B(port, MAS_IOADDR);
DebugIO("conf_inb(): value %x read from port %x\n",
(int) byte, (int) port);
return byte;
}
#endif
unsigned char bios_inb(unsigned short port)
{
unsigned char byte;
DebugIO("bios_inb entered.\n");
byte = NATIVE_READ_MAS_B(PHYS_X86_IO_BASE + port, MAS_IOADDR);
DebugIO("value %x read from port %x\n", (int) byte, (int) port);
DebugIO("bios_inb exited.\n");
return byte;
}
unsigned char bios_inb_p(unsigned long port)
{
unsigned char byte;
DebugIO("bios_inb_p entered.\n");
byte = NATIVE_READ_MAS_B(PHYS_X86_IO_BASE + port, MAS_IOADDR);
DebugIO("bios_inb_p exited.\n");
return byte;
}
void bios_outb_p(unsigned char byte, unsigned long port)
{
DebugIO("bios_outb_p entered.\n");
NATIVE_WRITE_MAS_B(PHYS_X86_IO_BASE + port, byte, MAS_IOADDR);
DebugIO("bios_outb_p exited.\n");
}
#ifdef CONFIG_E2K_SIC
void bios_conf_outb(int domain, unsigned char bus, unsigned char byte,
unsigned long port)
{
unsigned long conf_base;
conf_base = bios_get_domain_pci_conf_base(domain);
port = conf_base + port;
DebugIO("conf_outb(): port = %x\n", (int) port);
NATIVE_WRITE_MAS_B(port, byte, MAS_IOADDR);
DebugIO("conf_outb exited.\n");
}
void bios_ioh_e3s_outb(int domain, unsigned char bus, unsigned char byte,
unsigned long port)
{
unsigned long addr;
addr = IOHUB_SCRB_DOMAIN_START(domain);
addr += port;
NATIVE_WRITE_MAS_B(addr, byte, MAS_IOADDR);
DebugIOH("ioh_e3s_outb write 0x%x to domain %d bus 0x%x, port = 0x%x.\n",
byte, domain, bus, addr);
}
u8 bios_ioh_e3s_inb(int domain, unsigned char bus, unsigned long port)
{
unsigned long addr;
u8 byte;
addr = IOHUB_SCRB_DOMAIN_START(domain);
addr += port;
byte = NATIVE_READ_MAS_B(addr, MAS_IOADDR);
DebugIOH("bios_ioh_e3s_inb() read 0x%x from domain %d bus 0x%x, "
"port = 0x%x\n",
byte, domain, bus, addr);
return (byte);
}
#endif
void bios_outb(unsigned char byte, unsigned short port)
{
DebugIO("outb entered.\n");
NATIVE_WRITE_MAS_B(PHYS_X86_IO_BASE + port, byte, MAS_IOADDR);
DebugIO("outb exited.\n");
}
#ifdef CONFIG_E2K_SIC
void bios_conf_outw(int domain, unsigned char bus, u16 halfword,
unsigned long port)
{
unsigned long conf_base;
conf_base = bios_get_domain_pci_conf_base(domain);
port = conf_base + port;
DebugIO("conf_outw(): port = %x\n", (int) port);
NATIVE_WRITE_MAS_H(port, halfword, MAS_IOADDR);
DebugIO("conf_outw exited.\n");
}
void bios_ioh_e3s_outw(int domain, unsigned char bus, u16 halfword,
unsigned long port)
{
unsigned long addr;
addr = IOHUB_SCRB_DOMAIN_START(domain);
addr += port;
NATIVE_WRITE_MAS_H(addr, halfword, MAS_IOADDR);
DebugIOH("ioh_e3s_outw write 0x%x to domain %d bus 0x%x, port = 0x%x\n",
halfword, domain, bus, addr);
}
u16 bios_ioh_e3s_inw(int domain, unsigned char bus, unsigned long port)
{
unsigned long addr;
u16 halfword;
addr = IOHUB_SCRB_DOMAIN_START(domain);
addr += port;
halfword = NATIVE_READ_MAS_B(addr, MAS_IOADDR);
DebugIOH("bios_ioh_e3s_inw() read 0x%x from domain %d bus 0x%x, "
"port = 0x%x\n",
halfword, domain, bus, addr);
return (halfword);
}
#endif
void bios_outw(u16 halfword, unsigned short port)
{
DebugIO("outw entered.\n");
NATIVE_WRITE_MAS_H(PHYS_X86_IO_BASE + port, halfword, MAS_IOADDR);
DebugIO("outw exited.\n");
}
void bios_outw_p(u16 halfword, unsigned long port)
{
DebugIO("outw_p entered.\n");
NATIVE_WRITE_MAS_H(PHYS_X86_IO_BASE + port, halfword, MAS_IOADDR);
DebugIO("outw_p exited.\n");
}
#ifdef CONFIG_E2K_SIC
u16 bios_conf_inw(int domain, unsigned char bus, unsigned long port)
{
u16 hword;
unsigned long conf_base;
conf_base = bios_get_domain_pci_conf_base(domain);
port = conf_base + port;
hword = NATIVE_READ_MAS_H(port, MAS_IOADDR);
DebugIO("conf_inw(): value %x read from port %x\n",hword, (int)port);
DebugIO("conf_inw exited.\n");
return hword;
}
#endif
u16 bios_inw(unsigned short port)
{
u16 hword;
DebugIO("inw entered.\n");
hword = NATIVE_READ_MAS_H(PHYS_X86_IO_BASE + port, MAS_IOADDR);
DebugIO("inw exited.\n");
return hword;
}
u16 bios_inw_p(unsigned long port)
{
u16 hword;
DebugIO("inw_p entered.\n");
hword = NATIVE_READ_MAS_H(PHYS_X86_IO_BASE + port, MAS_IOADDR);
DebugIO("inw_p exited.\n");
return hword;
}
/*
* 'unsigned long' for I/O means 'u32', because IN/OUT ops are IA32-specific
*/
#ifdef CONFIG_E2K_SIC
void bios_conf_outl(int domain, unsigned char bus, u32 word, unsigned long port)
{
unsigned long conf_base;
conf_base = bios_get_domain_pci_conf_base(domain);
port = conf_base + port;
NATIVE_WRITE_MAS_W(port, word, MAS_IOADDR);
DebugIO("conf_outl exited.\n");
}
u32 bios_conf_inl(int domain, unsigned char bus, unsigned long port)
{
u32 word;
unsigned long conf_base;
conf_base = bios_get_domain_pci_conf_base(domain);
port = conf_base + port;
word = NATIVE_READ_MAS_W(port, MAS_IOADDR);
DebugIO("conf_inl(): value %x read from port %x\n",
(int) word, (int) port);
DebugIO("conf_inl exited.\n");
return word;
}
void bios_ioh_e3s_outl(int domain, unsigned char bus, u32 word,
unsigned long port)
{
unsigned long addr;
addr = IOHUB_SCRB_DOMAIN_START(domain);
addr += port;
NATIVE_WRITE_MAS_W(addr, word, MAS_IOADDR);
DebugIOH("ioh_e3s_outl write 0x%x to domain %d bus 0x%x, port = 0x%x\n",
word, domain, bus, addr);
}
u32 bios_ioh_e3s_inl(int domain, unsigned char bus, unsigned long port)
{
unsigned long addr;
u32 word;
addr = IOHUB_SCRB_DOMAIN_START(domain);
addr += port;
word = NATIVE_READ_MAS_W(addr, MAS_IOADDR);
DebugIOH("bios_ioh_e3s_inl read 0x%x from domain %d bus 0x%x, "
"port = 0x%x\n",
word, domain, bus, addr);
return (word);
}
#endif
void bios_outl(u32 word, unsigned short port)
{
DebugIO("outl entered.\n");
NATIVE_WRITE_MAS_W(PHYS_X86_IO_BASE + port, word, MAS_IOADDR);
DebugIO("outl exited.\n");
}
u32 bios_inl(unsigned short port)
{
u32 word;
DebugIO("inl entered.\n");
word = NATIVE_READ_MAS_W(PHYS_X86_IO_BASE + port, MAS_IOADDR);
DebugIO("inl(): value %x read from port %x\n", (int) word, (int) port);
DebugIO("inl exited.\n");
return word;
}
void bios_outll(unsigned long data, unsigned short port)
{
DebugIO("outb entered.\n");
NATIVE_WRITE_MAS_D(PHYS_X86_IO_BASE + port, data, MAS_IOADDR);
DebugIO("outb exited.\n");
}
unsigned long bios_inll(unsigned short port)
{
unsigned long dword;
DebugIO("inl entered.\n");
dword = NATIVE_READ_MAS_D(PHYS_X86_IO_BASE + port, MAS_IOADDR);
DebugIO("inl(): value %lx read from port %x\n",
(unsigned long)dword, (int)port);
DebugIO("inl exited.\n");
return dword;
}
static inline void fast_outw_p(u16 halfword, unsigned long port)
{
NATIVE_WRITE_MAS_H(PHYS_X86_IO_BASE + port, halfword, MAS_IOADDR);
}
void bios_outsw(unsigned long port, const void *src, unsigned long count)
{
u16 *hw_p = (u16 *)src;
DebugIO("outsw entered.\n");
DebugIO("outsw(): port=%lx src=%px count=%lx\n", port, src, count);
if (((unsigned long)src) & 0x1) {
rom_printk("outsw: memory address is not short aligned");
}
if (!count)
return;
while (count--) {
fast_outw_p(*hw_p++, port);
}
DebugIO("outsw exited.\n");
}
static inline u16 fast_inw_p(unsigned long port)
{
return NATIVE_READ_MAS_H(PHYS_X86_IO_BASE + port, MAS_IOADDR);
}
void bios_insw(unsigned long port, void *dst, unsigned long count)
{
u16 *hw_p = (u16 *)dst;
DebugIO("insw entered.\n");
DebugIO("insw(): port=%lx dst=%px count=%lx\n",port, dst, count);
if (((unsigned long)dst) & 0x1) {
rom_printk("insw: memory address is not short aligned");
}
if (!count)
return;
while (count--) {
*hw_p++ = fast_inw_p(port);
}
DebugIO("insw exited.\n");
}
/*
* Read COUNT 32-bit words from port PORT into memory starting at
* SRC. Now works with any alignment in SRC. Performance is important,
* but the interfaces seems to be slow: just using the inlined version
* of the bios_inl() breaks things.
*
* The source code was taken from Alpha's lib/io.c
*/
void bios_insl(unsigned long port, void *dst, unsigned long count)
{
unsigned int l = 0, l2;
if (!count)
return;
switch (((unsigned long) dst) & 0x3)
{
case 0x00: /* Buffer 32-bit aligned */
while (count--)
{
*(unsigned int *) dst = bios_inl(port);
dst += 4;
}
break;
/* Assuming little endian in cases 0x01 -- 0x03 ... */
case 0x02: /* Buffer 16-bit aligned */
--count;
l = bios_inl(port);
*(unsigned short *) dst = l;
dst += 2;
while (count--)
{
l2 = bios_inl(port);
*(unsigned int *) dst = l >> 16 | l2 << 16;
dst += 4;
l = l2;
}
*(unsigned short *) dst = l >> 16;
break;
case 0x01: /* Buffer 8-bit aligned */
--count;
l = bios_inl(port);
*(unsigned char *) dst = l;
dst += 1;
*(unsigned short *) dst = l >> 8;
dst += 2;
while (count--)
{
l2 = bios_inl(port);
*(unsigned int *) dst = l >> 24 | l2 << 8;
dst += 4;
l = l2;
}
*(unsigned char *) dst = l >> 24;
break;
case 0x03: /* Buffer 8-bit aligned */
--count;
l = bios_inl(port);
*(unsigned char *) dst = l;
dst += 1;
while (count--)
{
l2 = bios_inl(port);
*(unsigned int *) dst = l << 24 | l2 >> 8;
dst += 4;
l = l2;
}
*(unsigned short *) dst = l >> 8;
dst += 2;
*(unsigned char *) dst = l >> 24;
break;
}
}
/*
* Like insl but in the opposite direction. This is used by the IDE
* driver to write disk sectors. Works with any alignment in SRC.
* Performance is important, but the interfaces seems to be slow:
* just using the inlined version of the outl() breaks things.
*
* The source code was taken from Alpha's lib/io.c
*/
void bios_outsl(unsigned long port, const void *src, unsigned long count)
{
unsigned int l = 0, l2;
if (!count)
return;
switch (((unsigned long) src) & 0x3)
{
case 0x00: /* Buffer 32-bit aligned */
while (count--)
{
bios_outl(*(unsigned int *) src, port);
src += 4;
}
break;
case 0x02: /* Buffer 16-bit aligned */
--count;
l = *(unsigned short *) src << 16;
src += 2;
while (count--)
{
l2 = *(unsigned int *) src;
src += 4;
bios_outl(l >> 16 | l2 << 16, port);
l = l2;
}
l2 = *(unsigned short *) src;
bios_outl(l >> 16 | l2 << 16, port);
break;
case 0x01: /* Buffer 8-bit aligned */
--count;
l = *(unsigned char *) src << 8;
src += 1;
l |= *(unsigned short *) src << 16;
src += 2;
while (count--)
{
l2 = *(unsigned int *) src;
src += 4;
bios_outl(l >> 8 | l2 << 24, port);
l = l2;
}
l2 = *(unsigned char *) src;
bios_outl(l >> 8 | l2 << 24, port);
break;
case 0x03: /* Buffer 8-bit aligned */
--count;
l = *(unsigned char *) src << 24;
src += 1;
while (count--)
{
l2 = *(unsigned int *) src;
src += 4;
bios_outl(l >> 24 | l2 << 8, port);
l = l2;
}
l2 = *(unsigned short *) src;
src += 2;
l2 |= *(unsigned char *) src << 16;
bios_outl(l >> 24 | l2 << 8, port);
break;
}
}
/*
* Read COUNT 8-bit bytes from port PORT into memory starting at
* SRC.
*
* The source code was taken from Alpha's lib/io.c
*/
void bios_insb(unsigned long port, void *dst, unsigned long count)
{
while (((unsigned long)dst) & 0x3) {
if (!count)
return;
count--;
*(unsigned char *) dst = bios_inb(port);
dst += 1;
}
while (count >= 4) {
unsigned int w;
count -= 4;
w = bios_inb(port);
w |= bios_inb(port) << 8;
w |= bios_inb(port) << 16;
w |= bios_inb(port) << 24;
*(unsigned int *) dst = w;
dst += 4;
}
while (count) {
--count;
*(unsigned char *) dst = bios_inb(port);
dst += 1;
}
}
/*
* Like insb but in the opposite direction.
* Don't worry as much about doing aligned memory transfers:
* doing byte reads the "slow" way isn't nearly as slow as
* doing byte writes the slow way (no r-m-w cycle).
*
* The source code was taken from Alpha's lib/io.c
*/
void bios_outsb(unsigned long port, const void *src, unsigned long count)
{
while (count) {
count--;
bios_outb(*(char *)src, port);
src += 1;
}
}