/** * Called after libata determines the needed PIO mode. This * function programs the Octeon bootbus regions to support the * timing requirements of the PIO mode. * * @ap: ATA port information * @dev: ATA device */ static void octeon_cf_set_piomode(struct ata_port *ap, struct ata_device *dev) { struct octeon_cf_data *ocd = ap->dev->platform_data; union cvmx_mio_boot_reg_timx reg_tim; int cs = ocd->base_region; int T; struct ata_timing timing; int use_iordy; int trh; int pause; /* These names are timing parameters from the ATA spec */ int t1; int t2; int t2i; T = (int)(2000000000000LL / octeon_get_clock_rate()); if (ata_timing_compute(dev, dev->pio_mode, &timing, T, T)) BUG(); t1 = timing.setup; if (t1) t1--; t2 = timing.active; if (t2) t2--; t2i = timing.act8b; if (t2i) t2i--; trh = ns_to_tim_reg(2, 20); if (trh) trh--; pause = timing.cycle - timing.active - timing.setup - trh; if (pause) pause--; octeon_cf_set_boot_reg_cfg(cs); if (ocd->dma_engine >= 0) /* True IDE mode, program both chip selects. */ octeon_cf_set_boot_reg_cfg(cs + 1); use_iordy = ata_pio_need_iordy(dev); reg_tim.u64 = cvmx_read_csr(CVMX_MIO_BOOT_REG_TIMX(cs)); /* Disable page mode */ reg_tim.s.pagem = 0; /* Enable dynamic timing */ reg_tim.s.waitm = use_iordy; /* Pages are disabled */ reg_tim.s.pages = 0; /* We don't use multiplexed address mode */ reg_tim.s.ale = 0; /* Not used */ reg_tim.s.page = 0; /* Time after IORDY to coninue to assert the data */ reg_tim.s.wait = 0; /* Time to wait to complete the cycle. */ reg_tim.s.pause = pause; /* How long to hold after a write to de-assert CE. */ reg_tim.s.wr_hld = trh; /* How long to wait after a read to de-assert CE. */ reg_tim.s.rd_hld = trh; /* How long write enable is asserted */ reg_tim.s.we = t2; /* How long read enable is asserted */ reg_tim.s.oe = t2; /* Time after CE that read/write starts */ reg_tim.s.ce = ns_to_tim_reg(2, 5); /* Time before CE that address is valid */ reg_tim.s.adr = 0; /* Program the bootbus region timing for the data port chip select. */ cvmx_write_csr(CVMX_MIO_BOOT_REG_TIMX(cs), reg_tim.u64); if (ocd->dma_engine >= 0) /* True IDE mode, program both chip selects. */ cvmx_write_csr(CVMX_MIO_BOOT_REG_TIMX(cs + 1), reg_tim.u64); }
uint64_t cvmx_compactflash_generate_dma_tim(int tim_mult, uint16_t *ident_data, int *mwdma_mode_ptr) { cvmx_mio_boot_dma_timx_t dma_tim; int oe_a; int oe_n; int dma_acks; int dma_ackh; int dma_arq; int pause; int To,Tkr,Td; int mwdma_mode = -1; uint16_t word53_field_valid; uint16_t word63_mwdma; uint16_t word163_adv_timing_info; if (!ident_data) return 0; word53_field_valid = ident_data[53]; word63_mwdma = ident_data[63]; word163_adv_timing_info = ident_data[163]; dma_tim.u64 = 0; /* Check for basic MWDMA modes */ if (word53_field_valid & 0x2) { if (word63_mwdma & 0x4) mwdma_mode = 2; else if (word63_mwdma & 0x2) mwdma_mode = 1; else if (word63_mwdma & 0x1) mwdma_mode = 0; } /* Check for advanced MWDMA modes */ switch ((word163_adv_timing_info >> 3) & 0x7) { case 1: mwdma_mode = 3; break; case 2: mwdma_mode = 4; break; default: break; } /* DMA is not supported by this card */ if (mwdma_mode < 0) return 0; /* Now set up the DMA timing */ switch (tim_mult) { case 1: dma_tim.s.tim_mult = 1; break; case 2: dma_tim.s.tim_mult = 2; break; case 4: dma_tim.s.tim_mult = 0; break; case 8: dma_tim.s.tim_mult = 3; break; default: cvmx_dprintf("ERROR: invalid boot bus dma tim_mult setting\n"); break; } switch (mwdma_mode) { case 4: To = 80; Td = 55; Tkr = 20; oe_a = Td + 20; // Td (Seem to need more margin here.... oe_n = MAX(To - oe_a, Tkr); // Tkr from cf spec, lengthened to meet To // oe_n + oe_h must be >= To (cycle time) dma_acks = 0; //Ti dma_ackh = 5; // Tj dma_arq = 8; // not spec'ed, value in eclocks, not affected by tim_mult pause = 25 - dma_arq * 1000/(cvmx_sysinfo_get()->cpu_clock_hz/1000000); // Tz break; case 3: To = 100; Td = 65; Tkr = 20; oe_a = Td + 20; // Td (Seem to need more margin here.... oe_n = MAX(To - oe_a, Tkr); // Tkr from cf spec, lengthened to meet To // oe_n + oe_h must be >= To (cycle time) dma_acks = 0; //Ti dma_ackh = 5; // Tj dma_arq = 8; // not spec'ed, value in eclocks, not affected by tim_mult pause = 25 - dma_arq * 1000/(cvmx_sysinfo_get()->cpu_clock_hz/1000000); // Tz break; case 2: // +20 works // +10 works // + 10 + 0 fails // n=40, a=80 works To = 120; Td = 70; Tkr = 25; // oe_a 0 fudge doesn't work; 10 seems to oe_a = Td + 20 + 10; // Td (Seem to need more margin here.... oe_n = MAX(To - oe_a, Tkr) + 10; // Tkr from cf spec, lengthened to meet To // oe_n 0 fudge fails;;; 10 boots // 20 ns fudge needed on dma_acks // oe_n + oe_h must be >= To (cycle time) dma_acks = 0 + 20; //Ti dma_ackh = 5; // Tj dma_arq = 8; // not spec'ed, value in eclocks, not affected by tim_mult pause = 25 - dma_arq * 1000/(cvmx_sysinfo_get()->cpu_clock_hz/1000000); // Tz // no fudge needed on pause break; case 1: case 0: default: cvmx_dprintf("ERROR: Unsupported DMA mode: %d\n", mwdma_mode); return(-1); break; } if (mwdma_mode_ptr) *mwdma_mode_ptr = mwdma_mode; dma_tim.s.dmack_pi = 1; dma_tim.s.oe_n = ns_to_tim_reg(tim_mult, oe_n); dma_tim.s.oe_a = ns_to_tim_reg(tim_mult, oe_a); dma_tim.s.dmack_s = ns_to_tim_reg(tim_mult, dma_acks); dma_tim.s.dmack_h = ns_to_tim_reg(tim_mult, dma_ackh); dma_tim.s.dmarq = dma_arq; dma_tim.s.pause = ns_to_tim_reg(tim_mult, pause); dma_tim.s.rd_dly = 0; /* Sample right on edge */ /* writes only */ dma_tim.s.we_n = ns_to_tim_reg(tim_mult, oe_n); dma_tim.s.we_a = ns_to_tim_reg(tim_mult, oe_a); #if 0 cvmx_dprintf("ns to ticks (mult %d) of %d is: %d\n", TIM_MULT, 60, ns_to_tim_reg(60)); cvmx_dprintf("oe_n: %d, oe_a: %d, dmack_s: %d, dmack_h: %d, dmarq: %d, pause: %d\n", 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); #endif return(dma_tim.u64); }
static void octeon_cf_set_dmamode(struct ata_port *ap, struct ata_device *dev) { struct octeon_cf_data *ocd = dev->link->ap->dev->platform_data; union cvmx_mio_boot_dma_timx dma_tim; unsigned int oe_a; unsigned int oe_n; unsigned int dma_ackh; unsigned int dma_arq; unsigned int pause; unsigned int T0, Tkr, Td; unsigned int tim_mult; const struct ata_timing *timing; timing = ata_timing_find_mode(dev->dma_mode); T0 = timing->cycle; Td = timing->active; Tkr = timing->recover; dma_ackh = timing->dmack_hold; dma_tim.u64 = 0; /* dma_tim.s.tim_mult = 0 --> 4x */ tim_mult = 4; /* not spec'ed, value in eclocks, not affected by tim_mult */ dma_arq = 8; pause = 25 - dma_arq * 1000 / (octeon_get_clock_rate() / 1000000); /* Tz */ oe_a = Td; /* Tkr from cf spec, lengthened to meet T0 */ oe_n = max(T0 - oe_a, Tkr); dma_tim.s.dmack_pi = 1; dma_tim.s.oe_n = ns_to_tim_reg(tim_mult, oe_n); dma_tim.s.oe_a = ns_to_tim_reg(tim_mult, oe_a); /* * This is tI, C.F. spec. says 0, but Sony CF card requires * more, we use 20 nS. */ dma_tim.s.dmack_s = ns_to_tim_reg(tim_mult, 20); dma_tim.s.dmack_h = ns_to_tim_reg(tim_mult, dma_ackh); dma_tim.s.dmarq = dma_arq; dma_tim.s.pause = ns_to_tim_reg(tim_mult, pause); dma_tim.s.rd_dly = 0; /* Sample right on edge */ /* writes only */ dma_tim.s.we_n = ns_to_tim_reg(tim_mult, oe_n); dma_tim.s.we_a = ns_to_tim_reg(tim_mult, oe_a); pr_debug("ns to ticks (mult %d) of %d is: %d\n", tim_mult, 60, ns_to_tim_reg(tim_mult, 60)); pr_debug("oe_n: %d, oe_a: %d, dmack_s: %d, dmack_h: " "%d, dmarq: %d, pause: %d\n", 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); cvmx_write_csr(CVMX_MIO_BOOT_DMA_TIMX(ocd->dma_engine), dma_tim.u64); }