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 }