1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277
|
/*
* (C) Copyright 2008 Dmitry Rakhchev, EmCraft Systems, rda@emcraft.com
*
* Developed for DENX Software Engineering GmbH
*
* SPDX-License-Identifier: GPL-2.0+
*/
#include <post.h>
#include <common.h>
/*
* SYSMON test
*
* This test performs the system hardware monitoring.
* The test passes when all the following voltages and temperatures
* are within allowed ranges:
*
* Temperature -40 .. +90 C
* +5V +4.50 .. +5.50 V
* +5V standby +3.50 .. +5.50 V
*
* LCD backlight is not enabled if temperature values are not within
* allowed ranges (-30 .. + 80). The brightness of backlite can be
* controlled by setting "brightness" environment variable. Default value is 50%
*
* See the list of all parameters in the sysmon_table below
*/
#include <post.h>
#include <watchdog.h>
#include <i2c.h>
#if defined(CONFIG_VIDEO)
#include <mb862xx.h>
#endif
#if CONFIG_POST & CONFIG_SYS_POST_SYSMON
DECLARE_GLOBAL_DATA_PTR;
/* from dspic.c */
extern int dspic_read(ushort reg, ushort *data);
#define REG_TEMPERATURE 0x12BC
#define REG_VOLTAGE_5V 0x12CA
#define REG_VOLTAGE_5V_STANDBY 0x12C6
#define TEMPERATURE_MIN (-40) /* degr. C */
#define TEMPERATURE_MAX (+90) /* degr. C */
#define TEMPERATURE_DISPLAY_MIN (-35) /* degr. C */
#define TEMPERATURE_DISPLAY_MAX (+85) /* degr. C */
#define VOLTAGE_5V_MIN (+4500) /* mV */
#define VOLTAGE_5V_MAX (+5500) /* mV */
#define VOLTAGE_5V_STANDBY_MIN (+3500) /* mV */
#define VOLTAGE_5V_STANDBY_MAX (+5500) /* mV */
typedef struct sysmon_s sysmon_t;
typedef struct sysmon_table_s sysmon_table_t;
static void sysmon_dspic_init(sysmon_t *this);
static int sysmon_dspic_read(sysmon_t *this, uint addr, int *val);
static int sysmon_dspic_read_sgn(sysmon_t *this, uint addr, int *val);
static void sysmon_backlight_disable(sysmon_table_t *this);
struct sysmon_s {
uchar chip;
void (*init)(sysmon_t *);
int (*read)(sysmon_t *, uint, int *);
};
static sysmon_t sysmon_dspic = {
CONFIG_SYS_I2C_DSPIC_IO_ADDR,
sysmon_dspic_init,
sysmon_dspic_read
};
static sysmon_t sysmon_dspic_sgn = {
CONFIG_SYS_I2C_DSPIC_IO_ADDR,
sysmon_dspic_init,
sysmon_dspic_read_sgn
};
static sysmon_t *sysmon_list[] = {
&sysmon_dspic,
NULL
};
struct sysmon_table_s {
char *name;
char *unit_name;
sysmon_t *sysmon;
void (*exec_before)(sysmon_table_t *);
void (*exec_after)(sysmon_table_t *);
int unit_precision;
int unit_div;
int unit_min;
int unit_max;
uint val_mask;
uint val_min;
uint val_max;
int val_valid;
uint val_min_alt;
uint val_max_alt;
int val_valid_alt;
uint addr;
};
static sysmon_table_t sysmon_table[] = {
{
"Temperature", " C", &sysmon_dspic, NULL, sysmon_backlight_disable,
1, 1, -32768, 32767, 0xFFFF,
0x8000 + TEMPERATURE_MIN, 0x8000 + TEMPERATURE_MAX, 0,
0x8000 + TEMPERATURE_DISPLAY_MIN, 0x8000 + TEMPERATURE_DISPLAY_MAX, 0,
REG_TEMPERATURE,
},
{
"+ 5 V", "V", &sysmon_dspic, NULL, NULL,
100, 1000, -0x8000, 0x7FFF, 0xFFFF,
0x8000 + VOLTAGE_5V_MIN, 0x8000 + VOLTAGE_5V_MAX, 0,
0x8000 + VOLTAGE_5V_MIN, 0x8000 + VOLTAGE_5V_MAX, 0,
REG_VOLTAGE_5V,
},
{
"+ 5 V standby", "V", &sysmon_dspic, NULL, NULL,
100, 1000, -0x8000, 0x7FFF, 0xFFFF,
0x8000 + VOLTAGE_5V_STANDBY_MIN, 0x8000 + VOLTAGE_5V_STANDBY_MAX, 0,
0x8000 + VOLTAGE_5V_STANDBY_MIN, 0x8000 + VOLTAGE_5V_STANDBY_MAX, 0,
REG_VOLTAGE_5V_STANDBY,
},
{
"Temperature", "°C", &sysmon_dspic_sgn, NULL, sysmon_backlight_disable,
1, 1, -32768, 32767, 0xFFFF,
0x8000 + TEMPERATURE_MIN, 0x8000 + TEMPERATURE_MAX, 0,
0x8000 + TEMPERATURE_DISPLAY_MIN, 0x8000 + TEMPERATURE_DISPLAY_MAX, 0,
REG_TEMPERATURE,
},
};
int sysmon_init_f(void)
{
sysmon_t **l;
for (l = sysmon_list; *l; l++)
(*l)->init(*l);
return 0;
}
void sysmon_reloc(void)
{
/* Do nothing for now, sysmon_reloc() is required by the sysmon post */
}
static char *sysmon_unit_value(sysmon_table_t *s, uint val)
{
static char buf[32];
char *p, sign;
int decimal, frac;
int unit_val;
unit_val = s->unit_min + (s->unit_max - s->unit_min) * val / s->val_mask;
if (val == -1)
return "I/O ERROR";
if (unit_val < 0) {
sign = '-';
unit_val = -unit_val;
} else {
sign = '+';
}
p = buf + sprintf(buf, "%c%2d", sign, unit_val / s->unit_div);
frac = unit_val % s->unit_div;
frac /= (s->unit_div / s->unit_precision);
decimal = s->unit_precision;
if (decimal != 1)
*p++ = '.';
for (decimal /= 10; decimal != 0; decimal /= 10)
*p++ = '0' + (frac / decimal) % 10;
strcpy(p, s->unit_name);
return buf;
}
static void sysmon_dspic_init(sysmon_t *this)
{
}
static int sysmon_dspic_read(sysmon_t *this, uint addr, int *val)
{
ushort data;
if (dspic_read(addr, &data) == 0){
/* To fit into the table range we should add 0x8000 */
*val = data + 0x8000;
return 0;
}
return -1;
}
static int sysmon_dspic_read_sgn(sysmon_t *this, uint addr, int *val)
{
ushort data;
if (dspic_read(addr, &data) == 0){
/* To fit into the table range we should add 0x8000 */
*val = (signed short)data + 0x8000;
return 0;
}
return -1;
}
static void sysmon_backlight_disable(sysmon_table_t *this)
{
#if defined(CONFIG_VIDEO)
board_backlight_switch(this->val_valid_alt);
#endif
}
int sysmon_post_test(int flags)
{
int res = 0;
sysmon_table_t * t;
int val;
for (t = sysmon_table; t < sysmon_table + ARRAY_SIZE(sysmon_table); t++) {
t->val_valid = 1;
if (t->exec_before)
t->exec_before(t);
if (t->sysmon->read(t->sysmon, t->addr, &val) != 0) {
t->val_valid = 0;
t->val_valid_alt = 0;
post_log(": read failed\n");
res = 1;
break;
}
if (t->val_valid != 0) {
t->val_valid = val >= t->val_min && val <= t->val_max;
t->val_valid_alt = val >= t->val_min_alt && val <= t->val_max_alt;
}
if (t->exec_after)
t->exec_after(t);
if ((!t->val_valid) || (flags)) {
post_log("\n\t%-17s = %-10s ", t->name, sysmon_unit_value(t, val));
post_log("allowed range");
post_log(" %-8s ..", sysmon_unit_value(t, t->val_min));
post_log(" %-8s", sysmon_unit_value(t, t->val_max));
post_log(" %s", t->val_valid ? "OK" : "FAIL");
}
if (!t->val_valid) {
res = 1;
break;
}
}
post_log("\n");
return res;
}
#endif /* CONFIG_POST & CONFIG_SYS_POST_SYSMON */
|