From 515d0c1d290c1ac2fb1aa99e74ef4175c158a007 Mon Sep 17 00:00:00 2001 From: imp Date: Wed, 11 Jul 2012 20:17:14 +0000 Subject: Make the SoC stuff a little more modular, and start to move away from having the CPU device that's a child of atmelarm that does stuff. o Create a linker_set for the support fucntions for the SoCs. o Rename soc_data to soc_info. o Move the delay and reset function pointers to new soc_data struct o Create elements for all known SoCs o Add lookup of the SoC we found, and print a warning if it isn't one we know about. --- sys/arm/at91/at91_machdep.c | 94 +++++++++++++++++++++++++-------------------- sys/arm/at91/at91_mci.c | 2 +- sys/arm/at91/at91_st.c | 22 ++++++++--- sys/arm/at91/at91_streg.h | 3 ++ sys/arm/at91/at91rm9200.c | 12 +++++- sys/arm/at91/at91sam9260.c | 14 ++++++- sys/arm/at91/at91sam9g20.c | 12 +++++- sys/arm/at91/at91sam9x25.c | 12 +++++- sys/arm/at91/at91soc.c | 51 ++++++++++++++++++++++++ sys/arm/at91/at91soc.h | 58 ++++++++++++++++++++++++++++ sys/arm/at91/at91var.h | 19 +++++---- sys/arm/at91/files.at91 | 1 + 12 files changed, 239 insertions(+), 61 deletions(-) create mode 100644 sys/arm/at91/at91soc.c create mode 100644 sys/arm/at91/at91soc.h diff --git a/sys/arm/at91/at91_machdep.c b/sys/arm/at91/at91_machdep.c index 15e404f..0bb79bd 100644 --- a/sys/arm/at91/at91_machdep.c +++ b/sys/arm/at91/at91_machdep.c @@ -90,6 +90,7 @@ __FBSDID("$FreeBSD$"); #include #include +#include #include #include #include @@ -278,7 +279,7 @@ static const char *soc_subtype_name[] = { [AT91_ST_SAM9X35] = "at91sam9x35", }; -struct at91_soc_info soc_data; +struct at91_soc_info soc_info; /* * Read the SoC ID from the CIDR register and try to match it against the @@ -291,92 +292,92 @@ at91_try_id(uint32_t dbgu_base) { uint32_t socid; - soc_data.cidr = *(volatile uint32_t *)(AT91_BASE + dbgu_base + + soc_info.cidr = *(volatile uint32_t *)(AT91_BASE + dbgu_base + DBGU_C1R); - socid = soc_data.cidr & ~AT91_CPU_VERSION_MASK; + socid = soc_info.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 + + soc_info.type = AT91_T_NONE; + soc_info.subtype = AT91_ST_NONE; + soc_info.family = (soc_info.cidr & AT91_CPU_FAMILY_MASK) >> 20; + soc_info.exid = *(volatile uint32_t *)(AT91_BASE + dbgu_base + DBGU_C2R); switch (socid) { case AT91_CPU_CAP9: - soc_data.type = AT91_T_CAP9; + soc_info.type = AT91_T_CAP9; break; case AT91_CPU_RM9200: - soc_data.type = AT91_T_RM9200; + soc_info.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; + soc_info.type = AT91_T_SAM9260; + if (soc_info.family == AT91_FAMILY_SAM9XE) + soc_info.subtype = AT91_ST_SAM9XE; break; case AT91_CPU_SAM9261: - soc_data.type = AT91_T_SAM9261; + soc_info.type = AT91_T_SAM9261; break; case AT91_CPU_SAM9263: - soc_data.type = AT91_T_SAM9263; + soc_info.type = AT91_T_SAM9263; break; case AT91_CPU_SAM9G10: - soc_data.type = AT91_T_SAM9G10; + soc_info.type = AT91_T_SAM9G10; break; case AT91_CPU_SAM9G20: - soc_data.type = AT91_T_SAM9G20; + soc_info.type = AT91_T_SAM9G20; break; case AT91_CPU_SAM9G45: - soc_data.type = AT91_T_SAM9G45; + soc_info.type = AT91_T_SAM9G45; break; case AT91_CPU_SAM9N12: - soc_data.type = AT91_T_SAM9N12; + soc_info.type = AT91_T_SAM9N12; break; case AT91_CPU_SAM9RL64: - soc_data.type = AT91_T_SAM9RL; + soc_info.type = AT91_T_SAM9RL; break; case AT91_CPU_SAM9X5: - soc_data.type = AT91_T_SAM9X5; + soc_info.type = AT91_T_SAM9X5; break; default: return (0); } - switch (soc_data.type) { + switch (soc_info.type) { case AT91_T_SAM9G45: - switch (soc_data.exid) { + switch (soc_info.exid) { case AT91_EXID_SAM9G45: - soc_data.subtype = AT91_ST_SAM9G45; + soc_info.subtype = AT91_ST_SAM9G45; break; case AT91_EXID_SAM9G46: - soc_data.subtype = AT91_ST_SAM9G46; + soc_info.subtype = AT91_ST_SAM9G46; break; case AT91_EXID_SAM9M10: - soc_data.subtype = AT91_ST_SAM9M10; + soc_info.subtype = AT91_ST_SAM9M10; break; case AT91_EXID_SAM9M11: - soc_data.subtype = AT91_ST_SAM9M11; + soc_info.subtype = AT91_ST_SAM9M11; break; } break; case AT91_T_SAM9X5: - switch (soc_data.exid) { + switch (soc_info.exid) { case AT91_EXID_SAM9G15: - soc_data.subtype = AT91_ST_SAM9G15; + soc_info.subtype = AT91_ST_SAM9G15; break; case AT91_EXID_SAM9G25: - soc_data.subtype = AT91_ST_SAM9G25; + soc_info.subtype = AT91_ST_SAM9G25; break; case AT91_EXID_SAM9G35: - soc_data.subtype = AT91_ST_SAM9G35; + soc_info.subtype = AT91_ST_SAM9G35; break; case AT91_EXID_SAM9X25: - soc_data.subtype = AT91_ST_SAM9X25; + soc_info.subtype = AT91_ST_SAM9X25; break; case AT91_EXID_SAM9X35: - soc_data.subtype = AT91_ST_SAM9X35; + soc_info.subtype = AT91_ST_SAM9X35; break; } break; @@ -384,18 +385,24 @@ at91_try_id(uint32_t dbgu_base) break; } /* - * Disable interrupts + * Disable interrupts in the DBGU unit... */ *(volatile uint32_t *)(AT91_BASE + dbgu_base + USART_IDR) = 0xffffffff; /* * Save the name for later... */ - 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]); + snprintf(soc_info.name, sizeof(soc_info.name), "%s%s%s", + soc_type_name[soc_info.type], + soc_info.subtype == AT91_ST_NONE ? "" : " subtype ", + soc_info.subtype == AT91_ST_NONE ? "" : + soc_subtype_name[soc_info.subtype]); + + /* + * try to get the matching CPU support. + */ + soc_info.soc_data = at91_match_soc(soc_info.type, soc_info.subtype); + return (1); } @@ -548,6 +555,9 @@ initarm(struct arm_boot_params *abp) cninit(); + if (soc_info.soc_data == NULL) + printf("Warning: No soc support for %s found.\n", soc_info.name); + memsize = board_init(); physmem = memsize / PAGE_SIZE; @@ -637,16 +647,16 @@ void DELAY(int n) { - if (soc_data.delay) - soc_data.delay(n); + if (soc_info.soc_data) + soc_info.soc_data->soc_delay(n); } void cpu_reset(void) { - if (soc_data.reset) - soc_data.reset(); + if (soc_info.soc_data) + soc_info.soc_data->soc_reset(); while (1) continue; } diff --git a/sys/arm/at91/at91_mci.c b/sys/arm/at91/at91_mci.c index f69477e..196aa64 100644 --- a/sys/arm/at91/at91_mci.c +++ b/sys/arm/at91/at91_mci.c @@ -313,7 +313,7 @@ static int at91_mci_is_mci1rev2xx(void) { - switch (soc_data.type) { + switch (soc_info.type) { case AT91_T_SAM9260: case AT91_T_SAM9263: case AT91_T_CAP9: diff --git a/sys/arm/at91/at91_st.c b/sys/arm/at91/at91_st.c index 7ac8175..a18be2e 100644 --- a/sys/arm/at91/at91_st.c +++ b/sys/arm/at91/at91_st.c @@ -45,6 +45,7 @@ __FBSDID("$FreeBSD$"); #include #include #include +#include static struct at91_st_softc { struct resource * sc_irq_res; @@ -57,6 +58,12 @@ static inline uint32_t RD4(bus_size_t off) { + if (timer_softc == NULL) { + uint32_t *p = (uint32_t *)(AT91_BASE + AT91RM92_ST_BASE + off); + + return *p; + } + return (bus_read_4(timer_softc->sc_mem_res, off)); } @@ -64,7 +71,13 @@ static inline void WR4(bus_size_t off, uint32_t val) { - bus_write_4(timer_softc->sc_mem_res, off, val); + if (timer_softc == NULL) { + uint32_t *p = (uint32_t *)(AT91_BASE + AT91RM92_ST_BASE + off); + + *p = val; + } + else + bus_write_4(timer_softc->sc_mem_res, off, val); } static void at91_st_watchdog(void *, u_int, int *); @@ -105,7 +118,7 @@ clock_intr(void *arg) return (FILTER_STRAY); } -static void +void at91_st_delay(int n) { uint32_t start, end, cur; @@ -125,7 +138,7 @@ at91_st_delay(int n) } } -static void +void at91_st_cpu_reset(void) { /* @@ -209,9 +222,6 @@ at91_st_attach(device_t dev) if (err) return err; - soc_data.delay = at91_st_delay; - soc_data.reset = at91_st_cpu_reset; // XXX kinda late to be setting this... - timer_softc->sc_wet = EVENTHANDLER_REGISTER(watchdog_list, at91_st_watchdog, dev, 0); diff --git a/sys/arm/at91/at91_streg.h b/sys/arm/at91/at91_streg.h index 47b1419..48a63c3 100644 --- a/sys/arm/at91/at91_streg.h +++ b/sys/arm/at91/at91_streg.h @@ -55,4 +55,7 @@ /* ST_CRTR */ #define ST_CRTR_MASK 0xfffff /* 20-bit counter */ +void at91_st_delay(int n); +void at91_st_cpu_reset(void); + #endif /* ARM_AT91_AT91STREG_H */ diff --git a/sys/arm/at91/at91rm9200.c b/sys/arm/at91/at91rm9200.c index 22c331e..51627f0 100644 --- a/sys/arm/at91/at91rm9200.c +++ b/sys/arm/at91/at91rm9200.c @@ -42,7 +42,10 @@ __FBSDID("$FreeBSD$"); #include #include #include +#include #include +#include + struct at91rm92_softc { device_t dev; @@ -171,7 +174,7 @@ static int at91_probe(device_t dev) { - device_set_desc(dev, soc_data.name); + device_set_desc(dev, soc_info.name); return (0); } @@ -277,3 +280,10 @@ static driver_t at91rm92_driver = { static devclass_t at91rm92_devclass; DRIVER_MODULE(at91rm920, atmelarm, at91rm92_driver, at91rm92_devclass, 0, 0); + +static struct at91_soc_data soc_data = { + .soc_delay = at91_st_delay, + .soc_reset = at91_st_cpu_reset +}; + +AT91_SOC(AT91_T_RM9200, &soc_data); diff --git a/sys/arm/at91/at91sam9260.c b/sys/arm/at91/at91sam9260.c index 2eee2e5..9ea0335 100644 --- a/sys/arm/at91/at91sam9260.c +++ b/sys/arm/at91/at91sam9260.c @@ -39,10 +39,13 @@ __FBSDID("$FreeBSD$"); #include #include +#include #include #include +#include #include #include +#include struct at91sam9_softc { device_t dev; @@ -162,7 +165,7 @@ static void at91_identify(driver_t *drv, device_t parent) { - if (soc_data.type == AT91_T_SAM9260) { + if (soc_info.type == AT91_T_SAM9260) { at91_add_child(parent, 0, "at91sam9260", 0, 0, 0, -1, 0, 0); at91_cpu_add_builtin_children(parent); } @@ -172,7 +175,7 @@ static int at91_probe(device_t dev) { - device_set_desc(dev, soc_data.name); + device_set_desc(dev, soc_info.name); return (0); } @@ -293,3 +296,10 @@ static devclass_t at91sam9260_devclass; DRIVER_MODULE(at91sam9260, atmelarm, at91sam9260_driver, at91sam9260_devclass, NULL, NULL); + +static struct at91_soc_data soc_data = { + .soc_delay = at91_pit_delay, + .soc_reset = at91_rst_cpu_reset +}; + +AT91_SOC(AT91_T_SAM9260, &soc_data); diff --git a/sys/arm/at91/at91sam9g20.c b/sys/arm/at91/at91sam9g20.c index 9146fda..4b87ad0 100644 --- a/sys/arm/at91/at91sam9g20.c +++ b/sys/arm/at91/at91sam9g20.c @@ -39,10 +39,13 @@ __FBSDID("$FreeBSD$"); #include #include +#include #include #include +#include #include #include +#include struct at91sam9_softc { device_t dev; @@ -179,7 +182,7 @@ static int at91_probe(device_t dev) { - device_set_desc(dev, soc_data.name); + device_set_desc(dev, soc_info.name); return (0); } @@ -295,3 +298,10 @@ static driver_t at91sam9_driver = { static devclass_t at91sam9_devclass; DRIVER_MODULE(at91sam, atmelarm, at91sam9_driver, at91sam9_devclass, 0, 0); + +static struct at91_soc_data soc_data = { + .soc_delay = at91_pit_delay, + .soc_reset = at91_rst_cpu_reset +}; + +AT91_SOC(AT91_T_SAM9G20, &soc_data); diff --git a/sys/arm/at91/at91sam9x25.c b/sys/arm/at91/at91sam9x25.c index 0c10078..b84d30c 100644 --- a/sys/arm/at91/at91sam9x25.c +++ b/sys/arm/at91/at91sam9x25.c @@ -39,10 +39,13 @@ __FBSDID("$FreeBSD$"); #include #include +#include #include #include +#include #include #include +#include struct at91sam9x25_softc { device_t dev; @@ -171,7 +174,7 @@ static void at91_identify(driver_t *drv, device_t parent) { - if (soc_data.type == AT91_T_SAM9X5 && soc_data.subtype == AT91_ST_SAM9X25) { + if (soc_info.type == AT91_T_SAM9X5 && soc_info.subtype == AT91_ST_SAM9X25) { at91_add_child(parent, 0, "at91sam9x25", 0, 0, 0, -1, 0, 0); at91_cpu_add_builtin_children(parent); } @@ -284,3 +287,10 @@ static driver_t at91sam9x25_driver = { static devclass_t at91sam9x25_devclass; DRIVER_MODULE(at91sam9x25, atmelarm, at91sam9x25_driver, at91sam9x25_devclass, 0, 0); + +static struct at91_soc_data soc_data = { + .soc_delay = at91_pit_delay, + .soc_reset = at91_rst_cpu_reset +}; + +AT91_SOC_SUB(AT91_T_SAM9X5, AT91_ST_SAM9X25, &soc_data); diff --git a/sys/arm/at91/at91soc.c b/sys/arm/at91/at91soc.c new file mode 100644 index 0000000..7031e83 --- /dev/null +++ b/sys/arm/at91/at91soc.c @@ -0,0 +1,51 @@ +/*- + * Copyright (c) 2012 Warner Losh. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include +#include + +#include +#include + +SET_DECLARE(at91_socs, const struct at91_soc); + +struct at91_soc_data * +at91_match_soc(enum at91_soc_type type, enum at91_soc_subtype subtype) +{ + const struct at91_soc **socp; + + SET_FOREACH(socp, at91_socs) { + if ((*socp)->soc_type != type) + continue; + if ((*socp)->soc_subtype != AT91_ST_ANY && + (*socp)->soc_subtype != subtype) + continue; + return (*socp)->soc_data; + } + return NULL; +} diff --git a/sys/arm/at91/at91soc.h b/sys/arm/at91/at91soc.h new file mode 100644 index 0000000..e2f4d41 --- /dev/null +++ b/sys/arm/at91/at91soc.h @@ -0,0 +1,58 @@ +/*- + * Copyright (c) 2012 Warner Losh. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* $FreeBSD$ */ + +#ifndef _ARM_AT91_AT91SOC_H_ +#define _ARM_AT91_AT91SOC_H_ + +#include + +struct at91_soc { + enum at91_soc_type soc_type; /* Family of mail type of SoC */ + enum at91_soc_subtype soc_subtype; /* More specific soc, if any */ + struct at91_soc_data *soc_data; +}; + +// Make varadic +#define AT91_SOC(type, data) \ + static struct at91_soc this_soc = { \ + .soc_type = type, \ + .soc_subtype = AT91_ST_ANY, \ + .soc_data = data, \ + }; \ + DATA_SET(at91_socs, this_soc); + +#define AT91_SOC_SUB(type, subtype, data) \ + static struct at91_soc this_soc = { \ + .soc_type = type, \ + .soc_subtype = subtype, \ + .soc_data = data, \ + }; \ + DATA_SET(at91_socs, this_soc); + +struct at91_soc_data *at91_match_soc(enum at91_soc_type, enum at91_soc_subtype); + +#endif /* _ARM_AT91_AT91SOC_H_ */ diff --git a/sys/arm/at91/at91var.h b/sys/arm/at91/at91var.h index 614687c..183b723 100644 --- a/sys/arm/at91/at91var.h +++ b/sys/arm/at91/at91var.h @@ -74,6 +74,7 @@ enum at91_soc_type { }; enum at91_soc_subtype { + AT91_ST_ANY = -1, /* Match any type */ AT91_ST_NONE = 0, /* AT91RM9200 */ AT91_ST_RM9200_BGA, @@ -104,6 +105,11 @@ enum at91_soc_family { typedef void (*DELAY_t)(int); typedef void (*cpu_reset_t)(void); +struct at91_soc_data { + DELAY_t soc_delay; + cpu_reset_t soc_reset; +}; + struct at91_soc_info { enum at91_soc_type type; enum at91_soc_subtype subtype; @@ -111,11 +117,10 @@ struct at91_soc_info { uint32_t cidr; uint32_t exid; char name[AT91_SOC_NAME_MAX]; - DELAY_t delay; - cpu_reset_t reset; + struct at91_soc_data *soc_data; }; -extern struct at91_soc_info soc_data; +extern struct at91_soc_info soc_info; static inline int at91_is_rm92(void); static inline int at91_is_sam9(void); @@ -126,28 +131,28 @@ static inline int at91_is_rm92(void) { - return (soc_data.type == AT91_T_RM9200); + return (soc_info.type == AT91_T_RM9200); } static inline int at91_is_sam9(void) { - return (soc_data.family == AT91_FAMILY_SAM9); + return (soc_info.family == AT91_FAMILY_SAM9); } static inline int at91_is_sam9xe(void) { - return (soc_data.family == AT91_FAMILY_SAM9XE); + return (soc_info.family == AT91_FAMILY_SAM9XE); } static inline int at91_cpu_is(u_int cpu) { - return (soc_data.type == cpu); + return (soc_info.type == cpu); } void at91_add_child(device_t dev, int prio, const char *name, int unit, diff --git a/sys/arm/at91/files.at91 b/sys/arm/at91/files.at91 index 0816901..8e3a75d 100644 --- a/sys/arm/at91/files.at91 +++ b/sys/arm/at91/files.at91 @@ -27,6 +27,7 @@ arm/at91/uart_dev_at91usart.c optional uart # # All the "systems on a chip" we support # +arm/at91/at91soc.c standard arm/at91/at91rm9200.c optional at91rm9200 arm/at91/at91sam9260.c optional at91sam9260 arm/at91/at91sam9g20.c optional at91sam9g20 -- cgit v1.1