Esempio n. 1
0
/**
 * 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);
}
Esempio n. 2
0
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);


}
Esempio n. 3
0
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);

}