| #ifndef HPPA_H |
| #define HPPA_H |
| /* this file is included by x86.h */ |
| |
| /* version number of this SeaBIOS firmware */ |
| #define SEABIOS_HPPA_VERSION 15 |
| #define SEABIOS_HPPA_VERSION_STR "15" |
| |
| #ifdef __LP64__ |
| #define CONFIG_64BIT |
| #endif |
| |
| #include "parisc/hppa_hardware.h" |
| |
| #ifndef __ASSEMBLY__ |
| |
| #include "types.h" // u32 |
| #include "byteorder.h" // le16_to_cpu |
| |
| /* Pointer to zero-page of PA-RISC */ |
| #define PAGE0 ((struct zeropage *) 0UL) |
| |
| #define PSW_I 0x00000001 |
| |
| static inline unsigned long arch_local_save_flags(void) |
| { |
| unsigned long flags; |
| asm volatile("ssm 0, %0" : "=r" (flags) : : "memory"); |
| return flags; |
| } |
| |
| static inline void arch_local_irq_disable(void) |
| { |
| asm volatile("rsm %0,%%r0\n" : : "i" (PSW_I) : "memory"); |
| } |
| |
| static inline void arch_local_irq_enable(void) |
| { |
| asm volatile("ssm %0,%%r0\n" : : "i" (PSW_I) : "memory"); |
| } |
| |
| static inline unsigned long arch_local_irq_save(void) |
| { |
| unsigned long flags; |
| asm volatile("rsm %1,%0" : "=r" (flags) : "i" (PSW_I) : "memory"); |
| return flags; |
| } |
| |
| static inline void arch_local_irq_restore(unsigned long flags) |
| { |
| asm volatile("mtsm %0" : : "r" (flags) : "memory"); |
| } |
| |
| static inline void irq_disable(void) |
| { |
| arch_local_irq_disable(); |
| } |
| |
| static inline void irq_enable(void) |
| { |
| arch_local_irq_enable(); |
| } |
| |
| static inline u32 save_flags(void) |
| { |
| return arch_local_irq_save(); |
| } |
| |
| static inline void restore_flags(u32 flags) |
| { |
| arch_local_irq_restore(flags); |
| } |
| |
| |
| |
| static inline void cpu_relax(void) |
| { |
| asm volatile("nop": : :"memory"); |
| } |
| |
| static inline void nop(void) |
| { |
| asm volatile("nop"); |
| } |
| |
| extern void hlt(void); |
| |
| static inline void wbinvd(void) |
| { |
| asm volatile("sync": : :"memory"); |
| } |
| |
| #define mfctl(reg) ({ \ |
| unsigned long cr; \ |
| __asm__ __volatile__( \ |
| "mfctl %1,%0" : \ |
| "=r" (cr) : "i" (reg) \ |
| ); \ |
| cr; \ |
| }) |
| |
| #define mtctl(gr, cr) \ |
| __asm__ __volatile__("mtctl %0,%1" \ |
| : /* no outputs */ \ |
| : "r" (gr), "i" (cr) : "memory") |
| |
| /* these are here to de-mystefy the calling code, and to provide hooks */ |
| /* which I needed for debugging EIEM problems -PB */ |
| #define get_eiem() mfctl(15) |
| static inline void set_eiem(unsigned long val) |
| { |
| mtctl(val, 15); |
| } |
| |
| #define mfsp(reg) ({ \ |
| unsigned long cr; \ |
| __asm__ __volatile__( \ |
| "mfsp " #reg ",%0" : \ |
| "=r" (cr) \ |
| ); \ |
| cr; \ |
| }) |
| |
| #define mtsp(val, cr) \ |
| { if (__builtin_constant_p(val) && ((val) == 0)) \ |
| __asm__ __volatile__("mtsp %%r0,%0" : : "i" (cr) : "memory"); \ |
| else \ |
| __asm__ __volatile__("mtsp %0,%1" \ |
| : /* no outputs */ \ |
| : "r" (val), "i" (cr) : "memory"); } |
| |
| static inline unsigned long rdtscll(void) |
| { |
| return mfctl(16); |
| } |
| |
| static inline u32 __ffs(u32 x) |
| { |
| unsigned long ret; |
| |
| if (!x) |
| return 0; |
| |
| __asm__( |
| #ifdef CONFIG_64BIT |
| " ldi 63,%1\n" |
| " extrd,u,*<> %0,63,32,%%r0\n" |
| " extrd,u,*TR %0,31,32,%0\n" /* move top 32-bits down */ |
| " addi -32,%1,%1\n" |
| #else |
| " ldi 31,%1\n" |
| #endif |
| " extru,<> %0,31,16,%%r0\n" |
| " extru,TR %0,15,16,%0\n" /* xxxx0000 -> 0000xxxx */ |
| " addi -16,%1,%1\n" |
| " extru,<> %0,31,8,%%r0\n" |
| " extru,TR %0,23,8,%0\n" /* 0000xx00 -> 000000xx */ |
| " addi -8,%1,%1\n" |
| " extru,<> %0,31,4,%%r0\n" |
| " extru,TR %0,27,4,%0\n" /* 000000x0 -> 0000000x */ |
| " addi -4,%1,%1\n" |
| " extru,<> %0,31,2,%%r0\n" |
| " extru,TR %0,29,2,%0\n" /* 0000000y, 1100b -> 0011b */ |
| " addi -2,%1,%1\n" |
| " extru,= %0,31,1,%%r0\n" /* check last bit */ |
| " addi -1,%1,%1\n" |
| : "+r" (x), "=r" (ret) ); |
| return ret; |
| } |
| |
| static inline u32 __fls(u32 x) |
| { |
| int ret; |
| if (!x) |
| return 0; |
| |
| __asm__( |
| " ldi 1,%1\n" |
| " extru,<> %0,15,16,%%r0\n" |
| " zdep,TR %0,15,16,%0\n" /* xxxx0000 */ |
| " addi 16,%1,%1\n" |
| " extru,<> %0,7,8,%%r0\n" |
| " zdep,TR %0,23,24,%0\n" /* xx000000 */ |
| " addi 8,%1,%1\n" |
| " extru,<> %0,3,4,%%r0\n" |
| " zdep,TR %0,27,28,%0\n" /* x0000000 */ |
| " addi 4,%1,%1\n" |
| " extru,<> %0,1,2,%%r0\n" |
| " zdep,TR %0,29,30,%0\n" /* y0000000 (y&3 = 0) */ |
| " addi 2,%1,%1\n" |
| " extru,= %0,0,1,%%r0\n" |
| " addi 1,%1,%1\n" /* if y & 8, add 1 */ |
| : "+r" (x), "=r" (ret) ); |
| |
| return ret; |
| } |
| |
| static inline u32 rol(u32 val, u16 rol) { |
| u32 res, resr; |
| res = val << rol; |
| resr = val >> (32-rol); |
| res |= resr; |
| return res; |
| } |
| |
| static inline u32 ror(u32 word, unsigned int shift) |
| { |
| return (word >> (shift & 31)) | (word << ((-shift) & 31)); |
| } |
| |
| |
| /* F_EXTEND() is used to access I/O ports. ROM_EXTEND() to access firmware ROM/RAM */ |
| #if defined(__LP64__) |
| #define F_EXTEND(x) ((unsigned long)(0xfffffffful<<32) | (x)) |
| #define ROM_EXTEND(x) ((unsigned long)(0xfffffff0ul<<32) | (x)) |
| #else |
| #define F_EXTEND(x) ((unsigned long)(x)) |
| #define ROM_EXTEND(x) ((unsigned long)(x)) |
| #endif |
| |
| static inline void builtin_console_out(char c) |
| { |
| asm volatile("copy %0,%%r26 ! diag 0x101" : : "r" (c) : "r26"); |
| } |
| |
| |
| extern char has_astro; /* false for B160L machine with Dino PCI chip */ |
| extern unsigned long hppa_port_pci_cmd; |
| extern unsigned long hppa_port_pci_data; |
| |
| |
| #define pci_ioport_addr(port) ((port >= 0x1000) && (port < FIRMWARE_START)) |
| #define is_astro_ioport(port) (has_astro && (port < IOS_DIST_BASE_SIZE)) |
| |
| #define astro_ioport_addr(port) ((void *)(portaddr_t) F_EXTEND(IOS_DIST_BASE_ADDR + port)) |
| |
| /* inb()/outb() accesses little-endian memory and does byteswapping to host endianess */ |
| |
| static inline void outl(u32 value, portaddr_t port) { |
| if (is_astro_ioport(port)) |
| *(volatile u32 *)(astro_ioport_addr(port)) = cpu_to_le32(value); |
| else |
| if (!pci_ioport_addr(port)) { |
| *(volatile u32 *)(port) = be32_to_cpu(value); |
| } else { |
| /* write PCI I/O address to Dino's PCI_CONFIG_ADDR */ |
| *(volatile u32 *)(DINO_HPA + 0x064) = port; |
| /* write value to PCI_IO_DATA */ |
| *(volatile u32 *)(DINO_HPA + 0x06c) = cpu_to_le32(value); |
| } |
| } |
| |
| static inline void outw(u16 value, portaddr_t port) { |
| if (is_astro_ioport(port)) |
| *(volatile u16 *)(astro_ioport_addr(port)) = cpu_to_le16(value); |
| else |
| if (!pci_ioport_addr(port)) { |
| *(volatile u16 *)(port) = be16_to_cpu(value); |
| } else { |
| /* write PCI I/O address to Dino's PCI_CONFIG_ADDR */ |
| *(volatile u32 *)(DINO_HPA + 0x064) = port; |
| /* write value to PCI_IO_DATA */ |
| *(volatile u16 *)(DINO_HPA + 0x06c) = cpu_to_le16(value); |
| } |
| } |
| |
| static inline void outb(u8 value, portaddr_t port) { |
| if (is_astro_ioport(port)) |
| *(volatile u8 *)(astro_ioport_addr(port)) = value; |
| else |
| if (!pci_ioport_addr(port)) { |
| *(volatile u8 *)(port) = value; |
| } else { |
| /* write PCI I/O address to Dino's PCI_CONFIG_ADDR */ |
| *(volatile u32 *)(DINO_HPA + 0x064) = port & ~3U; |
| /* write value to PCI_IO_DATA */ |
| *(volatile u8 *)(DINO_HPA + 0x06c + (port & 3)) = value; |
| } |
| } |
| |
| static inline u8 inb(portaddr_t port) { |
| if (is_astro_ioport(port)) |
| return *(volatile u8 *)(astro_ioport_addr(port)); |
| else |
| if (has_astro || !pci_ioport_addr(port)) { |
| return *(volatile u8 *)(port); |
| } else { |
| /* write PCI I/O address to Dino's PCI_CONFIG_ADDR */ |
| *(volatile u32 *)(DINO_HPA + 0x064) = port & ~3U; |
| /* read value to PCI_IO_DATA */ |
| return *(volatile u8 *)(DINO_HPA + 0x06c + (port & 3)); |
| } |
| } |
| |
| static inline u16 inw(portaddr_t port) { |
| if (is_astro_ioport(port)) |
| return le16_to_cpu(*(volatile u16 *)(astro_ioport_addr(port))); |
| else |
| if (!pci_ioport_addr(port)) { |
| return *(volatile u16 *)(port); |
| } else { |
| /* write PCI I/O address to Dino's PCI_CONFIG_ADDR */ |
| *(volatile u32 *)(DINO_HPA + 0x064) = port & ~3U; |
| /* read value to PCI_IO_DATA */ |
| return le16_to_cpu(*(volatile u16 *)(DINO_HPA + 0x06c + (port & 3U))); |
| } |
| } |
| static inline u32 inl(portaddr_t port) { |
| if (is_astro_ioport(port)) |
| return le32_to_cpu(*(volatile u32 *)(astro_ioport_addr(port))); |
| else |
| if (!pci_ioport_addr(port)) { |
| return *(volatile u32 *)(port); |
| } else { |
| /* write PCI I/O address to Dino's PCI_CONFIG_ADDR */ |
| *(volatile u32 *)(DINO_HPA + 0x064) = port; |
| /* read value to PCI_IO_DATA */ |
| return le32_to_cpu(*(volatile u32 *)(DINO_HPA + 0x06c)); |
| } |
| } |
| |
| static inline void insb(portaddr_t port, u8 *data, u32 count) { |
| while (count--) |
| *data++ = inb(port); |
| } |
| static inline void insw(portaddr_t port, u16 *data, u32 count) { |
| while (count--) |
| *data++ = inw(port); |
| } |
| static inline void insl(portaddr_t port, u32 *data, u32 count) { |
| while (count--) |
| *data++ = inl(port); |
| } |
| // XXX - outs not limited to es segment |
| static inline void outsb(portaddr_t port, u8 *data, u32 count) { |
| while (count--) |
| outb(*data++, port); |
| } |
| static inline void outsw(portaddr_t port, u16 *data, u32 count) { |
| while (count--) { |
| outw(*data, port); |
| data++; |
| } |
| } |
| static inline void outsl(portaddr_t port, u32 *data, u32 count) { |
| while (count--) { |
| outl(*data, port); |
| data++; |
| } |
| } |
| |
| /* Compiler barrier is enough as an x86 CPU does not reorder reads or writes */ |
| static inline void smp_rmb(void) { |
| barrier(); |
| } |
| static inline void smp_wmb(void) { |
| barrier(); |
| } |
| |
| /* readX()/writeX() do byteswapping */ |
| |
| static inline void writel(void *addr, u32 val) { |
| barrier(); |
| *(volatile u32 *)addr = cpu_to_le32(val); |
| } |
| static inline void writew(void *addr, u16 val) { |
| barrier(); |
| *(volatile u16 *)addr = cpu_to_le16(val); |
| } |
| static inline void writeb(void *addr, u8 val) { |
| barrier(); |
| *(volatile u8 *)addr = val; |
| } |
| static inline u64 readq(const void *addr) { |
| u64 val = *(volatile const u64 *)addr; |
| barrier(); |
| return le64_to_cpu(val); |
| } |
| static inline u32 readl(const void *addr) { |
| u32 val = *(volatile const u32 *)addr; |
| barrier(); |
| return le32_to_cpu(val); |
| } |
| static inline u16 readw(const void *addr) { |
| u16 val = *(volatile const u16 *)addr; |
| barrier(); |
| return le16_to_cpu(val); |
| } |
| static inline u8 readb(const void *addr) { |
| u8 val = *(volatile const u8 *)addr; |
| barrier(); |
| return val; |
| } |
| |
| /* gsc_readX()/gsc_writeX() do no byteswapping */ |
| |
| static inline void gsc_writel(void *addr, u32 val) { |
| barrier(); |
| *(volatile u32 *)addr = val; |
| } |
| static inline void gsc_writeb(void *addr, u8 val) { |
| barrier(); |
| *(volatile u8 *)addr = val; |
| } |
| static inline u32 gsc_readl(const void *addr) { |
| u32 val = *(volatile const u32 *)addr; |
| barrier(); |
| return val; |
| } |
| static inline u8 gsc_readb(const void *addr) { |
| u8 val = *(volatile const u8 *)addr; |
| barrier(); |
| return val; |
| } |
| |
| // FLASH_FLOPPY not supported |
| #define GDT_CODE (0) |
| #define GDT_DATA (0) |
| #define GDT_B (0) |
| #define GDT_G (0) |
| #define GDT_BASE(v) ((v) & 0) |
| #define GDT_LIMIT(v) ((v) & 0) |
| #define GDT_GRANLIMIT(v) ((v) & 0) |
| |
| static inline u8 get_a20(void) { |
| return 0; |
| } |
| |
| static inline u8 set_a20(u8 cond) { |
| return 0; |
| } |
| |
| static inline void wrmsr(u32 index, u64 val) |
| { |
| } |
| |
| // x86.c |
| void cpuid(u32 index, u32 *eax, u32 *ebx, u32 *ecx, u32 *edx); |
| |
| // pci.c |
| unsigned long elroy_offset(u16 bdf); |
| void *elroy_port(unsigned long port, unsigned long offs); |
| |
| #endif // !__ASSEMBLY__ |
| #endif |