cm-x2xx-pci.c 5.24 KB
Newer Older
1
/*
2
 * linux/arch/arm/mach-pxa/cm-x2xx-pci.c
3 4 5 6 7
 *
 * PCI bios-type initialisation for PCI machines
 *
 * Bits taken from various places.
 *
8
 * Copyright (C) 2007, 2008 Compulab, Ltd.
9 10 11 12 13 14 15 16 17 18 19 20 21
 * Mike Rapoport <mike@compulab.co.il>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 as
 * published by the Free Software Foundation.
 */

#include <linux/kernel.h>
#include <linux/pci.h>
#include <linux/init.h>
#include <linux/device.h>
#include <linux/platform_device.h>
#include <linux/irq.h>
22
#include <linux/gpio.h>
23 24 25 26 27 28

#include <asm/mach/pci.h>
#include <asm/mach-types.h>

#include <asm/hardware/it8152.h>

29
unsigned long it8152_base_address;
30
static int cmx2xx_it8152_irq_gpio;
31 32 33 34 35 36 37

/*
 * Only first 64MB of memory can be accessed via PCI.
 * We use GFP_DMA to allocate safe buffers to do map/unmap.
 * This is really ugly and we need a better way of specifying
 * DMA-capable regions of memory.
 */
38
void __init cmx2xx_pci_adjust_zones(unsigned long *zone_size,
39 40 41 42
	unsigned long *zhole_size)
{
	unsigned int sz = SZ_64M >> PAGE_SHIFT;

43
	if (machine_is_armcore()) {
44
		pr_info("Adjusting zones for CM-X2XX\n");
45 46 47 48

		/*
		 * Only adjust if > 64M on current system
		 */
49
		if (zone_size[0] <= sz)
50 51 52 53 54 55 56
			return;

		zone_size[1] = zone_size[0] - sz;
		zone_size[0] = sz;
		zhole_size[1] = zhole_size[0];
		zhole_size[0] = 0;
	}
57 58
}

59
static void cmx2xx_it8152_irq_demux(unsigned int irq, struct irq_desc *desc)
60 61
{
	/* clear our parent irq */
62
	desc->irq_data.chip->irq_ack(&desc->irq_data);
63 64 65 66

	it8152_irq_demux(irq, desc);
}

67
void __cmx2xx_pci_init_irq(int irq_gpio)
68 69 70
{
	it8152_init_irq();

71
	cmx2xx_it8152_irq_gpio = irq_gpio;
72

73
	set_irq_type(gpio_to_irq(irq_gpio), IRQ_TYPE_EDGE_RISING);
74

75
	set_irq_chained_handler(gpio_to_irq(irq_gpio), cmx2xx_it8152_irq_demux);
76 77 78 79 80
}

#ifdef CONFIG_PM
static unsigned long sleep_save_ite[10];

81
void __cmx2xx_pci_suspend(void)
82 83 84 85 86 87 88 89 90 91 92
{
	/* save ITE state */
	sleep_save_ite[0] = __raw_readl(IT8152_INTC_PDCNIMR);
	sleep_save_ite[1] = __raw_readl(IT8152_INTC_LPCNIMR);
	sleep_save_ite[2] = __raw_readl(IT8152_INTC_LPNIAR);

	/* Clear ITE IRQ's */
	__raw_writel((0), IT8152_INTC_PDCNIRR);
	__raw_writel((0), IT8152_INTC_LPCNIRR);
}

93
void __cmx2xx_pci_resume(void)
94 95 96 97 98 99 100
{
	/* restore IT8152 state */
	__raw_writel((sleep_save_ite[0]), IT8152_INTC_PDCNIMR);
	__raw_writel((sleep_save_ite[1]), IT8152_INTC_LPCNIMR);
	__raw_writel((sleep_save_ite[2]), IT8152_INTC_LPNIAR);
}
#else
101 102
void cmx2xx_pci_suspend(void) {}
void cmx2xx_pci_resume(void) {}
103 104 105
#endif

