burner.c

00001 /* burner.c -- Burn the internal EEPROM
00002    Copyright 2000, 2001, 2002 Free Software Foundation, Inc.
00003    Written by Stephane Carrez (stcarrez@nerim.fr)
00004 
00005 This file is part of GEL.
00006 
00007 GEL is free software; you can redistribute it and/or modify
00008 it under the terms of the GNU General Public License as published by
00009 the Free Software Foundation; either version 2, or (at your option)
00010 any later version.
00011 
00012 GEL is distributed in the hope that it will be useful,
00013 but WITHOUT ANY WARRANTY; without even the implied warranty of
00014 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015 GNU General Public License for more details.
00016 
00017 You should have received a copy of the GNU General Public License
00018 along with GEL; see the file COPYING.  If not, write to
00019 the Free Software Foundation, 59 Temple Place - Suite 330,
00020 Boston, MA 02111-1307, USA.  */
00021 
00074 #include <sys/ports.h>
00075 
00076 typedef void __attribute__ ((noreturn)) (* func)();
00077 
00078 static unsigned short get_char (void);
00079 static unsigned char* get_addr (void);
00080 static volatile int __attribute__((noreturn)) main ();
00081 static void flush (void);
00082 void eeprom_write_byte (unsigned char *p, const unsigned char value);
00083 void udelay_10ms (void);
00084 
00085 void
00086 _start()
00087 {
00088   __asm__ __volatile__ ("bra main");
00089   /* main (); */
00090 }
00091 
00092 static void
00093 flush ()
00094 {
00095   while (!(_io_ports[M6811_SCSR] & M6811_TDRE))
00096     continue;
00097 }
00098 
00099 static void
00100 put_char (unsigned char c)
00101 {
00102   flush ();
00103   _io_ports[M6811_SCDR] = c;
00104   _io_ports[M6811_SCCR2] |= M6811_TE;
00105 }
00106 
00107 static volatile int
00108 main ()
00109 {
00110   unsigned char* addr;
00111   unsigned char c;
00112   
00113   while (1)
00114     {
00115       /* Print banner for synchronization.  */
00116       put_char ('\n');
00117       put_char ('>');
00118 
00119       /* Wait for command.  */
00120       c = get_char ();
00121 
00122       /* Write memory command.  Command format is:
00123 
00124          M<ADDR-HIGH><ADDR-LOW><SIZE>[<DATA>]
00125 
00126          Address, size and data are passed in binary form.
00127          A size of 0 corresponds to 256 bytes.
00128 
00129          Since burning a byte can take some time, we must synchronize
00130          with the host.  To do this, we echo the byte that was programmed
00131          and the host waits for it before sending the next one.  If the
00132          host does not wait, we can loose some bytes.  */
00133       if (c == 'M')
00134         {
00135           unsigned char size;
00136           
00137           addr = get_addr ();
00138           size = get_char ();
00139           do
00140             {
00141               *addr = get_char ();
00142               eeprom_write_byte (addr, get_char ());
00143               put_char (*addr);
00144             }
00145           while (--size != 0);
00146         }
00147 
00148       /* Go command.  Command format is:
00149 
00150          G<ADDR-HIGH><ADDR-LOW>
00151 
00152          We reply with a G.  Depending on the program, the final \n
00153          may not be received since we don't wait for it to be sent.  */
00154       else if (c == 'G')
00155         {
00156           func handler;
00157             
00158           addr = get_addr ();
00159           put_char ('G');
00160           put_char ('\n');
00161           flush ();
00162 
00163           handler = (func) addr;
00164           handler ();
00165         }
00166 
00167       /* For others, emit something to tell we are alive.  */
00168       else
00169         {
00170           put_char ('?');
00171         }
00172     }
00173 }
00174 
00175 void
00176 udelay_10ms ()
00177 {
00178   unsigned short tmp = 40000;
00179 
00180   __asm__ __volatile__ ("1: subd #1\n"
00181                         "       bne 1b" : "=d"(tmp) : "d"(tmp));
00182 }
00183 
00193 void 
00194 eeprom_write_byte (unsigned char *p, const unsigned char value)
00195 {
00196   unsigned char diff;
00197 
00198   diff = *p ^ value;
00199   if (diff)
00200     {
00201       if (diff & value)
00202         {
00203           /* Clear eeprom byte.  */
00204           diff = *p ^ value;
00205           if (diff == 0)
00206             return;
00207           
00208           _io_ports[M6811_PPROG] = M6811_EELAT | M6811_ERASE | M6811_BYTE;
00209           *p = value;
00210           _io_ports[M6811_PPROG] = M6811_EELAT | M6811_ERASE
00211             | M6811_BYTE | M6811_EEPGM;
00212 
00213           /* Wait 10 ms.  */
00214           udelay_10ms ();
00215           _io_ports[M6811_PPROG] = M6811_EELAT | M6811_ERASE | M6811_BYTE;
00216         }
00217       
00218       /* Write eeprom byte.  */
00219       _io_ports[M6811_PPROG] = M6811_EELAT;
00220       *p = value;
00221       _io_ports[M6811_PPROG] = M6811_EELAT | M6811_EEPGM;
00222 
00223       /* Wait 10 ms.  */
00224       udelay_10ms ();
00225       _io_ports[M6811_PPROG] = M6811_EELAT;
00226       _io_ports[M6811_PPROG] = 0;
00227     }
00228 }
00229 
00230 static unsigned char*
00231 get_addr ()
00232 {
00233   unsigned short c1, c2;
00234 
00235   c1 = get_char ();
00236   c2 = get_char ();
00237   return (unsigned char*) (((unsigned short) c1 << 8) | ((unsigned short) c2));
00238 }
00239 
00240 static unsigned short
00241 get_char ()
00242 {
00243   unsigned char c;
00244   volatile unsigned char* ports = &_io_ports[0];
00245   
00246   while (1)
00247     {
00248       c = ports[M6811_SCSR];
00249 
00250       if (c & M6811_RDRF)
00251         break;
00252     }
00253   return ports[M6811_SCDR];
00254 }