Commit ef93127e authored by Linus Torvalds's avatar Linus Torvalds

Merge master.kernel.org:/pub/scm/linux/kernel/git/davem/sparc-2.6

* master.kernel.org:/pub/scm/linux/kernel/git/davem/sparc-2.6:
  [SERIAL] sunsu: Fix section mismatch warnings.
  [SPARC64]: pgtable_cache_init() should be __init.
  [SPARC64]: Fix section mismatch warnings in arch/sparc64/kernel/prom.c
  [SPARC64]: Fix section mismatch warnings in arch/sparc64/kernel/pci.c
  [SPARC64]: Fix section mismatch warnings in arch/sparc64/kernel/console.c
  [MM]: sparse_init() should be __init.
  [SPARC64]: Update defconfig.
  [VIDEO]: Add Sun XVR-2500 framebuffer driver.
  [VIDEO]: Add Sun XVR-500 framebuffer driver.
  [SPARC64]: SUN4U PCI-E controller support.
  [SPARC]: Fix comment typo in smp4m_blackbox_current().
  [SCSI] SUNESP: sun_esp.c needs linux/delay.h

Fix up conflict in arch/sparc64/mm/init.c manually due to removal of
pgtable_cache_init() through the -mm patches (even though that patch was
also by David ;)
Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
parents 972d45fb 90a660a4
......@@ -405,7 +405,7 @@ void __init smp4m_blackbox_current(unsigned *addr)
addr[0] = 0x81580000 | rd; /* rd %tbr, reg */
addr[2] = 0x8130200a | rd | rs1; /* srl reg, 0xa, reg */
addr[4] = 0x8008200c | rd | rs1; /* and reg, 3, reg */
addr[4] = 0x8008200c | rd | rs1; /* and reg, 0xc, reg */
}
void __init sun4m_init_smp(void)
......
#
# Automatically generated make config: don't edit
# Linux kernel version: 2.6.21-rc4
# Sat Mar 17 14:18:44 2007
# Linux kernel version: 2.6.21
# Sun May 6 22:46:54 2007
#
CONFIG_SPARC=y
CONFIG_SPARC64=y
CONFIG_GENERIC_TIME=y
CONFIG_GENERIC_CLOCKEVENTS=y
CONFIG_64BIT=y
CONFIG_MMU=y
CONFIG_STACKTRACE_SUPPORT=y
CONFIG_LOCKDEP_SUPPORT=y
CONFIG_TIME_INTERPOLATION=y
CONFIG_ARCH_MAY_HAVE_PC_FDC=y
# CONFIG_ARCH_HAS_ILOG2_U32 is not set
# CONFIG_ARCH_HAS_ILOG2_U64 is not set
......@@ -108,6 +109,9 @@ CONFIG_GENERIC_HARDIRQS=y
#
# General machine setup
#
CONFIG_TICK_ONESHOT=y
CONFIG_NO_HZ=y
CONFIG_HIGH_RES_TIMERS=y
# CONFIG_SMP is not set
CONFIG_CPU_FREQ=y
CONFIG_CPU_FREQ_TABLE=m
......@@ -140,8 +144,7 @@ CONFIG_SELECT_MEMORY_MODEL=y
CONFIG_SPARSEMEM_MANUAL=y
CONFIG_SPARSEMEM=y
CONFIG_HAVE_MEMORY_PRESENT=y
# CONFIG_SPARSEMEM_STATIC is not set
CONFIG_SPARSEMEM_EXTREME=y
CONFIG_SPARSEMEM_STATIC=y
CONFIG_SPLIT_PTLOCK_CPUS=4
CONFIG_RESOURCES_64BIT=y
CONFIG_ZONE_DMA_FLAG=0
......@@ -151,6 +154,7 @@ CONFIG_SUN_AUXIO=y
CONFIG_SUN_IO=y
CONFIG_PCI=y
CONFIG_PCI_DOMAINS=y
CONFIG_ARCH_SUPPORTS_MSI=y
CONFIG_PCI_MSI=y
# CONFIG_PCI_DEBUG is not set
CONFIG_SUN_OPENPROMFS=m
......@@ -178,7 +182,6 @@ CONFIG_NET=y
#
# Networking options
#
# CONFIG_NETDEBUG is not set
CONFIG_PACKET=y
CONFIG_PACKET_MMAP=y
CONFIG_UNIX=y
......@@ -219,6 +222,7 @@ CONFIG_IPV6=m
CONFIG_IPV6_PRIVACY=y
CONFIG_IPV6_ROUTER_PREF=y
CONFIG_IPV6_ROUTE_INFO=y
CONFIG_IPV6_OPTIMISTIC_DAD=y
CONFIG_INET6_AH=m
CONFIG_INET6_ESP=m
CONFIG_INET6_IPCOMP=m
......@@ -292,6 +296,14 @@ CONFIG_NET_TCPPROBE=m
# CONFIG_HAMRADIO is not set
# CONFIG_IRDA is not set
# CONFIG_BT is not set
# CONFIG_AF_RXRPC is not set
#
# Wireless
#
# CONFIG_CFG80211 is not set
# CONFIG_WIRELESS_EXT is not set
# CONFIG_MAC80211 is not set
# CONFIG_IEEE80211 is not set
#
......@@ -312,10 +324,6 @@ CONFIG_FW_LOADER=y
# Connector - unified userspace <-> kernelspace linker
#
CONFIG_CONNECTOR=m
#
# Memory Technology Devices (MTD)
#
# CONFIG_MTD is not set
#
......@@ -383,7 +391,6 @@ CONFIG_BLK_DEV_IDEPCI=y
# CONFIG_BLK_DEV_OPTI621 is not set
CONFIG_BLK_DEV_IDEDMA_PCI=y
# CONFIG_BLK_DEV_IDEDMA_FORCED is not set
CONFIG_IDEDMA_PCI_AUTO=y
CONFIG_IDEDMA_ONLYDISK=y
# CONFIG_BLK_DEV_AEC62XX is not set
CONFIG_BLK_DEV_ALI15X3=y
......@@ -413,7 +420,6 @@ CONFIG_BLK_DEV_ALI15X3=y
# CONFIG_IDE_ARM is not set
CONFIG_BLK_DEV_IDEDMA=y
# CONFIG_IDEDMA_IVB is not set
CONFIG_IDEDMA_AUTO=y
# CONFIG_BLK_DEV_HD is not set
#
......@@ -443,6 +449,7 @@ CONFIG_SCSI_MULTI_LUN=y
CONFIG_SCSI_CONSTANTS=y
# CONFIG_SCSI_LOGGING is not set
# CONFIG_SCSI_SCAN_ASYNC is not set
CONFIG_SCSI_WAIT_SCAN=m
#
# SCSI Transports
......@@ -485,6 +492,7 @@ CONFIG_ISCSI_TCP=m
# CONFIG_SCSI_DC395x is not set
# CONFIG_SCSI_DC390T is not set
# CONFIG_SCSI_DEBUG is not set
# CONFIG_SCSI_ESP_CORE is not set
# CONFIG_SCSI_SUNESP is not set
# CONFIG_SCSI_SRP is not set
......@@ -628,9 +636,10 @@ CONFIG_BNX2=m
# CONFIG_TR is not set
#
# Wireless LAN (non-hamradio)
# Wireless LAN
#
# CONFIG_NET_RADIO is not set
# CONFIG_WLAN_PRE80211 is not set
# CONFIG_WLAN_80211 is not set
#
# Wan interfaces
......@@ -695,6 +704,12 @@ CONFIG_KEYBOARD_LKKBD=m
# CONFIG_KEYBOARD_STOWAWAY is not set
CONFIG_INPUT_MOUSE=y
CONFIG_MOUSE_PS2=y
CONFIG_MOUSE_PS2_ALPS=y
CONFIG_MOUSE_PS2_LOGIPS2PP=y
CONFIG_MOUSE_PS2_SYNAPTICS=y
CONFIG_MOUSE_PS2_LIFEBOOK=y
CONFIG_MOUSE_PS2_TRACKPOINT=y
# CONFIG_MOUSE_PS2_TOUCHKIT is not set
CONFIG_MOUSE_SERIAL=y
# CONFIG_MOUSE_VSXXXAA is not set
# CONFIG_INPUT_JOYSTICK is not set
......@@ -702,6 +717,7 @@ CONFIG_MOUSE_SERIAL=y
CONFIG_INPUT_MISC=y
CONFIG_INPUT_SPARCSPKR=y
# CONFIG_INPUT_UINPUT is not set
# CONFIG_INPUT_POLLDEV is not set
#
# Hardware I/O ports
......@@ -763,11 +779,8 @@ CONFIG_RTC=y
# TPM devices
#
# CONFIG_TCG_TPM is not set
#
# I2C support
#
CONFIG_I2C=y
CONFIG_I2C_BOARDINFO=y
# CONFIG_I2C_CHARDEV is not set
#
......@@ -791,17 +804,17 @@ CONFIG_I2C_ALGOBIT=y
# CONFIG_I2C_NFORCE2 is not set
# CONFIG_I2C_OCORES is not set
# CONFIG_I2C_PARPORT_LIGHT is not set
# CONFIG_I2C_PASEMI is not set
# CONFIG_I2C_PROSAVAGE is not set
# CONFIG_I2C_SAVAGE4 is not set
# CONFIG_I2C_SIMTEC is not set
# CONFIG_I2C_SIS5595 is not set
# CONFIG_I2C_SIS630 is not set
# CONFIG_I2C_SIS96X is not set
# CONFIG_I2C_STUB is not set
# CONFIG_I2C_TINY_USB is not set
# CONFIG_I2C_VIA is not set
# CONFIG_I2C_VIAPRO is not set
# CONFIG_I2C_VOODOO3 is not set
# CONFIG_I2C_PCA_ISA is not set
#
# Miscellaneous I2C Chip support
......@@ -912,7 +925,7 @@ CONFIG_FB_MODE_HELPERS=y
CONFIG_FB_TILEBLITTING=y
#
# Frambuffer hardware drivers
# Frame buffer hardware drivers
#
# CONFIG_FB_CIRRUS is not set
# CONFIG_FB_PM2 is not set
......@@ -937,6 +950,8 @@ CONFIG_FB_RADEON_I2C=y
# CONFIG_FB_3DFX is not set
# CONFIG_FB_VOODOO1 is not set
# CONFIG_FB_TRIDENT is not set
# CONFIG_FB_XVR500 is not set
# CONFIG_FB_XVR2500 is not set
# CONFIG_FB_PCI is not set
# CONFIG_FB_VIRTUAL is not set
......@@ -1093,6 +1108,14 @@ CONFIG_AC97_BUS=m
CONFIG_HID=y
# CONFIG_HID_DEBUG is not set
#
# USB Input Devices
#
CONFIG_USB_HID=y
# CONFIG_USB_HIDINPUT_POWERBOOK is not set
# CONFIG_HID_FF is not set
CONFIG_USB_HIDDEV=y
#
# USB support
#
......@@ -1106,6 +1129,7 @@ CONFIG_USB=y
# Miscellaneous USB options
#
CONFIG_USB_DEVICEFS=y
# CONFIG_USB_DEVICE_CLASS is not set
# CONFIG_USB_DYNAMIC_MINORS is not set
# CONFIG_USB_OTG is not set
......@@ -1156,10 +1180,6 @@ CONFIG_USB_STORAGE=m
#
# USB Input Devices
#
CONFIG_USB_HID=y
# CONFIG_USB_HIDINPUT_POWERBOOK is not set
# CONFIG_HID_FF is not set
CONFIG_USB_HIDDEV=y
# CONFIG_USB_AIPTEK is not set
# CONFIG_USB_WACOM is not set
# CONFIG_USB_ACECAD is not set
......@@ -1524,6 +1544,7 @@ CONFIG_CRYPTO_ECB=m
CONFIG_CRYPTO_CBC=y
CONFIG_CRYPTO_PCBC=m
CONFIG_CRYPTO_LRW=m
# CONFIG_CRYPTO_CRYPTD is not set
CONFIG_CRYPTO_DES=y
CONFIG_CRYPTO_FCRYPT=m
CONFIG_CRYPTO_BLOWFISH=m
......
......@@ -17,7 +17,7 @@ obj-y := process.o setup.o cpu.o idprom.o \
obj-$(CONFIG_STACKTRACE) += stacktrace.o
obj-$(CONFIG_PCI) += ebus.o isa.o pci_common.o pci_iommu.o \
pci_psycho.o pci_sabre.o pci_schizo.o \
pci_sun4v.o pci_sun4v_asm.o
pci_sun4v.o pci_sun4v_asm.o pci_fire.o
obj-$(CONFIG_SMP) += smp.o trampoline.o
obj-$(CONFIG_SPARC32_COMPAT) += sys32.o sys_sparc32.o signal32.o
obj-$(CONFIG_BINFMT_ELF32) += binfmt_elf32.o
......
......@@ -98,7 +98,7 @@ void apply_central_ranges(struct linux_central *central,
central->num_central_ranges);
}
void * __init central_alloc_bootmem(unsigned long size)
static void * __init central_alloc_bootmem(unsigned long size)
{
void *ret;
......@@ -116,7 +116,7 @@ static unsigned long prom_reg_to_paddr(struct linux_prom_registers *r)
return ret | (unsigned long) r->phys_addr;
}
static void probe_other_fhcs(void)
static void __init probe_other_fhcs(void)
{
struct device_node *dp;
const struct linux_prom64_registers *fpregs;
......@@ -298,7 +298,7 @@ static void init_all_fhc_hw(void)
}
void central_probe(void)
void __init central_probe(void)
{
struct linux_prom_registers fpregs[6];
const struct linux_prom_registers *pr;
......
......@@ -279,7 +279,7 @@ static void sun4u_irq_enable(unsigned int virt_irq)
struct irq_handler_data *data = get_irq_chip_data(virt_irq);
if (likely(data)) {
unsigned long cpuid, imap;
unsigned long cpuid, imap, val;
unsigned int tid;
cpuid = irq_choose_cpu(virt_irq);
......@@ -287,7 +287,11 @@ static void sun4u_irq_enable(unsigned int virt_irq)
tid = sun4u_compute_tid(imap, cpuid);
upa_writel(tid | IMAP_VALID, imap);
val = upa_readq(imap);
val &= ~(IMAP_TID_UPA | IMAP_TID_JBUS |
IMAP_AID_SAFARI | IMAP_NID_SAFARI);
val |= tid | IMAP_VALID;
upa_writeq(val, imap);
}
}
......@@ -297,10 +301,10 @@ static void sun4u_irq_disable(unsigned int virt_irq)
if (likely(data)) {
unsigned long imap = data->imap;
u32 tmp = upa_readl(imap);
u32 tmp = upa_readq(imap);
tmp &= ~IMAP_VALID;
upa_writel(tmp, imap);
upa_writeq(tmp, imap);
}
}
......@@ -309,7 +313,7 @@ static void sun4u_irq_end(unsigned int virt_irq)
struct irq_handler_data *data = get_irq_chip_data(virt_irq);
if (likely(data))
upa_writel(ICLR_IDLE, data->iclr);
upa_writeq(ICLR_IDLE, data->iclr);
}
static void sun4v_irq_enable(unsigned int virt_irq)
......@@ -465,7 +469,7 @@ unsigned int build_irq(int inofixup, unsigned long iclr, unsigned long imap)
BUG_ON(tlb_type == hypervisor);
ino = (upa_readl(imap) & (IMAP_IGN | IMAP_INO)) + inofixup;
ino = (upa_readq(imap) & (IMAP_IGN | IMAP_INO)) + inofixup;
bucket = &ivector_table[ino];
if (!bucket->virt_irq) {
bucket->virt_irq = virt_irq_alloc(__irq(bucket));
......
......@@ -190,6 +190,7 @@ extern void schizo_init(struct device_node *, const char *);
extern void schizo_plus_init(struct device_node *, const char *);
extern void tomatillo_init(struct device_node *, const char *);
extern void sun4v_pci_init(struct device_node *, const char *);
extern void fire_pci_init(struct device_node *, const char *);
static struct {
char *model_name;
......@@ -207,6 +208,7 @@ static struct {
{ "SUNW,tomatillo", tomatillo_init },
{ "pci108e,a801", tomatillo_init },
{ "SUNW,sun4v-pci", sun4v_pci_init },
{ "pciex108e,80f0", fire_pci_init },
};
#define PCI_NUM_CONTROLLER_TYPES (sizeof(pci_controller_table) / \
sizeof(pci_controller_table[0]))
......@@ -436,6 +438,13 @@ struct pci_dev *of_create_pci_dev(struct pci_pbm_info *pbm,
printk(" class: 0x%x device name: %s\n",
dev->class, pci_name(dev));
/* I have seen IDE devices which will not respond to
* the bmdma simplex check reads if bus mastering is
* disabled.
*/
if ((dev->class >> 8) == PCI_CLASS_STORAGE_IDE)
pci_set_master(dev);
dev->current_state = 4; /* unknown power state */
dev->error_state = pci_channel_io_normal;
......@@ -468,7 +477,7 @@ struct pci_dev *of_create_pci_dev(struct pci_pbm_info *pbm,
return dev;
}
static void __init apb_calc_first_last(u8 map, u32 *first_p, u32 *last_p)
static void __devinit apb_calc_first_last(u8 map, u32 *first_p, u32 *last_p)
{
u32 idx, first, last;
......@@ -497,7 +506,7 @@ static void __init pci_resource_adjust(struct resource *res,
/* Cook up fake bus resources for SUNW,simba PCI bridges which lack
* a proper 'ranges' property.
*/
static void __init apb_fake_ranges(struct pci_dev *dev,
static void __devinit apb_fake_ranges(struct pci_dev *dev,
struct pci_bus *bus,
struct pci_pbm_info *pbm)
{
......@@ -522,13 +531,13 @@ static void __init apb_fake_ranges(struct pci_dev *dev,
pci_resource_adjust(res, &pbm->mem_space);
}
static void __init pci_of_scan_bus(struct pci_pbm_info *pbm,
static void __devinit pci_of_scan_bus(struct pci_pbm_info *pbm,
struct device_node *node,
struct pci_bus *bus);
#define GET_64BIT(prop, i) ((((u64) (prop)[(i)]) << 32) | (prop)[(i)+1])
void __devinit of_scan_pci_bridge(struct pci_pbm_info *pbm,
static void __devinit of_scan_pci_bridge(struct pci_pbm_info *pbm,
struct device_node *node,
struct pci_dev *dev)
{
......@@ -629,7 +638,7 @@ void __devinit of_scan_pci_bridge(struct pci_pbm_info *pbm,
pci_of_scan_bus(pbm, node, bus);
}
static void __init pci_of_scan_bus(struct pci_pbm_info *pbm,
static void __devinit pci_of_scan_bus(struct pci_pbm_info *pbm,
struct device_node *node,
struct pci_bus *bus)
{
......@@ -733,7 +742,7 @@ int pci_host_bridge_write_pci_cfg(struct pci_bus *bus_dev,
return PCIBIOS_SUCCESSFUL;
}
struct pci_bus * __init pci_scan_one_pbm(struct pci_pbm_info *pbm)
struct pci_bus * __devinit pci_scan_one_pbm(struct pci_pbm_info *pbm)
{
struct pci_controller_info *p = pbm->parent;
struct device_node *node = pbm->prom_node;
......
/* pci_fire.c: Sun4u platform PCI-E controller support.
*
* Copyright (C) 2007 David S. Miller (davem@davemloft.net)
*/
#include <linux/kernel.h>
#include <linux/pci.h>
#include <linux/slab.h>
#include <linux/init.h>
#include <asm/pbm.h>
#include <asm/oplib.h>
#include <asm/prom.h>
#include "pci_impl.h"
#define fire_read(__reg) \
({ u64 __ret; \
__asm__ __volatile__("ldxa [%1] %2, %0" \
: "=r" (__ret) \
: "r" (__reg), "i" (ASI_PHYS_BYPASS_EC_E) \
: "memory"); \
__ret; \
})
#define fire_write(__reg, __val) \
__asm__ __volatile__("stxa %0, [%1] %2" \
: /* no outputs */ \
: "r" (__val), "r" (__reg), \
"i" (ASI_PHYS_BYPASS_EC_E) \
: "memory")
/* Fire config space address format is nearly identical to
* that of SCHIZO and PSYCHO, except that in order to accomodate
* PCI-E extended config space the encoding can handle 12 bits
* of register address:
*
* 32 28 27 20 19 15 14 12 11 2 1 0
* -------------------------------------------------
* |0 0 0 0 0| bus | device | function | reg | 0 0 |
* -------------------------------------------------
*/
#define FIRE_CONFIG_BASE(PBM) ((PBM)->config_space)
#define FIRE_CONFIG_ENCODE(BUS, DEVFN, REG) \
(((unsigned long)(BUS) << 20) | \
((unsigned long)(DEVFN) << 12) | \
((unsigned long)(REG)))
static void *fire_pci_config_mkaddr(struct pci_pbm_info *pbm,
unsigned char bus,
unsigned int devfn,
int where)
{
if (!pbm)
return NULL;
return (void *)
(FIRE_CONFIG_BASE(pbm) |
FIRE_CONFIG_ENCODE(bus, devfn, where));
}
/* FIRE PCI configuration space accessors. */
static int fire_read_pci_cfg(struct pci_bus *bus_dev, unsigned int devfn,
int where, int size, u32 *value)
{
struct pci_pbm_info *pbm = bus_dev->sysdata;
unsigned char bus = bus_dev->number;
u32 *addr;
u16 tmp16;
u8 tmp8;
if (bus_dev == pbm->pci_bus && devfn == 0x00)
return pci_host_bridge_read_pci_cfg(bus_dev, devfn, where,
size, value);
switch (size) {
case 1:
*value = 0xff;
break;
case 2:
*value = 0xffff;
break;
case 4:
*value = 0xffffffff;
break;
}
addr = fire_pci_config_mkaddr(pbm, bus, devfn, where);
if (!addr)
return PCIBIOS_SUCCESSFUL;
switch (size) {
case 1:
pci_config_read8((u8 *)addr, &tmp8);
*value = tmp8;
break;
case 2:
if (where & 0x01) {
printk("pci_read_config_word: misaligned reg [%x]\n",
where);
return PCIBIOS_SUCCESSFUL;
}
pci_config_read16((u16 *)addr, &tmp16);
*value = tmp16;
break;
case 4:
if (where & 0x03) {
printk("pci_read_config_dword: misaligned reg [%x]\n",
where);
return PCIBIOS_SUCCESSFUL;
}
pci_config_read32(addr, value);
break;
}
return PCIBIOS_SUCCESSFUL;
}
static int fire_write_pci_cfg(struct pci_bus *bus_dev, unsigned int devfn,
int where, int size, u32 value)
{
struct pci_pbm_info *pbm = bus_dev->sysdata;
unsigned char bus = bus_dev->number;
u32 *addr;
if (bus_dev == pbm->pci_bus && devfn == 0x00)
return pci_host_bridge_write_pci_cfg(bus_dev, devfn, where,
size, value);
addr = fire_pci_config_mkaddr(pbm, bus, devfn, where);
if (!addr)
return PCIBIOS_SUCCESSFUL;
switch (size) {
case 1:
pci_config_write8((u8 *)addr, value);
break;
case 2:
if (where & 0x01) {
printk("pci_write_config_word: misaligned reg [%x]\n",
where);
return PCIBIOS_SUCCESSFUL;
}
pci_config_write16((u16 *)addr, value);
break;
case 4:
if (where & 0x03) {
printk("pci_write_config_dword: misaligned reg [%x]\n",
where);
return PCIBIOS_SUCCESSFUL;
}
pci_config_write32(addr, value);
}
return PCIBIOS_SUCCESSFUL;
}
static struct pci_ops pci_fire_ops = {
.read = fire_read_pci_cfg,
.write = fire_write_pci_cfg,
};
static void pbm_scan_bus(struct pci_controller_info *p,
struct pci_pbm_info *pbm)
{
pbm->pci_bus = pci_scan_one_pbm(pbm);
}
static void pci_fire_scan_bus(struct pci_controller_info *p)
{
struct device_node *dp;
if ((dp = p->pbm_A.prom_node) != NULL)
pbm_scan_bus(p, &p->pbm_A);
if ((dp = p->pbm_B.prom_node) != NULL)
pbm_scan_bus(p, &p->pbm_B);
/* XXX register error interrupt handlers XXX */
}
#define FIRE_IOMMU_CONTROL 0x40000UL
#define FIRE_IOMMU_TSBBASE 0x40008UL
#define FIRE_IOMMU_FLUSH 0x40100UL
#define FIRE_IOMMU_FLUSHINV 0x40100UL
static void pci_fire_pbm_iommu_init(struct pci_pbm_info *pbm)
{
struct iommu *iommu = pbm->iommu;
u32 vdma[2], dma_mask;
u64 control;
int tsbsize;
/* No virtual-dma property on these guys, use largest size. */
vdma[0] = 0xc0000000; /* base */
vdma[1] = 0x40000000; /* size */
dma_mask = 0xffffffff;
tsbsize = 128;
/* Register addresses. */
iommu->iommu_control = pbm->pbm_regs + FIRE_IOMMU_CONTROL;
iommu->iommu_tsbbase = pbm->pbm_regs + FIRE_IOMMU_TSBBASE;
iommu->iommu_flush = pbm->pbm_regs + FIRE_IOMMU_FLUSH;
iommu->iommu_flushinv = pbm->pbm_regs + FIRE_IOMMU_FLUSHINV;
/* We use the main control/status register of FIRE as the write
* completion register.
*/
iommu->write_complete_reg = pbm->controller_regs + 0x410000UL;
/*
* Invalidate TLB Entries.
*/
fire_write(iommu->iommu_flushinv, ~(u64)0);
pci_iommu_table_init(iommu, tsbsize * 8 * 1024, vdma[0], dma_mask);
fire_write(iommu->iommu_tsbbase, __pa(iommu->page_table) | 0x7UL);
control = fire_read(iommu->iommu_control);
control |= (0x00000400 /* TSB cache snoop enable */ |
0x00000300 /* Cache mode */ |
0x00000002 /* Bypass enable */ |
0x00000001 /* Translation enable */);
fire_write(iommu->iommu_control, control);
}
/* Based at pbm->controller_regs */
#define FIRE_PARITY_CONTROL 0x470010UL
#define FIRE_PARITY_ENAB 0x8000000000000000UL
#define FIRE_FATAL_RESET_CTL 0x471028UL
#define FIRE_FATAL_RESET_SPARE 0x0000000004000000UL
#define FIRE_FATAL_RESET_MB 0x0000000002000000UL
#define FIRE_FATAL_RESET_CPE 0x0000000000008000UL
#define FIRE_FATAL_RESET_APE 0x0000000000004000UL
#define FIRE_FATAL_RESET_PIO 0x0000000000000040UL
#define FIRE_FATAL_RESET_JW 0x0000000000000004UL
#define FIRE_FATAL_RESET_JI 0x0000000000000002UL
#define FIRE_FATAL_RESET_JR 0x0000000000000001UL
#define FIRE_CORE_INTR_ENABLE 0x471800UL
/* Based at pbm->pbm_regs */
#define FIRE_TLU_CTRL 0x80000UL
#define FIRE_TLU_CTRL_TIM 0x00000000da000000UL
#define FIRE_TLU_CTRL_QDET 0x0000000000000100UL
#define FIRE_TLU_CTRL_CFG 0x0000000000000001UL
#define FIRE_TLU_DEV_CTRL 0x90008UL
#define FIRE_TLU_LINK_CTRL 0x90020UL
#define FIRE_TLU_LINK_CTRL_CLK 0x0000000000000040UL
#define FIRE_LPU_RESET 0xe2008UL
#define FIRE_LPU_LLCFG 0xe2200UL
#define FIRE_LPU_LLCFG_VC0 0x0000000000000100UL
#define FIRE_LPU_FCTRL_UCTRL 0xe2240UL
#define FIRE_LPU_FCTRL_UCTRL_N 0x0000000000000002UL
#define FIRE_LPU_FCTRL_UCTRL_P 0x0000000000000001UL
#define FIRE_LPU_TXL_FIFOP 0xe2430UL
#define FIRE_LPU_LTSSM_CFG2 0xe2788UL
#define FIRE_LPU_LTSSM_CFG3 0xe2790UL
#define FIRE_LPU_LTSSM_CFG4 0xe2798UL
#define FIRE_LPU_LTSSM_CFG5 0xe27a0UL
#define FIRE_DMC_IENAB 0x31800UL
#define FIRE_DMC_DBG_SEL_A 0x53000UL
#define FIRE_DMC_DBG_SEL_B 0x53008UL
#define FIRE_PEC_IENAB 0x51800UL
static void pci_fire_hw_init(struct pci_pbm_info *pbm)
{
u64 val;
fire_write(pbm->controller_regs + FIRE_PARITY_CONTROL,
FIRE_PARITY_ENAB);
fire_write(pbm->controller_regs + FIRE_FATAL_RESET_CTL,
(FIRE_FATAL_RESET_SPARE |
FIRE_FATAL_RESET_MB |
FIRE_FATAL_RESET_CPE |
FIRE_FATAL_RESET_APE |
FIRE_FATAL_RESET_PIO |
FIRE_FATAL_RESET_JW |
FIRE_FATAL_RESET_JI |
FIRE_FATAL_RESET_JR));
fire_write(pbm->controller_regs + FIRE_CORE_INTR_ENABLE, ~(u64)0);
val = fire_read(pbm->pbm_regs + FIRE_TLU_CTRL);
val |= (FIRE_TLU_CTRL_TIM |
FIRE_TLU_CTRL_QDET |
FIRE_TLU_CTRL_CFG);
fire_write(pbm->pbm_regs + FIRE_TLU_CTRL, val);
fire_write(pbm->pbm_regs + FIRE_TLU_DEV_CTRL, 0);
fire_write(pbm->pbm_regs + FIRE_TLU_LINK_CTRL,
FIRE_TLU_LINK_CTRL_CLK);
fire_write(pbm->pbm_regs + FIRE_LPU_RESET, 0);
fire_write(pbm->pbm_regs + FIRE_LPU_LLCFG,
FIRE_LPU_LLCFG_VC0);
fire_write(pbm->pbm_regs + FIRE_LPU_FCTRL_UCTRL,
(FIRE_LPU_FCTRL_UCTRL_N |
FIRE_LPU_FCTRL_UCTRL_P));
fire_write(pbm->pbm_regs + FIRE_LPU_TXL_FIFOP,
((0xffff << 16) | (0x0000 << 0)));
fire_write(pbm->pbm_regs + FIRE_LPU_LTSSM_CFG2, 3000000);
fire_write(pbm->pbm_regs + FIRE_LPU_LTSSM_CFG3, 500000);
fire_write(pbm->pbm_regs + FIRE_LPU_LTSSM_CFG4,
(2 << 16) | (140 << 8));
fire_write(pbm->pbm_regs + FIRE_LPU_LTSSM_CFG5, 0);
fire_write(pbm->pbm_regs + FIRE_DMC_IENAB, ~(u64)0);
fire_write(pbm->pbm_regs + FIRE_DMC_DBG_SEL_A, 0);
fire_write(pbm->pbm_regs + FIRE_DMC_DBG_SEL_B, 0);
fire_write(pbm->pbm_regs + FIRE_PEC_IENAB, ~(u64)0);
}
static void pci_fire_pbm_init(struct pci_controller_info *p,
struct device_node *dp, u32 portid)
{
const struct linux_prom64_registers *regs;
struct pci_pbm_info *pbm;
const u32 *ino_bitmap;
const unsigned int *busrange;
if ((portid & 1) == 0)
pbm = &p->pbm_A;
else
pbm = &p->pbm_B;
pbm->portid = portid;
pbm->parent = p;
pbm->prom_node = dp;
pbm->name = dp->full_name;
regs = of_get_property(dp, "reg", NULL);
pbm->pbm_regs = regs[0].phys_addr;
pbm->controller_regs = regs[1].phys_addr - 0x410000UL;
printk("%s: SUN4U PCIE Bus Module\n", pbm->name);
pci_determine_mem_io_space(pbm);
ino_bitmap = of_get_property(dp, "ino-bitmap", NULL);
pbm->ino_bitmap = (((u64)ino_bitmap[1] << 32UL) |
((u64)ino_bitmap[0] << 0UL));
busrange = of_get_property(dp, "bus-range", NULL);
pbm->pci_first_busno = busrange[0];
pbm->pci_last_busno = busrange[1];
pci_fire_hw_init(pbm);
pci_fire_pbm_iommu_init(pbm);
}
static inline int portid_compare(u32 x, u32 y)
{
if (x == (y ^ 1))
return 1;
return 0;
}
void fire_pci_init(struct device_node *dp, const char *model_name)
{
struct pci_controller_info *p;
u32 portid = of_getintprop_default(dp, "portid", 0xff);
struct iommu *iommu;
for (p = pci_controller_root; p; p = p->next) {
struct pci_pbm_info *pbm;
if (p->pbm_A.prom_node && p->pbm_B.prom_node)
continue;
pbm = (p->pbm_A.prom_node ?
&p->pbm_A :
&p->pbm_B);
if (portid_compare(pbm->portid, portid)) {
pci_fire_pbm_init(p, dp, portid);
return;
}
}
p = kzalloc(sizeof(struct pci_controller_info), GFP_ATOMIC);
if (!p)
goto fatal_memory_error;
iommu = kzalloc(sizeof(struct iommu), GFP_ATOMIC);
if (!iommu)
goto fatal_memory_error;
p->pbm_A.iommu = iommu;
iommu = kzalloc(sizeof(struct iommu), GFP_ATOMIC);
if (!iommu)
goto fatal_memory_error;
p->pbm_B.iommu = iommu;
p->next = pci_controller_root;
pci_controller_root = p;
p->index = pci_num_controllers++;
p->scan_bus = pci_fire_scan_bus;
/* XXX MSI support XXX */
p->pci_ops = &pci_fire_ops;
/* Like PSYCHO and SCHIZO we have a 2GB aligned area
* for memory space.
*/
pci_memspace_mask = 0x7fffffffUL;
pci_fire_pbm_init(p, dp, portid);
return;
fatal_memory_error:
prom_printf("PCI_FIRE: Fatal memory allocation error.\n");
prom_halt();
}
......@@ -37,6 +37,9 @@
/* Must be invoked under the IOMMU lock. */
static void __iommu_flushall(struct iommu *iommu)
{
if (iommu->iommu_flushinv) {
pci_iommu_write(iommu->iommu_flushinv, ~(u64)0);
} else {
unsigned long tag;
int entry;
......@@ -48,6 +51,7 @@ static void __iommu_flushall(struct iommu *iommu)
/* Ensure completion of previous PIO writes. */
(void) pci_iommu_read(iommu->write_complete_reg);
}
}
#define IOPTE_CONSISTENT(CTX) \
......
......@@ -386,11 +386,9 @@ static unsigned int psycho_irq_build(struct device_node *dp,
/* Now build the IRQ bucket. */
imap = controller_regs + imap_off;
imap += 4;
iclr_off = psycho_iclr_offset(ino);
iclr = controller_regs + iclr_off;
iclr += 4;
if ((ino & 0x20) == 0)
inofixup = ino & 0x03;
......@@ -398,7 +396,7 @@ static unsigned int psycho_irq_build(struct device_node *dp,
return build_irq(inofixup, iclr, imap);
}
static void psycho_irq_trans_init(struct device_node *dp)
static void __init psycho_irq_trans_init(struct device_node *dp)
{
const struct linux_prom64_registers *regs;
......@@ -613,11 +611,9 @@ static unsigned int sabre_irq_build(struct device_node *dp,
/* Now build the IRQ bucket. */
imap = controller_regs + imap_off;
imap += 4;
iclr_off = sabre_iclr_offset(ino);
iclr = controller_regs + iclr_off;
iclr += 4;
if ((ino & 0x20) == 0)
inofixup = ino & 0x03;
......@@ -640,7 +636,7 @@ static unsigned int sabre_irq_build(struct device_node *dp,
return virt_irq;
}
static void sabre_irq_trans_init(struct device_node *dp)
static void __init sabre_irq_trans_init(struct device_node *dp)
{
const struct linux_prom64_registers *regs;
struct sabre_irq_data *irq_data;
......@@ -679,13 +675,14 @@ static unsigned long schizo_iclr_offset(unsigned long ino)
static unsigned long schizo_ino_to_iclr(unsigned long pbm_regs,
unsigned int ino)
{
return pbm_regs + schizo_iclr_offset(ino) + 4;
return pbm_regs + schizo_iclr_offset(ino);
}
static unsigned long schizo_ino_to_imap(unsigned long pbm_regs,
unsigned int ino)
{
return pbm_regs + schizo_imap_offset(ino) + 4;
return pbm_regs + schizo_imap_offset(ino);
}
#define schizo_read(__reg) \
......@@ -796,7 +793,8 @@ static unsigned int schizo_irq_build(struct device_node *dp,
return virt_irq;
}
static void __schizo_irq_trans_init(struct device_node *dp, int is_tomatillo)
static void __init __schizo_irq_trans_init(struct device_node *dp,
int is_tomatillo)
{
const struct linux_prom64_registers *regs;
struct schizo_irq_data *irq_data;
......@@ -818,12 +816,12 @@ static void __schizo_irq_trans_init(struct device_node *dp, int is_tomatillo)
irq_data->chip_version = of_getintprop_default(dp, "version#", 0);
}
static void schizo_irq_trans_init(struct device_node *dp)
static void __init schizo_irq_trans_init(struct device_node *dp)
{
__schizo_irq_trans_init(dp, 0);
}
static void tomatillo_irq_trans_init(struct device_node *dp)
static void __init tomatillo_irq_trans_init(struct device_node *dp)
{
__schizo_irq_trans_init(dp, 1);
}
......@@ -837,7 +835,7 @@ static unsigned int pci_sun4v_irq_build(struct device_node *dp,
return sun4v_build_irq(devhandle, devino);
}
static void pci_sun4v_irq_trans_init(struct device_node *dp)
static void __init pci_sun4v_irq_trans_init(struct device_node *dp)
{
const struct linux_prom64_registers *regs;
......@@ -848,6 +846,85 @@ static void pci_sun4v_irq_trans_init(struct device_node *dp)
dp->irq_trans->data = (void *) (unsigned long)
((regs->phys_addr >> 32UL) & 0x0fffffff);
}
struct fire_irq_data {
unsigned long pbm_regs;
u32 portid;
};
#define FIRE_IMAP_BASE 0x001000
#define FIRE_ICLR_BASE 0x001400
static unsigned long fire_imap_offset(unsigned long ino)
{
return FIRE_IMAP_BASE + (ino * 8UL);
}
static unsigned long fire_iclr_offset(unsigned long ino)
{
return FIRE_ICLR_BASE + (ino * 8UL);
}
static unsigned long fire_ino_to_iclr(unsigned long pbm_regs,
unsigned int ino)
{
return pbm_regs + fire_iclr_offset(ino);
}
static unsigned long fire_ino_to_imap(unsigned long pbm_regs,
unsigned int ino)
{
return pbm_regs + fire_imap_offset(ino);
}
static unsigned int fire_irq_build(struct device_node *dp,
unsigned int ino,
void *_data)
{
struct fire_irq_data *irq_data = _data;
unsigned long pbm_regs = irq_data->pbm_regs;
unsigned long imap, iclr;
unsigned long int_ctrlr;
ino &= 0x3f;
/* Now build the IRQ bucket. */
imap = fire_ino_to_imap(pbm_regs, ino);
iclr = fire_ino_to_iclr(pbm_regs, ino);
/* Set the interrupt controller number. */
int_ctrlr = 1 << 6;
upa_writeq(int_ctrlr, imap);
/* The interrupt map registers do not have an INO field
* like other chips do. They return zero in the INO
* field, and the interrupt controller number is controlled
* in bits 6 thru 9. So in order for build_irq() to get
* the INO right we pass it in as part of the fixup
* which will get added to the map register zero value
* read by build_irq().
*/
ino |= (irq_data->portid << 6);
ino -= int_ctrlr;
return build_irq(ino, iclr, imap);
}
static void __init fire_irq_trans_init(struct device_node *dp)
{
const struct linux_prom64_registers *regs;
struct fire_irq_data *irq_data;
dp->irq_trans = prom_early_alloc(sizeof(struct of_irq_controller));
dp->irq_trans->irq_build = fire_irq_build;
irq_data = prom_early_alloc(sizeof(struct fire_irq_data));
regs = of_get_property(dp, "reg", NULL);
dp->irq_trans->data = irq_data;
irq_data->pbm_regs = regs[0].phys_addr;
irq_data->portid = of_getintprop_default(dp, "portid", 0);
}
#endif /* CONFIG_PCI */
#ifdef CONFIG_SBUS
......@@ -995,7 +1072,7 @@ static unsigned int sbus_of_build_irq(struct device_node *dp,
return build_irq(sbus_level, iclr, imap);
}
static void sbus_irq_trans_init(struct device_node *dp)
static void __init sbus_irq_trans_init(struct device_node *dp)
{
const struct linux_prom64_registers *regs;
......@@ -1042,7 +1119,7 @@ static unsigned int central_build_irq(struct device_node *dp,
return build_irq(0, iclr, imap);
}
static void central_irq_trans_init(struct device_node *dp)
static void __init central_irq_trans_init(struct device_node *dp)
{
dp->irq_trans = prom_early_alloc(sizeof(struct of_irq_controller));
dp->irq_trans->irq_build = central_build_irq;
......@@ -1056,7 +1133,7 @@ struct irq_trans {
};
#ifdef CONFIG_PCI
static struct irq_trans pci_irq_trans_table[] = {
static struct irq_trans __initdata pci_irq_trans_table[] = {
{ "SUNW,sabre", sabre_irq_trans_init },
{ "pci108e,a000", sabre_irq_trans_init },
{ "pci108e,a001", sabre_irq_trans_init },
......@@ -1069,6 +1146,7 @@ static struct irq_trans pci_irq_trans_table[] = {
{ "SUNW,tomatillo", tomatillo_irq_trans_init },
{ "pci108e,a801", tomatillo_irq_trans_init },
{ "SUNW,sun4v-pci", pci_sun4v_irq_trans_init },
{ "pciex108e,80f0", fire_irq_trans_init },
};
#endif
......@@ -1081,7 +1159,7 @@ static unsigned int sun4v_vdev_irq_build(struct device_node *dp,
return sun4v_build_irq(devhandle, devino);
}
static void sun4v_vdev_irq_trans_init(struct device_node *dp)
static void __init sun4v_vdev_irq_trans_init(struct device_node *dp)
{
const struct linux_prom64_registers *regs;
......@@ -1093,7 +1171,7 @@ static void sun4v_vdev_irq_trans_init(struct device_node *dp)
((regs->phys_addr >> 32UL) & 0x0fffffff);
}
static void irq_trans_init(struct device_node *dp)
static void __init irq_trans_init(struct device_node *dp)
{
#ifdef CONFIG_PCI
const char *model;
......
......@@ -5,6 +5,7 @@
#include <linux/kernel.h>
#include <linux/types.h>
#include <linux/delay.h>
#include <linux/module.h>
#include <linux/init.h>
......
......@@ -1312,7 +1312,7 @@ static void sunsu_console_write(struct console *co, const char *s,
* - initialize the serial port
* Return non-zero if we didn't find a serial port.
*/
static int sunsu_console_setup(struct console *co, char *options)
static int __init sunsu_console_setup(struct console *co, char *options)
{
struct uart_port *port;
int baud = 9600;
......@@ -1343,7 +1343,7 @@ static int sunsu_console_setup(struct console *co, char *options)
return uart_set_options(port, co, baud, parity, bits, flow);
}
static struct console sunsu_cons = {
static struct console sunsu_console = {
.name = "ttyS",
.write = sunsu_console_write,
.device = uart_console_device,
......@@ -1373,9 +1373,9 @@ static inline struct console *SUNSU_CONSOLE(int num_uart)
if (i == num_uart)
return NULL;
sunsu_cons.index = i;
sunsu_console.index = i;
return &sunsu_cons;
return &sunsu_console;
}
#else
#define SUNSU_CONSOLE(num_uart) (NULL)
......
......@@ -1383,6 +1383,32 @@ config FB_LEO
This is the frame buffer device driver for the SBUS-based Sun ZX
(leo) frame buffer cards.
config FB_XVR500
bool "Sun XVR-500 3DLABS Wildcat support"
depends on FB && PCI && SPARC64
select FB_CFB_FILLRECT
select FB_CFB_COPYAREA
select FB_CFB_IMAGEBLIT
help
This is the framebuffer device for the Sun XVR-500 and similar
graphics cards based upon the 3DLABS Wildcat chipset. The driver
only works on sparc64 systems where the system firwmare has
mostly initialized the card already. It is treated as a
completely dumb framebuffer device.
config FB_XVR2500
bool "Sun XVR-2500 3DLABS Wildcat support"
depends on FB && PCI && SPARC64
select FB_CFB_FILLRECT
select FB_CFB_COPYAREA
select FB_CFB_IMAGEBLIT
help
This is the framebuffer device for the Sun XVR-2500 and similar
graphics cards based upon the 3DLABS Wildcat chipset. The driver
only works on sparc64 systems where the system firwmare has
mostly initialized the card already. It is treated as a
completely dumb framebuffer device.
config FB_PCI
bool "PCI framebuffers"
depends on (FB = y) && PCI && SPARC
......
......@@ -67,6 +67,8 @@ obj-$(CONFIG_FB_ATARI) += atafb.o c2p.o atafb_mfb.o \
atafb_iplan2p2.o atafb_iplan2p4.o atafb_iplan2p8.o
obj-$(CONFIG_FB_MAC) += macfb.o
obj-$(CONFIG_FB_HGA) += hgafb.o
obj-$(CONFIG_FB_XVR500) += sunxvr500.o
obj-$(CONFIG_FB_XVR2500) += sunxvr2500.o
obj-$(CONFIG_FB_IGA) += igafb.o
obj-$(CONFIG_FB_APOLLO) += dnfb.o
obj-$(CONFIG_FB_Q40) += q40fb.o
......
/* s3d.c: Sun 3DLABS XVR-2500 et al. driver for sparc64 systems
*
* Copyright (C) 2007 David S. Miller (davem@davemloft.net)
*/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/fb.h>
#include <linux/pci.h>
#include <linux/init.h>
#include <asm/io.h>
#include <asm/prom.h>
#include <asm/of_device.h>
struct s3d_info {
struct fb_info *info;
struct pci_dev *pdev;
char __iomem *fb_base;
unsigned long fb_base_phys;
struct device_node *of_node;
unsigned int width;
unsigned int height;
unsigned int depth;
unsigned int fb_size;
u32 pseudo_palette[256];
};
static int __devinit s3d_get_props(struct s3d_info *sp)
{
sp->width = of_getintprop_default(sp->of_node, "width", 0);
sp->height = of_getintprop_default(sp->of_node, "height", 0);
sp->depth = of_getintprop_default(sp->of_node, "depth", 8);
if (!sp->width || !sp->height) {
printk(KERN_ERR "s3d: Critical properties missing for %s\n",
pci_name(sp->pdev));
return -EINVAL;
}
return 0;
}
static int s3d_setcolreg(unsigned regno,
unsigned red, unsigned green, unsigned blue,
unsigned transp, struct fb_info *info)
{
u32 value;
if (regno >= 256)
return 1;
red >>= 8;
green >>= 8;
blue >>= 8;
value = (blue << 24) | (green << 16) | (red << 8);
((u32 *)info->pseudo_palette)[regno] = value;
return 0;
}
static struct fb_ops s3d_ops = {
.owner = THIS_MODULE,
.fb_setcolreg = s3d_setcolreg,
.fb_fillrect = cfb_fillrect,
.fb_copyarea = cfb_copyarea,
.fb_imageblit = cfb_imageblit,
};
static int __devinit s3d_set_fbinfo(struct s3d_info *sp)
{
struct fb_info *info = sp->info;
struct fb_var_screeninfo *var = &info->var;
info->flags = FBINFO_DEFAULT;
info->fbops = &s3d_ops;
info->screen_base = sp->fb_base;
info->screen_size = sp->fb_size;
info->pseudo_palette = sp->pseudo_palette;
/* Fill fix common fields */
strlcpy(info->fix.id, "s3d", sizeof(info->fix.id));
info->fix.smem_start = sp->fb_base_phys;
info->fix.smem_len = sp->fb_size;
info->fix.type = FB_TYPE_PACKED_PIXELS;
if (sp->depth == 32 || sp->depth == 24)
info->fix.visual = FB_VISUAL_TRUECOLOR;
else
info->fix.visual = FB_VISUAL_PSEUDOCOLOR;
var->xres = sp->width;
var->yres = sp->height;
var->xres_virtual = var->xres;
var->yres_virtual = var->yres;
var->bits_per_pixel = sp->depth;
var->red.offset = 8;
var->red.length = 8;
var->green.offset = 16;
var->green.length = 8;
var->blue.offset = 24;
var->blue.length = 8;
var->transp.offset = 0;
var->transp.length = 0;
if (fb_alloc_cmap(&info->cmap, 256, 0)) {
printk(KERN_ERR "s3d: Cannot allocate color map.\n");
return -ENOMEM;
}
return 0;
}
static int __devinit s3d_pci_register(struct pci_dev *pdev,
const struct pci_device_id *ent)
{
struct fb_info *info;
struct s3d_info *sp;
int err;
err = pci_enable_device(pdev);
if (err < 0) {
printk(KERN_ERR "s3d: Cannot enable PCI device %s\n",
pci_name(pdev));
goto err_out;
}
info = framebuffer_alloc(sizeof(struct s3d_info), &pdev->dev);
if (!info) {
printk(KERN_ERR "s3d: Cannot allocate fb_info\n");
err = -ENOMEM;
goto err_disable;
}
sp = info->par;
sp->info = info;
sp->pdev = pdev;
sp->of_node = pci_device_to_OF_node(pdev);
if (!sp->of_node) {
printk(KERN_ERR "s3d: Cannot find OF node of %s\n",
pci_name(pdev));
err = -ENODEV;
goto err_release_fb;
}
sp->fb_base_phys = pci_resource_start (pdev, 1);
err = pci_request_region(pdev, 1, "s3d framebuffer");
if (err < 0) {
printk("s3d: Cannot request region 1 for %s\n",
pci_name(pdev));
goto err_release_fb;
}
err = s3d_get_props(sp);
if (err)
goto err_release_pci;
/* XXX 'linebytes' is often wrong, it is equal to the width
* XXX with depth of 32 on my XVR-2500 which is clearly not
* XXX right. So we don't try to use it.
*/
switch (sp->depth) {
case 8:
info->fix.line_length = sp->width;
break;
case 16:
info->fix.line_length = sp->width * 2;
break;
case 24:
info->fix.line_length = sp->width * 3;
break;
case 32:
info->fix.line_length = sp->width * 4;
break;
}
sp->fb_size = info->fix.line_length * sp->height;
sp->fb_base = ioremap(sp->fb_base_phys, sp->fb_size);
if (!sp->fb_base)
goto err_release_pci;
err = s3d_set_fbinfo(sp);
if (err)
goto err_unmap_fb;
pci_set_drvdata(pdev, info);
printk("s3d: Found device at %s\n", pci_name(pdev));
err = register_framebuffer(info);
if (err < 0) {
printk(KERN_ERR "s3d: Could not register framebuffer %s\n",
pci_name(pdev));
goto err_unmap_fb;
}
return 0;
err_unmap_fb:
iounmap(sp->fb_base);
err_release_pci:
pci_release_region(pdev, 1);
err_release_fb:
framebuffer_release(info);
err_disable:
pci_disable_device(pdev);
err_out:
return err;
}
static void __devexit s3d_pci_unregister(struct pci_dev *pdev)
{
struct fb_info *info = pci_get_drvdata(pdev);
struct s3d_info *sp = info->par;
unregister_framebuffer(info);
iounmap(sp->fb_base);
pci_release_region(pdev, 1);
framebuffer_release(info);
pci_disable_device(pdev);
}
static struct pci_device_id s3d_pci_table[] = {
{ /* XVR-2500 */
PCI_DEVICE(PCI_VENDOR_ID_3DLABS, 0x0032),
.driver_data = 1,
},
{ /* XVR-500 */
PCI_DEVICE(PCI_VENDOR_ID_3DLABS, 0x07a2),
.driver_data = 0,
},
{ 0, }
};
static struct pci_driver s3d_driver = {
.name = "s3d",
.id_table = s3d_pci_table,
.probe = s3d_pci_register,
.remove = __devexit_p(s3d_pci_unregister),
};
static int __init s3d_init(void)
{
if (fb_get_options("s3d", NULL))
return -ENODEV;
return pci_register_driver(&s3d_driver);
}
static void __exit s3d_exit(void)
{
pci_unregister_driver(&s3d_driver);
}
module_init(s3d_init);
module_exit(s3d_exit);
MODULE_DESCRIPTION("framebuffer driver for Sun XVR-2500 graphics");
MODULE_AUTHOR("David S. Miller <davem@davemloft.net>");
MODULE_VERSION("1.0");
MODULE_LICENSE("GPL");
/* sunxvr500.c: Sun 3DLABS XVR-500 Expert3D driver for sparc64 systems
*
* Copyright (C) 2007 David S. Miller (davem@davemloft.net)
*/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/fb.h>
#include <linux/pci.h>
#include <linux/init.h>
#include <asm/io.h>
#include <asm/prom.h>
#include <asm/of_device.h>
/* XXX This device has a 'dev-comm' property which aparently is
* XXX a pointer into the openfirmware's address space which is
* XXX a shared area the kernel driver can use to keep OBP
* XXX informed about the current resolution setting. The idea
* XXX is that the kernel can change resolutions, and as long
* XXX as the values in the 'dev-comm' area are accurate then
* XXX OBP can still render text properly to the console.
* XXX
* XXX I'm still working out the layout of this and whether there
* XXX are any signatures we need to look for etc.
*/
struct e3d_info {
struct fb_info *info;
struct pci_dev *pdev;
spinlock_t lock;
char __iomem *fb_base;
unsigned long fb_base_phys;
unsigned long fb8_buf_diff;
unsigned long regs_base_phys;
void __iomem *ramdac;
struct device_node *of_node;
unsigned int width;
unsigned int height;
unsigned int depth;
unsigned int fb_size;
u32 fb_base_reg;
u32 fb8_0_off;
u32 fb8_1_off;
u32 pseudo_palette[256];
};
static int __devinit e3d_get_props(struct e3d_info *ep)
{
ep->width = of_getintprop_default(ep->of_node, "width", 0);
ep->height = of_getintprop_default(ep->of_node, "height", 0);
ep->depth = of_getintprop_default(ep->of_node, "depth", 8);
if (!ep->width || !ep->height) {
printk(KERN_ERR "e3d: Critical properties missing for %s\n",
pci_name(ep->pdev));
return -EINVAL;
}
return 0;
}
/* My XVR-500 comes up, at 1280x768 and a FB base register value of
* 0x04000000, the following video layout register values:
*
* RAMDAC_VID_WH 0x03ff04ff
* RAMDAC_VID_CFG 0x1a0b0088
* RAMDAC_VID_32FB_0 0x04000000
* RAMDAC_VID_32FB_1 0x04800000
* RAMDAC_VID_8FB_0 0x05000000
* RAMDAC_VID_8FB_1 0x05200000
* RAMDAC_VID_XXXFB 0x05400000
* RAMDAC_VID_YYYFB 0x05c00000
* RAMDAC_VID_ZZZFB 0x05e00000
*/
/* Video layout registers */
#define RAMDAC_VID_WH 0x00000070UL /* (height-1)<<16 | (width-1) */
#define RAMDAC_VID_CFG 0x00000074UL /* 0x1a000088|(linesz_log2<<16) */
#define RAMDAC_VID_32FB_0 0x00000078UL /* PCI base 32bpp FB buffer 0 */
#define RAMDAC_VID_32FB_1 0x0000007cUL /* PCI base 32bpp FB buffer 1 */
#define RAMDAC_VID_8FB_0 0x00000080UL /* PCI base 8bpp FB buffer 0 */
#define RAMDAC_VID_8FB_1 0x00000084UL /* PCI base 8bpp FB buffer 1 */
#define RAMDAC_VID_XXXFB 0x00000088UL /* PCI base of XXX FB */
#define RAMDAC_VID_YYYFB 0x0000008cUL /* PCI base of YYY FB */
#define RAMDAC_VID_ZZZFB 0x00000090UL /* PCI base of ZZZ FB */
/* CLUT registers */
#define RAMDAC_INDEX 0x000000bcUL
#define RAMDAC_DATA 0x000000c0UL
static void e3d_clut_write(struct e3d_info *ep, int index, u32 val)
{
void __iomem *ramdac = ep->ramdac;
unsigned long flags;
spin_lock_irqsave(&ep->lock, flags);
writel(index, ramdac + RAMDAC_INDEX);
writel(val, ramdac + RAMDAC_DATA);
spin_unlock_irqrestore(&ep->lock, flags);
}
static int e3d_setcolreg(unsigned regno,
unsigned red, unsigned green, unsigned blue,
unsigned transp, struct fb_info *info)
{
struct e3d_info *ep = info->par;
u32 red_8, green_8, blue_8;
u32 red_10, green_10, blue_10;
u32 value;
if (regno >= 256)
return 1;
red_8 = red >> 8;
green_8 = green >> 8;
blue_8 = blue >> 8;
value = (blue_8 << 24) | (green_8 << 16) | (red_8 << 8);
((u32 *)info->pseudo_palette)[regno] = value;
red_10 = red >> 6;
green_10 = green >> 6;
blue_10 = blue >> 6;
value = (blue_10 << 20) | (green_10 << 10) | (red_10 << 0);
e3d_clut_write(ep, regno, value);
return 0;
}
/* XXX This is a bit of a hack. I can't figure out exactly how the
* XXX two 8bpp areas of the framebuffer work. I imagine there is
* XXX a WID attribute somewhere else in the framebuffer which tells
* XXX the ramdac which of the two 8bpp framebuffer regions to take
* XXX the pixel from. So, for now, render into both regions to make
* XXX sure the pixel shows up.
*/
static void e3d_imageblit(struct fb_info *info, const struct fb_image *image)
{
struct e3d_info *ep = info->par;
unsigned long flags;
spin_lock_irqsave(&ep->lock, flags);
cfb_imageblit(info, image);
info->screen_base += ep->fb8_buf_diff;
cfb_imageblit(info, image);
info->screen_base -= ep->fb8_buf_diff;
spin_unlock_irqrestore(&ep->lock, flags);
}
static void e3d_fillrect(struct fb_info *info, const struct fb_fillrect *rect)
{
struct e3d_info *ep = info->par;
unsigned long flags;
spin_lock_irqsave(&ep->lock, flags);
cfb_fillrect(info, rect);
info->screen_base += ep->fb8_buf_diff;
cfb_fillrect(info, rect);
info->screen_base -= ep->fb8_buf_diff;
spin_unlock_irqrestore(&ep->lock, flags);
}
static void e3d_copyarea(struct fb_info *info, const struct fb_copyarea *area)
{
struct e3d_info *ep = info->par;
unsigned long flags;
spin_lock_irqsave(&ep->lock, flags);
cfb_copyarea(info, area);
info->screen_base += ep->fb8_buf_diff;
cfb_copyarea(info, area);
info->screen_base -= ep->fb8_buf_diff;
spin_unlock_irqrestore(&ep->lock, flags);
}
static struct fb_ops e3d_ops = {
.owner = THIS_MODULE,
.fb_setcolreg = e3d_setcolreg,
.fb_fillrect = e3d_fillrect,
.fb_copyarea = e3d_copyarea,
.fb_imageblit = e3d_imageblit,
};
static int __devinit e3d_set_fbinfo(struct e3d_info *ep)
{
struct fb_info *info = ep->info;
struct fb_var_screeninfo *var = &info->var;
info->flags = FBINFO_DEFAULT;
info->fbops = &e3d_ops;
info->screen_base = ep->fb_base;
info->screen_size = ep->fb_size;
info->pseudo_palette = ep->pseudo_palette;
/* Fill fix common fields */
strlcpy(info->fix.id, "e3d", sizeof(info->fix.id));
info->fix.smem_start = ep->fb_base_phys;
info->fix.smem_len = ep->fb_size;
info->fix.type = FB_TYPE_PACKED_PIXELS;
if (ep->depth == 32 || ep->depth == 24)
info->fix.visual = FB_VISUAL_TRUECOLOR;
else
info->fix.visual = FB_VISUAL_PSEUDOCOLOR;
var->xres = ep->width;
var->yres = ep->height;
var->xres_virtual = var->xres;
var->yres_virtual = var->yres;
var->bits_per_pixel = ep->depth;
var->red.offset = 8;
var->red.length = 8;
var->green.offset = 16;
var->green.length = 8;
var->blue.offset = 24;
var->blue.length = 8;
var->transp.offset = 0;
var->transp.length = 0;
if (fb_alloc_cmap(&info->cmap, 256, 0)) {
printk(KERN_ERR "e3d: Cannot allocate color map.\n");
return -ENOMEM;
}
return 0;
}
static int __devinit e3d_pci_register(struct pci_dev *pdev,
const struct pci_device_id *ent)
{
struct fb_info *info;
struct e3d_info *ep;
unsigned int line_length;
int err;
err = pci_enable_device(pdev);
if (err < 0) {
printk(KERN_ERR "e3d: Cannot enable PCI device %s\n",
pci_name(pdev));
goto err_out;
}
info = framebuffer_alloc(sizeof(struct e3d_info), &pdev->dev);
if (!info) {
printk(KERN_ERR "e3d: Cannot allocate fb_info\n");
err = -ENOMEM;
goto err_disable;
}
ep = info->par;
ep->info = info;
ep->pdev = pdev;
spin_lock_init(&ep->lock);
ep->of_node = pci_device_to_OF_node(pdev);
if (!ep->of_node) {
printk(KERN_ERR "e3d: Cannot find OF node of %s\n",
pci_name(pdev));
err = -ENODEV;
goto err_release_fb;
}
/* Read the PCI base register of the frame buffer, which we
* need in order to interpret the RAMDAC_VID_*FB* values in
* the ramdac correctly.
*/
pci_read_config_dword(pdev, PCI_BASE_ADDRESS_0,
&ep->fb_base_reg);
ep->fb_base_reg &= PCI_BASE_ADDRESS_MEM_MASK;
ep->regs_base_phys = pci_resource_start (pdev, 1);
err = pci_request_region(pdev, 1, "e3d regs");
if (err < 0) {
printk("e3d: Cannot request region 1 for %s\n",
pci_name(pdev));
goto err_release_fb;
}
ep->ramdac = ioremap(ep->regs_base_phys + 0x8000, 0x1000);
if (!ep->ramdac)
goto err_release_pci1;
ep->fb8_0_off = readl(ep->ramdac + RAMDAC_VID_8FB_0);
ep->fb8_0_off -= ep->fb_base_reg;
ep->fb8_1_off = readl(ep->ramdac + RAMDAC_VID_8FB_1);
ep->fb8_1_off -= ep->fb_base_reg;
ep->fb8_buf_diff = ep->fb8_1_off - ep->fb8_0_off;
ep->fb_base_phys = pci_resource_start (pdev, 0);
ep->fb_base_phys += ep->fb8_0_off;
err = pci_request_region(pdev, 0, "e3d framebuffer");
if (err < 0) {
printk("e3d: Cannot request region 0 for %s\n",
pci_name(pdev));
goto err_unmap_ramdac;
}
err = e3d_get_props(ep);
if (err)
goto err_release_pci0;
line_length = (readl(ep->ramdac + RAMDAC_VID_CFG) >> 16) & 0xff;
line_length = 1 << line_length;
switch (ep->depth) {
case 8:
info->fix.line_length = line_length;
break;
case 16:
info->fix.line_length = line_length * 2;
break;
case 24:
info->fix.line_length = line_length * 3;
break;
case 32:
info->fix.line_length = line_length * 4;
break;
}
ep->fb_size = info->fix.line_length * ep->height;
ep->fb_base = ioremap(ep->fb_base_phys, ep->fb_size);
if (!ep->fb_base)
goto err_release_pci0;
err = e3d_set_fbinfo(ep);
if (err)
goto err_unmap_fb;
pci_set_drvdata(pdev, info);
printk("e3d: Found device at %s\n", pci_name(pdev));
err = register_framebuffer(info);
if (err < 0) {
printk(KERN_ERR "e3d: Could not register framebuffer %s\n",
pci_name(pdev));
goto err_unmap_fb;
}
return 0;
err_unmap_fb:
iounmap(ep->fb_base);
err_release_pci0:
pci_release_region(pdev, 0);
err_unmap_ramdac:
iounmap(ep->ramdac);
err_release_pci1:
pci_release_region(pdev, 1);
err_release_fb:
framebuffer_release(info);
err_disable:
pci_disable_device(pdev);
err_out:
return err;
}
static void __devexit e3d_pci_unregister(struct pci_dev *pdev)
{
struct fb_info *info = pci_get_drvdata(pdev);
struct e3d_info *ep = info->par;
unregister_framebuffer(info);
iounmap(ep->ramdac);
iounmap(ep->fb_base);
pci_release_region(pdev, 0);
pci_release_region(pdev, 1);
framebuffer_release(info);
pci_disable_device(pdev);
}
static struct pci_device_id e3d_pci_table[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_3DLABS, 0x7a0), },
{ PCI_DEVICE(PCI_VENDOR_ID_3DLABS, 0x7a2), },
{ .vendor = PCI_VENDOR_ID_3DLABS,
.device = PCI_ANY_ID,
.subvendor = PCI_VENDOR_ID_3DLABS,
.subdevice = 0x0108,
},
{ .vendor = PCI_VENDOR_ID_3DLABS,
.device = PCI_ANY_ID,
.subvendor = PCI_VENDOR_ID_3DLABS,
.subdevice = 0x0140,
},
{ .vendor = PCI_VENDOR_ID_3DLABS,
.device = PCI_ANY_ID,
.subvendor = PCI_VENDOR_ID_3DLABS,
.subdevice = 0x1024,
},
{ 0, }
};
static struct pci_driver e3d_driver = {
.name = "e3d",
.id_table = e3d_pci_table,
.probe = e3d_pci_register,
.remove = __devexit_p(e3d_pci_unregister),
};
static int __init e3d_init(void)
{
if (fb_get_options("e3d", NULL))
return -ENODEV;
return pci_register_driver(&e3d_driver);
}
static void __exit e3d_exit(void)
{
pci_unregister_driver(&e3d_driver);
}
module_init(e3d_init);
module_exit(e3d_exit);
MODULE_DESCRIPTION("framebuffer driver for Sun XVR-500 graphics");
MODULE_AUTHOR("David S. Miller <davem@davemloft.net>");
MODULE_VERSION("1.0");
MODULE_LICENSE("GPL");
......@@ -32,6 +32,7 @@ struct iommu {
unsigned long iommu_control;
unsigned long iommu_tsbbase;
unsigned long iommu_flush;
unsigned long iommu_flushinv;
unsigned long iommu_ctxflush;
unsigned long write_complete_reg;
unsigned long dummy_page;
......
......@@ -272,7 +272,7 @@ static void __kfree_section_memmap(struct page *memmap, unsigned long nr_pages)
* Allocate the accumulated non-linear sections, allocate a mem_map
* for each and record the physical to section mapping.
*/
void sparse_init(void)
void __init sparse_init(void)
{
unsigned long pnum;
struct page *map;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment