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