core_titan.c 19.8 KB
Newer Older
Linus Torvalds's avatar
Linus Torvalds committed
1 2 3 4 5 6 7
/*
 *	linux/arch/alpha/kernel/core_titan.c
 *
 * Code common to all TITAN core logic chips.
 */

#include <linux/config.h>
8
#include <linux/module.h>
Linus Torvalds's avatar
Linus Torvalds committed
9 10 11 12 13
#include <linux/kernel.h>
#include <linux/types.h>
#include <linux/pci.h>
#include <linux/sched.h>
#include <linux/init.h>
Ivan Kokshaysky's avatar
Ivan Kokshaysky committed
14
#include <linux/vmalloc.h>
Linus Torvalds's avatar
Linus Torvalds committed
15

Ivan Kokshaysky's avatar
Ivan Kokshaysky committed
16
#include <asm/hwrpb.h>
Linus Torvalds's avatar
Linus Torvalds committed
17 18 19
#include <asm/ptrace.h>
#include <asm/system.h>
#include <asm/smp.h>
Ivan Kokshaysky's avatar
Ivan Kokshaysky committed
20 21
#include <asm/pgalloc.h>
#include <asm/tlbflush.h>
Linus Torvalds's avatar
Linus Torvalds committed
22 23 24 25 26 27

#define __EXTERN_INLINE inline
#include <asm/io.h>
#include <asm/core_titan.h>
#undef __EXTERN_INLINE

Linus Torvalds's avatar
Linus Torvalds committed
28 29
#include <linux/bootmem.h>

Linus Torvalds's avatar
Linus Torvalds committed
30 31 32
#include "proto.h"
#include "pci_impl.h"

33 34 35
/* Save Titan configuration data as the console had it set up.  */

struct
Linus Torvalds's avatar
Linus Torvalds committed
36 37 38 39
{
	unsigned long wsba[4];
	unsigned long wsm[4];
	unsigned long tba[4];
40
} saved_config[4] __attribute__((common));
Linus Torvalds's avatar
Linus Torvalds committed
41 42 43 44 45 46 47 48 49 50 51 52 53 54

/*
 * BIOS32-style PCI interface:
 */

#define DEBUG_MCHECK 0  /* 0 = minimum, 1 = debug, 2 = dump+dump */
#define DEBUG_CONFIG 0

#if DEBUG_CONFIG
# define DBG_CFG(args)	printk args
#else
# define DBG_CFG(args)
#endif

Ivan Kokshaysky's avatar
Ivan Kokshaysky committed
55 56 57 58

/*
 * Routines to access TIG registers.
 */
59
static inline volatile unsigned long *
Ivan Kokshaysky's avatar
Ivan Kokshaysky committed
60 61 62 63 64
mk_tig_addr(int offset)
{
	return (volatile unsigned long *)(TITAN_TIG_SPACE + (offset << 6));
}

65
static inline u8 
Ivan Kokshaysky's avatar
Ivan Kokshaysky committed
66 67 68 69 70 71
titan_read_tig(int offset, u8 value)
{
	volatile unsigned long *tig_addr = mk_tig_addr(offset);
	return (u8)(*tig_addr & 0xff);
}

72
static inline void 
Ivan Kokshaysky's avatar
Ivan Kokshaysky committed
73 74 75 76 77 78 79
titan_write_tig(int offset, u8 value)
{
	volatile unsigned long *tig_addr = mk_tig_addr(offset);
	*tig_addr = (unsigned long)value;
}


Linus Torvalds's avatar
Linus Torvalds committed
80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114
/*
 * Given a bus, device, and function number, compute resulting
 * configuration space address
 * accordingly.  It is therefore not safe to have concurrent
 * invocations to configuration space access routines, but there
 * really shouldn't be any need for this.
 *
 * Note that all config space accesses use Type 1 address format.
 *
 * Note also that type 1 is determined by non-zero bus number.
 *
 * Type 1:
 *
 *  3 3|3 3 2 2|2 2 2 2|2 2 2 2|1 1 1 1|1 1 1 1|1 1 
 *  3 2|1 0 9 8|7 6 5 4|3 2 1 0|9 8 7 6|5 4 3 2|1 0 9 8|7 6 5 4|3 2 1 0
 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 * | | | | | | | | | | |B|B|B|B|B|B|B|B|D|D|D|D|D|F|F|F|R|R|R|R|R|R|0|1|
 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 *
 *	31:24	reserved
 *	23:16	bus number (8 bits = 128 possible buses)
 *	15:11	Device number (5 bits)
 *	10:8	function number
 *	 7:2	register number
 *  
 * Notes:
 *	The function number selects which function of a multi-function device 
 *	(e.g., SCSI and Ethernet).
 * 
 *	The register selects a DWORD (32 bit) register offset.  Hence it
 *	doesn't get shifted by 2 bits as we want to "drop" the bottom two
 *	bits.
 */

