#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#include "rpihw.h"
#define LINE_WIDTH_MAX 80
#define HW_VER_STRING "Revision"
#define PERIPH_BASE_RPI 0x20000000
#define PERIPH_BASE_RPI2 0x3f000000
#define VIDEOCORE_BASE_RPI 0x40000000
#define VIDEOCORE_BASE_RPI2 0xc0000000
#define RPI_MANUFACTURER_MASK (0xf << 16)
#define RPI_WARRANTY_MASK (0x3 << 24)
static const rpi_hw_t rpi_hw_info[] = {
{
.hwver = 0x02,
.type = RPI_HWVER_TYPE_PI1,
.periph_base = PERIPH_BASE_RPI,
.videocore_base = VIDEOCORE_BASE_RPI,
.desc = "Model B",
},
{
.hwver = 0x03,
.type = RPI_HWVER_TYPE_PI1,
.periph_base = PERIPH_BASE_RPI,
.videocore_base = VIDEOCORE_BASE_RPI,
.desc = "Model B",
},
{
.hwver = 0x04,
.type = RPI_HWVER_TYPE_PI1,
.periph_base = PERIPH_BASE_RPI,
.videocore_base = VIDEOCORE_BASE_RPI,
.desc = "Model B",
},
{
.hwver = 0x05,
.type = RPI_HWVER_TYPE_PI1,
.periph_base = PERIPH_BASE_RPI,
.videocore_base = VIDEOCORE_BASE_RPI,
.desc = "Model B",
},
{
.hwver = 0x06,
.type = RPI_HWVER_TYPE_PI1,
.periph_base = PERIPH_BASE_RPI,
.videocore_base = VIDEOCORE_BASE_RPI,
.desc = "Model B",
},
{
.hwver = 0x07,
.type = RPI_HWVER_TYPE_PI1,
.periph_base = PERIPH_BASE_RPI,
.videocore_base = VIDEOCORE_BASE_RPI,
.desc = "Model A",
},
{
.hwver = 0x08,
.type = RPI_HWVER_TYPE_PI1,
.periph_base = PERIPH_BASE_RPI,
.videocore_base = VIDEOCORE_BASE_RPI,
.desc = "Model A",
},
{
.hwver = 0x09,
.type = RPI_HWVER_TYPE_PI1,
.periph_base = PERIPH_BASE_RPI,
.videocore_base = VIDEOCORE_BASE_RPI,
.desc = "Model A",
},
{
.hwver = 0x0d,
.type = RPI_HWVER_TYPE_PI1,
.periph_base = PERIPH_BASE_RPI,
.videocore_base = VIDEOCORE_BASE_RPI,
.desc = "Model B",
},
{
.hwver = 0x0e,
.type = RPI_HWVER_TYPE_PI1,
.periph_base = PERIPH_BASE_RPI,
.videocore_base = VIDEOCORE_BASE_RPI,
.desc = "Model B",
},
{
.hwver = 0x0f,
.type = RPI_HWVER_TYPE_PI1,
.periph_base = PERIPH_BASE_RPI,
.videocore_base = VIDEOCORE_BASE_RPI,
.desc = "Model B",
},
{
.hwver = 0x10,
.type = RPI_HWVER_TYPE_PI1,
.periph_base = PERIPH_BASE_RPI,
.videocore_base = VIDEOCORE_BASE_RPI,
.desc = "Model B+",
},
{
.hwver = 0x13,
.type = RPI_HWVER_TYPE_PI1,
.periph_base = PERIPH_BASE_RPI,
.videocore_base = VIDEOCORE_BASE_RPI,
.desc = "Model B+",
},
{
.hwver = 0x900032,
.type = RPI_HWVER_TYPE_PI1,
.periph_base = PERIPH_BASE_RPI,
.videocore_base = VIDEOCORE_BASE_RPI,
.desc = "Model B+",
},
{
.hwver = 0x11,
.type = RPI_HWVER_TYPE_PI1,
.periph_base = PERIPH_BASE_RPI,
.videocore_base = VIDEOCORE_BASE_RPI,
.desc = "Compute Module 1",
},
{
.hwver = 0x14,
.type = RPI_HWVER_TYPE_PI1,
.periph_base = PERIPH_BASE_RPI,
.videocore_base = VIDEOCORE_BASE_RPI,
.desc = "Compute Module 1",
},
{
.hwver = 0x900092,
.type = RPI_HWVER_TYPE_PI1,
.periph_base = PERIPH_BASE_RPI,
.videocore_base = VIDEOCORE_BASE_RPI,
.desc = "Pi Zero v1.2",
},
{
.hwver = 0x900093,
.type = RPI_HWVER_TYPE_PI1,
.periph_base = PERIPH_BASE_RPI,
.videocore_base = VIDEOCORE_BASE_RPI,
.desc = "Pi Zero v1.3",
},
{
.hwver = 0x920093,
.type = RPI_HWVER_TYPE_PI1,
.periph_base = PERIPH_BASE_RPI,
.videocore_base = VIDEOCORE_BASE_RPI,
.desc = "Pi Zero v1.3",
},
{
.hwver = 0x9200c1,
.type = RPI_HWVER_TYPE_PI1,
.periph_base = PERIPH_BASE_RPI,
.videocore_base = VIDEOCORE_BASE_RPI,
.desc = "Pi Zero W v1.1",
},
{
.hwver = 0x9000c1,
.type = RPI_HWVER_TYPE_PI1,
.periph_base = PERIPH_BASE_RPI,
.videocore_base = VIDEOCORE_BASE_RPI,
.desc = "Pi Zero W v1.1",
},
{
.hwver = 0x12,
.type = RPI_HWVER_TYPE_PI1,
.periph_base = PERIPH_BASE_RPI,
.videocore_base = VIDEOCORE_BASE_RPI,
.desc = "Model A+",
},
{
.hwver = 0x15,
.type = RPI_HWVER_TYPE_PI1,
.periph_base = PERIPH_BASE_RPI,
.videocore_base = VIDEOCORE_BASE_RPI,
.desc = "Model A+",
},
{
.hwver = 0x900021,
.type = RPI_HWVER_TYPE_PI1,
.periph_base = PERIPH_BASE_RPI,
.videocore_base = VIDEOCORE_BASE_RPI,
.desc = "Model A+",
},
{
.hwver = 0xa01041,
.type = RPI_HWVER_TYPE_PI2,
.periph_base = PERIPH_BASE_RPI2,
.videocore_base = VIDEOCORE_BASE_RPI2,
.desc = "Pi 2",
},
{
.hwver = 0xa01040,
.type = RPI_HWVER_TYPE_PI2,
.periph_base = PERIPH_BASE_RPI2,
.videocore_base = VIDEOCORE_BASE_RPI2,
.desc = "Pi 2",
},
{
.hwver = 0xa21041,
.type = RPI_HWVER_TYPE_PI2,
.periph_base = PERIPH_BASE_RPI2,
.videocore_base = VIDEOCORE_BASE_RPI2,
.desc = "Pi 2",
},
{
.hwver = 0xa22042,
.type = RPI_HWVER_TYPE_PI2,
.periph_base = PERIPH_BASE_RPI2,
.videocore_base = VIDEOCORE_BASE_RPI2,
.desc = "Pi 2",
},
{
.hwver = 0xa02082,
.type = RPI_HWVER_TYPE_PI2,
.periph_base = PERIPH_BASE_RPI2,
.videocore_base = VIDEOCORE_BASE_RPI2,
.desc = "Pi 3",
},
{
.hwver = 0xa22082,
.type = RPI_HWVER_TYPE_PI2,
.periph_base = PERIPH_BASE_RPI2,
.videocore_base = VIDEOCORE_BASE_RPI2,
.desc = "Pi 3",
},
{
.hwver = 0xa020a0,
.type = RPI_HWVER_TYPE_PI2,
.periph_base = PERIPH_BASE_RPI2,
.videocore_base = VIDEOCORE_BASE_RPI2,
.desc = "Compute Module 3/L3",
},
};
const rpi_hw_t *rpi_hw_detect(void)
{
FILE *f = fopen("/proc/cpuinfo", "r");
char line[LINE_WIDTH_MAX];
const rpi_hw_t *result = NULL;
if (!f)
{
return NULL;
}
while (fgets(line, LINE_WIDTH_MAX - 1, f))
{
if (strstr(line, HW_VER_STRING))
{
uint32_t rev;
char *substr;
unsigned i;
substr = strstr(line, ": ");
if (!substr)
{
continue;
}
errno = 0;
rev = strtoul(&substr[1], NULL, 16); if (errno)
{
continue;
}
for (i = 0; i < (sizeof(rpi_hw_info) / sizeof(rpi_hw_info[0])); i++)
{
uint32_t hwver = rpi_hw_info[i].hwver;
hwver &= ~(RPI_WARRANTY_MASK | RPI_MANUFACTURER_MASK);
rev &= ~(RPI_WARRANTY_MASK | RPI_MANUFACTURER_MASK);
if (rev == hwver)
{
result = &rpi_hw_info[i];
goto done;
}
}
}
}
done:
fclose(f);
return result;
}