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 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 void _start (void);
00085 
00086 void
00087 _start()
00088 {
00089   __asm__ __volatile__ ("bra main");
00090   /* main (); */
00091 }
00092 
00093 static void
00094 flush ()
00095 {
00096   while (!(_io_ports[M6811_SCSR] & M6811_TDRE))
00097     continue;
00098 }
00099 
00100 static void
00101 put_char (unsigned char c)
00102 {
00103   flush ();
00104   _io_ports[M6811_SCDR] = c;
00105   _io_ports[M6811_SCCR2] |= M6811_TE;
00106 }
00107 
00108 volatile int
00109 main ()
00110 {
00111   unsigned char* addr;
00112   unsigned char c;
00113   
00114   while (1)
00115     {
00116       /* Print banner for synchronization.  */
00117       put_char ('\n');
00118       put_char ('>');
00119 
00120       /* Wait for command.  */
00121       c = get_char ();
00122 
00123       /* Write memory command.  Command format is:
00124 
00125          M<ADDR-HIGH><ADDR-LOW><SIZE>[<DATA>]
00126 
00127          Address, size and data are passed in binary form.
00128          A size of 0 corresponds to 256 bytes.
00129 
00130          Since burning a byte can take some time, we must synchronize
00131          with the host.  To do this, we echo the byte that was programmed
00132          and the host waits for it before sending the next one.  If the
00133          host does not wait, we can loose some bytes.  */
00134       if (c == 'M')
00135         {
00136           unsigned char size;
00137           
00138           addr = get_addr ();
00139           size = get_char ();
00140           do
00141             {
00142               *addr = get_char ();
00143               eeprom_write_byte (addr, get_char ());
00144               put_char (*addr);
00145             }
00146           while (--size != 0);
00147         }
00148 
00149       /* Go command.  Command format is:
00150 
00151          G<ADDR-HIGH><ADDR-LOW>
00152 
00153          We reply with a G.  Depending on the program, the final \n
00154          may not be received since we don't wait for it to be sent.  */
00155       else if (c == 'G')
00156         {
00157           func handler;
00158             
00159           addr = get_addr ();
00160           put_char ('G');
00161           put_char ('\n');
00162           flush ();
00163 
00164           handler = (func) addr;
00165           handler ();
00166         }
00167 
00168       /* For others, emit something to tell we are alive.  */
00169       else
00170         {
00171           put_char ('?');
00172         }
00173     }
00174 }
00175 
00176 void
00177 udelay_10ms ()
00178 {
00179   unsigned short tmp = 40000;
00180 
00181   __asm__ __volatile__ ("1: subd #1\n"
00182                         "       bne 1b" : "=d"(tmp) : "d"(tmp));
00183 }
00184 
00194 void 
00195 eeprom_write_byte (unsigned char *p, const unsigned char value)
00196 {
00197   unsigned char diff;
00198 
00199   diff = *p ^ value;
00200   if (diff)
00201     {
00202       if (diff & value)
00203         {
00204           /* Clear eeprom byte.  */
00205           diff = *p ^ value;
00206           if (diff == 0)
00207             return;
00208           
00209           _io_ports[M6811_PPROG] = M6811_EELAT | M6811_ERASE | M6811_BYTE;
00210           *p = value;
00211           _io_ports[M6811_PPROG] = M6811_EELAT | M6811_ERASE
00212             | M6811_BYTE | M6811_EEPGM;
00213 
00214           /* Wait 10 ms.  */
00215           udelay_10ms ();
00216           _io_ports[M6811_PPROG] = M6811_EELAT | M6811_ERASE | M6811_BYTE;
00217         }
00218       
00219       /* Write eeprom byte.  */
00220       _io_ports[M6811_PPROG] = M6811_EELAT;
00221       *p = value;
00222       _io_ports[M6811_PPROG] = M6811_EELAT | M6811_EEPGM;
00223 
00224       /* Wait 10 ms.  */
00225       udelay_10ms ();
00226       _io_ports[M6811_PPROG] = M6811_EELAT;
00227       _io_ports[M6811_PPROG] = 0;
00228     }
00229 }
00230 
00231 static unsigned char*
00232 get_addr ()
00233 {
00234   unsigned short c1, c2;
00235 
00236   c1 = get_char ();
00237   c2 = get_char ();
00238   return (unsigned char*) (((unsigned short) c1 << 8) | ((unsigned short) c2));
00239 }
00240 
00241 static unsigned short
00242 get_char ()
00243 {
00244   unsigned char c;
00245   volatile unsigned char* ports = &_io_ports[0];
00246   
00247   while (1)
00248     {
00249       c = ports[M6811_SCSR];
00250 
00251       if (c & M6811_RDRF)
00252         break;
00253     }
00254   return ports[M6811_SCDR];
00255 }