]> git.kernelconcepts.de Git - karo-tx-uboot.git/blob - cpu/s3c44b0/cpu.c
Patch by Klaus Heydeck, 12 May 2004:
[karo-tx-uboot.git] / cpu / s3c44b0 / cpu.c
1 /*
2  * (C) Copyright 2004
3  * DAVE Srl
4  * http://www.dave-tech.it
5  * http://www.wawnet.biz
6  * mailto:info@wawnet.biz
7  *
8  * See file CREDITS for list of people who contributed to this
9  * project.
10  *
11  * This program is free software; you can redistribute it and/or
12  * modify it under the terms of the GNU General Public License as
13  * published by the Free Software Foundation; either version 2 of
14  * the License, or (at your option) any later version.
15  *
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  * GNU General Public License for more details.
20  *
21  * You should have received a copy of the GNU General Public License
22  * along with this program; if not, write to the Free Software
23  * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
24  * MA 02111-1307 USA
25  */
26
27 /*
28  * S3C44B0 CPU specific code
29  */
30
31 #include <common.h>
32 #include <command.h>
33 #include <asm/hardware.h>
34
35 static void s3c44b0_flush_cache(void)
36 {
37         volatile int i;
38         /* flush cycle */
39         for(i=0x10002000;i<0x10004800;i+=16)
40         {
41                 *((int *)i)=0x0;
42         }
43 }
44
45
46 int cpu_init (void)
47 {
48         icache_enable();
49
50         return 0;
51 }
52
53 int cleanup_before_linux (void)
54 {
55         /*
56                 cache memory should be enabled before calling
57                 Linux to make the kernel uncompression faster
58         */
59         icache_enable();
60
61         disable_interrupts ();
62
63         return 0;
64 }
65
66 void reset_cpu (ulong addr)
67 {
68         /*
69                 reset the cpu using watchdog
70         */
71
72         /* Disable the watchdog.*/
73         WTCON&=~(1<<5);
74
75         /* set the timeout value to a short time... */
76         WTCNT = 0x1;
77
78         /* Enable the watchdog. */
79         WTCON|=1;
80         WTCON|=(1<<5);
81
82         while(1) {
83                 /*NOP*/
84         }
85 }
86
87 int do_reset (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
88 {
89         extern void reset_cpu (ulong addr);
90
91         disable_interrupts ();
92         reset_cpu (0);
93
94         /*NOTREACHED*/
95         return (0);
96 }
97
98 void icache_enable (void)
99 {
100         ulong reg;
101
102         s3c44b0_flush_cache();
103
104         /*
105                 Init cache
106                 Non-cacheable area (everything outside RAM)
107                 0x0000:0000 - 0x0C00:0000
108          */
109         NCACHBE0 = 0xC0000000;
110         NCACHBE1 = 0x00000000;
111
112         /*
113                 Enable chache
114         */
115         reg = SYSCFG;
116         reg |= 0x00000006; /* 8kB */
117         SYSCFG = reg;
118 }
119
120 void icache_disable (void)
121 {
122         ulong reg;
123
124         reg = SYSCFG;
125         reg &= ~0x00000006; /* 8kB */
126         SYSCFG = reg;
127 }
128
129 int icache_status (void)
130 {
131         return 0;
132 }
133
134 void dcache_enable (void)
135 {
136         icache_enable();
137 }
138
139 void dcache_disable (void)
140 {
141         icache_disable();
142 }
143
144 int dcache_status (void)
145 {
146         return dcache_status();
147 }
148
149 /*
150         RTC stuff
151 */
152 #include <rtc.h>
153 #ifndef BCD2HEX
154         #define BCD2HEX(n)  ((n>>4)*10+(n&0x0f))
155 #endif
156 #ifndef HEX2BCD
157         #define HEX2BCD(x) ((((x) / 10) << 4) + (x) % 10)
158 #endif
159
160 void rtc_get (struct rtc_time* tm)
161 {
162         RTCCON |= 1;
163         tm->tm_year  = BCD2HEX(BCDYEAR);
164         tm->tm_mon   = BCD2HEX(BCDMON);
165         tm->tm_wday   = BCD2HEX(BCDDATE);
166         tm->tm_mday   = BCD2HEX(BCDDAY);
167         tm->tm_hour  = BCD2HEX(BCDHOUR);
168         tm->tm_min  = BCD2HEX(BCDMIN);
169         tm->tm_sec  = BCD2HEX(BCDSEC);
170
171         if (tm->tm_sec==0) {
172                 /* we have to re-read the rtc data because of the "one second deviation" problem */
173                 /* see RTC datasheet for more info about it */
174                 tm->tm_year  = BCD2HEX(BCDYEAR);
175                 tm->tm_mon   = BCD2HEX(BCDMON);
176                 tm->tm_mday   = BCD2HEX(BCDDAY);
177                 tm->tm_wday   = BCD2HEX(BCDDATE);
178                 tm->tm_hour  = BCD2HEX(BCDHOUR);
179                 tm->tm_min  = BCD2HEX(BCDMIN);
180                 tm->tm_sec  = BCD2HEX(BCDSEC);
181         }
182
183         RTCCON &= ~1;
184
185         if(tm->tm_year >= 70)
186                 tm->tm_year += 1900;
187         else
188                 tm->tm_year += 2000;
189 }
190
191 void rtc_set (struct rtc_time* tm)
192 {
193         if(tm->tm_year < 2000)
194                 tm->tm_year -= 1900;
195         else
196                 tm->tm_year -= 2000;
197
198         RTCCON |= 1;
199         BCDYEAR = HEX2BCD(tm->tm_year);
200         BCDMON = HEX2BCD(tm->tm_mon);
201         BCDDAY = HEX2BCD(tm->tm_mday);
202         BCDDATE = HEX2BCD(tm->tm_wday);
203         BCDHOUR = HEX2BCD(tm->tm_hour);
204         BCDMIN = HEX2BCD(tm->tm_min);
205         BCDSEC = HEX2BCD(tm->tm_sec);
206         RTCCON &= 1;
207 }
208
209 void rtc_reset (void)
210 {
211         RTCCON |= 1;
212         BCDYEAR = 0;
213         BCDMON = 0;
214         BCDDAY = 0;
215         BCDDATE = 0;
216         BCDHOUR = 0;
217         BCDMIN = 0;
218         BCDSEC = 0;
219         RTCCON &= 1;
220 }
221
222
223 /*
224         I2C stuff
225 */
226
227 /*
228  * Initialization, must be called once on start up, may be called
229  * repeatedly to change the speed and slave addresses.
230  */
231 void i2c_init(int speed, int slaveaddr)
232 {
233         /*
234                 setting up I2C support
235         */
236         unsigned int save_F,save_PF,rIICCON,rPCONA,rPDATA,rPCONF,rPUPF;
237
238         save_F = PCONF;
239         save_PF = PUPF;
240
241         rPCONF = ((save_F & ~(0xF))| 0xa);
242         rPUPF = (save_PF | 0x3);
243         PCONF = rPCONF; /*PF0:IICSCL, PF1:IICSDA*/
244         PUPF = rPUPF; /* Disable pull-up */
245
246         /* Configuring pin for WC pin of EEprom */
247         rPCONA = PCONA;
248         rPCONA &= ~(1<<9);
249         PCONA = rPCONA;
250
251         rPDATA = PDATA;
252         rPDATA &= ~(1<<9);
253         PDATA = rPDATA;
254
255         /*
256                 Enable ACK, IICCLK=MCLK/16, enable interrupt
257                 75Mhz/16/(12+1) = 390625 Hz
258         */
259         rIICCON=(1<<7)|(0<<6)|(1<<5)|(0xC);
260         IICCON = rIICCON;
261
262         IICADD = slaveaddr;
263 }
264
265 /*
266  * Probe the given I2C chip address.  Returns 0 if a chip responded,
267  * not 0 on failure.
268  */
269 int i2c_probe(uchar chip)
270 {
271         /*
272                 not implemented
273         */
274
275         printf(__FUNCTION__ " chip %d\n", (int) chip);
276         return -1;
277 }
278
279 /*
280  * Read/Write interface:
281  *   chip:    I2C chip address, range 0..127
282  *   addr:    Memory (register) address within the chip
283  *   alen:    Number of bytes to use for addr (typically 1, 2 for larger
284  *              memories, 0 for register type devices with only one
285  *              register)
286  *   buffer:  Where to read/write the data
287  *   len:     How many bytes to read/write
288  *
289  *   Returns: 0 on success, not 0 on failure
290  */
291
292 #define S3C44B0X_rIIC_INTPEND               (1<<4)
293 #define S3C44B0X_rIIC_LAST_RECEIV_BIT       (1<<0)
294 #define S3C44B0X_rIIC_INTERRUPT_ENABLE      (1<<5)
295 #define S3C44B0_IIC_TIMEOUT 100
296
297 int i2c_read(uchar chip, uint addr, int alen, uchar *buffer, int len)
298 {
299
300         int k, j, temp;
301         u32 rIICSTAT;
302
303         /*
304                 send the device offset
305         */
306
307         rIICSTAT = 0xD0;
308         IICSTAT = rIICSTAT;
309
310         IICDS = chip;   /* this is a write operation... */
311
312         rIICSTAT |= (1<<5);
313         IICSTAT = rIICSTAT;
314
315         for(k=0; k<S3C44B0_IIC_TIMEOUT; k++) {
316                 temp = IICCON;
317                 if( (temp & S3C44B0X_rIIC_INTPEND) == S3C44B0X_rIIC_INTPEND)
318                 break;
319                 udelay(2000);
320         }
321         if (k==S3C44B0_IIC_TIMEOUT)
322                 return -1;
323
324         /* wait and check ACK */
325         temp = IICSTAT;
326         if ((temp & S3C44B0X_rIIC_LAST_RECEIV_BIT) == S3C44B0X_rIIC_LAST_RECEIV_BIT )
327                 return -1;
328
329         IICDS = addr;
330         IICCON = IICCON & ~(S3C44B0X_rIIC_INTPEND);
331
332         /* wait and check ACK */
333         for(k=0; k<S3C44B0_IIC_TIMEOUT; k++) {
334                 temp = IICCON;
335                 if( (temp & S3C44B0X_rIIC_INTPEND) == S3C44B0X_rIIC_INTPEND)
336                 break;
337                 udelay(2000);
338         }
339         if (k==S3C44B0_IIC_TIMEOUT)
340                 return -1;
341
342         temp = IICSTAT;
343         if ((temp & S3C44B0X_rIIC_LAST_RECEIV_BIT) == S3C44B0X_rIIC_LAST_RECEIV_BIT )
344                 return -1;
345
346         /*
347                 now we can start with the read operation...
348         */
349
350         IICDS = chip | 0x01;    /* this is a read operation... */
351
352         rIICSTAT = 0x90; /*master recv*/
353         rIICSTAT |= (1<<5);
354         IICSTAT = rIICSTAT;
355
356         IICCON = IICCON & ~(S3C44B0X_rIIC_INTPEND);
357
358         /* wait and check ACK */
359         for(k=0; k<S3C44B0_IIC_TIMEOUT; k++) {
360                 temp = IICCON;
361                 if( (temp & S3C44B0X_rIIC_INTPEND) == S3C44B0X_rIIC_INTPEND)
362                 break;
363                 udelay(2000);
364         }
365         if (k==S3C44B0_IIC_TIMEOUT)
366                 return -1;
367
368         temp = IICSTAT;
369         if ((temp & S3C44B0X_rIIC_LAST_RECEIV_BIT) == S3C44B0X_rIIC_LAST_RECEIV_BIT )
370                 return -1;
371
372         for (j=0; j<len-1; j++) {
373
374         /*clear pending bit to resume */
375
376         temp = IICCON & ~(S3C44B0X_rIIC_INTPEND);
377         IICCON = temp;
378
379         /* wait and check ACK */
380         for(k=0; k<S3C44B0_IIC_TIMEOUT; k++) {
381                 temp = IICCON;
382                 if( (temp & S3C44B0X_rIIC_INTPEND) == S3C44B0X_rIIC_INTPEND)
383                 break;
384                 udelay(2000);
385         }
386         if (k==S3C44B0_IIC_TIMEOUT)
387                 return -1;
388
389
390                 buffer[j] = IICDS; /*save readed data*/
391
392     } /*end for(j)*/
393
394         /*
395                 reading the last data
396                 unset ACK generation
397         */
398         temp = IICCON & ~(S3C44B0X_rIIC_INTPEND | (1<<7));
399         IICCON = temp;
400
401         /* wait but NOT check ACK */
402         for(k=0; k<S3C44B0_IIC_TIMEOUT; k++) {
403                 temp = IICCON;
404                 if( (temp & S3C44B0X_rIIC_INTPEND) == S3C44B0X_rIIC_INTPEND)
405                 break;
406                 udelay(2000);
407         }
408         if (k==S3C44B0_IIC_TIMEOUT)
409                 return -1;
410
411         buffer[j] = IICDS; /*save readed data*/
412
413         rIICSTAT = 0x90; /*master recv*/
414
415         /* Write operation Terminate sending STOP */
416         IICSTAT = rIICSTAT;
417         /*Clear Int Pending Bit to RESUME*/
418         temp = IICCON;
419         IICCON = temp & (~S3C44B0X_rIIC_INTPEND);
420
421         IICCON = IICCON | (1<<7);       /*restore ACK generation*/
422
423         return 0;
424 }
425
426 int i2c_write(uchar chip, uint addr, int alen, uchar *buffer, int len)
427 {
428         int j, k;
429         u32 rIICSTAT, temp;
430
431
432         /*
433                 send the device offset
434         */
435
436         rIICSTAT = 0xD0;
437         IICSTAT = rIICSTAT;
438
439         IICDS = chip;   /* this is a write operation... */
440
441         rIICSTAT |= (1<<5);
442         IICSTAT = rIICSTAT;
443
444         IICCON = IICCON & ~(S3C44B0X_rIIC_INTPEND);
445
446         /* wait and check ACK */
447         for(k=0; k<S3C44B0_IIC_TIMEOUT; k++) {
448                 temp = IICCON;
449                 if( (temp & S3C44B0X_rIIC_INTPEND) == S3C44B0X_rIIC_INTPEND)
450                 break;
451                 udelay(2000);
452         }
453         if (k==S3C44B0_IIC_TIMEOUT)
454                 return -1;
455
456         temp = IICSTAT;
457         if ((temp & S3C44B0X_rIIC_LAST_RECEIV_BIT) == S3C44B0X_rIIC_LAST_RECEIV_BIT )
458                 return -1;
459
460         IICDS = addr;
461         IICCON = IICCON & ~(S3C44B0X_rIIC_INTPEND);
462
463         /* wait and check ACK */
464         for(k=0; k<S3C44B0_IIC_TIMEOUT; k++) {
465                 temp = IICCON;
466                 if( (temp & S3C44B0X_rIIC_INTPEND) == S3C44B0X_rIIC_INTPEND)
467                 break;
468                 udelay(2000);
469         }
470         if (k==S3C44B0_IIC_TIMEOUT)
471           return -1;
472
473         temp = IICSTAT;
474         if ((temp & S3C44B0X_rIIC_LAST_RECEIV_BIT) == S3C44B0X_rIIC_LAST_RECEIV_BIT )
475                 return -1;
476
477         /*
478                 now we can start with the read write operation
479         */
480         for (j=0; j<len; j++) {
481
482                 IICDS = buffer[j]; /*prerare data to write*/
483
484                 /*clear pending bit to resume*/
485
486                 temp = IICCON & ~(S3C44B0X_rIIC_INTPEND);
487                 IICCON = temp;
488
489                 /* wait but NOT check ACK */
490                 for(k=0; k<S3C44B0_IIC_TIMEOUT; k++) {
491                         temp = IICCON;
492                         if( (temp & S3C44B0X_rIIC_INTPEND) == S3C44B0X_rIIC_INTPEND)
493                         break;
494
495                         udelay(2000);
496                 }
497
498                 if (k==S3C44B0_IIC_TIMEOUT)
499                         return -1;
500
501         } /* end for(j) */
502
503         /* sending stop to terminate */
504         rIICSTAT = 0xD0;  /*master send*/
505         IICSTAT = rIICSTAT;
506         /*Clear Int Pending Bit to RESUME*/
507         temp = IICCON;
508         IICCON = temp & (~S3C44B0X_rIIC_INTPEND);
509
510         return 0;
511 }