]> git.proxmox.com Git - mirror_ubuntu-jammy-kernel.git/blame - arch/sh/drivers/pci/pci-sh7780.c
sh: Fix up large system memory handling for SH7780 PCI.
[mirror_ubuntu-jammy-kernel.git] / arch / sh / drivers / pci / pci-sh7780.c
CommitLineData
5283ecb5 1/*
62c7ae87 2 * Low-Level PCI Support for the SH7780
5283ecb5 3 *
a45635df 4 * Copyright (C) 2005 - 2010 Paul Mundt
5283ecb5 5 *
62c7ae87
PM
6 * This file is subject to the terms and conditions of the GNU General Public
7 * License. See the file "COPYING" in the main directory of this archive
8 * for more details.
5283ecb5 9 */
5283ecb5
PM
10#include <linux/types.h>
11#include <linux/kernel.h>
12#include <linux/init.h>
13#include <linux/pci.h>
5283ecb5 14#include <linux/errno.h>
5283ecb5 15#include <linux/delay.h>
aee4467b 16#include <linux/log2.h>
959f85f8 17#include "pci-sh4.h"
a45635df
PM
18#include <asm/mmu.h>
19#include <asm/sizes.h>
5283ecb5 20
e79066a6
PM
21static struct resource sh7785_io_resource = {
22 .name = "SH7785_IO",
a45635df
PM
23 .start = 0x1000,
24 .end = SH7780_PCI_IO_SIZE - 1,
e79066a6
PM
25 .flags = IORESOURCE_IO
26};
27
28static struct resource sh7785_mem_resource = {
29 .name = "SH7785_mem",
30 .start = SH7780_PCI_MEMORY_BASE,
31 .end = SH7780_PCI_MEMORY_BASE + SH7780_PCI_MEM_SIZE - 1,
32 .flags = IORESOURCE_MEM
33};
34
35static struct pci_channel sh7780_pci_controller = {
36 .pci_ops = &sh4_pci_ops,
37 .mem_resource = &sh7785_mem_resource,
09cfeb13 38 .mem_offset = 0x00000000,
e79066a6 39 .io_resource = &sh7785_io_resource,
09cfeb13 40 .io_offset = 0x00000000,
5582b064 41 .io_map_base = SH7780_PCI_IO_BASE,
e79066a6
PM
42};
43
e79066a6 44static int __init sh7780_pci_init(void)
5283ecb5 45{
e79066a6 46 struct pci_channel *chan = &sh7780_pci_controller;
a45635df
PM
47 phys_addr_t memphys;
48 size_t memsize;
959f85f8 49 unsigned int id;
a45635df 50 const char *type;
5283ecb5 51
4e7b7fdb 52 printk(KERN_NOTICE "PCI: Starting intialization.\n");
5283ecb5 53
e4c6a360
MD
54 chan->reg_base = 0xfe040000;
55
4e7b7fdb
PM
56 /* Enable CPU access to the PCIC registers. */
57 __raw_writel(PCIECR_ENBL, PCIECR);
5283ecb5 58
a45635df
PM
59 /* Reset */
60 __raw_writel(SH4_PCICR_PREFIX | SH4_PCICR_PRST,
61 chan->reg_base + SH4_PCICR);
62
aee4467b
PM
63 /*
64 * Wait for it to come back up. The spec says to allow for up to
65 * 1 second after toggling the reset pin, but in practice 100ms
66 * is more than enough.
67 */
a45635df
PM
68 mdelay(100);
69
70 id = __raw_readw(chan->reg_base + PCI_VENDOR_ID);
71 if (id != PCI_VENDOR_ID_RENESAS) {
4e7b7fdb
PM
72 printk(KERN_ERR "PCI: Unknown vendor ID 0x%04x.\n", id);
73 return -ENODEV;
32351a28
PM
74 }
75
a45635df
PM
76 id = __raw_readw(chan->reg_base + PCI_DEVICE_ID);
77 type = (id == PCI_DEVICE_ID_RENESAS_SH7763) ? "SH7763" :
78 (id == PCI_DEVICE_ID_RENESAS_SH7780) ? "SH7780" :
79 (id == PCI_DEVICE_ID_RENESAS_SH7781) ? "SH7781" :
80 (id == PCI_DEVICE_ID_RENESAS_SH7785) ? "SH7785" :
4e7b7fdb
PM
81 NULL;
82 if (unlikely(!type)) {
83 printk(KERN_ERR "PCI: Found an unsupported Renesas host "
84 "controller, device id 0x%04x.\n", id);
85 return -EINVAL;
5283ecb5
PM
86 }
87
4e7b7fdb
PM
88 printk(KERN_NOTICE "PCI: Found a Renesas %s host "
89 "controller, revision %d.\n", type,
a45635df 90 __raw_readb(chan->reg_base + PCI_REVISION_ID));
4e7b7fdb 91
c66c1d79 92 /*
a45635df
PM
93 * Now throw it in to register initialization mode and
94 * start the real work.
c66c1d79 95 */
a45635df
PM
96 __raw_writel(SH4_PCICR_PREFIX, chan->reg_base + SH4_PCICR);
97
aee4467b
PM
98 __raw_writel(0, chan->reg_base + PCI_BASE_ADDRESS_0);
99
a45635df 100 memphys = __pa(memory_start);
aee4467b 101 memsize = roundup_pow_of_two(memory_end - memory_start);
0bbc9bc3 102
62c7ae87 103 /*
aee4467b
PM
104 * If there's more than 512MB of memory, we need to roll over to
105 * LAR1/LSR1.
5283ecb5 106 */
aee4467b
PM
107 if (memsize > SZ_512M) {
108 __raw_writel(memphys + SZ_512M, chan->reg_base + SH4_PCILAR1);
109 __raw_writel((((memsize - SZ_512M) - SZ_1M) & 0x1ff00000) | 1,
110 chan->reg_base + SH4_PCILSR1);
111 memsize = SZ_512M;
112 } else {
113 /*
114 * Otherwise just zero it out and disable it.
115 */
116 __raw_writel(0, chan->reg_base + SH4_PCILAR1);
117 __raw_writel(0, chan->reg_base + SH4_PCILSR1);
118 }
a45635df 119
aee4467b
PM
120 /*
121 * LAR0/LSR0 covers up to the first 512MB, which is enough to
122 * cover all of lowmem on most platforms.
123 */
a45635df 124 __raw_writel(memphys, chan->reg_base + SH4_PCILAR0);
aee4467b 125 __raw_writel(((memsize - SZ_1M) & 0x1ff00000) | 1,
a45635df
PM
126 chan->reg_base + SH4_PCILSR0);
127
128 /* Clear out PCI arbiter IRQs */
129 __raw_writel(0, chan->reg_base + SH4_PCIAINT);
130
131 /* Unmask all of the arbiter IRQs. */
132 __raw_writel(SH4_PCIAINT_MBKN | SH4_PCIAINT_TBTO | SH4_PCIAINT_MBTO | \
133 SH4_PCIAINT_TABT | SH4_PCIAINT_MABT | SH4_PCIAINT_RDPE | \
134 SH4_PCIAINT_WDPE, chan->reg_base + SH4_PCIAINTM);
135
136 /* Clear all error conditions */
137 __raw_writew(PCI_STATUS_DETECTED_PARITY | \
138 PCI_STATUS_SIG_SYSTEM_ERROR | \
139 PCI_STATUS_REC_MASTER_ABORT | \
140 PCI_STATUS_REC_TARGET_ABORT | \
141 PCI_STATUS_SIG_TARGET_ABORT | \
142 PCI_STATUS_PARITY, chan->reg_base + PCI_STATUS);
143
144 __raw_writew(PCI_COMMAND_SERR | PCI_COMMAND_WAIT | \
145 PCI_COMMAND_PARITY | PCI_COMMAND_MASTER | \
146 PCI_COMMAND_MEMORY, chan->reg_base + PCI_COMMAND);
147
148 /* Unmask all of the PCI IRQs */
149 __raw_writel(SH4_PCIINTM_TTADIM | SH4_PCIINTM_TMTOIM | \
150 SH4_PCIINTM_MDEIM | SH4_PCIINTM_APEDIM | \
151 SH4_PCIINTM_SDIM | SH4_PCIINTM_DPEITWM | \
152 SH4_PCIINTM_PEDITRM | SH4_PCIINTM_TADIMM | \
153 SH4_PCIINTM_MADIMM | SH4_PCIINTM_MWPDIM | \
154 SH4_PCIINTM_MRDPEIM, chan->reg_base + SH4_PCIINTM);
155
156 /*
157 * Disable the cache snoop controller for non-coherent DMA.
158 */
159 __raw_writel(0, chan->reg_base + SH7780_PCICSCR0);
160 __raw_writel(0, chan->reg_base + SH7780_PCICSAR0);
161 __raw_writel(0, chan->reg_base + SH7780_PCICSCR1);
162 __raw_writel(0, chan->reg_base + SH7780_PCICSAR1);
163
164 __raw_writel(0xfd000000, chan->reg_base + SH7780_PCIMBR0);
165 __raw_writel(0x00fc0000, chan->reg_base + SH7780_PCIMBMR0);
166
167 __raw_writel(0, chan->reg_base + SH7780_PCIIOBR);
168 __raw_writel(0, chan->reg_base + SH7780_PCIIOBMR);
169
170 /*
171 * Initialization mode complete, release the control register and
172 * enable round robin mode to stop device overruns/starvation.
173 */
174 __raw_writel(SH4_PCICR_PREFIX | SH4_PCICR_CFIN | SH4_PCICR_FTO,
175 chan->reg_base + SH4_PCICR);
5283ecb5 176
e79066a6
PM
177 register_pci_controller(chan);
178
d0e3db40 179 return 0;
5283ecb5 180}
e79066a6 181arch_initcall(sh7780_pci_init);