static int
115 116
mk_conf_addr(struct pci_bus *pbus, unsigned int device_fn, int where,
	     unsigned long *pci_addr, unsigned char *type1)
Linus Torvalds's avatar
Linus Torvalds committed
117
{
118
	struct pci_controller *hose = pbus->sysdata;
Linus Torvalds's avatar
Linus Torvalds committed
119
	unsigned long addr;
120
	u8 bus = pbus->number;
Linus Torvalds's avatar
Linus Torvalds committed
121 122 123 124 125

	DBG_CFG(("mk_conf_addr(bus=%d ,device_fn=0x%x, where=0x%x, "
		 "pci_addr=0x%p, type1=0x%p)\n",
		 bus, device_fn, where, pci_addr, type1));

126
        if (hose->first_busno == bus)
Linus Torvalds's avatar
Linus Torvalds committed
127 128 129 130 131 132 133 134 135 136 137 138
		bus = 0;
        *type1 = (bus != 0);

        addr = (bus << 16) | (device_fn << 8) | where;
	addr |= hose->config_space_base;
		
	*pci_addr = addr;
	DBG_CFG(("mk_conf_addr: returning pci_addr 0x%lx\n", addr));
	return 0;
}

static int
139 140
titan_read_config(struct pci_bus *bus, unsigned int devfn, int where,
		  int size, u32 *value)
Linus Torvalds's avatar
Linus Torvalds committed
141 142 143 144
{
	unsigned long addr;
	unsigned char type1;

145
	if (mk_conf_addr(bus, devfn, where, &addr, &type1))
Linus Torvalds's avatar
Linus Torvalds committed
146 147
		return PCIBIOS_DEVICE_NOT_FOUND;

148 149 150 151 152 153 154 155 156 157 158
	switch (size) {
	case 1:
		*value = __kernel_ldbu(*(vucp)addr);
		break;
	case 2:
		*value = __kernel_ldwu(*(vusp)addr);
		break;
	case 4:
		*value = *(vuip)addr;
		break;
	}
Linus Torvalds's avatar
Linus Torvalds committed
159 160 161 162 163

	return PCIBIOS_SUCCESSFUL;
}

static int 
164 165
titan_write_config(struct pci_bus *bus, unsigned int devfn, int where,
		   int size, u32 value)
Linus Torvalds's avatar
Linus Torvalds committed
166 167 168 169
{
	unsigned long addr;
	unsigned char type1;

170
	if (mk_conf_addr(bus, devfn, where, &addr, &type1))
Linus Torvalds's avatar
Linus Torvalds committed
171 172
		return PCIBIOS_DEVICE_NOT_FOUND;

173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189
	switch (size) {
	case 1:
		__kernel_stb(value, *(vucp)addr);
		mb();
		__kernel_ldbu(*(vucp)addr);
		break;
	case 2:
		__kernel_stw(value, *(vusp)addr);
		mb();
		__kernel_ldwu(*(vusp)addr);
		break;
	case 4:
		*(vuip)addr = value;
		mb();
		*(vuip)addr;
		break;
	}
Linus Torvalds's avatar
Linus Torvalds committed
190 191 192 193 194 195

	return PCIBIOS_SUCCESSFUL;
}

struct pci_ops titan_pci_ops = 
{
196 197
	.read =		titan_read_config,
	.write =	titan_write_config,
Linus Torvalds's avatar
Linus Torvalds committed
198 199 200 201
};


void
Linus Torvalds's avatar
Linus Torvalds committed
202
titan_pci_tbi(struct pci_controller *hose, dma_addr_t start, dma_addr_t end)
Linus Torvalds's avatar
Linus Torvalds committed
203 204 205 206 207 208 209
{
	titan_pachip *pachip = 
	  (hose->index & 1) ? TITAN_pachip1 : TITAN_pachip0;
	titan_pachip_port *port;
	volatile unsigned long *csr;
	unsigned long value;

210
	/* Get the right hose.  */
Linus Torvalds's avatar
Linus Torvalds committed
211 212 213 214 215
	port = &pachip->g_port;
	if (hose->index & 2) 
		port = &pachip->a_port;

	/* We can invalidate up to 8 tlb entries in a go.  The flush
Ivan Kokshaysky's avatar
Ivan Kokshaysky committed
216 217 218 219
	   matches against <31:16> in the pci address.  
	   Note that gtlbi* and atlbi* are in the same place in the g_port
	   and a_port, respectively, so the g_port offset can be used
	   even if hose is an a_port */
Linus Torvalds's avatar
Linus Torvalds committed
220 221 222 223 224 225 226 227 228 229 230 231 232 233
	csr = &port->port_specific.g.gtlbia.csr;
	if (((start ^ end) & 0xffff0000) == 0)
		csr = &port->port_specific.g.gtlbiv.csr;

	/* For TBIA, it doesn't matter what value we write.  For TBI, 
	   it's the shifted tag bits.  */
	value = (start & 0xffff0000) >> 12;

	wmb();
	*csr = value;
	mb();
	*csr;
}

