cvmx-compactflash.c revision 232812
1210284Sjmallett/***********************license start*************** 2232812Sjmallett * Copyright (c) 2003-2010 Cavium Inc. (support@cavium.com). All rights 3215990Sjmallett * reserved. 4210284Sjmallett * 5210284Sjmallett * 6215990Sjmallett * Redistribution and use in source and binary forms, with or without 7215990Sjmallett * modification, are permitted provided that the following conditions are 8215990Sjmallett * met: 9210284Sjmallett * 10215990Sjmallett * * Redistributions of source code must retain the above copyright 11215990Sjmallett * notice, this list of conditions and the following disclaimer. 12210284Sjmallett * 13215990Sjmallett * * Redistributions in binary form must reproduce the above 14215990Sjmallett * copyright notice, this list of conditions and the following 15215990Sjmallett * disclaimer in the documentation and/or other materials provided 16215990Sjmallett * with the distribution. 17215990Sjmallett 18232812Sjmallett * * Neither the name of Cavium Inc. nor the names of 19215990Sjmallett * its contributors may be used to endorse or promote products 20215990Sjmallett * derived from this software without specific prior written 21215990Sjmallett * permission. 22215990Sjmallett 23215990Sjmallett * This Software, including technical data, may be subject to U.S. export control 24215990Sjmallett * laws, including the U.S. Export Administration Act and its associated 25215990Sjmallett * regulations, and may be subject to export or import regulations in other 26215990Sjmallett * countries. 27215990Sjmallett 28215990Sjmallett * TO THE MAXIMUM EXTENT PERMITTED BY LAW, THE SOFTWARE IS PROVIDED "AS IS" 29232812Sjmallett * AND WITH ALL FAULTS AND CAVIUM INC. MAKES NO PROMISES, REPRESENTATIONS OR 30215990Sjmallett * WARRANTIES, EITHER EXPRESS, IMPLIED, STATUTORY, OR OTHERWISE, WITH RESPECT TO 31215990Sjmallett * THE SOFTWARE, INCLUDING ITS CONDITION, ITS CONFORMITY TO ANY REPRESENTATION OR 32215990Sjmallett * DESCRIPTION, OR THE EXISTENCE OF ANY LATENT OR PATENT DEFECTS, AND CAVIUM 33215990Sjmallett * SPECIFICALLY DISCLAIMS ALL IMPLIED (IF ANY) WARRANTIES OF TITLE, 34215990Sjmallett * MERCHANTABILITY, NONINFRINGEMENT, FITNESS FOR A PARTICULAR PURPOSE, LACK OF 35215990Sjmallett * VIRUSES, ACCURACY OR COMPLETENESS, QUIET ENJOYMENT, QUIET POSSESSION OR 36215990Sjmallett * CORRESPONDENCE TO DESCRIPTION. THE ENTIRE RISK ARISING OUT OF USE OR 37215990Sjmallett * PERFORMANCE OF THE SOFTWARE LIES WITH YOU. 38210284Sjmallett ***********************license end**************************************/ 39210284Sjmallett 40210284Sjmallett 41215990Sjmallett 42210284Sjmallett#include "cvmx.h" 43210284Sjmallett#include "cvmx-sysinfo.h" 44210284Sjmallett#include "cvmx-compactflash.h" 45210284Sjmallett 46210284Sjmallett 47210284Sjmallett#ifndef MAX 48210284Sjmallett#define MAX(a,b) (((a)>(b))?(a):(b)) 49210284Sjmallett#endif 50210284Sjmallett#define FLASH_RoundUP(_Dividend, _Divisor) (((_Dividend)+(_Divisor-1))/(_Divisor)) 51210284Sjmallett/** 52210284Sjmallett * Convert nanosecond based time to setting used in the 53210284Sjmallett * boot bus timing register, based on timing multiple 54215990Sjmallett * 55215990Sjmallett * 56210284Sjmallett */ 57210284Sjmallettstatic uint32_t ns_to_tim_reg(int tim_mult, uint32_t nsecs) 58210284Sjmallett{ 59210284Sjmallett uint32_t val; 60210284Sjmallett 61210284Sjmallett /* Compute # of eclock periods to get desired duration in nanoseconds */ 62215990Sjmallett val = FLASH_RoundUP(nsecs * (cvmx_clock_get_rate(CVMX_CLOCK_SCLK)/1000000), 1000); 63215990Sjmallett 64210284Sjmallett /* Factor in timing multiple, if not 1 */ 65210284Sjmallett if (tim_mult != 1) 66210284Sjmallett val = FLASH_RoundUP(val, tim_mult); 67215990Sjmallett 68210284Sjmallett return (val); 69210284Sjmallett} 70210284Sjmallett 71210284Sjmallettuint64_t cvmx_compactflash_generate_dma_tim(int tim_mult, uint16_t *ident_data, int *mwdma_mode_ptr) 72210284Sjmallett{ 73210284Sjmallett 74210284Sjmallett cvmx_mio_boot_dma_timx_t dma_tim; 75210284Sjmallett int oe_a; 76210284Sjmallett int oe_n; 77210284Sjmallett int dma_acks; 78210284Sjmallett int dma_ackh; 79210284Sjmallett int dma_arq; 80210284Sjmallett int pause; 81210284Sjmallett int To,Tkr,Td; 82210284Sjmallett int mwdma_mode = -1; 83210284Sjmallett uint16_t word53_field_valid; 84210284Sjmallett uint16_t word63_mwdma; 85210284Sjmallett uint16_t word163_adv_timing_info; 86210284Sjmallett 87210284Sjmallett if (!ident_data) 88210284Sjmallett return 0; 89210284Sjmallett 90210284Sjmallett word53_field_valid = ident_data[53]; 91215990Sjmallett word63_mwdma = ident_data[63]; 92210284Sjmallett word163_adv_timing_info = ident_data[163]; 93210284Sjmallett 94210284Sjmallett dma_tim.u64 = 0; 95210284Sjmallett 96210284Sjmallett /* Check for basic MWDMA modes */ 97210284Sjmallett if (word53_field_valid & 0x2) 98210284Sjmallett { 99210284Sjmallett if (word63_mwdma & 0x4) 100210284Sjmallett mwdma_mode = 2; 101210284Sjmallett else if (word63_mwdma & 0x2) 102210284Sjmallett mwdma_mode = 1; 103210284Sjmallett else if (word63_mwdma & 0x1) 104210284Sjmallett mwdma_mode = 0; 105210284Sjmallett } 106210284Sjmallett 107210284Sjmallett /* Check for advanced MWDMA modes */ 108210284Sjmallett switch ((word163_adv_timing_info >> 3) & 0x7) 109210284Sjmallett { 110210284Sjmallett case 1: 111210284Sjmallett mwdma_mode = 3; 112210284Sjmallett break; 113210284Sjmallett case 2: 114210284Sjmallett mwdma_mode = 4; 115210284Sjmallett break; 116210284Sjmallett default: 117210284Sjmallett break; 118210284Sjmallett 119210284Sjmallett } 120210284Sjmallett /* DMA is not supported by this card */ 121210284Sjmallett if (mwdma_mode < 0) 122210284Sjmallett return 0; 123210284Sjmallett 124210284Sjmallett /* Now set up the DMA timing */ 125210284Sjmallett switch (tim_mult) 126210284Sjmallett { 127210284Sjmallett case 1: 128210284Sjmallett dma_tim.s.tim_mult = 1; 129210284Sjmallett break; 130210284Sjmallett case 2: 131210284Sjmallett dma_tim.s.tim_mult = 2; 132210284Sjmallett break; 133210284Sjmallett case 4: 134210284Sjmallett dma_tim.s.tim_mult = 0; 135210284Sjmallett break; 136210284Sjmallett case 8: 137210284Sjmallett dma_tim.s.tim_mult = 3; 138210284Sjmallett break; 139210284Sjmallett default: 140210284Sjmallett cvmx_dprintf("ERROR: invalid boot bus dma tim_mult setting\n"); 141210284Sjmallett break; 142210284Sjmallett } 143210284Sjmallett 144210284Sjmallett 145210284Sjmallett switch (mwdma_mode) 146210284Sjmallett { 147210284Sjmallett case 4: 148210284Sjmallett To = 80; 149210284Sjmallett Td = 55; 150210284Sjmallett Tkr = 20; 151215990Sjmallett 152210284Sjmallett oe_a = Td + 20; // Td (Seem to need more margin here.... 153210284Sjmallett oe_n = MAX(To - oe_a, Tkr); // Tkr from cf spec, lengthened to meet To 154215990Sjmallett 155210284Sjmallett // oe_n + oe_h must be >= To (cycle time) 156210284Sjmallett dma_acks = 0; //Ti 157210284Sjmallett dma_ackh = 5; // Tj 158215990Sjmallett 159210284Sjmallett dma_arq = 8; // not spec'ed, value in eclocks, not affected by tim_mult 160215990Sjmallett pause = 25 - dma_arq * 1000/(cvmx_clock_get_rate(CVMX_CLOCK_SCLK)/1000000); // Tz 161210284Sjmallett break; 162210284Sjmallett case 3: 163210284Sjmallett To = 100; 164210284Sjmallett Td = 65; 165210284Sjmallett Tkr = 20; 166215990Sjmallett 167210284Sjmallett oe_a = Td + 20; // Td (Seem to need more margin here.... 168210284Sjmallett oe_n = MAX(To - oe_a, Tkr); // Tkr from cf spec, lengthened to meet To 169215990Sjmallett 170210284Sjmallett // oe_n + oe_h must be >= To (cycle time) 171210284Sjmallett dma_acks = 0; //Ti 172210284Sjmallett dma_ackh = 5; // Tj 173215990Sjmallett 174210284Sjmallett dma_arq = 8; // not spec'ed, value in eclocks, not affected by tim_mult 175215990Sjmallett pause = 25 - dma_arq * 1000/(cvmx_clock_get_rate(CVMX_CLOCK_SCLK)/1000000); // Tz 176210284Sjmallett break; 177210284Sjmallett case 2: 178210284Sjmallett // +20 works 179210284Sjmallett // +10 works 180210284Sjmallett // + 10 + 0 fails 181210284Sjmallett // n=40, a=80 works 182210284Sjmallett To = 120; 183210284Sjmallett Td = 70; 184210284Sjmallett Tkr = 25; 185210284Sjmallett 186210284Sjmallett // oe_a 0 fudge doesn't work; 10 seems to 187210284Sjmallett oe_a = Td + 20 + 10; // Td (Seem to need more margin here.... 188210284Sjmallett oe_n = MAX(To - oe_a, Tkr) + 10; // Tkr from cf spec, lengthened to meet To 189210284Sjmallett // oe_n 0 fudge fails;;; 10 boots 190210284Sjmallett 191210284Sjmallett // 20 ns fudge needed on dma_acks 192210284Sjmallett // oe_n + oe_h must be >= To (cycle time) 193210284Sjmallett dma_acks = 0 + 20; //Ti 194210284Sjmallett dma_ackh = 5; // Tj 195215990Sjmallett 196210284Sjmallett dma_arq = 8; // not spec'ed, value in eclocks, not affected by tim_mult 197215990Sjmallett pause = 25 - dma_arq * 1000/(cvmx_clock_get_rate(CVMX_CLOCK_SCLK)/1000000); // Tz 198210284Sjmallett // no fudge needed on pause 199215990Sjmallett 200210284Sjmallett break; 201210284Sjmallett case 1: 202210284Sjmallett case 0: 203210284Sjmallett default: 204210284Sjmallett cvmx_dprintf("ERROR: Unsupported DMA mode: %d\n", mwdma_mode); 205210284Sjmallett return(-1); 206210284Sjmallett break; 207210284Sjmallett } 208210284Sjmallett 209210284Sjmallett if (mwdma_mode_ptr) 210210284Sjmallett *mwdma_mode_ptr = mwdma_mode; 211215990Sjmallett 212210284Sjmallett dma_tim.s.dmack_pi = 1; 213215990Sjmallett 214210284Sjmallett dma_tim.s.oe_n = ns_to_tim_reg(tim_mult, oe_n); 215210284Sjmallett dma_tim.s.oe_a = ns_to_tim_reg(tim_mult, oe_a); 216215990Sjmallett 217210284Sjmallett dma_tim.s.dmack_s = ns_to_tim_reg(tim_mult, dma_acks); 218215990Sjmallett dma_tim.s.dmack_h = ns_to_tim_reg(tim_mult, dma_ackh); 219215990Sjmallett 220210284Sjmallett dma_tim.s.dmarq = dma_arq; 221210284Sjmallett dma_tim.s.pause = ns_to_tim_reg(tim_mult, pause); 222215990Sjmallett 223210284Sjmallett dma_tim.s.rd_dly = 0; /* Sample right on edge */ 224215990Sjmallett 225210284Sjmallett /* writes only */ 226210284Sjmallett dma_tim.s.we_n = ns_to_tim_reg(tim_mult, oe_n); 227210284Sjmallett dma_tim.s.we_a = ns_to_tim_reg(tim_mult, oe_a); 228215990Sjmallett 229210284Sjmallett#if 0 230210284Sjmallett cvmx_dprintf("ns to ticks (mult %d) of %d is: %d\n", TIM_MULT, 60, ns_to_tim_reg(60)); 231210284Sjmallett cvmx_dprintf("oe_n: %d, oe_a: %d, dmack_s: %d, dmack_h: %d, dmarq: %d, pause: %d\n", 232210284Sjmallett 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); 233210284Sjmallett#endif 234210284Sjmallett 235210284Sjmallett return(dma_tim.u64); 236210284Sjmallett 237210284Sjmallett 238210284Sjmallett} 239210284Sjmallett 240210284Sjmallett 241210284Sjmallett/** 242210284Sjmallett * Setup timing and region config to support a specific IDE PIO 243210284Sjmallett * mode over the bootbus. 244210284Sjmallett * 245210284Sjmallett * @param cs0 Bootbus region number connected to CS0 on the IDE device 246210284Sjmallett * @param cs1 Bootbus region number connected to CS1 on the IDE device 247210284Sjmallett * @param pio_mode PIO mode to set (0-6) 248210284Sjmallett */ 249210284Sjmallettvoid cvmx_compactflash_set_piomode(int cs0, int cs1, int pio_mode) 250210284Sjmallett{ 251210284Sjmallett cvmx_mio_boot_reg_cfgx_t mio_boot_reg_cfg; 252210284Sjmallett cvmx_mio_boot_reg_timx_t mio_boot_reg_tim; 253210284Sjmallett int cs; 254210284Sjmallett int clocks_us; /* Number of clock cycles per microsec */ 255210284Sjmallett int tim_mult; 256210284Sjmallett int use_iordy; /* Set for PIO0-4, not set for PIO5-6 */ 257210284Sjmallett int t1; /* These t names are timing parameters from the ATA spec */ 258210284Sjmallett int t2; 259210284Sjmallett int t2i; 260210284Sjmallett int t4; 261210284Sjmallett int t6; 262210284Sjmallett int t6z; 263210284Sjmallett int t9; 264210284Sjmallett 265210284Sjmallett /* PIO modes 0-4 all allow the device to deassert IORDY to slow down 266210284Sjmallett the host */ 267210284Sjmallett use_iordy = 1; 268210284Sjmallett 269210284Sjmallett /* Use the PIO mode to determine timing parameters */ 270210284Sjmallett switch(pio_mode) { 271210284Sjmallett case 6: 272210284Sjmallett /* CF spec say IORDY should be ignore in PIO 5 */ 273210284Sjmallett use_iordy = 0; 274210284Sjmallett t1 = 10; 275210284Sjmallett t2 = 55; 276210284Sjmallett t2i = 20; 277210284Sjmallett t4 = 5; 278210284Sjmallett t6 = 5; 279210284Sjmallett t6z = 20; 280210284Sjmallett t9 = 10; 281210284Sjmallett break; 282210284Sjmallett case 5: 283210284Sjmallett /* CF spec say IORDY should be ignore in PIO 6 */ 284210284Sjmallett use_iordy = 0; 285210284Sjmallett t1 = 15; 286210284Sjmallett t2 = 65; 287210284Sjmallett t2i = 25; 288210284Sjmallett t4 = 5; 289210284Sjmallett t6 = 5; 290210284Sjmallett t6z = 20; 291210284Sjmallett t9 = 10; 292210284Sjmallett break; 293210284Sjmallett case 4: 294210284Sjmallett t1 = 25; 295210284Sjmallett t2 = 70; 296210284Sjmallett t2i = 25; 297210284Sjmallett t4 = 10; 298210284Sjmallett t6 = 5; 299210284Sjmallett t6z = 30; 300210284Sjmallett t9 = 10; 301210284Sjmallett break; 302210284Sjmallett case 3: 303210284Sjmallett t1 = 30; 304210284Sjmallett t2 = 80; 305210284Sjmallett t2i = 70; 306210284Sjmallett t4 = 10; 307210284Sjmallett t6 = 5; 308210284Sjmallett t6z = 30; 309210284Sjmallett t9 = 10; 310210284Sjmallett break; 311210284Sjmallett case 2: 312210284Sjmallett t1 = 30; 313210284Sjmallett t2 = 100; 314210284Sjmallett t2i = 0; 315210284Sjmallett t4 = 15; 316210284Sjmallett t6 = 5; 317210284Sjmallett t6z = 30; 318210284Sjmallett t9 = 10; 319210284Sjmallett break; 320210284Sjmallett case 1: 321210284Sjmallett t1 = 50; 322210284Sjmallett t2 = 125; 323210284Sjmallett t2i = 0; 324210284Sjmallett t4 = 20; 325210284Sjmallett t6 = 5; 326210284Sjmallett t6z = 30; 327210284Sjmallett t9 = 15; 328210284Sjmallett break; 329210284Sjmallett default: 330210284Sjmallett t1 = 70; 331210284Sjmallett t2 = 165; 332210284Sjmallett t2i = 0; 333210284Sjmallett t4 = 30; 334210284Sjmallett t6 = 5; 335210284Sjmallett t6z = 30; 336210284Sjmallett t9 = 20; 337210284Sjmallett break; 338210284Sjmallett } 339210284Sjmallett /* Convert times in ns to clock cycles, rounding up */ 340215990Sjmallett clocks_us = FLASH_RoundUP(cvmx_clock_get_rate(CVMX_CLOCK_SCLK), 1000000); 341210284Sjmallett 342210284Sjmallett /* Convert times in clock cycles, rounding up. Octeon parameters are in 343210284Sjmallett minus one notation, so take off one after the conversion */ 344210284Sjmallett t1 = FLASH_RoundUP(t1 * clocks_us, 1000); 345210284Sjmallett if (t1) 346210284Sjmallett t1--; 347210284Sjmallett t2 = FLASH_RoundUP(t2 * clocks_us, 1000); 348210284Sjmallett if (t2) 349210284Sjmallett t2--; 350210284Sjmallett t2i = FLASH_RoundUP(t2i * clocks_us, 1000); 351210284Sjmallett if (t2i) 352210284Sjmallett t2i--; 353210284Sjmallett t4 = FLASH_RoundUP(t4 * clocks_us, 1000); 354210284Sjmallett if (t4) 355210284Sjmallett t4--; 356210284Sjmallett t6 = FLASH_RoundUP(t6 * clocks_us, 1000); 357210284Sjmallett if (t6) 358210284Sjmallett t6--; 359210284Sjmallett t6z = FLASH_RoundUP(t6z * clocks_us, 1000); 360210284Sjmallett if (t6z) 361210284Sjmallett t6z--; 362210284Sjmallett t9 = FLASH_RoundUP(t9 * clocks_us, 1000); 363210284Sjmallett if (t9) 364210284Sjmallett t9--; 365210284Sjmallett 366210284Sjmallett /* Start using a scale factor of one cycle. Keep doubling it until 367210284Sjmallett the parameters fit in their fields. Since t2 is the largest number, 368210284Sjmallett we only need to check it */ 369210284Sjmallett tim_mult = 1; 370210284Sjmallett while (t2 >= 1<<6) 371210284Sjmallett { 372210284Sjmallett t1 = FLASH_RoundUP(t1, 2); 373210284Sjmallett t2 = FLASH_RoundUP(t2, 2); 374210284Sjmallett t2i = FLASH_RoundUP(t2i, 2); 375210284Sjmallett t4 = FLASH_RoundUP(t4, 2); 376210284Sjmallett t6 = FLASH_RoundUP(t6, 2); 377210284Sjmallett t6z = FLASH_RoundUP(t6z, 2); 378210284Sjmallett t9 = FLASH_RoundUP(t9, 2); 379210284Sjmallett tim_mult *= 2; 380210284Sjmallett } 381210284Sjmallett 382210284Sjmallett cs = cs0; 383210284Sjmallett do { 384210284Sjmallett mio_boot_reg_cfg.u64 = cvmx_read_csr(CVMX_MIO_BOOT_REG_CFGX(cs)); 385210284Sjmallett mio_boot_reg_cfg.s.dmack = 0; /* Don't assert DMACK on access */ 386210284Sjmallett switch(tim_mult) { 387210284Sjmallett case 1: 388210284Sjmallett mio_boot_reg_cfg.s.tim_mult = 1; 389210284Sjmallett break; 390210284Sjmallett case 2: 391210284Sjmallett mio_boot_reg_cfg.s.tim_mult = 2; 392210284Sjmallett break; 393210284Sjmallett case 4: 394210284Sjmallett mio_boot_reg_cfg.s.tim_mult = 0; 395210284Sjmallett break; 396210284Sjmallett case 8: 397210284Sjmallett default: 398210284Sjmallett mio_boot_reg_cfg.s.tim_mult = 3; 399210284Sjmallett break; 400210284Sjmallett } 401210284Sjmallett mio_boot_reg_cfg.s.rd_dly = 0; /* Sample on falling edge of BOOT_OE */ 402210284Sjmallett mio_boot_reg_cfg.s.sam = 0; /* Don't combine write and output enable */ 403210284Sjmallett mio_boot_reg_cfg.s.we_ext = 0; /* No write enable extension */ 404210284Sjmallett mio_boot_reg_cfg.s.oe_ext = 0; /* No read enable extension */ 405210284Sjmallett mio_boot_reg_cfg.s.en = 1; /* Enable this region */ 406210284Sjmallett mio_boot_reg_cfg.s.orbit = 0; /* Don't combine with previos region */ 407210284Sjmallett mio_boot_reg_cfg.s.width = 1; /* 16 bits wide */ 408210284Sjmallett cvmx_write_csr(CVMX_MIO_BOOT_REG_CFGX(cs), mio_boot_reg_cfg.u64); 409210284Sjmallett if(cs == cs0) 410210284Sjmallett cs = cs1; 411210284Sjmallett else 412210284Sjmallett cs = cs0; 413210284Sjmallett } while(cs != cs0); 414210284Sjmallett 415210284Sjmallett mio_boot_reg_tim.u64 = 0; 416210284Sjmallett mio_boot_reg_tim.s.pagem = 0; /* Disable page mode */ 417210284Sjmallett mio_boot_reg_tim.s.waitm = use_iordy; /* Enable dynamic timing */ 418210284Sjmallett mio_boot_reg_tim.s.pages = 0; /* Pages are disabled */ 419210284Sjmallett mio_boot_reg_tim.s.ale = 8; /* If someone uses ALE, this seems to work */ 420210284Sjmallett mio_boot_reg_tim.s.page = 0; /* Not used */ 421210284Sjmallett mio_boot_reg_tim.s.wait = 0; /* Time after IORDY to coninue to assert the data */ 422210284Sjmallett mio_boot_reg_tim.s.pause = 0; /* Time after CE that signals stay valid */ 423210284Sjmallett mio_boot_reg_tim.s.wr_hld = t9; /* How long to hold after a write */ 424210284Sjmallett mio_boot_reg_tim.s.rd_hld = t9; /* How long to wait after a read for device to tristate */ 425210284Sjmallett mio_boot_reg_tim.s.we = t2; /* How long write enable is asserted */ 426210284Sjmallett mio_boot_reg_tim.s.oe = t2; /* How long read enable is asserted */ 427210284Sjmallett mio_boot_reg_tim.s.ce = t1; /* Time after CE that read/write starts */ 428210284Sjmallett mio_boot_reg_tim.s.adr = 1; /* Time before CE that address is valid */ 429210284Sjmallett 430210284Sjmallett /* Program the bootbus region timing for both chip selects */ 431210284Sjmallett cvmx_write_csr(CVMX_MIO_BOOT_REG_TIMX(cs0), mio_boot_reg_tim.u64); 432210284Sjmallett cvmx_write_csr(CVMX_MIO_BOOT_REG_TIMX(cs1), mio_boot_reg_tim.u64); 433210284Sjmallett} 434