1 /* 2 * (C) Copyright 2009 Reinhard Arlt, reinhard.arlt@esd-electronics.com 3 * 4 * base on universe.h by 5 * 6 * (C) Copyright 2003 Stefan Roese, stefan.roese@esd-electronics.com 7 * 8 * SPDX-License-Identifier: GPL-2.0+ 9 */ 10 11 #include <common.h> 12 #include <command.h> 13 #include <malloc.h> 14 #include <asm/io.h> 15 #include <pci.h> 16 17 #include <tsi148.h> 18 19 #define LPCI_VENDOR PCI_VENDOR_ID_TUNDRA 20 #define LPCI_DEVICE PCI_DEVICE_ID_TUNDRA_TSI148 21 22 typedef struct _TSI148_DEV TSI148_DEV; 23 24 struct _TSI148_DEV { 25 int bus; 26 pci_dev_t busdevfn; 27 TSI148 *uregs; 28 unsigned int pci_bs; 29 }; 30 31 static TSI148_DEV *dev; 32 33 /* 34 * Most of the TSI148 register are BIGENDIAN 35 * This is the reason for the __raw_writel(htonl(x), x) usage! 36 */ 37 38 int tsi148_init(void) 39 { 40 int j, result; 41 pci_dev_t busdevfn; 42 unsigned int val; 43 44 busdevfn = pci_find_device(LPCI_VENDOR, LPCI_DEVICE, 0); 45 if (busdevfn == -1) { 46 puts("Tsi148: No Tundra Tsi148 found!\n"); 47 return -1; 48 } 49 50 /* Lets turn Latency off */ 51 pci_write_config_dword(busdevfn, 0x0c, 0); 52 53 dev = malloc(sizeof(*dev)); 54 if (NULL == dev) { 55 puts("Tsi148: No memory!\n"); 56 return -1; 57 } 58 59 memset(dev, 0, sizeof(*dev)); 60 dev->busdevfn = busdevfn; 61 62 pci_read_config_dword(busdevfn, PCI_BASE_ADDRESS_0, &val); 63 val &= ~0xf; 64 dev->uregs = (TSI148 *)val; 65 66 debug("Tsi148: Base : %p\n", dev->uregs); 67 68 /* check mapping */ 69 debug("Tsi148: Read via mapping, PCI_ID = %08X\n", 70 readl(&dev->uregs->pci_id)); 71 if (((LPCI_DEVICE << 16) | LPCI_VENDOR) != readl(&dev->uregs->pci_id)) { 72 printf("Tsi148: Cannot read PCI-ID via Mapping: %08x\n", 73 readl(&dev->uregs->pci_id)); 74 result = -1; 75 goto break_30; 76 } 77 78 debug("Tsi148: PCI_BS = %08X\n", readl(&dev->uregs->pci_mbarl)); 79 80 dev->pci_bs = readl(&dev->uregs->pci_mbarl); 81 82 /* turn off windows */ 83 for (j = 0; j < 8; j++) { 84 __raw_writel(htonl(0x00000000), &dev->uregs->outbound[j].otat); 85 __raw_writel(htonl(0x00000000), &dev->uregs->inbound[j].itat); 86 } 87 88 /* Tsi148 VME timeout etc */ 89 __raw_writel(htonl(0x00000084), &dev->uregs->vctrl); 90 91 #ifdef DEBUG 92 if ((__raw_readl(&dev->uregs->vstat) & 0x00000100) != 0) 93 printf("Tsi148: System Controller!\n"); 94 else 95 printf("Tsi148: Not System Controller!\n"); 96 #endif 97 98 /* 99 * Lets turn off interrupts 100 */ 101 /* Disable interrupts in Tsi148 first */ 102 __raw_writel(htonl(0x00000000), &dev->uregs->inten); 103 /* Disable interrupt out */ 104 __raw_writel(htonl(0x00000000), &dev->uregs->inteo); 105 eieio(); 106 /* Reset all IRQ's */ 107 __raw_writel(htonl(0x03ff3f00), &dev->uregs->intc); 108 /* Map all ints to 0 */ 109 __raw_writel(htonl(0x00000000), &dev->uregs->intm1); 110 __raw_writel(htonl(0x00000000), &dev->uregs->intm2); 111 eieio(); 112 113 val = __raw_readl(&dev->uregs->vstat); 114 val &= ~(0x00004000); 115 __raw_writel(val, &dev->uregs->vstat); 116 eieio(); 117 118 debug("Tsi148: register struct size %08x\n", sizeof(TSI148)); 119 120 return 0; 121 122 break_30: 123 free(dev); 124 dev = NULL; 125 126 return result; 127 } 128 129 /* 130 * Create pci slave window (access: pci -> vme) 131 */ 132 int tsi148_pci_slave_window(unsigned int pciAddr, unsigned int vmeAddr, 133 int size, int vam, int vdw) 134 { 135 int result, i; 136 unsigned int ctl = 0; 137 138 if (NULL == dev) { 139 result = -1; 140 goto exit_10; 141 } 142 143 for (i = 0; i < 8; i++) { 144 if (0x00000000 == readl(&dev->uregs->outbound[i].otat)) 145 break; 146 } 147 148 if (i > 7) { 149 printf("Tsi148: No Image available\n"); 150 result = -1; 151 goto exit_10; 152 } 153 154 debug("Tsi148: Using image %d\n", i); 155 156 printf("Tsi148: Pci addr %08x\n", pciAddr); 157 158 __raw_writel(htonl(pciAddr), &dev->uregs->outbound[i].otsal); 159 __raw_writel(0x00000000, &dev->uregs->outbound[i].otsau); 160 __raw_writel(htonl(pciAddr + size), &dev->uregs->outbound[i].oteal); 161 __raw_writel(0x00000000, &dev->uregs->outbound[i].oteau); 162 __raw_writel(htonl(vmeAddr - pciAddr), &dev->uregs->outbound[i].otofl); 163 __raw_writel(0x00000000, &dev->uregs->outbound[i].otofu); 164 165 switch (vam & VME_AM_Axx) { 166 case VME_AM_A16: 167 ctl = 0x00000000; 168 break; 169 case VME_AM_A24: 170 ctl = 0x00000001; 171 break; 172 case VME_AM_A32: 173 ctl = 0x00000002; 174 break; 175 } 176 177 switch (vam & VME_AM_Mxx) { 178 case VME_AM_DATA: 179 ctl |= 0x00000000; 180 break; 181 case VME_AM_PROG: 182 ctl |= 0x00000010; 183 break; 184 } 185 186 if (vam & VME_AM_SUP) 187 ctl |= 0x00000020; 188 189 switch (vdw & VME_FLAG_Dxx) { 190 case VME_FLAG_D16: 191 ctl |= 0x00000000; 192 break; 193 case VME_FLAG_D32: 194 ctl |= 0x00000040; 195 break; 196 } 197 198 ctl |= 0x80040000; /* enable, no prefetch */ 199 200 __raw_writel(htonl(ctl), &dev->uregs->outbound[i].otat); 201 202 debug("Tsi148: window-addr =%p\n", 203 &dev->uregs->outbound[i].otsau); 204 debug("Tsi148: pci slave window[%d] attr =%08x\n", 205 i, ntohl(__raw_readl(&dev->uregs->outbound[i].otat))); 206 debug("Tsi148: pci slave window[%d] start =%08x\n", 207 i, ntohl(__raw_readl(&dev->uregs->outbound[i].otsal))); 208 debug("Tsi148: pci slave window[%d] end =%08x\n", 209 i, ntohl(__raw_readl(&dev->uregs->outbound[i].oteal))); 210 debug("Tsi148: pci slave window[%d] offset=%08x\n", 211 i, ntohl(__raw_readl(&dev->uregs->outbound[i].otofl))); 212 213 return 0; 214 215 exit_10: 216 return -result; 217 } 218 219 unsigned int tsi148_eval_vam(int vam) 220 { 221 unsigned int ctl = 0; 222 223 switch (vam & VME_AM_Axx) { 224 case VME_AM_A16: 225 ctl = 0x00000000; 226 break; 227 case VME_AM_A24: 228 ctl = 0x00000010; 229 break; 230 case VME_AM_A32: 231 ctl = 0x00000020; 232 break; 233 } 234 switch (vam & VME_AM_Mxx) { 235 case VME_AM_DATA: 236 ctl |= 0x00000001; 237 break; 238 case VME_AM_PROG: 239 ctl |= 0x00000002; 240 break; 241 case (VME_AM_PROG | VME_AM_DATA): 242 ctl |= 0x00000003; 243 break; 244 } 245 246 if (vam & VME_AM_SUP) 247 ctl |= 0x00000008; 248 if (vam & VME_AM_USR) 249 ctl |= 0x00000004; 250 251 return ctl; 252 } 253 254 /* 255 * Create vme slave window (access: vme -> pci) 256 */ 257 int tsi148_vme_slave_window(unsigned int vmeAddr, unsigned int pciAddr, 258 int size, int vam) 259 { 260 int result, i; 261 unsigned int ctl = 0; 262 263 if (NULL == dev) { 264 result = -1; 265 goto exit_10; 266 } 267 268 for (i = 0; i < 8; i++) { 269 if (0x00000000 == readl(&dev->uregs->inbound[i].itat)) 270 break; 271 } 272 273 if (i > 7) { 274 printf("Tsi148: No Image available\n"); 275 result = -1; 276 goto exit_10; 277 } 278 279 debug("Tsi148: Using image %d\n", i); 280 281 __raw_writel(htonl(vmeAddr), &dev->uregs->inbound[i].itsal); 282 __raw_writel(0x00000000, &dev->uregs->inbound[i].itsau); 283 __raw_writel(htonl(vmeAddr + size), &dev->uregs->inbound[i].iteal); 284 __raw_writel(0x00000000, &dev->uregs->inbound[i].iteau); 285 __raw_writel(htonl(pciAddr - vmeAddr), &dev->uregs->inbound[i].itofl); 286 if (vmeAddr > pciAddr) 287 __raw_writel(0xffffffff, &dev->uregs->inbound[i].itofu); 288 else 289 __raw_writel(0x00000000, &dev->uregs->inbound[i].itofu); 290 291 ctl = tsi148_eval_vam(vam); 292 ctl |= 0x80000000; /* enable */ 293 __raw_writel(htonl(ctl), &dev->uregs->inbound[i].itat); 294 295 debug("Tsi148: window-addr =%p\n", 296 &dev->uregs->inbound[i].itsau); 297 debug("Tsi148: vme slave window[%d] attr =%08x\n", 298 i, ntohl(__raw_readl(&dev->uregs->inbound[i].itat))); 299 debug("Tsi148: vme slave window[%d] start =%08x\n", 300 i, ntohl(__raw_readl(&dev->uregs->inbound[i].itsal))); 301 debug("Tsi148: vme slave window[%d] end =%08x\n", 302 i, ntohl(__raw_readl(&dev->uregs->inbound[i].iteal))); 303 debug("Tsi148: vme slave window[%d] offset=%08x\n", 304 i, ntohl(__raw_readl(&dev->uregs->inbound[i].itofl))); 305 306 return 0; 307 308 exit_10: 309 return -result; 310 } 311 312 /* 313 * Create vme slave window (access: vme -> gcsr) 314 */ 315 int tsi148_vme_gcsr_window(unsigned int vmeAddr, int vam) 316 { 317 int result; 318 unsigned int ctl; 319 320 result = 0; 321 322 if (NULL == dev) { 323 result = 1; 324 } else { 325 __raw_writel(htonl(vmeAddr), &dev->uregs->gbal); 326 __raw_writel(0x00000000, &dev->uregs->gbau); 327 328 ctl = tsi148_eval_vam(vam); 329 ctl |= 0x00000080; /* enable */ 330 __raw_writel(htonl(ctl), &dev->uregs->gcsrat); 331 } 332 333 return result; 334 } 335 336 /* 337 * Create vme slave window (access: vme -> crcsr) 338 */ 339 int tsi148_vme_crcsr_window(unsigned int vmeAddr) 340 { 341 int result; 342 unsigned int ctl; 343 344 result = 0; 345 346 if (NULL == dev) { 347 result = 1; 348 } else { 349 __raw_writel(htonl(vmeAddr), &dev->uregs->crol); 350 __raw_writel(0x00000000, &dev->uregs->crou); 351 352 ctl = 0x00000080; /* enable */ 353 __raw_writel(htonl(ctl), &dev->uregs->crat); 354 } 355 356 return result; 357 } 358 359 /* 360 * Create vme slave window (access: vme -> crg) 361 */ 362 int tsi148_vme_crg_window(unsigned int vmeAddr, int vam) 363 { 364 int result; 365 unsigned int ctl; 366 367 result = 0; 368 369 if (NULL == dev) { 370 result = 1; 371 } else { 372 __raw_writel(htonl(vmeAddr), &dev->uregs->cbal); 373 __raw_writel(0x00000000, &dev->uregs->cbau); 374 375 ctl = tsi148_eval_vam(vam); 376 ctl |= 0x00000080; /* enable */ 377 __raw_writel(htonl(ctl), &dev->uregs->crgat); 378 } 379 380 return result; 381 } 382 383 /* 384 * Tundra Tsi148 configuration 385 */ 386 int do_tsi148(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) 387 { 388 ulong addr1 = 0, addr2 = 0, size = 0, vam = 0, vdw = 0; 389 char cmd = 'x'; 390 391 /* get parameter */ 392 if (argc > 1) 393 cmd = argv[1][0]; 394 if (argc > 2) 395 addr1 = simple_strtoul(argv[2], NULL, 16); 396 if (argc > 3) 397 addr2 = simple_strtoul(argv[3], NULL, 16); 398 if (argc > 4) 399 size = simple_strtoul(argv[4], NULL, 16); 400 if (argc > 5) 401 vam = simple_strtoul(argv[5], NULL, 16); 402 if (argc > 6) 403 vdw = simple_strtoul(argv[6], NULL, 16); 404 405 switch (cmd) { 406 case 'c': 407 if (strcmp(argv[1], "crg") == 0) { 408 vam = addr2; 409 printf("Tsi148: Configuring VME CRG Window " 410 "(VME->CRG):\n"); 411 printf(" vme=%08lx vam=%02lx\n", addr1, vam); 412 tsi148_vme_crg_window(addr1, vam); 413 } else { 414 printf("Tsi148: Configuring VME CR/CSR Window " 415 "(VME->CR/CSR):\n"); 416 printf(" pci=%08lx\n", addr1); 417 tsi148_vme_crcsr_window(addr1); 418 } 419 break; 420 case 'i': /* init */ 421 tsi148_init(); 422 break; 423 case 'g': 424 vam = addr2; 425 printf("Tsi148: Configuring VME GCSR Window (VME->GCSR):\n"); 426 printf(" vme=%08lx vam=%02lx\n", addr1, vam); 427 tsi148_vme_gcsr_window(addr1, vam); 428 break; 429 case 'v': /* vme */ 430 printf("Tsi148: Configuring VME Slave Window (VME->PCI):\n"); 431 printf(" vme=%08lx pci=%08lx size=%08lx vam=%02lx\n", 432 addr1, addr2, size, vam); 433 tsi148_vme_slave_window(addr1, addr2, size, vam); 434 break; 435 case 'p': /* pci */ 436 printf("Tsi148: Configuring PCI Slave Window (PCI->VME):\n"); 437 printf(" pci=%08lx vme=%08lx size=%08lx vam=%02lx vdw=%02lx\n", 438 addr1, addr2, size, vam, vdw); 439 tsi148_pci_slave_window(addr1, addr2, size, vam, vdw); 440 break; 441 default: 442 printf("Tsi148: Command %s not supported!\n", argv[1]); 443 } 444 445 return 0; 446 } 447 448 U_BOOT_CMD( 449 tsi148, 7, 1, do_tsi148, 450 "initialize and configure Turndra Tsi148\n", 451 "init\n" 452 " - initialize tsi148\n" 453 "tsi148 vme [vme_addr] [pci_addr] [size] [vam]\n" 454 " - create vme slave window (access: vme->pci)\n" 455 "tsi148 pci [pci_addr] [vme_addr] [size] [vam] [vdw]\n" 456 " - create pci slave window (access: pci->vme)\n" 457 "tsi148 crg [vme_addr] [vam]\n" 458 " - create vme slave window: (access vme->CRG\n" 459 "tsi148 crcsr [pci_addr]\n" 460 " - create vme slave window: (access vme->CR/CSR\n" 461 "tsi148 gcsr [vme_addr] [vam]\n" 462 " - create vme slave window: (access vme->GCSR\n" 463 " [vam] = VMEbus Address-Modifier: 01 -> A16 Address Space\n" 464 " 02 -> A24 Address Space\n" 465 " 03 -> A32 Address Space\n" 466 " 04 -> Usr AM Code\n" 467 " 08 -> Supervisor AM Code\n" 468 " 10 -> Data AM Code\n" 469 " 20 -> Program AM Code\n" 470 " [vdw] = VMEbus Maximum Datawidth: 02 -> D16 Data Width\n" 471 " 03 -> D32 Data Width\n" 472 ); 473