Ivan Kokshaysky's avatar
Ivan Kokshaysky committed
234
static int
Linus Torvalds's avatar
Linus Torvalds committed
235 236 237 238 239 240 241 242 243 244
titan_query_agp(titan_pachip_port *port)
{
	union TPAchipPCTL pctl;

	/* set up APCTL */
	pctl.pctl_q_whole = port->pctl.csr;

	return pctl.pctl_r_bits.apctl_v_agp_present;

}
245

Linus Torvalds's avatar
Linus Torvalds committed
246 247 248
static void __init
titan_init_one_pachip_port(titan_pachip_port *port, int index)
{
Linus Torvalds's avatar
Linus Torvalds committed
249
	struct pci_controller *hose;
Linus Torvalds's avatar
Linus Torvalds committed
250

Linus Torvalds's avatar
Linus Torvalds committed
251
	hose = alloc_pci_controller();
Linus Torvalds's avatar
Linus Torvalds committed
252 253 254 255 256
	if (index == 0)
		pci_isa_hose = hose;
	hose->io_space = alloc_resource();
	hose->mem_space = alloc_resource();

Ivan Kokshaysky's avatar
Ivan Kokshaysky committed
257 258 259 260 261 262 263
	/*
	 * This is for userland consumption.  The 40-bit PIO bias that we 
	 * use in the kernel through KSEG doesn't work in the page table 
	 * based user mappings. (43-bit KSEG sign extends the physical
	 * address from bit 40 to hit the I/O bit - mapped addresses don't).
	 * So make sure we get the 43-bit PIO bias.  
	 */
Linus Torvalds's avatar
Linus Torvalds committed
264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292
	hose->sparse_mem_base = 0;
	hose->sparse_io_base = 0;
	hose->dense_mem_base
	  = (TITAN_MEM(index) & 0xffffffffff) | 0x80000000000;
	hose->dense_io_base
	  = (TITAN_IO(index) & 0xffffffffff) | 0x80000000000;

	hose->config_space_base = TITAN_CONF(index);
	hose->index = index;

	hose->io_space->start = TITAN_IO(index) - TITAN_IO_BIAS;
	hose->io_space->end = hose->io_space->start + TITAN_IO_SPACE - 1;
	hose->io_space->name = pci_io_names[index];
	hose->io_space->flags = IORESOURCE_IO;

	hose->mem_space->start = TITAN_MEM(index) - TITAN_MEM_BIAS;
	hose->mem_space->end = hose->mem_space->start + 0xffffffff;
	hose->mem_space->name = pci_mem_names[index];
	hose->mem_space->flags = IORESOURCE_MEM;

	if (request_resource(&ioport_resource, hose->io_space) < 0)
		printk(KERN_ERR "Failed to request IO on hose %d\n", index);
	if (request_resource(&iomem_resource, hose->mem_space) < 0)
		printk(KERN_ERR "Failed to request MEM on hose %d\n", index);

	/*
	 * Save the existing PCI window translations.  SRM will 
	 * need them when we go to reboot.
	 */
293 294 295
	saved_config[index].wsba[0] = port->wsba[0].csr;
	saved_config[index].wsm[0]  = port->wsm[0].csr;
	saved_config[index].tba[0]  = port->tba[0].csr;
Linus Torvalds's avatar
Linus Torvalds committed
296

297 298 299
	saved_config[index].wsba[1] = port->wsba[1].csr;
	saved_config[index].wsm[1]  = port->wsm[1].csr;
	saved_config[index].tba[1]  = port->tba[1].csr;
Linus Torvalds's avatar
Linus Torvalds committed
300

301 302 303
	saved_config[index].wsba[2] = port->wsba[2].csr;
	saved_config[index].wsm[2]  = port->wsm[2].csr;
	saved_config[index].tba[2]  = port->tba[2].csr;
Linus Torvalds's avatar
Linus Torvalds committed
304

305 306 307
	saved_config[index].wsba[3] = port->wsba[3].csr;
	saved_config[index].wsm[3]  = port->wsm[3].csr;
	saved_config[index].tba[3]  = port->tba[3].csr;
Linus Torvalds's avatar
Linus Torvalds committed
308 309 310 311

	/*
	 * Set up the PCI to main memory translation windows.
	 *
312
	 * Note: Window 3 on Titan is Scatter-Gather ONLY.
Linus Torvalds's avatar
Linus Torvalds committed
313 314
	 *
	 * Window 0 is scatter-gather 8MB at 8MB (for isa)
Ivan Kokshaysky's avatar
Ivan Kokshaysky committed
315 316
	 * Window 1 is direct access 1GB at 2GB
	 * Window 2 is scatter-gather 1GB at 3GB
Linus Torvalds's avatar
Linus Torvalds committed
317 318 319 320
	 */
	hose->sg_isa = iommu_arena_new(hose, 0x00800000, 0x00800000, 0);
	hose->sg_isa->align_entry = 8; /* 64KB for ISA */

Ivan Kokshaysky's avatar
Ivan Kokshaysky committed
321
	hose->sg_pci = iommu_arena_new(hose, 0xc0000000, 0x40000000, 0);
Linus Torvalds's avatar
Linus Torvalds committed
322 323 324 325 326 327
	hose->sg_pci->align_entry = 4; /* Titan caches 4 PTEs at a time */

	port->wsba[0].csr = hose->sg_isa->dma_base | 3;
	port->wsm[0].csr  = (hose->sg_isa->size - 1) & 0xfff00000;
	port->tba[0].csr  = virt_to_phys(hose->sg_isa->ptes);

Ivan Kokshaysky's avatar
Ivan Kokshaysky committed
328 329 330
	port->wsba[1].csr = __direct_map_base | 1;
	port->wsm[1].csr  = (__direct_map_size - 1) & 0xfff00000;
	port->tba[1].csr  = 0;
Linus Torvalds's avatar
Linus Torvalds committed
331

Ivan Kokshaysky's avatar
Ivan Kokshaysky committed
332 333 334
	port->wsba[2].csr = hose->sg_pci->dma_base | 3;
	port->wsm[2].csr  = (hose->sg_pci->size - 1) & 0xfff00000;
	port->tba[2].csr  = virt_to_phys(hose->sg_pci->ptes);
Linus Torvalds's avatar
Linus Torvalds committed
335 336

	port->wsba[3].csr = 0;
Linus Torvalds's avatar
Linus Torvalds committed
337

338
	/* Enable the Monster Window to make DAC pci64 possible.  */
Linus Torvalds's avatar
Linus Torvalds committed
339
	port->pctl.csr |= pctl_m_mwin;
Linus Torvalds's avatar
Linus Torvalds committed
340

Ivan Kokshaysky's avatar
Ivan Kokshaysky committed
341
	/*
342
	 * If it's an AGP port, initialize agplastwr.
Ivan Kokshaysky's avatar
Ivan Kokshaysky committed
343 344 345 346
	 */
	if (titan_query_agp(port)) 
		port->port_specific.a.agplastwr.csr = __direct_map_base;

Linus Torvalds's avatar
Linus Torvalds committed
347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363
	titan_pci_tbi(hose, 0, -1);
}

