1/* 2 * Support for SCC external PCI 3 * 4 * (C) Copyright 2004-2007 TOSHIBA CORPORATION 5 * 6 * This program is free software; you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License as published by 8 * the Free Software Foundation; either version 2 of the License, or 9 * (at your option) any later version. 10 * 11 * This program is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 * GNU General Public License for more details. 15 * 16 * You should have received a copy of the GNU General Public License along 17 * with this program; if not, write to the Free Software Foundation, Inc., 18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 19 */ 20 21#undef DEBUG 22 23#include <linux/kernel.h> 24#include <linux/threads.h> 25#include <linux/pci.h> 26#include <linux/init.h> 27#include <linux/pci_regs.h> 28#include <linux/bootmem.h> 29 30#include <asm/io.h> 31#include <asm/irq.h> 32#include <asm/prom.h> 33#include <asm/machdep.h> 34#include <asm/pci-bridge.h> 35#include <asm/ppc-pci.h> 36 37#include "scc.h" 38#include "pci.h" 39#include "interrupt.h" 40 41#define MAX_PCI_DEVICES 32 42#define MAX_PCI_FUNCTIONS 8 43 44#define iob() __asm__ __volatile__("eieio; sync":::"memory") 45 46static inline volatile void __iomem *celleb_epci_get_epci_base( 47 struct pci_controller *hose) 48{ 49 /* 50 * Note: 51 * Celleb epci uses cfg_addr as a base address for 52 * epci control registers. 53 */ 54 55 return hose->cfg_addr; 56} 57 58static inline volatile void __iomem *celleb_epci_get_epci_cfg( 59 struct pci_controller *hose) 60{ 61 /* 62 * Note: 63 * Celleb epci uses cfg_data as a base address for 64 * configuration area for epci devices. 65 */ 66 67 return hose->cfg_data; 68} 69 70 71static inline void clear_and_disable_master_abort_interrupt( 72 struct pci_controller *hose) 73{ 74 volatile void __iomem *epci_base, *reg; 75 epci_base = celleb_epci_get_epci_base(hose); 76 reg = epci_base + PCI_COMMAND; 77 out_be32(reg, in_be32(reg) | (PCI_STATUS_REC_MASTER_ABORT << 16)); 78} 79 80static int celleb_epci_check_abort(struct pci_controller *hose, 81 volatile void __iomem *addr) 82{ 83 volatile void __iomem *reg, *epci_base; 84 u32 val; 85 86 iob(); 87 epci_base = celleb_epci_get_epci_base(hose); 88 89 reg = epci_base + PCI_COMMAND; 90 val = in_be32(reg); 91 92 if (val & (PCI_STATUS_REC_MASTER_ABORT << 16)) { 93 out_be32(reg, 94 (val & 0xffff) | (PCI_STATUS_REC_MASTER_ABORT << 16)); 95 96 /* clear PCI Controller error, FRE, PMFE */ 97 reg = epci_base + SCC_EPCI_STATUS; 98 out_be32(reg, SCC_EPCI_INT_PAI); 99 100 reg = epci_base + SCC_EPCI_VCSR; 101 val = in_be32(reg) & 0xffff; 102 val |= SCC_EPCI_VCSR_FRE; 103 out_be32(reg, val); 104 105 reg = epci_base + SCC_EPCI_VISTAT; 106 out_be32(reg, SCC_EPCI_VISTAT_PMFE); 107 return PCIBIOS_DEVICE_NOT_FOUND; 108 } 109 110 return PCIBIOS_SUCCESSFUL; 111} 112 113static volatile void __iomem *celleb_epci_make_config_addr( 114 struct pci_bus *bus, 115 struct pci_controller *hose, 116 unsigned int devfn, int where) 117{ 118 volatile void __iomem *addr; 119 120 if (bus != hose->bus) 121 addr = celleb_epci_get_epci_cfg(hose) + 122 (((bus->number & 0xff) << 16) 123 | ((devfn & 0xff) << 8) 124 | (where & 0xff) 125 | 0x01000000); 126 else 127 addr = celleb_epci_get_epci_cfg(hose) + 128 (((devfn & 0xff) << 8) | (where & 0xff)); 129 130 pr_debug("EPCI: config_addr = 0x%p\n", addr); 131 132 return addr; 133} 134 135static int celleb_epci_read_config(struct pci_bus *bus, 136 unsigned int devfn, int where, int size, u32 * val) 137{ 138 volatile void __iomem *epci_base, *addr; 139 struct device_node *node; 140 struct pci_controller *hose; 141 142 /* allignment check */ 143 BUG_ON(where % size); 144 145 node = (struct device_node *)bus->sysdata; 146 hose = pci_find_hose_for_OF_device(node); 147 148 if (!celleb_epci_get_epci_cfg(hose)) 149 return PCIBIOS_DEVICE_NOT_FOUND; 150 151 if (bus->number == hose->first_busno && devfn == 0) { 152 /* EPCI controller self */ 153 154 epci_base = celleb_epci_get_epci_base(hose); 155 addr = epci_base + where; 156 157 switch (size) { 158 case 1: 159 *val = in_8(addr); 160 break; 161 case 2: 162 *val = in_be16(addr); 163 break; 164 case 4: 165 *val = in_be32(addr); 166 break; 167 default: 168 return PCIBIOS_DEVICE_NOT_FOUND; 169 } 170 171 } else { 172 173 clear_and_disable_master_abort_interrupt(hose); 174 addr = celleb_epci_make_config_addr(bus, hose, devfn, where); 175 176 switch (size) { 177 case 1: 178 *val = in_8(addr); 179 break; 180 case 2: 181 *val = in_le16(addr); 182 break; 183 case 4: 184 *val = in_le32(addr); 185 break; 186 default: 187 return PCIBIOS_DEVICE_NOT_FOUND; 188 } 189 } 190 191 pr_debug("EPCI: " 192 "addr=0x%p, devfn=0x%x, where=0x%x, size=0x%x, val=0x%x\n", 193 addr, devfn, where, size, *val); 194 195 return celleb_epci_check_abort(hose, NULL); 196} 197 198static int celleb_epci_write_config(struct pci_bus *bus, 199 unsigned int devfn, int where, int size, u32 val) 200{ 201 volatile void __iomem *epci_base, *addr; 202 struct device_node *node; 203 struct pci_controller *hose; 204 205 /* allignment check */ 206 BUG_ON(where % size); 207 208 node = (struct device_node *)bus->sysdata; 209 hose = pci_find_hose_for_OF_device(node); 210 211 212 if (!celleb_epci_get_epci_cfg(hose)) 213 return PCIBIOS_DEVICE_NOT_FOUND; 214 215 if (bus->number == hose->first_busno && devfn == 0) { 216 /* EPCI controller self */ 217 218 epci_base = celleb_epci_get_epci_base(hose); 219 addr = epci_base + where; 220 221 switch (size) { 222 case 1: 223 out_8(addr, val); 224 break; 225 case 2: 226 out_be16(addr, val); 227 break; 228 case 4: 229 out_be32(addr, val); 230 break; 231 default: 232 return PCIBIOS_DEVICE_NOT_FOUND; 233 } 234 235 } else { 236 237 clear_and_disable_master_abort_interrupt(hose); 238 addr = celleb_epci_make_config_addr(bus, hose, devfn, where); 239 240 switch (size) { 241 case 1: 242 out_8(addr, val); 243 break; 244 case 2: 245 out_le16(addr, val); 246 break; 247 case 4: 248 out_le32(addr, val); 249 break; 250 default: 251 return PCIBIOS_DEVICE_NOT_FOUND; 252 } 253 } 254 255 return celleb_epci_check_abort(hose, addr); 256} 257 258struct pci_ops celleb_epci_ops = { 259 celleb_epci_read_config, 260 celleb_epci_write_config, 261}; 262 263/* to be moved in FW */ 264static int __devinit celleb_epci_init(struct pci_controller *hose) 265{ 266 u32 val; 267 volatile void __iomem *reg, *epci_base; 268 int hwres = 0; 269 270 epci_base = celleb_epci_get_epci_base(hose); 271 272 /* PCI core reset(Internal bus and PCI clock) */ 273 reg = epci_base + SCC_EPCI_CKCTRL; 274 val = in_be32(reg); 275 if (val == 0x00030101) 276 hwres = 1; 277 else { 278 val &= ~(SCC_EPCI_CKCTRL_CRST0 | SCC_EPCI_CKCTRL_CRST1); 279 out_be32(reg, val); 280 281 /* set PCI core clock */ 282 val = in_be32(reg); 283 val |= (SCC_EPCI_CKCTRL_OCLKEN | SCC_EPCI_CKCTRL_LCLKEN); 284 out_be32(reg, val); 285 286 /* release PCI core reset (internal bus) */ 287 val = in_be32(reg); 288 val |= SCC_EPCI_CKCTRL_CRST0; 289 out_be32(reg, val); 290 291 /* set PCI clock select */ 292 reg = epci_base + SCC_EPCI_CLKRST; 293 val = in_be32(reg); 294 val &= ~SCC_EPCI_CLKRST_CKS_MASK; 295 val |= SCC_EPCI_CLKRST_CKS_2; 296 out_be32(reg, val); 297 298 /* set arbiter */ 299 reg = epci_base + SCC_EPCI_ABTSET; 300 out_be32(reg, 0x0f1f001f); /* temporary value */ 301 302 /* buffer on */ 303 reg = epci_base + SCC_EPCI_CLKRST; 304 val = in_be32(reg); 305 val |= SCC_EPCI_CLKRST_BC; 306 out_be32(reg, val); 307 308 /* PCI clock enable */ 309 val = in_be32(reg); 310 val |= SCC_EPCI_CLKRST_PCKEN; 311 out_be32(reg, val); 312 313 /* release PCI core reset (all) */ 314 reg = epci_base + SCC_EPCI_CKCTRL; 315 val = in_be32(reg); 316 val |= (SCC_EPCI_CKCTRL_CRST0 | SCC_EPCI_CKCTRL_CRST1); 317 out_be32(reg, val); 318 319 /* set base translation registers. (already set by Beat) */ 320 321 /* set base address masks. (already set by Beat) */ 322 } 323 324 /* release interrupt masks and clear all interrupts */ 325 reg = epci_base + SCC_EPCI_INTSET; 326 out_be32(reg, 0x013f011f); /* all interrupts enable */ 327 reg = epci_base + SCC_EPCI_VIENAB; 328 val = SCC_EPCI_VIENAB_PMPEE | SCC_EPCI_VIENAB_PMFEE; 329 out_be32(reg, val); 330 reg = epci_base + SCC_EPCI_STATUS; 331 out_be32(reg, 0xffffffff); 332 reg = epci_base + SCC_EPCI_VISTAT; 333 out_be32(reg, 0xffffffff); 334 335 /* disable PCI->IB address translation */ 336 reg = epci_base + SCC_EPCI_VCSR; 337 val = in_be32(reg); 338 val &= ~(SCC_EPCI_VCSR_DR | SCC_EPCI_VCSR_AT); 339 out_be32(reg, val); 340 341 /* set base addresses. (no need to set?) */ 342 343 /* memory space, bus master enable */ 344 reg = epci_base + PCI_COMMAND; 345 val = PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER; 346 out_be32(reg, val); 347 348 /* endian mode setup */ 349 reg = epci_base + SCC_EPCI_ECMODE; 350 val = 0x00550155; 351 out_be32(reg, val); 352 353 /* set control option */ 354 reg = epci_base + SCC_EPCI_CNTOPT; 355 val = in_be32(reg); 356 val |= SCC_EPCI_CNTOPT_O2PMB; 357 out_be32(reg, val); 358 359 reg = epci_base + SCC_EPCI_CNF10_REG; 360 out_be32(reg, 0x80000008); 361 reg = epci_base + SCC_EPCI_CNF14_REG; 362 out_be32(reg, 0x40000008); 363 364 reg = epci_base + SCC_EPCI_BAM0; 365 out_be32(reg, 0x80000000); 366 reg = epci_base + SCC_EPCI_BAM1; 367 out_be32(reg, 0xe0000000); 368 369 reg = epci_base + SCC_EPCI_PVBAT; 370 out_be32(reg, 0x80000000); 371 372 if (!hwres) { 373 /* release external PCI reset */ 374 reg = epci_base + SCC_EPCI_CLKRST; 375 val = in_be32(reg); 376 val |= SCC_EPCI_CLKRST_PCIRST; 377 out_be32(reg, val); 378 } 379 380 return 0; 381} 382 383int __devinit celleb_setup_epci(struct device_node *node, 384 struct pci_controller *hose) 385{ 386 struct resource r; 387 388 pr_debug("PCI: celleb_setup_epci()\n"); 389 390 /* 391 * Note: 392 * Celleb epci uses cfg_addr and cfg_data member of 393 * pci_controller structure in irregular way. 394 * 395 * cfg_addr is used to map for control registers of 396 * celleb epci. 397 * 398 * cfg_data is used for configuration area of devices 399 * on Celleb epci buses. 400 */ 401 402 if (of_address_to_resource(node, 0, &r)) 403 goto error; 404 hose->cfg_addr = ioremap(r.start, (r.end - r.start + 1)); 405 if (!hose->cfg_addr) 406 goto error; 407 pr_debug("EPCI: cfg_addr map 0x%016lx->0x%016lx + 0x%016lx\n", 408 r.start, (unsigned long)hose->cfg_addr, 409 (r.end - r.start + 1)); 410 411 if (of_address_to_resource(node, 2, &r)) 412 goto error; 413 hose->cfg_data = ioremap(r.start, (r.end - r.start + 1)); 414 if (!hose->cfg_data) 415 goto error; 416 pr_debug("EPCI: cfg_data map 0x%016lx->0x%016lx + 0x%016lx\n", 417 r.start, (unsigned long)hose->cfg_data, 418 (r.end - r.start + 1)); 419 420 celleb_epci_init(hose); 421 422 return 0; 423 424error: 425 return 1; 426} 427