summaryrefslogtreecommitdiffstats
path: root/arch/sh/boards/renesas/hs7751rvoip/pci.c
blob: 7a442d1eca46861e891a0e832942756b4760c06e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
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
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
/*
 * linux/arch/sh/kernel/pci-hs7751rvoip.c
 *
 * Author:  Ian DaSilva (idasilva@mvista.com)
 *
 * Highly leveraged from pci-bigsur.c, written by Dustin McIntire.
 *
 * May be copied or modified under the terms of the GNU General Public
 * License.  See linux/COPYING for more information.
 *
 * PCI initialization for the Renesas SH7751R HS7751RVoIP board
 */

#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/types.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/pci.h>
#include <linux/module.h>

#include <asm/io.h>
#include "../../../drivers/pci/pci-sh7751.h"
#include <asm/hs7751rvoip/hs7751rvoip.h>

#define PCIMCR_MRSET_OFF	0xBFFFFFFF
#define PCIMCR_RFSH_OFF		0xFFFFFFFB

/*
 * Only long word accesses of the PCIC's internal local registers and the
 * configuration registers from the CPU is supported.
 */
#define PCIC_WRITE(x,v) writel((v), PCI_REG(x))
#define PCIC_READ(x) readl(PCI_REG(x))

/*
 * Description:  This function sets up and initializes the pcic, sets
 * up the BARS, maps the DRAM into the address space etc, etc.
 */
int __init pcibios_init_platform(void)
{
	unsigned long bcr1, wcr1, wcr2, wcr3, mcr;
	unsigned short bcr2, bcr3;

	/*
	 * Initialize the slave bus controller on the pcic.  The values used
	 * here should not be hardcoded, but they should be taken from the bsc
	 * on the processor, to make this function as generic as possible.
	 * (i.e. Another sbc may usr different SDRAM timing settings -- in order
	 * for the pcic to work, its settings need to be exactly the same.)
	 */
	bcr1 = (*(volatile unsigned long *)(SH7751_BCR1));
	bcr2 = (*(volatile unsigned short *)(SH7751_BCR2));
	bcr3 = (*(volatile unsigned short *)(SH7751_BCR3));
	wcr1 = (*(volatile unsigned long *)(SH7751_WCR1));
	wcr2 = (*(volatile unsigned long *)(SH7751_WCR2));
	wcr3 = (*(volatile unsigned long *)(SH7751_WCR3));
	mcr = (*(volatile unsigned long *)(SH7751_MCR));

	bcr1 = bcr1 | 0x00080000;  /* Enable Bit 19, BREQEN */
	(*(volatile unsigned long *)(SH7751_BCR1)) = bcr1;

	bcr1 = bcr1 | 0x40080000;  /* Enable Bit 19 BREQEN, set PCIC to slave */
	PCIC_WRITE(SH7751_PCIBCR1, bcr1);	/* PCIC BCR1 */
	PCIC_WRITE(SH7751_PCIBCR2, bcr2);	/* PCIC BCR2 */
	PCIC_WRITE(SH7751_PCIBCR3, bcr3);	/* PCIC BCR3 */
	PCIC_WRITE(SH7751_PCIWCR1, wcr1);	/* PCIC WCR1 */
	PCIC_WRITE(SH7751_PCIWCR2, wcr2);	/* PCIC WCR2 */
	PCIC_WRITE(SH7751_PCIWCR3, wcr3);	/* PCIC WCR3 */
	mcr = (mcr & PCIMCR_MRSET_OFF) & PCIMCR_RFSH_OFF;
	PCIC_WRITE(SH7751_PCIMCR, mcr);		/* PCIC MCR */

	/* Enable all interrupts, so we know what to fix */
	PCIC_WRITE(SH7751_PCIINTM, 0x0000c3ff);
	PCIC_WRITE(SH7751_PCIAINTM, 0x0000380f);

	/* Set up standard PCI config registers */
	PCIC_WRITE(SH7751_PCICONF1, 0xFB900047); /* Bus Master, Mem & I/O access */
	PCIC_WRITE(SH7751_PCICONF2, 0x00000000); /* PCI Class code & Revision ID */
	PCIC_WRITE(SH7751_PCICONF4, 0xab000001); /* PCI I/O address (local regs) */
	PCIC_WRITE(SH7751_PCICONF5, 0x0c000000); /* PCI MEM address (local RAM)  */
	PCIC_WRITE(SH7751_PCICONF6, 0xd0000000); /* PCI MEM address (unused) */
	PCIC_WRITE(SH7751_PCICONF11, 0x35051054); /* PCI Subsystem ID & Vendor ID */
	PCIC_WRITE(SH7751_PCILSR0, 0x03f00000);	/* MEM (full 64M exposed) */
	PCIC_WRITE(SH7751_PCILSR1, 0x00000000); /* MEM (unused) */
	PCIC_WRITE(SH7751_PCILAR0, 0x0c000000); /* MEM (direct map from PCI) */
	PCIC_WRITE(SH7751_PCILAR1, 0x00000000); /* MEM (unused) */

	/* Now turn it on... */
	PCIC_WRITE(SH7751_PCICR, 0xa5000001);

	/*
	 * Set PCIMBR and PCIIOBR here, assuming a single window
	 * (16M MEM, 256K IO) is enough.  If a larger space is
	 * needed, the readx/writex and inx/outx functions will
	 * have to do more (e.g. setting registers for each call).
	 */

	/*
	 * Set the MBR so PCI address is one-to-one with window,
	 * meaning all calls go straight through... use ifdef to
	 * catch erroneous assumption.
	 */
	BUG_ON(PCIBIOS_MIN_MEM != SH7751_PCI_MEMORY_BASE);

	PCIC_WRITE(SH7751_PCIMBR, PCIBIOS_MIN_MEM);

	/* Set IOBR for window containing area specified in pci.h */
	PCIC_WRITE(SH7751_PCIIOBR, (PCIBIOS_MIN_IO & SH7751_PCIIOBR_MASK));

	/* All done, may as well say so... */
	printk("SH7751R PCI: Finished initialization of the PCI controller\n");

	return 1;
}

int __init pcibios_map_platform_irq(u8 slot, u8 pin)
{
        switch (slot) {
	case 0: return IRQ_PCISLOT;	/* PCI Extend slot */
	case 1: return IRQ_PCMCIA;	/* PCI Cardbus Bridge */
	case 2: return IRQ_PCIETH;	/* Realtek Ethernet controller */
	case 3: return IRQ_PCIHUB;	/* Realtek Ethernet Hub controller */
	default:
		printk("PCI: Bad IRQ mapping request for slot %d\n", slot);
		return -1;
	}
}

static struct resource sh7751_io_resource = {
	.name	= "SH7751_IO",
	.start	= 0x4000,
	.end	= 0x4000 + SH7751_PCI_IO_SIZE - 1,
	.flags	= IORESOURCE_IO
};

static struct resource sh7751_mem_resource = {
	.name	= "SH7751_mem",
	.start	= SH7751_PCI_MEMORY_BASE,
	.end	= SH7751_PCI_MEMORY_BASE + SH7751_PCI_MEM_SIZE - 1,
	.flags	= IORESOURCE_MEM
};

extern struct pci_ops sh7751_pci_ops;

struct pci_channel board_pci_channels[] = {
	{ &sh7751_pci_ops, &sh7751_io_resource, &sh7751_mem_resource, 0, 0xff },
	{ NULL, NULL, NULL, 0, 0 },
};
EXPORT_SYMBOL(board_pci_channels);
OpenPOWER on IntegriCloud