static void __init
titan_init_pachips(titan_pachip *pachip0, titan_pachip *pachip1)
{
	int pchip1_present = TITAN_cchip->csc.csr & 1L<<14;

	/* Init the ports in hose order... */
	titan_init_one_pachip_port(&pachip0->g_port, 0);	/* hose 0 */
	if (pchip1_present)
		titan_init_one_pachip_port(&pachip1->g_port, 1);/* hose 1 */
	titan_init_one_pachip_port(&pachip0->a_port, 2);	/* hose 2 */
	if (pchip1_present)
		titan_init_one_pachip_port(&pachip1->a_port, 3);/* hose 3 */
}

Ivan Kokshaysky's avatar
Ivan Kokshaysky committed
364 365 366 367 368 369 370 371 372 373 374 375 376 377
static void __init
titan_init_vga_hose(void)
{
#ifdef CONFIG_VGA_HOSE
	u64 *pu64 = (u64 *)((u64)hwrpb + hwrpb->ctbt_offset);

	if (pu64[7] == 3) {	/* TERM_TYPE == graphics */
		struct pci_controller *hose;
		int h = (pu64[30] >> 24) & 0xff;	/* console hose # */

		/*
		 * Our hose numbering matches the console's, so just find
		 * the right one...
		 */
378
		for (hose = hose_head; hose; hose = hose->next) {
Ivan Kokshaysky's avatar
Ivan Kokshaysky committed
379 380 381 382 383 384 385 386 387 388 389
			if (hose->index == h) break;
		}

		if (hose) {
			printk("Console graphics on hose %d\n", hose->index);
			pci_vga_hose = hose;
		}
	}
#endif /* CONFIG_VGA_HOSE */
}

