You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

595 lines
16 KiB

/*
* Modifications to support Loongson Arch:
* Copyright (c) 2008 Lemote. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice unmodified, this list of conditions, and the following
* disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
*/
/*
* VESA framebuffer support. Author: Lj.Peng <penglj@lemote.com>
*/
#include <stdio.h>
#include <stdlib.h>
#include <dev/pci/pcivar.h>
#include "xf86int10.h"
#include "xf86x86emu.h"
#include "linux/io.h"
#include "mod_framebuffer.h"
#include "vesa.h"
#include <mod_sisfb.h>
//#include "bonito.h"
extern struct pci_device *vga_dev,*pcie_dev;
int vesa_mode = 1;
/*
* The following macros are especially useful for __asm__
* inline assembler.
*/
#ifndef __STR
#define __STR(x) #x
#endif
#ifndef STR
#define STR(x) __STR(x)
#endif
/*
* Configure language
*/
#ifdef __ASSEMBLY__
#define _ULCAST_
#else
#define _ULCAST_ (unsigned long)
#endif
/*
* Coprocessor 0 register names
*/
#define CP0_INDEX $0
#define CP0_RANDOM $1
#define CP0_ENTRYLO0 $2
#define CP0_ENTRYLO1 $3
#define CP0_CONF $3
#define CP0_CONTEXT $4
#define CP0_PAGEMASK $5
#define CP0_WIRED $6
#define CP0_INFO $7
#define CP0_BADVADDR $8
#define CP0_COUNT $9
#define CP0_ENTRYHI $10
#define CP0_COMPARE $11
#define CP0_STATUS $12
#define CP0_CAUSE $13
#define CP0_EPC $14
#define CP0_PRID $15
#define CP0_CONFIG $16
#define CP0_LLADDR $17
#define CP0_WATCHLO $18
#define CP0_WATCHHI $19
#define CP0_XCONTEXT $20
#define CP0_FRAMEMASK $21
#define CP0_DIAGNOSTIC $22
#define CP0_DEBUG $23
#define CP0_DEPC $24
#define CP0_PERFORMANCE $25
#define CP0_ECC $26
#define CP0_CACHEERR $27
#define CP0_TAGLO $28
#define CP0_TAGHI $29
#define CP0_ERROREPC $30
#define CP0_DESAVE $31
/*
* R4640/R4650 cp0 register names. These registers are listed
* here only for completeness; without MMU these CPUs are not useable
* by Linux. A future ELKS port might take make Linux run on them
* though ...
*/
#define CP0_IBASE $0
#define CP0_IBOUND $1
#define CP0_DBASE $2
#define CP0_DBOUND $3
#define CP0_CALG $17
#define CP0_IWATCH $18
#define CP0_DWATCH $19
/*
* Coprocessor 0 Set 1 register names
*/
#define CP0_S1_DERRADDR0 $26
#define CP0_S1_DERRADDR1 $27
#define CP0_S1_INTCONTROL $20
/*
* TX39 Series
*/
#define CP0_TX39_CACHE $7
/*
* Coprocessor 1 (FPU) register names
*/
#define CP1_REVISION $0
#define CP1_STATUS $31
#define PM_4K 0x00000000
#define PM_16K 0x00006000
#define PM_64K 0x0001e000
#define PM_256K 0x0007e000
#define PM_1M 0x001fe000
#define PM_4M 0x007fe000
#define PM_16M 0x01ffe000
#define PM_64M 0x07ffe000
#define PM_256M 0x1fffe000
/* Page size 64kb */
#define CONFIG_PAGE_SIZE_1M
/*
* Default page size for a given kernel configuration
*/
#ifdef CONFIG_PAGE_SIZE_4KB
#define PM_DEFAULT_MASK PM_4K
#elif defined(CONFIG_PAGE_SIZE_16KB)
#define PM_DEFAULT_MASK PM_16K
#elif defined(CONFIG_PAGE_SIZE_64KB)
#define PM_DEFAULT_MASK PM_64K
#elif defined(CONFIG_PAGE_SIZE_256KB)
#define PM_DEFAULT_MASK PM_256K
#elif defined(CONFIG_PAGE_SIZE_1M)
#define PM_DEFAULT_MASK PM_1M
#elif defined(CONFIG_PAGE_SIZE_4M)
#define PM_DEFAULT_MASK PM_4M
#else
#error Bad page size configuration!
#endif
/*
* Values used for computation of new tlb entries
*/
#define PL_4K 12
#define PL_16K 14
#define PL_64K 16
#define PL_256K 18
#define PL_1M 20
#define PL_4M 22
#define PL_16M 24
#define PL_64M 26
#define PL_256M 28
/*
* Macros to access the system control coprocessor
*/
#define __read_32bit_c0_register(source, sel) \
({ int __res; \
if (sel == 0) \
__asm__ __volatile__( \
"mfc0\t%0, " #source "\n\t" \
: "=r" (__res)); \
else \
__asm__ __volatile__( \
".set\tmips32\n\t" \
"mfc0\t%0, " #source ", " #sel "\n\t" \
".set\tmips0\n\t" \
: "=r" (__res)); \
__res; \
})
#define __read_64bit_c0_register(source, sel) \
({ unsigned long __res; \
if (sel == 0) \
__asm__ __volatile__( \
".set\tmips3\n\t" \
"dmfc0\t%0, " #source "\n\t" \
".set\tmips0" \
: "=r" (__res)); \
else \
__asm__ __volatile__( \
".set\tmips64\n\t" \
"dmfc0\t%0, " #source ", " #sel "\n\t" \
".set\tmips0" \
: "=r" (__res)); \
__res; \
})
#define __write_32bit_c0_register(register, sel, value) \
do { \
if (sel == 0) \
__asm__ __volatile__( \
"mtc0\t%z0, " #register "\n\t" \
: : "Jr" (value)); \
else \
__asm__ __volatile__( \
".set\tmips32\n\t" \
"mtc0\t%z0, " #register ", " #sel "\n\t" \
".set\tmips0" \
: : "Jr" (value)); \
} while (0)
#define __write_64bit_c0_register(register, sel, value) \
do { \
if (sel == 0) \
__asm__ __volatile__( \
".set\tmips3\n\t" \
"dmtc0\t%z0, " #register "\n\t" \
".set\tmips0" \
: : "Jr" (value)); \
else \
__asm__ __volatile__( \
".set\tmips64\n\t" \
"dmtc0\t%z0, " #register ", " #sel "\n\t" \
".set\tmips0" \
: : "Jr" (value)); \
} while (0)
#define __read_ulong_c0_register(reg, sel) \
((sizeof(unsigned long) == 4) ? \
__read_32bit_c0_register(reg, sel) : \
__read_64bit_c0_register(reg, sel))
#define __write_ulong_c0_register(reg, sel, val) \
do { \
if (sizeof(unsigned long) == 4) \
__write_32bit_c0_register(reg, sel, val); \
else \
__write_64bit_c0_register(reg, sel, val); \
} while (0)
#define read_c0_index() __read_32bit_c0_register($0, 0)
#define write_c0_index(val) __write_32bit_c0_register($0, 0, val)
#define read_c0_entrylo0() __read_ulong_c0_register($2, 0)
#define write_c0_entrylo0(val) __write_ulong_c0_register($2, 0, val)
#define read_c0_entrylo1() __read_ulong_c0_register($3, 0)
#define write_c0_entrylo1(val) __write_ulong_c0_register($3, 0, val)
#define read_c0_conf() __read_32bit_c0_register($3, 0)
#define write_c0_conf(val) __write_32bit_c0_register($3, 0, val)
#define read_c0_context() __read_ulong_c0_register($4, 0)
#define write_c0_context(val) __write_ulong_c0_register($4, 0, val)
#define read_c0_pagemask() __read_32bit_c0_register($5, 0)
#define write_c0_pagemask(val) __write_32bit_c0_register($5, 0, val)
#define read_c0_wired() __read_32bit_c0_register($6, 0)
#define write_c0_wired(val) __write_32bit_c0_register($6, 0, val)
#define read_c0_info() __read_32bit_c0_register($7, 0)
#define read_c0_cache() __read_32bit_c0_register($7, 0) /* TX39xx */
#define write_c0_cache(val) __write_32bit_c0_register($7, 0, val)
#define read_c0_count() __read_32bit_c0_register($9, 0)
#define write_c0_count(val) __write_32bit_c0_register($9, 0, val)
#define read_c0_entryhi() __read_ulong_c0_register($10, 0)
#define write_c0_entryhi(val) __write_ulong_c0_register($10, 0, val)
#define read_c0_compare() __read_32bit_c0_register($11, 0)
#define write_c0_compare(val) __write_32bit_c0_register($11, 0, val)
#define read_c0_status() __read_32bit_c0_register($12, 0)
#define write_c0_status(val) __write_32bit_c0_register($12, 0, val)
#define read_c0_cause() __read_32bit_c0_register($13, 0)
#define write_c0_cause(val) __write_32bit_c0_register($13, 0, val)
#define read_c0_prid() __read_32bit_c0_register($15, 0)
#define read_c0_config() __read_32bit_c0_register($16, 0)
#define read_c0_config1() __read_32bit_c0_register($16, 1)
#define read_c0_config2() __read_32bit_c0_register($16, 2)
#define read_c0_config3() __read_32bit_c0_register($16, 3)
#define write_c0_config(val) __write_32bit_c0_register($16, 0, val)
#define write_c0_config1(val) __write_32bit_c0_register($16, 1, val)
#define write_c0_config2(val) __write_32bit_c0_register($16, 2, val)
#define write_c0_config3(val) __write_32bit_c0_register($16, 3, val)
#define read_c0_framemask() __read_32bit_c0_register($21, 0)
#define write_c0_framemask(val) __write_32bit_c0_register($21, 0, val)
#define read_c0_debug() __read_32bit_c0_register($23, 0)
#define write_c0_debug(val) __write_32bit_c0_register($23, 0, val)
#define read_c0_depc() __read_ulong_c0_register($24, 0)
#define write_c0_depc(val) __write_ulong_c0_register($24, 0, val)
#define read_c0_ecc() __read_32bit_c0_register($26, 0)
#define write_c0_ecc(val) __write_32bit_c0_register($26, 0, val)
#define read_c0_derraddr0() __read_ulong_c0_register($26, 1)
#define write_c0_derraddr0(val) __write_ulong_c0_register($26, 1, val)
#define read_c0_cacheerr() __read_32bit_c0_register($27, 0)
#define read_c0_derraddr1() __read_ulong_c0_register($27, 1)
#define write_c0_derraddr1(val) __write_ulong_c0_register($27, 1, val)
#define read_c0_taglo() __read_32bit_c0_register($28, 0)
#define write_c0_taglo(val) __write_32bit_c0_register($28, 0, val)
#define read_c0_taghi() __read_32bit_c0_register($29, 0)
#define write_c0_taghi(val) __write_32bit_c0_register($29, 0, val)
#define read_c0_errorepc() __read_ulong_c0_register($30, 0)
#define write_c0_errorepc(val) __write_ulong_c0_register($30, 0, val)
/*
* TLB operations.
*/
static inline void tlb_probe(void)
{
__asm__ __volatile__(
".set noreorder\n\t"
"tlbp\n\t"
".set reorder");
}
static inline void tlb_read(void)
{
__asm__ __volatile__(
".set noreorder\n\t"
"tlbr\n\t"
".set reorder");
}
static inline void tlb_write_indexed(void)
{
__asm__ __volatile__(
".set noreorder\n\t"
"tlbwi\n\t"
".set reorder");
}
static inline void tlb_write_random(void)
{
__asm__ __volatile__(
".set noreorder\n\t"
"tlbwr\n\t"
".set reorder");
}
#define ASID_INC 0x1
#define ASID_MASK 0xff
/*
* PAGE_SHIFT determines the page size
*/
#ifdef CONFIG_PAGE_SIZE_4KB
#define PAGE_SHIFT 12
#endif
#ifdef CONFIG_PAGE_SIZE_16KB
#define PAGE_SHIFT 14
#endif
#ifdef CONFIG_PAGE_SIZE_64KB
#define PAGE_SHIFT 16
#endif
#ifdef CONFIG_PAGE_SIZE_256KB
#define PAGE_SHIFT 18
#endif
#ifdef CONFIG_PAGE_SIZE_1M
#define PAGE_SHIFT 20
#endif
#define PAGE_SIZE (1UL << PAGE_SHIFT)
#define PAGE_MASK (~(PAGE_SIZE-1))
/* For vesa mode control */
#define GRAPHIC_MODE_100 0x100 /* 640x400 256*/
#define GRAPHIC_MODE_101 0x101 /* 640x480 256*/
#define GRAPHIC_MODE_102 0x102 /* 800x600 16 */
#define GRAPHIC_MODE_103 0x103 /* 800x600 256*/
#define GRAPHIC_MODE_104 0x104 /* 1024x768 16*/
#define GRAPHIC_MODE_105 0x105 /* 1024x768 256*/
#define GRAPHIC_MODE_106 0x106 /* 1280x1024 16*/
#define GRAPHIC_MODE_107 0x107 /* 1280x1024 256*/
#define GRAPHIC_MODE_10d 0x10d /* 320x200 32K(1:5:5:5)*/
#define GRAPHIC_MODE_10e 0x10e /* 320x200 64K(5:6:5)*/
#define GRAPHIC_MODE_10f 0x10f /* 320x200 16.8M(8:8:8)*/
#define GRAPHIC_MODE_110 0x110 /* 640x480 32K*/
#define GRAPHIC_MODE_111 0x111 /* 640x480 64K*/
#define GRAPHIC_MODE_112 0x112 /* 640x480 16.8M*/
#define GRAPHIC_MODE_113 0x113 /* 800x600 32K*/
#define GRAPHIC_MODE_114 0x114 /* 800x600 64K*/
#define GRAPHIC_MODE_115 0x115 /* 800x600 16.8M*/
#define GRAPHIC_MODE_116 0x116 /* 1024x768 32K*/
#define GRAPHIC_MODE_117 0x117 /* 1024x768 64K*/
#define GRAPHIC_MODE_118 0x118 /* 1024x768 16.8M*/
#define GRAPHIC_MODE_119 0x119 /* 1280x1024 32K*/
#define GRAPHIC_MODE_11a 0x11a /* 1280x1024 64K*/
#define GRAPHIC_MODE_11b 0x11b /* 1280x1024 16.8M*/
#define USE_LINEAR_FRAMEBUFFER 0x4000
struct vesamode vesamode[] = {
{GRAPHIC_MODE_114,800,600,16}, /* default 800x600x16 */
{GRAPHIC_MODE_100,640,400,8},
{GRAPHIC_MODE_101,640,480,8},
{GRAPHIC_MODE_102,800,600,4},
{GRAPHIC_MODE_103,800,600,8},
{GRAPHIC_MODE_104,1024,768,16},
{GRAPHIC_MODE_105,1024,768,8},
{GRAPHIC_MODE_106,1280,1024,16},
{GRAPHIC_MODE_107,1280,1024,8},
{GRAPHIC_MODE_10d,320,200,15},
{GRAPHIC_MODE_10e,320,200,16},
{GRAPHIC_MODE_10f,320,200,24},
{GRAPHIC_MODE_110,640,480,15},
{GRAPHIC_MODE_111,640,480,16},
{GRAPHIC_MODE_112,640,480,24},
{GRAPHIC_MODE_113,800,600,15},
{GRAPHIC_MODE_114,800,600,16},
{GRAPHIC_MODE_115,800,600,24},
{GRAPHIC_MODE_116,1024,768,15},
{GRAPHIC_MODE_117,1024,768,16},
{GRAPHIC_MODE_118,1024,768,24},
{GRAPHIC_MODE_119,1280,1024,15},
{GRAPHIC_MODE_11a,1280,1024,16},
{GRAPHIC_MODE_11b,1280,1024,24},
};
struct vesamode *vesa_mode_head = vesamode;
static u32 io_vaddr;
void tlbmap(u32 viraddr, u32 phyaddr, u32 size)
{
u32 tmp_size;
u32 pid, idx;
write_c0_pagemask(PM_DEFAULT_MASK);
pid = read_c0_entryhi() & ASID_MASK;
printf("tlbmap vaddr %x paddr %x size %x\n", viraddr, phyaddr, size);
for (tmp_size = 0 ;tmp_size < size; tmp_size += (2*PAGE_SIZE)) {
viraddr &= (PAGE_MASK << 1);
write_c0_entryhi(viraddr | (pid));
tlb_probe();
idx = read_c0_index();
printf("viraddr=%08x,phyaddr=%08x,pid=%x,idx=%x\n",viraddr,phyaddr,pid,idx);
/* Uncached accelerate */
write_c0_entrylo0((phyaddr >> 6)|0x3f);
write_c0_entrylo1(((phyaddr+PAGE_SIZE) >> 6)|0x3f);
write_c0_entryhi(viraddr | (pid));
if(idx < 0) {
tlb_write_random();
} else {
tlb_write_indexed();
}
viraddr += (PAGE_SIZE*2);
phyaddr += (PAGE_SIZE*2);
}
write_c0_entryhi(pid);
}
#define BONITO_REGBASE 0x100
#define BONITO_PCIMAP BONITO(BONITO_REGBASE + 0x10)
#define BONITO(x) *(volatile unsigned long *)(0xbfe00000+(x))
#define BONITO_PCIMAP BONITO(BONITO_REGBASE + 0x10)
#define BONITO_PCIMAP_PCIMAP_LO0 0x0000003f
#define BONITO_PCIMAP_WIN(WIN,ADDR) ((((ADDR)>>26) & BONITO_PCIMAP_PCIMAP_LO0) << ((WIN)*6))
int vesafb_init(void)
{
u32 video_mem_size;
u32 fb_address, io_address;
u32 tmp;
if(vga_dev != NULL){
fb_address =_pci_conf_read(vga_dev->pa.pa_tag,0x10);
io_address =_pci_conf_read(vga_dev->pa.pa_tag,0x18);
}
if(pcie_dev != NULL){
fb_address =_pci_conf_read(pcie_dev->pa.pa_tag,0x10);
io_address =_pci_conf_read(pcie_dev->pa.pa_tag,0x18);
}
//io_vaddr = io_address | 0xbfd00000;
//io_vaddr = io_address | BONITO_PCIIO_BASE_VA;
io_vaddr = io_address | 0xb8000000;
/* We assume all the framebuffer is required remmapping */
#ifdef USETLB
/* Remap framebuffer address to 0x40000000, which can be accessed by same physical address from cpu */
_pci_conf_write(vga_dev->pa.pa_tag, 0x10, 0x40000000);
/* FIXME: video memory size should be detected by software, but now fixed in 2MB that's enough in PMON */
video_mem_size = 0x200000;
#if 1
/* Map cpu physical address 0x40000000 to BONITO address 0x40000000 -> PCI address 0x40000000.
* Master0 window 3 */
asm (
".set mips3\n"
".set noreorder\n"
"dli $2, 0x900000003ff00000\n"
"dli $3, 0x0000000040000000\n"
"sd $3, 0x18($2)\n"
"dli $3, 0x0000000040000001\n"
"sd $3, 0x58($2)\n"
"dli $3, 0xffffffffc0000000\n"
"sd $3, 0x38($2)\n"
".set reorder\n"
".set mips0\n"
:::"$2","$3","memory"
);
#endif
/* If framebuffer bar is NULL, then it has too large memory to be alloced in kernel mode */
/* TLB map physical address to virtual address in kseg3. Start address is 0xe0000000 */
tlbmap(0xe0000000, 0x40000000, video_mem_size);
#else
#if 0
/* 0x10000000 -> 0x40000000 PCI mapping */
_pci_conf_write(vga_dev->pa.pa_tag, 0x10, 0x40000000);
tmp = BONITO_PCIMAP;
BONITO_PCIMAP =
BONITO_PCIMAP_WIN(0, 0x40000000) |
(tmp & ~BONITO_PCIMAP_PCIMAP_LO0);
#endif
#endif
printf("VESA FB init complete.\n");
return 0;
}
/* dummy implementation */
void video_set_lut2(int index, int rgb)
{
return;
}
int GetXRes(void)
{
return vesamode[vesa_mode].width;
}
int GetYRes(void)
{
return vesamode[vesa_mode].height;
}
int GetBytesPP(void)
{
return (vesamode[vesa_mode].bpp+1)/8;
}
void video_set_lut(int index, int r, int g, int b)
{
linux_outb(index, 0x03C8);
linux_outb(r >> 2, 0x03C9);
linux_outb(g >> 2, 0x03C9);
linux_outb(b >> 2, 0x03C9);
}