1/*  *********************************************************************
2    *  Broadcom Common Firmware Environment (CFE)
3    *
4    *  DS1743W RTC  driver		File: dev_ds1743wclock.c
5    *
6    *  This module contains a CFE driver for a DS1743W generic bus
7    *  real-time-clock.
8    *
9    *  Author:  Mitch Lichtenberg
10    *
11    *********************************************************************
12    *
13    *  Copyright 2000,2001,2002,2003
14    *  Broadcom Corporation. All rights reserved.
15    *
16    *  This software is furnished under license and may be used and
17    *  copied only in accordance with the following terms and
18    *  conditions.  Subject to these conditions, you may download,
19    *  copy, install, use, modify and distribute modified or unmodified
20    *  copies of this software in source and/or binary form.  No title
21    *  or ownership is transferred hereby.
22    *
23    *  1) Any source code used, modified or distributed must reproduce
24    *     and retain this copyright notice and list of conditions
25    *     as they appear in the source file.
26    *
27    *  2) No right is granted to use any trade name, trademark, or
28    *     logo of Broadcom Corporation.  The "Broadcom Corporation"
29    *     name may not be used to endorse or promote products derived
30    *     from this software without the prior written permission of
31    *     Broadcom Corporation.
32    *
33    *  3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR
34    *     IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED
35    *     WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
36    *     PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT
37    *     SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN
38    *     PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT,
39    *     INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
40    *     (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
41    *     GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
42    *     BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
43    *     OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
44    *     TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF
45    *     THE POSSIBILITY OF SUCH DAMAGE.
46    ********************************************************************* */
47
48#include "cfe.h"
49#include "lib_physio.h"
50
51
52/*  *********************************************************************
53    *  Constants
54    ********************************************************************* */
55
56#define M_DS1743_BF	0x80
57#define M_DS1743_FT	0x40
58#define M_DS1743_OSC	0x80
59#define M_DS1743_W	0x80
60#define M_DS1743_R	0x40
61
62#define M_DS1743_MONTH	0x1F
63#define M_DS1743_DATE	0x3F
64#define M_DS1743_DAY	0x03
65#define M_DS1743_MINUTE 0x7F
66#define M_DS1743_SECOND	0x7F
67#define M_DS1743_CENTURY 0x3F
68
69
70#define DS1743_NVRAM_SIZE 0x1FF8
71
72#define DS1743_CONTROL	0x1FF8
73#define DS1743_CENTURY	0x1FF8
74#define DS1743_SECOND	0x1FF9
75#define DS1743_MINUTE	0x1FFA
76#define DS1743_HOUR	0x1FFB
77#define DS1743_DAY	0x1FFC
78#define DS1743_DATE	0x1FFD
79#define DS1743_MONTH	0x1FFE
80#define DS1743_YEAR	0x1FFF
81
82#define BCD(x) (((x) % 10) + (((x) / 10) << 4))
83#define SET_TIME	0x00
84#define SET_DATE	0x01
85
86#if ENDIAN_BIG
87#define WRITECSR(p,v) phys_write8((p)^3,(v))
88#define READCSR(p) phys_read8((p)^3)
89#elif ENDIAN_LITTLE
90#define WRITECSR(p,v) phys_write8((p),(v))
91#define READCSR(p) phys_read8((p))
92#else
93#error "dev_ds1743: system endian not set"
94#endif
95
96/*  *********************************************************************
97    *  Forward declarations
98    ********************************************************************* */
99
100static void ds1743_clock_probe(cfe_driver_t *drv,
101			      unsigned long probe_a, unsigned long probe_b,
102			      void *probe_ptr);
103
104static int ds1743_clock_open(cfe_devctx_t *ctx);
105static int ds1743_clock_read(cfe_devctx_t *ctx,iocb_buffer_t *buffer);
106static int ds1743_clock_inpstat(cfe_devctx_t *ctx,iocb_inpstat_t *inpstat);
107static int ds1743_clock_write(cfe_devctx_t *ctx,iocb_buffer_t *buffer);
108static int ds1743_clock_ioctl(cfe_devctx_t *ctx,iocb_buffer_t *buffer);
109static int ds1743_clock_close(cfe_devctx_t *ctx);
110
111
112/*  *********************************************************************
113    *  Device dispatch
114    ********************************************************************* */
115
116const static cfe_devdisp_t ds1743_clock_dispatch = {
117  ds1743_clock_open,
118  ds1743_clock_read,
119  ds1743_clock_inpstat,
120  ds1743_clock_write,
121  ds1743_clock_ioctl,
122  ds1743_clock_close,
123  NULL,
124  NULL
125};
126
127const cfe_driver_t ds1743_clock = {
128  "Dallas DS1743 RTC",
129  "clock",
130  CFE_DEV_CLOCK,
131  &ds1743_clock_dispatch,
132  ds1743_clock_probe
133};
134
135
136/*  *********************************************************************
137    *  Structures
138    ********************************************************************* */
139typedef struct ds1743_clock_s {
140    physaddr_t clock_base;
141} ds1743_clock_t;
142
143/*  *********************************************************************
144    *  ds1743_clock_probe(drv,a,b,ptr)
145    *
146    *  Probe routine for this driver.  This routine creates the
147    *  local device context and attaches it to the driver list
148    *  within CFE.
149    *
150    *  Input parameters:
151    *  	   drv - driver handle
152    *  	   a,b - probe hints (longs)
153    *  	   ptr - probe hint (pointer)
154    *
155    *  Return value:
156    *  	   nothing
157    ********************************************************************* */
158
159static void ds1743_clock_probe(cfe_driver_t *drv,
160				     unsigned long probe_a, unsigned long probe_b,
161				     void *probe_ptr)
162{
163    ds1743_clock_t *softc;
164    char descr[80];
165
166    softc = (ds1743_clock_t *) KMALLOC(sizeof(ds1743_clock_t),0);
167
168    /*
169     * Probe_a is the clock base address
170     * Probe_b is unused.
171     * Probe_ptr is unused.
172     */
173
174    softc->clock_base = probe_a;
175
176    xsprintf(descr,"%s at 0x%X",
177	     drv->drv_description,(uint32_t)probe_a);
178    cfe_attach(drv,softc,NULL,descr);
179
180}
181
182/*  *********************************************************************
183    *  ds1743_clock_open(ctx)
184    *
185    *  Open this device.  For the DS1743, we do a quick test
186    *  read to be sure the device is out there.
187    *
188    *  Input parameters:
189    *  	   ctx - device context (can obtain our softc here)
190    *
191    *  Return value:
192    *  	   0 if ok
193    *  	   else error code
194    ********************************************************************* */
195
196static int ds1743_clock_open(cfe_devctx_t *ctx)
197{
198    ds1743_clock_t *softc = ctx->dev_softc;
199    physaddr_t clockbase;
200
201    clockbase =  softc->clock_base;
202
203    /* Make sure battery is still good and RTC valid */
204    if (!(READCSR(clockbase+DS1743_DAY) & M_DS1743_BF)) {
205	printf("Warning: Battery has failed.  Clock setting is not accurate.\n");
206	}
207
208
209    return 0;
210}
211
212/*  *********************************************************************
213    *  ds1743_clock_read(ctx,buffer)
214    *
215    *  Read time/date from the RTC. Read a total of 8 bytes in this format:
216    *  hour-minute-second-month-day-year1-year2
217    *
218    *  Input parameters:
219    *  	   ctx - device context (can obtain our softc here)
220    *  	   buffer - buffer descriptor (target buffer, length, offset)
221    *
222    *  Return value:
223    *  	   number of bytes read
224    *  	   -1 if an error occured
225    ********************************************************************* */
226
227static int ds1743_clock_read(cfe_devctx_t *ctx,iocb_buffer_t *buffer)
228{
229
230    ds1743_clock_t *softc = ctx->dev_softc;
231    hsaddr_t bptr;
232    uint8_t b;
233    physaddr_t clockbase;
234    uint8_t byte;
235
236    clockbase = softc->clock_base;
237
238    bptr = buffer->buf_ptr;
239
240    byte = (uint8_t) (READCSR(clockbase+DS1743_CONTROL) & 0xFF);
241    WRITECSR(clockbase+DS1743_CONTROL,M_DS1743_R | byte);
242
243    b =  READCSR(clockbase+DS1743_HOUR);  hs_write8(bptr,b); bptr++;
244    b =  READCSR(clockbase+DS1743_MINUTE); hs_write8(bptr,b); bptr++;
245    b =  READCSR(clockbase+DS1743_SECOND); hs_write8(bptr,b); bptr++;
246    b =  READCSR(clockbase+DS1743_MONTH) & M_DS1743_MONTH; hs_write8(bptr,b); bptr++;
247    b =  READCSR(clockbase+DS1743_DATE) & M_DS1743_DATE; hs_write8(bptr,b); bptr++;
248    b =  READCSR(clockbase+DS1743_YEAR); hs_write8(bptr,b); bptr++;
249    b =  READCSR(clockbase+DS1743_CENTURY) & M_DS1743_CENTURY; hs_write8(bptr,b); bptr++;
250
251    byte = (uint8_t) (READCSR(clockbase+DS1743_CONTROL) & 0xFF);
252    WRITECSR(clockbase+DS1743_CONTROL,~M_DS1743_R & byte);
253
254    buffer->buf_retlen = 8;
255    return 0;
256}
257
258/*  *********************************************************************
259    *  ds1743_clock_write(ctx,buffer)
260    *
261    *  Write time/date to the RTC. Write in this format:
262    *  hour-minute-second-month-day-year1-year2-(time/date flag)
263    *
264    *  Input parameters:
265    *  	   ctx - device context (can obtain our softc here)
266    *  	   buffer - buffer descriptor (target buffer, length, offset)
267    *
268    *  Return value:
269    *  	   number of bytes written
270    *  	   -1 if an error occured
271    ********************************************************************* */
272
273static int ds1743_clock_write(cfe_devctx_t *ctx,iocb_buffer_t *buffer)
274{
275    ds1743_clock_t *softc = ctx->dev_softc;
276    uint8_t byte;
277    hsaddr_t bptr;
278    uint8_t hr,min,sec;
279    uint8_t mo,day,yr,y2k;
280    uint8_t timeDateFlag;
281    physaddr_t clockbase;
282
283    clockbase = softc->clock_base;
284
285    bptr = buffer->buf_ptr;
286
287    /* Set SET bit */
288    byte = (uint8_t) (READCSR(clockbase+DS1743_CONTROL) & 0xFF);
289    WRITECSR(clockbase+DS1743_CONTROL,M_DS1743_W | byte);
290
291    timeDateFlag = hs_read8(bptr + 7);
292
293    /* write time or date */
294    if(timeDateFlag == SET_TIME) {
295
296	hr = (uint8_t) hs_read8(bptr);
297	WRITECSR(clockbase+DS1743_HOUR,BCD(hr));
298
299	min = (uint8_t) hs_read8(bptr+1);
300	WRITECSR(clockbase+DS1743_MINUTE,BCD(min));
301
302	sec = (uint8_t) hs_read8(bptr+2);
303	WRITECSR(clockbase+DS1743_SECOND,BCD(sec));
304
305	buffer->buf_retlen = 3;
306	}
307    else if(timeDateFlag == SET_DATE) {
308	uint8_t byte;
309
310	mo = (uint8_t) hs_read8(bptr+3);
311	WRITECSR(clockbase+DS1743_MONTH,BCD(mo));
312
313	day = (uint8_t) hs_read8(bptr+4);
314	WRITECSR(clockbase+DS1743_DATE,BCD(day));
315
316	yr = (uint8_t) hs_read8(bptr+5);
317	WRITECSR(clockbase+DS1743_YEAR,BCD(yr));
318
319	y2k = (uint8_t) hs_read8(bptr+6);
320	byte = READCSR(clockbase+DS1743_CENTURY);
321	byte &= ~M_DS1743_CENTURY;
322	byte |= (y2k & M_DS1743_CENTURY);
323 	WRITECSR(clockbase+DS1743_CENTURY, byte);
324
325	buffer->buf_retlen = 4;
326	}
327    else {
328	return -1;
329	}
330
331    /* clear SET bit */
332    byte = (uint8_t) (READCSR(clockbase+DS1743_CONTROL) & 0xFF);
333    WRITECSR(clockbase+DS1743_CONTROL,~M_DS1743_W & byte);
334
335  return 0;
336}
337
338/*  *********************************************************************
339    *  ds1743_clock_inpstat(ctx,inpstat)
340    *
341    *  Test input (read) status for the device
342    *
343    *  Input parameters:
344    *  	   ctx - device context (can obtain our softc here)
345    *  	   inpstat - input status descriptor to receive value
346    *
347    *  Return value:
348    *  	   0 if ok
349    *  	   -1 if an error occured
350    ********************************************************************* */
351
352static int ds1743_clock_inpstat(cfe_devctx_t *ctx,iocb_inpstat_t *inpstat)
353{
354    inpstat->inp_status = 1;
355
356    return 0;
357}
358
359/*  *********************************************************************
360    *  ds1743_clock_ioctl(ctx,buffer)
361    *
362    *  Perform miscellaneous I/O control operations on the device.
363    *
364    *  Input parameters:
365    *  	   ctx - device context (can obtain our softc here)
366    *  	   buffer - buffer descriptor (target buffer, length, offset)
367    *
368    *  Return value:
369    *  	   number of bytes read
370    *  	   -1 if an error occured
371    ********************************************************************* */
372
373static int ds1743_clock_ioctl(cfe_devctx_t *ctx,iocb_buffer_t *buffer)
374{
375  return 0;
376}
377
378/*  *********************************************************************
379    *  ds1743_clock_close(ctx,buffer)
380    *
381    *  Close the device.
382    *
383    *  Input parameters:
384    *  	   ctx - device context (can obtain our softc here)
385    *
386    *  Return value:
387    *  	   0 if ok
388    *  	   -1 if an error occured
389    ********************************************************************* */
390
391static int ds1743_clock_close(cfe_devctx_t *ctx)
392{
393    return 0;
394}
395
396
397
398/*  *********************************************************************
399    *  Forward Declarations
400    ********************************************************************* */
401
402static void ds1743_nvram_probe(cfe_driver_t *drv,
403			       unsigned long probe_a, unsigned long probe_b,
404			       void *probe_ptr);
405
406
407static int ds1743_nvram_open(cfe_devctx_t *ctx);
408static int ds1743_nvram_read(cfe_devctx_t *ctx,iocb_buffer_t *buffer);
409static int ds1743_nvram_inpstat(cfe_devctx_t *ctx,iocb_inpstat_t *inpstat);
410static int ds1743_nvram_write(cfe_devctx_t *ctx,iocb_buffer_t *buffer);
411static int ds1743_nvram_ioctl(cfe_devctx_t *ctx,iocb_buffer_t *buffer);
412static int ds1743_nvram_close(cfe_devctx_t *ctx);
413
414/*  *********************************************************************
415    *  Dispatch tables
416    ********************************************************************* */
417
418const static cfe_devdisp_t ds1743_nvram_dispatch = {
419    ds1743_nvram_open,
420    ds1743_nvram_read,
421    ds1743_nvram_inpstat,
422    ds1743_nvram_write,
423    ds1743_nvram_ioctl,
424    ds1743_nvram_close,
425    NULL,
426    NULL
427};
428
429const cfe_driver_t ds1743_nvram = {
430    "Dallas DS1743 NVRAM",
431    "nvram",
432    CFE_DEV_NVRAM,
433    &ds1743_nvram_dispatch,
434    ds1743_nvram_probe
435};
436
437typedef struct ds1743_nvram_s {
438    int base_addr;
439    int dev_size;
440    int env_offset;
441    int env_size;
442    volatile unsigned char* data; /* NV region */
443} ds1743_nvram_t;
444
445
446
447/*  *********************************************************************
448    *  ds1743_nvram_probe(drv,a,b,ptr)
449    *
450    *  Probe routine for this driver.  This routine creates the
451    *  local device context and attaches it to the driver list
452    *  within CFE.
453    *
454    *  Input parameters:
455    *  	   drv - driver handle
456    *  	   a,b - probe hints (longs)
457    *  	   ptr - probe hint (pointer)
458    *
459    *  Return value:
460    *  	   nothing
461    ********************************************************************* */
462static void ds1743_nvram_probe(cfe_driver_t *drv,
463			       unsigned long probe_a, unsigned long probe_b,
464			       void *probe_ptr)
465{
466    ds1743_nvram_t *softc;
467    char descr[80];
468
469    softc = (ds1743_nvram_t *) KMALLOC(sizeof(ds1743_nvram_t),0);
470
471    /*
472     * Probe_a is the NVRAM base address.
473     * Probe_b is unused
474     * Probe_ptr is unused.
475     */
476
477    softc->base_addr = (int)probe_a;
478    softc->dev_size = DS1743_NVRAM_SIZE;
479    softc->env_offset  = 0;
480    softc->env_size = softc->dev_size;
481    softc->data = (volatile unsigned char*) UNCADDR(softc->base_addr);
482    /* PHYS_TO_XKSEG_UNCACHED(softc->base_addr); */
483
484    xsprintf(descr,"%s at %x size %dKB",
485	     drv->drv_description,
486	     softc->base_addr,
487	     softc->dev_size / 1024 );
488
489    cfe_attach(drv,softc,NULL,descr);
490}
491
492
493
494/*  *********************************************************************
495    *  ds1743_nvram_open(ctx)
496    *
497    *  Open this device.  For the X1240, we do a quick test
498    *  read to be sure the device is out there.
499    *
500    *  Input parameters:
501    *  	   ctx - device context (can obtain our softc here)
502    *
503    *  Return value:
504    *  	   0 if ok
505    *  	   else error code
506    ********************************************************************* */
507
508static int ds1743_nvram_open(cfe_devctx_t *ctx)
509{
510    return 0;
511}
512
513/*  *********************************************************************
514    *  ds1743_nvram_read(ctx,buffer)
515    *
516    *  Read bytes from the device.
517    *
518    *  Input parameters:
519    *  	   ctx - device context (can obtain our softc here)
520    *  	   buffer - buffer descriptor (target buffer, length, offset)
521    *
522    *  Return value:
523    *  	   number of bytes read
524    *  	   -1 if an error occured
525    ********************************************************************* */
526
527static int ds1743_nvram_read(cfe_devctx_t *ctx,iocb_buffer_t *buffer)
528{
529    ds1743_nvram_t *softc = ctx->dev_softc;
530    hsaddr_t bptr;
531    int blen;
532    int idx;
533    int b = 0;
534
535    bptr = buffer->buf_ptr;
536    blen = buffer->buf_length;
537
538    if ((buffer->buf_offset + blen) > softc->dev_size) return -1;
539
540    idx = (int) buffer->buf_offset;
541
542    while (blen > 0) {
543	b = softc->data[idx];
544	hs_write8(bptr,(unsigned char) b);
545	bptr++;
546	blen--;
547	idx++;
548    }
549
550    buffer->buf_retlen = bptr - buffer->buf_ptr;
551    return (b < 0) ? -1 : 0;
552}
553
554/*  *********************************************************************
555    *  ds1743_nvram_inpstat(ctx,inpstat)
556    *
557    *  Test input (read) status for the device
558    *
559    *  Input parameters:
560    *  	   ctx - device context (can obtain our softc here)
561    *  	   inpstat - input status descriptor to receive value
562    *
563    *  Return value:
564    *  	   0 if ok
565    *  	   -1 if an error occured
566    ********************************************************************* */
567
568static int ds1743_nvram_inpstat(cfe_devctx_t *ctx,iocb_inpstat_t *inpstat)
569{
570    inpstat->inp_status = 1;
571
572    return 0;
573}
574
575/*  *********************************************************************
576    *  ds1743_nvram_write(ctx,buffer)
577    *
578    *  Write bytes from the device.
579    *
580    *  Input parameters:
581    *  	   ctx - device context (can obtain our softc here)
582    *  	   buffer - buffer descriptor (target buffer, length, offset)
583    *
584    *  Return value:
585    *  	   number of bytes read
586    *  	   -1 if an error occured
587    ********************************************************************* */
588
589static int ds1743_nvram_write(cfe_devctx_t *ctx,iocb_buffer_t *buffer)
590{
591    ds1743_nvram_t *softc = ctx->dev_softc;
592    hsaddr_t bptr;
593    int blen;
594    int idx;
595    int b = 0;
596
597    bptr = buffer->buf_ptr;
598    blen = buffer->buf_length;
599
600    if ((buffer->buf_offset + blen) > softc->dev_size) return -1;
601
602    idx = (int) buffer->buf_offset;
603
604    while (blen > 0) {
605	b = hs_read8(bptr);
606	bptr++;
607	softc->data[idx] = b;
608	blen--;
609	idx++;
610    }
611
612    buffer->buf_retlen = bptr - buffer->buf_ptr;
613    return (b < 0) ? -1 : 0;
614}
615
616/*  *********************************************************************
617    *  ds1743_nvram_ioctl(ctx,buffer)
618    *
619    *  Perform miscellaneous I/O control operations on the device.
620    *
621    *  Input parameters:
622    *  	   ctx - device context (can obtain our softc here)
623    *  	   buffer - buffer descriptor (target buffer, length, offset)
624    *
625    *  Return value:
626    *  	   number of bytes read
627    *  	   -1 if an error occured
628    ********************************************************************* */
629
630static int ds1743_nvram_ioctl(cfe_devctx_t *ctx,iocb_buffer_t *buffer)
631{
632    ds1743_nvram_t *softc = ctx->dev_softc;
633    nvram_info_t info;
634
635    switch ((int)buffer->buf_ioctlcmd) {
636	case IOCTL_NVRAM_GETINFO:
637	    if (buffer->buf_length != sizeof(nvram_info_t)) return -1;
638	    info.nvram_offset = softc->env_offset;
639	    info.nvram_size =   softc->env_size;
640	    info.nvram_eraseflg = FALSE;
641	    hs_memcpy_to_hs(buffer->buf_ptr,&info,sizeof(info));
642	    buffer->buf_retlen = sizeof(nvram_info_t);
643	    return 0;
644	default:
645	    return -1;
646	}
647}
648
649/*  *********************************************************************
650    *  ds1743_nvram_close(ctx,buffer)
651    *
652    *  Close the device.
653    *
654    *  Input parameters:
655    *  	   ctx - device context (can obtain our softc here)
656    *
657    *  Return value:
658    *  	   0 if ok
659    *  	   -1 if an error occured
660    ********************************************************************* */
661
662static int ds1743_nvram_close(cfe_devctx_t *ctx)
663{
664    return 0;
665}
666
667
668