Linus Torvalds's avatar
Linus Torvalds committed
390 391 392 393
void __init
titan_init_arch(void)
{
#if 0
Ivan Kokshaysky's avatar
Ivan Kokshaysky committed
394 395 396 397 398 399 400 401 402 403 404 405 406 407 408
	printk("%s: titan_init_arch()\n", __FUNCTION__);
	printk("%s: CChip registers:\n", __FUNCTION__);
	printk("%s: CSR_CSC 0x%lx\n", __FUNCTION__, TITAN_cchip->csc.csr);
	printk("%s: CSR_MTR 0x%lx\n", __FUNCTION__, TITAN_cchip->mtr.csr);
	printk("%s: CSR_MISC 0x%lx\n", __FUNCTION__, TITAN_cchip->misc.csr);
	printk("%s: CSR_DIM0 0x%lx\n", __FUNCTION__, TITAN_cchip->dim0.csr);
	printk("%s: CSR_DIM1 0x%lx\n", __FUNCTION__, TITAN_cchip->dim1.csr);
	printk("%s: CSR_DIR0 0x%lx\n", __FUNCTION__, TITAN_cchip->dir0.csr);
	printk("%s: CSR_DIR1 0x%lx\n", __FUNCTION__, TITAN_cchip->dir1.csr);
	printk("%s: CSR_DRIR 0x%lx\n", __FUNCTION__, TITAN_cchip->drir.csr);

	printk("%s: DChip registers:\n", __FUNCTION__);
	printk("%s: CSR_DSC 0x%lx\n", __FUNCTION__, TITAN_dchip->dsc.csr);
	printk("%s: CSR_STR 0x%lx\n", __FUNCTION__, TITAN_dchip->str.csr);
	printk("%s: CSR_DREV 0x%lx\n", __FUNCTION__, TITAN_dchip->drev.csr);
Linus Torvalds's avatar
Linus Torvalds committed
409 410 411 412 413 414 415 416
#endif

	boot_cpuid = __hard_smp_processor_id();

	/* With multiple PCI busses, we play with I/O as physical addrs.  */
	ioport_resource.end = ~0UL;
	iomem_resource.end = ~0UL;

417
	/* PCI DMA Direct Mapping is 1GB at 2GB.  */
Ivan Kokshaysky's avatar
Ivan Kokshaysky committed
418 419 420
	__direct_map_base = 0x80000000;
	__direct_map_size = 0x40000000;

421
	/* Init the PA chip(s).  */
Linus Torvalds's avatar
Linus Torvalds committed
422
	titan_init_pachips(TITAN_pachip0, TITAN_pachip1);
Ivan Kokshaysky's avatar
Ivan Kokshaysky committed
423

424
	/* Check for graphic console location (if any).  */
Ivan Kokshaysky's avatar
Ivan Kokshaysky committed
425
	titan_init_vga_hose();
Linus Torvalds's avatar
Linus Torvalds committed
426 427 428 429 430
}

static void
titan_kill_one_pachip_port(titan_pachip_port *port, int index)
{
431 432 433
	port->wsba[0].csr = saved_config[index].wsba[0];
	port->wsm[0].csr  = saved_config[index].wsm[0];
	port->tba[0].csr  = saved_config[index].tba[0];
Linus Torvalds's avatar
Linus Torvalds committed
434

435 436 437
	port->wsba[1].csr = saved_config[index].wsba[1];
	port->wsm[1].csr  = saved_config[index].wsm[1];
	port->tba[1].csr  = saved_config[index].tba[1];
Linus Torvalds's avatar
Linus Torvalds committed
438

439 440 441
	port->wsba[2].csr = saved_config[index].wsba[2];
	port->wsm[2].csr  = saved_config[index].wsm[2];
	port->tba[2].csr  = saved_config[index].tba[2];
Linus Torvalds's avatar
Linus Torvalds committed
442

443 444 445
	port->wsba[3].csr = saved_config[index].wsba[3];
	port->wsm[3].csr  = saved_config[index].wsm[3];
	port->tba[3].csr  = saved_config[index].tba[3];
Linus Torvalds's avatar
Linus Torvalds committed
446 447 448 449 450 451 452 453
}

static void
titan_kill_pachips(titan_pachip *pachip0, titan_pachip *pachip1)
{
	int pchip1_present = TITAN_cchip->csc.csr & 1L<<14;

	if (pchip1_present) {
454 455
		titan_kill_one_pachip_port(&pachip1->g_port, 1);
		titan_kill_one_pachip_port(&pachip1->a_port, 3);
Linus Torvalds's avatar
Linus Torvalds committed
456 457 458 459 460 461 462 463 464 465 466
	}
	titan_kill_one_pachip_port(&pachip0->g_port, 0);
	titan_kill_one_pachip_port(&pachip0->a_port, 2);
}

void
titan_kill_arch(int mode)
{
	titan_kill_pachips(TITAN_pachip0, TITAN_pachip1);
}

Ivan Kokshaysky's avatar
Ivan Kokshaysky committed
467 468

/*
469
 * IO map support.
Ivan Kokshaysky's avatar
Ivan Kokshaysky committed
470 471 472
 */
