1/*  *********************************************************************
2    *  Broadcom Common Firmware Environment (CFE)
3    *
4    *  Temperature sensor commands:		File: ui_tempsensor.c
5    *
6    *  Temperature sensor commands
7    *
8    *  Author:  Mitch Lichtenberg (mpl@broadcom.com)
9    *
10    *********************************************************************
11    *
12    *  Copyright 2000,2001,2002,2003
13    *  Broadcom Corporation. All rights reserved.
14    *
15    *  This software is furnished under license and may be used and
16    *  copied only in accordance with the following terms and
17    *  conditions.  Subject to these conditions, you may download,
18    *  copy, install, use, modify and distribute modified or unmodified
19    *  copies of this software in source and/or binary form.  No title
20    *  or ownership is transferred hereby.
21    *
22    *  1) Any source code used, modified or distributed must reproduce
23    *     and retain this copyright notice and list of conditions
24    *     as they appear in the source file.
25    *
26    *  2) No right is granted to use any trade name, trademark, or
27    *     logo of Broadcom Corporation.  The "Broadcom Corporation"
28    *     name may not be used to endorse or promote products derived
29    *     from this software without the prior written permission of
30    *     Broadcom Corporation.
31    *
32    *  3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR
33    *     IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED
34    *     WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
35    *     PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT
36    *     SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN
37    *     PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT,
38    *     INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
39    *     (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
40    *     GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
41    *     BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
42    *     OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
43    *     TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF
44    *     THE POSSIBILITY OF SUCH DAMAGE.
45    ********************************************************************* */
46
47
48#include "lib_types.h"
49#include "lib_string.h"
50#include "lib_queue.h"
51#include "lib_malloc.h"
52#include "lib_printf.h"
53
54#include "cfe_console.h"
55#include "cfe_timer.h"
56
57#include "cfe_error.h"
58
59#include "ui_command.h"
60#include "cfe.h"
61
62#include "bsp_config.h"
63
64#include "sbmips.h"
65#include "sb1250_regs.h"
66#include "sb1250_smbus.h"
67
68
69/*  *********************************************************************
70    *  Configuration
71    ********************************************************************* */
72
73#define _MAX6654_	/* Support Maxim 6654 temperature chip w/parasitic mode */
74
75/*  *********************************************************************
76    *  prototypes
77    ********************************************************************* */
78
79int ui_init_tempsensorcmds(void);
80
81#if (defined(TEMPSENSOR_SMBUS_DEV) && defined(TEMPSENSOR_SMBUS_CHAN))
82static int ui_cmd_showtemp(ui_cmdline_t *cmd,int argc,char *argv[]);
83static void temp_timer_proc(void *);
84#endif
85
86/*  *********************************************************************
87    *  Data
88    ********************************************************************* */
89
90#if (defined(TEMPSENSOR_SMBUS_DEV) && defined(TEMPSENSOR_SMBUS_CHAN))
91static int64_t temp_timer = 0;
92static int temp_prev_local = 0;
93static int temp_prev_remote = 0;
94#endif
95
96/*  *********************************************************************
97    *  ui_init_swarmcmds()
98    *
99    *  Add SWARM-specific commands to the command table
100    *
101    *  Input parameters:
102    *  	   nothing
103    *
104    *  Return value:
105    *  	   0
106    ********************************************************************* */
107
108
109int ui_init_tempsensorcmds(void)
110{
111
112#if (defined(TEMPSENSOR_SMBUS_DEV) && defined(TEMPSENSOR_SMBUS_CHAN))
113    cmd_addcmd("show temp",
114	       ui_cmd_showtemp,
115	       NULL,
116	       "Display CPU temperature",
117	       "show temp",
118	       "-continuous;Poll for temperature changes|"
119	       "-stop;Stop polling for temperature changes");
120
121    cfe_bg_add(temp_timer_proc,NULL);
122#endif
123
124    return 0;
125}
126
127
128
129#if (defined(TEMPSENSOR_SMBUS_DEV) && defined(TEMPSENSOR_SMBUS_CHAN))
130/*  *********************************************************************
131    *  temp_smbus_init(chan)
132    *
133    *  Initialize the specified SMBus channel for the temp sensor
134    *
135    *  Input parameters:
136    *  	   chan - channel # (0 or 1)
137    *
138    *  Return value:
139    *  	   nothing
140    ********************************************************************* */
141
142static void temp_smbus_init(int chan)
143{
144    uintptr_t reg;
145
146    reg = PHYS_TO_K1(A_SMB_REGISTER(chan,R_SMB_FREQ));
147
148    SBWRITECSR(reg,K_SMB_FREQ_100KHZ);			/* 400Khz clock */
149
150    reg = PHYS_TO_K1(A_SMB_REGISTER(chan,R_SMB_CONTROL));
151
152    SBWRITECSR(reg,0);			/* not in direct mode, no interrupts, will poll */
153
154}
155
156/*  *********************************************************************
157    *  temp_smbus_waitready(chan)
158    *
159    *  Wait until the SMBus channel is ready.  We simply poll
160    *  the busy bit until it clears.
161    *
162    *  Input parameters:
163    *  	   chan - channel (0 or 1)
164    *
165    *  Return value:
166    *      nothing
167    ********************************************************************* */
168static int temp_smbus_waitready(int chan)
169{
170    uintptr_t reg;
171    uint64_t status;
172
173    reg = PHYS_TO_K1(A_SMB_REGISTER(chan,R_SMB_STATUS));
174
175    for (;;) {
176	status = SBREADCSR(reg);
177	if (status & M_SMB_BUSY) continue;
178	break;
179	}
180
181    if (status & M_SMB_ERROR) {
182	SBWRITECSR(reg,(status & M_SMB_ERROR));
183	return -1;
184	}
185    return 0;
186}
187
188/*  *********************************************************************
189    *  temp_smbus_read(chan,slaveaddr,devaddr)
190    *
191    *  Read a byte from the temperature sensor chip
192    *
193    *  Input parameters:
194    *  	   chan - SMBus channel
195    *  	   slaveaddr -  SMBus slave address
196    *  	   devaddr - byte with in the sensor device to read
197    *
198    *  Return value:
199    *  	   0 if ok
200    *  	   else -1
201    ********************************************************************* */
202
203static int temp_smbus_read(int chan,int slaveaddr,int devaddr)
204{
205    uintptr_t reg;
206    int err;
207
208    /*
209     * Make sure the bus is idle (probably should
210     * ignore error here)
211     */
212
213    if (temp_smbus_waitready(chan) < 0) return -1;
214
215    /*
216     * Write the device address to the controller. There are two
217     * parts, the high part goes in the "CMD" field, and the
218     * low part is the data field.
219     */
220
221    reg = PHYS_TO_K1(A_SMB_REGISTER(chan,R_SMB_CMD));
222    SBWRITECSR(reg,devaddr);
223
224    /*
225     * Read the data byte
226     */
227
228    reg = PHYS_TO_K1(A_SMB_REGISTER(chan,R_SMB_START));
229    SBWRITECSR(reg,V_SMB_TT(K_SMB_TT_CMD_RD1BYTE) | slaveaddr);
230
231    err = temp_smbus_waitready(chan);
232    if (err < 0) return err;
233
234    reg = PHYS_TO_K1(A_SMB_REGISTER(chan,R_SMB_DATA));
235    err = SBREADCSR(reg);
236
237    return (err & 0xFF);
238}
239
240#ifdef _MAX6654_
241/*  *********************************************************************
242    *  temp_smbus_write(chan,slaveaddr,devaddr,data)
243    *
244    *  write a byte to the temperature sensor chip
245    *
246    *  Input parameters:
247    *  	   chan - SMBus channel
248    *  	   slaveaddr -  SMBus slave address
249    *  	   devaddr - byte with in the sensor device to read
250    *
251    *  Return value:
252    *  	   0 if ok
253    *  	   else -1
254    ********************************************************************* */
255
256static int temp_smbus_write(int chan,int slaveaddr,int devaddr,int data)
257{
258    uintptr_t reg;
259    int err;
260
261    /*
262     * Make sure the bus is idle (probably should
263     * ignore error here)
264     */
265
266    if (temp_smbus_waitready(chan) < 0) return -1;
267
268    /*
269     * Write the device address to the controller. There are two
270     * parts, the high part goes in the "CMD" field, and the
271     * low part is the data field.
272     */
273
274    reg = PHYS_TO_K1(A_SMB_REGISTER(chan,R_SMB_CMD));
275    SBWRITECSR(reg,devaddr);
276
277    /*
278     * Write the data byte
279     */
280
281    reg = PHYS_TO_K1(A_SMB_REGISTER(chan,R_SMB_DATA));
282    SBWRITECSR(reg,data);
283
284    /*
285     * Do the write command.
286     */
287
288    reg = PHYS_TO_K1(A_SMB_REGISTER(chan,R_SMB_START));
289    SBWRITECSR(reg,V_SMB_TT(K_SMB_TT_WR2BYTE) | slaveaddr);
290
291    err = temp_smbus_waitready(chan);
292
293    return err;
294}
295#endif
296
297
298/*  *********************************************************************
299    *  temp_showtemp(noisy)
300    *
301    *  Display the temperature.  If 'noisy' is true, display it
302    *  regardless of whether it has changed, otherwise only display
303    *  when it has changed.
304    *
305    *  Input parameters:
306    *  	   noisy - display whether or not changed
307    *
308    *  Return value:
309    *  	   nothing
310    ********************************************************************* */
311
312static int temp_showtemp(int noisy)
313{
314    int local,remote,status;
315    char statstr[50];
316
317    local  = temp_smbus_read(TEMPSENSOR_SMBUS_CHAN,TEMPSENSOR_SMBUS_DEV,0);
318    remote = temp_smbus_read(TEMPSENSOR_SMBUS_CHAN,TEMPSENSOR_SMBUS_DEV,1);
319    status = temp_smbus_read(TEMPSENSOR_SMBUS_CHAN,TEMPSENSOR_SMBUS_DEV,2);
320
321    if ((local < 0) || (remote < 0) || (status < 0)) {
322	if (noisy) printf("Temperature sensor device did not respond\n");
323	return -1;
324	}
325
326    if (noisy || (local != temp_prev_local) || (remote != temp_prev_remote)) {
327	statstr[0] = 0;
328	if (status & 0x80) strcat(statstr,"Busy ");
329	if (status & 0x40) strcat(statstr,"HiTempLcl ");
330	if (status & 0x20) strcat(statstr,"LoTempLcl ");
331	if (status & 0x10) strcat(statstr,"HiTempRem ");
332	if (status & 0x08) strcat(statstr,"LoTempRem ");
333	if (status & 0x04) strcat(statstr,"Fault ");
334
335	if (noisy || !(status & 0x80)) {
336	    /* don't display if busy, always display if noisy */
337	    console_log("Temperature:  CPU: %dC  Board: %dC  Status:%02X [ %s]",
338		    remote,local,status,statstr);
339	    }
340	}
341
342    temp_prev_local = local;
343    temp_prev_remote = remote;
344
345    return 0;
346}
347
348
349
350
351/*  *********************************************************************
352    *  ui_cmd_showtemp(cmd,argc,argv)
353    *
354    *  Show temperature
355    *
356    *  Input parameters:
357    *  	   cmd - command structure
358    *  	   argc,argv - parameters
359    *
360    *  Return value:
361    *  	   -1 if error occured.  Does not return otherwise
362    ********************************************************************* */
363
364static int ui_cmd_showtemp(ui_cmdline_t *cmd,int argc,char *argv[])
365{
366
367    temp_smbus_init(TEMPSENSOR_SMBUS_CHAN);
368
369#ifdef _MAX6654_
370    do {
371	int dev,rev;
372	static int didinit = 0;
373
374	if (!didinit) {
375	    didinit = 1;
376	    dev = temp_smbus_read(TEMPSENSOR_SMBUS_CHAN,TEMPSENSOR_SMBUS_DEV,0xFE);
377	    rev = temp_smbus_read(TEMPSENSOR_SMBUS_CHAN,TEMPSENSOR_SMBUS_DEV,0xFF);
378	    printf("Temperature Sensor Device ID %02X rev %02X\n",dev,rev);
379
380	    if (dev == 0x4D) {		/* MAX6654 */
381		printf("Switching MAX6654 to parasitic mode\n");
382		/* Switch to 1hz conversion rate (1 seconds per conversion) */
383		temp_smbus_write(TEMPSENSOR_SMBUS_CHAN,TEMPSENSOR_SMBUS_DEV,0x0A,0x04);
384		/* Switch to parasitic mode */
385		temp_smbus_write(TEMPSENSOR_SMBUS_CHAN,TEMPSENSOR_SMBUS_DEV,9,0x10);
386		}
387	    }
388       } while (0);
389#endif
390
391    if (temp_showtemp(1) < 0) {
392	TIMER_CLEAR(temp_timer);
393	return -1;
394	}
395
396    if (cmd_sw_isset(cmd,"-continuous")) {
397	TIMER_SET(temp_timer,2*CFE_HZ);
398	}
399    if (cmd_sw_isset(cmd,"-stop")) {
400	TIMER_CLEAR(temp_timer);
401	}
402
403    return 0;
404}
405
406/*  *********************************************************************
407    *  temp_timer_proc()
408    *
409    *  So we can be fancy and log temperature changes as they happen.
410    *
411    *  Input parameters:
412    *  	   nothing
413    *
414    *  Return value:
415    *  	   nothing
416    ********************************************************************* */
417
418void temp_timer_proc(void *arg)
419{
420    if (!TIMER_RUNNING(temp_timer)) return;
421
422    if (TIMER_EXPIRED(temp_timer)) {
423	temp_showtemp(0);
424	TIMER_SET(temp_timer,2*CFE_HZ);
425	}
426}
427#endif
428