1/***********************license start*************** 2 * Copyright (c) 2003-2010 Cavium Inc. (support@cavium.com). All rights 3 * reserved. 4 * 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions are 8 * met: 9 * 10 * * Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 13 * * Redistributions in binary form must reproduce the above 14 * copyright notice, this list of conditions and the following 15 * disclaimer in the documentation and/or other materials provided 16 * with the distribution. 17 18 * * Neither the name of Cavium Inc. nor the names of 19 * its contributors may be used to endorse or promote products 20 * derived from this software without specific prior written 21 * permission. 22 23 * This Software, including technical data, may be subject to U.S. export control 24 * laws, including the U.S. Export Administration Act and its associated 25 * regulations, and may be subject to export or import regulations in other 26 * countries. 27 28 * TO THE MAXIMUM EXTENT PERMITTED BY LAW, THE SOFTWARE IS PROVIDED "AS IS" 29 * AND WITH ALL FAULTS AND CAVIUM INC. MAKES NO PROMISES, REPRESENTATIONS OR 30 * WARRANTIES, EITHER EXPRESS, IMPLIED, STATUTORY, OR OTHERWISE, WITH RESPECT TO 31 * THE SOFTWARE, INCLUDING ITS CONDITION, ITS CONFORMITY TO ANY REPRESENTATION OR 32 * DESCRIPTION, OR THE EXISTENCE OF ANY LATENT OR PATENT DEFECTS, AND CAVIUM 33 * SPECIFICALLY DISCLAIMS ALL IMPLIED (IF ANY) WARRANTIES OF TITLE, 34 * MERCHANTABILITY, NONINFRINGEMENT, FITNESS FOR A PARTICULAR PURPOSE, LACK OF 35 * VIRUSES, ACCURACY OR COMPLETENESS, QUIET ENJOYMENT, QUIET POSSESSION OR 36 * CORRESPONDENCE TO DESCRIPTION. THE ENTIRE RISK ARISING OUT OF USE OR 37 * PERFORMANCE OF THE SOFTWARE LIES WITH YOU. 38 ***********************license end**************************************/ 39 40 41 42#include "cvmx.h" 43#include "cvmx-sysinfo.h" 44#include "cvmx-compactflash.h" 45 46 47#ifndef MAX 48#define MAX(a,b) (((a)>(b))?(a):(b)) 49#endif 50#define FLASH_RoundUP(_Dividend, _Divisor) (((_Dividend)+(_Divisor-1))/(_Divisor)) 51/** 52 * Convert nanosecond based time to setting used in the 53 * boot bus timing register, based on timing multiple 54 * 55 * 56 */ 57static uint32_t ns_to_tim_reg(int tim_mult, uint32_t nsecs) 58{ 59 uint32_t val; 60 61 /* Compute # of eclock periods to get desired duration in nanoseconds */ 62 val = FLASH_RoundUP(nsecs * (cvmx_clock_get_rate(CVMX_CLOCK_SCLK)/1000000), 1000); 63 64 /* Factor in timing multiple, if not 1 */ 65 if (tim_mult != 1) 66 val = FLASH_RoundUP(val, tim_mult); 67 68 return (val); 69} 70 71uint64_t cvmx_compactflash_generate_dma_tim(int tim_mult, uint16_t *ident_data, int *mwdma_mode_ptr) 72{ 73 74 cvmx_mio_boot_dma_timx_t dma_tim; 75 int oe_a; 76 int oe_n; 77 int dma_acks; 78 int dma_ackh; 79 int dma_arq; 80 int pause; 81 int To,Tkr,Td; 82 int mwdma_mode = -1; 83 uint16_t word53_field_valid; 84 uint16_t word63_mwdma; 85 uint16_t word163_adv_timing_info; 86 87 if (!ident_data) 88 return 0; 89 90 word53_field_valid = ident_data[53]; 91 word63_mwdma = ident_data[63]; 92 word163_adv_timing_info = ident_data[163]; 93 94 dma_tim.u64 = 0; 95 96 /* Check for basic MWDMA modes */ 97 if (word53_field_valid & 0x2) 98 { 99 if (word63_mwdma & 0x4) 100 mwdma_mode = 2; 101 else if (word63_mwdma & 0x2) 102 mwdma_mode = 1; 103 else if (word63_mwdma & 0x1) 104 mwdma_mode = 0; 105 } 106 107 /* Check for advanced MWDMA modes */ 108 switch ((word163_adv_timing_info >> 3) & 0x7) 109 { 110 case 1: 111 mwdma_mode = 3; 112 break; 113 case 2: 114 mwdma_mode = 4; 115 break; 116 default: 117 break; 118 119 } 120 /* DMA is not supported by this card */ 121 if (mwdma_mode < 0) 122 return 0; 123 124 /* Now set up the DMA timing */ 125 switch (tim_mult) 126 { 127 case 1: 128 dma_tim.s.tim_mult = 1; 129 break; 130 case 2: 131 dma_tim.s.tim_mult = 2; 132 break; 133 case 4: 134 dma_tim.s.tim_mult = 0; 135 break; 136 case 8: 137 dma_tim.s.tim_mult = 3; 138 break; 139 default: 140 cvmx_dprintf("ERROR: invalid boot bus dma tim_mult setting\n"); 141 break; 142 } 143 144 145 switch (mwdma_mode) 146 { 147 case 4: 148 To = 80; 149 Td = 55; 150 Tkr = 20; 151 152 oe_a = Td + 20; // Td (Seem to need more margin here.... 153 oe_n = MAX(To - oe_a, Tkr); // Tkr from cf spec, lengthened to meet To 154 155 // oe_n + oe_h must be >= To (cycle time) 156 dma_acks = 0; //Ti 157 dma_ackh = 5; // Tj 158 159 dma_arq = 8; // not spec'ed, value in eclocks, not affected by tim_mult 160 pause = 25 - dma_arq * 1000/(cvmx_clock_get_rate(CVMX_CLOCK_SCLK)/1000000); // Tz 161 break; 162 case 3: 163 To = 100; 164 Td = 65; 165 Tkr = 20; 166 167 oe_a = Td + 20; // Td (Seem to need more margin here.... 168 oe_n = MAX(To - oe_a, Tkr); // Tkr from cf spec, lengthened to meet To 169 170 // oe_n + oe_h must be >= To (cycle time) 171 dma_acks = 0; //Ti 172 dma_ackh = 5; // Tj 173 174 dma_arq = 8; // not spec'ed, value in eclocks, not affected by tim_mult 175 pause = 25 - dma_arq * 1000/(cvmx_clock_get_rate(CVMX_CLOCK_SCLK)/1000000); // Tz 176 break; 177 case 2: 178 // +20 works 179 // +10 works 180 // + 10 + 0 fails 181 // n=40, a=80 works 182 To = 120; 183 Td = 70; 184 Tkr = 25; 185 186 // oe_a 0 fudge doesn't work; 10 seems to 187 oe_a = Td + 20 + 10; // Td (Seem to need more margin here.... 188 oe_n = MAX(To - oe_a, Tkr) + 10; // Tkr from cf spec, lengthened to meet To 189 // oe_n 0 fudge fails;;; 10 boots 190 191 // 20 ns fudge needed on dma_acks 192 // oe_n + oe_h must be >= To (cycle time) 193 dma_acks = 0 + 20; //Ti 194 dma_ackh = 5; // Tj 195 196 dma_arq = 8; // not spec'ed, value in eclocks, not affected by tim_mult 197 pause = 25 - dma_arq * 1000/(cvmx_clock_get_rate(CVMX_CLOCK_SCLK)/1000000); // Tz 198 // no fudge needed on pause 199 200 break; 201 case 1: 202 case 0: 203 default: 204 cvmx_dprintf("ERROR: Unsupported DMA mode: %d\n", mwdma_mode); 205 return(-1); 206 break; 207 } 208 209 if (mwdma_mode_ptr) 210 *mwdma_mode_ptr = mwdma_mode; 211 212 dma_tim.s.dmack_pi = 1; 213 214 dma_tim.s.oe_n = ns_to_tim_reg(tim_mult, oe_n); 215 dma_tim.s.oe_a = ns_to_tim_reg(tim_mult, oe_a); 216 217 dma_tim.s.dmack_s = ns_to_tim_reg(tim_mult, dma_acks); 218 dma_tim.s.dmack_h = ns_to_tim_reg(tim_mult, dma_ackh); 219 220 dma_tim.s.dmarq = dma_arq; 221 dma_tim.s.pause = ns_to_tim_reg(tim_mult, pause); 222 223 dma_tim.s.rd_dly = 0; /* Sample right on edge */ 224 225 /* writes only */ 226 dma_tim.s.we_n = ns_to_tim_reg(tim_mult, oe_n); 227 dma_tim.s.we_a = ns_to_tim_reg(tim_mult, oe_a); 228 229#if 0 230 cvmx_dprintf("ns to ticks (mult %d) of %d is: %d\n", TIM_MULT, 60, ns_to_tim_reg(60)); 231 cvmx_dprintf("oe_n: %d, oe_a: %d, dmack_s: %d, dmack_h: %d, dmarq: %d, pause: %d\n", 232 dma_tim.s.oe_n, dma_tim.s.oe_a, dma_tim.s.dmack_s, dma_tim.s.dmack_h, dma_tim.s.dmarq, dma_tim.s.pause); 233#endif 234 235 return(dma_tim.u64); 236 237 238} 239 240 241/** 242 * Setup timing and region config to support a specific IDE PIO 243 * mode over the bootbus. 244 * 245 * @param cs0 Bootbus region number connected to CS0 on the IDE device 246 * @param cs1 Bootbus region number connected to CS1 on the IDE device 247 * @param pio_mode PIO mode to set (0-6) 248 */ 249void cvmx_compactflash_set_piomode(int cs0, int cs1, int pio_mode) 250{ 251 cvmx_mio_boot_reg_cfgx_t mio_boot_reg_cfg; 252 cvmx_mio_boot_reg_timx_t mio_boot_reg_tim; 253 int cs; 254 int clocks_us; /* Number of clock cycles per microsec */ 255 int tim_mult; 256 int use_iordy; /* Set for PIO0-4, not set for PIO5-6 */ 257 int t1; /* These t names are timing parameters from the ATA spec */ 258 int t2; 259 int t2i; 260 int t4; 261 int t6; 262 int t6z; 263 int t9; 264 265 /* PIO modes 0-4 all allow the device to deassert IORDY to slow down 266 the host */ 267 use_iordy = 1; 268 269 /* Use the PIO mode to determine timing parameters */ 270 switch(pio_mode) { 271 case 6: 272 /* CF spec say IORDY should be ignore in PIO 5 */ 273 use_iordy = 0; 274 t1 = 10; 275 t2 = 55; 276 t2i = 20; 277 t4 = 5; 278 t6 = 5; 279 t6z = 20; 280 t9 = 10; 281 break; 282 case 5: 283 /* CF spec say IORDY should be ignore in PIO 6 */ 284 use_iordy = 0; 285 t1 = 15; 286 t2 = 65; 287 t2i = 25; 288 t4 = 5; 289 t6 = 5; 290 t6z = 20; 291 t9 = 10; 292 break; 293 case 4: 294 t1 = 25; 295 t2 = 70; 296 t2i = 25; 297 t4 = 10; 298 t6 = 5; 299 t6z = 30; 300 t9 = 10; 301 break; 302 case 3: 303 t1 = 30; 304 t2 = 80; 305 t2i = 70; 306 t4 = 10; 307 t6 = 5; 308 t6z = 30; 309 t9 = 10; 310 break; 311 case 2: 312 t1 = 30; 313 t2 = 100; 314 t2i = 0; 315 t4 = 15; 316 t6 = 5; 317 t6z = 30; 318 t9 = 10; 319 break; 320 case 1: 321 t1 = 50; 322 t2 = 125; 323 t2i = 0; 324 t4 = 20; 325 t6 = 5; 326 t6z = 30; 327 t9 = 15; 328 break; 329 default: 330 t1 = 70; 331 t2 = 165; 332 t2i = 0; 333 t4 = 30; 334 t6 = 5; 335 t6z = 30; 336 t9 = 20; 337 break; 338 } 339 /* Convert times in ns to clock cycles, rounding up */ 340 clocks_us = FLASH_RoundUP(cvmx_clock_get_rate(CVMX_CLOCK_SCLK), 1000000); 341 342 /* Convert times in clock cycles, rounding up. Octeon parameters are in 343 minus one notation, so take off one after the conversion */ 344 t1 = FLASH_RoundUP(t1 * clocks_us, 1000); 345 if (t1) 346 t1--; 347 t2 = FLASH_RoundUP(t2 * clocks_us, 1000); 348 if (t2) 349 t2--; 350 t2i = FLASH_RoundUP(t2i * clocks_us, 1000); 351 if (t2i) 352 t2i--; 353 t4 = FLASH_RoundUP(t4 * clocks_us, 1000); 354 if (t4) 355 t4--; 356 t6 = FLASH_RoundUP(t6 * clocks_us, 1000); 357 if (t6) 358 t6--; 359 t6z = FLASH_RoundUP(t6z * clocks_us, 1000); 360 if (t6z) 361 t6z--; 362 t9 = FLASH_RoundUP(t9 * clocks_us, 1000); 363 if (t9) 364 t9--; 365 366 /* Start using a scale factor of one cycle. Keep doubling it until 367 the parameters fit in their fields. Since t2 is the largest number, 368 we only need to check it */ 369 tim_mult = 1; 370 while (t2 >= 1<<6) 371 { 372 t1 = FLASH_RoundUP(t1, 2); 373 t2 = FLASH_RoundUP(t2, 2); 374 t2i = FLASH_RoundUP(t2i, 2); 375 t4 = FLASH_RoundUP(t4, 2); 376 t6 = FLASH_RoundUP(t6, 2); 377 t6z = FLASH_RoundUP(t6z, 2); 378 t9 = FLASH_RoundUP(t9, 2); 379 tim_mult *= 2; 380 } 381 382 cs = cs0; 383 do { 384 mio_boot_reg_cfg.u64 = cvmx_read_csr(CVMX_MIO_BOOT_REG_CFGX(cs)); 385 mio_boot_reg_cfg.s.dmack = 0; /* Don't assert DMACK on access */ 386 switch(tim_mult) { 387 case 1: 388 mio_boot_reg_cfg.s.tim_mult = 1; 389 break; 390 case 2: 391 mio_boot_reg_cfg.s.tim_mult = 2; 392 break; 393 case 4: 394 mio_boot_reg_cfg.s.tim_mult = 0; 395 break; 396 case 8: 397 default: 398 mio_boot_reg_cfg.s.tim_mult = 3; 399 break; 400 } 401 mio_boot_reg_cfg.s.rd_dly = 0; /* Sample on falling edge of BOOT_OE */ 402 mio_boot_reg_cfg.s.sam = 0; /* Don't combine write and output enable */ 403 mio_boot_reg_cfg.s.we_ext = 0; /* No write enable extension */ 404 mio_boot_reg_cfg.s.oe_ext = 0; /* No read enable extension */ 405 mio_boot_reg_cfg.s.en = 1; /* Enable this region */ 406 mio_boot_reg_cfg.s.orbit = 0; /* Don't combine with previos region */ 407 mio_boot_reg_cfg.s.width = 1; /* 16 bits wide */ 408 cvmx_write_csr(CVMX_MIO_BOOT_REG_CFGX(cs), mio_boot_reg_cfg.u64); 409 if(cs == cs0) 410 cs = cs1; 411 else 412 cs = cs0; 413 } while(cs != cs0); 414 415 mio_boot_reg_tim.u64 = 0; 416 mio_boot_reg_tim.s.pagem = 0; /* Disable page mode */ 417 mio_boot_reg_tim.s.waitm = use_iordy; /* Enable dynamic timing */ 418 mio_boot_reg_tim.s.pages = 0; /* Pages are disabled */ 419 mio_boot_reg_tim.s.ale = 8; /* If someone uses ALE, this seems to work */ 420 mio_boot_reg_tim.s.page = 0; /* Not used */ 421 mio_boot_reg_tim.s.wait = 0; /* Time after IORDY to coninue to assert the data */ 422 mio_boot_reg_tim.s.pause = 0; /* Time after CE that signals stay valid */ 423 mio_boot_reg_tim.s.wr_hld = t9; /* How long to hold after a write */ 424 mio_boot_reg_tim.s.rd_hld = t9; /* How long to wait after a read for device to tristate */ 425 mio_boot_reg_tim.s.we = t2; /* How long write enable is asserted */ 426 mio_boot_reg_tim.s.oe = t2; /* How long read enable is asserted */ 427 mio_boot_reg_tim.s.ce = t1; /* Time after CE that read/write starts */ 428 mio_boot_reg_tim.s.adr = 1; /* Time before CE that address is valid */ 429 430 /* Program the bootbus region timing for both chip selects */ 431 cvmx_write_csr(CVMX_MIO_BOOT_REG_TIMX(cs0), mio_boot_reg_tim.u64); 432 cvmx_write_csr(CVMX_MIO_BOOT_REG_TIMX(cs1), mio_boot_reg_tim.u64); 433} 434