unsigned long
titan_ioremap(unsigned long addr, unsigned long size)
Linus Torvalds's avatar
Linus Torvalds committed
473
{
Ivan Kokshaysky's avatar
Ivan Kokshaysky committed
474 475 476 477 478 479 480 481 482 483
	int h = (addr & TITAN_HOSE_MASK) >> TITAN_HOSE_SHIFT;
	unsigned long baddr = addr & ~TITAN_HOSE_MASK;
	unsigned long last = baddr + size - 1;
	struct pci_controller *hose;	
	struct vm_struct *area;
	unsigned long vaddr;
	unsigned long *ptes;
	unsigned long pfn;

	/*
484
	 * Adjust the addr.
Ivan Kokshaysky's avatar
Ivan Kokshaysky committed
485 486 487 488 489 490 491 492 493
	 */ 
#ifdef CONFIG_VGA_HOSE
	if (pci_vga_hose && __titan_is_mem_vga(addr)) {
		h = pci_vga_hose->index;
		addr += pci_vga_hose->mem_space->start;
	}
#endif

	/*
494
	 * Find the hose.
Ivan Kokshaysky's avatar
Ivan Kokshaysky committed
495
	 */
496
	for (hose = hose_head; hose; hose = hose->next)
Ivan Kokshaysky's avatar
Ivan Kokshaysky committed
497 498 499 500 501 502 503 504 505 506 507
		if (hose->index == h) break;
	if (!hose) return (unsigned long)NULL;

	/*
	 * Is it direct-mapped?
	 */
	if ((baddr >= __direct_map_base) && 
	    ((baddr + size - 1) < __direct_map_base + __direct_map_size)) 
		return addr - __direct_map_base + TITAN_MEM_BIAS;

	/* 
508
	 * Check the scatter-gather arena.
Ivan Kokshaysky's avatar
Ivan Kokshaysky committed
509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527
	 */
	if (hose->sg_pci &&
	    baddr >= (unsigned long)hose->sg_pci->dma_base &&
	    last < (unsigned long)hose->sg_pci->dma_base + hose->sg_pci->size){

		/*
		 * Adjust the limits (mappings must be page aligned)
		 */
		baddr -= hose->sg_pci->dma_base;
		last -= hose->sg_pci->dma_base;
		baddr &= PAGE_MASK;
		size = PAGE_ALIGN(last) - baddr;

		/*
		 * Map it
		 */
		area = get_vm_area(size, VM_IOREMAP);
		if (!area) return (unsigned long)NULL;
		ptes = hose->sg_pci->ptes;
528
		for (vaddr = (unsigned long)area->addr; 
Ivan Kokshaysky's avatar
Ivan Kokshaysky committed
529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554
		    baddr <= last; 
		    baddr += PAGE_SIZE, vaddr += PAGE_SIZE) {
			pfn = ptes[baddr >> PAGE_SHIFT];
			if (!(pfn & 1)) {
				printk("ioremap failed... pte not valid...\n");
				vfree(area->addr);
				return (unsigned long)NULL;
			}
			pfn >>= 1;	/* make it a true pfn */
			
			if (__alpha_remap_area_pages(VMALLOC_VMADDR(vaddr), 
						     pfn << PAGE_SHIFT, 
						     PAGE_SIZE, 0)) {
				printk("FAILED to map...\n");
				vfree(area->addr);
				return (unsigned long)NULL;
			}
		}

		flush_tlb_all();

		vaddr = (unsigned long)area->addr + (addr & ~PAGE_MASK);
		return vaddr;
	}

	/*
555
	 * Not found - assume legacy ioremap.
Ivan Kokshaysky's avatar
Ivan Kokshaysky committed
556 557
	 */
	return addr + TITAN_MEM_BIAS;
Linus Torvalds's avatar
Linus Torvalds committed
558 559 560

}

Ivan Kokshaysky's avatar
Ivan Kokshaysky committed
561 562
void
titan_iounmap(unsigned long addr)
Linus Torvalds's avatar
Linus Torvalds committed
563
{
Ivan Kokshaysky's avatar
Ivan Kokshaysky committed
564 565
	if (((long)addr >> 41) == -2)
		return;	/* kseg map, nothing to do */
566 567
	if (addr)
		vfree((void *)(PAGE_MASK & addr)); 
Ivan Kokshaysky's avatar
Ivan Kokshaysky committed
568
}
Linus Torvalds's avatar
Linus Torvalds committed
569

570
#ifndef CONFIG_ALPHA_GENERIC
571 572
EXPORT_SYMBOL(titan_ioremap);
EXPORT_SYMBOL(titan_iounmap);
573
#endif
Ivan Kokshaysky's avatar
Ivan Kokshaysky committed
574 575

/*
576
 * AGP GART Support.
Ivan Kokshaysky's avatar
Ivan Kokshaysky committed
577 578 579 580 581 582 583 584 585 586 587 588 589 590
 */
