summaryrefslogtreecommitdiffstats
path: root/sys/arm
diff options
context:
space:
mode:
authorimp <imp@FreeBSD.org>2012-06-06 06:19:52 +0000
committerimp <imp@FreeBSD.org>2012-06-06 06:19:52 +0000
commit691dfc2d38f86af8b930db40efa6e0ec1a6e455d (patch)
tree617d0d8012fd119d3365d9c0af1002c05b650c26 /sys/arm
parent189fa08e47a3906066f9b390ce70cd71487ca409 (diff)
downloadFreeBSD-src-691dfc2d38f86af8b930db40efa6e0ec1a6e455d.zip
FreeBSD-src-691dfc2d38f86af8b930db40efa6e0ec1a6e455d.tar.gz
Enhance the Atmel SoC chip identification routines to account for more
SoC variants. Fold the AT91SAM9XE chips into the AT91SAM9260 handling, where appropriate. The following SoCs/SoC families are recognized: at91cap9, at91rm9200, at91sam9260, at91sam9261, at91sam9263, at91sam9g10, at91sam9g20, at91sam9g45, at91sam9n12, at91sam9rl, at91sam9x5 and the following variations are also recognized: at91rm9200_bga, at91rm9200_pqfp, at91sam9xe, at91sam9g45, at91sam9m10, at91sam9g46, at91sam9m11, at91sam9g15, at91sam9g25, at91sam9g35, at91sam9x25, at91sam9x35 This is only the identification routine: no additional Atmel devices are supported at this time. # With these changes, I'm able to boot to the point of identification # on a few different Atmel SoCs that we don't yet support using the # KB920X config file -- someday tht will be an ATMEL config file...
Diffstat (limited to 'sys/arm')
-rw-r--r--sys/arm/at91/at91.c2
-rw-r--r--sys/arm/at91/at91_machdep.c155
-rw-r--r--sys/arm/at91/at91_mci.c24
-rw-r--r--sys/arm/at91/at91_pmc.c4
-rw-r--r--sys/arm/at91/at91reg.h42
-rw-r--r--sys/arm/at91/at91rm9200.c9
-rw-r--r--sys/arm/at91/at91sam9260.c25
-rw-r--r--sys/arm/at91/at91sam9g20.c13
-rw-r--r--sys/arm/at91/at91var.h63
9 files changed, 255 insertions, 82 deletions
diff --git a/sys/arm/at91/at91.c b/sys/arm/at91/at91.c
index e9f27b5..9cdb531 100644
--- a/sys/arm/at91/at91.c
+++ b/sys/arm/at91/at91.c
@@ -54,8 +54,6 @@ static void at91_eoi(void *);
extern const struct pmap_devmap at91_devmap[];
-uint32_t at91_chip_id;
-
uint32_t at91_master_clock;
static int
diff --git a/sys/arm/at91/at91_machdep.c b/sys/arm/at91/at91_machdep.c
index 1f0d8a7..a6b8d87 100644
--- a/sys/arm/at91/at91_machdep.c
+++ b/sys/arm/at91/at91_machdep.c
@@ -232,6 +232,156 @@ at91_ramsize(void)
return (1 << (cols + rows + banks + bw));
}
+const char *soc_type_name[] = {
+ [AT91_T_CAP9] = "at91cap9",
+ [AT91_T_RM9200] = "at91rm9200",
+ [AT91_T_SAM9260] = "at91sam9260",
+ [AT91_T_SAM9261] = "at91sam9261",
+ [AT91_T_SAM9263] = "at91sam9263",
+ [AT91_T_SAM9G10] = "at91sam9g10",
+ [AT91_T_SAM9G20] = "at91sam9g20",
+ [AT91_T_SAM9G45] = "at91sam9g45",
+ [AT91_T_SAM9N12] = "at91sam9n12",
+ [AT91_T_SAM9RL] = "at91sam9rl",
+ [AT91_T_SAM9X5] = "at91sam9x5",
+ [AT91_T_NONE] = "UNKNOWN"
+};
+
+const char *soc_subtype_name[] = {
+ [AT91_ST_NONE] = "UNKNOWN",
+ [AT91_ST_RM9200_BGA] = "at91rm9200_bga",
+ [AT91_ST_RM9200_PQFP] = "at91rm9200_pqfp",
+ [AT91_ST_SAM9XE] = "at91sam9xe",
+ [AT91_ST_SAM9G45] = "at91sam9g45",
+ [AT91_ST_SAM9M10] = "at91sam9m10",
+ [AT91_ST_SAM9G46] = "at91sam9g46",
+ [AT91_ST_SAM9M11] = "at91sam9m11",
+ [AT91_ST_SAM9G15] = "at91sam9g15",
+ [AT91_ST_SAM9G25] = "at91sam9g25",
+ [AT91_ST_SAM9G35] = "at91sam9g35",
+ [AT91_ST_SAM9X25] = "at91sam9x25",
+ [AT91_ST_SAM9X35] = "at91sam9x35",
+};
+
+#define AT91_DBGU0 0x0ffff200 /* Most */
+#define AT91_DBGU1 0x0fffee00 /* SAM9263, CAP9, and SAM9G45 */
+
+struct at91_soc_info soc_data;
+
+/*
+ * Read the SoC ID from the CIDR register and try to match it against the
+ * values we know. If we find a good one, we return true. If not, we
+ * return false. When we find a good one, we also find the subtype
+ * and CPU family.
+ */
+static int
+at91_try_id(uint32_t dbgu_base)
+{
+ uint32_t socid;
+
+ soc_data.cidr = *(volatile uint32_t *)(AT91_BASE + dbgu_base + DBGU_C1R);
+ socid = soc_data.cidr & ~AT91_CPU_VERSION_MASK;
+
+ soc_data.type = AT91_T_NONE;
+ soc_data.subtype = AT91_ST_NONE;
+ soc_data.family = (soc_data.cidr & AT91_CPU_FAMILY_MASK) >> 20;
+ soc_data.exid = *(volatile uint32_t *)(AT91_BASE + dbgu_base + DBGU_C2R);
+
+ switch (socid) {
+ case AT91_CPU_CAP9:
+ soc_data.type = AT91_T_CAP9;
+ break;
+ case AT91_CPU_RM9200:
+ soc_data.type = AT91_T_RM9200;
+ break;
+ case AT91_CPU_SAM9XE128:
+ case AT91_CPU_SAM9XE256:
+ case AT91_CPU_SAM9XE512:
+ case AT91_CPU_SAM9260:
+ soc_data.type = AT91_T_SAM9260;
+ if (soc_data.family == AT91_FAMILY_SAM9XE)
+ soc_data.subtype = AT91_ST_SAM9XE;
+ break;
+ case AT91_CPU_SAM9261:
+ soc_data.type = AT91_T_SAM9261;
+ break;
+ case AT91_CPU_SAM9263:
+ soc_data.type = AT91_T_SAM9263;
+ break;
+ case AT91_CPU_SAM9G10:
+ soc_data.type = AT91_T_SAM9G10;
+ break;
+ case AT91_CPU_SAM9G20:
+ soc_data.type = AT91_T_SAM9G20;
+ break;
+ case AT91_CPU_SAM9G45:
+ soc_data.type = AT91_T_SAM9G45;
+ break;
+ case AT91_CPU_SAM9N12:
+ soc_data.type = AT91_T_SAM9N12;
+ break;
+ case AT91_CPU_SAM9RL64:
+ soc_data.type = AT91_T_SAM9RL;
+ break;
+ case AT91_CPU_SAM9X5:
+ soc_data.type = AT91_T_SAM9X5;
+ break;
+ default:
+ return 0;
+ }
+
+ switch (soc_data.type) {
+ case AT91_T_SAM9G45:
+ switch (soc_data.exid) {
+ case AT91_EXID_SAM9G45:
+ soc_data.subtype = AT91_ST_SAM9G45;
+ break;
+ case AT91_EXID_SAM9G46:
+ soc_data.subtype = AT91_ST_SAM9G46;
+ break;
+ case AT91_EXID_SAM9M10:
+ soc_data.subtype = AT91_ST_SAM9M10;
+ break;
+ case AT91_EXID_SAM9M11:
+ soc_data.subtype = AT91_ST_SAM9M11;
+ break;
+ }
+ break;
+ case AT91_T_SAM9X5:
+ switch (soc_data.exid) {
+ case AT91_EXID_SAM9G15:
+ soc_data.subtype = AT91_ST_SAM9G15;
+ break;
+ case AT91_EXID_SAM9G25:
+ soc_data.subtype = AT91_ST_SAM9G25;
+ break;
+ case AT91_EXID_SAM9G35:
+ soc_data.subtype = AT91_ST_SAM9G35;
+ break;
+ case AT91_EXID_SAM9X25:
+ soc_data.subtype = AT91_ST_SAM9X25;
+ break;
+ case AT91_EXID_SAM9X35:
+ soc_data.subtype = AT91_ST_SAM9X35;
+ break;
+ }
+ break;
+ default:
+ break;
+ }
+ snprintf(soc_data.name, sizeof(soc_data.name), "%s%s%s", soc_type_name[soc_data.type],
+ soc_data.subtype == AT91_ST_NONE ? "" : " subtype ",
+ soc_data.subtype == AT91_ST_NONE ? "" : soc_subtype_name[soc_data.subtype]);
+ return 1;
+}
+
+static void
+at91_soc_id(void)
+{
+ if (!at91_try_id(AT91_DBGU0))
+ at91_try_id(AT91_DBGU1);
+}
+
void *
initarm(struct arm_boot_params *abp)
{
@@ -355,12 +505,11 @@ initarm(struct arm_boot_params *abp)
cpu_tlb_flushID();
cpu_domains(DOMAIN_CLIENT << (PMAP_DOMAIN_KERNEL*2));
+ at91_soc_id();
+
/* Initialize all the clocks, so that the console can work */
at91_pmc_init_clock();
- /* Get chip id so device drivers know about differences */
- at91_chip_id = *(uint32_t *)(AT91_BASE + AT91_DBGU_BASE + DBGU_C1R);
-
cninit();
memsize = board_init();
diff --git a/sys/arm/at91/at91_mci.c b/sys/arm/at91/at91_mci.c
index 56cff68..9735bab 100644
--- a/sys/arm/at91/at91_mci.c
+++ b/sys/arm/at91/at91_mci.c
@@ -313,23 +313,17 @@ static int
at91_mci_is_mci1rev2xx(void)
{
- switch (AT91_CPU(at91_chip_id)) {
- case AT91_CPU_SAM9260:
- case AT91_CPU_SAM9263:
-#ifdef notyet
- case AT91_CPU_CAP9:
-#endif
- case AT91_CPU_SAM9G10:
- case AT91_CPU_SAM9G20:
-#ifdef notyet
- case AT91_CPU_SAM9RL:
-#endif
- case AT91_CPU_SAM9XE128:
- case AT91_CPU_SAM9XE256:
- case AT91_CPU_SAM9XE512:
+ switch (soc_data.type) {
+ case AT91_T_SAM9260:
+ case AT91_T_SAM9263:
+ case AT91_T_CAP9:
+ case AT91_T_SAM9G10:
+ case AT91_T_SAM9G20:
+ case AT91_T_SAM9RL:
return(1);
+ default:
+ return (0);
}
- return (0);
}
static void
diff --git a/sys/arm/at91/at91_pmc.c b/sys/arm/at91/at91_pmc.c
index 2a7ee5e..799a87b 100644
--- a/sys/arm/at91/at91_pmc.c
+++ b/sys/arm/at91/at91_pmc.c
@@ -471,7 +471,7 @@ at91_pmc_init_clock(void)
at91_pmc_pll_rate(&plla, RD4(sc, CKGR_PLLAR));
- if (at91_cpu_is(AT91_CPU_SAM9G45) && (mckr & PMC_MCKR_PLLADIV2))
+ if (at91_cpu_is(AT91_T_SAM9G45) && (mckr & PMC_MCKR_PLLADIV2))
plla.hz /= 2;
/*
@@ -512,7 +512,7 @@ at91_pmc_init_clock(void)
mck.hz /= (1 + mdiv);
/* Only found on SAM9G20 */
- if (at91_cpu_is(AT91_CPU_SAM9G20))
+ if (at91_cpu_is(AT91_T_SAM9G20))
cpu.hz /= (mckr & PMC_MCKR_PDIV) ? 2 : 1;
at91_master_clock = mck.hz;
diff --git a/sys/arm/at91/at91reg.h b/sys/arm/at91/at91reg.h
index 7493de8..0401291 100644
--- a/sys/arm/at91/at91reg.h
+++ b/sys/arm/at91/at91reg.h
@@ -46,32 +46,40 @@
#define AT91_SYS_BASE 0xffff000
#define AT91_SYS_SIZE 0x1000
-#if defined(AT91SAM9G45) || defined(AT91SAM9263)
-#define AT91_DBGU_BASE 0xfffee00
-#else
-#define AT91_DBGU_BASE 0xffff200
-#endif
#define AT91_DBGU_SIZE 0x200
#define DBGU_C1R (64) /* Chip ID1 Register */
#define DBGU_C2R (68) /* Chip ID2 Register */
#define DBGU_FNTR (72) /* Force NTRST Register */
#define AT91_CPU_VERSION_MASK 0x0000001f
-#define AT91_CPU_RM9200 0x09290780
-#define AT91_CPU_SAM9260 0x019803a0
-#define AT91_CPU_SAM9261 0x019703a0
-#define AT91_CPU_SAM9263 0x019607a0
-#define AT91_CPU_SAM9G10 0x819903a0
-#define AT91_CPU_SAM9G20 0x019905a0
-#define AT91_CPU_SAM9G45 0x819b05a0
+#define AT91_CPU_FAMILY_MASK 0x0ff00000
+
+#define AT91_CPU_RM9200 0x09290780
+#define AT91_CPU_SAM9260 0x019803a0
+#define AT91_CPU_SAM9261 0x019703a0
+#define AT91_CPU_SAM9263 0x019607a0
+#define AT91_CPU_SAM9G10 0x819903a0
+#define AT91_CPU_SAM9G20 0x019905a0
+#define AT91_CPU_SAM9G45 0x819b05a0
+#define AT91_CPU_SAM9N12 0x819a07a0
+#define AT91_CPU_SAM9RL64 0x019b03a0
+#define AT91_CPU_SAM9X5 0x819a05a0
+
#define AT91_CPU_SAM9XE128 0x329973a0
#define AT91_CPU_SAM9XE256 0x329a93a0
#define AT91_CPU_SAM9XE512 0x329aa3a0
-#define AT91_ARCH(chipid) ((chipid >> 20) & 0xff)
-#define AT91_CPU(chipid) (chipid & ~AT91_CPU_VERSION_MASK)
-#define AT91_ARCH_SAM9 (0x19)
-#define AT91_ARCH_SAM9XE (0x29)
-#define AT91_ARCH_RM92 (0x92)
+#define AT91_CPU_CAP9 0x039a03a0
+
+#define AT91_EXID_SAM9M11 0x00000001
+#define AT91_EXID_SAM9M10 0x00000002
+#define AT91_EXID_SAM9G46 0x00000003
+#define AT91_EXID_SAM9G45 0x00000004
+
+#define AT91_EXID_SAM9G15 0x00000000
+#define AT91_EXID_SAM9G35 0x00000001
+#define AT91_EXID_SAM9X35 0x00000002
+#define AT91_EXID_SAM9G25 0x00000003
+#define AT91_EXID_SAM9X25 0x00000004
#endif /* _AT91REG_H_ */
diff --git a/sys/arm/at91/at91rm9200.c b/sys/arm/at91/at91rm9200.c
index 9a0fae5..f2c4c48 100644
--- a/sys/arm/at91/at91rm9200.c
+++ b/sys/arm/at91/at91rm9200.c
@@ -197,7 +197,7 @@ static void
at91_identify(driver_t *drv, device_t parent)
{
- if (at91_cpu_is(AT91_CPU_RM9200)) {
+ if (at91_cpu_is(AT91_T_RM9200)) {
at91_add_child(parent, 0, "at91rm920", 0, 0, 0, -1, 0, 0);
at91_cpu_add_builtin_children(parent);
}
@@ -207,11 +207,8 @@ static int
at91_probe(device_t dev)
{
- if (at91_cpu_is(AT91_CPU_RM9200)) {
- device_set_desc(dev, "AT91RM9200");
- return (0);
- }
- return (ENXIO);
+ device_set_desc(dev, soc_data.name);
+ return (0);
}
static int
diff --git a/sys/arm/at91/at91sam9260.c b/sys/arm/at91/at91sam9260.c
index cbc5a27..71448f4 100644
--- a/sys/arm/at91/at91sam9260.c
+++ b/sys/arm/at91/at91sam9260.c
@@ -197,11 +197,7 @@ static void
at91_identify(driver_t *drv, device_t parent)
{
- switch (AT91_CPU(at91_chip_id)) {
- case AT91_CPU_SAM9260:
- case AT91_CPU_SAM9XE128:
- case AT91_CPU_SAM9XE256:
- case AT91_CPU_SAM9XE512:
+ if (soc_data.type == AT91_CPU_SAM9260) {
at91_add_child(parent, 0, "at91sam9260", 0, 0, 0, -1, 0, 0);
at91_cpu_add_builtin_children(parent);
break;
@@ -211,25 +207,8 @@ at91_identify(driver_t *drv, device_t parent)
static int
at91_probe(device_t dev)
{
- const char *desc;
- switch (AT91_CPU(at91_chip_id)) {
- case AT91_CPU_SAM9260:
- desc = "AT91SAM9260";
- break;
- case AT91_CPU_SAM9XE128:
- desc = "AT91SAM9XE128";
- break;
- case AT91_CPU_SAM9XE256:
- desc = "AT91SAM9XE256";
- break;
- case AT91_CPU_SAM9XE512:
- desc = "AT91SAM9XE512";
- break;
- default:
- return (ENXIO);
- }
- device_set_desc(dev, desc);
+ device_set_desc(dev, soc_data.name);
return (0);
}
diff --git a/sys/arm/at91/at91sam9g20.c b/sys/arm/at91/at91sam9g20.c
index 61d9ac4..063a7bf 100644
--- a/sys/arm/at91/at91sam9g20.c
+++ b/sys/arm/at91/at91sam9g20.c
@@ -137,8 +137,8 @@ at91_add_child(device_t dev, int prio, const char *name, int unit,
kid = device_add_child_ordered(dev, prio, name, unit);
if (kid == NULL) {
- printf("Can't add child %s%d ordered\n", name, unit);
- return;
+ printf("Can't add child %s%d ordered\n", name, unit);
+ return;
}
ivar = malloc(sizeof(*ivar), M_DEVBUF, M_NOWAIT | M_ZERO);
if (ivar == NULL) {
@@ -204,7 +204,7 @@ static void
at91_identify(driver_t *drv, device_t parent)
{
- if (at91_cpu_is(AT91_CPU_SAM9G20)) {
+ if (at91_cpu_is(AT91_T_SAM9G20)) {
at91_add_child(parent, 0, "at91sam", 9, 0, 0, -1, 0, 0);
at91_cpu_add_builtin_children(parent);
}
@@ -214,11 +214,8 @@ static int
at91_probe(device_t dev)
{
- if (at91_cpu_is(AT91_CPU_SAM9G20)) {
- device_set_desc(dev, "AT91SAM9G20");
- return (0);
- }
- return (ENXIO);
+ device_set_desc(dev, soc_data.name);
+ return (0);
}
static int
diff --git a/sys/arm/at91/at91var.h b/sys/arm/at91/at91var.h
index be82eee..a8df717 100644
--- a/sys/arm/at91/at91var.h
+++ b/sys/arm/at91/at91var.h
@@ -59,7 +59,59 @@ struct cpu_devs
const char *parent_clk;
};
-extern uint32_t at91_chip_id;
+enum at91_soc_type {
+ AT91_T_NONE = 0,
+ AT91_T_CAP9,
+ AT91_T_RM9200,
+ AT91_T_SAM9260,
+ AT91_T_SAM9261,
+ AT91_T_SAM9263,
+ AT91_T_SAM9G10,
+ AT91_T_SAM9G20,
+ AT91_T_SAM9G45,
+ AT91_T_SAM9N12,
+ AT91_T_SAM9RL,
+ AT91_T_SAM9X5,
+};
+
+enum at91_soc_subtype {
+ AT91_ST_NONE = 0,
+ /* AT91RM9200 */
+ AT91_ST_RM9200_BGA,
+ AT91_ST_RM9200_PQFP,
+ /* AT91SAM9260 */
+ AT91_ST_SAM9XE,
+ /* AT91SAM9G45 */
+ AT91_ST_SAM9G45,
+ AT91_ST_SAM9M10,
+ AT91_ST_SAM9G46,
+ AT91_ST_SAM9M11,
+ /* AT91SAM9X5 */
+ AT91_ST_SAM9G15,
+ AT91_ST_SAM9G25,
+ AT91_ST_SAM9G35,
+ AT91_ST_SAM9X25,
+ AT91_ST_SAM9X35,
+};
+
+enum at91_soc_family {
+ AT91_FAMILY_SAM9 = 0x19,
+ AT91_FAMILY_SAM9XE = 0x29,
+ AT91_FAMILY_RM92 = 0x92,
+};
+
+#define AT91_SOC_NAME_MAX 50
+
+struct at91_soc_info {
+ enum at91_soc_type type;
+ enum at91_soc_subtype subtype;
+ enum at91_soc_family family;
+ uint32_t cidr;
+ uint32_t exid;
+ char name[AT91_SOC_NAME_MAX];
+};
+
+extern struct at91_soc_info soc_data;
static inline int at91_is_rm92(void);
static inline int at91_is_sam9(void);
@@ -70,33 +122,32 @@ static inline int
at91_is_rm92(void)
{
- return (AT91_ARCH(at91_chip_id) == AT91_ARCH_RM92);
+ return (soc_data.type == AT91_T_RM9200);
}
static inline int
at91_is_sam9(void)
{
- return (AT91_ARCH(at91_chip_id) == AT91_ARCH_SAM9);
+ return (soc_data.family == AT91_FAMILY_SAM9);
}
static inline int
at91_is_sam9xe(void)
{
- return (AT91_ARCH(at91_chip_id) == AT91_ARCH_SAM9XE);
+ return (soc_data.family == AT91_FAMILY_SAM9XE);
}
static inline int
at91_cpu_is(u_int cpu)
{
- return (AT91_CPU(at91_chip_id) == cpu);
+ return (soc_data.type == cpu);
}
extern uint32_t at91_irq_system;
extern uint32_t at91_master_clock;
-
void at91_pmc_init_clock(void);
#endif /* _AT91VAR_H_ */
OpenPOWER on IntegriCloud