wdenk | bc01dd5 | 2004-01-02 16:05:07 +0000 | [diff] [blame] | 1 | /* |
| 2 | * (C) Copyright 2003 |
| 3 | * Martin Winistoerfer, martinwinistoerfer@gmx.ch. |
| 4 | * Atapted for PATI |
| 5 | * Denis Peter, d.peter@mpl.ch |
Wolfgang Denk | d79de1d | 2013-07-08 09:37:19 +0200 | [diff] [blame] | 6 | * SPDX-License-Identifier: GPL-2.0+ |
wdenk | bc01dd5 | 2004-01-02 16:05:07 +0000 | [diff] [blame] | 7 | */ |
| 8 | |
| 9 | /*********************************************************************************** |
| 10 | * Bits for the SDRAM controller |
| 11 | * ----------------------------- |
| 12 | * |
| 13 | * CAL: CAS Latency. If cleared to 0 (default) the SDRAM controller asserts TA# on |
| 14 | * the 2nd Clock after ACTIVE command (CAS Latency = 2). If set to 1 the SDRAM |
| 15 | * controller asserts TA# on the 3rd Clock after ACTIVE command (CAS Latency = 3). |
| 16 | * RCD: RCD ACTIVE to READ or WRITE Delay (Ras to Cas Delay). If cleared 0 (default) |
| 17 | * tRCD of the SDRAM must equal or less 25ns. If set to 1 tRCD must be equal or less 50ns. |
| 18 | * WREC:Write Recovery. If cleared 0 (default) tWR of the SDRAM must equal or less 25ns. |
| 19 | * If set to 1 tWR must be equal or less 50ns. |
| 20 | * RP: Precharge Command Time. If cleared 0 (default) tRP of the SDRAM must equal or less |
| 21 | * 25ns. If set to 1 tRP must be equal or less 50ns. |
| 22 | * RC: Auto Refresh to Active Time. If cleared 0 (default) tRC of the SDRAM must equal |
| 23 | * or less 75ns. If set to 1 tRC must be equal or less 100ns. |
| 24 | * LMR: Bit to set the Mode Register of the SDRAM. If set, the next access to the SDRAM |
| 25 | * is the Load Mode Register Command. |
| 26 | * IIP: Init in progress. Set to 1 for starting the init sequence |
| 27 | * (Precharge All). As long this bit is set, the Precharge All is still in progress. |
| 28 | * After command has completed, wait at least for 8 refresh (200usec) before proceed. |
| 29 | **********************************************************************************/ |
| 30 | |
| 31 | #include <common.h> |
Simon Glass | a73bda4 | 2015-11-08 23:47:45 -0700 | [diff] [blame] | 32 | #include <console.h> |
wdenk | bc01dd5 | 2004-01-02 16:05:07 +0000 | [diff] [blame] | 33 | #include <mpc5xx.h> |
Jean-Christophe PLAGNIOL-VILLARD | 2a7a031 | 2009-05-16 12:14:54 +0200 | [diff] [blame] | 34 | #include <stdio_dev.h> |
wdenk | bc01dd5 | 2004-01-02 16:05:07 +0000 | [diff] [blame] | 35 | #include <pci_ids.h> |
| 36 | #define PLX9056_LOC |
| 37 | #include "plx9056.h" |
| 38 | #include "pati.h" |
| 39 | |
| 40 | #if defined(__APPLE__) |
| 41 | /* Leading underscore on symbols */ |
| 42 | # define SYM_CHAR "_" |
| 43 | #else /* No leading character on symbols */ |
| 44 | # define SYM_CHAR |
| 45 | #endif |
| 46 | |
| 47 | #undef SDRAM_DEBUG |
| 48 | /* |
| 49 | * Macros to generate global absolutes. |
| 50 | */ |
| 51 | #define GEN_SYMNAME(str) SYM_CHAR #str |
| 52 | #define GEN_VALUE(str) #str |
| 53 | #define GEN_ABS(name, value) \ |
| 54 | asm (".globl " GEN_SYMNAME(name)); \ |
| 55 | asm (GEN_SYMNAME(name) " = " GEN_VALUE(value)) |
| 56 | |
| 57 | |
Simon Glass | 39f90ba | 2017-03-31 08:40:25 -0600 | [diff] [blame] | 58 | DECLARE_GLOBAL_DATA_PTR; |
| 59 | |
wdenk | bc01dd5 | 2004-01-02 16:05:07 +0000 | [diff] [blame] | 60 | /************************************************************************ |
| 61 | * Early debug routines |
| 62 | */ |
| 63 | void write_hex (unsigned char i) |
| 64 | { |
| 65 | char cc; |
| 66 | |
| 67 | cc = i >> 4; |
| 68 | cc &= 0xf; |
| 69 | if (cc > 9) |
| 70 | serial_putc (cc + 55); |
| 71 | else |
| 72 | serial_putc (cc + 48); |
| 73 | cc = i & 0xf; |
| 74 | if (cc > 9) |
| 75 | serial_putc (cc + 55); |
| 76 | else |
| 77 | serial_putc (cc + 48); |
| 78 | } |
| 79 | |
| 80 | #if defined(SDRAM_DEBUG) |
| 81 | |
| 82 | void write_4hex (unsigned long val) |
| 83 | { |
| 84 | write_hex ((unsigned char) (val >> 24)); |
| 85 | write_hex ((unsigned char) (val >> 16)); |
| 86 | write_hex ((unsigned char) (val >> 8)); |
| 87 | write_hex ((unsigned char) val); |
| 88 | } |
| 89 | |
| 90 | #endif |
| 91 | |
| 92 | unsigned long in32(unsigned long addr) |
| 93 | { |
| 94 | unsigned long *p=(unsigned long *)addr; |
| 95 | return *p; |
| 96 | } |
| 97 | |
| 98 | void out32(unsigned long addr,unsigned long data) |
| 99 | { |
| 100 | unsigned long *p=(unsigned long *)addr; |
| 101 | *p=data; |
| 102 | } |
| 103 | |
| 104 | typedef struct { |
| 105 | unsigned short boardtype; /* Board revision and Population Options */ |
| 106 | unsigned char cal; /* cas Latency 0:CAL=2 1:CAL=3 */ |
| 107 | unsigned char rcd; /* ras to cas delay 0:<25ns 1:<50ns*/ |
| 108 | unsigned char wrec; /* write recovery 0:<25ns 1:<50ns */ |
| 109 | unsigned char pr; /* Precharge Command Time 0:<25ns 1:<50ns */ |
| 110 | unsigned char rc; /* Auto Refresh to Active Time 0:<75ns 1:<100ns */ |
| 111 | unsigned char sz; /* log binary => Size = (4MByte<<sz) 5 = 128, 4 = 64, 3 = 32, 2 = 16, 1=8 */ |
| 112 | } sdram_t; |
| 113 | |
| 114 | const sdram_t sdram_table[] = { |
| 115 | { 0x0000, /* PATI Rev A, 16MByte -1 Board */ |
| 116 | 1, /* Case Latenty = 3 */ |
| 117 | 0, /* ras to cas delay 0 (20ns) */ |
| 118 | 0, /* write recovery 0:<25ns 1:<50ns*/ |
| 119 | 0, /* Precharge Command Time 0 (20ns) */ |
| 120 | 0, /* Auto Refresh to Active Time 0 (68) */ |
| 121 | 2 /* log binary => Size 2 = 16MByte, 1=8 */ |
| 122 | }, |
| 123 | { 0xffff, /* terminator */ |
| 124 | 0xff, |
| 125 | 0xff, |
| 126 | 0xff, |
| 127 | 0xff, |
| 128 | 0xff, |
| 129 | 0xff } |
| 130 | }; |
| 131 | |
| 132 | |
| 133 | extern int mem_test (unsigned long start, unsigned long ramsize, int quiet); |
wdenk | bc01dd5 | 2004-01-02 16:05:07 +0000 | [diff] [blame] | 134 | |
| 135 | /* |
| 136 | * Get RAM size. |
| 137 | */ |
Simon Glass | d35f338 | 2017-04-06 12:47:05 -0600 | [diff] [blame] | 138 | int dram_init(void) |
wdenk | bc01dd5 | 2004-01-02 16:05:07 +0000 | [diff] [blame] | 139 | { |
| 140 | unsigned char board_rev; |
| 141 | unsigned long reg; |
| 142 | unsigned long lmr; |
| 143 | int i,timeout; |
| 144 | |
| 145 | #if defined(SDRAM_DEBUG) |
| 146 | reg=in32(PLD_CONFIG_BASE+PLD_PART_ID); |
| 147 | puts("\n\nSYSTEM part 0x"); write_4hex(SYSCNTR_PART(reg)); |
| 148 | puts(" Vers 0x"); write_4hex(SYSCNTR_ID(reg)); |
| 149 | puts("\nSDRAM part 0x"); write_4hex(SDRAM_PART(reg)); |
| 150 | puts(" Vers 0x"); write_4hex(SDRAM_ID(reg)); |
| 151 | reg=in32(PLD_CONFIG_BASE+PLD_BOARD_TIMING); |
| 152 | puts("\nBoard rev. 0x"); write_4hex(SYSCNTR_BREV(reg)); |
| 153 | putc('\n'); |
| 154 | #endif |
| 155 | reg=in32(PLD_CONFIG_BASE+PLD_BOARD_TIMING); |
| 156 | board_rev=(unsigned char)(SYSCNTR_BREV(reg)); |
| 157 | i=0; |
| 158 | while(1) { |
| 159 | if(sdram_table[i].boardtype==0xffff) { |
| 160 | puts("ERROR, found no table for Board 0x"); |
| 161 | write_hex(board_rev); |
| 162 | while(1); |
| 163 | } |
| 164 | if(sdram_table[i].boardtype==(unsigned char)board_rev) |
| 165 | break; |
| 166 | i++; |
| 167 | } |
| 168 | /* Set CAL, RCD, WREQ, PR and RC Bits */ |
| 169 | #if defined(SDRAM_DEBUG) |
| 170 | puts("Set CAL, RCD, WREQ, PR and RC Bits\n"); |
| 171 | #endif |
| 172 | /* mask bits */ |
| 173 | reg &= ~(SET_REG_BIT(1,SDRAM_CAL) | SET_REG_BIT(1,SDRAM_RCD) | SET_REG_BIT(1,SDRAM_WREQ) | |
| 174 | SET_REG_BIT(1,SDRAM_PR) | SET_REG_BIT(1,SDRAM_RC) | SET_REG_BIT(1,SDRAM_LMR) | |
| 175 | SET_REG_BIT(1,SDRAM_IIP) | SET_REG_BIT(1,SDRAM_RES0)); |
| 176 | /* set bits */ |
| 177 | reg |= (SET_REG_BIT(sdram_table[i].cal,SDRAM_CAL) | |
| 178 | SET_REG_BIT(sdram_table[i].rcd,SDRAM_RCD) | |
| 179 | SET_REG_BIT(sdram_table[i].wrec,SDRAM_WREQ) | |
| 180 | SET_REG_BIT(sdram_table[i].pr,SDRAM_PR) | |
| 181 | SET_REG_BIT(sdram_table[i].rc,SDRAM_RC)); |
| 182 | |
| 183 | out32(PLD_CONFIG_BASE+PLD_BOARD_TIMING,reg); |
| 184 | /* step 2 set IIP */ |
| 185 | #if defined(SDRAM_DEBUG) |
| 186 | puts("step 2 set IIP\n"); |
| 187 | #endif |
| 188 | /* step 2 set IIP */ |
| 189 | reg |= SET_REG_BIT(1,SDRAM_IIP); |
| 190 | timeout=0; |
| 191 | while (timeout!=0xffff) { |
| 192 | __asm__ volatile("eieio"); |
| 193 | reg=in32(PLD_CONFIG_BASE+PLD_BOARD_TIMING); |
| 194 | if((reg & SET_REG_BIT(1,SDRAM_IIP))==0) |
| 195 | break; |
| 196 | timeout++; |
| 197 | udelay(1); |
| 198 | } |
| 199 | /* wait for at least 8 refresh */ |
| 200 | udelay(1000); |
| 201 | /* set LMR */ |
| 202 | reg |= SET_REG_BIT(1,SDRAM_LMR); |
| 203 | out32(PLD_CONFIG_BASE+PLD_BOARD_TIMING,reg); |
| 204 | __asm__ volatile("eieio"); |
| 205 | lmr=0x00000002; /* sequential burst 4 data */ |
| 206 | if(sdram_table[i].cal==1) |
| 207 | lmr|=0x00000030; /* cal = 3 */ |
| 208 | else |
| 209 | lmr|=0000000020; /* cal = 2 */ |
| 210 | /* rest standard operation programmed write burst length */ |
| 211 | /* we have a x32 bit bus to the SDRAM, so shift the addr with 2 */ |
| 212 | lmr<<=2; |
Jean-Christophe PLAGNIOL-VILLARD | 0383694 | 2008-10-16 15:01:15 +0200 | [diff] [blame] | 213 | in32(CONFIG_SYS_SDRAM_BASE + lmr); |
Simon Glass | 39f90ba | 2017-03-31 08:40:25 -0600 | [diff] [blame] | 214 | /* ok, we're done, set SDRAM size to log2 value of 4MByte*/ |
| 215 | gd->ram_size = 0x400000 << sdram_table[i].sz; |
| 216 | |
| 217 | return 0; |
wdenk | bc01dd5 | 2004-01-02 16:05:07 +0000 | [diff] [blame] | 218 | } |
| 219 | |
| 220 | |
| 221 | void set_flash_vpp(int ext_vpp, int ext_wp, int int_vpp) |
| 222 | { |
| 223 | unsigned long reg; |
| 224 | reg=in32(PLD_CONF_REG2+PLD_CONFIG_BASE); |
| 225 | reg &= ~(SET_REG_BIT(1,SYSCNTR_CPU_VPP) | |
| 226 | SET_REG_BIT(1,SYSCNTR_FL_VPP) | |
| 227 | SET_REG_BIT(1,SYSCNTR_FL_WP)); |
| 228 | |
| 229 | reg |= (SET_REG_BIT(int_vpp,SYSCNTR_CPU_VPP) | |
| 230 | SET_REG_BIT(ext_vpp,SYSCNTR_FL_VPP) | |
| 231 | SET_REG_BIT(ext_wp,SYSCNTR_FL_WP)); |
| 232 | out32(PLD_CONF_REG2+PLD_CONFIG_BASE,reg); |
| 233 | udelay(100); |
| 234 | } |
| 235 | |
| 236 | |
| 237 | void show_pld_regs(void) |
| 238 | { |
| 239 | unsigned long reg,reg1; |
| 240 | reg=in32(PLD_CONFIG_BASE+PLD_PART_ID); |
| 241 | printf("\nSYSTEM part %ld, Vers %ld\n",SYSCNTR_PART(reg),SYSCNTR_ID(reg)); |
| 242 | printf("SDRAM part %ld, Vers %ld\n",SDRAM_PART(reg),SDRAM_ID(reg)); |
| 243 | reg=in32(PLD_CONFIG_BASE+PLD_BOARD_TIMING); |
| 244 | printf("Board rev. %c\n",(char) (SYSCNTR_BREV(reg)+'A')); |
| 245 | printf("Waitstates %ld\n",GET_SYSCNTR_FLWAIT(reg)); |
| 246 | printf("SDRAM: CAL=%ld RCD=%ld WREQ=%ld PR=%ld\n RC=%ld LMR=%ld IIP=%ld\n", |
| 247 | GET_REG_BIT(reg,SDRAM_CAL),GET_REG_BIT(reg,SDRAM_RCD), |
| 248 | GET_REG_BIT(reg,SDRAM_WREQ),GET_REG_BIT(reg,SDRAM_PR), |
| 249 | GET_REG_BIT(reg,SDRAM_RC),GET_REG_BIT(reg,SDRAM_LMR), |
| 250 | GET_REG_BIT(reg,SDRAM_IIP)); |
| 251 | reg=in32(PLD_CONFIG_BASE+PLD_CONF_REG1); |
| 252 | reg1=in32(PLD_CONFIG_BASE+PLD_CONF_REG2); |
| 253 | printf("HW Config: FLAG=%ld IP=%ld index=%ld PRPM=%ld\n ICW=%ld ISB=%ld BDIS=%ld PCIM=%ld\n", |
| 254 | GET_REG_BIT(reg,SYSCNTR_FLAG),GET_REG_BIT(reg,SYSCNTR_IP), |
| 255 | GET_SYSCNTR_BOOTIND(reg),GET_REG_BIT(reg,SYSCNTR_PRM), |
| 256 | GET_REG_BIT(reg,SYSCNTR_ICW),GET_SYSCNTR_ISB(reg), |
| 257 | GET_REG_BIT(reg1,SYSCNTR_BDIS),GET_REG_BIT(reg1,SYSCNTR_PCIM)); |
| 258 | printf("Switches: MUX=%ld PCI_DIS=%ld Boot_EN=%ld Config=%ld\n",GET_SDRAM_MUX(reg), |
| 259 | GET_REG_BIT(reg,SDRAM_PDIS),GET_REG_BIT(reg1,SYSCNTR_BOOTEN), |
| 260 | GET_SYSCNTR_CFG(reg1)); |
| 261 | printf("Misc: RIP=%ld CPU_VPP=%ld FLSH_VPP=%ld FLSH_WP=%ld\n\n", |
| 262 | GET_REG_BIT(reg,SDRAM_RIP),GET_REG_BIT(reg1,SYSCNTR_CPU_VPP), |
| 263 | GET_REG_BIT(reg1,SYSCNTR_FL_VPP),GET_REG_BIT(reg1,SYSCNTR_FL_WP)); |
| 264 | } |
| 265 | |
| 266 | |
| 267 | /**************************************************************** |
| 268 | * Setting IOs |
| 269 | * ----------- |
| 270 | * GPIO6 is User LED1 |
| 271 | * GPIO7 is Interrupt PLX (Output) |
| 272 | * GPIO5 is User LED0 |
| 273 | * GPIO2 is PLX USERi (Output) |
| 274 | * GPIO1 is PLX Interrupt (Input) |
| 275 | ****************************************************************/ |
| 276 | void init_ios(void) |
| 277 | { |
Jean-Christophe PLAGNIOL-VILLARD | 0383694 | 2008-10-16 15:01:15 +0200 | [diff] [blame] | 278 | volatile immap_t * immr = (immap_t *) CONFIG_SYS_IMMR; |
wdenk | bc01dd5 | 2004-01-02 16:05:07 +0000 | [diff] [blame] | 279 | volatile sysconf5xx_t *sysconf = &immr->im_siu_conf; |
| 280 | unsigned long reg; |
| 281 | reg=sysconf->sc_sgpiocr; /* Data direction register */ |
| 282 | reg &= ~0x67000000; |
| 283 | reg |= 0x27000000; /* set outpupts */ |
| 284 | sysconf->sc_sgpiocr=reg; /* Data direction register */ |
| 285 | reg=sysconf->sc_sgpiodt2; /* Data register */ |
| 286 | /* set output to 0 */ |
| 287 | reg &= ~0x27000000; |
| 288 | /* set IRQ and USERi to 1 */ |
| 289 | reg |= 0x28000000; |
| 290 | sysconf->sc_sgpiodt2=reg; /* Data register */ |
| 291 | } |
| 292 | |
| 293 | void user_led0(int led_on) |
| 294 | { |
Jean-Christophe PLAGNIOL-VILLARD | 0383694 | 2008-10-16 15:01:15 +0200 | [diff] [blame] | 295 | volatile immap_t * immr = (immap_t *) CONFIG_SYS_IMMR; |
wdenk | bc01dd5 | 2004-01-02 16:05:07 +0000 | [diff] [blame] | 296 | volatile sysconf5xx_t *sysconf = &immr->im_siu_conf; |
| 297 | unsigned long reg; |
| 298 | reg=sysconf->sc_sgpiodt2; /* Data register */ |
| 299 | if(led_on) /* set output to 1 */ |
| 300 | reg |= 0x04000000; |
| 301 | else |
| 302 | reg &= ~0x04000000; |
| 303 | sysconf->sc_sgpiodt2=reg; /* Data register */ |
| 304 | } |
| 305 | |
| 306 | void user_led1(int led_on) |
| 307 | { |
Jean-Christophe PLAGNIOL-VILLARD | 0383694 | 2008-10-16 15:01:15 +0200 | [diff] [blame] | 308 | volatile immap_t * immr = (immap_t *) CONFIG_SYS_IMMR; |
wdenk | bc01dd5 | 2004-01-02 16:05:07 +0000 | [diff] [blame] | 309 | volatile sysconf5xx_t *sysconf = &immr->im_siu_conf; |
| 310 | unsigned long reg; |
| 311 | reg=sysconf->sc_sgpiodt2; /* Data register */ |
| 312 | if(led_on) /* set output to 1 */ |
| 313 | reg |= 0x02000000; |
| 314 | else |
| 315 | reg &= ~0x02000000; |
| 316 | sysconf->sc_sgpiodt2=reg; /* Data register */ |
| 317 | } |
| 318 | |
David Müller (ELSOFT AG) | a58fc8e | 2014-09-30 13:23:54 +0200 | [diff] [blame] | 319 | int board_early_init_f(void) |
| 320 | { |
| 321 | spi_init_f(); |
| 322 | return 0; |
| 323 | } |
wdenk | bc01dd5 | 2004-01-02 16:05:07 +0000 | [diff] [blame] | 324 | |
| 325 | /**************************************************************** |
| 326 | * Last Stage Init |
| 327 | ****************************************************************/ |
| 328 | int last_stage_init (void) |
| 329 | { |
wdenk | bc01dd5 | 2004-01-02 16:05:07 +0000 | [diff] [blame] | 330 | init_ios(); |
| 331 | return 0; |
| 332 | } |
| 333 | |
| 334 | /**************************************************************** |
| 335 | * Check the board |
| 336 | ****************************************************************/ |
| 337 | |
| 338 | #define BOARD_NAME "PATI" |
| 339 | |
| 340 | int checkboard (void) |
| 341 | { |
Wolfgang Denk | c00ae01 | 2009-07-19 01:15:52 +0200 | [diff] [blame] | 342 | char s[50]; |
| 343 | ulong reg; |
wdenk | bc01dd5 | 2004-01-02 16:05:07 +0000 | [diff] [blame] | 344 | char rev; |
| 345 | int i; |
| 346 | |
| 347 | puts ("\nBoard: "); |
| 348 | reg=in32(PLD_CONFIG_BASE+PLD_BOARD_TIMING); |
| 349 | rev=(char)(SYSCNTR_BREV(reg)+'A'); |
Wolfgang Denk | 76af278 | 2010-07-24 21:55:43 +0200 | [diff] [blame] | 350 | i = getenv_f("serial#", s, 32); |
wdenk | bc01dd5 | 2004-01-02 16:05:07 +0000 | [diff] [blame] | 351 | if ((i == -1)) { |
| 352 | puts ("### No HW ID - assuming " BOARD_NAME); |
| 353 | printf(" Rev. %c\n",rev); |
| 354 | } |
| 355 | else { |
| 356 | s[sizeof(BOARD_NAME)-1] = 0; |
| 357 | printf ("%s-1 Rev %c SN: %s\n", s,rev, |
| 358 | &s[sizeof(BOARD_NAME)]); |
| 359 | } |
| 360 | set_flash_vpp(1,0,0); /* set Flash VPP */ |
| 361 | return 0; |
| 362 | } |
| 363 | |
| 364 | |
Jean-Christophe PLAGNIOL-VILLARD | 0383694 | 2008-10-16 15:01:15 +0200 | [diff] [blame] | 365 | #ifdef CONFIG_SYS_PCI_CON_DEVICE |
wdenk | bc01dd5 | 2004-01-02 16:05:07 +0000 | [diff] [blame] | 366 | /************************************************************************ |
| 367 | * PCI Communication |
| 368 | * |
| 369 | * Alive (Pinging): |
| 370 | * ---------------- |
| 371 | * PCI Host sends message ALIVE, Local acknowledges with ALIVE |
| 372 | * |
| 373 | * PCI_CON console over PCI: |
| 374 | * ------------------------- |
| 375 | * Local side: |
| 376 | * - uses PCI9056_LOC_TO_PCI_DBELL register to signal that |
| 377 | * data is avaible (PCIMSG_CONN) |
| 378 | * - uses PCI9056_MAILBOX1 to send data |
| 379 | * - uses PCI9056_MAILBOX0 to receive data |
| 380 | * PCI side: |
| 381 | * - uses PCI9056_PCI_TO_LOC_DBELL register to signal that |
| 382 | * data is avaible (PCIMSG_CONN) |
| 383 | * - uses PCI9056_MAILBOX0 to send data |
| 384 | * - uses PCI9056_MAILBOX1 to receive data |
| 385 | * |
| 386 | * How it works: |
| 387 | * Send: |
| 388 | * - check if PCICON_TRANSMIT_REG is empty |
| 389 | * - write data or'ed with 0x80000000 into the PCICON_TRANSMIT_REG |
| 390 | * - write PCIMSG_CONN into the PCICON_DBELL_REG to signal a data |
| 391 | * is waiting |
| 392 | * Receive: |
| 393 | * - get an interrupt via the PCICON_ACK_REG register message |
| 394 | * PCIMSG_CONN |
| 395 | * - write the data from the PCICON_RECEIVE_REG into the receive |
| 396 | * buffer and if the receive buffer is not full, clear the |
| 397 | * PCICON_RECEIVE_REG (this allows the counterpart to write more data) |
| 398 | * - Clear the interrupt by writing 0xFFFFFFFF to the PCICON_ACK_REG |
| 399 | * |
| 400 | * The PCICON_RECEIVE_REG must be cleared by the routine which reads |
| 401 | * the receive buffer if the buffer is not full any more |
| 402 | * |
| 403 | */ |
| 404 | |
| 405 | #undef PCI_CON_DEBUG |
| 406 | |
| 407 | #ifdef PCI_CON_DEBUG |
| 408 | #define PCI_CON_PRINTF(fmt,args...) serial_printf (fmt ,##args) |
| 409 | #else |
| 410 | #define PCI_CON_PRINTF(fmt,args...) |
| 411 | #endif |
| 412 | |
| 413 | |
| 414 | /********************************************************* |
| 415 | * we work only with a receive buffer on eiter side. |
| 416 | * Transmit buffer is free, if mailbox is cleared. |
| 417 | * Transmit character is or'ed with 0x80000000 |
| 418 | * PATI receive register MAILBOX0 |
| 419 | * PATI transmit register MAILBOX1 |
| 420 | *********************************************************/ |
| 421 | #define PCICON_RECEIVE_REG PCI9056_MAILBOX0 |
| 422 | #define PCICON_TRANSMIT_REG PCI9056_MAILBOX1 |
| 423 | #define PCICON_DBELL_REG PCI9056_LOC_TO_PCI_DBELL |
| 424 | #define PCICON_ACK_REG PCI9056_PCI_TO_LOC_DBELL |
| 425 | |
| 426 | |
| 427 | #define PCIMSG_ALIVE 0x1 |
| 428 | #define PCIMSG_CONN 0x2 |
| 429 | #define PCIMSG_DISC 0x3 |
| 430 | #define PCIMSG_CON_DATA 0x5 |
| 431 | |
| 432 | |
| 433 | #define PCICON_GET_REG(x) (in32(x + PCI_CONFIG_BASE)) |
| 434 | #define PCICON_SET_REG(x,y) (out32(x + PCI_CONFIG_BASE,y)) |
| 435 | #define PCICON_TX_FLAG 0x80000000 |
| 436 | |
| 437 | |
| 438 | #define REC_BUFFER_SIZE 0x100 |
| 439 | int recbuf[REC_BUFFER_SIZE]; |
| 440 | static int r_ptr = 0; |
| 441 | int w_ptr; |
Jean-Christophe PLAGNIOL-VILLARD | 2a7a031 | 2009-05-16 12:14:54 +0200 | [diff] [blame] | 442 | struct stdio_dev pci_con_dev; |
wdenk | bc01dd5 | 2004-01-02 16:05:07 +0000 | [diff] [blame] | 443 | int conn=0; |
| 444 | int buff_full=0; |
| 445 | |
| 446 | void pci_con_put_it(const char c) |
| 447 | { |
| 448 | /* Test for completition */ |
| 449 | unsigned long reg; |
| 450 | do { |
| 451 | reg=PCICON_GET_REG(PCICON_TRANSMIT_REG); |
| 452 | }while(reg); |
| 453 | reg=PCICON_TX_FLAG + c; |
| 454 | PCICON_SET_REG(PCICON_TRANSMIT_REG,reg); |
| 455 | PCICON_SET_REG(PCICON_DBELL_REG,PCIMSG_CON_DATA); |
| 456 | } |
| 457 | |
Simon Glass | 0d1e1f7 | 2014-07-23 06:54:59 -0600 | [diff] [blame] | 458 | void pci_con_putc(struct stdio_dev *dev, const char c) |
wdenk | bc01dd5 | 2004-01-02 16:05:07 +0000 | [diff] [blame] | 459 | { |
| 460 | pci_con_put_it(c); |
| 461 | if(c == '\n') |
| 462 | pci_con_put_it('\r'); |
| 463 | } |
| 464 | |
| 465 | |
Simon Glass | 0d1e1f7 | 2014-07-23 06:54:59 -0600 | [diff] [blame] | 466 | int pci_con_getc(struct stdio_dev *dev) |
wdenk | bc01dd5 | 2004-01-02 16:05:07 +0000 | [diff] [blame] | 467 | { |
| 468 | int res; |
| 469 | int diff; |
| 470 | while(r_ptr==(volatile int)w_ptr); |
| 471 | res=recbuf[r_ptr++]; |
| 472 | if(r_ptr==REC_BUFFER_SIZE) |
| 473 | r_ptr=0; |
| 474 | if(w_ptr<r_ptr) |
| 475 | diff=r_ptr+REC_BUFFER_SIZE-w_ptr; |
| 476 | else |
| 477 | diff=r_ptr-w_ptr; |
| 478 | if((diff<(REC_BUFFER_SIZE-4)) && buff_full) { |
Wolfgang Denk | a1be476 | 2008-05-20 16:00:29 +0200 | [diff] [blame] | 479 | /* clear Mail box */ |
wdenk | bc01dd5 | 2004-01-02 16:05:07 +0000 | [diff] [blame] | 480 | buff_full=0; |
| 481 | PCICON_SET_REG(PCICON_RECEIVE_REG,0L); |
| 482 | } |
| 483 | return res; |
| 484 | } |
| 485 | |
Simon Glass | 0d1e1f7 | 2014-07-23 06:54:59 -0600 | [diff] [blame] | 486 | int pci_con_tstc(struct stdio_dev *dev) |
wdenk | bc01dd5 | 2004-01-02 16:05:07 +0000 | [diff] [blame] | 487 | { |
| 488 | if(r_ptr==(volatile int)w_ptr) |
| 489 | return 0; |
| 490 | return 1; |
| 491 | } |
| 492 | |
Simon Glass | 0d1e1f7 | 2014-07-23 06:54:59 -0600 | [diff] [blame] | 493 | void pci_con_puts(struct stdio_dev *dev, const char *s) |
wdenk | bc01dd5 | 2004-01-02 16:05:07 +0000 | [diff] [blame] | 494 | { |
| 495 | while (*s) { |
| 496 | pci_con_putc(*s); |
| 497 | ++s; |
| 498 | } |
| 499 | } |
| 500 | |
| 501 | void pci_con_init (void) |
| 502 | { |
| 503 | w_ptr = 0; |
| 504 | r_ptr = 0; |
| 505 | PCICON_SET_REG(PCICON_RECEIVE_REG,0L); |
| 506 | conn=1; |
| 507 | } |
| 508 | |
| 509 | /******************************************* |
| 510 | * IRQ routine |
| 511 | ******************************************/ |
| 512 | int pci_dorbell_irq(void) |
| 513 | { |
| 514 | unsigned long reg,data; |
| 515 | int diff; |
| 516 | reg=PCICON_GET_REG(PCI9056_INT_CTRL_STAT); |
| 517 | PCI_CON_PRINTF(" PCI9056_INT_CTRL_STAT = %08lX\n",reg); |
| 518 | if(reg & (1<<20) ) { |
| 519 | /* read doorbell */ |
| 520 | reg=PCICON_GET_REG(PCICON_ACK_REG); |
| 521 | switch(reg) { |
| 522 | case PCIMSG_ALIVE: |
| 523 | PCI_CON_PRINTF(" Alive\n"); |
| 524 | PCICON_SET_REG(PCICON_DBELL_REG,PCIMSG_ALIVE); |
| 525 | break; |
| 526 | case PCIMSG_CONN: |
| 527 | PCI_CON_PRINTF(" Conn %d",conn); |
| 528 | w_ptr = 0; |
| 529 | r_ptr = 0; |
| 530 | buff_full=0; |
| 531 | PCICON_SET_REG(PCICON_RECEIVE_REG,0L); |
| 532 | conn=1; |
| 533 | PCI_CON_PRINTF(" ... %d\n",conn); |
| 534 | break; |
| 535 | case PCIMSG_CON_DATA: |
| 536 | data=PCICON_GET_REG(PCICON_RECEIVE_REG); |
| 537 | recbuf[w_ptr++]=(int)(data&0xff); |
| 538 | PCI_CON_PRINTF(" Data Console %lX, %X %d %d %X\n",data,((int)(data&0xFF)), |
| 539 | r_ptr,w_ptr,recbuf[w_ptr-1]); |
| 540 | if(w_ptr==REC_BUFFER_SIZE) |
| 541 | w_ptr=0; |
| 542 | if(w_ptr<r_ptr) |
| 543 | diff=r_ptr+REC_BUFFER_SIZE-w_ptr; |
| 544 | else |
| 545 | diff=r_ptr-w_ptr; |
| 546 | if(diff>(REC_BUFFER_SIZE-4)) |
| 547 | buff_full=1; |
| 548 | else |
| 549 | /* clear Mail box */ |
| 550 | PCICON_SET_REG(PCICON_RECEIVE_REG,0L); |
| 551 | break; |
| 552 | default: |
| 553 | serial_printf(" PCI9056_PCI_TO_LOC_DBELL = %08lX\n",reg); |
| 554 | } |
| 555 | /* clear IRQ */ |
| 556 | PCICON_SET_REG(PCICON_ACK_REG,~0L); |
| 557 | } |
| 558 | return 0; |
| 559 | } |
| 560 | |
| 561 | void pci_con_connect(void) |
| 562 | { |
| 563 | unsigned long reg; |
| 564 | conn=0; |
| 565 | reg=PCICON_GET_REG(PCI9056_INT_CTRL_STAT); |
| 566 | /* default 0x0f010180 */ |
| 567 | reg &= 0xff000000; |
| 568 | reg |= 0x00030000; /* enable local dorbell */ |
| 569 | reg |= 0x00000300; /* enable PCI dorbell */ |
| 570 | PCICON_SET_REG(PCI9056_INT_CTRL_STAT , reg); |
| 571 | irq_install_handler (0x2, (interrupt_handler_t *) pci_dorbell_irq,NULL); |
| 572 | memset (&pci_con_dev, 0, sizeof (pci_con_dev)); |
| 573 | strcpy (pci_con_dev.name, "pci_con"); |
Bin Meng | 6abe4b6 | 2015-11-03 23:23:37 -0800 | [diff] [blame] | 574 | pci_con_dev.flags = DEV_FLAGS_OUTPUT | DEV_FLAGS_INPUT; |
wdenk | bc01dd5 | 2004-01-02 16:05:07 +0000 | [diff] [blame] | 575 | pci_con_dev.putc = pci_con_putc; |
| 576 | pci_con_dev.puts = pci_con_puts; |
| 577 | pci_con_dev.getc = pci_con_getc; |
| 578 | pci_con_dev.tstc = pci_con_tstc; |
Jean-Christophe PLAGNIOL-VILLARD | 2a7a031 | 2009-05-16 12:14:54 +0200 | [diff] [blame] | 579 | stdio_register (&pci_con_dev); |
wdenk | bc01dd5 | 2004-01-02 16:05:07 +0000 | [diff] [blame] | 580 | printf("PATI ready for PCI connection, type ctrl-c for exit\n"); |
| 581 | do { |
| 582 | udelay(10); |
| 583 | if((volatile int)conn) |
| 584 | break; |
| 585 | if(ctrlc()) { |
| 586 | irq_free_handler(0x2); |
| 587 | return; |
| 588 | } |
| 589 | }while(1); |
| 590 | console_assign(stdin,"pci_con"); |
| 591 | console_assign(stderr,"pci_con"); |
| 592 | console_assign(stdout,"pci_con"); |
| 593 | } |
| 594 | |
| 595 | void pci_con_disc(void) |
| 596 | { |
| 597 | console_assign(stdin,"serial"); |
| 598 | console_assign(stderr,"serial"); |
| 599 | console_assign(stdout,"serial"); |
| 600 | PCICON_SET_REG(PCICON_DBELL_REG,PCIMSG_DISC); |
| 601 | /* reconnection */ |
| 602 | irq_free_handler(0x02); |
| 603 | pci_con_connect(); |
| 604 | } |
Jean-Christophe PLAGNIOL-VILLARD | 0383694 | 2008-10-16 15:01:15 +0200 | [diff] [blame] | 605 | #endif /* #ifdef CONFIG_SYS_PCI_CON_DEVICE */ |
wdenk | bc01dd5 | 2004-01-02 16:05:07 +0000 | [diff] [blame] | 606 | |
| 607 | /* |
| 608 | * Absolute environment address for linker file. |
| 609 | */ |
Jean-Christophe PLAGNIOL-VILLARD | 0383694 | 2008-10-16 15:01:15 +0200 | [diff] [blame] | 610 | GEN_ABS(env_start, CONFIG_ENV_OFFSET + CONFIG_SYS_FLASH_BASE); |