#include <linux/agp_backend.h>
#include <asm/agp_backend.h>
#include <linux/slab.h>
#include <linux/delay.h>

#define TITAN_AGP_APER_SIZE (64 * 1024 * 1024)

struct titan_agp_aperture {
	struct pci_iommu_arena *arena;
	long pg_start;
	long pg_count;
};

591 592
static int
titan_agp_setup(alpha_agp_info *agp)
Ivan Kokshaysky's avatar
Ivan Kokshaysky committed
593 594 595 596
{
	struct titan_agp_aperture *aper;

	aper = kmalloc(sizeof(struct titan_agp_aperture), GFP_KERNEL);
597 598
	if (aper == NULL)
		return -ENOMEM;
Ivan Kokshaysky's avatar
Ivan Kokshaysky committed
599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615

	aper->arena = agp->hose->sg_pci;
	aper->pg_count = TITAN_AGP_APER_SIZE / PAGE_SIZE;
	aper->pg_start = iommu_reserve(aper->arena, aper->pg_count,
				       aper->pg_count - 1);
	if (aper->pg_start < 0) {
		printk(KERN_ERR "Failed to reserve AGP memory\n");
		kfree(aper);
		return -ENOMEM;
	}

	agp->aperture.bus_base = 
		aper->arena->dma_base + aper->pg_start * PAGE_SIZE;
	agp->aperture.size = aper->pg_count * PAGE_SIZE;
	agp->aperture.sysdata = aper;

	return 0;
Linus Torvalds's avatar
Linus Torvalds committed
616 617
}

618 619
static void
titan_agp_cleanup(alpha_agp_info *agp)
Linus Torvalds's avatar
Linus Torvalds committed
620
{
Ivan Kokshaysky's avatar
Ivan Kokshaysky committed
621 622 623 624 625 626 627 628 629 630 631
	struct titan_agp_aperture *aper = agp->aperture.sysdata;
	int status;

	status = iommu_release(aper->arena, aper->pg_start, aper->pg_count);
	if (status == -EBUSY) {
		printk(KERN_WARNING 
		       "Attempted to release bound AGP memory - unbinding\n");
		iommu_unbind(aper->arena, aper->pg_start, aper->pg_count);
		status = iommu_release(aper->arena, aper->pg_start, 
				       aper->pg_count);
	}
632 633
	if (status < 0)
		printk(KERN_ERR "Failed to release AGP memory\n");
Linus Torvalds's avatar
Linus Torvalds committed
634

Ivan Kokshaysky's avatar
Ivan Kokshaysky committed
635 636
	kfree(aper);
	kfree(agp);
Linus Torvalds's avatar
Linus Torvalds committed
637 638
}

639 640
static int
titan_agp_configure(alpha_agp_info *agp)
Ivan Kokshaysky's avatar
Ivan Kokshaysky committed
641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662
{
	union TPAchipPCTL pctl;
	titan_pachip_port *port = agp->private;
	pctl.pctl_q_whole = port->pctl.csr;

	/* Side-Band Addressing? */
	pctl.pctl_r_bits.apctl_v_agp_sba_en = agp->mode.bits.sba;

	/* AGP Rate? */
	pctl.pctl_r_bits.apctl_v_agp_rate = 0;		/* 1x */
	if (agp->mode.bits.rate & 2) 
		pctl.pctl_r_bits.apctl_v_agp_rate = 1;	/* 2x */
#if 0
	if (agp->mode.bits.rate & 4) 
		pctl.pctl_r_bits.apctl_v_agp_rate = 2;	/* 4x */
#endif
	
	/* RQ Depth? */
	pctl.pctl_r_bits.apctl_v_agp_hp_rd = 2;
	pctl.pctl_r_bits.apctl_v_agp_lp_rd = 7;

	/*
663
	 * AGP Enable.
Ivan Kokshaysky's avatar
Ivan Kokshaysky committed
664 665 666
	 */
	pctl.pctl_r_bits.apctl_v_agp_en = agp->mode.bits.enable;

667
	/* Tell the user.  */
Ivan Kokshaysky's avatar
Ivan Kokshaysky committed
668 669 670 671
	printk("Enabling AGP: %dX%s\n", 
	       1 << pctl.pctl_r_bits.apctl_v_agp_rate,
	       pctl.pctl_r_bits.apctl_v_agp_sba_en ? " - SBA" : "");
	       
672
	/* Write it.  */
Ivan Kokshaysky's avatar
Ivan Kokshaysky committed
673 674
	port->pctl.csr = pctl.pctl_q_whole;
	
675
	/* And wait at least 5000 66MHz cycles (per Titan spec).  */
Ivan Kokshaysky's avatar
Ivan Kokshaysky committed
676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738
	udelay(100);

	return 0;
}

