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