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