MOXA linux-2.6.x / linux-2.6.19-uc1 from UC-7110-LX-BOOTLOADER-1.9_VERSION-4.2.tgz
[linux-2.6.19-moxart.git] / drivers / mtd / chips / epcs_low.c
blobc529fd3ce42d0ecb0483c744028946b93fb07988
1 /*
2 * (C) Copyright 2004, Psyent Corporation <www.psyent.com>
3 * Scott McNutt <smcnutt@psyent.com>
5 * See file CREDITS for list of people who contributed to this
6 * project.
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License as
10 * published by the Free Software Foundation; either version 2 of
11 * the License, or (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
21 * MA 02111-1307 USA
24 * Modified by Jai Dhar, FPS-Tech <contact@fps-tech.net>
25 * Modifications made to work with uClinux, linux 2.6.11 kernel
27 * TODO: - Add timeouts to while loops; kernel will stall if somethings
28 * goes bad otherwise
29 * - Possibly add verifying to writes?
30 * - LED Displays
34 #include <asm/io.h>
35 #include "epcs.h"
39 /*-----------------------------------------------------------------------*/
40 /* Operation codes for serial configuration devices
42 #define EPCS_WRITE_ENA 0x06 /* Write enable */
43 #define EPCS_WRITE_DIS 0x04 /* Write disable */
44 #define EPCS_READ_STAT 0x05 /* Read status */
45 #define EPCS_READ_BYTES 0x03 /* Read bytes */
46 #define EPCS_READ_ID 0xab /* Read silicon id */
47 #define EPCS_WRITE_STAT 0x01 /* Write status */
48 #define EPCS_WRITE_BYTES 0x02 /* Write bytes */
49 #define EPCS_ERASE_BULK 0xc7 /* Erase entire device */
50 #define EPCS_ERASE_SECT 0xd8 /* Erase sector */
52 /* Device status register bits
54 #define EPCS_STATUS_WIP (1<<0) /* Write in progress */
55 #define EPCS_STATUS_WEL (1<<1) /* Write enable latch */
58 static nios_spi_t *epcs;
60 void epcs_print_regs(void)
62 printk(KERN_NOTICE "Printing EPCS Registers\n");
63 printk(KERN_NOTICE "rxdata: 0x%X, 0x%X\n",(u_int) &epcs->rxdata,(u_int) readl(&epcs->rxdata));
64 printk(KERN_NOTICE "txdata: 0x%X, 0x%X\n",(u_int) &epcs->txdata,(u_int) readl(&epcs->txdata));
65 printk(KERN_NOTICE "status: 0x%X, 0x%X\n",(u_int) &epcs->status,(u_int) readl(&epcs->status));
66 printk(KERN_NOTICE "control: 0x%X, 0x%X\n",(u_int) &epcs->control,(u_int) readl(&epcs->control));
67 printk(KERN_NOTICE "reserved: 0x%X, 0x%X\n",(u_int) &epcs->reserved,(u_int) readl(&epcs->reserved));
68 printk(KERN_NOTICE "slaveselect: 0x%X, 0x%X\n",(u_int) &epcs->slaveselect,(u_int) readl(&epcs->slaveselect));
72 /***********************************************************************
73 * Device access
74 ***********************************************************************/
75 static int epcs_cs (int assert)
77 u_int tmp;
79 if (assert) {
81 #if EPCS_DEBUG3
82 printk(KERN_NOTICE "epcs_cs: Asserting CS\n");
83 #endif
85 writel (NIOS_SPI_SSO, &epcs->control);
86 } else {
88 #if EPCS_DEBUG3
89 printk(KERN_NOTICE "epcs_cs: De-asserting CS\n");
90 #endif
92 /* Let all bits shift out */
93 while ((readl (&epcs->status) & NIOS_SPI_TMT) == 0);
95 tmp = readl (&epcs->control);
96 writel (0,&epcs->control);
99 return 0;
105 static int epcs_tx (unsigned char c)
107 u_int status;
109 status = (u_int)readl(&epcs->status);
111 #if EPCS_DEBUG3
112 printk(KERN_NOTICE "epcs_tx: 0x%X, 0x%X, 0x%X\n",(u_int) &epcs->status,status,NIOS_SPI_TRDY);
113 #endif
115 //start = get_timer (0);
116 while ((status & NIOS_SPI_TRDY) == 0)
118 status = (u_int)readl(&epcs->status);
121 /*if (get_timer (start) > EPCS_TIMEOUT)
122 return (-1);*/
123 writel (c, &epcs->txdata);
124 return (0);
127 static int epcs_rx (void)
129 u_int status;
131 status = (u_int)readl(&epcs->status);
133 #if EPCS_DEBUG3
134 printk(KERN_NOTICE "epcs_rx: 0x%X, 0x%X, 0x%X\n",(u_int) &epcs->status,status,NIOS_SPI_RRDY);
135 #endif
137 while ((status & NIOS_SPI_RRDY) == 0)
139 status = (u_int)readl(&epcs->status);
141 return (readl (&epcs->rxdata));
144 #if 0
145 static unsigned char bitrev[] = {
146 0x00, 0x08, 0x04, 0x0c, 0x02, 0x0a, 0x06, 0x0e,
147 0x01, 0x09, 0x05, 0x0d, 0x03, 0x0b, 0x07, 0x0f
149 #endif
151 #if 0
152 static unsigned char epcs_bitrev (unsigned char c)
154 unsigned char val;
156 val = bitrev[c>>4];
157 val |= bitrev[c & 0x0f]<<4;
158 return (val);
160 #endif
161 static void epcs_rcv (unsigned char *dst, int len)
163 while (len--) {
164 epcs_tx (0);
165 *dst++ = epcs_rx ();
169 #if 0
170 static void epcs_rrcv (unsigned char *dst, int len)
172 while (len--) {
173 epcs_tx (0);
174 *dst++ = epcs_bitrev (epcs_rx ());
177 #endif
179 static void epcs_snd (const unsigned char *src, int len)
181 while (len--) {
182 epcs_tx (*src++);
183 epcs_rx ();
187 #if 0
188 static void epcs_rsnd (unsigned char *src, int len)
190 while (len--) {
191 epcs_tx (epcs_bitrev (*src++));
192 epcs_rx ();
196 #endif
198 static void epcs_wr_enable (void)
200 epcs_cs (1);
201 epcs_tx (EPCS_WRITE_ENA);
202 epcs_rx ();
203 epcs_cs (0);
206 static unsigned char epcs_status_rd (void)
208 unsigned char status;
210 epcs_cs (1);
211 epcs_tx (EPCS_READ_STAT);
212 epcs_rx ();
213 epcs_tx (0);
214 status = epcs_rx ();
215 epcs_cs (0);
216 return (status);
219 #if 0
220 static void epcs_status_wr (unsigned char status)
222 epcs_wr_enable ();
223 epcs_cs (1);
224 epcs_tx (EPCS_WRITE_STAT);
225 epcs_rx ();
226 epcs_tx (status);
227 epcs_rx ();
228 epcs_cs (0);
229 return;
231 #endif
233 /***********************************************************************
234 * Device information
235 ***********************************************************************/
237 int epcs_reset (void)
239 /* When booting from an epcs controller, the epcs bootrom
240 * code may leave the slave select in an asserted state.
241 * This causes two problems: (1) The initial epcs access
242 * will fail -- not a big deal, and (2) a software reset
243 * will cause the bootrom code to hang since it does not
244 * ensure the select is negated prior to first access -- a
245 * big deal. Here we just negate chip select and everything
246 * gets better :-)
249 /* Assign base address */
250 epcs = (nios_spi_t *) ((na_epcs_controller | 0x200) | 0x80000000);
251 /* Clear status and control registers */
253 #if 1
254 writel(0,&epcs->status);
255 writel(0,&epcs->control);
256 writel(1,&epcs->slaveselect);
257 #endif
259 epcs_cs (0); /* Negate chip select */
262 return (0);
265 u_char epcs_dev_find (void)
267 unsigned char buf[4];
268 unsigned char id;
270 #if EPCS_DEBUG2
271 printk(KERN_NOTICE "epcs_dev_find()\n");
272 #endif
274 /* Read silicon id requires 3 "dummy bytes" before it's put
275 * on the wire.
277 buf[0] = EPCS_READ_ID;
278 buf[1] = 0;
279 buf[2] = 0;
280 buf[3] = 0;
282 epcs_cs (1);
284 epcs_snd (buf,4);
285 epcs_rcv (buf,1);
286 if (epcs_cs (0) == -1)
287 return (0);
288 id = buf[0];
291 #if EPCS_DEBUG1
292 printk(KERN_NOTICE "epcs_dev_find: Device ID: 0x%X\n",id);
293 #endif
295 return id;
297 #if 0
299 /* Find the info struct */
300 i = 0;
301 while (devinfo[i].name) {
302 if (id == devinfo[i].id) {
303 dev = &devinfo[i];
304 break;
306 i++;
309 return (dev);
310 #endif
313 /***********************************************************************
314 * Misc Utilities
315 ***********************************************************************/
317 #if 1
318 u_int epcs_buf_erase (u_int off, u_int len, u_int sz)
320 u_char buf[4];
322 /* Erase the requested sectors. An address is required
323 * that lies within the requested sector -- we'll just
324 * use the first address in the sector.
327 #if EPCS_DEBUG2
328 /* Check if address is a sector */
329 printk(KERN_NOTICE "epcs_erase(): off: 0x%X, len: 0x%X, sz: 0x%X\n",off,len,sz);
330 #endif
332 if ((off % sz) || (len % sz))
334 printk(KERN_NOTICE "epcs_erase: Address is not sector-aligned, halting!\n");
335 while(1);
338 while (len) {
341 #if EPCS_DEBUG3
342 printk(KERN_NOTICE "epcs_erase: Erasing 0x%X\n",off);
343 #endif
345 buf[0] = EPCS_ERASE_SECT;
346 buf[1] = off >> 16;
347 buf[2] = off >> 8;
348 buf[3] = off;
350 epcs_wr_enable ();
351 epcs_cs (1);
352 epcs_snd (buf,4);
353 epcs_cs (0);
355 /* Wait for erase to complete */
356 while (epcs_status_rd() & EPCS_STATUS_WIP);
358 len -= sz;
359 off += sz;
361 return (0);
363 #endif
365 #if 1
366 int epcs_buf_read (u_char *dst, u_int off, u_int cnt)
368 u_char buf[4];
371 buf[0] = EPCS_READ_BYTES;
372 buf[1] = off >> 16;
373 buf[2] = off >> 8;
374 buf[3] = off;
376 epcs_cs (1);
377 epcs_snd (buf,4);
378 //epcs_rrcv ((u_char *)addr, cnt);
379 epcs_rcv (dst, cnt);
380 epcs_cs (0);
382 return (0);
385 #endif
387 #if 1
388 int epcs_buf_write (const u_char *addr, u_int off, u_int cnt)
390 u_int wrcnt;
391 u_int pgsz;
392 u_char buf[4];
394 pgsz = EPCS_PAGESIZE;
396 #if EPCS_DEBUG2
397 printk(KERN_NOTICE "epcs_buf_write(): 0x%X, 0x%X\n",cnt,off);
398 #endif
400 while (cnt) {
401 if (off % pgsz)
402 wrcnt = pgsz - (off % pgsz);
403 else
404 wrcnt = pgsz;
405 wrcnt = (wrcnt > cnt) ? cnt : wrcnt;
407 buf[0] = EPCS_WRITE_BYTES;
408 buf[1] = off >> 16;
409 buf[2] = off >> 8;
410 buf[3] = off;
412 #if EPCS_DEBUG3
413 printk(KERN_NOTICE "epcs_buf_write: wrcnt: 0x%X, offset: 0x%X\n",wrcnt,off);
414 #endif
416 epcs_wr_enable ();
417 epcs_cs (1);
418 epcs_snd (buf,4);
419 //epcs_rsnd ((unsigned char *)addr, wrcnt);
420 epcs_snd (addr, wrcnt);
421 epcs_cs (0);
423 /* Wait for write to complete */
424 while (epcs_status_rd() & EPCS_STATUS_WIP);
426 cnt -= wrcnt;
427 off += wrcnt;
428 addr += wrcnt;
431 return (0);
434 #endif
436 #if 0
437 int epcs_verify (ulong addr, ulong off, ulong cnt, ulong *err)
439 ulong rdcnt;
440 unsigned char buf[256];
441 unsigned char *start,*end;
442 int i;
444 start = end = (unsigned char *)addr;
445 while (cnt) {
446 rdcnt = (cnt>sizeof(buf)) ? sizeof(buf) : cnt;
447 epcs_read ((ulong)buf, off, rdcnt);
448 for (i=0; i<rdcnt; i++) {
449 if (*end != buf[i]) {
450 *err = end - start;
451 return(-1);
453 end++;
455 cnt -= rdcnt;
456 off += rdcnt;
458 return (0);
461 static int epcs_sect_erased (int sect, unsigned *offset,
462 struct epcs_devinfo_t *dev)
464 unsigned char buf[128];
465 unsigned off, end;
466 unsigned sectsz;
467 int i;
469 sectsz = (1 << dev->sz_sect);
470 off = sectsz * sect;
471 end = off + sectsz;
473 while (off < end) {
474 epcs_read ((ulong)buf, off, sizeof(buf));
475 for (i=0; i < sizeof(buf); i++) {
476 if (buf[i] != 0xff) {
477 *offset = off + i;
478 return (0);
481 off += sizeof(buf);
483 return (1);
486 #endif