/* PCI IRQ mapping*/
106
static int __init cmx2xx_pci_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
107 108 109
{
	int irq;

110
	dev_dbg(&dev->dev, "%s: slot=%x, pin=%x\n", __func__, slot, pin);
111 112 113 114 115 116 117

	irq = it8152_pci_map_irq(dev, slot, pin);
	if (irq)
		return irq;

	/*
	  Here comes the ugly part. The routing is baseboard specific,
118 119
	  but defining a platform for each possible base of CM-X2XX is
	  unrealistic. Here we keep mapping for ATXBase and SB-X2XX.
120 121 122 123 124
	*/
	/* ATXBASE PCI slot */
	if (slot == 7)
		return IT8152_PCI_INTA;

125
	/* ATXBase/SB-X2XX CardBus */
126 127 128 129 130 131 132
	if (slot == 8 || slot == 0)
		return IT8152_PCI_INTB;

	/* ATXBase Ethernet */
	if (slot == 9)
		return IT8152_PCI_INTA;

133 134 135 136 137
	/* CM-x255 Onboard Ethernet */
	if (slot == 15)
		return IT8152_PCI_INTC;

	/* SB-x2xx Ethernet */
138 139 140 141 142 143 144 145 146 147 148 149
	if (slot == 16)
		return IT8152_PCI_INTA;

	/* PC104+ interrupt routing */
	if ((slot == 17) || (slot == 19))
		return IT8152_PCI_INTA;
	if ((slot == 18) || (slot == 20))
		return IT8152_PCI_INTB;

	return(0);
}

150
static void cmx2xx_pci_preinit(void)
151
{
152
	pr_info("Initializing CM-X2XX PCI subsystem\n");
153 154 155

	__raw_writel(0x800, IT8152_PCI_CFG_ADDR);
	if (__raw_readl(IT8152_PCI_CFG_DATA) == 0x81521283) {
Mike Rapoport's avatar
Mike Rapoport committed
156
		pr_info("PCI Bridge found.\n");
157 158 159 160 161 162 163 164 165 166 167 168 169 170

		/* set PCI I/O base at 0 */
		writel(0x848, IT8152_PCI_CFG_ADDR);
		writel(0, IT8152_PCI_CFG_DATA);

		/* set PCI memory base at 0 */
		writel(0x840, IT8152_PCI_CFG_ADDR);
		writel(0, IT8152_PCI_CFG_DATA);

		writel(0x20, IT8152_GPIO_GPDR);

		/* CardBus Controller on ATXbase baseboard */
		writel(0x4000, IT8152_PCI_CFG_ADDR);
		if (readl(IT8152_PCI_CFG_DATA) == 0xAC51104C) {
Mike Rapoport's avatar
Mike Rapoport committed
171
			pr_info("CardBus Bridge found.\n");
172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205

			/* Configure socket 0 */
			writel(0x408C, IT8152_PCI_CFG_ADDR);
			writel(0x1022, IT8152_PCI_CFG_DATA);

			writel(0x4080, IT8152_PCI_CFG_ADDR);
			writel(0x3844d060, IT8152_PCI_CFG_DATA);

			writel(0x4090, IT8152_PCI_CFG_ADDR);
			writel(((readl(IT8152_PCI_CFG_DATA) & 0xffff) |
				0x60440000),
			       IT8152_PCI_CFG_DATA);

			writel(0x4018, IT8152_PCI_CFG_ADDR);
			writel(0xb0000000, IT8152_PCI_CFG_DATA);

			/* Configure socket 1 */
			writel(0x418C, IT8152_PCI_CFG_ADDR);
			writel(0x1022, IT8152_PCI_CFG_DATA);

			writel(0x4180, IT8152_PCI_CFG_ADDR);
			writel(0x3844d060, IT8152_PCI_CFG_DATA);

			writel(0x4190, IT8152_PCI_CFG_ADDR);
			writel(((readl(IT8152_PCI_CFG_DATA) & 0xffff) |
				0x60440000),
			       IT8152_PCI_CFG_DATA);

			writel(0x4118, IT8152_PCI_CFG_ADDR);
			writel(0xb0000000, IT8152_PCI_CFG_DATA);
		}
	}
}

206
static struct hw_pci cmx2xx_pci __initdata = {
207
	.swizzle	= pci_std_swizzle,
208
	.map_irq	= cmx2xx_pci_map_irq,
209 210
	.nr_controllers	= 1,
	.setup		= it8152_pci_setup,
Mike Rapoport's avatar
Mike Rapoport committed
211
	.scan		= it8152_pci_scan_bus,
212
	.preinit	= cmx2xx_pci_preinit,
213 214
};

215
static int __init cmx2xx_init_pci(void)
216 217
{
	if (machine_is_armcore())
218
		pci_common_init(&cmx2xx_pci);
219 220 221 222

	return 0;
}

223
subsys_initcall(cmx2xx_init_pci);