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