static int 
titan_agp_bind_memory(alpha_agp_info *agp, off_t pg_start, agp_memory *mem)
{
	struct titan_agp_aperture *aper = agp->aperture.sysdata;
	return iommu_bind(aper->arena, aper->pg_start + pg_start, 
			  mem->page_count, mem->memory);
}

static int 
titan_agp_unbind_memory(alpha_agp_info *agp, off_t pg_start, agp_memory *mem)
{
	struct titan_agp_aperture *aper = agp->aperture.sysdata;
	return iommu_unbind(aper->arena, aper->pg_start + pg_start,
			    mem->page_count);
}

static unsigned long
titan_agp_translate(alpha_agp_info *agp, dma_addr_t addr)
{
	struct titan_agp_aperture *aper = agp->aperture.sysdata;
	unsigned long baddr = addr - aper->arena->dma_base;
	unsigned long pte;

	if (addr < agp->aperture.bus_base ||
	    addr >= agp->aperture.bus_base + agp->aperture.size) {
		printk("%s: addr out of range\n", __FUNCTION__);
		return -EINVAL;
	}

	pte = aper->arena->ptes[baddr >> PAGE_SHIFT];
	if (!(pte & 1)) {
		printk("%s: pte not valid\n", __FUNCTION__);
		return -EINVAL;
	}

	return (pte >> 1) << PAGE_SHIFT;
}

struct alpha_agp_ops titan_agp_ops =
{
	setup:		titan_agp_setup,
	cleanup:	titan_agp_cleanup,
	configure:	titan_agp_configure,
	bind:		titan_agp_bind_memory,
	unbind:		titan_agp_unbind_memory,
	translate:	titan_agp_translate
};

alpha_agp_info *
titan_agp_info(void)
{
	alpha_agp_info *agp;
	struct pci_controller *hose;
	titan_pachip_port *port;
	int hosenum = -1;
	union TPAchipPCTL pctl;

	/*
739
	 * Find the AGP port.
Ivan Kokshaysky's avatar
Ivan Kokshaysky committed
740 741 742 743 744 745 746 747 748
	 */
	port = &TITAN_pachip0->a_port;
	if (titan_query_agp(port))
		hosenum = 2;
	if (hosenum < 0 && 
	    titan_query_agp(port = &TITAN_pachip1->a_port)) 
		hosenum = 3;
	
	/*
749
	 * Find the hose the port is on.
Ivan Kokshaysky's avatar
Ivan Kokshaysky committed
750
	 */
751 752 753
	for (hose = hose_head; hose; hose = hose->next)
		if (hose->index == hosenum)
			break;
Ivan Kokshaysky's avatar
Ivan Kokshaysky committed
754

755 756
	if (!hose || !hose->sg_pci)
		return NULL;
Ivan Kokshaysky's avatar
Ivan Kokshaysky committed
757 758

	/*
759
	 * Allocate the info structure.
Ivan Kokshaysky's avatar
Ivan Kokshaysky committed
760 761 762 763
	 */
	agp = kmalloc(sizeof(*agp), GFP_KERNEL);

	/*
764
	 * Fill it in.
Ivan Kokshaysky's avatar
Ivan Kokshaysky committed
765
	 */
766
	agp->type = 0 /* FIXME: ALPHA_CORE_AGP */;
Ivan Kokshaysky's avatar
Ivan Kokshaysky committed
767 768 769 770 771
	agp->hose = hose;
	agp->private = port;
	agp->ops = &titan_agp_ops;

	/*
772
	 * Aperture - not configured until ops.setup().
Ivan Kokshaysky's avatar
Ivan Kokshaysky committed
773 774 775 776 777 778 779 780
	 *
	 * FIXME - should we go ahead and allocate it here?
	 */
	agp->aperture.bus_base = 0;
	agp->aperture.size = 0;
	agp->aperture.sysdata = NULL;

	/*
781
	 * Capabilities.
Ivan Kokshaysky's avatar
Ivan Kokshaysky committed
782 783 784 785 786 787 788
	 */
	agp->capability.lw = 0;
	agp->capability.bits.rate = 3; 	/* 2x, 1x */
	agp->capability.bits.sba = 1;
	agp->capability.bits.rq = 7;	/* 8 - 1 */

	/*
789
	 * Mode.
Ivan Kokshaysky's avatar
Ivan Kokshaysky committed
790 791 792 793 794 795 796 797 798 799
	 */
	pctl.pctl_q_whole = port->pctl.csr;
	agp->mode.lw = 0;
	agp->mode.bits.rate = 1 << pctl.pctl_r_bits.apctl_v_agp_rate;
	agp->mode.bits.sba = pctl.pctl_r_bits.apctl_v_agp_sba_en;
	agp->mode.bits.rq = 7;	/* RQ Depth? */
	agp->mode.bits.enable = pctl.pctl_r_bits.apctl_v_agp_en;

	return agp;
}