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