]> CyberLeo.Net >> Repos - FreeBSD/releng/8.2.git/blob - sys/contrib/octeon-sdk/cvmx-compactflash.c
Copy stable/8 to releng/8.2 in preparation for FreeBSD-8.2 release.
[FreeBSD/releng/8.2.git] / sys / contrib / octeon-sdk / cvmx-compactflash.c
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  */
55 static 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
69 uint64_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  */
247 void 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 }