Index: head/sys/arm/at91/at91_aic.c =================================================================== --- head/sys/arm/at91/at91_aic.c (revision 333141) +++ head/sys/arm/at91/at91_aic.c (revision 333142) @@ -1,184 +1,184 @@ /*- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD * - * Copyright (c) 2014 Warner Losh. All rights reserved. + * Copyright (c) 2014 M. Warner Losh. * * 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 "opt_platform.h" #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef FDT #include #include #endif static struct aic_softc { struct resource *mem_res; /* Memory resource */ void *intrhand; /* Interrupt handle */ device_t sc_dev; } *sc; static inline uint32_t RD4(struct aic_softc *sc, bus_size_t off) { return (bus_read_4(sc->mem_res, off)); } static inline void WR4(struct aic_softc *sc, bus_size_t off, uint32_t val) { bus_write_4(sc->mem_res, off, val); } void arm_mask_irq(uintptr_t nb) { WR4(sc, IC_IDCR, 1 << nb); } int arm_get_next_irq(int last __unused) { int status; int irq; irq = RD4(sc, IC_IVR); status = RD4(sc, IC_ISR); if (status == 0) { WR4(sc, IC_EOICR, 1); return (-1); } return (irq); } void arm_unmask_irq(uintptr_t nb) { WR4(sc, IC_IECR, 1 << nb); WR4(sc, IC_EOICR, 0); } static int at91_aic_probe(device_t dev) { #ifdef FDT if (!ofw_bus_is_compatible(dev, "atmel,at91rm9200-aic")) return (ENXIO); #endif device_set_desc(dev, "AIC"); return (0); } static int at91_aic_attach(device_t dev) { int i, rid, err = 0; device_printf(dev, "Attach %d\n", bus_current_pass); sc = device_get_softc(dev); sc->sc_dev = dev; rid = 0; sc->mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, RF_ACTIVE); if (sc->mem_res == NULL) panic("couldn't allocate register resources"); /* * Setup the interrupt table. */ if (soc_info.soc_data == NULL || soc_info.soc_data->soc_irq_prio == NULL) panic("Interrupt priority table missing\n"); for (i = 0; i < 32; i++) { WR4(sc, IC_SVR + i * 4, i); /* Priority. */ WR4(sc, IC_SMR + i * 4, soc_info.soc_data->soc_irq_prio[i]); if (i < 8) WR4(sc, IC_EOICR, 1); } WR4(sc, IC_SPU, 32); /* No debug. */ WR4(sc, IC_DCR, 0); /* Disable and clear all interrupts. */ WR4(sc, IC_IDCR, 0xffffffff); WR4(sc, IC_ICCR, 0xffffffff); enable_interrupts(PSR_I | PSR_F); return (err); } static void at91_aic_new_pass(device_t dev) { device_printf(dev, "Pass %d\n", bus_current_pass); } static device_method_t at91_aic_methods[] = { DEVMETHOD(device_probe, at91_aic_probe), DEVMETHOD(device_attach, at91_aic_attach), DEVMETHOD(bus_new_pass, at91_aic_new_pass), DEVMETHOD_END }; static driver_t at91_aic_driver = { "at91_aic", at91_aic_methods, sizeof(struct aic_softc), }; static devclass_t at91_aic_devclass; #ifdef FDT EARLY_DRIVER_MODULE(at91_aic, simplebus, at91_aic_driver, at91_aic_devclass, NULL, NULL, BUS_PASS_INTERRUPT); #else EARLY_DRIVER_MODULE(at91_aic, atmelarm, at91_aic_driver, at91_aic_devclass, NULL, NULL, BUS_PASS_INTERRUPT); #endif Index: head/sys/arm/at91/at91_common.c =================================================================== --- head/sys/arm/at91/at91_common.c (revision 333141) +++ head/sys/arm/at91/at91_common.c (revision 333142) @@ -1,121 +1,121 @@ /*- - * Copyright (c) 2014 M. Warner Losh. All rights reserved. + * Copyright (c) 2014 M. Warner Losh. * * 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$"); #define _ARM32_BUS_DMA_PRIVATE #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include extern const struct devmap_entry at91_devmap[]; #ifndef INTRNG static int fdt_aic_decode_ic(phandle_t node, pcell_t *intr, int *interrupt, int *trig, int *pol) { int offset; if (ofw_bus_node_is_compatible(node, "atmel,at91rm9200-aic")) offset = 0; else return (ENXIO); *interrupt = fdt32_to_cpu(intr[0]) + offset; *trig = INTR_TRIGGER_CONFORM; *pol = INTR_POLARITY_CONFORM; return (0); } fdt_pic_decode_t fdt_pic_table[] = { &fdt_aic_decode_ic, NULL }; #endif static void at91_eoi(void *unused) { uint32_t *eoicr = (uint32_t *)(0xdffff000 + IC_EOICR); *eoicr = 0; } vm_offset_t platform_lastaddr(void) { return (devmap_lastaddr()); } void platform_probe_and_attach(void) { arm_post_filter = at91_eoi; at91_soc_id(); } int platform_devmap_init(void) { // devmap_add_entry(0xfff00000, 0x00100000); /* 1MB - uart, aic and timers*/ devmap_register_table(at91_devmap); return (0); } void platform_gpio_init(void) { } void platform_late_init(void) { } Index: head/sys/arm/at91/at91_gpio.h =================================================================== --- head/sys/arm/at91/at91_gpio.h (revision 333141) +++ head/sys/arm/at91/at91_gpio.h (revision 333142) @@ -1,298 +1,298 @@ /*- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD * - * Copyright (c) 2014 M. Warner Losh. All rights reserved. + * Copyright (c) 2014 M. Warner Losh. * * 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_AT91_GPIO_H #define ARM_AT91_AT91_GPIO_H typedef uint32_t at91_pin_t; #define AT91_PIN_NONE 0xfffffffful /* No pin / Not GPIO controlled */ /* * Map Atmel PIO pins to a unique number. They are just numbered sequentially. */ #define AT91_PIN_PA0 (at91_pin_t)0 #define AT91_PIN_PA1 (at91_pin_t)1 #define AT91_PIN_PA2 (at91_pin_t)2 #define AT91_PIN_PA3 (at91_pin_t)3 #define AT91_PIN_PA4 (at91_pin_t)4 #define AT91_PIN_PA5 (at91_pin_t)5 #define AT91_PIN_PA6 (at91_pin_t)6 #define AT91_PIN_PA7 (at91_pin_t)7 #define AT91_PIN_PA8 (at91_pin_t)8 #define AT91_PIN_PA9 (at91_pin_t)9 #define AT91_PIN_PA10 (at91_pin_t)10 #define AT91_PIN_PA11 (at91_pin_t)11 #define AT91_PIN_PA12 (at91_pin_t)12 #define AT91_PIN_PA13 (at91_pin_t)13 #define AT91_PIN_PA14 (at91_pin_t)14 #define AT91_PIN_PA15 (at91_pin_t)15 #define AT91_PIN_PA16 (at91_pin_t)16 #define AT91_PIN_PA17 (at91_pin_t)17 #define AT91_PIN_PA18 (at91_pin_t)18 #define AT91_PIN_PA19 (at91_pin_t)19 #define AT91_PIN_PA20 (at91_pin_t)20 #define AT91_PIN_PA21 (at91_pin_t)21 #define AT91_PIN_PA22 (at91_pin_t)22 #define AT91_PIN_PA23 (at91_pin_t)23 #define AT91_PIN_PA24 (at91_pin_t)24 #define AT91_PIN_PA25 (at91_pin_t)25 #define AT91_PIN_PA26 (at91_pin_t)26 #define AT91_PIN_PA27 (at91_pin_t)27 #define AT91_PIN_PA28 (at91_pin_t)28 #define AT91_PIN_PA29 (at91_pin_t)29 #define AT91_PIN_PA30 (at91_pin_t)30 #define AT91_PIN_PA31 (at91_pin_t)31 #define AT91_PIN_PB0 (at91_pin_t)32 #define AT91_PIN_PB1 (at91_pin_t)33 #define AT91_PIN_PB2 (at91_pin_t)34 #define AT91_PIN_PB3 (at91_pin_t)35 #define AT91_PIN_PB4 (at91_pin_t)36 #define AT91_PIN_PB5 (at91_pin_t)37 #define AT91_PIN_PB6 (at91_pin_t)38 #define AT91_PIN_PB7 (at91_pin_t)39 #define AT91_PIN_PB8 (at91_pin_t)40 #define AT91_PIN_PB9 (at91_pin_t)41 #define AT91_PIN_PB10 (at91_pin_t)42 #define AT91_PIN_PB11 (at91_pin_t)43 #define AT91_PIN_PB12 (at91_pin_t)44 #define AT91_PIN_PB13 (at91_pin_t)45 #define AT91_PIN_PB14 (at91_pin_t)46 #define AT91_PIN_PB15 (at91_pin_t)47 #define AT91_PIN_PB16 (at91_pin_t)48 #define AT91_PIN_PB17 (at91_pin_t)49 #define AT91_PIN_PB18 (at91_pin_t)50 #define AT91_PIN_PB19 (at91_pin_t)51 #define AT91_PIN_PB20 (at91_pin_t)52 #define AT91_PIN_PB21 (at91_pin_t)53 #define AT91_PIN_PB22 (at91_pin_t)54 #define AT91_PIN_PB23 (at91_pin_t)55 #define AT91_PIN_PB24 (at91_pin_t)56 #define AT91_PIN_PB25 (at91_pin_t)57 #define AT91_PIN_PB26 (at91_pin_t)58 #define AT91_PIN_PB27 (at91_pin_t)59 #define AT91_PIN_PB28 (at91_pin_t)60 #define AT91_PIN_PB29 (at91_pin_t)61 #define AT91_PIN_PB30 (at91_pin_t)62 #define AT91_PIN_PB31 (at91_pin_t)63 #define AT91_PIN_PC0 (at91_pin_t)64 #define AT91_PIN_PC1 (at91_pin_t)65 #define AT91_PIN_PC2 (at91_pin_t)66 #define AT91_PIN_PC3 (at91_pin_t)67 #define AT91_PIN_PC4 (at91_pin_t)68 #define AT91_PIN_PC5 (at91_pin_t)69 #define AT91_PIN_PC6 (at91_pin_t)70 #define AT91_PIN_PC7 (at91_pin_t)71 #define AT91_PIN_PC8 (at91_pin_t)72 #define AT91_PIN_PC9 (at91_pin_t)73 #define AT91_PIN_PC10 (at91_pin_t)74 #define AT91_PIN_PC11 (at91_pin_t)75 #define AT91_PIN_PC12 (at91_pin_t)76 #define AT91_PIN_PC13 (at91_pin_t)77 #define AT91_PIN_PC14 (at91_pin_t)78 #define AT91_PIN_PC15 (at91_pin_t)79 #define AT91_PIN_PC16 (at91_pin_t)80 #define AT91_PIN_PC17 (at91_pin_t)81 #define AT91_PIN_PC18 (at91_pin_t)82 #define AT91_PIN_PC19 (at91_pin_t)83 #define AT91_PIN_PC20 (at91_pin_t)84 #define AT91_PIN_PC21 (at91_pin_t)85 #define AT91_PIN_PC22 (at91_pin_t)86 #define AT91_PIN_PC23 (at91_pin_t)87 #define AT91_PIN_PC24 (at91_pin_t)88 #define AT91_PIN_PC25 (at91_pin_t)89 #define AT91_PIN_PC26 (at91_pin_t)90 #define AT91_PIN_PC27 (at91_pin_t)91 #define AT91_PIN_PC28 (at91_pin_t)92 #define AT91_PIN_PC29 (at91_pin_t)93 #define AT91_PIN_PC30 (at91_pin_t)94 #define AT91_PIN_PC31 (at91_pin_t)95 #define AT91_PIN_PD0 (at91_pin_t)96 #define AT91_PIN_PD1 (at91_pin_t)97 #define AT91_PIN_PD2 (at91_pin_t)98 #define AT91_PIN_PD3 (at91_pin_t)99 #define AT91_PIN_PD4 (at91_pin_t)100 #define AT91_PIN_PD5 (at91_pin_t)101 #define AT91_PIN_PD6 (at91_pin_t)102 #define AT91_PIN_PD7 (at91_pin_t)103 #define AT91_PIN_PD8 (at91_pin_t)104 #define AT91_PIN_PD9 (at91_pin_t)105 #define AT91_PIN_PD10 (at91_pin_t)106 #define AT91_PIN_PD11 (at91_pin_t)107 #define AT91_PIN_PD12 (at91_pin_t)108 #define AT91_PIN_PD13 (at91_pin_t)109 #define AT91_PIN_PD14 (at91_pin_t)110 #define AT91_PIN_PD15 (at91_pin_t)111 #define AT91_PIN_PD16 (at91_pin_t)112 #define AT91_PIN_PD17 (at91_pin_t)113 #define AT91_PIN_PD18 (at91_pin_t)114 #define AT91_PIN_PD19 (at91_pin_t)115 #define AT91_PIN_PD20 (at91_pin_t)116 #define AT91_PIN_PD21 (at91_pin_t)117 #define AT91_PIN_PD22 (at91_pin_t)118 #define AT91_PIN_PD23 (at91_pin_t)119 #define AT91_PIN_PD24 (at91_pin_t)120 #define AT91_PIN_PD25 (at91_pin_t)121 #define AT91_PIN_PD26 (at91_pin_t)122 #define AT91_PIN_PD27 (at91_pin_t)123 #define AT91_PIN_PD28 (at91_pin_t)124 #define AT91_PIN_PD29 (at91_pin_t)125 #define AT91_PIN_PD30 (at91_pin_t)126 #define AT91_PIN_PD31 (at91_pin_t)127 #define AT91_PIN_PE0 (at91_pin_t)128 #define AT91_PIN_PE1 (at91_pin_t)129 #define AT91_PIN_PE2 (at91_pin_t)130 #define AT91_PIN_PE3 (at91_pin_t)131 #define AT91_PIN_PE4 (at91_pin_t)132 #define AT91_PIN_PE5 (at91_pin_t)133 #define AT91_PIN_PE6 (at91_pin_t)134 #define AT91_PIN_PE7 (at91_pin_t)135 #define AT91_PIN_PE8 (at91_pin_t)136 #define AT91_PIN_PE9 (at91_pin_t)137 #define AT91_PIN_PE10 (at91_pin_t)138 #define AT91_PIN_PE11 (at91_pin_t)139 #define AT91_PIN_PE12 (at91_pin_t)140 #define AT91_PIN_PE13 (at91_pin_t)141 #define AT91_PIN_PE14 (at91_pin_t)142 #define AT91_PIN_PE15 (at91_pin_t)143 #define AT91_PIN_PE16 (at91_pin_t)144 #define AT91_PIN_PE17 (at91_pin_t)145 #define AT91_PIN_PE18 (at91_pin_t)146 #define AT91_PIN_PE19 (at91_pin_t)147 #define AT91_PIN_PE20 (at91_pin_t)148 #define AT91_PIN_PE21 (at91_pin_t)149 #define AT91_PIN_PE22 (at91_pin_t)150 #define AT91_PIN_PE23 (at91_pin_t)151 #define AT91_PIN_PE24 (at91_pin_t)152 #define AT91_PIN_PE25 (at91_pin_t)153 #define AT91_PIN_PE26 (at91_pin_t)154 #define AT91_PIN_PE27 (at91_pin_t)155 #define AT91_PIN_PE28 (at91_pin_t)156 #define AT91_PIN_PE29 (at91_pin_t)157 #define AT91_PIN_PE30 (at91_pin_t)158 #define AT91_PIN_PE31 (at91_pin_t)159 #define AT91_PIN_PF0 (at91_pin_t)160 #define AT91_PIN_PF1 (at91_pin_t)161 #define AT91_PIN_PF2 (at91_pin_t)162 #define AT91_PIN_PF3 (at91_pin_t)163 #define AT91_PIN_PF4 (at91_pin_t)164 #define AT91_PIN_PF5 (at91_pin_t)165 #define AT91_PIN_PF6 (at91_pin_t)166 #define AT91_PIN_PF7 (at91_pin_t)167 #define AT91_PIN_PF8 (at91_pin_t)168 #define AT91_PIN_PF9 (at91_pin_t)169 #define AT91_PIN_PF10 (at91_pin_t)170 #define AT91_PIN_PF11 (at91_pin_t)171 #define AT91_PIN_PF12 (at91_pin_t)172 #define AT91_PIN_PF13 (at91_pin_t)173 #define AT91_PIN_PF14 (at91_pin_t)174 #define AT91_PIN_PF15 (at91_pin_t)175 #define AT91_PIN_PF16 (at91_pin_t)176 #define AT91_PIN_PF17 (at91_pin_t)177 #define AT91_PIN_PF18 (at91_pin_t)178 #define AT91_PIN_PF19 (at91_pin_t)179 #define AT91_PIN_PF20 (at91_pin_t)180 #define AT91_PIN_PF21 (at91_pin_t)181 #define AT91_PIN_PF22 (at91_pin_t)182 #define AT91_PIN_PF23 (at91_pin_t)183 #define AT91_PIN_PF24 (at91_pin_t)184 #define AT91_PIN_PF25 (at91_pin_t)185 #define AT91_PIN_PF26 (at91_pin_t)186 #define AT91_PIN_PF27 (at91_pin_t)187 #define AT91_PIN_PF28 (at91_pin_t)188 #define AT91_PIN_PF29 (at91_pin_t)189 #define AT91_PIN_PF30 (at91_pin_t)190 #define AT91_PIN_PF31 (at91_pin_t)191 #define AT91_PIN_PG0 (at91_pin_t)192 #define AT91_PIN_PG1 (at91_pin_t)193 #define AT91_PIN_PG2 (at91_pin_t)194 #define AT91_PIN_PG3 (at91_pin_t)195 #define AT91_PIN_PG4 (at91_pin_t)196 #define AT91_PIN_PG5 (at91_pin_t)197 #define AT91_PIN_PG6 (at91_pin_t)198 #define AT91_PIN_PG7 (at91_pin_t)199 #define AT91_PIN_PG8 (at91_pin_t)200 #define AT91_PIN_PG9 (at91_pin_t)201 #define AT91_PIN_PG10 (at91_pin_t)202 #define AT91_PIN_PG11 (at91_pin_t)203 #define AT91_PIN_PG12 (at91_pin_t)204 #define AT91_PIN_PG13 (at91_pin_t)205 #define AT91_PIN_PG14 (at91_pin_t)206 #define AT91_PIN_PG15 (at91_pin_t)207 #define AT91_PIN_PG16 (at91_pin_t)208 #define AT91_PIN_PG17 (at91_pin_t)209 #define AT91_PIN_PG18 (at91_pin_t)210 #define AT91_PIN_PG19 (at91_pin_t)211 #define AT91_PIN_PG20 (at91_pin_t)212 #define AT91_PIN_PG21 (at91_pin_t)213 #define AT91_PIN_PG22 (at91_pin_t)214 #define AT91_PIN_PG23 (at91_pin_t)215 #define AT91_PIN_PG24 (at91_pin_t)216 #define AT91_PIN_PG25 (at91_pin_t)217 #define AT91_PIN_PG26 (at91_pin_t)218 #define AT91_PIN_PG27 (at91_pin_t)219 #define AT91_PIN_PG28 (at91_pin_t)220 #define AT91_PIN_PG29 (at91_pin_t)221 #define AT91_PIN_PG30 (at91_pin_t)222 #define AT91_PIN_PG31 (at91_pin_t)223 #define AT91_PIN_PH0 (at91_pin_t)224 #define AT91_PIN_PH1 (at91_pin_t)225 #define AT91_PIN_PH2 (at91_pin_t)226 #define AT91_PIN_PH3 (at91_pin_t)227 #define AT91_PIN_PH4 (at91_pin_t)228 #define AT91_PIN_PH5 (at91_pin_t)229 #define AT91_PIN_PH6 (at91_pin_t)230 #define AT91_PIN_PH7 (at91_pin_t)231 #define AT91_PIN_PH8 (at91_pin_t)232 #define AT91_PIN_PH9 (at91_pin_t)233 #define AT91_PIN_PH10 (at91_pin_t)234 #define AT91_PIN_PH11 (at91_pin_t)235 #define AT91_PIN_PH12 (at91_pin_t)236 #define AT91_PIN_PH13 (at91_pin_t)237 #define AT91_PIN_PH14 (at91_pin_t)238 #define AT91_PIN_PH15 (at91_pin_t)239 #define AT91_PIN_PH16 (at91_pin_t)240 #define AT91_PIN_PH17 (at91_pin_t)241 #define AT91_PIN_PH18 (at91_pin_t)242 #define AT91_PIN_PH19 (at91_pin_t)243 #define AT91_PIN_PH20 (at91_pin_t)244 #define AT91_PIN_PH21 (at91_pin_t)245 #define AT91_PIN_PH22 (at91_pin_t)246 #define AT91_PIN_PH23 (at91_pin_t)247 #define AT91_PIN_PH24 (at91_pin_t)248 #define AT91_PIN_PH25 (at91_pin_t)249 #define AT91_PIN_PH26 (at91_pin_t)250 #define AT91_PIN_PH27 (at91_pin_t)251 #define AT91_PIN_PH28 (at91_pin_t)252 #define AT91_PIN_PH29 (at91_pin_t)253 #define AT91_PIN_PH30 (at91_pin_t)254 #define AT91_PIN_PH31 (at91_pin_t)255 #endif /* ARM_AT91_AT91_GPIO_H */ Index: head/sys/arm/at91/at91_mci.c =================================================================== --- head/sys/arm/at91/at91_mci.c (revision 333141) +++ head/sys/arm/at91/at91_mci.c (revision 333142) @@ -1,1406 +1,1406 @@ /*- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD * * Copyright (c) 2006 Bernd Walter. All rights reserved. - * Copyright (c) 2006 M. Warner Losh. All rights reserved. + * Copyright (c) 2006 M. Warner Losh. * Copyright (c) 2010 Greg Ansley. 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 "opt_platform.h" #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef FDT #include #include #endif #include "mmcbr_if.h" #include "opt_at91.h" /* * About running the MCI bus above 25MHz * * Historically, the MCI bus has been run at 30MHz on systems with a 60MHz * master clock, in part due to a bug in dev/mmc.c making always request * 30MHz, and in part over clocking the bus because 15MHz was too slow. * Fixing that bug causes the mmc driver to request a 25MHz clock (as it * should) and the logic in at91_mci_update_ios() picks the highest speed that * doesn't exceed that limit. With a 60MHz MCK that would be 15MHz, and * that's a real performance buzzkill when you've been getting away with 30MHz * all along. * * By defining AT91_MCI_ALLOW_OVERCLOCK (or setting the allow_overclock=1 * device hint or sysctl) you can enable logic in at91_mci_update_ios() to * overlcock the SD bus a little by running it at MCK / 2 when the requested * speed is 25MHz and the next highest speed is 15MHz or less. This appears * to work on virtually all SD cards, since it is what this driver has been * doing prior to the introduction of this option, where the overclocking vs * underclocking decision was automatically "overclock". Modern SD cards can * run at 45mhz/1-bit in standard mode (high speed mode enable commands not * sent) without problems. * * Speaking of high-speed mode, the rm9200 manual says the MCI device supports * the SD v1.0 specification and can run up to 50MHz. This is interesting in * that the SD v1.0 spec caps the speed at 25MHz; high speed mode was added in * the v1.10 spec. Furthermore, high speed mode doesn't just crank up the * clock, it alters the signal timing. The rm9200 MCI device doesn't support * these altered timings. So while speeds over 25MHz may work, they only work * in what the SD spec calls "default" speed mode, and it amounts to violating * the spec by overclocking the bus. * * If you also enable 4-wire mode it's possible transfers faster than 25MHz * will fail. On the AT91RM9200, due to bugs in the bus contention logic, if * you have the USB host device and OHCI driver enabled will fail. Even * underclocking to 15MHz, intermittant overrun and underrun errors occur. * Note that you don't even need to have usb devices attached to the system, * the errors begin to occur as soon as the OHCI driver sets the register bit * to enable periodic transfers. It appears (based on brief investigation) * that the usb host controller uses so much ASB bandwidth that sometimes the * DMA for MCI transfers doesn't get a bus grant in time and data gets * dropped. Adding even a modicum of network activity changes the symptom * from intermittant to very frequent. Members of the AT91SAM9 family have * corrected this problem, or are at least better about their use of the bus. */ #ifndef AT91_MCI_ALLOW_OVERCLOCK #define AT91_MCI_ALLOW_OVERCLOCK 1 #endif /* * Allocate 2 bounce buffers we'll use to endian-swap the data due to the rm9200 * erratum. We use a pair of buffers because when reading that lets us begin * endian-swapping the data in the first buffer while the DMA is reading into * the second buffer. (We can't use the same trick for writing because we might * not get all the data in the 2nd buffer swapped before the hardware needs it; * dealing with that would add complexity to the driver.) * * The buffers are sized at 16K each due to the way the busdma cache sync * operations work on arm. A dcache_inv_range() operation on a range larger * than 16K gets turned into a dcache_wbinv_all(). That needlessly flushes the * entire data cache, impacting overall system performance. */ #define BBCOUNT 2 #define BBSIZE (16*1024) #define MAX_BLOCKS ((BBSIZE*BBCOUNT)/512) static int mci_debug; struct at91_mci_softc { void *intrhand; /* Interrupt handle */ device_t dev; int sc_cap; #define CAP_HAS_4WIRE 1 /* Has 4 wire bus */ #define CAP_NEEDS_BYTESWAP 2 /* broken hardware needing bounce */ #define CAP_MCI1_REV2XX 4 /* MCI 1 rev 2.x */ int flags; #define PENDING_CMD 0x01 #define PENDING_STOP 0x02 #define CMD_MULTIREAD 0x10 #define CMD_MULTIWRITE 0x20 int has_4wire; int allow_overclock; struct resource *irq_res; /* IRQ resource */ struct resource *mem_res; /* Memory resource */ struct mtx sc_mtx; bus_dma_tag_t dmatag; struct mmc_host host; int bus_busy; struct mmc_request *req; struct mmc_command *curcmd; bus_dmamap_t bbuf_map[BBCOUNT]; char * bbuf_vaddr[BBCOUNT]; /* bounce bufs in KVA space */ uint32_t bbuf_len[BBCOUNT]; /* len currently queued for bounce buf */ uint32_t bbuf_curidx; /* which bbuf is the active DMA buffer */ uint32_t xfer_offset; /* offset so far into caller's buf */ }; /* bus entry points */ static int at91_mci_probe(device_t dev); static int at91_mci_attach(device_t dev); static int at91_mci_detach(device_t dev); static void at91_mci_intr(void *); /* helper routines */ static int at91_mci_activate(device_t dev); static void at91_mci_deactivate(device_t dev); static int at91_mci_is_mci1rev2xx(void); #define AT91_MCI_LOCK(_sc) mtx_lock(&(_sc)->sc_mtx) #define AT91_MCI_UNLOCK(_sc) mtx_unlock(&(_sc)->sc_mtx) #define AT91_MCI_LOCK_INIT(_sc) \ mtx_init(&_sc->sc_mtx, device_get_nameunit(_sc->dev), \ "mci", MTX_DEF) #define AT91_MCI_LOCK_DESTROY(_sc) mtx_destroy(&_sc->sc_mtx); #define AT91_MCI_ASSERT_LOCKED(_sc) mtx_assert(&_sc->sc_mtx, MA_OWNED); #define AT91_MCI_ASSERT_UNLOCKED(_sc) mtx_assert(&_sc->sc_mtx, MA_NOTOWNED); static inline uint32_t RD4(struct at91_mci_softc *sc, bus_size_t off) { return (bus_read_4(sc->mem_res, off)); } static inline void WR4(struct at91_mci_softc *sc, bus_size_t off, uint32_t val) { bus_write_4(sc->mem_res, off, val); } static void at91_bswap_buf(struct at91_mci_softc *sc, void * dptr, void * sptr, uint32_t memsize) { uint32_t * dst = (uint32_t *)dptr; uint32_t * src = (uint32_t *)sptr; uint32_t i; /* * If the hardware doesn't need byte-swapping, let bcopy() do the * work. Use bounce buffer even if we don't need byteswap, since * buffer may straddle a page boundary, and we don't handle * multi-segment transfers in hardware. Seen from 'bsdlabel -w' which * uses raw geom access to the volume. Greg Ansley (gja (at) * ansley.com) */ if (!(sc->sc_cap & CAP_NEEDS_BYTESWAP)) { memcpy(dptr, sptr, memsize); return; } /* * Nice performance boost for slightly unrolling this loop. * (But very little extra boost for further unrolling it.) */ for (i = 0; i < memsize; i += 16) { *dst++ = bswap32(*src++); *dst++ = bswap32(*src++); *dst++ = bswap32(*src++); *dst++ = bswap32(*src++); } /* Mop up the last 1-3 words, if any. */ for (i = 0; i < (memsize & 0x0F); i += 4) { *dst++ = bswap32(*src++); } } static void at91_mci_getaddr(void *arg, bus_dma_segment_t *segs, int nsegs, int error) { if (error != 0) return; *(bus_addr_t *)arg = segs[0].ds_addr; } static void at91_mci_pdc_disable(struct at91_mci_softc *sc) { WR4(sc, PDC_PTCR, PDC_PTCR_TXTDIS | PDC_PTCR_RXTDIS); WR4(sc, PDC_RPR, 0); WR4(sc, PDC_RCR, 0); WR4(sc, PDC_RNPR, 0); WR4(sc, PDC_RNCR, 0); WR4(sc, PDC_TPR, 0); WR4(sc, PDC_TCR, 0); WR4(sc, PDC_TNPR, 0); WR4(sc, PDC_TNCR, 0); } /* * Reset the controller, then restore most of the current state. * * This is called after detecting an error. It's also called after stopping a * multi-block write, to un-wedge the device so that it will handle the NOTBUSY * signal correctly. See comments in at91_mci_stop_done() for more details. */ static void at91_mci_reset(struct at91_mci_softc *sc) { uint32_t mr; uint32_t sdcr; uint32_t dtor; uint32_t imr; at91_mci_pdc_disable(sc); /* save current state */ imr = RD4(sc, MCI_IMR); mr = RD4(sc, MCI_MR) & 0x7fff; sdcr = RD4(sc, MCI_SDCR); dtor = RD4(sc, MCI_DTOR); /* reset the controller */ WR4(sc, MCI_IDR, 0xffffffff); WR4(sc, MCI_CR, MCI_CR_MCIDIS | MCI_CR_SWRST); /* restore state */ WR4(sc, MCI_CR, MCI_CR_MCIEN|MCI_CR_PWSEN); WR4(sc, MCI_MR, mr); WR4(sc, MCI_SDCR, sdcr); WR4(sc, MCI_DTOR, dtor); WR4(sc, MCI_IER, imr); /* * Make sure sdio interrupts will fire. Not sure why reading * SR ensures that, but this is in the linux driver. */ RD4(sc, MCI_SR); } static void at91_mci_init(device_t dev) { struct at91_mci_softc *sc = device_get_softc(dev); uint32_t val; WR4(sc, MCI_CR, MCI_CR_MCIDIS | MCI_CR_SWRST); /* device into reset */ WR4(sc, MCI_IDR, 0xffffffff); /* Turn off interrupts */ WR4(sc, MCI_DTOR, MCI_DTOR_DTOMUL_1M | 1); val = MCI_MR_PDCMODE; val |= 0x34a; /* PWSDIV = 3; CLKDIV = 74 */ // if (sc->sc_cap & CAP_MCI1_REV2XX) // val |= MCI_MR_RDPROOF | MCI_MR_WRPROOF; WR4(sc, MCI_MR, val); #ifndef AT91_MCI_SLOT_B WR4(sc, MCI_SDCR, 0); /* SLOT A, 1 bit bus */ #else /* * XXX Really should add second "unit" but nobody using using * a two slot card that we know of. XXX */ WR4(sc, MCI_SDCR, 1); /* SLOT B, 1 bit bus */ #endif /* * Enable controller, including power-save. The slower clock * of the power-save mode is only in effect when there is no * transfer in progress, so it can be left in this mode all * the time. */ WR4(sc, MCI_CR, MCI_CR_MCIEN|MCI_CR_PWSEN); } static void at91_mci_fini(device_t dev) { struct at91_mci_softc *sc = device_get_softc(dev); WR4(sc, MCI_IDR, 0xffffffff); /* Turn off interrupts */ at91_mci_pdc_disable(sc); WR4(sc, MCI_CR, MCI_CR_MCIDIS | MCI_CR_SWRST); /* device into reset */ } static int at91_mci_probe(device_t dev) { #ifdef FDT if (!ofw_bus_is_compatible(dev, "atmel,hsmci")) return (ENXIO); #endif device_set_desc(dev, "MCI mmc/sd host bridge"); return (0); } static int at91_mci_attach(device_t dev) { struct at91_mci_softc *sc = device_get_softc(dev); struct sysctl_ctx_list *sctx; struct sysctl_oid *soid; device_t child; int err, i; sctx = device_get_sysctl_ctx(dev); soid = device_get_sysctl_tree(dev); sc->dev = dev; sc->sc_cap = 0; if (at91_is_rm92()) sc->sc_cap |= CAP_NEEDS_BYTESWAP; /* * MCI1 Rev 2 controllers need some workarounds, flag if so. */ if (at91_mci_is_mci1rev2xx()) sc->sc_cap |= CAP_MCI1_REV2XX; err = at91_mci_activate(dev); if (err) goto out; AT91_MCI_LOCK_INIT(sc); at91_mci_fini(dev); at91_mci_init(dev); /* * Allocate DMA tags and maps and bounce buffers. * * The parms in the tag_create call cause the dmamem_alloc call to * create each bounce buffer as a single contiguous buffer of BBSIZE * bytes aligned to a 4096 byte boundary. * * Do not use DMA_COHERENT for these buffers because that maps the * memory as non-cachable, which prevents cache line burst fills/writes, * which is something we need since we're trying to overlap the * byte-swapping with the DMA operations. */ err = bus_dma_tag_create(bus_get_dma_tag(dev), 4096, 0, BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, NULL, NULL, BBSIZE, 1, BBSIZE, 0, NULL, NULL, &sc->dmatag); if (err != 0) goto out; for (i = 0; i < BBCOUNT; ++i) { err = bus_dmamem_alloc(sc->dmatag, (void **)&sc->bbuf_vaddr[i], BUS_DMA_NOWAIT, &sc->bbuf_map[i]); if (err != 0) goto out; } /* * Activate the interrupt */ err = bus_setup_intr(dev, sc->irq_res, INTR_TYPE_MISC | INTR_MPSAFE, NULL, at91_mci_intr, sc, &sc->intrhand); if (err) { AT91_MCI_LOCK_DESTROY(sc); goto out; } /* * Allow 4-wire to be initially set via #define. * Allow a device hint to override that. * Allow a sysctl to override that. */ #if defined(AT91_MCI_HAS_4WIRE) && AT91_MCI_HAS_4WIRE != 0 sc->has_4wire = 1; #endif resource_int_value(device_get_name(dev), device_get_unit(dev), "4wire", &sc->has_4wire); SYSCTL_ADD_UINT(sctx, SYSCTL_CHILDREN(soid), OID_AUTO, "4wire", CTLFLAG_RW, &sc->has_4wire, 0, "has 4 wire SD Card bus"); if (sc->has_4wire) sc->sc_cap |= CAP_HAS_4WIRE; sc->allow_overclock = AT91_MCI_ALLOW_OVERCLOCK; resource_int_value(device_get_name(dev), device_get_unit(dev), "allow_overclock", &sc->allow_overclock); SYSCTL_ADD_UINT(sctx, SYSCTL_CHILDREN(soid), OID_AUTO, "allow_overclock", CTLFLAG_RW, &sc->allow_overclock, 0, "Allow up to 30MHz clock for 25MHz request when next highest speed 15MHz or less."); SYSCTL_ADD_UINT(sctx, SYSCTL_CHILDREN(soid), OID_AUTO, "debug", CTLFLAG_RWTUN, &mci_debug, 0, "enable debug output"); /* * Our real min freq is master_clock/512, but upper driver layers are * going to set the min speed during card discovery, and the right speed * for that is 400kHz, so advertise a safe value just under that. * * For max speed, while the rm9200 manual says the max is 50mhz, it also * says it supports only the SD v1.0 spec, which means the real limit is * 25mhz. On the other hand, historical use has been to slightly violate * the standard by running the bus at 30MHz. For more information on * that, see the comments at the top of this file. */ sc->host.f_min = 375000; sc->host.f_max = at91_master_clock / 2; if (sc->host.f_max > 25000000) sc->host.f_max = 25000000; sc->host.host_ocr = MMC_OCR_320_330 | MMC_OCR_330_340; sc->host.caps = 0; if (sc->sc_cap & CAP_HAS_4WIRE) sc->host.caps |= MMC_CAP_4_BIT_DATA; child = device_add_child(dev, "mmc", 0); device_set_ivars(dev, &sc->host); err = bus_generic_attach(dev); out: if (err) at91_mci_deactivate(dev); return (err); } static int at91_mci_detach(device_t dev) { struct at91_mci_softc *sc = device_get_softc(dev); at91_mci_fini(dev); at91_mci_deactivate(dev); bus_dmamem_free(sc->dmatag, sc->bbuf_vaddr[0], sc->bbuf_map[0]); bus_dmamem_free(sc->dmatag, sc->bbuf_vaddr[1], sc->bbuf_map[1]); bus_dma_tag_destroy(sc->dmatag); return (EBUSY); /* XXX */ } static int at91_mci_activate(device_t dev) { struct at91_mci_softc *sc; int rid; sc = device_get_softc(dev); rid = 0; sc->mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, RF_ACTIVE); if (sc->mem_res == NULL) goto errout; rid = 0; sc->irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, RF_ACTIVE); if (sc->irq_res == NULL) goto errout; return (0); errout: at91_mci_deactivate(dev); return (ENOMEM); } static void at91_mci_deactivate(device_t dev) { struct at91_mci_softc *sc; sc = device_get_softc(dev); if (sc->intrhand) bus_teardown_intr(dev, sc->irq_res, sc->intrhand); sc->intrhand = NULL; bus_generic_detach(sc->dev); if (sc->mem_res) bus_release_resource(dev, SYS_RES_MEMORY, rman_get_rid(sc->mem_res), sc->mem_res); sc->mem_res = NULL; if (sc->irq_res) bus_release_resource(dev, SYS_RES_IRQ, rman_get_rid(sc->irq_res), sc->irq_res); sc->irq_res = NULL; return; } static int at91_mci_is_mci1rev2xx(void) { switch (soc_info.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); } } static int at91_mci_update_ios(device_t brdev, device_t reqdev) { struct at91_mci_softc *sc; struct mmc_ios *ios; uint32_t clkdiv; uint32_t freq; sc = device_get_softc(brdev); ios = &sc->host.ios; /* * Calculate our closest available clock speed that doesn't exceed the * requested speed. * * When overclocking is allowed, the requested clock is 25MHz, the * computed frequency is 15MHz or smaller and clockdiv is 1, use * clockdiv of 0 to double that. If less than 12.5MHz, double * regardless of the overclocking setting. * * Whatever we come up with, store it back into ios->clock so that the * upper layer drivers can report the actual speed of the bus. */ if (ios->clock == 0) { WR4(sc, MCI_CR, MCI_CR_MCIDIS); clkdiv = 0; } else { WR4(sc, MCI_CR, MCI_CR_MCIEN|MCI_CR_PWSEN); if ((at91_master_clock % (ios->clock * 2)) == 0) clkdiv = ((at91_master_clock / ios->clock) / 2) - 1; else clkdiv = (at91_master_clock / ios->clock) / 2; freq = at91_master_clock / ((clkdiv+1) * 2); if (clkdiv == 1 && ios->clock == 25000000 && freq <= 15000000) { if (sc->allow_overclock || freq <= 12500000) { clkdiv = 0; freq = at91_master_clock / ((clkdiv+1) * 2); } } ios->clock = freq; } if (ios->bus_width == bus_width_4) WR4(sc, MCI_SDCR, RD4(sc, MCI_SDCR) | MCI_SDCR_SDCBUS); else WR4(sc, MCI_SDCR, RD4(sc, MCI_SDCR) & ~MCI_SDCR_SDCBUS); WR4(sc, MCI_MR, (RD4(sc, MCI_MR) & ~MCI_MR_CLKDIV) | clkdiv); /* Do we need a settle time here? */ /* XXX We need to turn the device on/off here with a GPIO pin */ return (0); } static void at91_mci_start_cmd(struct at91_mci_softc *sc, struct mmc_command *cmd) { uint32_t cmdr, mr; struct mmc_data *data; sc->curcmd = cmd; data = cmd->data; /* XXX Upper layers don't always set this */ cmd->mrq = sc->req; /* Begin setting up command register. */ cmdr = cmd->opcode; if (sc->host.ios.bus_mode == opendrain) cmdr |= MCI_CMDR_OPDCMD; /* Set up response handling. Allow max timeout for responses. */ if (MMC_RSP(cmd->flags) == MMC_RSP_NONE) cmdr |= MCI_CMDR_RSPTYP_NO; else { cmdr |= MCI_CMDR_MAXLAT; if (cmd->flags & MMC_RSP_136) cmdr |= MCI_CMDR_RSPTYP_136; else cmdr |= MCI_CMDR_RSPTYP_48; } /* * If there is no data transfer, just set up the right interrupt mask * and start the command. * * The interrupt mask needs to be CMDRDY plus all non-data-transfer * errors. It's important to leave the transfer-related errors out, to * avoid spurious timeout or crc errors on a STOP command following a * multiblock read. When a multiblock read is in progress, sending a * STOP in the middle of a block occasionally triggers such errors, but * we're totally disinterested in them because we've already gotten all * the data we wanted without error before sending the STOP command. */ if (data == NULL) { uint32_t ier = MCI_SR_CMDRDY | MCI_SR_RTOE | MCI_SR_RENDE | MCI_SR_RCRCE | MCI_SR_RDIRE | MCI_SR_RINDE; at91_mci_pdc_disable(sc); if (cmd->opcode == MMC_STOP_TRANSMISSION) cmdr |= MCI_CMDR_TRCMD_STOP; /* Ignore response CRC on CMD2 and ACMD41, per standard. */ if (cmd->opcode == MMC_SEND_OP_COND || cmd->opcode == ACMD_SD_SEND_OP_COND) ier &= ~MCI_SR_RCRCE; if (mci_debug) printf("CMDR %x (opcode %d) ARGR %x no data\n", cmdr, cmd->opcode, cmd->arg); WR4(sc, MCI_ARGR, cmd->arg); WR4(sc, MCI_CMDR, cmdr); WR4(sc, MCI_IDR, 0xffffffff); WR4(sc, MCI_IER, ier); return; } /* There is data, set up the transfer-related parts of the command. */ if (data->flags & MMC_DATA_READ) cmdr |= MCI_CMDR_TRDIR; if (data->flags & (MMC_DATA_READ | MMC_DATA_WRITE)) cmdr |= MCI_CMDR_TRCMD_START; if (data->flags & MMC_DATA_STREAM) cmdr |= MCI_CMDR_TRTYP_STREAM; else if (data->flags & MMC_DATA_MULTI) { cmdr |= MCI_CMDR_TRTYP_MULTIPLE; sc->flags |= (data->flags & MMC_DATA_READ) ? CMD_MULTIREAD : CMD_MULTIWRITE; } /* * Disable PDC until we're ready. * * Set block size and turn on PDC mode for dma xfer. * Note that the block size is the smaller of the amount of data to be * transferred, or 512 bytes. The 512 size is fixed by the standard; * smaller blocks are possible, but never larger. */ WR4(sc, PDC_PTCR, PDC_PTCR_RXTDIS | PDC_PTCR_TXTDIS); mr = RD4(sc,MCI_MR) & ~MCI_MR_BLKLEN; mr |= min(data->len, 512) << 16; WR4(sc, MCI_MR, mr | MCI_MR_PDCMODE|MCI_MR_PDCPADV); /* * Set up DMA. * * Use bounce buffers even if we don't need to byteswap, because doing * multi-block IO with large DMA buffers is way fast (compared to * single-block IO), even after incurring the overhead of also copying * from/to the caller's buffers (which may be in non-contiguous physical * pages). * * In an ideal non-byteswap world we could create a dma tag that allows * for discontiguous segments and do the IO directly from/to the * caller's buffer(s), using ENDRX/ENDTX interrupts to chain the * discontiguous buffers through the PDC. Someday. * * If a read is bigger than 2k, split it in half so that we can start * byte-swapping the first half while the second half is on the wire. * It would be best if we could split it into 8k chunks, but we can't * always keep up with the byte-swapping due to other system activity, * and if an RXBUFF interrupt happens while we're still handling the * byte-swap from the prior buffer (IE, we haven't returned from * handling the prior interrupt yet), then data will get dropped on the * floor and we can't easily recover from that. The right fix for that * would be to have the interrupt handling only keep the DMA flowing and * enqueue filled buffers to be byte-swapped in a non-interrupt context. * Even that won't work on the write side of things though; in that * context we have to have all the data ready to go before starting the * dma. * * XXX what about stream transfers? */ sc->xfer_offset = 0; sc->bbuf_curidx = 0; if (data->flags & (MMC_DATA_READ | MMC_DATA_WRITE)) { uint32_t len; uint32_t remaining = data->len; bus_addr_t paddr; int err; if (remaining > (BBCOUNT*BBSIZE)) panic("IO read size exceeds MAXDATA\n"); if (data->flags & MMC_DATA_READ) { if (remaining > 2048) // XXX len = remaining / 2; else len = remaining; err = bus_dmamap_load(sc->dmatag, sc->bbuf_map[0], sc->bbuf_vaddr[0], len, at91_mci_getaddr, &paddr, BUS_DMA_NOWAIT); if (err != 0) panic("IO read dmamap_load failed\n"); bus_dmamap_sync(sc->dmatag, sc->bbuf_map[0], BUS_DMASYNC_PREREAD); WR4(sc, PDC_RPR, paddr); WR4(sc, PDC_RCR, len / 4); sc->bbuf_len[0] = len; remaining -= len; if (remaining == 0) { sc->bbuf_len[1] = 0; } else { len = remaining; err = bus_dmamap_load(sc->dmatag, sc->bbuf_map[1], sc->bbuf_vaddr[1], len, at91_mci_getaddr, &paddr, BUS_DMA_NOWAIT); if (err != 0) panic("IO read dmamap_load failed\n"); bus_dmamap_sync(sc->dmatag, sc->bbuf_map[1], BUS_DMASYNC_PREREAD); WR4(sc, PDC_RNPR, paddr); WR4(sc, PDC_RNCR, len / 4); sc->bbuf_len[1] = len; remaining -= len; } WR4(sc, PDC_PTCR, PDC_PTCR_RXTEN); } else { len = min(BBSIZE, remaining); at91_bswap_buf(sc, sc->bbuf_vaddr[0], data->data, len); err = bus_dmamap_load(sc->dmatag, sc->bbuf_map[0], sc->bbuf_vaddr[0], len, at91_mci_getaddr, &paddr, BUS_DMA_NOWAIT); if (err != 0) panic("IO write dmamap_load failed\n"); bus_dmamap_sync(sc->dmatag, sc->bbuf_map[0], BUS_DMASYNC_PREWRITE); /* * Erratum workaround: PDC transfer length on a write * must not be smaller than 12 bytes (3 words); only * blklen bytes (set above) are actually transferred. */ WR4(sc, PDC_TPR,paddr); WR4(sc, PDC_TCR, (len < 12) ? 3 : len / 4); sc->bbuf_len[0] = len; remaining -= len; if (remaining == 0) { sc->bbuf_len[1] = 0; } else { len = remaining; at91_bswap_buf(sc, sc->bbuf_vaddr[1], ((char *)data->data)+BBSIZE, len); err = bus_dmamap_load(sc->dmatag, sc->bbuf_map[1], sc->bbuf_vaddr[1], len, at91_mci_getaddr, &paddr, BUS_DMA_NOWAIT); if (err != 0) panic("IO write dmamap_load failed\n"); bus_dmamap_sync(sc->dmatag, sc->bbuf_map[1], BUS_DMASYNC_PREWRITE); WR4(sc, PDC_TNPR, paddr); WR4(sc, PDC_TNCR, (len < 12) ? 3 : len / 4); sc->bbuf_len[1] = len; remaining -= len; } /* do not enable PDC xfer until CMDRDY asserted */ } data->xfer_len = 0; /* XXX what's this? appears to be unused. */ } if (mci_debug) printf("CMDR %x (opcode %d) ARGR %x with data len %d\n", cmdr, cmd->opcode, cmd->arg, cmd->data->len); WR4(sc, MCI_ARGR, cmd->arg); WR4(sc, MCI_CMDR, cmdr); WR4(sc, MCI_IER, MCI_SR_ERROR | MCI_SR_CMDRDY); } static void at91_mci_next_operation(struct at91_mci_softc *sc) { struct mmc_request *req; req = sc->req; if (req == NULL) return; if (sc->flags & PENDING_CMD) { sc->flags &= ~PENDING_CMD; at91_mci_start_cmd(sc, req->cmd); return; } else if (sc->flags & PENDING_STOP) { sc->flags &= ~PENDING_STOP; at91_mci_start_cmd(sc, req->stop); return; } WR4(sc, MCI_IDR, 0xffffffff); sc->req = NULL; sc->curcmd = NULL; //printf("req done\n"); req->done(req); } static int at91_mci_request(device_t brdev, device_t reqdev, struct mmc_request *req) { struct at91_mci_softc *sc = device_get_softc(brdev); AT91_MCI_LOCK(sc); if (sc->req != NULL) { AT91_MCI_UNLOCK(sc); return (EBUSY); } //printf("new req\n"); sc->req = req; sc->flags = PENDING_CMD; if (sc->req->stop) sc->flags |= PENDING_STOP; at91_mci_next_operation(sc); AT91_MCI_UNLOCK(sc); return (0); } static int at91_mci_get_ro(device_t brdev, device_t reqdev) { return (0); } static int at91_mci_acquire_host(device_t brdev, device_t reqdev) { struct at91_mci_softc *sc = device_get_softc(brdev); int err = 0; AT91_MCI_LOCK(sc); while (sc->bus_busy) msleep(sc, &sc->sc_mtx, PZERO, "mciah", hz / 5); sc->bus_busy++; AT91_MCI_UNLOCK(sc); return (err); } static int at91_mci_release_host(device_t brdev, device_t reqdev) { struct at91_mci_softc *sc = device_get_softc(brdev); AT91_MCI_LOCK(sc); sc->bus_busy--; wakeup(sc); AT91_MCI_UNLOCK(sc); return (0); } static void at91_mci_read_done(struct at91_mci_softc *sc, uint32_t sr) { struct mmc_command *cmd = sc->curcmd; char * dataptr = (char *)cmd->data->data; uint32_t curidx = sc->bbuf_curidx; uint32_t len = sc->bbuf_len[curidx]; /* * We arrive here when a DMA transfer for a read is done, whether it's * a single or multi-block read. * * We byte-swap the buffer that just completed, and if that is the * last buffer that's part of this read then we move on to the next * operation, otherwise we wait for another ENDRX for the next bufer. */ bus_dmamap_sync(sc->dmatag, sc->bbuf_map[curidx], BUS_DMASYNC_POSTREAD); bus_dmamap_unload(sc->dmatag, sc->bbuf_map[curidx]); at91_bswap_buf(sc, dataptr + sc->xfer_offset, sc->bbuf_vaddr[curidx], len); if (mci_debug) { printf("read done sr %x curidx %d len %d xfer_offset %d\n", sr, curidx, len, sc->xfer_offset); } sc->xfer_offset += len; sc->bbuf_curidx = !curidx; /* swap buffers */ /* * If we've transferred all the data, move on to the next operation. * * If we're still transferring the last buffer, RNCR is already zero but * we have to write a zero anyway to clear the ENDRX status so we don't * re-interrupt until the last buffer is done. */ if (sc->xfer_offset == cmd->data->len) { WR4(sc, PDC_PTCR, PDC_PTCR_RXTDIS | PDC_PTCR_TXTDIS); cmd->error = MMC_ERR_NONE; at91_mci_next_operation(sc); } else { WR4(sc, PDC_RNCR, 0); WR4(sc, MCI_IER, MCI_SR_ERROR | MCI_SR_ENDRX); } } static void at91_mci_write_done(struct at91_mci_softc *sc, uint32_t sr) { struct mmc_command *cmd = sc->curcmd; /* * We arrive here when the entire DMA transfer for a write is done, * whether it's a single or multi-block write. If it's multi-block we * have to immediately move on to the next operation which is to send * the stop command. If it's a single-block transfer we need to wait * for NOTBUSY, but if that's already asserted we can avoid another * interrupt and just move on to completing the request right away. */ WR4(sc, PDC_PTCR, PDC_PTCR_RXTDIS | PDC_PTCR_TXTDIS); bus_dmamap_sync(sc->dmatag, sc->bbuf_map[sc->bbuf_curidx], BUS_DMASYNC_POSTWRITE); bus_dmamap_unload(sc->dmatag, sc->bbuf_map[sc->bbuf_curidx]); if ((cmd->data->flags & MMC_DATA_MULTI) || (sr & MCI_SR_NOTBUSY)) { cmd->error = MMC_ERR_NONE; at91_mci_next_operation(sc); } else { WR4(sc, MCI_IER, MCI_SR_ERROR | MCI_SR_NOTBUSY); } } static void at91_mci_notbusy(struct at91_mci_softc *sc) { struct mmc_command *cmd = sc->curcmd; /* * We arrive here by either completion of a single-block write, or * completion of the stop command that ended a multi-block write (and, * I suppose, after a card-select or erase, but I haven't tested * those). Anyway, we're done and it's time to move on to the next * command. */ cmd->error = MMC_ERR_NONE; at91_mci_next_operation(sc); } static void at91_mci_stop_done(struct at91_mci_softc *sc, uint32_t sr) { struct mmc_command *cmd = sc->curcmd; /* * We arrive here after receiving CMDRDY for a MMC_STOP_TRANSMISSION * command. Depending on the operation being stopped, we may have to * do some unusual things to work around hardware bugs. */ /* * This is known to be true of at91rm9200 hardware; it may or may not * apply to more recent chips: * * After stopping a multi-block write, the NOTBUSY bit in MCI_SR does * not properly reflect the actual busy state of the card as signaled * on the DAT0 line; it always claims the card is not-busy. If we * believe that and let operations continue, following commands will * fail with response timeouts (except of course MMC_SEND_STATUS -- it * indicates the card is busy in the PRG state, which was the smoking * gun that showed MCI_SR NOTBUSY was not tracking DAT0 correctly). * * The atmel docs are emphatic: "This flag [NOTBUSY] must be used only * for Write Operations." I guess technically since we sent a stop * it's not a write operation anymore. But then just what did they * think it meant for the stop command to have "...an optional busy * signal transmitted on the data line" according to the SD spec? * * I tried a variety of things to un-wedge the MCI and get the status * register to reflect NOTBUSY correctly again, but the only thing * that worked was a full device reset. It feels like an awfully big * hammer, but doing a full reset after every multiblock write is * still faster than doing single-block IO (by almost two orders of * magnitude: 20KB/sec improves to about 1.8MB/sec best case). * * After doing the reset, wait for a NOTBUSY interrupt before * continuing with the next operation. * * This workaround breaks multiwrite on the rev2xx parts, but some other * workaround is needed. */ if ((sc->flags & CMD_MULTIWRITE) && (sc->sc_cap & CAP_NEEDS_BYTESWAP)) { at91_mci_reset(sc); WR4(sc, MCI_IER, MCI_SR_ERROR | MCI_SR_NOTBUSY); return; } /* * This is known to be true of at91rm9200 hardware; it may or may not * apply to more recent chips: * * After stopping a multi-block read, loop to read and discard any * data that coasts in after we sent the stop command. The docs don't * say anything about it, but empirical testing shows that 1-3 * additional words of data get buffered up in some unmentioned * internal fifo and if we don't read and discard them here they end * up on the front of the next read DMA transfer we do. * * This appears to be unnecessary for rev2xx parts. */ if ((sc->flags & CMD_MULTIREAD) && (sc->sc_cap & CAP_NEEDS_BYTESWAP)) { uint32_t sr; int count = 0; do { sr = RD4(sc, MCI_SR); if (sr & MCI_SR_RXRDY) { RD4(sc, MCI_RDR); ++count; } } while (sr & MCI_SR_RXRDY); at91_mci_reset(sc); } cmd->error = MMC_ERR_NONE; at91_mci_next_operation(sc); } static void at91_mci_cmdrdy(struct at91_mci_softc *sc, uint32_t sr) { struct mmc_command *cmd = sc->curcmd; int i; if (cmd == NULL) return; /* * We get here at the end of EVERY command. We retrieve the command * response (if any) then decide what to do next based on the command. */ if (cmd->flags & MMC_RSP_PRESENT) { for (i = 0; i < ((cmd->flags & MMC_RSP_136) ? 4 : 1); i++) { cmd->resp[i] = RD4(sc, MCI_RSPR + i * 4); if (mci_debug) printf("RSPR[%d] = %x sr=%x\n", i, cmd->resp[i], sr); } } /* * If this was a stop command, go handle the various special * conditions (read: bugs) that have to be dealt with following a stop. */ if (cmd->opcode == MMC_STOP_TRANSMISSION) { at91_mci_stop_done(sc, sr); return; } /* * If this command can continue to assert BUSY beyond the response then * we need to wait for NOTBUSY before the command is really done. * * Note that this may not work properly on the at91rm9200. It certainly * doesn't work for the STOP command that follows a multi-block write, * so post-stop CMDRDY is handled separately; see the special handling * in at91_mci_stop_done(). * * Beside STOP, there are other R1B-type commands that use the busy * signal after CMDRDY: CMD7 (card select), CMD28-29 (write protect), * CMD38 (erase). I haven't tested any of them, but I rather expect * them all to have the same sort of problem with MCI_SR not actually * reflecting the state of the DAT0-line busy indicator. So this code * may need to grow some sort of special handling for them too. (This * just in: CMD7 isn't a problem right now because dev/mmc.c incorrectly * sets the response flags to R1 rather than R1B.) XXX */ if ((cmd->flags & MMC_RSP_BUSY)) { WR4(sc, MCI_IER, MCI_SR_ERROR | MCI_SR_NOTBUSY); return; } /* * If there is a data transfer with this command, then... * - If it's a read, we need to wait for ENDRX. * - If it's a write, now is the time to enable the PDC, and we need * to wait for a BLKE that follows a TXBUFE, because if we're doing * a split transfer we get a BLKE after the first half (when TPR/TCR * get loaded from TNPR/TNCR). So first we wait for the TXBUFE, and * the handling for that interrupt will then invoke the wait for the * subsequent BLKE which indicates actual completion. */ if (cmd->data) { uint32_t ier; if (cmd->data->flags & MMC_DATA_READ) { ier = MCI_SR_ENDRX; } else { ier = MCI_SR_TXBUFE; WR4(sc, PDC_PTCR, PDC_PTCR_TXTEN); } WR4(sc, MCI_IER, MCI_SR_ERROR | ier); return; } /* * If we made it to here, we don't need to wait for anything more for * the current command, move on to the next command (will complete the * request if there is no next command). */ cmd->error = MMC_ERR_NONE; at91_mci_next_operation(sc); } static void at91_mci_intr(void *arg) { struct at91_mci_softc *sc = (struct at91_mci_softc*)arg; struct mmc_command *cmd = sc->curcmd; uint32_t sr, isr; AT91_MCI_LOCK(sc); sr = RD4(sc, MCI_SR); isr = sr & RD4(sc, MCI_IMR); if (mci_debug) printf("i 0x%x sr 0x%x\n", isr, sr); /* * All interrupts are one-shot; disable it now. * The next operation will re-enable whatever interrupts it wants. */ WR4(sc, MCI_IDR, isr); if (isr & MCI_SR_ERROR) { if (isr & (MCI_SR_RTOE | MCI_SR_DTOE)) cmd->error = MMC_ERR_TIMEOUT; else if (isr & (MCI_SR_RCRCE | MCI_SR_DCRCE)) cmd->error = MMC_ERR_BADCRC; else if (isr & (MCI_SR_OVRE | MCI_SR_UNRE)) cmd->error = MMC_ERR_FIFO; else cmd->error = MMC_ERR_FAILED; /* * CMD8 is used to probe for SDHC cards, a standard SD card * will get a response timeout; don't report it because it's a * normal and expected condition. One might argue that all * error reporting should be left to higher levels, but when * they report at all it's always EIO, which isn't very * helpful. XXX bootverbose? */ if (cmd->opcode != 8) { device_printf(sc->dev, "IO error; status MCI_SR = 0x%b cmd opcode = %d%s\n", sr, MCI_SR_BITSTRING, cmd->opcode, (cmd->opcode != 12) ? "" : (sc->flags & CMD_MULTIREAD) ? " after read" : " after write"); /* XXX not sure RTOE needs a full reset, just a retry */ at91_mci_reset(sc); } at91_mci_next_operation(sc); } else { if (isr & MCI_SR_TXBUFE) { // printf("TXBUFE\n"); /* * We need to wait for a BLKE that follows TXBUFE * (intermediate BLKEs might happen after ENDTXes if * we're chaining multiple buffers). If BLKE is also * asserted at the time we get TXBUFE, we can avoid * another interrupt and process it right away, below. */ if (sr & MCI_SR_BLKE) isr |= MCI_SR_BLKE; else WR4(sc, MCI_IER, MCI_SR_BLKE); } if (isr & MCI_SR_RXBUFF) { // printf("RXBUFF\n"); } if (isr & MCI_SR_ENDTX) { // printf("ENDTX\n"); } if (isr & MCI_SR_ENDRX) { // printf("ENDRX\n"); at91_mci_read_done(sc, sr); } if (isr & MCI_SR_NOTBUSY) { // printf("NOTBUSY\n"); at91_mci_notbusy(sc); } if (isr & MCI_SR_DTIP) { // printf("Data transfer in progress\n"); } if (isr & MCI_SR_BLKE) { // printf("Block transfer end\n"); at91_mci_write_done(sc, sr); } if (isr & MCI_SR_TXRDY) { // printf("Ready to transmit\n"); } if (isr & MCI_SR_RXRDY) { // printf("Ready to receive\n"); } if (isr & MCI_SR_CMDRDY) { // printf("Command ready\n"); at91_mci_cmdrdy(sc, sr); } } AT91_MCI_UNLOCK(sc); } static int at91_mci_read_ivar(device_t bus, device_t child, int which, uintptr_t *result) { struct at91_mci_softc *sc = device_get_softc(bus); switch (which) { default: return (EINVAL); case MMCBR_IVAR_BUS_MODE: *(int *)result = sc->host.ios.bus_mode; break; case MMCBR_IVAR_BUS_WIDTH: *(int *)result = sc->host.ios.bus_width; break; case MMCBR_IVAR_CHIP_SELECT: *(int *)result = sc->host.ios.chip_select; break; case MMCBR_IVAR_CLOCK: *(int *)result = sc->host.ios.clock; break; case MMCBR_IVAR_F_MIN: *(int *)result = sc->host.f_min; break; case MMCBR_IVAR_F_MAX: *(int *)result = sc->host.f_max; break; case MMCBR_IVAR_HOST_OCR: *(int *)result = sc->host.host_ocr; break; case MMCBR_IVAR_MODE: *(int *)result = sc->host.mode; break; case MMCBR_IVAR_OCR: *(int *)result = sc->host.ocr; break; case MMCBR_IVAR_POWER_MODE: *(int *)result = sc->host.ios.power_mode; break; case MMCBR_IVAR_VDD: *(int *)result = sc->host.ios.vdd; break; case MMCBR_IVAR_CAPS: if (sc->has_4wire) { sc->sc_cap |= CAP_HAS_4WIRE; sc->host.caps |= MMC_CAP_4_BIT_DATA; } else { sc->sc_cap &= ~CAP_HAS_4WIRE; sc->host.caps &= ~MMC_CAP_4_BIT_DATA; } *(int *)result = sc->host.caps; break; case MMCBR_IVAR_MAX_DATA: /* * Something is wrong with the 2x parts and multiblock, so * just do 1 block at a time for now, which really kills * performance. */ if (sc->sc_cap & CAP_MCI1_REV2XX) *(int *)result = 1; else *(int *)result = MAX_BLOCKS; break; } return (0); } static int at91_mci_write_ivar(device_t bus, device_t child, int which, uintptr_t value) { struct at91_mci_softc *sc = device_get_softc(bus); switch (which) { default: return (EINVAL); case MMCBR_IVAR_BUS_MODE: sc->host.ios.bus_mode = value; break; case MMCBR_IVAR_BUS_WIDTH: sc->host.ios.bus_width = value; break; case MMCBR_IVAR_CHIP_SELECT: sc->host.ios.chip_select = value; break; case MMCBR_IVAR_CLOCK: sc->host.ios.clock = value; break; case MMCBR_IVAR_MODE: sc->host.mode = value; break; case MMCBR_IVAR_OCR: sc->host.ocr = value; break; case MMCBR_IVAR_POWER_MODE: sc->host.ios.power_mode = value; break; case MMCBR_IVAR_VDD: sc->host.ios.vdd = value; break; /* These are read-only */ case MMCBR_IVAR_CAPS: case MMCBR_IVAR_HOST_OCR: case MMCBR_IVAR_F_MIN: case MMCBR_IVAR_F_MAX: case MMCBR_IVAR_MAX_DATA: return (EINVAL); } return (0); } static device_method_t at91_mci_methods[] = { /* device_if */ DEVMETHOD(device_probe, at91_mci_probe), DEVMETHOD(device_attach, at91_mci_attach), DEVMETHOD(device_detach, at91_mci_detach), /* Bus interface */ DEVMETHOD(bus_read_ivar, at91_mci_read_ivar), DEVMETHOD(bus_write_ivar, at91_mci_write_ivar), /* mmcbr_if */ DEVMETHOD(mmcbr_update_ios, at91_mci_update_ios), DEVMETHOD(mmcbr_request, at91_mci_request), DEVMETHOD(mmcbr_get_ro, at91_mci_get_ro), DEVMETHOD(mmcbr_acquire_host, at91_mci_acquire_host), DEVMETHOD(mmcbr_release_host, at91_mci_release_host), DEVMETHOD_END }; static driver_t at91_mci_driver = { "at91_mci", at91_mci_methods, sizeof(struct at91_mci_softc), }; static devclass_t at91_mci_devclass; #ifdef FDT DRIVER_MODULE(at91_mci, simplebus, at91_mci_driver, at91_mci_devclass, NULL, NULL); #else DRIVER_MODULE(at91_mci, atmelarm, at91_mci_driver, at91_mci_devclass, NULL, NULL); #endif MMC_DECLARE_BRIDGE(at91_mci); Index: head/sys/arm/at91/at91_mcireg.h =================================================================== --- head/sys/arm/at91/at91_mcireg.h (revision 333141) +++ head/sys/arm/at91/at91_mcireg.h (revision 333142) @@ -1,158 +1,158 @@ /*- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD * * Copyright (c) 2006 Berndt Walter. All rights reserved. - * Copyright (c) 2006 M. Warner Losh. All rights reserved. + * Copyright (c) 2006 M. Warner Losh. * * 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_AT91_MCIREG_H #define ARM_AT91_AT91_MCIREG_H #define MMC_MAX 30 #define MCI_CR 0x00 /* MCI Control Register */ #define MCI_MR 0x04 /* MCI Mode Register */ #define MCI_DTOR 0x08 /* MCI Data Timeout Register */ #define MCI_SDCR 0x0c /* MCI SD Card Register */ #define MCI_ARGR 0x10 /* MCI Argument Register */ #define MCI_CMDR 0x14 /* MCI Command Register */ #define MCI_RSPR 0x20 /* MCI Response Registers - 4 of them */ #define MCI_RDR 0x30 /* MCI Receive Data Register */ #define MCI_TDR 0x34 /* MCI Transmit Data Register */ #define MCI_SR 0x40 /* MCI Status Register */ #define MCI_IER 0x44 /* MCI Interrupt Enable Register */ #define MCI_IDR 0x48 /* MCI Interrupt Disable Register */ #define MCI_IMR 0x4c /* MCI Interrupt Mask Register */ /* -------- MCI_CR : (MCI Offset: 0x0) MCI Control Register -------- */ #define MCI_CR_MCIEN (0x1u << 0) /* (MCI) Multimedia Interface Enable */ #define MCI_CR_MCIDIS (0x1u << 1) /* (MCI) Multimedia Interface Disable */ #define MCI_CR_PWSEN (0x1u << 2) /* (MCI) Power Save Mode Enable */ #define MCI_CR_PWSDIS (0x1u << 3) /* (MCI) Power Save Mode Disable */ #define MCI_CR_SWRST (0x1u << 7) /* (MCI) Software Reset */ /* -------- MCI_MR : (MCI Offset: 0x4) MCI Mode Register -------- */ #define MCI_MR_CLKDIV (0xffu << 0) /* (MCI) Clock Divider */ #define MCI_MR_PWSDIV (0x3fu << 8) /* (MCI) Power Saving Divider */ #define MCI_MR_RDPROOF (0x1u << 11) /* (MCI) Read Proof Enable */ #define MCI_MR_WRPROOF (0x1u << 12) /* (MCI) Write Proof Enable */ #define MCI_MR_PDCFBYTE (0x1u << 13) /* (MCI) PDC Force Byte Transfer */ #define MCI_MR_PDCPADV (0x1u << 14) /* (MCI) PDC Padding Value */ #define MCI_MR_PDCMODE (0x1u << 15) /* (MCI) PDC Oriented Mode */ #define MCI_MR_BLKLEN 0x3fff0000ul /* (MCI) Data Block Length */ /* -------- MCI_DTOR : (MCI Offset: 0x8) MCI Data Timeout Register -------- */ #define MCI_DTOR_DTOCYC (0xfu << 0) /* (MCI) Data Timeout Cycle Number */ #define MCI_DTOR_DTOMUL (0x7u << 4) /* (MCI) Data Timeout Multiplier */ #define MCI_DTOR_DTOMUL_1 (0x0u << 4) /* (MCI) DTOCYC x 1 */ #define MCI_DTOR_DTOMUL_16 (0x1u << 4) /* (MCI) DTOCYC x 16 */ #define MCI_DTOR_DTOMUL_128 (0x2u << 4) /* (MCI) DTOCYC x 128 */ #define MCI_DTOR_DTOMUL_256 (0x3u << 4) /* (MCI) DTOCYC x 256 */ #define MCI_DTOR_DTOMUL_1k (0x4u << 4) /* (MCI) DTOCYC x 1024 */ #define MCI_DTOR_DTOMUL_4k (0x5u << 4) /* (MCI) DTOCYC x 4096 */ #define MCI_DTOR_DTOMUL_64k (0x6u << 4) /* (MCI) DTOCYC x 65536 */ #define MCI_DTOR_DTOMUL_1M (0x7u << 4) /* (MCI) DTOCYC x 1048576 */ /* -------- MCI_SDCR : (MCI Offset: 0xc) MCI SD Card Register -------- */ #define MCI_SDCR_SDCSEL (0x1u << 0) /* (MCI) SD Card Selector */ #define MCI_SDCR_SDCBUS (0x1u << 7) /* (MCI) SD Card Bus Width */ /* -------- MCI_CMDR : (MCI Offset: 0x14) MCI Command Register -------- */ #define MCI_CMDR_CMDNB (0x1Fu << 0) /* (MCI) Command Number */ #define MCI_CMDR_RSPTYP (0x3u << 6) /* (MCI) Response Type */ #define MCI_CMDR_RSPTYP_NO (0x0u << 6) /* (MCI) No response */ #define MCI_CMDR_RSPTYP_48 (0x1u << 6) /* (MCI) 48-bit response */ #define MCI_CMDR_RSPTYP_136 (0x2u << 6) /* (MCI) 136-bit response */ #define MCI_CMDR_SPCMD (0x7u << 8) /* (MCI) Special CMD */ #define MCI_CMDR_SPCMD_NONE (0x0u << 8) /* (MCI) Not a special CMD */ #define MCI_CMDR_SPCMD_INIT (0x1u << 8) /* (MCI) Initialization CMD */ #define MCI_CMDR_SPCMD_SYNC (0x2u << 8) /* (MCI) Synchronized CMD */ #define MCI_CMDR_SPCMD_IT_CMD (0x4u << 8) /* (MCI) Interrupt command */ #define MCI_CMDR_SPCMD_IT_REP (0x5u << 8) /* (MCI) Interrupt response */ #define MCI_CMDR_OPDCMD (0x1u << 11) /* (MCI) Open Drain Command */ #define MCI_CMDR_MAXLAT (0x1u << 12) /* (MCI) Maximum Latency for Command to respond */ #define MCI_CMDR_TRCMD (0x3u << 16) /* (MCI) Transfer CMD */ #define MCI_CMDR_TRCMD_NO (0x0u << 16) /* (MCI) No transfer */ #define MCI_CMDR_TRCMD_START (0x1u << 16) /* (MCI) Start transfer */ #define MCI_CMDR_TRCMD_STOP (0x2u << 16) /* (MCI) Stop transfer */ #define MCI_CMDR_TRDIR (0x1u << 18) /* (MCI) Transfer Direction */ #define MCI_CMDR_TRTYP (0x3u << 19) /* (MCI) Transfer Type */ #define MCI_CMDR_TRTYP_BLOCK (0x0u << 19) /* (MCI) Block Transfer type */ #define MCI_CMDR_TRTYP_MULTIPLE (0x1u << 19) /* (MCI) Multiple Block transfer type */ #define MCI_CMDR_TRTYP_STREAM (0x2u << 19) /* (MCI) Stream transfer type */ /* -------- MCI_SR : (MCI Offset: 0x40) MCI Status Register -------- */ #define MCI_SR_CMDRDY (0x1u << 0) /* (MCI) Command Ready flag */ #define MCI_SR_RXRDY (0x1u << 1) /* (MCI) RX Ready flag */ #define MCI_SR_TXRDY (0x1u << 2) /* (MCI) TX Ready flag */ #define MCI_SR_BLKE (0x1u << 3) /* (MCI) Data Block Transfer Ended flag */ #define MCI_SR_DTIP (0x1u << 4) /* (MCI) Data Transfer in Progress flag */ #define MCI_SR_NOTBUSY (0x1u << 5) /* (MCI) Data Line Not Busy flag */ #define MCI_SR_ENDRX (0x1u << 6) /* (MCI) End of RX Buffer flag */ #define MCI_SR_ENDTX (0x1u << 7) /* (MCI) End of TX Buffer flag */ #define MCI_SR_RXBUFF (0x1u << 14) /* (MCI) RX Buffer Full flag */ #define MCI_SR_TXBUFE (0x1u << 15) /* (MCI) TX Buffer Empty flag */ #define MCI_SR_RINDE (0x1u << 16) /* (MCI) Response Index Error flag */ #define MCI_SR_RDIRE (0x1u << 17) /* (MCI) Response Direction Error flag */ #define MCI_SR_RCRCE (0x1u << 18) /* (MCI) Response CRC Error flag */ #define MCI_SR_RENDE (0x1u << 19) /* (MCI) Response End Bit Error flag */ #define MCI_SR_RTOE (0x1u << 20) /* (MCI) Response Time-out Error flag */ #define MCI_SR_DCRCE (0x1u << 21) /* (MCI) data CRC Error flag */ #define MCI_SR_DTOE (0x1u << 22) /* (MCI) Data timeout Error flag */ #define MCI_SR_OVRE (0x1u << 30) /* (MCI) Overrun flag */ #define MCI_SR_UNRE (0x1u << 31) /* (MCI) Underrun flag */ /* TXRDY,DTIP,ENDTX,TXBUFE,RTOE */ #define MCI_SR_BITSTRING \ "\020" \ "\001CMDRDY" \ "\002RXRDY" \ "\003TXRDY" \ "\004BLKE" \ "\005DTIP" \ "\006NOTBUSY" \ "\007ENDRX" \ "\010ENDTX" \ "\017RXBUFF" \ "\020TXBUFE" \ "\021RINDE" \ "\022RDIRE" \ "\023RCRCE" \ "\024RENDE" \ "\025RTOE" \ "\026DCRCE" \ "\027DTOE" \ "\037OVRE" \ "\040UNRE" /* -------- MCI_IER : (MCI Offset: 0x44) MCI Interrupt Enable Register -------- */ /* -------- MCI_IDR : (MCI Offset: 0x48) MCI Interrupt Disable Register -------- */ /* -------- MCI_IMR : (MCI Offset: 0x4c) MCI Interrupt Mask Register -------- */ #define MCI_SR_ERROR (MCI_SR_UNRE | MCI_SR_OVRE | MCI_SR_DTOE | \ MCI_SR_DCRCE | MCI_SR_RTOE | MCI_SR_RENDE | \ MCI_SR_RCRCE | MCI_SR_RDIRE | MCI_SR_RINDE) #define AT91C_BUS_WIDTH_1BIT 0x00 #define AT91C_BUS_WIDTH_4BITS 0x02 #endif /* ARM_AT91_AT91_MCIREG_H */ Index: head/sys/arm/at91/at91_ohci.c =================================================================== --- head/sys/arm/at91/at91_ohci.c (revision 333141) +++ head/sys/arm/at91/at91_ohci.c (revision 333142) @@ -1,236 +1,236 @@ /*- - * Copyright (c) 2006 M. Warner Losh. All rights reserved. + * Copyright (c) 2006 M. Warner Losh. * * 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 THE AUTHOR ``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 THE AUTHOR 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 #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define MEM_RID 0 static device_probe_t ohci_atmelarm_probe; static device_attach_t ohci_atmelarm_attach; static device_detach_t ohci_atmelarm_detach; struct at91_ohci_softc { struct ohci_softc sc_ohci; /* must be first */ struct at91_pmc_clock *mclk; struct at91_pmc_clock *iclk; struct at91_pmc_clock *fclk; }; static int ohci_atmelarm_probe(device_t dev) { device_set_desc(dev, "AT91 integrated OHCI controller"); return (BUS_PROBE_DEFAULT); } static int ohci_atmelarm_attach(device_t dev) { struct at91_ohci_softc *sc = device_get_softc(dev); int err; int rid; /* initialise some bus fields */ sc->sc_ohci.sc_bus.parent = dev; sc->sc_ohci.sc_bus.devices = sc->sc_ohci.sc_devices; sc->sc_ohci.sc_bus.devices_max = OHCI_MAX_DEVICES; sc->sc_ohci.sc_bus.dma_bits = 32; /* get all DMA memory */ if (usb_bus_mem_alloc_all(&sc->sc_ohci.sc_bus, USB_GET_DMA_TAG(dev), &ohci_iterate_hw_softc)) { return (ENOMEM); } sc->mclk = at91_pmc_clock_ref("mck"); sc->iclk = at91_pmc_clock_ref("ohci_clk"); sc->fclk = at91_pmc_clock_ref("uhpck"); sc->sc_ohci.sc_dev = dev; rid = MEM_RID; sc->sc_ohci.sc_io_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, RF_ACTIVE); if (!(sc->sc_ohci.sc_io_res)) { err = ENOMEM; goto error; } sc->sc_ohci.sc_io_tag = rman_get_bustag(sc->sc_ohci.sc_io_res); sc->sc_ohci.sc_io_hdl = rman_get_bushandle(sc->sc_ohci.sc_io_res); sc->sc_ohci.sc_io_size = rman_get_size(sc->sc_ohci.sc_io_res); rid = 0; sc->sc_ohci.sc_irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, RF_ACTIVE); if (!(sc->sc_ohci.sc_irq_res)) { goto error; } sc->sc_ohci.sc_bus.bdev = device_add_child(dev, "usbus", -1); if (!(sc->sc_ohci.sc_bus.bdev)) { goto error; } device_set_ivars(sc->sc_ohci.sc_bus.bdev, &sc->sc_ohci.sc_bus); strlcpy(sc->sc_ohci.sc_vendor, "Atmel", sizeof(sc->sc_ohci.sc_vendor)); err = bus_setup_intr(dev, sc->sc_ohci.sc_irq_res, INTR_TYPE_BIO | INTR_MPSAFE, NULL, (driver_intr_t *)ohci_interrupt, sc, &sc->sc_ohci.sc_intr_hdl); if (err) { sc->sc_ohci.sc_intr_hdl = NULL; goto error; } /* * turn on the clocks from the AT91's point of view. Keep the unit in reset. */ at91_pmc_clock_enable(sc->mclk); at91_pmc_clock_enable(sc->iclk); at91_pmc_clock_enable(sc->fclk); bus_space_write_4(sc->sc_ohci.sc_io_tag, sc->sc_ohci.sc_io_hdl, OHCI_CONTROL, 0); err = ohci_init(&sc->sc_ohci); if (!err) { err = device_probe_and_attach(sc->sc_ohci.sc_bus.bdev); } if (err) { goto error; } return (0); error: ohci_atmelarm_detach(dev); return (ENXIO); } static int ohci_atmelarm_detach(device_t dev) { struct at91_ohci_softc *sc = device_get_softc(dev); int err; /* during module unload there are lots of children leftover */ device_delete_children(dev); /* * Put the controller into reset, then disable clocks and do * the MI tear down. We have to disable the clocks/hardware * after we do the rest of the teardown. We also disable the * clocks in the opposite order we acquire them, but that * doesn't seem to be absolutely necessary. We free up the * clocks after we disable them, so the system could, in * theory, reuse them. */ bus_space_write_4(sc->sc_ohci.sc_io_tag, sc->sc_ohci.sc_io_hdl, OHCI_CONTROL, 0); at91_pmc_clock_disable(sc->fclk); at91_pmc_clock_disable(sc->iclk); at91_pmc_clock_disable(sc->mclk); at91_pmc_clock_deref(sc->fclk); at91_pmc_clock_deref(sc->iclk); at91_pmc_clock_deref(sc->mclk); if (sc->sc_ohci.sc_irq_res && sc->sc_ohci.sc_intr_hdl) { /* * only call ohci_detach() after ohci_init() */ ohci_detach(&sc->sc_ohci); err = bus_teardown_intr(dev, sc->sc_ohci.sc_irq_res, sc->sc_ohci.sc_intr_hdl); sc->sc_ohci.sc_intr_hdl = NULL; } if (sc->sc_ohci.sc_irq_res) { bus_release_resource(dev, SYS_RES_IRQ, 0, sc->sc_ohci.sc_irq_res); sc->sc_ohci.sc_irq_res = NULL; } if (sc->sc_ohci.sc_io_res) { bus_release_resource(dev, SYS_RES_MEMORY, MEM_RID, sc->sc_ohci.sc_io_res); sc->sc_ohci.sc_io_res = NULL; } usb_bus_mem_free_all(&sc->sc_ohci.sc_bus, &ohci_iterate_hw_softc); return (0); } static device_method_t ohci_methods[] = { /* Device interface */ DEVMETHOD(device_probe, ohci_atmelarm_probe), DEVMETHOD(device_attach, ohci_atmelarm_attach), DEVMETHOD(device_detach, ohci_atmelarm_detach), DEVMETHOD(device_suspend, bus_generic_suspend), DEVMETHOD(device_resume, bus_generic_resume), DEVMETHOD(device_shutdown, bus_generic_shutdown), DEVMETHOD_END }; static driver_t ohci_driver = { .name = "ohci", .methods = ohci_methods, .size = sizeof(struct at91_ohci_softc), }; static devclass_t ohci_devclass; DRIVER_MODULE(ohci, atmelarm, ohci_driver, ohci_devclass, 0, 0); MODULE_DEPEND(ohci, usb, 1, 1, 1); Index: head/sys/arm/at91/at91_ohci_fdt.c =================================================================== --- head/sys/arm/at91/at91_ohci_fdt.c (revision 333141) +++ head/sys/arm/at91/at91_ohci_fdt.c (revision 333142) @@ -1,244 +1,244 @@ /*- - * Copyright (c) 2006 M. Warner Losh. All rights reserved. + * Copyright (c) 2006 M. Warner Losh. * * 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 THE AUTHOR ``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 THE AUTHOR 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 #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define MEM_RID 0 static device_probe_t ohci_at91_fdt_probe; static device_attach_t ohci_at91_fdt_attach; static device_detach_t ohci_at91_fdt_detach; struct at91_ohci_softc { struct ohci_softc sc_ohci; /* must be first */ struct at91_pmc_clock *mclk; struct at91_pmc_clock *iclk; struct at91_pmc_clock *fclk; }; static int ohci_at91_fdt_probe(device_t dev) { if (!ofw_bus_is_compatible(dev, "atmel,at91rm9200-ohci")) return (ENXIO); device_set_desc(dev, "AT91 integrated OHCI controller"); return (BUS_PROBE_DEFAULT); } static int ohci_at91_fdt_attach(device_t dev) { struct at91_ohci_softc *sc = device_get_softc(dev); int err; int rid; /* initialise some bus fields */ sc->sc_ohci.sc_bus.parent = dev; sc->sc_ohci.sc_bus.devices = sc->sc_ohci.sc_devices; sc->sc_ohci.sc_bus.devices_max = OHCI_MAX_DEVICES; sc->sc_ohci.sc_bus.dma_bits = 32; /* get all DMA memory */ if (usb_bus_mem_alloc_all(&sc->sc_ohci.sc_bus, USB_GET_DMA_TAG(dev), &ohci_iterate_hw_softc)) { return (ENOMEM); } sc->mclk = at91_pmc_clock_ref("mck"); sc->iclk = at91_pmc_clock_ref("ohci_clk"); sc->fclk = at91_pmc_clock_ref("uhpck"); sc->sc_ohci.sc_dev = dev; rid = MEM_RID; sc->sc_ohci.sc_io_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, RF_ACTIVE); if (!(sc->sc_ohci.sc_io_res)) { err = ENOMEM; goto error; } sc->sc_ohci.sc_io_tag = rman_get_bustag(sc->sc_ohci.sc_io_res); sc->sc_ohci.sc_io_hdl = rman_get_bushandle(sc->sc_ohci.sc_io_res); sc->sc_ohci.sc_io_size = rman_get_size(sc->sc_ohci.sc_io_res); rid = 0; sc->sc_ohci.sc_irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, RF_ACTIVE); if (!(sc->sc_ohci.sc_irq_res)) { goto error; } sc->sc_ohci.sc_bus.bdev = device_add_child(dev, "usbus", -1); if (!(sc->sc_ohci.sc_bus.bdev)) { goto error; } device_set_ivars(sc->sc_ohci.sc_bus.bdev, &sc->sc_ohci.sc_bus); strlcpy(sc->sc_ohci.sc_vendor, "Atmel", sizeof(sc->sc_ohci.sc_vendor)); err = bus_setup_intr(dev, sc->sc_ohci.sc_irq_res, INTR_TYPE_BIO | INTR_MPSAFE, NULL, (driver_intr_t *)ohci_interrupt, sc, &sc->sc_ohci.sc_intr_hdl); if (err) { sc->sc_ohci.sc_intr_hdl = NULL; goto error; } /* * turn on the clocks from the AT91's point of view. Keep the unit in reset. */ at91_pmc_clock_enable(sc->mclk); at91_pmc_clock_enable(sc->iclk); at91_pmc_clock_enable(sc->fclk); bus_space_write_4(sc->sc_ohci.sc_io_tag, sc->sc_ohci.sc_io_hdl, OHCI_CONTROL, 0); err = ohci_init(&sc->sc_ohci); if (!err) { err = device_probe_and_attach(sc->sc_ohci.sc_bus.bdev); } if (err) { goto error; } return (0); error: ohci_at91_fdt_detach(dev); return (ENXIO); } static int ohci_at91_fdt_detach(device_t dev) { struct at91_ohci_softc *sc = device_get_softc(dev); int err; /* during module unload there are lots of children leftover */ device_delete_children(dev); if (sc->sc_ohci.sc_io_res != NULL) { /* * Put the controller into reset, then disable clocks and do * the MI tear down. We have to disable the clocks/hardware * after we do the rest of the teardown. We also disable the * clocks in the opposite order we acquire them, but that * doesn't seem to be absolutely necessary. We free up the * clocks after we disable them, so the system could, in * theory, reuse them. */ bus_space_write_4(sc->sc_ohci.sc_io_tag, sc->sc_ohci.sc_io_hdl, OHCI_CONTROL, 0); at91_pmc_clock_disable(sc->fclk); at91_pmc_clock_disable(sc->iclk); at91_pmc_clock_disable(sc->mclk); at91_pmc_clock_deref(sc->fclk); at91_pmc_clock_deref(sc->iclk); at91_pmc_clock_deref(sc->mclk); if (sc->sc_ohci.sc_irq_res && sc->sc_ohci.sc_intr_hdl) { /* * only call ohci_detach() after ohci_init() */ ohci_detach(&sc->sc_ohci); err = bus_teardown_intr(dev, sc->sc_ohci.sc_irq_res, sc->sc_ohci.sc_intr_hdl); sc->sc_ohci.sc_intr_hdl = NULL; } if (sc->sc_ohci.sc_irq_res) { bus_release_resource(dev, SYS_RES_IRQ, 0, sc->sc_ohci.sc_irq_res); sc->sc_ohci.sc_irq_res = NULL; } if (sc->sc_ohci.sc_io_res) { bus_release_resource(dev, SYS_RES_MEMORY, MEM_RID, sc->sc_ohci.sc_io_res); sc->sc_ohci.sc_io_res = NULL; } } usb_bus_mem_free_all(&sc->sc_ohci.sc_bus, &ohci_iterate_hw_softc); return (0); } static device_method_t ohci_methods[] = { /* Device interface */ DEVMETHOD(device_probe, ohci_at91_fdt_probe), DEVMETHOD(device_attach, ohci_at91_fdt_attach), DEVMETHOD(device_detach, ohci_at91_fdt_detach), DEVMETHOD(device_suspend, bus_generic_suspend), DEVMETHOD(device_resume, bus_generic_resume), DEVMETHOD(device_shutdown, bus_generic_shutdown), DEVMETHOD_END }; static driver_t ohci_driver = { .name = "ohci", .methods = ohci_methods, .size = sizeof(struct at91_ohci_softc), }; static devclass_t ohci_devclass; DRIVER_MODULE(ohci, simplebus, ohci_driver, ohci_devclass, 0, 0); MODULE_DEPEND(ohci, usb, 1, 1, 1); Index: head/sys/arm/at91/at91_pdcreg.h =================================================================== --- head/sys/arm/at91/at91_pdcreg.h (revision 333141) +++ head/sys/arm/at91/at91_pdcreg.h (revision 333142) @@ -1,50 +1,50 @@ /*- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD * - * Copyright (c) 2006 M. Warner Losh. All rights reserved. + * Copyright (c) 2006 M. Warner Losh. * * 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_AT91_PDCREG_H #define ARM_AT91_AT91_PDCREG_H #define PDC_RPR 0x100 /* PDC Receive Pointer Register */ #define PDC_RCR 0x104 /* PDC Receive Counter Register */ #define PDC_TPR 0x108 /* PDC Transmit Pointer Register */ #define PDC_TCR 0x10c /* PDC Transmit Counter Register */ #define PDC_RNPR 0x110 /* PDC Receive Next Pointer Register */ #define PDC_RNCR 0x114 /* PDC Receive Next Counter Register */ #define PDC_TNPR 0x118 /* PDC Transmit Next Pointer Reg */ #define PDC_TNCR 0x11c /* PDC Transmit Next Counter Reg */ #define PDC_PTCR 0x120 /* PDC Transfer Control Register */ #define PDC_PTSR 0x124 /* PDC Transfer Status Register */ /* PTCR/PTSR */ #define PDC_PTCR_RXTEN (1UL << 0) /* RXTEN: Receiver Transfer Enable */ #define PDC_PTCR_RXTDIS (1UL << 1) /* RXTDIS: Receiver Transfer Disable */ #define PDC_PTCR_TXTEN (1UL << 8) /* TXTEN: Transmitter Transfer En */ #define PDC_PTCR_TXTDIS (1UL << 9) /* TXTDIS: Transmitter Transmit Dis */ #endif /* ARM_AT91_AT91_PDCREG_H */ Index: head/sys/arm/at91/at91_pinctrl.c =================================================================== --- head/sys/arm/at91/at91_pinctrl.c (revision 333141) +++ head/sys/arm/at91/at91_pinctrl.c (revision 333142) @@ -1,517 +1,517 @@ /*- - * Copyright (c) 2014 Warner Losh. All rights reserved. + * Copyright (c) 2014 M. Warner Losh. * * 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 #include #include #include #include #include #include #include #include #include #include #define BUS_PASS_PINMUX (BUS_PASS_INTERRUPT + 1) struct pinctrl_range { uint64_t bus; uint64_t host; uint64_t size; }; struct pinctrl_softc { device_t dev; phandle_t node; struct pinctrl_range *ranges; int nranges; pcell_t acells, scells; int done_pinmux; }; struct pinctrl_devinfo { struct ofw_bus_devinfo obdinfo; struct resource_list rl; }; static int at91_pinctrl_probe(device_t dev) { if (!ofw_bus_is_compatible(dev, "atmel,at91rm9200-pinctrl")) return (ENXIO); device_set_desc(dev, "pincontrol bus"); return (0); } /* XXX Make this a subclass of simplebus */ static struct pinctrl_devinfo * at91_pinctrl_setup_dinfo(device_t dev, phandle_t node) { struct pinctrl_softc *sc; struct pinctrl_devinfo *ndi; uint32_t *reg, *intr, icells; uint64_t phys, size; phandle_t iparent; int i, j, k; int nintr; int nreg; sc = device_get_softc(dev); ndi = malloc(sizeof(*ndi), M_DEVBUF, M_WAITOK | M_ZERO); if (ofw_bus_gen_setup_devinfo(&ndi->obdinfo, node) != 0) { free(ndi, M_DEVBUF); return (NULL); } resource_list_init(&ndi->rl); nreg = OF_getencprop_alloc_multi(node, "reg", sizeof(*reg), (void **)®); if (nreg == -1) nreg = 0; if (nreg % (sc->acells + sc->scells) != 0) { // if (bootverbose) device_printf(dev, "Malformed reg property on <%s>\n", ndi->obdinfo.obd_name); nreg = 0; } for (i = 0, k = 0; i < nreg; i += sc->acells + sc->scells, k++) { phys = size = 0; for (j = 0; j < sc->acells; j++) { phys <<= 32; phys |= reg[i + j]; } for (j = 0; j < sc->scells; j++) { size <<= 32; size |= reg[i + sc->acells + j]; } resource_list_add(&ndi->rl, SYS_RES_MEMORY, k, phys, phys + size - 1, size); } OF_prop_free(reg); nintr = OF_getencprop_alloc_multi(node, "interrupts", sizeof(*intr), (void **)&intr); if (nintr > 0) { if (OF_searchencprop(node, "interrupt-parent", &iparent, sizeof(iparent)) == -1) { device_printf(dev, "No interrupt-parent found, " "assuming direct parent\n"); iparent = OF_parent(node); } if (OF_searchencprop(OF_node_from_xref(iparent), "#interrupt-cells", &icells, sizeof(icells)) == -1) { device_printf(dev, "Missing #interrupt-cells property," " assuming <1>\n"); icells = 1; } if (icells < 1 || icells > nintr) { device_printf(dev, "Invalid #interrupt-cells property " "value <%d>, assuming <1>\n", icells); icells = 1; } for (i = 0, k = 0; i < nintr; i += icells, k++) { intr[i] = ofw_bus_map_intr(dev, iparent, icells, &intr[i]); resource_list_add(&ndi->rl, SYS_RES_IRQ, k, intr[i], intr[i], 1); } OF_prop_free(intr); } return (ndi); } static int at91_pinctrl_fill_ranges(phandle_t node, struct pinctrl_softc *sc) { int host_address_cells; cell_t *base_ranges; ssize_t nbase_ranges; int err; int i, j, k; err = OF_searchencprop(OF_parent(node), "#address-cells", &host_address_cells, sizeof(host_address_cells)); if (err <= 0) return (-1); nbase_ranges = OF_getproplen(node, "ranges"); if (nbase_ranges < 0) return (-1); sc->nranges = nbase_ranges / sizeof(cell_t) / (sc->acells + host_address_cells + sc->scells); if (sc->nranges == 0) return (0); sc->ranges = malloc(sc->nranges * sizeof(sc->ranges[0]), M_DEVBUF, M_WAITOK); base_ranges = malloc(nbase_ranges, M_DEVBUF, M_WAITOK); OF_getencprop(node, "ranges", base_ranges, nbase_ranges); for (i = 0, j = 0; i < sc->nranges; i++) { sc->ranges[i].bus = 0; for (k = 0; k < sc->acells; k++) { sc->ranges[i].bus <<= 32; sc->ranges[i].bus |= base_ranges[j++]; } sc->ranges[i].host = 0; for (k = 0; k < host_address_cells; k++) { sc->ranges[i].host <<= 32; sc->ranges[i].host |= base_ranges[j++]; } sc->ranges[i].size = 0; for (k = 0; k < sc->scells; k++) { sc->ranges[i].size <<= 32; sc->ranges[i].size |= base_ranges[j++]; } } free(base_ranges, M_DEVBUF); return (sc->nranges); } static int at91_pinctrl_attach(device_t dev) { struct pinctrl_softc *sc; struct pinctrl_devinfo *di; phandle_t node; device_t cdev; sc = device_get_softc(dev); node = ofw_bus_get_node(dev); sc->dev = dev; sc->node = node; /* * Some important numbers */ sc->acells = 2; OF_getencprop(node, "#address-cells", &sc->acells, sizeof(sc->acells)); sc->scells = 1; OF_getencprop(node, "#size-cells", &sc->scells, sizeof(sc->scells)); if (at91_pinctrl_fill_ranges(node, sc) < 0) { device_printf(dev, "could not get ranges\n"); return (ENXIO); } for (node = OF_child(node); node > 0; node = OF_peer(node)) { if ((di = at91_pinctrl_setup_dinfo(dev, node)) == NULL) continue; cdev = device_add_child(dev, NULL, -1); if (cdev == NULL) { device_printf(dev, "<%s>: device_add_child failed\n", di->obdinfo.obd_name); resource_list_free(&di->rl); ofw_bus_gen_destroy_devinfo(&di->obdinfo); free(di, M_DEVBUF); continue; } device_set_ivars(cdev, di); } fdt_pinctrl_register(dev, "atmel,pins"); return (bus_generic_attach(dev)); } static const struct ofw_bus_devinfo * pinctrl_get_devinfo(device_t bus __unused, device_t child) { struct pinctrl_devinfo *ndi; ndi = device_get_ivars(child); return (&ndi->obdinfo); } static struct resource * pinctrl_alloc_resource(device_t bus, device_t child, int type, int *rid, u_long start, u_long end, u_long count, u_int flags) { struct pinctrl_softc *sc; struct pinctrl_devinfo *di; struct resource_list_entry *rle; int j; sc = device_get_softc(bus); /* * Request for the default allocation with a given rid: use resource * list stored in the local device info. */ if (RMAN_IS_DEFAULT_RANGE(start, end)) { if ((di = device_get_ivars(child)) == NULL) return (NULL); if (type == SYS_RES_IOPORT) type = SYS_RES_MEMORY; rle = resource_list_find(&di->rl, type, *rid); if (rle == NULL) { // if (bootverbose) device_printf(bus, "no default resources for " "rid = %d, type = %d\n", *rid, type); return (NULL); } start = rle->start; end = rle->end; count = rle->count; } if (type == SYS_RES_MEMORY) { /* Remap through ranges property */ for (j = 0; j < sc->nranges; j++) { if (start >= sc->ranges[j].bus && end < sc->ranges[j].bus + sc->ranges[j].size) { start -= sc->ranges[j].bus; start += sc->ranges[j].host; end -= sc->ranges[j].bus; end += sc->ranges[j].host; break; } } if (j == sc->nranges && sc->nranges != 0) { // if (bootverbose) device_printf(bus, "Could not map resource " "%#lx-%#lx\n", start, end); return (NULL); } } return (bus_generic_alloc_resource(bus, child, type, rid, start, end, count, flags)); } static int pinctrl_print_res(struct pinctrl_devinfo *di) { int rv; rv = 0; rv += resource_list_print_type(&di->rl, "mem", SYS_RES_MEMORY, "%#jx"); rv += resource_list_print_type(&di->rl, "irq", SYS_RES_IRQ, "%jd"); return (rv); } static void pinctrl_probe_nomatch(device_t bus, device_t child) { const char *name, *type, *compat; // if (!bootverbose) return; name = ofw_bus_get_name(child); type = ofw_bus_get_type(child); compat = ofw_bus_get_compat(child); device_printf(bus, "<%s>", name != NULL ? name : "unknown"); pinctrl_print_res(device_get_ivars(child)); if (!ofw_bus_status_okay(child)) printf(" disabled"); if (type) printf(" type %s", type); if (compat) printf(" compat %s", compat); printf(" (no driver attached)\n"); } static int pinctrl_print_child(device_t bus, device_t child) { int rv; rv = bus_print_child_header(bus, child); rv += pinctrl_print_res(device_get_ivars(child)); if (!ofw_bus_status_okay(child)) rv += printf(" disabled"); rv += bus_print_child_footer(bus, child); return (rv); } const char *periphs[] = {"gpio", "periph A", "periph B", "periph C", "periph D", "periph E" }; struct pincfg { uint32_t unit; uint32_t pin; uint32_t periph; uint32_t flags; }; static int pinctrl_configure_pins(device_t bus, phandle_t cfgxref) { struct pinctrl_softc *sc; struct pincfg *cfg, *cfgdata; char name[32]; phandle_t node; ssize_t npins; int i; sc = device_get_softc(bus); node = OF_node_from_xref(cfgxref); memset(name, 0, sizeof(name)); OF_getprop(node, "name", name, sizeof(name)); npins = OF_getencprop_alloc_multi(node, "atmel,pins", sizeof(*cfgdata), (void **)&cfgdata); if (npins < 0) { printf("We're doing it wrong %s\n", name); return (ENXIO); } if (npins == 0) return (0); for (i = 0, cfg = cfgdata; i < npins; i++, cfg++) { uint32_t pio; pio = (0xfffffff & sc->ranges[0].bus) + 0x200 * cfg->unit; printf("P%c%d %s %#x\n", cfg->unit + 'A', cfg->pin, periphs[cfg->periph], cfg->flags); switch (cfg->periph) { case 0: at91_pio_use_gpio(pio, 1u << cfg->pin); at91_pio_gpio_pullup(pio, 1u << cfg->pin, !!(cfg->flags & 1)); at91_pio_gpio_high_z(pio, 1u << cfg->pin, !!(cfg->flags & 2)); at91_pio_gpio_set_deglitch(pio, 1u << cfg->pin, !!(cfg->flags & 4)); // at91_pio_gpio_pulldown(pio, 1u << cfg->pin, // !!(cfg->flags & 8)); // at91_pio_gpio_dis_schmidt(pio, // 1u << cfg->pin, !!(cfg->flags & 16)); break; case 1: at91_pio_use_periph_a(pio, 1u << cfg->pin, cfg->flags); break; case 2: at91_pio_use_periph_b(pio, 1u << cfg->pin, cfg->flags); break; } } OF_prop_free(cfgdata); return (0); } static void pinctrl_new_pass(device_t bus) { struct pinctrl_softc *sc; sc = device_get_softc(bus); bus_generic_new_pass(bus); if (sc->done_pinmux || bus_current_pass < BUS_PASS_PINMUX) return; sc->done_pinmux++; fdt_pinctrl_configure_tree(bus); } static device_method_t at91_pinctrl_methods[] = { DEVMETHOD(device_probe, at91_pinctrl_probe), DEVMETHOD(device_attach, at91_pinctrl_attach), DEVMETHOD(bus_print_child, pinctrl_print_child), DEVMETHOD(bus_probe_nomatch, pinctrl_probe_nomatch), DEVMETHOD(bus_setup_intr, bus_generic_setup_intr), DEVMETHOD(bus_teardown_intr, bus_generic_teardown_intr), DEVMETHOD(bus_alloc_resource, pinctrl_alloc_resource), DEVMETHOD(bus_release_resource, bus_generic_release_resource), DEVMETHOD(bus_activate_resource, bus_generic_activate_resource), DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource), DEVMETHOD(bus_adjust_resource, bus_generic_adjust_resource), DEVMETHOD(bus_child_pnpinfo_str, ofw_bus_gen_child_pnpinfo_str), DEVMETHOD(bus_new_pass, pinctrl_new_pass), /* ofw_bus interface */ DEVMETHOD(ofw_bus_get_devinfo, pinctrl_get_devinfo), DEVMETHOD(ofw_bus_get_compat, ofw_bus_gen_get_compat), DEVMETHOD(ofw_bus_get_model, ofw_bus_gen_get_model), DEVMETHOD(ofw_bus_get_name, ofw_bus_gen_get_name), DEVMETHOD(ofw_bus_get_node, ofw_bus_gen_get_node), DEVMETHOD(ofw_bus_get_type, ofw_bus_gen_get_type), /* fdt_pintrl interface */ DEVMETHOD(fdt_pinctrl_configure,pinctrl_configure_pins), DEVMETHOD_END }; static driver_t at91_pinctrl_driver = { "at91_pinctrl", at91_pinctrl_methods, sizeof(struct pinctrl_softc), }; static devclass_t at91_pinctrl_devclass; EARLY_DRIVER_MODULE(at91_pinctrl, simplebus, at91_pinctrl_driver, at91_pinctrl_devclass, NULL, NULL, BUS_PASS_BUS); /* * dummy driver to force pass BUS_PASS_PINMUX to happen. */ static int at91_pingroup_probe(device_t dev) { return ENXIO; } static device_method_t at91_pingroup_methods[] = { DEVMETHOD(device_probe, at91_pingroup_probe), DEVMETHOD_END }; static driver_t at91_pingroup_driver = { "at91_pingroup", at91_pingroup_methods, 0, }; static devclass_t at91_pingroup_devclass; EARLY_DRIVER_MODULE(at91_pingroup, at91_pinctrl, at91_pingroup_driver, at91_pingroup_devclass, NULL, NULL, BUS_PASS_PINMUX); Index: head/sys/arm/at91/at91_pio.c =================================================================== --- head/sys/arm/at91/at91_pio.c (revision 333141) +++ head/sys/arm/at91/at91_pio.c (revision 333142) @@ -1,655 +1,655 @@ /*- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD * - * Copyright (c) 2006 M. Warner Losh. All rights reserved. + * Copyright (c) 2006 M. Warner Losh. * Copyright (C) 2012 Ian Lepore. 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 "opt_platform.h" #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef FDT #include #include #endif #define MAX_CHANGE 64 struct at91_pio_softc { device_t dev; /* Myself */ void *intrhand; /* Interrupt handle */ struct resource *irq_res; /* IRQ resource */ struct resource *mem_res; /* Memory resource */ struct sx sc_mtx; /* basically a perimeter lock */ struct cdev *cdev; struct selinfo selp; int buflen; uint8_t buf[MAX_CHANGE]; int flags; #define OPENED 1 }; static inline uint32_t RD4(struct at91_pio_softc *sc, bus_size_t off) { return (bus_read_4(sc->mem_res, off)); } static inline void WR4(struct at91_pio_softc *sc, bus_size_t off, uint32_t val) { bus_write_4(sc->mem_res, off, val); } #define AT91_PIO_LOCK(_sc) sx_xlock(&(_sc)->sc_mtx) #define AT91_PIO_UNLOCK(_sc) sx_xunlock(&(_sc)->sc_mtx) #define AT91_PIO_LOCK_INIT(_sc) \ sx_init(&_sc->sc_mtx, device_get_nameunit(_sc->dev)) #define AT91_PIO_LOCK_DESTROY(_sc) sx_destroy(&_sc->sc_mtx); #define AT91_PIO_ASSERT_LOCKED(_sc) sx_assert(&_sc->sc_mtx, SA_XLOCKED); #define AT91_PIO_ASSERT_UNLOCKED(_sc) sx_assert(&_sc->sc_mtx, SA_UNLOCKED); #define CDEV2SOFTC(dev) ((dev)->si_drv1) static devclass_t at91_pio_devclass; /* bus entry points */ static int at91_pio_probe(device_t dev); static int at91_pio_attach(device_t dev); static int at91_pio_detach(device_t dev); static void at91_pio_intr(void *); /* helper routines */ static int at91_pio_activate(device_t dev); static void at91_pio_deactivate(device_t dev); /* cdev routines */ static d_open_t at91_pio_open; static d_close_t at91_pio_close; static d_read_t at91_pio_read; static d_poll_t at91_pio_poll; static d_ioctl_t at91_pio_ioctl; static struct cdevsw at91_pio_cdevsw = { .d_version = D_VERSION, .d_open = at91_pio_open, .d_close = at91_pio_close, .d_read = at91_pio_read, .d_poll = at91_pio_poll, .d_ioctl = at91_pio_ioctl }; static int at91_pio_probe(device_t dev) { const char *name; #ifdef FDT if (!ofw_bus_is_compatible(dev, "atmel,at91rm9200-gpio")) return (ENXIO); #endif switch (device_get_unit(dev)) { case 0: name = "PIOA"; break; case 1: name = "PIOB"; break; case 2: name = "PIOC"; break; case 3: name = "PIOD"; break; case 4: name = "PIOE"; break; case 5: name = "PIOF"; break; default: name = "PIO"; break; } device_set_desc(dev, name); return (0); } static int at91_pio_attach(device_t dev) { struct at91_pio_softc *sc; int err; sc = device_get_softc(dev); sc->dev = dev; err = at91_pio_activate(dev); if (err) goto out; if (bootverbose) device_printf(dev, "ABSR: %#x OSR: %#x PSR:%#x ODSR: %#x\n", RD4(sc, PIO_ABSR), RD4(sc, PIO_OSR), RD4(sc, PIO_PSR), RD4(sc, PIO_ODSR)); AT91_PIO_LOCK_INIT(sc); /* * Activate the interrupt, but disable all interrupts in the hardware. */ WR4(sc, PIO_IDR, 0xffffffff); err = bus_setup_intr(dev, sc->irq_res, INTR_TYPE_MISC, NULL, at91_pio_intr, sc, &sc->intrhand); if (err) { AT91_PIO_LOCK_DESTROY(sc); goto out; } sc->cdev = make_dev(&at91_pio_cdevsw, device_get_unit(dev), UID_ROOT, GID_WHEEL, 0600, "pio%d", device_get_unit(dev)); if (sc->cdev == NULL) { err = ENOMEM; goto out; } sc->cdev->si_drv1 = sc; out: if (err) at91_pio_deactivate(dev); return (err); } static int at91_pio_detach(device_t dev) { return (EBUSY); /* XXX */ } static int at91_pio_activate(device_t dev) { struct at91_pio_softc *sc; int rid; sc = device_get_softc(dev); rid = 0; sc->mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, RF_ACTIVE); if (sc->mem_res == NULL) goto errout; rid = 0; sc->irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, RF_ACTIVE | RF_SHAREABLE); if (sc->irq_res == NULL) goto errout; return (0); errout: at91_pio_deactivate(dev); return (ENOMEM); } static void at91_pio_deactivate(device_t dev) { struct at91_pio_softc *sc; sc = device_get_softc(dev); if (sc->intrhand) bus_teardown_intr(dev, sc->irq_res, sc->intrhand); sc->intrhand = NULL; bus_generic_detach(sc->dev); if (sc->mem_res) bus_release_resource(dev, SYS_RES_MEMORY, rman_get_rid(sc->mem_res), sc->mem_res); sc->mem_res = NULL; if (sc->irq_res) bus_release_resource(dev, SYS_RES_IRQ, rman_get_rid(sc->irq_res), sc->irq_res); sc->irq_res = NULL; } static void at91_pio_intr(void *xsc) { struct at91_pio_softc *sc = xsc; uint32_t status; int i; /* Reading the status also clears the interrupt. */ status = RD4(sc, PIO_ISR) & RD4(sc, PIO_IMR); if (status != 0) { AT91_PIO_LOCK(sc); for (i = 0; status != 0 && sc->buflen < MAX_CHANGE; ++i) { if (status & 1) sc->buf[sc->buflen++] = (uint8_t)i; status >>= 1; } AT91_PIO_UNLOCK(sc); wakeup(sc); selwakeup(&sc->selp); } } static int at91_pio_open(struct cdev *dev, int oflags, int devtype, struct thread *td) { struct at91_pio_softc *sc; sc = CDEV2SOFTC(dev); AT91_PIO_LOCK(sc); if (!(sc->flags & OPENED)) { sc->flags |= OPENED; } AT91_PIO_UNLOCK(sc); return (0); } static int at91_pio_close(struct cdev *dev, int fflag, int devtype, struct thread *td) { struct at91_pio_softc *sc; sc = CDEV2SOFTC(dev); AT91_PIO_LOCK(sc); sc->flags &= ~OPENED; AT91_PIO_UNLOCK(sc); return (0); } static int at91_pio_poll(struct cdev *dev, int events, struct thread *td) { struct at91_pio_softc *sc; int revents = 0; sc = CDEV2SOFTC(dev); AT91_PIO_LOCK(sc); if (events & (POLLIN | POLLRDNORM)) { if (sc->buflen != 0) revents |= events & (POLLIN | POLLRDNORM); else selrecord(td, &sc->selp); } AT91_PIO_UNLOCK(sc); return (revents); } static int at91_pio_read(struct cdev *dev, struct uio *uio, int flag) { struct at91_pio_softc *sc; int err, ret, len; sc = CDEV2SOFTC(dev); AT91_PIO_LOCK(sc); err = 0; ret = 0; while (uio->uio_resid) { while (sc->buflen == 0 && err == 0) err = msleep(sc, &sc->sc_mtx, PCATCH | PZERO, "prd", 0); if (err != 0) break; len = MIN(sc->buflen, uio->uio_resid); err = uiomove(sc->buf, len, uio); if (err != 0) break; /* * If we read the whole thing no datacopy is needed, * otherwise we move the data down. */ ret += len; if (sc->buflen == len) sc->buflen = 0; else { bcopy(sc->buf + len, sc->buf, sc->buflen - len); sc->buflen -= len; } /* If there's no data left, end the read. */ if (sc->buflen == 0) break; } AT91_PIO_UNLOCK(sc); return (err); } static void at91_pio_bang32(struct at91_pio_softc *sc, uint32_t bits, uint32_t datapin, uint32_t clockpin) { int i; for (i = 0; i < 32; i++) { if (bits & 0x80000000) WR4(sc, PIO_SODR, datapin); else WR4(sc, PIO_CODR, datapin); bits <<= 1; WR4(sc, PIO_CODR, clockpin); WR4(sc, PIO_SODR, clockpin); } } static void at91_pio_bang(struct at91_pio_softc *sc, uint8_t bits, uint32_t bitcount, uint32_t datapin, uint32_t clockpin) { int i; for (i = 0; i < bitcount; i++) { if (bits & 0x80) WR4(sc, PIO_SODR, datapin); else WR4(sc, PIO_CODR, datapin); bits <<= 1; WR4(sc, PIO_CODR, clockpin); WR4(sc, PIO_SODR, clockpin); } } static int at91_pio_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int fflag, struct thread *td) { struct at91_pio_softc *sc; struct at91_gpio_cfg *cfg; struct at91_gpio_info *info; struct at91_gpio_bang *bang; struct at91_gpio_bang_many *bangmany; uint32_t i, num; uint8_t many[1024], *walker; int err; int bitcount; sc = CDEV2SOFTC(dev); switch(cmd) { case AT91_GPIO_SET: /* turn bits on */ WR4(sc, PIO_SODR, *(uint32_t *)data); return (0); case AT91_GPIO_CLR: /* turn bits off */ WR4(sc, PIO_CODR, *(uint32_t *)data); return (0); case AT91_GPIO_READ: /* Get the status of input bits */ *(uint32_t *)data = RD4(sc, PIO_PDSR); return (0); case AT91_GPIO_CFG: /* Configure AT91_GPIO pins */ cfg = (struct at91_gpio_cfg *)data; if (cfg->cfgmask & AT91_GPIO_CFG_INPUT) { WR4(sc, PIO_OER, cfg->iomask & ~cfg->input); WR4(sc, PIO_ODR, cfg->iomask & cfg->input); } if (cfg->cfgmask & AT91_GPIO_CFG_HI_Z) { WR4(sc, PIO_MDDR, cfg->iomask & ~cfg->hi_z); WR4(sc, PIO_MDER, cfg->iomask & cfg->hi_z); } if (cfg->cfgmask & AT91_GPIO_CFG_PULLUP) { WR4(sc, PIO_PUDR, cfg->iomask & ~cfg->pullup); WR4(sc, PIO_PUER, cfg->iomask & cfg->pullup); } if (cfg->cfgmask & AT91_GPIO_CFG_GLITCH) { WR4(sc, PIO_IFDR, cfg->iomask & ~cfg->glitch); WR4(sc, PIO_IFER, cfg->iomask & cfg->glitch); } if (cfg->cfgmask & AT91_GPIO_CFG_GPIO) { WR4(sc, PIO_PDR, cfg->iomask & ~cfg->gpio); WR4(sc, PIO_PER, cfg->iomask & cfg->gpio); } if (cfg->cfgmask & AT91_GPIO_CFG_PERIPH) { WR4(sc, PIO_ASR, cfg->iomask & ~cfg->periph); WR4(sc, PIO_BSR, cfg->iomask & cfg->periph); } if (cfg->cfgmask & AT91_GPIO_CFG_INTR) { WR4(sc, PIO_IDR, cfg->iomask & ~cfg->intr); WR4(sc, PIO_IER, cfg->iomask & cfg->intr); } return (0); case AT91_GPIO_BANG: bang = (struct at91_gpio_bang *)data; at91_pio_bang32(sc, bang->bits, bang->datapin, bang->clockpin); return (0); case AT91_GPIO_BANG_MANY: bangmany = (struct at91_gpio_bang_many *)data; walker = (uint8_t *)bangmany->bits; bitcount = bangmany->numbits; while (bitcount > 0) { num = MIN((bitcount + 7) / 8, sizeof(many)); err = copyin(walker, many, num); if (err) return err; for (i = 0; i < num && bitcount > 0; i++, bitcount -= 8) if (bitcount >= 8) at91_pio_bang(sc, many[i], 8, bangmany->datapin, bangmany->clockpin); else at91_pio_bang(sc, many[i], bitcount, bangmany->datapin, bangmany->clockpin); walker += num; } return (0); case AT91_GPIO_INFO: /* Learn about this device's AT91_GPIO bits */ info = (struct at91_gpio_info *)data; info->output_status = RD4(sc, PIO_ODSR); info->input_status = RD4(sc, PIO_OSR); info->highz_status = RD4(sc, PIO_MDSR); info->pullup_status = RD4(sc, PIO_PUSR); info->glitch_status = RD4(sc, PIO_IFSR); info->enabled_status = RD4(sc, PIO_PSR); info->periph_status = RD4(sc, PIO_ABSR); info->intr_status = RD4(sc, PIO_IMR); memset(info->extra_status, 0, sizeof(info->extra_status)); return (0); } return (ENOTTY); } /* * The following functions are called early in the boot process, so * don't use bus_space, as that isn't yet available when we need to use * them. */ void at91_pio_use_periph_a(uint32_t pio, uint32_t periph_a_mask, int use_pullup) { uint32_t *PIO = (uint32_t *)(AT91_BASE + pio); PIO[PIO_ASR / 4] = periph_a_mask; PIO[PIO_PDR / 4] = periph_a_mask; if (use_pullup) PIO[PIO_PUER / 4] = periph_a_mask; else PIO[PIO_PUDR / 4] = periph_a_mask; } void at91_pio_use_periph_b(uint32_t pio, uint32_t periph_b_mask, int use_pullup) { uint32_t *PIO = (uint32_t *)(AT91_BASE + pio); PIO[PIO_BSR / 4] = periph_b_mask; PIO[PIO_PDR / 4] = periph_b_mask; if (use_pullup) PIO[PIO_PUER / 4] = periph_b_mask; else PIO[PIO_PUDR / 4] = periph_b_mask; } void at91_pio_use_gpio(uint32_t pio, uint32_t gpio_mask) { uint32_t *PIO = (uint32_t *)(AT91_BASE + pio); PIO[PIO_PER / 4] = gpio_mask; } void at91_pio_gpio_input(uint32_t pio, uint32_t input_enable_mask) { uint32_t *PIO = (uint32_t *)(AT91_BASE + pio); PIO[PIO_ODR / 4] = input_enable_mask; } void at91_pio_gpio_output(uint32_t pio, uint32_t output_enable_mask, int use_pullup) { uint32_t *PIO = (uint32_t *)(AT91_BASE + pio); PIO[PIO_OER / 4] = output_enable_mask; if (use_pullup) PIO[PIO_PUER / 4] = output_enable_mask; else PIO[PIO_PUDR / 4] = output_enable_mask; } void at91_pio_gpio_high_z(uint32_t pio, uint32_t high_z_mask, int enable) { uint32_t *PIO = (uint32_t *)(AT91_BASE + pio); if (enable) PIO[PIO_MDER / 4] = high_z_mask; else PIO[PIO_MDDR / 4] = high_z_mask; } void at91_pio_gpio_set(uint32_t pio, uint32_t data_mask) { uint32_t *PIO = (uint32_t *)(AT91_BASE + pio); PIO[PIO_SODR / 4] = data_mask; } void at91_pio_gpio_clear(uint32_t pio, uint32_t data_mask) { uint32_t *PIO = (uint32_t *)(AT91_BASE + pio); PIO[PIO_CODR / 4] = data_mask; } uint32_t at91_pio_gpio_get(uint32_t pio, uint32_t data_mask) { uint32_t *PIO = (uint32_t *)(AT91_BASE + pio); return (PIO[PIO_PDSR / 4] & data_mask); } void at91_pio_gpio_set_deglitch(uint32_t pio, uint32_t data_mask, int use_deglitch) { uint32_t *PIO = (uint32_t *)(AT91_BASE + pio); if (use_deglitch) PIO[PIO_IFER / 4] = data_mask; else PIO[PIO_IFDR / 4] = data_mask; } void at91_pio_gpio_pullup(uint32_t pio, uint32_t data_mask, int do_pullup) { uint32_t *PIO = (uint32_t *)(AT91_BASE + pio); if (do_pullup) PIO[PIO_PUER / 4] = data_mask; else PIO[PIO_PUDR / 4] = data_mask; } void at91_pio_gpio_set_interrupt(uint32_t pio, uint32_t data_mask, int enable_interrupt) { uint32_t *PIO = (uint32_t *)(AT91_BASE + pio); if (enable_interrupt) PIO[PIO_IER / 4] = data_mask; else PIO[PIO_IDR / 4] = data_mask; } uint32_t at91_pio_gpio_clear_interrupt(uint32_t pio) { uint32_t *PIO = (uint32_t *)(AT91_BASE + pio); /* Reading this register will clear the interrupts. */ return (PIO[PIO_ISR / 4]); } static void at91_pio_new_pass(device_t dev) { device_printf(dev, "Pass %d\n", bus_current_pass); } static device_method_t at91_pio_methods[] = { /* Device interface */ DEVMETHOD(device_probe, at91_pio_probe), DEVMETHOD(device_attach, at91_pio_attach), DEVMETHOD(device_detach, at91_pio_detach), DEVMETHOD(bus_new_pass, at91_pio_new_pass), DEVMETHOD_END }; static driver_t at91_pio_driver = { "at91_pio", at91_pio_methods, sizeof(struct at91_pio_softc), }; #ifdef FDT EARLY_DRIVER_MODULE(at91_pio, at91_pinctrl, at91_pio_driver, at91_pio_devclass, NULL, NULL, BUS_PASS_INTERRUPT); #else DRIVER_MODULE(at91_pio, atmelarm, at91_pio_driver, at91_pio_devclass, NULL, NULL); #endif Index: head/sys/arm/at91/at91_pioreg.h =================================================================== --- head/sys/arm/at91/at91_pioreg.h (revision 333141) +++ head/sys/arm/at91/at91_pioreg.h (revision 333142) @@ -1,234 +1,234 @@ /*- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD * - * Copyright (c) 2006 M. Warner Losh. All rights reserved. + * Copyright (c) 2006 M. Warner Losh. * * 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_AT91_PIOREG_H #define ARM_AT91_AT91_PIOREG_H #ifndef ATMEL_ENV /* Registers */ #define PIO_PER 0x00 /* PIO Enable Register */ #define PIO_PDR 0x04 /* PIO Disable Register */ #define PIO_PSR 0x08 /* PIO Status Register */ /* 0x0c reserved */ #define PIO_OER 0x10 /* PIO Output Enable Register */ #define PIO_ODR 0x14 /* PIO Output Disable Register */ #define PIO_OSR 0x18 /* PIO Output Status Register */ /* 0x1c reserved */ #define PIO_IFER 0x20 /* PIO Glitch Input Enable Register */ #define PIO_IFDR 0x24 /* PIO Glitch Input Disable Register */ #define PIO_IFSR 0x28 /* PIO Glitch Input Status Register */ /* 0x2c reserved */ #define PIO_SODR 0x30 /* PIO Set Output Data Register */ #define PIO_CODR 0x34 /* PIO Clear Output Data Register */ #define PIO_ODSR 0x38 /* PIO Output Data Status Register */ #define PIO_PDSR 0x3c /* PIO Pin Data Status Register */ #define PIO_IER 0x40 /* PIO Interrupt Enable Register */ #define PIO_IDR 0x44 /* PIO Interrupt Disable Register */ #define PIO_IMR 0x48 /* PIO Interrupt Mask Register */ #define PIO_ISR 0x4c /* PIO Interrupt Status Register */ #define PIO_MDER 0x50 /* PIO Multi-Driver Enable Register */ #define PIO_MDDR 0x54 /* PIO Multi-Driver Disable Register */ #define PIO_MDSR 0x58 /* PIO Multi-Driver Status Register */ /* 0x5c reserved */ #define PIO_PUDR 0x60 /* PIO Pull-up Disable Register */ #define PIO_PUER 0x64 /* PIO Pull-up Enable Register */ #define PIO_PUSR 0x68 /* PIO Pull-up Status Register */ /* 0x6c reserved */ #define PIO_ASR 0x70 /* PIO Peripheral A Select Register */ #define PIO_BSR 0x74 /* PIO Peripheral B Select Register */ #define PIO_ABSR 0x78 /* PIO AB Status Register */ /* 0x7c-0x9c reserved */ #define PIO_OWER 0xa0 /* PIO Output Write Enable Register */ #define PIO_OWDR 0xa4 /* PIO Output Write Disable Register */ #define PIO_OWSR 0xa8 /* PIO Output Write Status Register */ /* 0xac reserved */ #endif #define AT91C_PIO_PA0 ((unsigned int) 1 << 0) // Pin Controlled by PA0 #define AT91C_PIO_PA1 ((unsigned int) 1 << 1) // Pin Controlled by PA1 #define AT91C_PIO_PA2 ((unsigned int) 1 << 2) // Pin Controlled by PA2 #define AT91C_PIO_PA3 ((unsigned int) 1 << 3) // Pin Controlled by PA3 #define AT91C_PIO_PA4 ((unsigned int) 1 << 4) // Pin Controlled by PA4 #define AT91C_PIO_PA5 ((unsigned int) 1 << 5) // Pin Controlled by PA5 #define AT91C_PIO_PA6 ((unsigned int) 1 << 6) // Pin Controlled by PA6 #define AT91C_PIO_PA7 ((unsigned int) 1 << 7) // Pin Controlled by PA7 #define AT91C_PIO_PA8 ((unsigned int) 1 << 8) // Pin Controlled by PA8 #define AT91C_PIO_PA9 ((unsigned int) 1 << 9) // Pin Controlled by PA9 #define AT91C_PIO_PA10 ((unsigned int) 1 << 10) // Pin Controlled by PA10 #define AT91C_PIO_PA11 ((unsigned int) 1 << 11) // Pin Controlled by PA11 #define AT91C_PIO_PA12 ((unsigned int) 1 << 12) // Pin Controlled by PA12 #define AT91C_PIO_PA13 ((unsigned int) 1 << 13) // Pin Controlled by PA13 #define AT91C_PIO_PA14 ((unsigned int) 1 << 14) // Pin Controlled by PA14 #define AT91C_PIO_PA15 ((unsigned int) 1 << 15) // Pin Controlled by PA15 #define AT91C_PIO_PA16 ((unsigned int) 1 << 16) // Pin Controlled by PA16 #define AT91C_PIO_PA17 ((unsigned int) 1 << 17) // Pin Controlled by PA17 #define AT91C_PIO_PA18 ((unsigned int) 1 << 18) // Pin Controlled by PA18 #define AT91C_PIO_PA19 ((unsigned int) 1 << 19) // Pin Controlled by PA19 #define AT91C_PIO_PA20 ((unsigned int) 1 << 20) // Pin Controlled by PA20 #define AT91C_PIO_PA21 ((unsigned int) 1 << 21) // Pin Controlled by PA21 #define AT91C_PIO_PA22 ((unsigned int) 1 << 22) // Pin Controlled by PA22 #define AT91C_PIO_PA23 ((unsigned int) 1 << 23) // Pin Controlled by PA23 #define AT91C_PIO_PA24 ((unsigned int) 1 << 24) // Pin Controlled by PA24 #define AT91C_PIO_PA25 ((unsigned int) 1 << 25) // Pin Controlled by PA25 #define AT91C_PIO_PA26 ((unsigned int) 1 << 26) // Pin Controlled by PA26 #define AT91C_PIO_PA27 ((unsigned int) 1 << 27) // Pin Controlled by PA27 #define AT91C_PIO_PA28 ((unsigned int) 1 << 28) // Pin Controlled by PA28 #define AT91C_PIO_PA29 ((unsigned int) 1 << 29) // Pin Controlled by PA29 #define AT91C_PIO_PA30 ((unsigned int) 1 << 30) // Pin Controlled by PA30 #define AT91C_PIO_PA31 ((unsigned int) 1 << 31) // Pin Controlled by PA31 #define AT91C_PIO_PB0 ((unsigned int) 1 << 0) // Pin Controlled by PB0 #define AT91C_PIO_PB1 ((unsigned int) 1 << 1) // Pin Controlled by PB1 #define AT91C_PIO_PB2 ((unsigned int) 1 << 2) // Pin Controlled by PB2 #define AT91C_PIO_PB3 ((unsigned int) 1 << 3) // Pin Controlled by PB3 #define AT91C_PIO_PB4 ((unsigned int) 1 << 4) // Pin Controlled by PB4 #define AT91C_PIO_PB5 ((unsigned int) 1 << 5) // Pin Controlled by PB5 #define AT91C_PIO_PB6 ((unsigned int) 1 << 6) // Pin Controlled by PB6 #define AT91C_PIO_PB7 ((unsigned int) 1 << 7) // Pin Controlled by PB7 #define AT91C_PIO_PB8 ((unsigned int) 1 << 8) // Pin Controlled by PB8 #define AT91C_PIO_PB9 ((unsigned int) 1 << 9) // Pin Controlled by PB9 #define AT91C_PIO_PB10 ((unsigned int) 1 << 10) // Pin Controlled by PB10 #define AT91C_PIO_PB11 ((unsigned int) 1 << 11) // Pin Controlled by PB11 #define AT91C_PIO_PB12 ((unsigned int) 1 << 12) // Pin Controlled by PB12 #define AT91C_PIO_PB13 ((unsigned int) 1 << 13) // Pin Controlled by PB13 #define AT91C_PIO_PB14 ((unsigned int) 1 << 14) // Pin Controlled by PB14 #define AT91C_PIO_PB15 ((unsigned int) 1 << 15) // Pin Controlled by PB15 #define AT91C_PIO_PB16 ((unsigned int) 1 << 16) // Pin Controlled by PB16 #define AT91C_PIO_PB17 ((unsigned int) 1 << 17) // Pin Controlled by PB17 #define AT91C_PIO_PB18 ((unsigned int) 1 << 18) // Pin Controlled by PB18 #define AT91C_PIO_PB19 ((unsigned int) 1 << 19) // Pin Controlled by PB19 #define AT91C_PIO_PB20 ((unsigned int) 1 << 20) // Pin Controlled by PB20 #define AT91C_PIO_PB21 ((unsigned int) 1 << 21) // Pin Controlled by PB21 #define AT91C_PIO_PB22 ((unsigned int) 1 << 22) // Pin Controlled by PB22 #define AT91C_PIO_PB23 ((unsigned int) 1 << 23) // Pin Controlled by PB23 #define AT91C_PIO_PB24 ((unsigned int) 1 << 24) // Pin Controlled by PB24 #define AT91C_PIO_PB25 ((unsigned int) 1 << 25) // Pin Controlled by PB25 #define AT91C_PIO_PB26 ((unsigned int) 1 << 26) // Pin Controlled by PB26 #define AT91C_PIO_PB27 ((unsigned int) 1 << 27) // Pin Controlled by PB27 #define AT91C_PIO_PB28 ((unsigned int) 1 << 28) // Pin Controlled by PB28 #define AT91C_PIO_PB29 ((unsigned int) 1 << 29) // Pin Controlled by PB29 #define AT91C_PIO_PB30 ((unsigned int) 1 << 30) // Pin Controlled by PB30 #define AT91C_PIO_PB31 ((unsigned int) 1 << 31) // Pin Controlled by PB31 #define AT91C_PIO_PC0 ((unsigned int) 1 << 0) // Pin Controlled by PC0 #define AT91C_PIO_PC1 ((unsigned int) 1 << 1) // Pin Controlled by PC1 #define AT91C_PIO_PC2 ((unsigned int) 1 << 2) // Pin Controlled by PC2 #define AT91C_PIO_PC3 ((unsigned int) 1 << 3) // Pin Controlled by PC3 #define AT91C_PIO_PC4 ((unsigned int) 1 << 4) // Pin Controlled by PC4 #define AT91C_PIO_PC5 ((unsigned int) 1 << 5) // Pin Controlled by PC5 #define AT91C_PIO_PC6 ((unsigned int) 1 << 6) // Pin Controlled by PC6 #define AT91C_PIO_PC7 ((unsigned int) 1 << 7) // Pin Controlled by PC7 #define AT91C_PIO_PC8 ((unsigned int) 1 << 8) // Pin Controlled by PC8 #define AT91C_PIO_PC9 ((unsigned int) 1 << 9) // Pin Controlled by PC9 #define AT91C_PIO_PC10 ((unsigned int) 1 << 10) // Pin Controlled by PC10 #define AT91C_PIO_PC11 ((unsigned int) 1 << 11) // Pin Controlled by PC11 #define AT91C_PIO_PC12 ((unsigned int) 1 << 12) // Pin Controlled by PC12 #define AT91C_PIO_PC13 ((unsigned int) 1 << 13) // Pin Controlled by PC13 #define AT91C_PIO_PC14 ((unsigned int) 1 << 14) // Pin Controlled by PC14 #define AT91C_PIO_PC15 ((unsigned int) 1 << 15) // Pin Controlled by PC15 #define AT91C_PIO_PC16 ((unsigned int) 1 << 16) // Pin Controlled by PC16 #define AT91C_PIO_PC17 ((unsigned int) 1 << 17) // Pin Controlled by PC17 #define AT91C_PIO_PC18 ((unsigned int) 1 << 18) // Pin Controlled by PC18 #define AT91C_PIO_PC19 ((unsigned int) 1 << 19) // Pin Controlled by PC19 #define AT91C_PIO_PC20 ((unsigned int) 1 << 20) // Pin Controlled by PC20 #define AT91C_PIO_PC21 ((unsigned int) 1 << 21) // Pin Controlled by PC21 #define AT91C_PIO_PC22 ((unsigned int) 1 << 22) // Pin Controlled by PC22 #define AT91C_PIO_PC23 ((unsigned int) 1 << 23) // Pin Controlled by PC23 #define AT91C_PIO_PC24 ((unsigned int) 1 << 24) // Pin Controlled by PC24 #define AT91C_PIO_PC25 ((unsigned int) 1 << 25) // Pin Controlled by PC25 #define AT91C_PIO_PC26 ((unsigned int) 1 << 26) // Pin Controlled by PC26 #define AT91C_PIO_PC27 ((unsigned int) 1 << 27) // Pin Controlled by PC27 #define AT91C_PIO_PC28 ((unsigned int) 1 << 28) // Pin Controlled by PC28 #define AT91C_PIO_PC29 ((unsigned int) 1 << 29) // Pin Controlled by PC29 #define AT91C_PIO_PC30 ((unsigned int) 1 << 30) // Pin Controlled by PC30 #define AT91C_PIO_PC31 ((unsigned int) 1 << 31) // Pin Controlled by PC31 #define AT91C_PIO_PD0 ((unsigned int) 1 << 0) // Pin Controlled by PD0 #define AT91C_PIO_PD1 ((unsigned int) 1 << 1) // Pin Controlled by PD1 #define AT91C_PIO_PD2 ((unsigned int) 1 << 2) // Pin Controlled by PD2 #define AT91C_PIO_PD3 ((unsigned int) 1 << 3) // Pin Controlled by PD3 #define AT91C_PIO_PD4 ((unsigned int) 1 << 4) // Pin Controlled by PD4 #define AT91C_PIO_PD5 ((unsigned int) 1 << 5) // Pin Controlled by PD5 #define AT91C_PIO_PD6 ((unsigned int) 1 << 6) // Pin Controlled by PD6 #define AT91C_PIO_PD7 ((unsigned int) 1 << 7) // Pin Controlled by PD7 #define AT91C_PIO_PD8 ((unsigned int) 1 << 8) // Pin Controlled by PD8 #define AT91C_PIO_PD9 ((unsigned int) 1 << 9) // Pin Controlled by PD9 #define AT91C_PIO_PD10 ((unsigned int) 1 << 10) // Pin Controlled by PD10 #define AT91C_PIO_PD11 ((unsigned int) 1 << 11) // Pin Controlled by PD11 #define AT91C_PIO_PD12 ((unsigned int) 1 << 12) // Pin Controlled by PD12 #define AT91C_PIO_PD13 ((unsigned int) 1 << 13) // Pin Controlled by PD13 #define AT91C_PIO_PD14 ((unsigned int) 1 << 14) // Pin Controlled by PD14 #define AT91C_PIO_PD15 ((unsigned int) 1 << 15) // Pin Controlled by PD15 #define AT91C_PIO_PD16 ((unsigned int) 1 << 16) // Pin Controlled by PD16 #define AT91C_PIO_PD17 ((unsigned int) 1 << 17) // Pin Controlled by PD17 #define AT91C_PIO_PD18 ((unsigned int) 1 << 18) // Pin Controlled by PD18 #define AT91C_PIO_PD19 ((unsigned int) 1 << 19) // Pin Controlled by PD19 #define AT91C_PIO_PD20 ((unsigned int) 1 << 20) // Pin Controlled by PD20 #define AT91C_PIO_PD21 ((unsigned int) 1 << 21) // Pin Controlled by PD21 #define AT91C_PIO_PD22 ((unsigned int) 1 << 22) // Pin Controlled by PD22 #define AT91C_PIO_PD23 ((unsigned int) 1 << 23) // Pin Controlled by PD23 #define AT91C_PIO_PD24 ((unsigned int) 1 << 24) // Pin Controlled by PD24 #define AT91C_PIO_PD25 ((unsigned int) 1 << 25) // Pin Controlled by PD25 #define AT91C_PIO_PD26 ((unsigned int) 1 << 26) // Pin Controlled by PD26 #define AT91C_PIO_PD27 ((unsigned int) 1 << 27) // Pin Controlled by PD27 #define AT91C_PIO_PD28 ((unsigned int) 1 << 28) // Pin Controlled by PD28 #define AT91C_PIO_PD29 ((unsigned int) 1 << 29) // Pin Controlled by PD29 #define AT91C_PIO_PD30 ((unsigned int) 1 << 30) // Pin Controlled by PD30 #define AT91C_PIO_PD31 ((unsigned int) 1 << 31) // Pin Controlled by PD31 #define AT91C_PIO_PE0 ((unsigned int) 1 << 0) // Pin Controlled by PE0 #define AT91C_PIO_PE1 ((unsigned int) 1 << 1) // Pin Controlled by PE1 #define AT91C_PIO_PE2 ((unsigned int) 1 << 2) // Pin Controlled by PE2 #define AT91C_PIO_PE3 ((unsigned int) 1 << 3) // Pin Controlled by PE3 #define AT91C_PIO_PE4 ((unsigned int) 1 << 4) // Pin Controlled by PE4 #define AT91C_PIO_PE5 ((unsigned int) 1 << 5) // Pin Controlled by PE5 #define AT91C_PIO_PE6 ((unsigned int) 1 << 6) // Pin Controlled by PE6 #define AT91C_PIO_PE7 ((unsigned int) 1 << 7) // Pin Controlled by PE7 #define AT91C_PIO_PE8 ((unsigned int) 1 << 8) // Pin Controlled by PE8 #define AT91C_PIO_PE9 ((unsigned int) 1 << 9) // Pin Controlled by PE9 #define AT91C_PIO_PE10 ((unsigned int) 1 << 10) // Pin Controlled by PE10 #define AT91C_PIO_PE11 ((unsigned int) 1 << 11) // Pin Controlled by PE11 #define AT91C_PIO_PE12 ((unsigned int) 1 << 12) // Pin Controlled by PE12 #define AT91C_PIO_PE13 ((unsigned int) 1 << 13) // Pin Controlled by PE13 #define AT91C_PIO_PE14 ((unsigned int) 1 << 14) // Pin Controlled by PE14 #define AT91C_PIO_PE15 ((unsigned int) 1 << 15) // Pin Controlled by PE15 #define AT91C_PIO_PE16 ((unsigned int) 1 << 16) // Pin Controlled by PE16 #define AT91C_PIO_PE17 ((unsigned int) 1 << 17) // Pin Controlled by PE17 #define AT91C_PIO_PE18 ((unsigned int) 1 << 18) // Pin Controlled by PE18 #define AT91C_PIO_PE19 ((unsigned int) 1 << 19) // Pin Controlled by PE19 #define AT91C_PIO_PE20 ((unsigned int) 1 << 20) // Pin Controlled by PE20 #define AT91C_PIO_PE21 ((unsigned int) 1 << 21) // Pin Controlled by PE21 #define AT91C_PIO_PE22 ((unsigned int) 1 << 22) // Pin Controlled by PE22 #define AT91C_PIO_PE23 ((unsigned int) 1 << 23) // Pin Controlled by PE23 #define AT91C_PIO_PE24 ((unsigned int) 1 << 24) // Pin Controlled by PE24 #define AT91C_PIO_PE25 ((unsigned int) 1 << 25) // Pin Controlled by PE25 #define AT91C_PIO_PE26 ((unsigned int) 1 << 26) // Pin Controlled by PE26 #define AT91C_PIO_PE27 ((unsigned int) 1 << 27) // Pin Controlled by PE27 #define AT91C_PIO_PE28 ((unsigned int) 1 << 28) // Pin Controlled by PE28 #define AT91C_PIO_PE29 ((unsigned int) 1 << 29) // Pin Controlled by PE29 #define AT91C_PIO_PE30 ((unsigned int) 1 << 30) // Pin Controlled by PE30 #define AT91C_PIO_PE31 ((unsigned int) 1 << 31) // Pin Controlled by PE31 #endif /* ARM_AT91_AT91_PIOREG_H */ Index: head/sys/arm/at91/at91_piovar.h =================================================================== --- head/sys/arm/at91/at91_piovar.h (revision 333141) +++ head/sys/arm/at91/at91_piovar.h (revision 333142) @@ -1,52 +1,52 @@ /*- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD * - * Copyright (c) 2006 M. Warner Losh. All rights reserved. + * Copyright (c) 2006 M. Warner Losh. * * 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_AT91_PIOVAR_H #define ARM_AT91_AT91_PIOVAR_H void at91_pio_use_periph_a(uint32_t pio, uint32_t periph_a_mask, int use_pullup); void at91_pio_use_periph_b(uint32_t pio, uint32_t periph_b_mask, int use_pullup); void at91_pio_use_gpio(uint32_t pio, uint32_t gpio_mask); void at91_pio_gpio_input(uint32_t pio, uint32_t input_enable_mask); void at91_pio_gpio_output(uint32_t pio, uint32_t output_enable_mask, int use_pullup); void at91_pio_gpio_high_z(uint32_t pio, uint32_t high_z_mask, int enable); void at91_pio_gpio_set(uint32_t pio, uint32_t data_mask); void at91_pio_gpio_clear(uint32_t pio, uint32_t data_mask); uint32_t at91_pio_gpio_get(uint32_t pio, uint32_t data_mask); void at91_pio_gpio_set_deglitch(uint32_t pio, uint32_t data_mask, int use_deglitch); void at91_pio_gpio_set_interrupt(uint32_t pio, uint32_t data_mask, int enable_interrupt); uint32_t at91_pio_gpio_clear_interrupt(uint32_t pio); void at91_pio_gpio_pullup(uint32_t pio, uint32_t data_mask, int do_pullup); #endif /* ARM_AT91_AT91_PIOVAR_H */ Index: head/sys/arm/at91/at91_pmc.c =================================================================== --- head/sys/arm/at91/at91_pmc.c (revision 333141) +++ head/sys/arm/at91/at91_pmc.c (revision 333142) @@ -1,719 +1,719 @@ /*- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD * - * Copyright (c) 2006 M. Warner Losh. All rights reserved. + * Copyright (c) 2006 M. Warner Losh. * Copyright (c) 2010 Greg Ansley. 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 "opt_platform.h" #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef FDT #include #include #endif static struct at91_pmc_softc { bus_space_tag_t sc_st; bus_space_handle_t sc_sh; struct resource *mem_res; /* Memory resource */ device_t dev; } *pmc_softc; static uint32_t pllb_init; MALLOC_DECLARE(M_PMC_CLK); MALLOC_DEFINE(M_PMC_CLK, "at91_pmc_clocks", "AT91 PMC Clock descriptors"); #define AT91_PMC_BASE 0xffffc00 static void at91_pmc_set_pllb_mode(struct at91_pmc_clock *, int); static void at91_pmc_set_upll_mode(struct at91_pmc_clock *, int); static void at91_pmc_set_sys_mode(struct at91_pmc_clock *, int); static void at91_pmc_set_periph_mode(struct at91_pmc_clock *, int); static void at91_pmc_clock_alias(const char *name, const char *alias); static struct at91_pmc_clock slck = { .name = "slck", /* 32,768 Hz slow clock */ .hz = 32768, .refcnt = 1, .id = 0, .primary = 1, }; /* * NOTE: Clocks for "ordinary peripheral" devices e.g. spi0, udp0, uhp0 etc. * are now created automatically. Only "system" clocks need be defined here. */ static struct at91_pmc_clock main_ck = { .name = "main", /* Main clock */ .refcnt = 0, .id = 1, .primary = 1, .pmc_mask = PMC_IER_MOSCS, }; static struct at91_pmc_clock plla = { .name = "plla", /* PLLA Clock, used for CPU clocking */ .parent = &main_ck, .refcnt = 1, .id = 0, .primary = 1, .pll = 1, .pmc_mask = PMC_IER_LOCKA, }; static struct at91_pmc_clock pllb = { .name = "pllb", /* PLLB Clock, used for USB functions */ .parent = &main_ck, .refcnt = 0, .id = 0, .primary = 1, .pll = 1, .pmc_mask = PMC_IER_LOCKB, .set_mode = &at91_pmc_set_pllb_mode, }; /* Used by USB on at91sam9g45 */ static struct at91_pmc_clock upll = { .name = "upll", /* UTMI PLL, used for USB functions on 9G45 family */ .parent = &main_ck, .refcnt = 0, .id = 0, .primary = 1, .pll = 1, .pmc_mask = (1 << 6), .set_mode = &at91_pmc_set_upll_mode, }; static struct at91_pmc_clock udpck = { .name = "udpck", .parent = &pllb, .pmc_mask = PMC_SCER_UDP, .set_mode = at91_pmc_set_sys_mode }; static struct at91_pmc_clock uhpck = { .name = "uhpck", .parent = &pllb, .pmc_mask = PMC_SCER_UHP, .set_mode = at91_pmc_set_sys_mode }; static struct at91_pmc_clock mck = { .name = "mck", /* Master (Peripheral) Clock */ .pmc_mask = PMC_IER_MCKRDY, .refcnt = 0, }; static struct at91_pmc_clock cpu = { .name = "cpu", /* CPU Clock */ .parent = &plla, .pmc_mask = PMC_SCER_PCK, .refcnt = 0, }; /* "+32" or the automatic peripheral clocks */ static struct at91_pmc_clock *clock_list[16+32] = { &slck, &main_ck, &plla, &pllb, &upll, &udpck, &uhpck, &mck, &cpu }; static inline uint32_t RD4(struct at91_pmc_softc *sc, bus_size_t off) { if (sc == NULL) { uint32_t *p = (uint32_t *)(AT91_BASE + AT91_PMC_BASE + off); return *p; } return (bus_read_4(sc->mem_res, off)); } static inline void WR4(struct at91_pmc_softc *sc, bus_size_t off, uint32_t val) { if (sc == NULL) { uint32_t *p = (uint32_t *)(AT91_BASE + AT91_PMC_BASE + off); *p = val; } else bus_write_4(sc->mem_res, off, val); } /* * The following is unused currently since we don't ever set the PLLA * frequency of the device. If we did, we'd have to also pay attention * to the ICPLLA bit in the PMC_PLLICPR register for frequencies lower * than ~600MHz, which the PMC code doesn't do right now. */ uint32_t at91_pmc_800mhz_plla_outb(int freq) { uint32_t outa; /* * Set OUTA, per the data sheet. See Table 46-16 titled * PLLA Frequency Regarding ICPLLA and OUTA in the SAM9X25 doc, * Table 46-17 in the SAM9G20 doc, or Table 46-16 in the SAM9G45 doc. * Note: the frequencies overlap by 5MHz, so we add 3 here to * center shoot the transition. */ freq /= 1000000; /* MHz */ if (freq >= 800) freq = 800; freq += 3; /* Allow for overlap. */ outa = 3 - ((freq / 50) & 3); /* 750 / 50 = 7, see table */ return (1 << 29)| (outa << 14); } uint32_t at91_pmc_800mhz_pllb_outb(int freq) { return (0); } void at91_pmc_set_pllb_mode(struct at91_pmc_clock *clk, int on) { struct at91_pmc_softc *sc = pmc_softc; uint32_t value; value = on ? pllb_init : 0; /* * Only write to the register if the value is changing. Besides being * good common sense, this works around RM9200 Errata #26 (CKGR_PLL[AB]R * must not be written with the same value currently in the register). */ if (RD4(sc, CKGR_PLLBR) != value) { WR4(sc, CKGR_PLLBR, value); while (on && (RD4(sc, PMC_SR) & PMC_IER_LOCKB) != PMC_IER_LOCKB) continue; } } static void at91_pmc_set_upll_mode(struct at91_pmc_clock *clk, int on) { struct at91_pmc_softc *sc = pmc_softc; uint32_t value; if (on) { on = PMC_IER_LOCKU; value = CKGR_UCKR_UPLLEN | CKGR_UCKR_BIASEN; } else value = 0; WR4(sc, CKGR_UCKR, RD4(sc, CKGR_UCKR) | value); while ((RD4(sc, PMC_SR) & PMC_IER_LOCKU) != on) continue; WR4(sc, PMC_USB, PMC_USB_USBDIV(9) | PMC_USB_USBS); WR4(sc, PMC_SCER, PMC_SCER_UHP_SAM9); } static void at91_pmc_set_sys_mode(struct at91_pmc_clock *clk, int on) { struct at91_pmc_softc *sc = pmc_softc; WR4(sc, on ? PMC_SCER : PMC_SCDR, clk->pmc_mask); if (on) while ((RD4(sc, PMC_SCSR) & clk->pmc_mask) != clk->pmc_mask) continue; else while ((RD4(sc, PMC_SCSR) & clk->pmc_mask) == clk->pmc_mask) continue; } static void at91_pmc_set_periph_mode(struct at91_pmc_clock *clk, int on) { struct at91_pmc_softc *sc = pmc_softc; WR4(sc, on ? PMC_PCER : PMC_PCDR, clk->pmc_mask); if (on) while ((RD4(sc, PMC_PCSR) & clk->pmc_mask) != clk->pmc_mask) continue; else while ((RD4(sc, PMC_PCSR) & clk->pmc_mask) == clk->pmc_mask) continue; } struct at91_pmc_clock * at91_pmc_clock_add(const char *name, uint32_t irq, struct at91_pmc_clock *parent) { struct at91_pmc_clock *clk; int i, buflen; clk = malloc(sizeof(*clk), M_PMC_CLK, M_NOWAIT | M_ZERO); if (clk == NULL) goto err; buflen = strlen(name) + 1; clk->name = malloc(buflen, M_PMC_CLK, M_NOWAIT); if (clk->name == NULL) goto err; strlcpy(clk->name, name, buflen); clk->pmc_mask = 1 << irq; clk->set_mode = &at91_pmc_set_periph_mode; if (parent == NULL) clk->parent = &mck; else clk->parent = parent; for (i = 0; i < nitems(clock_list); i++) { if (clock_list[i] == NULL) { clock_list[i] = clk; return (clk); } } err: if (clk != NULL) { if (clk->name != NULL) free(clk->name, M_PMC_CLK); free(clk, M_PMC_CLK); } panic("could not allocate pmc clock '%s'", name); return (NULL); } static void at91_pmc_clock_alias(const char *name, const char *alias) { struct at91_pmc_clock *clk, *alias_clk; clk = at91_pmc_clock_ref(name); if (clk) alias_clk = at91_pmc_clock_add(alias, 0, clk->parent); if (clk && alias_clk) { alias_clk->hz = clk->hz; alias_clk->pmc_mask = clk->pmc_mask; alias_clk->set_mode = clk->set_mode; } } struct at91_pmc_clock * at91_pmc_clock_ref(const char *name) { int i; for (i = 0; i < nitems(clock_list); i++) { if (clock_list[i] == NULL) break; if (strcmp(name, clock_list[i]->name) == 0) return (clock_list[i]); } return (NULL); } void at91_pmc_clock_deref(struct at91_pmc_clock *clk) { if (clk == NULL) return; } void at91_pmc_clock_enable(struct at91_pmc_clock *clk) { if (clk == NULL) return; /* XXX LOCKING? XXX */ if (clk->parent) at91_pmc_clock_enable(clk->parent); if (clk->refcnt++ == 0 && clk->set_mode) clk->set_mode(clk, 1); } void at91_pmc_clock_disable(struct at91_pmc_clock *clk) { if (clk == NULL) return; /* XXX LOCKING? XXX */ if (--clk->refcnt == 0 && clk->set_mode) clk->set_mode(clk, 0); if (clk->parent) at91_pmc_clock_disable(clk->parent); } static int at91_pmc_pll_rate(struct at91_pmc_clock *clk, uint32_t reg) { uint32_t mul, div, freq; freq = clk->parent->hz; div = (reg >> clk->pll_div_shift) & clk->pll_div_mask; mul = (reg >> clk->pll_mul_shift) & clk->pll_mul_mask; #if 0 printf("pll = (%d / %d) * %d = %d\n", freq, div, mul + 1, (freq/div) * (mul+1)); #endif if (div != 0 && mul != 0) { freq /= div; freq *= mul + 1; } else freq = 0; clk->hz = freq; return (freq); } static uint32_t at91_pmc_pll_calc(struct at91_pmc_clock *clk, uint32_t out_freq) { uint32_t i, div = 0, mul = 0, diff = 1 << 30; unsigned ret = 0x3e00; if (out_freq > clk->pll_max_out) goto fail; for (i = 1; i < 256; i++) { int32_t diff1; uint32_t input, mul1; input = clk->parent->hz / i; if (input < clk->pll_min_in) break; if (input > clk->pll_max_in) continue; mul1 = out_freq / input; if (mul1 > (clk->pll_mul_mask + 1)) continue; if (mul1 == 0) break; diff1 = out_freq - input * mul1; if (diff1 < 0) diff1 = -diff1; if (diff > diff1) { diff = diff1; div = i; mul = mul1; if (diff == 0) break; } } if (diff > (out_freq >> PMC_PLL_SHIFT_TOL)) goto fail; if (clk->set_outb != NULL) ret |= clk->set_outb(out_freq); return (ret | ((mul - 1) << clk->pll_mul_shift) | (div << clk->pll_div_shift)); fail: return (0); } #if !defined(AT91C_MAIN_CLOCK) static const unsigned int at91_main_clock_tbl[] = { 3000000, 3276800, 3686400, 3840000, 4000000, 4433619, 4915200, 5000000, 5242880, 6000000, 6144000, 6400000, 6553600, 7159090, 7372800, 7864320, 8000000, 9830400, 10000000, 11059200, 12000000, 12288000, 13560000, 14318180, 14745600, 16000000, 17344700, 18432000, 20000000 }; #define MAIN_CLOCK_TBL_LEN nitems(at91_main_clock_tbl) #endif static unsigned int at91_pmc_sense_main_clock(void) { #if !defined(AT91C_MAIN_CLOCK) unsigned int ckgr_val; unsigned int diff, matchdiff, freq; int i; ckgr_val = (RD4(NULL, CKGR_MCFR) & CKGR_MCFR_MAINF_MASK) << 11; /* * Clocks up to 50MHz can be connected to some models. If * the frequency is >= 21MHz, assume that the slow clock can * measure it correctly, and that any error can be adequately * compensated for by roudning to the nearest 500Hz. Users * with fast, or odd-ball clocks will need to set * AT91C_MAIN_CLOCK in the kernel config file. */ if (ckgr_val >= 21000000) return (rounddown(ckgr_val + 250, 500)); /* * Try to find the standard frequency that match best. */ freq = at91_main_clock_tbl[0]; matchdiff = abs(ckgr_val - at91_main_clock_tbl[0]); for (i = 1; i < MAIN_CLOCK_TBL_LEN; i++) { diff = abs(ckgr_val - at91_main_clock_tbl[i]); if (diff < matchdiff) { freq = at91_main_clock_tbl[i]; matchdiff = diff; } } return (freq); #else return (AT91C_MAIN_CLOCK); #endif } void at91_pmc_init_clock(void) { struct at91_pmc_softc *sc = NULL; unsigned int main_clock; uint32_t mckr; uint32_t mdiv; soc_info.soc_data->soc_clock_init(); main_clock = at91_pmc_sense_main_clock(); if (at91_is_sam9() || at91_is_sam9xe()) { uhpck.pmc_mask = PMC_SCER_UHP_SAM9; udpck.pmc_mask = PMC_SCER_UDP_SAM9; } /* There is no pllb on AT91SAM9G45 */ if (at91_cpu_is(AT91_T_SAM9G45)) { uhpck.parent = &upll; uhpck.pmc_mask = PMC_SCER_UHP_SAM9; } mckr = RD4(sc, PMC_MCKR); main_ck.hz = main_clock; /* * Note: this means outa calc code for plla never used since * we never change it. If we did, we'd also have to mind * ICPLLA to get the charge pump current right. */ at91_pmc_pll_rate(&plla, RD4(sc, CKGR_PLLAR)); if (at91_cpu_is(AT91_T_SAM9G45) && (mckr & PMC_MCKR_PLLADIV2)) plla.hz /= 2; /* * Initialize the usb clock. This sets up pllb, but disables the * actual clock. XXX except for the if 0 :( */ if (!at91_cpu_is(AT91_T_SAM9G45)) { pllb_init = at91_pmc_pll_calc(&pllb, 48000000 * 2) | 0x10000000; at91_pmc_pll_rate(&pllb, pllb_init); #if 0 /* Turn off USB clocks */ at91_pmc_set_periph_mode(&ohci_clk, 0); at91_pmc_set_periph_mode(&udc_clk, 0); #endif } if (at91_is_rm92()) { WR4(sc, PMC_SCDR, PMC_SCER_UHP | PMC_SCER_UDP); WR4(sc, PMC_SCER, PMC_SCER_MCKUDP); } else WR4(sc, PMC_SCDR, PMC_SCER_UHP_SAM9 | PMC_SCER_UDP_SAM9); /* * MCK and PCU derive from one of the primary clocks. Initialize * this relationship. */ mck.parent = clock_list[mckr & 0x3]; mck.parent->refcnt++; cpu.hz = mck.hz = mck.parent->hz / (1 << ((mckr & PMC_MCKR_PRES_MASK) >> 2)); mdiv = (mckr & PMC_MCKR_MDIV_MASK) >> 8; if (at91_is_sam9() || at91_is_sam9xe()) { /* * On AT91SAM9G45 when mdiv == 3 we need to divide * MCK by 3 but not, for example, on 9g20. */ if (!at91_cpu_is(AT91_T_SAM9G45) || mdiv <= 2) mdiv *= 2; if (mdiv > 0) mck.hz /= mdiv; } else mck.hz /= (1 + mdiv); /* Only found on SAM9G20 */ if (at91_cpu_is(AT91_T_SAM9G20)) cpu.hz /= (mckr & PMC_MCKR_PDIV) ? 2 : 1; at91_master_clock = mck.hz; /* These clocks refrenced by "special" names */ at91_pmc_clock_alias("ohci0", "ohci_clk"); at91_pmc_clock_alias("udp0", "udp_clk"); /* Turn off "Progamable" clocks */ WR4(sc, PMC_SCDR, PMC_SCER_PCK0 | PMC_SCER_PCK1 | PMC_SCER_PCK2 | PMC_SCER_PCK3); /* XXX kludge, turn on all peripherals */ WR4(sc, PMC_PCER, 0xffffffff); /* Disable all interrupts for PMC */ WR4(sc, PMC_IDR, 0xffffffff); } static void at91_pmc_deactivate(device_t dev) { struct at91_pmc_softc *sc; sc = device_get_softc(dev); bus_generic_detach(sc->dev); if (sc->mem_res) bus_release_resource(dev, SYS_RES_IOPORT, rman_get_rid(sc->mem_res), sc->mem_res); sc->mem_res = NULL; } static int at91_pmc_activate(device_t dev) { struct at91_pmc_softc *sc; int rid; sc = device_get_softc(dev); rid = 0; sc->mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, RF_ACTIVE); if (sc->mem_res == NULL) goto errout; return (0); errout: at91_pmc_deactivate(dev); return (ENOMEM); } static int at91_pmc_probe(device_t dev) { #ifdef FDT if (!ofw_bus_is_compatible(dev, "atmel,at91rm9200-pmc") && !ofw_bus_is_compatible(dev, "atmel,at91sam9260-pmc") && !ofw_bus_is_compatible(dev, "atmel,at91sam9g45-pmc") && !ofw_bus_is_compatible(dev, "atmel,at91sam9x5-pmc")) return (ENXIO); #endif device_set_desc(dev, "PMC"); return (0); } static int at91_pmc_attach(device_t dev) { int err; pmc_softc = device_get_softc(dev); pmc_softc->dev = dev; if ((err = at91_pmc_activate(dev)) != 0) return (err); /* * Configure main clock frequency. */ at91_pmc_init_clock(); /* * Display info about clocks previously computed */ device_printf(dev, "Primary: %d Hz PLLA: %d MHz CPU: %d MHz MCK: %d MHz\n", main_ck.hz, plla.hz / 1000000, cpu.hz / 1000000, mck.hz / 1000000); return (0); } static device_method_t at91_pmc_methods[] = { DEVMETHOD(device_probe, at91_pmc_probe), DEVMETHOD(device_attach, at91_pmc_attach), DEVMETHOD_END }; static driver_t at91_pmc_driver = { "at91_pmc", at91_pmc_methods, sizeof(struct at91_pmc_softc), }; static devclass_t at91_pmc_devclass; #ifdef FDT EARLY_DRIVER_MODULE(at91_pmc, simplebus, at91_pmc_driver, at91_pmc_devclass, NULL, NULL, BUS_PASS_CPU); #else EARLY_DRIVER_MODULE(at91_pmc, atmelarm, at91_pmc_driver, at91_pmc_devclass, NULL, NULL, BUS_PASS_CPU); #endif Index: head/sys/arm/at91/at91_pmcreg.h =================================================================== --- head/sys/arm/at91/at91_pmcreg.h (revision 333141) +++ head/sys/arm/at91/at91_pmcreg.h (revision 333142) @@ -1,146 +1,146 @@ /*- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD * - * Copyright (c) 2005 M. Warner Losh. All rights reserved. + * Copyright (c) 2005 M. Warner Losh. * * 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_AT91_PMCREG_H #define ARM_AT91_AT91_PMCREG_H /* Registers */ #define PMC_SCER 0x00 /* System Clock Enable Register */ #define PMC_SCDR 0x04 /* System Clock Disable Register */ #define PMC_SCSR 0x08 /* System Clock Status Register */ /* 0x0c reserved */ #define PMC_PCER 0x10 /* Peripheral Clock Enable Register */ #define PMC_PCDR 0x14 /* Peripheral Clock Disable Register */ #define PMC_PCSR 0x18 /* Peripheral Clock Status Register */ #define CKGR_UCKR 0x1c /* UTMI Clock Configuration Register */ #define CKGR_MOR 0x20 /* Main Oscillator Register */ #define CKGR_MCFR 0x24 /* Main Clock Frequency Register */ #define CKGR_PLLAR 0x28 /* PLL A Register */ #define CKGR_PLLBR 0x2c /* PLL B Register */ #define PMC_MCKR 0x30 /* Master Clock Register */ /* 0x34 reserved */ #define PMC_USB 0x38 /* USB Clock Register */ /* 0x3c reserved */ #define PMC_PCK0 0x40 /* Programmable Clock 0 Register */ #define PMC_PCK1 0x44 /* Programmable Clock 1 Register */ #define PMC_PCK2 0x48 /* Programmable Clock 2 Register */ #define PMC_PCK3 0x4c /* Programmable Clock 3 Register */ /* 0x50 reserved */ /* 0x54 reserved */ /* 0x58 reserved */ /* 0x5c reserved */ #define PMC_IER 0x60 /* Interrupt Enable Register */ #define PMC_IDR 0x64 /* Interrupt Disable Register */ #define PMC_SR 0x68 /* Status Register */ #define PMC_IMR 0x6c /* Interrupt Mask Register */ /* 0x70 reserved */ /* 0x74 reserved */ /* 0x78 reserved */ /* 0x7c reserved */ #define PMC_PLLICPR 0x80 /* PLL Charge Pump Current Register */ /* PMC System Clock Enable Register */ /* PMC System Clock Disable Register */ /* PMC System Clock StatusRegister */ #define PMC_SCER_PCK (1UL << 0) /* PCK: Processor Clock Enable */ #define PMC_SCER_UDP (1UL << 1) /* UDP: USB Device Port Clock Enable */ #define PMC_SCER_MCKUDP (1UL << 2) /* MCKUDP: Master disable susp/res */ #define PMC_SCER_UHP (1UL << 4) /* UHP: USB Host Port Clock Enable */ #define PMC_SCER_PCK0 (1UL << 8) /* PCK0: Programmable Clock out en */ #define PMC_SCER_PCK1 (1UL << 9) /* PCK1: Programmable Clock out en */ #define PMC_SCER_PCK2 (1UL << 10) /* PCK2: Programmable Clock out en */ #define PMC_SCER_PCK3 (1UL << 11) /* PCK3: Programmable Clock out en */ #define PMC_SCER_UHP_SAM9 (1UL << 6) /* UHP: USB Host Port Clock Enable */ #define PMC_SCER_UDP_SAM9 (1UL << 7) /* UDP: USB Device Port Clock Enable */ /* PMC Peripheral Clock Enable Register */ /* PMC Peripheral Clock Disable Register */ /* PMC Peripheral Clock Status Register */ /* Each bit here is 1 << peripheral number to enable/disable/status */ /* PMC UTMI Clock Configuration Register */ #define CKGR_UCKR_BIASEN (1UL << 24) #define CKGR_UCKR_UPLLEN (1UL << 16) /* PMC Clock Generator Main Oscillator Register */ #define CKGR_MOR_MOSCEN (1UL << 0) /* MOSCEN: Main Oscillator Enable */ #define CKGR_MOR_OSCBYPASS (1UL << 1) /* Oscillator Bypass */ #define CKGR_MOR_OSCOUNT(x) (x << 8) /* Main Oscillator Start-up Time */ /* PMC Clock Generator Main Clock Frequency Register */ #define CKGR_MCFR_MAINRDY (1UL << 16) /* Main Clock Ready */ #define CKGR_MCFR_MAINF_MASK 0xfffful /* Main Clock Frequency */ /* PMC Clock Generator Master Clock Register */ #define PMC_MCKR_PDIV (1 << 12) /* SAM9G20 Only */ #define PMC_MCKR_PLLADIV2 (1 << 12) /* SAM9G45 Only */ #define PMC_MCKR_CSS_MASK (3 << 0) #define PMC_MCKR_MDIV_MASK (3 << 8) #define PMC_MCKR_PRES_MASK (7 << 2) /* PMC USB Clock Register */ #define PMC_USB_USBDIV(n) (((n) & 0x0F) << 8) #define PMC_USB_USBS (1 << 0) /* PMC Interrupt Enable Register */ /* PMC Interrupt Disable Register */ /* PMC Status Register */ /* PMC Interrupt Mask Register */ #define PMC_IER_MOSCS (1UL << 0) /* Main Oscillator Status */ #define PMC_IER_LOCKA (1UL << 1) /* PLL A Locked */ #define PMC_IER_LOCKB (1UL << 2) /* PLL B Locked */ #define PMC_IER_MCKRDY (1UL << 3) /* Master Clock Status */ #define PMC_IER_LOCKU (1UL << 6) /* UPLL Locked */ #define PMC_IER_PCK0RDY (1UL << 8) /* Programmable Clock 0 Ready */ #define PMC_IER_PCK1RDY (1UL << 9) /* Programmable Clock 1 Ready */ #define PMC_IER_PCK2RDY (1UL << 10) /* Programmable Clock 2 Ready */ #define PMC_IER_PCK3RDY (1UL << 11) /* Programmable Clock 3 Ready */ /* * PLL input frequency spec sheet says it must be between 1MHz and 32MHz, * but it works down as low as 100kHz, a frequency necessary for some * output frequencies to work. */ #define PMC_PLL_MIN_IN_FREQ 100000 #define PMC_PLL_MAX_IN_FREQ 32000000 /* * PLL Max output frequency is 240MHz. The errata says 180MHz is the max * for some revisions of this part. Be more permissive and optimistic. */ #define PMC_PLL_MAX_OUT_FREQ 240000000 #define PMC_PLL_MULT_MIN 2 #define PMC_PLL_MULT_MAX 2048 #define PMC_PLL_SHIFT_TOL 5 /* Allow errors 1 part in 32 */ #define PMC_PLL_FAST_THRESH 155000000 #endif /* ARM_AT91_AT91_PMCREG_H */ Index: head/sys/arm/at91/at91_pmcvar.h =================================================================== --- head/sys/arm/at91/at91_pmcvar.h (revision 333141) +++ head/sys/arm/at91/at91_pmcvar.h (revision 333142) @@ -1,69 +1,69 @@ /*- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD * - * Copyright (c) 2005 M. Warner Losh. All rights reserved. + * Copyright (c) 2005 M. Warner Losh. * * 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_AT91_PMCVAR_H #define ARM_AT91_AT91_PMCVAR_H struct at91_pmc_clock { char *name; uint32_t hz; struct at91_pmc_clock *parent; uint32_t pmc_mask; void (*set_mode)(struct at91_pmc_clock *, int); uint32_t refcnt; unsigned id:2; unsigned primary:1; unsigned pll:1; unsigned programmable:1; /* PLL Params */ uint32_t pll_min_in; uint32_t pll_max_in; uint32_t pll_min_out; uint32_t pll_max_out; uint32_t pll_div_shift; uint32_t pll_div_mask; uint32_t pll_mul_shift; uint32_t pll_mul_mask; uint32_t (*set_outb)(int); }; struct at91_pmc_clock *at91_pmc_clock_add(const char *name, uint32_t irq, struct at91_pmc_clock *parent); struct at91_pmc_clock *at91_pmc_clock_ref(const char *name); void at91_pmc_clock_deref(struct at91_pmc_clock *); void at91_pmc_clock_enable(struct at91_pmc_clock *); void at91_pmc_clock_disable(struct at91_pmc_clock *); uint32_t at91_pmc_800mhz_plla_outb(int freq); uint32_t at91_pmc_800mhz_pllb_outb(int freq); #endif /* ARM_AT91_AT91_PMCVAR_H */ Index: head/sys/arm/at91/at91_rtc.c =================================================================== --- head/sys/arm/at91/at91_rtc.c (revision 333141) +++ head/sys/arm/at91/at91_rtc.c (revision 333142) @@ -1,366 +1,366 @@ /*- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD * - * Copyright (c) 2006 M. Warner Losh. All rights reserved. + * Copyright (c) 2006 M. Warner Losh. * Copyright (c) 2012 Ian Lepore. 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. */ /* * Driver for the at91 on-chip realtime clock. * * This driver does not currently support alarms, just date and time. * * The RTC on the AT91RM9200 resets when the core rests, so it is useless as a * source of time (except when the CPU clock is powered down to save power, * which we don't currently do). On AT91SAM9 chips, the RTC survives chip * reset, and there's provisions for it to keep time via battery backup if the * system loses power. On those systems, we use it as a RTC. We tell the two * apart because the century field is 19 on AT91RM9200 on reset, or on AT91SAM9 * chips that haven't had their time properly set. */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "clock_if.h" /* * The driver has all the infrastructure to use interrupts but doesn't actually * have any need to do so right now. There's a non-zero cost for installing the * handler because the RTC shares the system interrupt (IRQ 1), and thus will * get called a lot for no reason at all. */ #define AT91_RTC_USE_INTERRUPTS_NOT struct at91_rtc_softc { device_t dev; /* Myself */ void *intrhand; /* Interrupt handle */ struct resource *irq_res; /* IRQ resource */ struct resource *mem_res; /* Memory resource */ struct mtx sc_mtx; /* basically a perimeter lock */ }; static inline uint32_t RD4(struct at91_rtc_softc *sc, bus_size_t off) { return bus_read_4(sc->mem_res, off); } static inline void WR4(struct at91_rtc_softc *sc, bus_size_t off, uint32_t val) { bus_write_4(sc->mem_res, off, val); } #define AT91_RTC_LOCK(_sc) mtx_lock_spin(&(_sc)->sc_mtx) #define AT91_RTC_UNLOCK(_sc) mtx_unlock_spin(&(_sc)->sc_mtx) #define AT91_RTC_LOCK_INIT(_sc) \ mtx_init(&_sc->sc_mtx, device_get_nameunit(_sc->dev), \ "rtc", MTX_SPIN) #define AT91_RTC_LOCK_DESTROY(_sc) mtx_destroy(&_sc->sc_mtx); #define AT91_RTC_ASSERT_LOCKED(_sc) mtx_assert(&_sc->sc_mtx, MA_OWNED); #define AT91_RTC_ASSERT_UNLOCKED(_sc) mtx_assert(&_sc->sc_mtx, MA_NOTOWNED); static devclass_t at91_rtc_devclass; /* bus entry points */ static int at91_rtc_probe(device_t dev); static int at91_rtc_attach(device_t dev); static int at91_rtc_detach(device_t dev); /* helper routines */ static int at91_rtc_activate(device_t dev); static void at91_rtc_deactivate(device_t dev); #ifdef AT91_RTC_USE_INTERRUPTS static int at91_rtc_intr(void *xsc) { struct at91_rtc_softc *sc; uint32_t status; sc = xsc; /* Must clear the status bits after reading them to re-arm. */ status = RD4(sc, RTC_SR); WR4(sc, RTC_SCCR, status); if (status == 0) return; AT91_RTC_LOCK(sc); /* Do something here */ AT91_RTC_UNLOCK(sc); wakeup(sc); return (FILTER_HANDLED); } #endif static int at91_rtc_probe(device_t dev) { device_set_desc(dev, "RTC"); return (0); } static int at91_rtc_attach(device_t dev) { struct at91_rtc_softc *sc = device_get_softc(dev); int err; sc->dev = dev; err = at91_rtc_activate(dev); if (err) goto out; AT91_RTC_LOCK_INIT(sc); /* * Disable all interrupts in the hardware. * Clear all bits in the status register. * Set 24-hour-clock mode. */ WR4(sc, RTC_IDR, 0xffffffff); WR4(sc, RTC_SCCR, 0x1f); WR4(sc, RTC_MR, 0); #ifdef AT91_RTC_USE_INTERRUPTS err = bus_setup_intr(dev, sc->irq_res, INTR_TYPE_MISC, at91_rtc_intr, NULL, sc, &sc->intrhand); if (err) { AT91_RTC_LOCK_DESTROY(sc); goto out; } #endif /* * Read the calendar register. If the century is 19 then the clock has * never been set. Try to store an invalid value into the register, * which will turn on the error bit in RTC_VER, and our getclock code * knows to return EINVAL if any error bits are on. */ if (RTC_CALR_CEN(RD4(sc, RTC_CALR)) == 19) WR4(sc, RTC_CALR, 0); /* * Register as a time of day clock with 1-second resolution. */ clock_register(dev, 1000000); out: if (err) at91_rtc_deactivate(dev); return (err); } /* * Cannot support detach, since there's no clock_unregister function. */ static int at91_rtc_detach(device_t dev) { return (EBUSY); } static int at91_rtc_activate(device_t dev) { struct at91_rtc_softc *sc; int rid; sc = device_get_softc(dev); rid = 0; sc->mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, RF_ACTIVE); if (sc->mem_res == NULL) goto errout; #ifdef AT91_RTC_USE_INTERRUPTS rid = 0; sc->irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, RF_ACTIVE | RF_SHAREABLE); if (sc->irq_res == NULL) goto errout; #endif return (0); errout: at91_rtc_deactivate(dev); return (ENOMEM); } static void at91_rtc_deactivate(device_t dev) { struct at91_rtc_softc *sc; sc = device_get_softc(dev); #ifdef AT91_RTC_USE_INTERRUPTS WR4(sc, RTC_IDR, 0xffffffff); if (sc->intrhand) bus_teardown_intr(dev, sc->irq_res, sc->intrhand); sc->intrhand = NULL; #endif bus_generic_detach(sc->dev); if (sc->mem_res) bus_release_resource(dev, SYS_RES_MEMORY, rman_get_rid(sc->mem_res), sc->mem_res); sc->mem_res = NULL; #ifdef AT91_RTC_USE_INTERRUPTS if (sc->irq_res) bus_release_resource(dev, SYS_RES_IRQ, rman_get_rid(sc->irq_res), sc->irq_res); sc->irq_res = NULL; #endif return; } /* * Get the time of day clock and return it in ts. * Return 0 on success, an error number otherwise. */ static int at91_rtc_gettime(device_t dev, struct timespec *ts) { struct clocktime ct; uint32_t calr, calr2, timr, timr2; struct at91_rtc_softc *sc; sc = device_get_softc(dev); /* If the error bits are set we can't return useful values. */ if (RD4(sc, RTC_VER) & (RTC_VER_NVTIM | RTC_VER_NVCAL)) return EINVAL; /* * The RTC hardware can update registers while the CPU is reading them. * The manual advises reading until you obtain the same values twice. * Interleaving the reads (rather than timr, timr2, calr, calr2 order) * also ensures we don't miss a midnight rollover/carry between reads. */ do { timr = RD4(sc, RTC_TIMR); calr = RD4(sc, RTC_CALR); timr2 = RD4(sc, RTC_TIMR); calr2 = RD4(sc, RTC_CALR); } while (timr != timr2 || calr != calr2); ct.nsec = 0; ct.sec = RTC_TIMR_SEC(timr); ct.min = RTC_TIMR_MIN(timr); ct.hour = RTC_TIMR_HR(timr); ct.year = RTC_CALR_CEN(calr) * 100 + RTC_CALR_YEAR(calr); ct.mon = RTC_CALR_MON(calr); ct.day = RTC_CALR_DAY(calr); ct.dow = -1; return clock_ct_to_ts(&ct, ts); } /* * Set the time of day clock based on the value of the struct timespec arg. * Return 0 on success, an error number otherwise. */ static int at91_rtc_settime(device_t dev, struct timespec *ts) { struct at91_rtc_softc *sc; struct clocktime ct; int rv; sc = device_get_softc(dev); clock_ts_to_ct(ts, &ct); /* * Can't set the clock unless a second has elapsed since we last did so. */ while ((RD4(sc, RTC_SR) & RTC_SR_SECEV) == 0) cpu_spinwait(); /* * Stop the clocks for an update; wait until hardware is ready. * Clear the update-ready status after it gets asserted (the manual says * to do this before updating the value registers). */ WR4(sc, RTC_CR, RTC_CR_UPDCAL | RTC_CR_UPDTIM); while ((RD4(sc, RTC_SR) & RTC_SR_ACKUPD) == 0) cpu_spinwait(); WR4(sc, RTC_SCCR, RTC_SR_ACKUPD); /* * Set the values in the hardware, then check whether the hardware was * happy with them so we can return the correct status. */ WR4(sc, RTC_TIMR, RTC_TIMR_MK(ct.hour, ct.min, ct.sec)); WR4(sc, RTC_CALR, RTC_CALR_MK(ct.year, ct.mon, ct.day, ct.dow+1)); if (RD4(sc, RTC_VER) & (RTC_VER_NVTIM | RTC_VER_NVCAL)) rv = EINVAL; else rv = 0; /* * Restart the clocks (turn off the update bits). * Clear the second-event bit (because the manual says to). */ WR4(sc, RTC_CR, RD4(sc, RTC_CR) & ~(RTC_CR_UPDCAL | RTC_CR_UPDTIM)); WR4(sc, RTC_SCCR, RTC_SR_SECEV); return (0); } static device_method_t at91_rtc_methods[] = { /* Device interface */ DEVMETHOD(device_probe, at91_rtc_probe), DEVMETHOD(device_attach, at91_rtc_attach), DEVMETHOD(device_detach, at91_rtc_detach), /* clock interface */ DEVMETHOD(clock_gettime, at91_rtc_gettime), DEVMETHOD(clock_settime, at91_rtc_settime), DEVMETHOD_END }; static driver_t at91_rtc_driver = { "at91_rtc", at91_rtc_methods, sizeof(struct at91_rtc_softc), }; DRIVER_MODULE(at91_rtc, atmelarm, at91_rtc_driver, at91_rtc_devclass, 0, 0); Index: head/sys/arm/at91/at91_rtcreg.h =================================================================== --- head/sys/arm/at91/at91_rtcreg.h (revision 333141) +++ head/sys/arm/at91/at91_rtcreg.h (revision 333142) @@ -1,105 +1,105 @@ /*- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD * - * Copyright (c) 2006 M. Warner Losh. All rights reserved. + * Copyright (c) 2006 M. Warner Losh. * * 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_AT91_RTCREG_H #define ARM_AT91_AT91_RTCREG_H /* Registers */ #define RTC_CR 0x00 /* RTC Control Register */ #define RTC_MR 0x04 /* RTC Mode Register */ #define RTC_TIMR 0x08 /* RTC Time Register */ #define RTC_CALR 0x0c /* RTC Calendar Register */ #define RTC_TIMALR 0x10 /* RTC Time Alarm Register */ #define RTC_CALALR 0x14 /* RTC Calendar Alarm Register */ #define RTC_SR 0x18 /* RTC Status Register */ #define RTC_SCCR 0x1c /* RTC Status Command Clear Register */ #define RTC_IER 0x20 /* RTC Interrupt Enable Register */ #define RTC_IDR 0x24 /* RTC Interrupt Disable Register */ #define RTC_IMR 0x28 /* RTC Interrupt Mask Register */ #define RTC_VER 0x2c /* RTC Valid Entry Register */ /* CR */ #define RTC_CR_UPDTIM (0x1u << 0) /* Request update of time register */ #define RTC_CR_UPDCAL (0x1u << 1) /* Request update of calendar reg. */ /* TIMR */ #define RTC_TIMR_SEC_M 0x7fUL #define RTC_TIMR_SEC_S 0 #define RTC_TIMR_SEC(x) FROMBCD(((x) & RTC_TIMR_SEC_M) >> RTC_TIMR_SEC_S) #define RTC_TIMR_MIN_M 0x7f00UL #define RTC_TIMR_MIN_S 8 #define RTC_TIMR_MIN(x) FROMBCD(((x) & RTC_TIMR_MIN_M) >> RTC_TIMR_MIN_S) #define RTC_TIMR_HR_M 0x3f0000UL #define RTC_TIMR_HR_S 16 #define RTC_TIMR_HR(x) FROMBCD(((x) & RTC_TIMR_HR_M) >> RTC_TIMR_HR_S) #define RTC_TIMR_MK(hr, min, sec) \ ((TOBCD(hr) << RTC_TIMR_HR_S) | \ (TOBCD(min) << RTC_TIMR_MIN_S) | \ (TOBCD(sec) << RTC_TIMR_SEC_S)) #define RTC_TIMR_PM (1UL << 22) /* CALR */ #define RTC_CALR_CEN_M 0x0000007fUL #define RTC_CALR_CEN_S 0 #define RTC_CALR_CEN(x) FROMBCD(((x) & RTC_CALR_CEN_M) >> RTC_CALR_CEN_S) #define RTC_CALR_YEAR_M 0x0000ff00UL #define RTC_CALR_YEAR_S 8 #define RTC_CALR_YEAR(x) FROMBCD(((x) & RTC_CALR_YEAR_M) >> RTC_CALR_YEAR_S) #define RTC_CALR_MON_M 0x001f0000UL #define RTC_CALR_MON_S 16 #define RTC_CALR_MON(x) FROMBCD(((x) & RTC_CALR_MON_M) >> RTC_CALR_MON_S) #define RTC_CALR_DOW_M 0x00d0000UL #define RTC_CALR_DOW_S 21 #define RTC_CALR_DOW(x) FROMBCD(((x) & RTC_CALR_DOW_M) >> RTC_CALR_DOW_S) #define RTC_CALR_DAY_M 0x3f000000UL #define RTC_CALR_DAY_S 24 #define RTC_CALR_DAY(x) FROMBCD(((x) & RTC_CALR_DAY_M) >> RTC_CALR_DAY_S) #define RTC_CALR_MK(yr, mon, day, dow) \ ((TOBCD((yr) / 100) << RTC_CALR_CEN_S) | \ (TOBCD((yr) % 100) << RTC_CALR_YEAR_S) | \ (TOBCD(mon) << RTC_CALR_MON_S) | \ (TOBCD(dow) << RTC_CALR_DOW_S) | \ (TOBCD(day) << RTC_CALR_DAY_S)) /* SR */ #define RTC_SR_ACKUPD (0x1u << 0) /* Acknowledge for Update */ #define RTC_SR_ALARM (0x1u << 1) /* Alarm Flag */ #define RTC_SR_SECEV (0x1u << 2) /* Second Event */ #define RTC_SR_TIMEV (0x1u << 3) /* Time Event */ #define RTC_SR_CALEV (0x1u << 4) /* Calendar event */ /* VER */ #define RTC_VER_NVTIM (0x1 << 0) /* Non-valid time */ #define RTC_VER_NVCAL (0x1 << 1) /* Non-valid calendar */ #define RTC_VER_NVTIMALR (0x1 << 2) /* Non-valid time alarm */ #define RTC_VER_NVCALALR (0x1 << 3) /* Non-valid calendar alarm */ #endif /* ARM_AT91_AT91_RTCREG_H */ Index: head/sys/arm/at91/at91_sdramc.c =================================================================== --- head/sys/arm/at91/at91_sdramc.c (revision 333141) +++ head/sys/arm/at91/at91_sdramc.c (revision 333142) @@ -1,106 +1,106 @@ /*- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD * - * Copyright (c) 2014 Warner Losh. All rights reserved. + * Copyright (c) 2014 M. Warner Losh. * * 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 "opt_platform.h" #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #ifdef FDT #include #include #endif struct sdramc_softc { struct resource *mem_res; /* Memory resource */ device_t sc_dev; }; static int at91_sdramc_probe(device_t dev) { #ifdef FDT if (!ofw_bus_is_compatible(dev, "atmel,at91sam9260-sdramc")) return (ENXIO); #endif device_set_desc(dev, "SDRAMC"); return (0); } static int at91_sdramc_attach(device_t dev) { int rid, err = 0; struct sdramc_softc *sc; sc = device_get_softc(dev); sc->sc_dev = dev; rid = 0; sc->mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, RF_ACTIVE); if (sc->mem_res == NULL) panic("couldn't allocate register resources"); return (err); } static device_method_t at91_sdramc_methods[] = { DEVMETHOD(device_probe, at91_sdramc_probe), DEVMETHOD(device_attach, at91_sdramc_attach), DEVMETHOD_END }; static driver_t at91_sdramc_driver = { "at91_sdramc", at91_sdramc_methods, sizeof(struct sdramc_softc), }; static devclass_t at91_sdramc_devclass; #ifdef FDT DRIVER_MODULE(at91_sdramc, simplebus, at91_sdramc_driver, at91_sdramc_devclass, NULL, NULL); #else DRIVER_MODULE(at91_sdramc, atmelarm, at91_sdramc_driver, at91_sdramc_devclass, NULL, NULL); #endif Index: head/sys/arm/at91/at91_shdwc.c =================================================================== --- head/sys/arm/at91/at91_shdwc.c (revision 333141) +++ head/sys/arm/at91/at91_shdwc.c (revision 333142) @@ -1,106 +1,106 @@ /*- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD * - * Copyright (c) 2014 Warner Losh. All rights reserved. + * Copyright (c) 2014 M. Warner Losh. * * 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 "opt_platform.h" #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #ifdef FDT #include #include #endif struct shdwc_softc { struct resource *mem_res; /* Memory resource */ device_t sc_dev; }; static int at91_shdwc_probe(device_t dev) { #ifdef FDT if (!ofw_bus_is_compatible(dev, "atmel,at91sam9260-shdwc")) return (ENXIO); #endif device_set_desc(dev, "SHDWC"); return (0); } static int at91_shdwc_attach(device_t dev) { int rid, err = 0; struct shdwc_softc *sc; sc = device_get_softc(dev); sc->sc_dev = dev; rid = 0; sc->mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, RF_ACTIVE); if (sc->mem_res == NULL) panic("couldn't allocate register resources"); return (err); } static device_method_t at91_shdwc_methods[] = { DEVMETHOD(device_probe, at91_shdwc_probe), DEVMETHOD(device_attach, at91_shdwc_attach), DEVMETHOD_END }; static driver_t at91_shdwc_driver = { "at91_shdwc", at91_shdwc_methods, sizeof(struct shdwc_softc), }; static devclass_t at91_shdwc_devclass; #ifdef FDT DRIVER_MODULE(at91_shdwc, simplebus, at91_shdwc_driver, at91_shdwc_devclass, NULL, NULL); #else DRIVER_MODULE(at91_shdwc, atmelarm, at91_shdwc_driver, at91_shdwc_devclass, NULL, NULL); #endif Index: head/sys/arm/at91/at91_smc.c =================================================================== --- head/sys/arm/at91/at91_smc.c (revision 333141) +++ head/sys/arm/at91/at91_smc.c (revision 333142) @@ -1,93 +1,93 @@ /*- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD * - * Copyright (c) 2014 M. Warner Losh. All rights reserved. + * Copyright (c) 2014 M. Warner Losh. * * 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 /* * RD4HW()/WR4HW() read and write at91 hardware register space directly. They * serve the same purpose as the RD4()/WR4() idiom you see in many drivers, * except that those translate to bus_space calls, but in this code we need to * access some devices before bus_space is ready to use. Of course for this to * work the appropriate static device mappings need to be made in machdep.c. */ static inline uint32_t RD4HW(uint32_t devbase, uint32_t regoff) { return *(volatile uint32_t *)(AT91_BASE + devbase + regoff); } static inline void WR4HW(uint32_t devbase, uint32_t regoff, uint32_t val) { *(volatile uint32_t *)(AT91_BASE + devbase + regoff) = val; } void at91_smc_setup(int id, int cs, const struct at91_smc_init *smc) { // Need a generic way to get this address for all SoCs... Assume 9260 for now... uint32_t base = AT91SAM9260_SMC_BASE + SMC_CS_OFF(cs); WR4HW(base, SMC_SETUP, SMC_SETUP_NCS_RD_SETUP(smc->ncs_rd_setup) | SMC_SETUP_NRD_SETUP(smc->nrd_setup) | SMC_SETUP_NCS_WR_SETUP(smc->ncs_wr_setup) | SMC_SETUP_NWE_SETUP(smc->nwe_setup)); WR4HW(base, SMC_PULSE, SMC_PULSE_NCS_RD_PULSE(smc->ncs_rd_pulse) | SMC_PULSE_NRD_PULSE(smc->nrd_pulse) | SMC_PULSE_NCS_WR_PULSE(smc->ncs_wr_pulse) | SMC_PULSE_NWE_PULSE(smc->nwe_pulse)); WR4HW(base, SMC_CYCLE, SMC_CYCLE_NRD_CYCLE(smc->nrd_cycle) | SMC_CYCLE_NWE_CYCLE(smc->nwe_cycle)); WR4HW(base, SMC_MODE, smc->mode | SMC_MODE_TDF_CYCLES(smc->tdf_cycles)); } void at91_ebi_enable(int bank) { WR4HW(AT91SAM9260_MATRIX_BASE, AT91SAM9260_EBICSA, (1 << bank) | RD4HW(AT91SAM9260_MATRIX_BASE, AT91SAM9260_EBICSA)); } void at91_ebi_disable(int bank) { WR4HW(AT91SAM9260_MATRIX_BASE, AT91SAM9260_EBICSA, ~(1 << bank) & RD4HW(AT91SAM9260_MATRIX_BASE, AT91SAM9260_EBICSA)); } Index: head/sys/arm/at91/at91_smc.h =================================================================== --- head/sys/arm/at91/at91_smc.h (revision 333141) +++ head/sys/arm/at91/at91_smc.h (revision 333142) @@ -1,118 +1,118 @@ /*- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD * - * Copyright (c) 2014 M. Warner Losh. All rights reserved. + * Copyright (c) 2014 M. Warner Losh. * * 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_AT91_SMC_H #define ARM_AT91_AT91_SMC_H /* Registers */ #define SMC_SETUP 0x00 #define SMC_PULSE 0x04 #define SMC_CYCLE 0x08 #define SMC_MODE 0x0C #define SMC_CS_OFF(cs) (0x10 * (cs)) /* Setup */ #define SMC_SETUP_NCS_RD_SETUP(x) ((x) << 24) #define SMC_SETUP_NRD_SETUP(x) ((x) << 16) #define SMC_SETUP_NCS_WR_SETUP(x) ((x) << 8) #define SMC_SETUP_NWE_SETUP(x) (x) /* Pulse */ #define SMC_PULSE_NCS_RD_PULSE(x) ((x) << 24) #define SMC_PULSE_NRD_PULSE(x) ((x) << 16) #define SMC_PULSE_NCS_WR_PULSE(x) ((x) << 8) #define SMC_PULSE_NWE_PULSE(x) (x) /* Cycle */ #define SMC_CYCLE_NRD_CYCLE(x) ((x) << 16) #define SMC_CYCLE_NWE_CYCLE(x) (x) /* Mode */ #define SMC_MODE_READ (1 << 0) #define SMC_MODE_WRITE (1 << 1) #define SMC_MODE_EXNW_DISABLED (0 << 4) #define SMC_MODE_EXNW_FROZEN_MODE (2 << 4) #define SMC_MODE_EXNW_READY_MODE (3 << 4) #define SMC_MODE_BAT (1 << 8) #define SMC_MODE_DBW_8BIT (0 << 12) #define SMC_MODE_DBW_16BIT (1 << 12) #define SMC_MODE_DBW_32_BIT (2 << 12) #define SMC_MODE_TDF_CYCLES(x) ((x) << 16) #define SMC_MODE_TDF_MODE (1 << 20) #define SMC_MODE_PMEN (1 << 24) #define SMC_PS_4BYTE (0 << 28) #define SMC_PS_8BYTE (1 << 28) #define SMC_PS_16BYTE (2 << 28) #define SMC_PS_32BYTE (3 << 28) /* * structure to ease init. See the SMC chapter in the datasheet for * the appropriate SoC you are using for details. */ struct at91_smc_init { /* Setup register */ uint8_t ncs_rd_setup; uint8_t nrd_setup; uint8_t ncs_wr_setup; uint8_t nwe_setup; /* Pulse register */ uint8_t ncs_rd_pulse; uint8_t nrd_pulse; uint8_t ncs_wr_pulse; uint8_t nwe_pulse; /* Cycle register */ uint16_t nrd_cycle; uint16_t nwe_cycle; /* Mode register */ uint8_t mode; /* Combo of READ/WRITE/EXNW fields */ uint8_t bat; uint8_t dwb; uint8_t tdf_cycles; uint8_t tdf_mode; uint8_t pmen; uint8_t ps; }; /* * Convenience routine to fill in SMC registers for a given chip select. */ void at91_smc_setup(int id, int cs, const struct at91_smc_init *smc); /* * Disable/Enable different External Bus Interfaces (EBI) */ void at91_ebi_enable(int cs); void at91_ebi_disable(int cs); #endif /* ARM_AT91_AT91_SMC_H */ Index: head/sys/arm/at91/at91_spireg.h =================================================================== --- head/sys/arm/at91/at91_spireg.h (revision 333141) +++ head/sys/arm/at91/at91_spireg.h (revision 333142) @@ -1,71 +1,71 @@ /*- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD * - * Copyright (c) 2006 M. Warner Losh. All rights reserved. + * Copyright (c) 2006 M. Warner Losh. * * 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_AT91_SPIREG_H #define ARM_AT91_AT91_SPIREG_H #define SPI_CR 0x00 /* CR: Control Register */ #define SPI_CR_SPIEN 0x1 #define SPI_CR_SPIDIS 0x2 #define SPI_CR_SWRST 0x8 #define SPI_MR 0x04 /* MR: Mode Register */ #define SPI_MR_MSTR 0x01 #define SPI_MR_PS 0x02 #define SPI_MR_PCSDEC 0x04 #define SPI_MR_DIV32 0x08 #define SPI_MR_MODFDIS 0x10 #define SPI_MR_LLB 0x80 #define SPI_MR_PSC_CS0 0xe0000 #define SPI_MR_PSC_CS1 0xd0000 #define SPI_MR_PSC_CS2 0xb0000 #define SPI_MR_PSC_CS3 0x70000 #define SPI_RDR 0x08 /* RDR: Receive Data Register */ #define SPI_TDR 0x0c /* TDR: Transmit Data Register */ #define SPI_SR 0x10 /* SR: Status Register */ #define SPI_SR_RDRF 0x00001 #define SPI_SR_TDRE 0x00002 #define SPI_SR_MODF 0x00004 #define SPI_SR_OVRES 0x00008 #define SPI_SR_ENDRX 0x00010 #define SPI_SR_ENDTX 0x00020 #define SPI_SR_RXBUFF 0x00040 #define SPI_SR_TXBUFE 0x00080 #define SPI_SR_NSSR 0x00100 #define SPI_SR_TXEMPTY 0x00200 #define SPI_SR_SPIENS 0x10000 #define SPI_IER 0x14 /* IER: Interrupt Enable Regsiter */ #define SPI_IDR 0x18 /* IDR: Interrupt Disable Regsiter */ #define SPI_IMR 0x1c /* IMR: Interrupt Mask Regsiter */ #define SPI_CSR0 0x30 /* CS0: Chip Select 0 */ #define SPI_CSR_CPOL 0x01 #define SPI_CSR1 0x34 /* CS1: Chip Select 1 */ #define SPI_CSR2 0x38 /* CS2: Chip Select 2 */ #define SPI_CSR3 0x3c /* CS3: Chip Select 3 */ #endif /* ARM_AT91_AT91_SPIREG_H */ Index: head/sys/arm/at91/at91_ssc.c =================================================================== --- head/sys/arm/at91/at91_ssc.c (revision 333141) +++ head/sys/arm/at91/at91_ssc.c (revision 333142) @@ -1,272 +1,272 @@ /*- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD * - * Copyright (c) 2006 M. Warner Losh. All rights reserved. + * Copyright (c) 2006 M. Warner Losh. * * 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 #include #include #include #include #include #include #include struct at91_ssc_softc { device_t dev; /* Myself */ void *intrhand; /* Interrupt handle */ struct resource *irq_res; /* IRQ resource */ struct resource *mem_res; /* Memory resource */ struct mtx sc_mtx; /* basically a perimeter lock */ struct cdev *cdev; int flags; #define OPENED 1 }; static inline uint32_t RD4(struct at91_ssc_softc *sc, bus_size_t off) { return bus_read_4(sc->mem_res, off); } static inline void WR4(struct at91_ssc_softc *sc, bus_size_t off, uint32_t val) { bus_write_4(sc->mem_res, off, val); } #define AT91_SSC_LOCK(_sc) mtx_lock(&(_sc)->sc_mtx) #define AT91_SSC_UNLOCK(_sc) mtx_unlock(&(_sc)->sc_mtx) #define AT91_SSC_LOCK_INIT(_sc) \ mtx_init(&(_sc)->sc_mtx, device_get_nameunit((_sc)->dev), \ "ssc", MTX_DEF) #define AT91_SSC_LOCK_DESTROY(_sc) mtx_destroy(&(_sc)->sc_mtx); #define AT91_SSC_ASSERT_LOCKED(_sc) mtx_assert(&(_sc)->sc_mtx, MA_OWNED); #define AT91_SSC_ASSERT_UNLOCKED(_sc) mtx_assert(&(_sc)->sc_mtx, MA_NOTOWNED); #define CDEV2SOFTC(dev) ((dev)->si_drv1) static devclass_t at91_ssc_devclass; /* bus entry points */ static int at91_ssc_probe(device_t dev); static int at91_ssc_attach(device_t dev); static int at91_ssc_detach(device_t dev); static void at91_ssc_intr(void *); /* helper routines */ static int at91_ssc_activate(device_t dev); static void at91_ssc_deactivate(device_t dev); /* cdev routines */ static d_open_t at91_ssc_open; static d_close_t at91_ssc_close; static d_read_t at91_ssc_read; static d_write_t at91_ssc_write; static struct cdevsw at91_ssc_cdevsw = { .d_version = D_VERSION, .d_open = at91_ssc_open, .d_close = at91_ssc_close, .d_read = at91_ssc_read, .d_write = at91_ssc_write, }; static int at91_ssc_probe(device_t dev) { device_set_desc(dev, "SSC"); return (0); } static int at91_ssc_attach(device_t dev) { struct at91_ssc_softc *sc = device_get_softc(dev); int err; sc->dev = dev; err = at91_ssc_activate(dev); if (err) goto out; AT91_SSC_LOCK_INIT(sc); /* * Activate the interrupt */ err = bus_setup_intr(dev, sc->irq_res, INTR_TYPE_MISC | INTR_MPSAFE, NULL, at91_ssc_intr, sc, &sc->intrhand); if (err) { AT91_SSC_LOCK_DESTROY(sc); goto out; } sc->cdev = make_dev(&at91_ssc_cdevsw, device_get_unit(dev), UID_ROOT, GID_WHEEL, 0600, "ssc%d", device_get_unit(dev)); if (sc->cdev == NULL) { err = ENOMEM; goto out; } sc->cdev->si_drv1 = sc; // Init for TSC needs WR4(sc, SSC_CR, SSC_CR_SWRST); WR4(sc, SSC_CMR, 0); // clock divider unused WR4(sc, SSC_RCMR, SSC_RCMR_CKS_RK | SSC_RCMR_CKO_NONE | SSC_RCMR_START_FALL_EDGE_RF); WR4(sc, SSC_RFMR, 0x1f | SSC_RFMR_MSFBF | SSC_RFMR_FSOS_NONE); WR4(sc, SSC_TCMR, SSC_TCMR_CKS_TK | SSC_TCMR_CKO_NONE | SSC_RCMR_START_CONT); WR4(sc, SSC_TFMR, 0x1f | SSC_TFMR_DATDEF | SSC_TFMR_MSFBF | SSC_TFMR_FSOS_NEG_PULSE); out: if (err) at91_ssc_deactivate(dev); return (err); } static int at91_ssc_detach(device_t dev) { return (EBUSY); /* XXX */ } static int at91_ssc_activate(device_t dev) { struct at91_ssc_softc *sc; int rid; sc = device_get_softc(dev); rid = 0; sc->mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, RF_ACTIVE); if (sc->mem_res == NULL) goto errout; rid = 0; sc->irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, RF_ACTIVE); if (sc->irq_res == NULL) goto errout; return (0); errout: at91_ssc_deactivate(dev); return (ENOMEM); } static void at91_ssc_deactivate(device_t dev) { struct at91_ssc_softc *sc; sc = device_get_softc(dev); if (sc->intrhand) bus_teardown_intr(dev, sc->irq_res, sc->intrhand); sc->intrhand = NULL; bus_generic_detach(sc->dev); if (sc->mem_res) bus_release_resource(dev, SYS_RES_IOPORT, rman_get_rid(sc->mem_res), sc->mem_res); sc->mem_res = NULL; if (sc->irq_res) bus_release_resource(dev, SYS_RES_IRQ, rman_get_rid(sc->irq_res), sc->irq_res); sc->irq_res = NULL; return; } static void at91_ssc_intr(void *xsc) { struct at91_ssc_softc *sc = xsc; wakeup(sc); return; } static int at91_ssc_open(struct cdev *dev, int oflags, int devtype, struct thread *td) { struct at91_ssc_softc *sc; sc = CDEV2SOFTC(dev); AT91_SSC_LOCK(sc); if (!(sc->flags & OPENED)) { sc->flags |= OPENED; } AT91_SSC_UNLOCK(sc); return (0); } static int at91_ssc_close(struct cdev *dev, int fflag, int devtype, struct thread *td) { struct at91_ssc_softc *sc; sc = CDEV2SOFTC(dev); AT91_SSC_LOCK(sc); sc->flags &= ~OPENED; AT91_SSC_UNLOCK(sc); return (0); } static int at91_ssc_read(struct cdev *dev, struct uio *uio, int flag) { return EIO; } static int at91_ssc_write(struct cdev *dev, struct uio *uio, int flag) { return EIO; } static device_method_t at91_ssc_methods[] = { /* Device interface */ DEVMETHOD(device_probe, at91_ssc_probe), DEVMETHOD(device_attach, at91_ssc_attach), DEVMETHOD(device_detach, at91_ssc_detach), { 0, 0 } }; static driver_t at91_ssc_driver = { "at91_ssc", at91_ssc_methods, sizeof(struct at91_ssc_softc), }; DRIVER_MODULE(at91_ssc, atmelarm, at91_ssc_driver, at91_ssc_devclass, 0, 0); Index: head/sys/arm/at91/at91_sscreg.h =================================================================== --- head/sys/arm/at91/at91_sscreg.h (revision 333141) +++ head/sys/arm/at91/at91_sscreg.h (revision 333142) @@ -1,152 +1,152 @@ /*- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD * - * Copyright (c) 2006 M. Warner Losh. All rights reserved. + * Copyright (c) 2006 M. Warner Losh. * * 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_AT91_SSCREG_H #define ARM_AT91_AT91_SSCREG_H /* Registers */ #define SSC_CR 0x00 /* Control Register */ #define SSC_CMR 0x04 /* Clock Mode Register */ /* 0x08 Reserved */ /* 0x0c Reserved */ #define SSC_RCMR 0x10 /* Receive Clock Mode Register */ #define SSC_RFMR 0x14 /* Receive Frame Mode Register */ #define SSC_TCMR 0x18 /* Transmit Clock Mode Register */ #define SSC_TFMR 0x1c /* Transmit Frame Mode register */ #define SSC_RHR 0x20 /* Receive Holding Register */ #define SSC_THR 0x24 /* Transmit Holding Register */ /* 0x28 Reserved */ /* 0x2c Reserved */ #define SSC_RSHR 0x30 /* Receive Sync Holding Register */ #define SSC_TSHR 0x34 /* Transmit Sync Holding Register */ /* 0x38 Reserved */ /* 0x3c Reserved */ #define SSC_SR 0x40 /* Status Register */ #define SSC_IER 0x44 /* Interrupt Enable Register */ #define SSC_IDR 0x48 /* Interrupt Disable Register */ #define SSC_IMR 0x4c /* Interrupt Mask Register */ /* And PDC registers */ /* SSC_CR */ #define SSC_CR_RXEN (1u << 0) /* RXEN: Receive Enable */ #define SSC_CR_RXDIS (1u << 1) /* RXDIS: Receive Disable */ #define SSC_CR_TXEN (1u << 8) /* TXEN: Transmit Enable */ #define SSC_CR_TXDIS (1u << 9) /* TXDIS: Transmit Disable */ #define SSC_CR_SWRST (1u << 15) /* SWRST: Software Reset */ /* SSC_CMR */ #define SSC_CMR_DIV 0xfffu /* DIV: Clock Divider mask */ /* SSC_RCMR */ #define SSC_RCMR_PERIOD (0xffu << 24) /* PERIOD: Receive Period Divider sel*/ #define SSC_RCMR_STTDLY (0xffu << 16) /* STTDLY: Receive Start Delay */ #define SSC_RCMR_START (0xfu << 8) /* START: Receive Start Sel */ #define SSC_RCMR_START_CONT (0u << 8) #define SSC_RCMR_START_TX_START (1u << 8) #define SSC_RCMR_START_LOW_RF (2u << 8) #define SSC_RCMR_START_HIGH_RF (3u << 8) #define SSC_RCMR_START_FALL_EDGE_RF (4u << 8) #define SSC_RCMR_START_RISE_EDGE_RF (5u << 8) #define SSC_RCMR_START_LEVEL_CHANGE_RF (6u << 8) #define SSC_RCMR_START_ANY_EDGE_RF (7u << 8) #define SSC_RCMR_CKI (1u << 5) /* CKI: Receive Clock Inversion */ #define SSC_RCMR_CKO (7u << 2) /* CKO: Receive Clock Output Mode Sel*/ #define SSC_RCMR_CKO_NONE (0u << 2) #define SSC_RCMR_CKO_CONTINUOUS (1u << 2) #define SSC_RCMR_CKS (3u) /* CKS: Receive Clock Selection */ #define SSC_RCMR_CKS_DIVIDED (0) #define SSC_RCMR_CKS_TK_CLOCK (1) #define SSC_RCMR_CKS_RK (2) /* SSC_RFMR */ #define SSC_RFMR_FSEDGE (1u << 24) /* FSEDGE: Frame Sync Edge Detection */ #define SSC_RFMR_FSOS (7u << 20) /* FSOS: Receive frame Sync Out sel */ #define SSC_RFMR_FSOS_NONE (0u << 20) #define SSC_RFMR_FSOS_NEG_PULSE (1u << 20) #define SSC_RFMR_FSOS_POS_PULSE (2u << 20) #define SSC_RFMR_FSOS_LOW (3u << 20) #define SSC_RFMR_FSOS_HIGH (4u << 20) #define SSC_RFMR_FSOS_TOGGLE (5u << 20) #define SSC_RFMR_FSLEN (0xfu << 16) /* FSLEN: Receive Frame Sync Length */ #define SSC_RFMR_DATNB (0xfu << 8) /* DATNB: Data Number per Frame */ #define SSC_RFMR_MSFBF (1u << 7) /* MSBF: Most Significant Bit First */ #define SSC_RFMR_LOOP (1u << 5) /* LOOP: Loop Mode */ #define SSC_RFMR_DATLEN (0x1fu << 0) /* DATLEN: Data Length */ /* SSC_TCMR */ #define SSC_TCMR_PERIOD (0xffu << 24) /* PERIOD: Receive Period Divider sel*/ #define SSC_TCMR_STTDLY (0xffu << 16) /* STTDLY: Receive Start Delay */ #define SSC_TCMR_START (0xfu << 8) /* START: Receive Start Sel */ #define SSC_TCMR_START_CONT (0u << 8) #define SSC_TCMR_START_RX_START (1u << 8) #define SSC_TCMR_START_LOW_RF (2u << 8) #define SSC_TCMR_START_HIGH_RF (3u << 8) #define SSC_TCMR_START_FALL_EDGE_RF (4u << 8) #define SSC_TCMR_START_RISE_EDGE_RF (5u << 8) #define SSC_TCMR_START_LEVEL_CHANGE_RF (6u << 8) #define SSC_TCMR_START_ANY_EDGE_RF (7u << 8) #define SSC_TCMR_CKI (1u << 5) /* CKI: Receive Clock Inversion */ #define SSC_TCMR_CKO (7u << 2) /* CKO: Receive Clock Output Mode Sel*/ #define SSC_TCMR_CKO_NONE (0u << 2) #define SSC_TCMR_CKO_CONTINUOUS (1u << 2) #define SSC_TCMR_CKS (3u) /* CKS: Receive Clock Selection */ #define SSC_TCMR_CKS_DIVIDED (0) #define SSC_TCMR_CKS_RK_CLOCK (1) #define SSC_TCMR_CKS_TK (2) /* SSC_TFMR */ #define SSC_TFMR_FSEDGE (1u << 24) /* FSEDGE: Frame Sync Edge Detection */ #define SSC_TFMR_FSOS (7u << 20) /* FSOS: Receive frame Sync Out sel */ #define SSC_TFMR_FSOS_NONE (0u << 20) #define SSC_TFMR_FSOS_NEG_PULSE (1u << 20) #define SSC_TFMR_FSOS_POS_PULSE (2u << 20) #define SSC_TFMR_FSOS_LOW (3u << 20) #define SSC_TFMR_FSOS_HIGH (4u << 20) #define SSC_TFMR_FSOS_TOGGLE (5u << 20) #define SSC_TFMR_FSLEN (0xfu << 16) /* FSLEN: Receive Frame Sync Length */ #define SSC_TFMR_DATNB (0xfu << 8) /* DATNB: Data Number per Frame */ #define SSC_TFMR_MSFBF (1u << 7) /* MSBF: Most Significant Bit First */ #define SSC_TFMR_DATDEF (1u << 5) /* DATDEF: Data Default Value */ #define SSC_TFMR_DATLEN (0x1fu << 0) /* DATLEN: Data Length */ /* SSC_SR */ #define SSC_SR_TXRDY (1u << 0) #define SSC_SR_TXEMPTY (1u << 1) #define SSC_SR_ENDTX (1u << 2) #define SSC_SR_TXBUFE (1u << 3) #define SSC_SR_RXRDY (1u << 4) #define SSC_SR_OVRUN (1u << 5) #define SSC_SR_ENDRX (1u << 6) #define SSC_SR_RXBUFF (1u << 7) #define SSC_SR_TXSYN (1u << 10) #define SSC_SR_RSSYN (1u << 11) #define SSC_SR_TXEN (1u << 16) #define SSC_SR_RXEN (1u << 17) #endif /* ARM_AT91_AT91_SSCREG_H */ Index: head/sys/arm/at91/at91_streg.h =================================================================== --- head/sys/arm/at91/at91_streg.h (revision 333141) +++ head/sys/arm/at91/at91_streg.h (revision 333142) @@ -1,63 +1,63 @@ /*- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD * - * Copyright (c) 2005 M. Warner Losh. All rights reserved. + * Copyright (c) 2005 M. Warner Losh. * * 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_AT91STREG_H #define ARM_AT91_AT91STREG_H #define ST_CR 0x00 /* Control register */ #define ST_PIMR 0x04 /* Period interval mode register */ #define ST_WDMR 0x08 /* Watchdog mode register */ #define ST_RTMR 0x0c /* Real-time mode register */ #define ST_SR 0x10 /* Status register */ #define ST_IER 0x14 /* Interrupt enable register */ #define ST_IDR 0x18 /* Interrupt disable register */ #define ST_IMR 0x1c /* Interrupt mask register */ #define ST_RTAR 0x20 /* Real-time alarm register */ #define ST_CRTR 0x24 /* Current real-time register */ /* ST_CR */ #define ST_CR_WDRST (1U << 0) /* WDRST: Watchdog Timer Restart */ /* ST_WDMR */ #define ST_WDMR_EXTEN (1U << 17) /* EXTEN: External Signal Assert Enable */ #define ST_WDMR_RSTEN (1U << 16) /* RSTEN: Reset Enable */ /* ST_SR, ST_IER, ST_IDR, ST_IMR */ #define ST_SR_PITS (1U << 0) /* PITS: Period Interval Timer Status */ #define ST_SR_WDOVF (1U << 1) /* WDOVF: Watchdog Overflow */ #define ST_SR_RTTINC (1U << 2) /* RTTINC: Real-time Timer Increment */ #define ST_SR_ALMS (1U << 3) /* ALMS: Alarm Status */ /* 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 */ Index: head/sys/arm/at91/at91_tcb.c =================================================================== --- head/sys/arm/at91/at91_tcb.c (revision 333141) +++ head/sys/arm/at91/at91_tcb.c (revision 333142) @@ -1,106 +1,106 @@ /*- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD * - * Copyright (c) 2014 Warner Losh. All rights reserved. + * Copyright (c) 2014 M. Warner Losh. * * 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 "opt_platform.h" #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #ifdef FDT #include #include #endif struct tcb_softc { struct resource *mem_res; /* Memory resource */ device_t sc_dev; }; static int at91_tcb_probe(device_t dev) { #ifdef FDT if (!ofw_bus_is_compatible(dev, "atmel,at91rm9200-tcb")) return (ENXIO); #endif device_set_desc(dev, "TCB"); return (0); } static int at91_tcb_attach(device_t dev) { int rid, err = 0; struct tcb_softc *sc; sc = device_get_softc(dev); sc->sc_dev = dev; rid = 0; sc->mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, RF_ACTIVE); if (sc->mem_res == NULL) panic("couldn't allocate register resources"); return (err); } static device_method_t at91_tcb_methods[] = { DEVMETHOD(device_probe, at91_tcb_probe), DEVMETHOD(device_attach, at91_tcb_attach), DEVMETHOD_END }; static driver_t at91_tcb_driver = { "at91_tcb", at91_tcb_methods, sizeof(struct tcb_softc), }; static devclass_t at91_tcb_devclass; #ifdef FDT DRIVER_MODULE(at91_tcb, simplebus, at91_tcb_driver, at91_tcb_devclass, NULL, NULL); #else DRIVER_MODULE(at91_tcb, atmelarm, at91_tcb_driver, at91_tcb_devclass, NULL, NULL); #endif Index: head/sys/arm/at91/at91_twi.c =================================================================== --- head/sys/arm/at91/at91_twi.c (revision 333141) +++ head/sys/arm/at91/at91_twi.c (revision 333142) @@ -1,430 +1,430 @@ /*- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD * - * Copyright (c) 2006 M. Warner Losh. All rights reserved. + * Copyright (c) 2006 M. Warner Losh. * * 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 "opt_platform.h" #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "iicbus_if.h" #ifdef FDT #include #include #endif #define TWI_SLOW_CLOCK 1500 #define TWI_FAST_CLOCK 45000 #define TWI_FASTEST_CLOCK 90000 struct at91_twi_softc { device_t dev; /* Myself */ void *intrhand; /* Interrupt handle */ struct resource *irq_res; /* IRQ resource */ struct resource *mem_res; /* Memory resource */ struct mtx sc_mtx; /* basically a perimeter lock */ volatile uint32_t flags; uint32_t cwgr; int sc_started; int twi_addr; device_t iicbus; }; static inline uint32_t RD4(struct at91_twi_softc *sc, bus_size_t off) { return bus_read_4(sc->mem_res, off); } static inline void WR4(struct at91_twi_softc *sc, bus_size_t off, uint32_t val) { bus_write_4(sc->mem_res, off, val); } #define AT91_TWI_LOCK(_sc) mtx_lock(&(_sc)->sc_mtx) #define AT91_TWI_UNLOCK(_sc) mtx_unlock(&(_sc)->sc_mtx) #define AT91_TWI_LOCK_INIT(_sc) \ mtx_init(&_sc->sc_mtx, device_get_nameunit(_sc->dev), \ "twi", MTX_DEF) #define AT91_TWI_LOCK_DESTROY(_sc) mtx_destroy(&_sc->sc_mtx); #define AT91_TWI_ASSERT_LOCKED(_sc) mtx_assert(&_sc->sc_mtx, MA_OWNED); #define AT91_TWI_ASSERT_UNLOCKED(_sc) mtx_assert(&_sc->sc_mtx, MA_NOTOWNED); #define TWI_DEF_CLK 100000 static devclass_t at91_twi_devclass; /* bus entry points */ static int at91_twi_probe(device_t dev); static int at91_twi_attach(device_t dev); static int at91_twi_detach(device_t dev); static void at91_twi_intr(void *); /* helper routines */ static int at91_twi_activate(device_t dev); static void at91_twi_deactivate(device_t dev); static int at91_twi_probe(device_t dev) { #ifdef FDT /* XXXX need a whole list, since there's at least 4 different ones */ if (!ofw_bus_is_compatible(dev, "atmel,at91sam9g20-i2c")) return (ENXIO); #endif device_set_desc(dev, "TWI"); return (0); } static int at91_twi_attach(device_t dev) { struct at91_twi_softc *sc = device_get_softc(dev); int err; sc->dev = dev; err = at91_twi_activate(dev); if (err) goto out; AT91_TWI_LOCK_INIT(sc); #ifdef FDT /* * Disable devices need to hold their resources, so return now and not attach * the iicbus, setup interrupt handlers, etc. */ if (!ofw_bus_status_okay(dev)) return 0; #endif /* * Activate the interrupt */ err = bus_setup_intr(dev, sc->irq_res, INTR_TYPE_MISC | INTR_MPSAFE, NULL, at91_twi_intr, sc, &sc->intrhand); if (err) { AT91_TWI_LOCK_DESTROY(sc); goto out; } sc->cwgr = TWI_CWGR_CKDIV(8 * at91_master_clock / TWI_FASTEST_CLOCK) | TWI_CWGR_CHDIV(TWI_CWGR_DIV(TWI_DEF_CLK)) | TWI_CWGR_CLDIV(TWI_CWGR_DIV(TWI_DEF_CLK)); WR4(sc, TWI_CR, TWI_CR_SWRST); WR4(sc, TWI_CR, TWI_CR_MSEN | TWI_CR_SVDIS); WR4(sc, TWI_CWGR, sc->cwgr); if ((sc->iicbus = device_add_child(dev, "iicbus", -1)) == NULL) device_printf(dev, "could not allocate iicbus instance\n"); /* Probe and attach the iicbus when interrupts are available. */ config_intrhook_oneshot((ich_func_t)bus_generic_attach, dev); out: if (err) at91_twi_deactivate(dev); return (err); } static int at91_twi_detach(device_t dev) { struct at91_twi_softc *sc; int rv; sc = device_get_softc(dev); at91_twi_deactivate(dev); if (sc->iicbus && (rv = device_delete_child(dev, sc->iicbus)) != 0) return (rv); AT91_TWI_LOCK_DESTROY(sc); return (0); } static int at91_twi_activate(device_t dev) { struct at91_twi_softc *sc; int rid; sc = device_get_softc(dev); rid = 0; sc->mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, RF_ACTIVE); if (sc->mem_res == NULL) goto errout; rid = 0; sc->irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, RF_ACTIVE); if (sc->irq_res == NULL) goto errout; return (0); errout: at91_twi_deactivate(dev); return (ENOMEM); } static void at91_twi_deactivate(device_t dev) { struct at91_twi_softc *sc; sc = device_get_softc(dev); if (sc->intrhand) bus_teardown_intr(dev, sc->irq_res, sc->intrhand); sc->intrhand = NULL; bus_generic_detach(sc->dev); if (sc->mem_res) bus_release_resource(dev, SYS_RES_MEMORY, rman_get_rid(sc->mem_res), sc->mem_res); sc->mem_res = NULL; if (sc->irq_res) bus_release_resource(dev, SYS_RES_IRQ, rman_get_rid(sc->irq_res), sc->irq_res); sc->irq_res = NULL; return; } static void at91_twi_intr(void *xsc) { struct at91_twi_softc *sc = xsc; uint32_t status; status = RD4(sc, TWI_SR); if (status == 0) return; AT91_TWI_LOCK(sc); sc->flags |= status & (TWI_SR_OVRE | TWI_SR_UNRE | TWI_SR_NACK); if (status & TWI_SR_RXRDY) sc->flags |= TWI_SR_RXRDY; if (status & TWI_SR_TXRDY) sc->flags |= TWI_SR_TXRDY; if (status & TWI_SR_TXCOMP) sc->flags |= TWI_SR_TXCOMP; WR4(sc, TWI_IDR, status); wakeup(sc); AT91_TWI_UNLOCK(sc); return; } static int at91_twi_wait(struct at91_twi_softc *sc, uint32_t bit) { int err = 0; int counter = 100000; uint32_t sr; AT91_TWI_ASSERT_LOCKED(sc); while (!((sr = RD4(sc, TWI_SR)) & bit) && counter-- > 0 && !(sr & TWI_SR_NACK)) continue; if (counter <= 0) err = EBUSY; else if (sr & TWI_SR_NACK) err = ENXIO; // iic nack convention return (err); } static int at91_twi_rst_card(device_t dev, u_char speed, u_char addr, u_char *oldaddr) { struct at91_twi_softc *sc; int clk; sc = device_get_softc(dev); AT91_TWI_LOCK(sc); if (oldaddr) *oldaddr = sc->twi_addr; sc->twi_addr = addr; /* * speeds are for 1.5kb/s, 45kb/s and 90kb/s. */ switch (speed) { case IIC_SLOW: clk = TWI_SLOW_CLOCK; break; case IIC_FAST: clk = TWI_FAST_CLOCK; break; case IIC_UNKNOWN: case IIC_FASTEST: default: clk = TWI_FASTEST_CLOCK; break; } sc->cwgr = TWI_CWGR_CKDIV(1) | TWI_CWGR_CHDIV(TWI_CWGR_DIV(clk)) | TWI_CWGR_CLDIV(TWI_CWGR_DIV(clk)); WR4(sc, TWI_CR, TWI_CR_SWRST); WR4(sc, TWI_CR, TWI_CR_MSEN | TWI_CR_SVDIS); WR4(sc, TWI_CWGR, sc->cwgr); AT91_TWI_UNLOCK(sc); return 0; } static int at91_twi_callback(device_t dev, int index, caddr_t data) { int error = 0; switch (index) { case IIC_REQUEST_BUS: break; case IIC_RELEASE_BUS: break; default: error = EINVAL; } return (error); } static int at91_twi_transfer(device_t dev, struct iic_msg *msgs, uint32_t nmsgs) { struct at91_twi_softc *sc; int i, len, err; uint32_t rdwr; uint8_t *buf; uint32_t sr; sc = device_get_softc(dev); err = 0; AT91_TWI_LOCK(sc); for (i = 0; i < nmsgs; i++) { /* * The linux atmel driver doesn't use the internal device * address feature of twi. A separate i2c message needs to * be written to use this. * See http://lists.arm.linux.org.uk/pipermail/linux-arm-kernel/2004-September/024411.html * for details. Upon reflection, we could use this as an * optimization, but it is unclear the code bloat will * result in faster/better operations. */ rdwr = (msgs[i].flags & IIC_M_RD) ? TWI_MMR_MREAD : 0; WR4(sc, TWI_MMR, TWI_MMR_DADR(msgs[i].slave) | rdwr); len = msgs[i].len; buf = msgs[i].buf; /* zero byte transfers aren't allowed */ if (len == 0 || buf == NULL) { err = EINVAL; goto out; } if (len == 1 && msgs[i].flags & IIC_M_RD) WR4(sc, TWI_CR, TWI_CR_START | TWI_CR_STOP); else WR4(sc, TWI_CR, TWI_CR_START); if (msgs[i].flags & IIC_M_RD) { sr = RD4(sc, TWI_SR); while (!(sr & TWI_SR_TXCOMP)) { if ((sr = RD4(sc, TWI_SR)) & TWI_SR_RXRDY) { len--; *buf++ = RD4(sc, TWI_RHR) & 0xff; if (len == 1) WR4(sc, TWI_CR, TWI_CR_STOP); } } if (len > 0 || (sr & TWI_SR_NACK)) { err = ENXIO; // iic nack convention goto out; } } else { while (len--) { if ((err = at91_twi_wait(sc, TWI_SR_TXRDY))) goto out; WR4(sc, TWI_THR, *buf++); } WR4(sc, TWI_CR, TWI_CR_STOP); } if ((err = at91_twi_wait(sc, TWI_SR_TXCOMP))) break; } out: if (err) { WR4(sc, TWI_CR, TWI_CR_SWRST); WR4(sc, TWI_CR, TWI_CR_MSEN | TWI_CR_SVDIS); WR4(sc, TWI_CWGR, sc->cwgr); } AT91_TWI_UNLOCK(sc); return (err); } static device_method_t at91_twi_methods[] = { /* Device interface */ DEVMETHOD(device_probe, at91_twi_probe), DEVMETHOD(device_attach, at91_twi_attach), DEVMETHOD(device_detach, at91_twi_detach), /* iicbus interface */ DEVMETHOD(iicbus_callback, at91_twi_callback), DEVMETHOD(iicbus_reset, at91_twi_rst_card), DEVMETHOD(iicbus_transfer, at91_twi_transfer), DEVMETHOD_END }; static driver_t at91_twi_driver = { "at91_twi", at91_twi_methods, sizeof(struct at91_twi_softc), }; #ifdef FDT DRIVER_MODULE(at91_twi, simplebus, at91_twi_driver, at91_twi_devclass, NULL, NULL); #else DRIVER_MODULE(at91_twi, atmelarm, at91_twi_driver, at91_twi_devclass, NULL, NULL); #endif DRIVER_MODULE(iicbus, at91_twi, iicbus_driver, iicbus_devclass, NULL, NULL); MODULE_DEPEND(at91_twi, iicbus, 1, 1, 1); Index: head/sys/arm/at91/at91_twiio.h =================================================================== --- head/sys/arm/at91/at91_twiio.h (revision 333141) +++ head/sys/arm/at91/at91_twiio.h (revision 333142) @@ -1,64 +1,64 @@ /*- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD * - * Copyright (c) 2006 M. Warner Losh. All rights reserved. + * Copyright (c) 2006 M. Warner Losh. * * 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_AT91_TWIIO_H #define _ARM_AT91_AT91_TWIIO_H #include struct at91_twi_io { int dadr; /* Device address */ int type; /* read/write */ #define TWI_IO_READ_MASTER 1 #define TWI_IO_WRITE_MASTER 2 int iadrsz; /* Internal addr size */ uint32_t iadr; /* Interbak addr */ size_t xfer_len; /* Size to transfer */ caddr_t xfer_buf; /* buffer for xfer */ }; struct at91_twi_clock { int ckdiv; /* Clock divider */ int high_rate; /* rate of clock high period */ int low_rate; /* rate of clock low period */ }; /** TWIIOCXFER: Do a two-wire transfer */ #define TWIIOCXFER _IOW('x', 1, struct at91_twi_io) /** TWIIOCSETCLOCK: Sets the clocking parameters for this operation. */ #define TWIIOCSETCLOCK _IOW('x', 2, struct at91_twi_clock) #endif /* !_ARM_AT91_AT91_TWIIO_H */ Index: head/sys/arm/at91/at91_twireg.h =================================================================== --- head/sys/arm/at91/at91_twireg.h (revision 333141) +++ head/sys/arm/at91/at91_twireg.h (revision 333142) @@ -1,88 +1,88 @@ /*- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD * - * Copyright (c) 2006 M. Warner Losh. All rights reserved. + * Copyright (c) 2006 M. Warner Losh. * * 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_AT91_TWIREG_H #define ARM_AT91_AT91_TWIREG_H #define TWI_CR 0x00 /* TWI Control Register */ #define TWI_MMR 0x04 /* TWI Master Mode Register */ #define TWI_SMR 0x08 /* TWI Master Mode Register */ #define TWI_IADR 0x0c /* TWI Internal Address Register */ #define TWI_CWGR 0x10 /* TWI Clock Waveform Generator Reg */ /* 0x14 reserved */ /* 0x18 reserved */ /* 0x1c reserved */ #define TWI_SR 0x20 /* TWI Status Register */ #define TWI_IER 0x24 /* TWI Interrupt Enable Register */ #define TWI_IDR 0x28 /* TWI Interrupt Disable Register */ #define TWI_IMR 0x2c /* TWI Interrupt Mask Register */ #define TWI_RHR 0x30 /* TWI Receiver Holding Register */ #define TWI_THR 0x34 /* TWI Transmit Holding Register */ /* TWI_CR */ #define TWI_CR_START (1U << 0) /* Send a start */ #define TWI_CR_STOP (1U << 1) /* Send a stop */ #define TWI_CR_MSEN (1U << 2) /* Master Transfer Enable */ #define TWI_CR_MSDIS (1U << 3) /* Master Transfer Disable */ #define TWI_CR_SVEN (1U << 4) /* Slave Transfer Enable */ #define TWI_CR_SVDIS (1U << 5) /* Slave Transfer Disable */ #define TWI_CR_SWRST (1U << 7) /* Software Reset */ /* TWI_MMR */ /* TWI_SMR */ #define TWI_MMR_IADRSZ(n) ((n) << 8) /* Set size of transfer */ #define TWI_MMR_MWRITE 0U /* Master Read Direction */ #define TWI_MMR_MREAD (1U << 12) /* Master Read Direction */ #define TWI_MMR_DADR(n) ((n) << 15) /* Device Address */ /* TWI_CWGR */ #define TWI_CWGR_CKDIV(x) ((x) << 16) /* Clock Divider */ #define TWI_CWGR_CHDIV(x) ((x) << 8) /* Clock High Divider */ #define TWI_CWGR_CLDIV(x) ((x) << 0) /* Clock Low Divider */ #define TWI_CWGR_DIV(rate) \ (at91_is_sam9() || at91_is_sam9xe() ? \ ((at91_master_clock / (4 * (rate))) - 3) : \ ((at91_master_clock / (4 * (rate))) - 2)) /* TWI_SR */ /* TWI_IER */ /* TWI_IDR */ /* TWI_IMR */ #define TWI_SR_TXCOMP (1U << 0) /* Transmission Completed */ #define TWI_SR_RXRDY (1U << 1) /* Receive Holding Register Ready */ #define TWI_SR_TXRDY (1U << 2) /* Transmit Holding Register Ready */ #define TWI_SR_SVREAD (1U << 3) /* Slave Read */ #define TWI_SR_SVACC (1U << 4) /* Slave Access */ #define TWI_SR_GCACC (1U << 5) /* General Call Access */ #define TWI_SR_OVRE (1U << 6) /* Overrun error */ #define TWI_SR_UNRE (1U << 7) /* Underrun Error */ #define TWI_SR_NACK (1U << 8) /* Not Acknowledged */ #define TWI_SR_ARBLST (1U << 9) /* Arbitration Lost */ #endif /* ARM_AT91_AT91_TWIREG_H */ Index: head/sys/arm/at91/at91board.h =================================================================== --- head/sys/arm/at91/at91board.h (revision 333141) +++ head/sys/arm/at91/at91board.h (revision 333142) @@ -1,38 +1,38 @@ /*- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD * - * Copyright (c) 2008 Warner Losh. All rights reserved. + * Copyright (c) 2008 M. Warner Losh. * * 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_AT91BOARD_H_ #define _ARM_AT91_AT91BOARD_H_ /* * These routines are used by board init routines */ long at91_ramsize(void); #endif /* _ARM_AT91_AT91BOARD_H_ */ Index: head/sys/arm/at91/at91rm9200_devices.c =================================================================== --- head/sys/arm/at91/at91rm9200_devices.c (revision 333141) +++ head/sys/arm/at91/at91rm9200_devices.c (revision 333142) @@ -1,144 +1,144 @@ /*- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD * - * Copyright (c) 2012 M. Warner Losh. All Rights Reserved. + * Copyright (c) 2012 M. Warner Losh. * * 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 #include #include #define _ARM32_BUS_DMA_PRIVATE #include #include #include #include #include #include #include /* * The AT91RM9200 uses the same silicon for both the BGA and PQFP * packages. There's no documented way to detect this at runtime, * so we require the board code to register what type of SoC is on the * board in question. The pinouts are not quite compatible, and we * use this information to cope with the slight differences. */ void at91rm9200_set_subtype(enum at91_soc_subtype st) { switch (st) { case AT91_ST_RM9200_BGA: case AT91_ST_RM9200_PQFP: soc_info.subtype = st; break; default: panic("Bad SoC subtype %d for at91rm9200_set_subtype.", st); break; } } void at91rm9200_config_uart(unsigned devid, unsigned unit, unsigned pinmask) { /* * Since the USART supports RS-485 multidrop mode, it allows the * TX pins to float. However, for RS-232 operations, we don't want * these pins to float. Instead, they should be pulled up to avoid * mismatches. Linux does something similar when it configures the * TX lines. This implies that we also allow the RX lines to float * rather than be in the state they are left in by the boot loader. * Since they are input pins, I think that this is the right thing * to do. */ /* * Current boards supported don't need the extras, but they should be * implemented. But that should wait until the new pin api goes in. */ switch (devid) { case AT91_ID_DBGU: at91_pio_use_periph_a(AT91RM92_PIOA_BASE, AT91C_PIO_PA30, 0); /* DRXD */ at91_pio_use_periph_a(AT91RM92_PIOA_BASE, AT91C_PIO_PA31, 1); /* DTXD */ break; case AT91RM9200_ID_USART0: at91_pio_use_periph_a(AT91RM92_PIOA_BASE, AT91C_PIO_PA17, 1); /* TXD0 */ at91_pio_use_periph_a(AT91RM92_PIOA_BASE, AT91C_PIO_PA18, 0); /* RXD0 */ /* CTS PA20 */ /* RTS -- errata #39 PA21 */ break; case AT91RM9200_ID_USART1: at91_pio_use_periph_a(AT91RM92_PIOB_BASE, AT91C_PIO_PB20, 1); /* TXD1 */ at91_pio_use_periph_a(AT91RM92_PIOB_BASE, AT91C_PIO_PB21, 0); /* RXD1 */ /* RI - PB18 */ /* DTR - PB19 */ /* DCD - PB23 */ /* CTS - PB24 */ /* DSR - PB25 */ /* RTS - PB26 */ break; case AT91RM9200_ID_USART2: at91_pio_use_periph_a(AT91RM92_PIOA_BASE, AT91C_PIO_PA22, 0); /* RXD2 */ at91_pio_use_periph_a(AT91RM92_PIOA_BASE, AT91C_PIO_PA23, 1); /* TXD2 */ /* CTS - PA30 B periph */ /* RTS - PA31 B periph */ break; case AT91RM9200_ID_USART3: at91_pio_use_periph_b(AT91RM92_PIOA_BASE, AT91C_PIO_PA5, 1); /* TXD3 */ at91_pio_use_periph_b(AT91RM92_PIOA_BASE, AT91C_PIO_PA6, 0); /* RXD3 */ /* CTS - PB0 B periph */ /* RTS - PB1 B periph */ break; default: break; } } void at91rm9200_config_mci(int has_4wire) { /* XXX TODO chip changed GPIO, other slots, etc */ at91_pio_use_periph_a(AT91RM92_PIOA_BASE, AT91C_PIO_PA27, 0); /* MCCK */ at91_pio_use_periph_a(AT91RM92_PIOA_BASE, AT91C_PIO_PA28, 1); /* MCCDA */ at91_pio_use_periph_a(AT91RM92_PIOA_BASE, AT91C_PIO_PA29, 1); /* MCDA0 */ if (has_4wire) { at91_pio_use_periph_b(AT91RM92_PIOB_BASE, AT91C_PIO_PB3, 1); /* MCDA1 */ at91_pio_use_periph_b(AT91RM92_PIOB_BASE, AT91C_PIO_PB4, 1); /* MCDA2 */ at91_pio_use_periph_b(AT91RM92_PIOB_BASE, AT91C_PIO_PB5, 1); /* MCDA3 */ } } Index: head/sys/arm/at91/at91rm9200var.h =================================================================== --- head/sys/arm/at91/at91rm9200var.h (revision 333141) +++ head/sys/arm/at91/at91rm9200var.h (revision 333142) @@ -1,60 +1,60 @@ /*- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD * - * Copyright (c) 2012 M. Warner Losh. All rights reserved. + * Copyright (c) 2012 M. Warner Losh. * * 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_AT91RM9200VAR_H #define ARM_AT91_AT91RM9200VAR_H void at91rm9200_set_subtype(enum at91_soc_subtype st); #define AT91RM9200_ID_USART0 1 #define AT91RM9200_ID_USART1 2 #define AT91RM9200_ID_USART2 3 #define AT91RM9200_ID_USART3 4 /* * Serial port convenience routines */ /* uart pins that are wired... */ #define AT91_UART_CTS 0x01 #define AT91_UART_RTS 0x02 #define AT91_UART_RI 0x04 #define AT91_UART_DTR 0x08 #define AT91_UART_DCD 0x10 #define AT91_UART_DSR 0x20 #define AT91_ID_DBGU 0 void at91rm9200_config_uart(unsigned devid, unsigned unit, unsigned pinmask); /* * MCI (sd/mmc card support) */ void at91rm9200_config_mci(int has_4wire); #endif /* ARM_AT91_AT91RM9200VAR_H */ Index: head/sys/arm/at91/at91sam9x5.c =================================================================== --- head/sys/arm/at91/at91sam9x5.c (revision 333141) +++ head/sys/arm/at91/at91sam9x5.c (revision 333142) @@ -1,189 +1,189 @@ /*- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD * * Copyright (c) 2005 Olivier Houchard. All rights reserved. * Copyright (c) 2010 Greg Ansley. All rights reserved. - * Copyright (c) 2012 M. Warner Losh.. All rights reserved. + * Copyright (c) 2012 M. Warner Losh. * * 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 #include #include #include #include #include #include #include #include #include #include #include #include /* * Standard priority levels for the system. 0 is lowest and 7 is highest. * These values are the ones Atmel uses for its Linux port */ static const int at91_irq_prio[32] = { 7, /* Advanced Interrupt Controller (FIQ) */ 7, /* System Peripherals */ 1, /* Parallel IO Controller A and B */ 1, /* Parallel IO Controller C and D */ 4, /* Soft Modem */ 5, /* USART 0 */ 5, /* USART 1 */ 5, /* USART 2 */ 5, /* USART 3 */ 6, /* Two-Wire Interface 0 */ 6, /* Two-Wire Interface 1 */ 6, /* Two-Wire Interface 2 */ 0, /* Multimedia Card Interface 0 */ 5, /* Serial Peripheral Interface 0 */ 5, /* Serial Peripheral Interface 1 */ 5, /* UART 0 */ 5, /* UART 1 */ 0, /* Timer Counter 0, 1, 2, 3, 4 and 5 */ 0, /* Pulse Width Modulation Controller */ 0, /* ADC Controller */ 0, /* DMA Controller 0 */ 0, /* DMA Controller 1 */ 2, /* USB Host High Speed port */ 2, /* USB Device High speed port */ 3, /* Ethernet MAC 0 */ 3, /* LDC Controller or Image Sensor Interface */ 0, /* Multimedia Card Interface 1 */ 3, /* Ethernet MAC 1 */ 4, /* Synchronous Serial Interface */ 4, /* CAN Controller 0 */ 4, /* CAN Controller 1 */ 0, /* Advanced Interrupt Controller (IRQ0) */ }; static const uint32_t at91_pio_base[] = { AT91SAM9X25_PIOA_BASE, AT91SAM9X25_PIOB_BASE, AT91SAM9X25_PIOC_BASE, AT91SAM9X25_PIOD_BASE, }; #define DEVICE(_name, _id, _unit) \ { \ _name, _unit, \ AT91SAM9X25_ ## _id ##_BASE, \ AT91SAM9X25_ ## _id ## _SIZE, \ AT91SAM9X25_IRQ_ ## _id \ } static const struct cpu_devs at91_devs[] = { DEVICE("at91_aic", AIC, 0), DEVICE("at91_pmc", PMC, 0), DEVICE("at91_wdt", WDT, 0), DEVICE("at91_rst", RSTC, 0), DEVICE("at91_pit", PIT, 0), DEVICE("at91_pio", PIOA, 0), DEVICE("at91_pio", PIOB, 1), DEVICE("at91_pio", PIOC, 2), DEVICE("at91_pio", PIOD, 3), DEVICE("at91_twi", TWI0, 0), DEVICE("at91_twi", TWI1, 1), DEVICE("at91_twi", TWI2, 2), DEVICE("at91_mci", HSMCI0, 0), DEVICE("at91_mci", HSMCI1, 1), DEVICE("uart", DBGU, 0), DEVICE("uart", USART0, 1), DEVICE("uart", USART1, 2), DEVICE("uart", USART2, 3), DEVICE("uart", USART3, 4), DEVICE("spi", SPI0, 0), DEVICE("spi", SPI1, 1), DEVICE("macb", EMAC0, 0), DEVICE("macb", EMAC1, 0), DEVICE("nand", NAND, 0), DEVICE("ohci", OHCI, 0), DEVICE("ehci", EHCI, 0), { 0, 0, 0, 0, 0 } }; static void at91_clock_init(void) { struct at91_pmc_clock *clk; /* Update USB device port clock info */ clk = at91_pmc_clock_ref("udpck"); clk->pmc_mask = PMC_SCER_UDP_SAM9; at91_pmc_clock_deref(clk); /* Update USB host port clock info */ clk = at91_pmc_clock_ref("uhpck"); clk->pmc_mask = PMC_SCER_UHP_SAM9; at91_pmc_clock_deref(clk); /* Each SOC has different PLL contraints */ clk = at91_pmc_clock_ref("plla"); clk->pll_min_in = SAM9X25_PLL_A_MIN_IN_FREQ; /* 2 MHz */ clk->pll_max_in = SAM9X25_PLL_A_MAX_IN_FREQ; /* 32 MHz */ clk->pll_min_out = SAM9X25_PLL_A_MIN_OUT_FREQ; /* 400 MHz */ clk->pll_max_out = SAM9X25_PLL_A_MAX_OUT_FREQ; /* 800 MHz */ clk->pll_mul_shift = SAM9X25_PLL_A_MUL_SHIFT; clk->pll_mul_mask = SAM9X25_PLL_A_MUL_MASK; clk->pll_div_shift = SAM9X25_PLL_A_DIV_SHIFT; clk->pll_div_mask = SAM9X25_PLL_A_DIV_MASK; clk->set_outb = at91_pmc_800mhz_plla_outb; at91_pmc_clock_deref(clk); clk = at91_pmc_clock_ref("pllb"); clk->pll_min_in = SAM9X25_PLL_B_MIN_IN_FREQ; /* 2 MHz */ clk->pll_max_in = SAM9X25_PLL_B_MAX_IN_FREQ; /* 32 MHz */ clk->pll_min_out = SAM9X25_PLL_B_MIN_OUT_FREQ; /* 30 MHz */ clk->pll_max_out = SAM9X25_PLL_B_MAX_OUT_FREQ; /* 100 MHz */ clk->pll_mul_shift = SAM9X25_PLL_B_MUL_SHIFT; clk->pll_mul_mask = SAM9X25_PLL_B_MUL_MASK; clk->pll_div_shift = SAM9X25_PLL_B_DIV_SHIFT; clk->pll_div_mask = SAM9X25_PLL_B_DIV_MASK; clk->set_outb = at91_pmc_800mhz_pllb_outb; at91_pmc_clock_deref(clk); } static struct at91_soc_data soc_data = { .soc_delay = at91_pit_delay, .soc_reset = at91_rst_cpu_reset, .soc_clock_init = at91_clock_init, .soc_irq_prio = at91_irq_prio, .soc_children = at91_devs, .soc_pio_base = at91_pio_base, .soc_pio_count = nitems(at91_pio_base), }; AT91_SOC_SUB(AT91_T_SAM9X5, AT91_ST_SAM9X25, &soc_data); Index: head/sys/arm/at91/at91soc.c =================================================================== --- head/sys/arm/at91/at91soc.c (revision 333141) +++ head/sys/arm/at91/at91soc.c (revision 333142) @@ -1,53 +1,53 @@ /*- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD * - * Copyright (c) 2012 Warner Losh. All rights reserved. + * Copyright (c) 2012 M. Warner Losh. * * 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; } Index: head/sys/arm/at91/at91soc.h =================================================================== --- head/sys/arm/at91/at91soc.h (revision 333141) +++ head/sys/arm/at91/at91soc.h (revision 333142) @@ -1,60 +1,60 @@ /*- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD * - * Copyright (c) 2012 Warner Losh. All rights reserved. + * Copyright (c) 2012 M. Warner Losh. * * 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_ */ Index: head/sys/arm/at91/board_bwct.c =================================================================== --- head/sys/arm/at91/board_bwct.c (revision 333141) +++ head/sys/arm/at91/board_bwct.c (revision 333142) @@ -1,56 +1,56 @@ /*- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD * * Copyright (c) 2005-2008 Olivier Houchard. All rights reserved. - * Copyright (c) 2005-2012 Warner Losh. All rights reserved. + * Copyright (c) 2005-2012 M. Warner Losh. * * 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 #include #include BOARD_INIT long board_init(void) { at91rm9200_set_subtype(AT91_ST_RM9200_BGA); /* * I don't know anything at all about this board. */ at91rm9200_config_uart(AT91_ID_DBGU, 0, 0); /* DBGU just Tx and Rx */ at91rm9200_config_mci(0); /* Configure ethernet */ return (at91_ramsize()); } ARM_BOARD(NONE, "BWCT special"); Index: head/sys/arm/at91/board_eb9200.c =================================================================== --- head/sys/arm/at91/board_eb9200.c (revision 333141) +++ head/sys/arm/at91/board_eb9200.c (revision 333142) @@ -1,70 +1,70 @@ /*- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD * * Copyright (c) 2005-2008 Olivier Houchard. All rights reserved. - * Copyright (c) 2005-2012 Warner Losh. All rights reserved. + * Copyright (c) 2005-2012 M. Warner Losh. * * 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 #include #include BOARD_INIT long board_init(void) { at91rm9200_set_subtype(AT91_ST_RM9200_BGA); /* * Setup the serial ports. * DBGU and USART0 are DB9 ports. * USART2 is IrDA. */ at91rm9200_config_uart(AT91_ID_DBGU, 0, 0); /* DBGU just Tx and Rx */ at91rm9200_config_uart(AT91RM9200_ID_USART0, 1, AT91_UART_CTS | AT91_UART_RTS | AT91_UART_DTR | AT91_UART_DSR | AT91_UART_DCD | AT91_UART_RI); at91rm9200_config_uart(AT91RM9200_ID_USART1, 2, 0); at91rm9200_config_mci(1); /* CFE interface */ /* SPI interface */ /* ethernet interface */ /* USB host */ /* USB device (gadget) */ /* TWI */ /* CF interface */ /* SmartMedia Interface */ return (at91_ramsize()); } ARM_BOARD(ATEB9200, "Embest ATEB9200") Index: head/sys/arm/at91/board_hl200.c =================================================================== --- head/sys/arm/at91/board_hl200.c (revision 333141) +++ head/sys/arm/at91/board_hl200.c (revision 333142) @@ -1,67 +1,67 @@ /*- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD * * Copyright (c) 2005-2008 Olivier Houchard. All rights reserved. - * Copyright (c) 2005-2012 Warner Losh. All rights reserved. + * Copyright (c) 2005-2012 M. Warner Losh. * * 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 #include #include #include BOARD_INIT long board_init(void) { at91rm9200_set_subtype(AT91_ST_RM9200_BGA); /* * Unsure what all is in the HOTe HL200, but I do know there's * one serial port that isn't DBGU. There's many other peripherals * that need to be configured here. */ at91rm9200_config_uart(AT91_ID_DBGU, 0, 0); /* DBGU just Tx and Rx */ at91rm9200_config_uart(AT91RM9200_ID_USART0, 1, 0); /* Tx and Rx */ at91rm9200_config_mci(0); /* HOTe HL200 unknown 1 vs 4 wire */ /* Enable CF card slot */ /* Enable sound thing */ /* Enable VGA chip */ /* Enable ethernet */ /* Enable TWI + RTC */ /* Enable USB Host */ /* Enable USB Device (gadget) */ return (at91_ramsize()); } ARM_BOARD(NONE, "HOTe 200"); Index: head/sys/arm/at91/board_hl201.c =================================================================== --- head/sys/arm/at91/board_hl201.c (revision 333141) +++ head/sys/arm/at91/board_hl201.c (revision 333142) @@ -1,123 +1,123 @@ /*- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD * * Copyright (c) 2005-2008 Olivier Houchard. All rights reserved. - * Copyright (c) 2005-2008 Warner Losh. All rights reserved. + * Copyright (c) 2005-2008 M. Warner Losh. * * 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 #include #include #include #include #include #include static struct at91_smc_init nand_smc = { .ncs_rd_setup = 0, .nrd_setup = 2, .ncs_wr_setup = 0, .nwe_setup = 2, .ncs_rd_pulse = 4, .nrd_pulse = 4, .ncs_wr_pulse = 4, .nwe_pulse = 4, .nrd_cycle = 7, .nwe_cycle = 7, .mode = SMC_MODE_READ | SMC_MODE_WRITE | SMC_MODE_EXNW_DISABLED, .tdf_cycles = 3, }; static struct at91_nand_params nand_param = { .ale = 1u << 21, .cle = 1u << 22, .width = 8, .rnb_pin = AT91_PIN_PC13, /* Note: These pins not confirmed */ .nce_pin = AT91_PIN_PC14, .cs = 3, }; BOARD_INIT long board_init(void) { /* Setup Ethernet Pins */ at91_pio_use_periph_a(AT91SAM9G20_PIOA_BASE, 1<<7, 0); at91_pio_gpio_input(AT91SAM9G20_PIOA_BASE, 1<<7); at91_pio_gpio_set_deglitch(AT91SAM9G20_PIOA_BASE, 1<<7, 1); at91_pio_use_periph_a(AT91SAM9G20_PIOA_BASE, AT91C_PIO_PA19, 0); /* ETXCK_EREFCK */ at91_pio_use_periph_a(AT91SAM9G20_PIOA_BASE, AT91C_PIO_PA17, 0); /* ERXDV */ at91_pio_use_periph_a(AT91SAM9G20_PIOA_BASE, AT91C_PIO_PA14, 0); /* ERX0 */ at91_pio_use_periph_a(AT91SAM9G20_PIOA_BASE, AT91C_PIO_PA15, 0); /* ERX1 */ at91_pio_use_periph_a(AT91SAM9G20_PIOA_BASE, AT91C_PIO_PA18, 0); /* ERXER */ at91_pio_use_periph_a(AT91SAM9G20_PIOA_BASE, AT91C_PIO_PA16, 0); /* ETXEN */ at91_pio_use_periph_a(AT91SAM9G20_PIOA_BASE, AT91C_PIO_PA12, 0); /* ETX0 */ at91_pio_use_periph_a(AT91SAM9G20_PIOA_BASE, AT91C_PIO_PA13, 0); /* ETX1 */ at91_pio_use_periph_a(AT91SAM9G20_PIOA_BASE, AT91C_PIO_PA21, 0); /* EMDIO */ at91_pio_use_periph_a(AT91SAM9G20_PIOA_BASE, AT91C_PIO_PA20, 0); /* EMDC */ at91_pio_use_periph_b(AT91SAM9G20_PIOA_BASE, AT91C_PIO_PA28, 0); /* ECRS */ at91_pio_use_periph_b(AT91SAM9G20_PIOA_BASE, AT91C_PIO_PA29, 0); /* ECOL */ at91_pio_use_periph_b(AT91SAM9G20_PIOA_BASE, AT91C_PIO_PA25, 0); /* ERX2 */ at91_pio_use_periph_b(AT91SAM9G20_PIOA_BASE, AT91C_PIO_PA26, 0); /* ERX3 */ at91_pio_use_periph_b(AT91SAM9G20_PIOA_BASE, AT91C_PIO_PA27, 0); /* ERXCK */ at91_pio_use_periph_b(AT91SAM9G20_PIOA_BASE, AT91C_PIO_PA23, 0); /* ETX2 */ at91_pio_use_periph_b(AT91SAM9G20_PIOA_BASE, AT91C_PIO_PA24, 0); /* ETX3 */ at91_pio_use_periph_b(AT91SAM9G20_PIOA_BASE, AT91C_PIO_PA22, 0); /* ETXER */ /* Setup Static Memory Controller */ at91_smc_setup(0, 3, &nand_smc); at91_enable_nand(&nand_param); /* * This assumes * - RNB is on pin PC13 * - CE is on pin PC14 * * Nothing actually uses RNB right now. * * For CE, this currently asserts it during board setup and leaves it * that way forever. * * All this can go away when the gpio pin-renumbering happens... */ at91_pio_use_gpio(AT91SAM9G20_PIOC_BASE, AT91C_PIO_PC13 | AT91C_PIO_PC14); at91_pio_gpio_input(AT91SAM9G20_PIOC_BASE, AT91C_PIO_PC13); /* RNB */ at91_pio_gpio_output(AT91SAM9G20_PIOC_BASE, AT91C_PIO_PC14, 0); /* nCS */ at91_pio_gpio_clear(AT91SAM9G20_PIOC_BASE, AT91C_PIO_PC14); /* Assert nCS */ return (at91_ramsize()); } ARM_BOARD(NONE, "HOTe 201"); Index: head/sys/arm/at91/board_kb920x.c =================================================================== --- head/sys/arm/at91/board_kb920x.c (revision 333141) +++ head/sys/arm/at91/board_kb920x.c (revision 333142) @@ -1,68 +1,68 @@ /*- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD * * Copyright (c) 2005-2008 Olivier Houchard. All rights reserved. - * Copyright (c) 2005-2012 Warner Losh. All rights reserved. + * Copyright (c) 2005-2012 M. Warner Losh. * * 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 #include #include BOARD_INIT long board_init(void) { at91rm9200_set_subtype(AT91_ST_RM9200_PQFP); /* * Setup the serial ports. * DBGU is the main one, although jumpers can make USART0 default. * USART1 is IrDA, and USART3 is optional RS485. */ at91rm9200_config_uart(AT91_ID_DBGU, 0, 0); /* DBGU just Tx and Rx */ at91rm9200_config_uart(AT91RM9200_ID_USART0, 1, 0); /* Tx and Rx */ at91rm9200_config_uart(AT91RM9200_ID_USART1, 2, 0); /* Tx and Rx - IRDA */ at91rm9200_config_uart(AT91RM9200_ID_USART3, 3, /* Tx, Rx, CTS, RTS - RS485 */ AT91_UART_CTS | AT91_UART_RTS); at91rm9200_config_mci(1); /* CFE interface */ /* ethernet interface */ /* lcd interface */ /* USB host */ /* USB device (gadget) */ /* TWI */ return (at91_ramsize()); } ARM_BOARD(KB9200, "Kwikbyte KB920x") Index: head/sys/arm/at91/board_tsc4370.c =================================================================== --- head/sys/arm/at91/board_tsc4370.c (revision 333141) +++ head/sys/arm/at91/board_tsc4370.c (revision 333142) @@ -1,610 +1,610 @@ /*- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD * * Copyright (c) 2005-2008 Olivier Houchard. All rights reserved. - * Copyright (c) 2005-2012 Warner Losh. All rights reserved. + * Copyright (c) 2005-2012 M. Warner Losh. * Copyright (c) 2007-2014 Ian Lepore. 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. */ /* * Board init code for the TSC4370, and all other current TSC mainboards. */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include /* * RD4HW()/WR4HW() read and write at91rm9200 hardware register space directly. * They serve the same purpose as the RD4()/WR4() idiom you see in many drivers, * except that those translate to bus_space calls, but in this code we need to * access the registers directly before the at91 bus_space stuff is set up. */ static inline uint32_t RD4HW(uint32_t devbase, uint32_t regoff) { return *(volatile uint32_t *)(AT91_BASE + devbase + regoff); } static inline void WR4HW(uint32_t devbase, uint32_t regoff, uint32_t val) { *(volatile uint32_t *)(AT91_BASE + devbase + regoff) = val; } /* * This is the same calculation the at91 uart driver does, we use it to update * the console uart baud rate after changing the MCK rate. */ #ifndef BAUD2DIVISOR #define BAUD2DIVISOR(b) \ ((((at91_master_clock * 10) / ((b) * 16)) + 5) / 10) #endif /* * If doing an in-house build, use tsc_bootinfo.h which is shared with our * custom boot2. Otherwise define some crucial bits of it here, enough to allow * this code to compile. */ #ifdef TSC_BUILD #include #else struct tsc_bootinfo { uint32_t bi_size; uint32_t bi_version; uint32_t bi_flags; /* RB_xxxxx flags from sys/reboot.h */ char bi_rootdevname[64]; }; #define TSC_BOOTINFO_MAGIC 0x06C30000 #endif static struct arm_boot_params boot_params; static struct tsc_bootinfo inkernel_bootinfo; /* * Change the master clock config and wait for it to stabilize. */ static void change_mckr(uint32_t mckr) { int i; WR4HW(AT91RM92_PMC_BASE, PMC_MCKR, mckr); for (i = 0; i < 1000; ++i) if ((RD4HW(AT91RM92_PMC_BASE, PMC_SR) & PMC_IER_MCKRDY)) return; } /* * Allow the master clock frequency to be changed from whatever the bootloader * set up, because sometimes it's harder to change/update a bootloader than it * is to change/update the kernel once a product is in the field. */ static void master_clock_init(void) { uint32_t mckr = RD4HW(AT91RM92_PMC_BASE, PMC_MCKR); int hintvalue = 0; int newmckr = 0; /* * If there's a hint that specifies the contents of MCKR, use it * without question (it had better be right). * * If there's a "mckfreq" hint it might be in hertz or mhz (convert the * latter to hz). Calculate the new MCK divider. If the CPU frequency * is not a sane multiple of the hinted MCK frequency this is likely to * behave badly. The moral is: don't hint at impossibilities. */ if (resource_int_value("at91", 0, "mckr", &hintvalue) == 0) { newmckr = hintvalue; } else { hintvalue = 90; /* Default to 90mhz if not specified. */ resource_int_value("at91", 0, "mckfreq", &hintvalue); if (hintvalue != 0) { if (hintvalue < 1000) hintvalue *= 1000000; if (hintvalue != at91_master_clock) { uint32_t divider; struct at91_pmc_clock * cpuclk; cpuclk = at91_pmc_clock_ref("cpu"); divider = (cpuclk->hz / hintvalue) - 1; newmckr = (mckr & 0xFFFFFCFF) | ((divider & 0x03) << 8); at91_pmc_clock_deref(cpuclk); } } } /* If the new mckr value is different than what's in the register now, * make the change and wait for the clocks to settle (MCKRDY status). * * MCKRDY will never be asserted unless either the selected clock or the * prescaler value changes (but not both at once) [this is detailed in * the rm9200 errata]. This code assumes the prescaler value is always * zero and that by time we get to here we're running on something other * than the slow clock, so to change the mckr divider we first change * back to the slow clock (keeping prescaler and divider unchanged), * then go back to the original selected clock with the new divider. * * After changing MCK, go re-init everything clock-related, and reset * the baud rate generator for the console (doing this here is kind of a * rude hack, but hey, you do what you have to to run MCK faster). */ if (newmckr != 0 && newmckr != mckr) { if (mckr & 0x03) change_mckr(mckr & ~0x03); change_mckr(newmckr); at91_pmc_init_clock(); WR4HW(AT91RM92_DBGU_BASE, USART_BRGR, BAUD2DIVISOR(115200)); } } /* * TSC-specific code to read the ID eeprom on the mainboard and extract the * unit's EUI-64 which gets translated into a MAC-48 for ethernet. */ static void eeprom_init(void) { const uint32_t twiHz = 400000; const uint32_t twiCkDiv = 1 << 16; const uint32_t twiChDiv = ((at91_master_clock / twiHz) - 2) << 8; const uint32_t twiClDiv = ((at91_master_clock / twiHz) - 2); /* * Set the TWCK and TWD lines for Periph A, no pullup, open-drain. */ at91_pio_use_periph_a(AT91RM92_PIOA_BASE, AT91C_PIO_PA25 | AT91C_PIO_PA26, 0); at91_pio_gpio_high_z(AT91RM92_PIOA_BASE, AT91C_PIO_PA25, 1); /* * Enable TWI power (irq numbers are also device IDs for power) */ WR4HW(AT91RM92_PMC_BASE, PMC_PCER, 1u << AT91RM92_IRQ_TWI); /* * Disable TWI interrupts, reset device, enable Master mode, * disable Slave mode, set the clock. */ WR4HW(AT91RM92_TWI_BASE, TWI_IDR, 0xffffffff); WR4HW(AT91RM92_TWI_BASE, TWI_CR, TWI_CR_SWRST); WR4HW(AT91RM92_TWI_BASE, TWI_CR, TWI_CR_MSEN | TWI_CR_SVDIS); WR4HW(AT91RM92_TWI_BASE, TWI_CWGR, twiCkDiv | twiChDiv | twiClDiv); } static int eeprom_read(uint32_t EE_DEV_ADDR, uint32_t ee_off, void * buf, uint32_t size) { uint8_t *bufptr = (uint8_t *)buf; uint32_t status; uint32_t count; /* Clean out any old status and received byte. */ status = RD4HW(AT91RM92_TWI_BASE, TWI_SR); status = RD4HW(AT91RM92_TWI_BASE, TWI_RHR); /* Set the TWI Master Mode Register */ WR4HW(AT91RM92_TWI_BASE, TWI_MMR, TWI_MMR_DADR(EE_DEV_ADDR) | TWI_MMR_IADRSZ(2) | TWI_MMR_MREAD); /* Set TWI Internal Address Register */ WR4HW(AT91RM92_TWI_BASE, TWI_IADR, ee_off); /* Start transfer */ WR4HW(AT91RM92_TWI_BASE, TWI_CR, TWI_CR_START); status = RD4HW(AT91RM92_TWI_BASE, TWI_SR); while (size-- > 1){ /* Wait until Receive Holding Register is full */ count = 1000000; while (!(RD4HW(AT91RM92_TWI_BASE, TWI_SR) & TWI_SR_RXRDY) && --count != 0) continue; if (count <= 0) return -1; /* Read and store byte */ *bufptr++ = (uint8_t)RD4HW(AT91RM92_TWI_BASE, TWI_RHR); } WR4HW(AT91RM92_TWI_BASE, TWI_CR, TWI_CR_STOP); status = RD4HW(AT91RM92_TWI_BASE, TWI_SR); /* Wait until transfer is finished */ while (!(RD4HW(AT91RM92_TWI_BASE, TWI_SR) & TWI_SR_TXCOMP)) continue; /* Read last byte */ *bufptr = (uint8_t)RD4HW(AT91RM92_TWI_BASE, TWI_RHR); return 0; } static int set_mac_from_idprom(void) { #define SIGNATURE_SIZE 4 #define EETYPE_SIZE 2 #define BSLENGTH_SIZE 2 #define RAW_SIZE 52 #define EUI64_SIZE 8 #define BS_SIGNATURE 0x21706d69 #define BSO_SIGNATURE 0x216f7362 #define DEVOFFSET_BSO_SIGNATURE 0x20 #define OFFSET_BS_SIGNATURE 0 #define SIZE_BS_SIGNATURE SIGNATURE_SIZE #define OFFSET_EETYPE (OFFSET_BS_SIGNATURE + SIZE_BS_SIGNATURE) #define SIZE_EETYPE EETYPE_SIZE #define OFFSET_BOOTSECTSIZE (OFFSET_EETYPE + SIZE_EETYPE) #define SIZE_BOOTSECTSIZE BSLENGTH_SIZE #define OFFSET_RAW (OFFSET_BOOTSECTSIZE + SIZE_BOOTSECTSIZE) #define OFFSET_EUI64 (OFFSET_RAW + RAW_SIZE) #define EE_DEV_ADDR 0xA0 /* eeprom is AT24C256 at address 0xA0 */ int status; uint32_t dev_offset = 0; uint32_t sig; uint8_t eui64[EUI64_SIZE]; uint8_t eaddr[ETHER_ADDR_LEN]; eeprom_init(); /* Check for the boot section signature at offset 0. */ status = eeprom_read(EE_DEV_ADDR, OFFSET_BS_SIGNATURE, &sig, sizeof(sig)); if (status == -1) return -1; if (sig != BS_SIGNATURE) { /* Check for the boot section offset signature. */ status = eeprom_read(EE_DEV_ADDR, DEVOFFSET_BSO_SIGNATURE, &sig, sizeof(sig)); if ((status == -1) || (sig != BSO_SIGNATURE)) return -1; /* Read the device offset of the boot section structure. */ status = eeprom_read(EE_DEV_ADDR, DEVOFFSET_BSO_SIGNATURE + sizeof(sig), &dev_offset, sizeof(dev_offset)); if (status == -1) return -1; /* Check for the boot section signature. */ status = eeprom_read(EE_DEV_ADDR, dev_offset + OFFSET_BS_SIGNATURE, &sig, sizeof(sig)); if ((status == -1) || (sig != BS_SIGNATURE)) return -1; } dev_offset += OFFSET_EUI64; /* Read the EUI64 from the device. */ if (eeprom_read(EE_DEV_ADDR, dev_offset, eui64, sizeof(eui64)) == -1) return -1; /* Transcribe the EUI-64 to a MAC-48. * * Given an EUI-64 of aa:bb:cc:dd:ee:ff:gg:hh * * if (ff is zero and ee is non-zero) * mac is aa:bb:cc:ee:gg:hh * else * mac is aa:bb:cc:ff:gg:hh * * This logic fixes a glitch in our mfg process in which the ff byte was * always zero and the ee byte contained a non-zero value. This * resulted in duplicate MAC addresses because we discarded the ee byte. * Now they've fixed the process so that the ff byte is non-zero and * unique addresses are formed from the ff:gg:hh bytes. If the ff byte * is zero, then we have a unit manufactured during the glitch era, and * we fix the problem by grabbing the ee byte rather than the ff byte. */ eaddr[0] = eui64[0]; eaddr[1] = eui64[1]; eaddr[2] = eui64[2]; eaddr[3] = eui64[5]; eaddr[4] = eui64[6]; eaddr[5] = eui64[7]; if (eui64[5] == 0 && eui64[4] != 0) { eaddr[3] = eui64[4]; } /* * Set the address in the hardware regs where the ate driver * looks for it. */ WR4HW(AT91RM92_EMAC_BASE, ETH_SA1L, (eaddr[3] << 24) | (eaddr[2] << 16) | (eaddr[1] << 8) | eaddr[0]); WR4HW(AT91RM92_EMAC_BASE, ETH_SA1H, (eaddr[5] << 8) | (eaddr[4])); printf( "ID: EUI-64 %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x\n" " MAC-48 %02x:%02x:%02x:%02x:%02x:%02x\n" " read from i2c device 0x%02X offset 0x%x\n", eui64[0], eui64[1], eui64[2], eui64[3], eui64[4], eui64[5], eui64[6], eui64[7], eaddr[0], eaddr[1], eaddr[2], eaddr[3], eaddr[4], eaddr[5], EE_DEV_ADDR, dev_offset); return (0); } /* * Assign SPI chip select pins based on which chip selects are found in hints. */ static void assign_spi_pins(void) { struct { uint32_t num; const char * name; } chipsel_pins[] = { { AT91C_PIO_PA3, "PA3", }, { AT91C_PIO_PA4, "PA4", }, { AT91C_PIO_PA5, "PA5", }, { AT91C_PIO_PA6, "PA6", }, }; int anchor = 0; uint32_t chipsel_inuse = 0; /* * Search through all device hints looking for any that have * ".at=spibus0". For each one found, ensure that there is also a * chip select hint ".cs=" and that is 0-3, and assign the * corresponding pin to the SPI peripheral. Whine if we find a SPI * device with a missing or invalid chipsel hint. */ for (;;) { const char * rName = ""; int unit = 0; int cs = 0; int ret; ret = resource_find_match(&anchor, &rName, &unit, "at", "spibus0"); if (ret != 0) break; ret = resource_int_value(rName, unit, "cs", &cs); if (ret != 0) { printf( "Error: hint for SPI device %s%d " "without a chip select hint; " "device will not function.\n", rName, unit); continue; } if (cs < 0 || cs > 3) { printf( "Error: hint for SPI device %s%d " "contains an invalid chip select " "value: %d\n", rName, unit, cs); continue; } if (chipsel_inuse & (1 << cs)) { printf( "Error: hint for SPI device %s%d " "specifies chip select %d, which " "is already used by another device\n", rName, unit, cs); continue; } chipsel_inuse |= 1 << cs; at91_pio_use_periph_a(AT91RM92_PIOA_BASE, chipsel_pins[cs].num, 1); printf( "Configured pin %s as SPI chip " "select %d for %s%d\n", chipsel_pins[cs].name, cs, rName, unit); } /* * If there were hints for any SPI devices, assign the basic SPI IO pins * and enable SPI power (irq numbers are also device IDs for power). */ if (chipsel_inuse != 0) { at91_pio_use_periph_a(AT91RM92_PIOA_BASE, AT91C_PIO_PA1 | AT91C_PIO_PA0 | AT91C_PIO_PA2, 0); WR4HW(AT91RM92_PMC_BASE, PMC_PCER, 1u << AT91RM92_IRQ_SPI); } } BOARD_INIT long board_init(void) { int is_bga, rev_mii; /* * Deal with bootinfo (if any) passed in from the boot2 bootloader and * copied to the static inkernel_bootinfo earlier in the init. Do this * early so that bootverbose is set from this point on. */ if (inkernel_bootinfo.bi_size > 0 && (inkernel_bootinfo.bi_flags & RB_BOOTINFO)) { struct tsc_bootinfo *bip = &inkernel_bootinfo; printf("TSC_BOOTINFO: size %u howtoflags=0x%08x rootdev='%s'\n", bip->bi_size, bip->bi_flags, bip->bi_rootdevname); boothowto = bip->bi_flags; bootverbose = (boothowto & RB_VERBOSE); if (bip->bi_rootdevname[0] != 0) rootdevnames[0] = bip->bi_rootdevname; } /* * The only way to know if we're in a BGA package (and thus have PIOD) * is to be told via a hint; there's nothing detectable in the silicon. * This is esentially an rm92-specific extension to getting the chip ID * (which was done by at91_machdep just before calling this routine). * If it is the BGA package, enable the clock for PIOD. */ is_bga = 0; resource_int_value("at91", 0, "is_bga_package", &is_bga); if (is_bga) WR4HW(AT91RM92_PMC_BASE, PMC_PCER, 1u << AT91RM92_IRQ_PIOD); #if __FreeBSD_version >= 1000000 at91rm9200_set_subtype(is_bga ? AT91_ST_RM9200_BGA : AT91_ST_RM9200_PQFP); #endif /* * Go reprogram the MCK frequency based on hints. */ master_clock_init(); /* From this point on you can use printf. */ /* * Configure UARTs. */ at91rm9200_config_uart(AT91_ID_DBGU, 0, 0); /* DBGU just Tx and Rx */ at91rm9200_config_uart(AT91RM9200_ID_USART0, 1, 0); /* Tx and Rx */ at91rm9200_config_uart(AT91RM9200_ID_USART1, 2, 0); /* Tx and Rx */ at91rm9200_config_uart(AT91RM9200_ID_USART2, 3, 0); /* Tx and Rx */ at91rm9200_config_uart(AT91RM9200_ID_USART3, 4, 0); /* Tx and Rx */ /* * Configure MCI (sdcard) */ at91rm9200_config_mci(0); /* * Assign the pins needed by the emac device, and power it up. Also, * configure it for RMII operation unless the 'revmii_mode' hint is set, * in which case configure the full set of MII pins. The revmii_mode * hint is for so-called reverse-MII, used for connections to a Broadcom * 5325E switch on some boards. Note that order is important here: * configure pins, then power on the device, then access the device's * config registers. */ rev_mii = 0; resource_int_value("ate", 0, "phy_revmii_mode", &rev_mii); at91_pio_use_periph_a(AT91RM92_PIOA_BASE, AT91C_PIO_PA7 | AT91C_PIO_PA8 | AT91C_PIO_PA9 | AT91C_PIO_PA10 | AT91C_PIO_PA11 | AT91C_PIO_PA12 | AT91C_PIO_PA13 | AT91C_PIO_PA14 | AT91C_PIO_PA15 | AT91C_PIO_PA16, 0); if (rev_mii) { at91_pio_use_periph_b(AT91RM92_PIOB_BASE, AT91C_PIO_PB12 | AT91C_PIO_PB13 | AT91C_PIO_PB14 | AT91C_PIO_PB15 | AT91C_PIO_PB16 | AT91C_PIO_PB17 | AT91C_PIO_PB18 | AT91C_PIO_PB19, 0); } WR4HW(AT91RM92_PMC_BASE, PMC_PCER, 1u << AT91RM92_IRQ_EMAC); if (!rev_mii) { WR4HW(AT91RM92_EMAC_BASE, ETH_CFG, RD4HW(AT91RM92_EMAC_BASE, ETH_CFG) | ETH_CFG_RMII); } /* * Get our ethernet MAC address from the ID eeprom. * Configures TWI as a side effect. */ set_mac_from_idprom(); /* * Configure SPI */ assign_spi_pins(); /* * Configure SSC */ at91_pio_use_periph_a( AT91RM92_PIOB_BASE, AT91C_PIO_PB6 | AT91C_PIO_PB7 | AT91C_PIO_PB8 | /* transmit */ AT91C_PIO_PB9 | AT91C_PIO_PB10 | AT91C_PIO_PB11, /* receive */ 0); /* no pullup */ /* * We're using TC1's A1 input for PPS measurements that drive the * kernel PLL and our NTP refclock. On some old boards we route a 5mhz * signal to TC1's A2 input (pin PA21), but we have never used that * clock (it rolls over too fast for hz=100), and now newer boards are * using pin PA21 as a CTS0 for USART1, so we no longer assign it to * the timer block like we used to here. */ at91_pio_use_periph_b(AT91RM92_PIOA_BASE, AT91C_PIO_PA19, 0); /* * Configure pins used to bitbang-upload the firmware to the main FPGA. */ at91_pio_use_gpio(AT91RM92_PIOB_BASE, AT91C_PIO_PB16 | AT91C_PIO_PB17 | AT91C_PIO_PB18 | AT91C_PIO_PB19); return (at91_ramsize()); } /* * Override the default boot param parser (supplied via weak linkage) with one * that knows how to handle our custom tsc_bootinfo passed in from boot2. */ vm_offset_t parse_boot_param(struct arm_boot_params *abp) { boot_params = *abp; /* * If the right magic is in r0 and a non-NULL pointer is in r1, then * it's our bootinfo, copy it. The pointer in r1 is a physical address * passed from boot2. This routine is called immediately upon entry to * initarm() and is in very nearly the same environment as boot2. In * particular, va=pa and we can safely copy the args before we lose easy * access to the memory they're stashed in right now. * * Note that all versions of boot2 that we've ever shipped have put * zeroes into r2 and r3. Maybe that'll be useful some day. */ if (abp->abp_r0 == TSC_BOOTINFO_MAGIC && abp->abp_r1 != 0) { inkernel_bootinfo = *(struct tsc_bootinfo *)(abp->abp_r1); } return fake_preload_metadata(abp, NULL, 0); } ARM_BOARD(NONE, "TSC4370 Controller Board"); Index: head/sys/arm/at91/if_ate.c =================================================================== --- head/sys/arm/at91/if_ate.c (revision 333141) +++ head/sys/arm/at91/if_ate.c (revision 333142) @@ -1,1532 +1,1532 @@ /*- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD * - * Copyright (c) 2006 M. Warner Losh. All rights reserved. + * Copyright (c) 2006 M. Warner Losh. * Copyright (c) 2009 Greg Ansley. 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. */ /* TODO * * 1) Turn on the clock in pmc? Turn off? * 2) GPIO initializtion in board setup code. */ #include "opt_platform.h" #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef INET #include #include #include #include #endif #include #include #include #include #include "opt_at91.h" #include #include #include #ifdef FDT #include #include #endif #include "miibus_if.h" /* * Driver-specific flags. */ #define ATE_FLAG_DETACHING 0x01 #define ATE_FLAG_MULTICAST 0x02 /* * Old EMAC assumes whole packet fits in one buffer; * new EBACB assumes all receive buffers are 128 bytes */ #define RX_BUF_SIZE(sc) (sc->is_emacb ? 128 : MCLBYTES) /* * EMACB has an 11 bit counter for Rx/Tx Descriptors * for max total of 1024 decriptors each. */ #define ATE_MAX_RX_DESCR 1024 #define ATE_MAX_TX_DESCR 1024 /* How many buffers to allocate */ #define ATE_MAX_TX_BUFFERS 4 /* We have ping-pong tx buffers */ /* How much memory to use for rx buffers */ #define ATE_RX_MEMORY (ATE_MAX_RX_DESCR * 128) /* Actual number of descriptors we allocate */ #define ATE_NUM_RX_DESCR ATE_MAX_RX_DESCR #define ATE_NUM_TX_DESCR ATE_MAX_TX_BUFFERS #if ATE_NUM_TX_DESCR > ATE_MAX_TX_DESCR #error "Can't have more TX buffers that descriptors" #endif #if ATE_NUM_RX_DESCR > ATE_MAX_RX_DESCR #error "Can't have more RX buffers that descriptors" #endif /* Wrap indexes the same way the hardware does */ #define NEXT_RX_IDX(sc, cur) \ ((sc->rx_descs[cur].addr & ETH_WRAP_BIT) ? 0 : (cur + 1)) #define NEXT_TX_IDX(sc, cur) \ ((sc->tx_descs[cur].status & ETHB_TX_WRAP) ? 0 : (cur + 1)) struct ate_softc { struct ifnet *ifp; /* ifnet pointer */ struct mtx sc_mtx; /* Basically a perimeter lock */ device_t dev; /* Myself */ device_t miibus; /* My child miibus */ struct resource *irq_res; /* IRQ resource */ struct resource *mem_res; /* Memory resource */ struct callout tick_ch; /* Tick callout */ struct ifmib_iso_8802_3 mibdata; /* Stuff for network mgmt */ bus_dma_tag_t mtag; /* bus dma tag for mbufs */ bus_dma_tag_t rx_tag; bus_dma_tag_t rx_desc_tag; bus_dmamap_t rx_desc_map; bus_dmamap_t rx_map[ATE_MAX_RX_DESCR]; bus_addr_t rx_desc_phys; /* PA of rx descriptors */ eth_rx_desc_t *rx_descs; /* VA of rx descriptors */ void *rx_buf[ATE_NUM_RX_DESCR]; /* RX buffer space */ int rxhead; /* Current RX map/desc index */ uint32_t rx_buf_size; /* Size of Rx buffers */ bus_dma_tag_t tx_desc_tag; bus_dmamap_t tx_desc_map; bus_dmamap_t tx_map[ATE_MAX_TX_BUFFERS]; bus_addr_t tx_desc_phys; /* PA of tx descriptors */ eth_tx_desc_t *tx_descs; /* VA of tx descriptors */ int txhead; /* Current TX map/desc index */ int txtail; /* Current TX map/desc index */ struct mbuf *sent_mbuf[ATE_MAX_TX_BUFFERS]; /* Sent mbufs */ void *intrhand; /* Interrupt handle */ int flags; int if_flags; int use_rmii; int is_emacb; /* SAM9x hardware version */ }; static inline uint32_t RD4(struct ate_softc *sc, bus_size_t off) { return (bus_read_4(sc->mem_res, off)); } static inline void WR4(struct ate_softc *sc, bus_size_t off, uint32_t val) { bus_write_4(sc->mem_res, off, val); } static inline void BARRIER(struct ate_softc *sc, bus_size_t off, bus_size_t len, int flags) { bus_barrier(sc->mem_res, off, len, flags); } #define ATE_LOCK(_sc) mtx_lock(&(_sc)->sc_mtx) #define ATE_UNLOCK(_sc) mtx_unlock(&(_sc)->sc_mtx) #define ATE_LOCK_INIT(_sc) \ mtx_init(&_sc->sc_mtx, device_get_nameunit(_sc->dev), \ MTX_NETWORK_LOCK, MTX_DEF) #define ATE_LOCK_DESTROY(_sc) mtx_destroy(&_sc->sc_mtx); #define ATE_ASSERT_LOCKED(_sc) mtx_assert(&_sc->sc_mtx, MA_OWNED); #define ATE_ASSERT_UNLOCKED(_sc) mtx_assert(&_sc->sc_mtx, MA_NOTOWNED); static devclass_t ate_devclass; /* * ifnet entry points. */ static void ateinit_locked(void *); static void atestart_locked(struct ifnet *); static void ateinit(void *); static void atestart(struct ifnet *); static void atestop(struct ate_softc *); static int ateioctl(struct ifnet * ifp, u_long, caddr_t); /* * Bus entry points. */ static int ate_probe(device_t dev); static int ate_attach(device_t dev); static int ate_detach(device_t dev); static void ate_intr(void *); /* * Helper routines. */ static int ate_activate(device_t dev); static void ate_deactivate(struct ate_softc *sc); static int ate_ifmedia_upd(struct ifnet *ifp); static void ate_ifmedia_sts(struct ifnet *ifp, struct ifmediareq *ifmr); static int ate_get_mac(struct ate_softc *sc, u_char *eaddr); static void ate_set_mac(struct ate_softc *sc, u_char *eaddr); static void ate_rxfilter(struct ate_softc *sc); static int ate_miibus_readreg(device_t dev, int phy, int reg); static int ate_miibus_writereg(device_t dev, int phy, int reg, int data); /* * The AT91 family of products has the ethernet interface called EMAC. * However, it isn't self identifying. It is anticipated that the parent bus * code will take care to only add ate devices where they really are. As * such, we do nothing here to identify the device and just set its name. * However, FDT makes it self-identifying. */ static int ate_probe(device_t dev) { #ifdef FDT if (!ofw_bus_is_compatible(dev, "cdns,at91rm9200-emac") && !ofw_bus_is_compatible(dev, "cdns,emac") && !ofw_bus_is_compatible(dev, "cdns,at32ap7000-macb")) return (ENXIO); #endif device_set_desc(dev, "EMAC"); return (0); } #ifdef FDT /* * We have to know if we're using MII or RMII attachment * for the MACB to talk to the PHY correctly. With FDT, * we must use rmii if there's a proprety phy-mode * equal to "rmii". Otherwise we MII mode is used. */ static void ate_set_rmii(struct ate_softc *sc) { phandle_t node; char prop[10]; ssize_t len; node = ofw_bus_get_node(sc->dev); memset(prop, 0 ,sizeof(prop)); len = OF_getproplen(node, "phy-mode"); if (len != 4) return; if (OF_getprop(node, "phy-mode", prop, len) != len) return; if (strncmp(prop, "rmii", 4) == 0) sc->use_rmii = 1; } #else /* * We have to know if we're using MII or RMII attachment * for the MACB to talk to the PHY correctly. Without FDT, * there's no good way to do this. So, if the config file * has 'option AT91_ATE_USE_RMII', then we'll force RMII. * Otherwise, we'll use what the bootloader setup. Either * it setup RMII or MII, in which case we'll get it right, * or it did nothing, and we'll fall back to MII and the * option would override if present. */ static void ate_set_rmii(struct ate_softc *sc) { /* Default to what boot rom did */ if (!sc->is_emacb) sc->use_rmii = (RD4(sc, ETH_CFG) & ETH_CFG_RMII) == ETH_CFG_RMII; else sc->use_rmii = (RD4(sc, ETHB_UIO) & ETHB_UIO_RMII) == ETHB_UIO_RMII; #ifdef AT91_ATE_USE_RMII /* Compile time override */ sc->use_rmii = 1; #endif } #endif static int ate_attach(device_t dev) { struct ate_softc *sc; struct ifnet *ifp = NULL; struct sysctl_ctx_list *sctx; struct sysctl_oid *soid; u_char eaddr[ETHER_ADDR_LEN]; uint32_t rnd; int rid, err; sc = device_get_softc(dev); sc->dev = dev; ATE_LOCK_INIT(sc); rid = 0; sc->mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, RF_ACTIVE); if (sc->mem_res == NULL) { device_printf(dev, "could not allocate memory resources.\n"); err = ENOMEM; goto out; } rid = 0; sc->irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, RF_ACTIVE); if (sc->irq_res == NULL) { device_printf(dev, "could not allocate interrupt resources.\n"); err = ENOMEM; goto out; } /* New or old version, chooses buffer size. */ #ifdef FDT sc->is_emacb = ofw_bus_is_compatible(dev, "cdns,at32ap7000-macb"); #else sc->is_emacb = at91_is_sam9() || at91_is_sam9xe(); #endif sc->rx_buf_size = RX_BUF_SIZE(sc); err = ate_activate(dev); if (err) goto out; ate_set_rmii(sc); /* Sysctls */ sctx = device_get_sysctl_ctx(dev); soid = device_get_sysctl_tree(dev); SYSCTL_ADD_UINT(sctx, SYSCTL_CHILDREN(soid), OID_AUTO, "rmii", CTLFLAG_RW, &sc->use_rmii, 0, "rmii in use"); /* Calling atestop before ifp is set is OK. */ ATE_LOCK(sc); atestop(sc); ATE_UNLOCK(sc); callout_init_mtx(&sc->tick_ch, &sc->sc_mtx, 0); if ((err = ate_get_mac(sc, eaddr)) != 0) { /* No MAC address configured. Generate the random one. */ if (bootverbose) device_printf(dev, "Generating random ethernet address.\n"); rnd = arc4random(); /* * Set OUI to convenient locally assigned address. 'b' * is 0x62, which has the locally assigned bit set, and * the broadcast/multicast bit clear. */ eaddr[0] = 'b'; eaddr[1] = 's'; eaddr[2] = 'd'; eaddr[3] = (rnd >> 16) & 0xff; eaddr[4] = (rnd >> 8) & 0xff; eaddr[5] = (rnd >> 0) & 0xff; } sc->ifp = ifp = if_alloc(IFT_ETHER); err = mii_attach(dev, &sc->miibus, ifp, ate_ifmedia_upd, ate_ifmedia_sts, BMSR_DEFCAPMASK, MII_PHY_ANY, MII_OFFSET_ANY, 0); if (err != 0) { device_printf(dev, "attaching PHYs failed\n"); goto out; } /* * XXX: Clear the isolate bit, or we won't get up, * at least on the HL201 */ ate_miibus_writereg(dev, 0, 0, 0x3000); ifp->if_softc = sc; if_initname(ifp, device_get_name(dev), device_get_unit(dev)); ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; ifp->if_capabilities |= IFCAP_VLAN_MTU; ifp->if_capenable |= IFCAP_VLAN_MTU; /* The hw bits already set. */ ifp->if_start = atestart; ifp->if_ioctl = ateioctl; ifp->if_init = ateinit; ifp->if_baudrate = 10000000; IFQ_SET_MAXLEN(&ifp->if_snd, IFQ_MAXLEN); ifp->if_snd.ifq_drv_maxlen = IFQ_MAXLEN; IFQ_SET_READY(&ifp->if_snd); ifp->if_linkmib = &sc->mibdata; ifp->if_linkmiblen = sizeof(sc->mibdata); sc->mibdata.dot3Compliance = DOT3COMPLIANCE_COLLS; sc->if_flags = ifp->if_flags; ether_ifattach(ifp, eaddr); /* Activate the interrupt. */ err = bus_setup_intr(dev, sc->irq_res, INTR_TYPE_NET | INTR_MPSAFE, NULL, ate_intr, sc, &sc->intrhand); if (err) { device_printf(dev, "could not establish interrupt handler.\n"); ether_ifdetach(ifp); goto out; } out: if (err) ate_detach(dev); return (err); } static int ate_detach(device_t dev) { struct ate_softc *sc; struct ifnet *ifp; sc = device_get_softc(dev); KASSERT(sc != NULL, ("[ate: %d]: sc is NULL", __LINE__)); ifp = sc->ifp; if (device_is_attached(dev)) { ATE_LOCK(sc); sc->flags |= ATE_FLAG_DETACHING; atestop(sc); ATE_UNLOCK(sc); callout_drain(&sc->tick_ch); ether_ifdetach(ifp); } if (sc->miibus != NULL) { device_delete_child(dev, sc->miibus); sc->miibus = NULL; } bus_generic_detach(sc->dev); ate_deactivate(sc); if (sc->intrhand != NULL) { bus_teardown_intr(dev, sc->irq_res, sc->intrhand); sc->intrhand = NULL; } if (ifp != NULL) { if_free(ifp); sc->ifp = NULL; } if (sc->mem_res != NULL) { bus_release_resource(dev, SYS_RES_IOPORT, rman_get_rid(sc->mem_res), sc->mem_res); sc->mem_res = NULL; } if (sc->irq_res != NULL) { bus_release_resource(dev, SYS_RES_IRQ, rman_get_rid(sc->irq_res), sc->irq_res); sc->irq_res = NULL; } ATE_LOCK_DESTROY(sc); return (0); } static void ate_getaddr(void *arg, bus_dma_segment_t *segs, int nsegs, int error) { if (error != 0) return; *(bus_addr_t *)arg = segs[0].ds_addr; } static void ate_load_rx_buf(void *arg, bus_dma_segment_t *segs, int nsegs, int error) { struct ate_softc *sc; if (error != 0) return; sc = (struct ate_softc *)arg; bus_dmamap_sync(sc->rx_desc_tag, sc->rx_desc_map, BUS_DMASYNC_PREWRITE); sc->rx_descs[sc->rxhead].addr = segs[0].ds_addr; sc->rx_descs[sc->rxhead].status = 0; bus_dmamap_sync(sc->rx_desc_tag, sc->rx_desc_map, BUS_DMASYNC_POSTWRITE); } static uint32_t ate_mac_hash(const uint8_t *buf) { uint32_t index = 0; for (int i = 0; i < 48; i++) { index ^= ((buf[i >> 3] >> (i & 7)) & 1) << (i % 6); } return (index); } /* * Compute the multicast filter for this device. */ static int ate_setmcast(struct ate_softc *sc) { uint32_t index; uint32_t mcaf[2]; u_char *af = (u_char *) mcaf; struct ifmultiaddr *ifma; struct ifnet *ifp; ifp = sc->ifp; if ((ifp->if_flags & IFF_PROMISC) != 0) return (0); if ((ifp->if_flags & IFF_ALLMULTI) != 0) { WR4(sc, ETH_HSL, 0xffffffff); WR4(sc, ETH_HSH, 0xffffffff); return (1); } /* Compute the multicast hash. */ mcaf[0] = 0; mcaf[1] = 0; if_maddr_rlock(ifp); TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { if (ifma->ifma_addr->sa_family != AF_LINK) continue; index = ate_mac_hash(LLADDR((struct sockaddr_dl *) ifma->ifma_addr)); af[index >> 3] |= 1 << (index & 7); } if_maddr_runlock(ifp); /* * Write the hash to the hash register. This card can also * accept unicast packets as well as multicast packets using this * register for easier bridging operations, but we don't take * advantage of that. Locks here are to avoid LOR with the * if_maddr_rlock, but might not be strictly necessary. */ WR4(sc, ETH_HSL, mcaf[0]); WR4(sc, ETH_HSH, mcaf[1]); return (mcaf[0] || mcaf[1]); } static int ate_activate(device_t dev) { struct ate_softc *sc; int i; sc = device_get_softc(dev); /* Allocate DMA tags and maps for TX mbufs */ if (bus_dma_tag_create(bus_get_dma_tag(dev), 1, 0, BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, NULL, NULL, MCLBYTES, 1, MCLBYTES, 0, busdma_lock_mutex, &sc->sc_mtx, &sc->mtag)) goto errout; for (i = 0; i < ATE_MAX_TX_BUFFERS; i++) { if ( bus_dmamap_create(sc->mtag, 0, &sc->tx_map[i])) goto errout; } /* DMA tag and map for the RX descriptors. */ if (bus_dma_tag_create(bus_get_dma_tag(dev), sizeof(eth_rx_desc_t), 0, BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, NULL, NULL, ATE_NUM_RX_DESCR * sizeof(eth_rx_desc_t), 1, ATE_NUM_RX_DESCR * sizeof(eth_rx_desc_t), 0, busdma_lock_mutex, &sc->sc_mtx, &sc->rx_desc_tag)) goto errout; if (bus_dmamem_alloc(sc->rx_desc_tag, (void **)&sc->rx_descs, BUS_DMA_NOWAIT | BUS_DMA_COHERENT, &sc->rx_desc_map) != 0) goto errout; if (bus_dmamap_load(sc->rx_desc_tag, sc->rx_desc_map, sc->rx_descs, ATE_NUM_RX_DESCR * sizeof(eth_rx_desc_t), ate_getaddr, &sc->rx_desc_phys, 0) != 0) goto errout; /* Allocate DMA tags and maps for RX. buffers */ if (bus_dma_tag_create(bus_get_dma_tag(dev), 1, 0, BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, NULL, NULL, sc->rx_buf_size, 1, sc->rx_buf_size, 0, busdma_lock_mutex, &sc->sc_mtx, &sc->rx_tag)) goto errout; /* * Allocate our RX buffers. * This chip has a RX structure that's filled in. * XXX On MACB (SAM9 part) we should receive directly into mbuf * to avoid the copy. XXX */ sc->rxhead = 0; for (sc->rxhead = 0; sc->rxhead < ATE_RX_MEMORY/sc->rx_buf_size; sc->rxhead++) { if (bus_dmamem_alloc(sc->rx_tag, (void **)&sc->rx_buf[sc->rxhead], BUS_DMA_NOWAIT, &sc->rx_map[sc->rxhead]) != 0) goto errout; if (bus_dmamap_load(sc->rx_tag, sc->rx_map[sc->rxhead], sc->rx_buf[sc->rxhead], sc->rx_buf_size, ate_load_rx_buf, sc, 0) != 0) { printf("bus_dmamem_load\n"); goto errout; } bus_dmamap_sync(sc->rx_tag, sc->rx_map[sc->rxhead], BUS_DMASYNC_PREREAD); } /* * For the last buffer, set the wrap bit so the controller * restarts from the first descriptor. */ sc->rx_descs[--sc->rxhead].addr |= ETH_WRAP_BIT; sc->rxhead = 0; /* Flush the memory for the EMAC rx descriptor. */ bus_dmamap_sync(sc->rx_desc_tag, sc->rx_desc_map, BUS_DMASYNC_PREWRITE); /* Write the descriptor queue address. */ WR4(sc, ETH_RBQP, sc->rx_desc_phys); /* * DMA tag and map for the TX descriptors. */ if (bus_dma_tag_create(bus_get_dma_tag(dev), sizeof(eth_tx_desc_t), 0, BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, NULL, NULL, ATE_MAX_TX_BUFFERS * sizeof(eth_tx_desc_t), 1, ATE_MAX_TX_BUFFERS * sizeof(eth_tx_desc_t), 0, busdma_lock_mutex, &sc->sc_mtx, &sc->tx_desc_tag) != 0) goto errout; if (bus_dmamem_alloc(sc->tx_desc_tag, (void **)&sc->tx_descs, BUS_DMA_NOWAIT | BUS_DMA_COHERENT, &sc->tx_desc_map) != 0) goto errout; if (bus_dmamap_load(sc->tx_desc_tag, sc->tx_desc_map, sc->tx_descs, ATE_MAX_TX_BUFFERS * sizeof(eth_tx_desc_t), ate_getaddr, &sc->tx_desc_phys, 0) != 0) goto errout; /* Initialize descriptors; mark all empty */ for (i = 0; i < ATE_MAX_TX_BUFFERS; i++) { sc->tx_descs[i].addr =0; sc->tx_descs[i].status = ETHB_TX_USED; sc->sent_mbuf[i] = NULL; } /* Mark last entry to cause wrap when indexing through */ sc->tx_descs[ATE_MAX_TX_BUFFERS - 1].status = ETHB_TX_WRAP | ETHB_TX_USED; /* Flush the memory for the EMAC tx descriptor. */ bus_dmamap_sync(sc->tx_desc_tag, sc->tx_desc_map, BUS_DMASYNC_PREWRITE); sc->txhead = sc->txtail = 0; if (sc->is_emacb) { /* Write the descriptor queue address. */ WR4(sc, ETHB_TBQP, sc->tx_desc_phys); /* EMACB: Enable transceiver input clock */ WR4(sc, ETHB_UIO, RD4(sc, ETHB_UIO) | ETHB_UIO_CLKE); } return (0); errout: return (ENOMEM); } static void ate_deactivate(struct ate_softc *sc) { int i; KASSERT(sc != NULL, ("[ate, %d]: sc is NULL!", __LINE__)); if (sc->mtag != NULL) { for (i = 0; i < ATE_MAX_TX_BUFFERS; i++) { if (sc->sent_mbuf[i] != NULL) { bus_dmamap_sync(sc->mtag, sc->tx_map[i], BUS_DMASYNC_POSTWRITE); bus_dmamap_unload(sc->mtag, sc->tx_map[i]); m_freem(sc->sent_mbuf[i]); } bus_dmamap_destroy(sc->mtag, sc->tx_map[i]); sc->sent_mbuf[i] = NULL; sc->tx_map[i] = NULL; } bus_dma_tag_destroy(sc->mtag); } if (sc->rx_desc_tag != NULL) { if (sc->rx_descs != NULL) { if (sc->rx_desc_phys != 0) { bus_dmamap_sync(sc->rx_desc_tag, sc->rx_desc_map, BUS_DMASYNC_POSTREAD); bus_dmamap_unload(sc->rx_desc_tag, sc->rx_desc_map); sc->rx_desc_phys = 0; } } } if (sc->rx_tag != NULL) { for (i = 0; sc->rx_buf[i] != NULL; i++) { if (sc->rx_descs[i].addr != 0) { bus_dmamap_sync(sc->rx_tag, sc->rx_map[i], BUS_DMASYNC_POSTREAD); bus_dmamap_unload(sc->rx_tag, sc->rx_map[i]); sc->rx_descs[i].addr = 0; } bus_dmamem_free(sc->rx_tag, sc->rx_buf[i], sc->rx_map[i]); sc->rx_buf[i] = NULL; } bus_dma_tag_destroy(sc->rx_tag); } if (sc->rx_desc_tag != NULL) { if (sc->rx_descs != NULL) bus_dmamem_free(sc->rx_desc_tag, sc->rx_descs, sc->rx_desc_map); bus_dma_tag_destroy(sc->rx_desc_tag); sc->rx_descs = NULL; sc->rx_desc_tag = NULL; } if (sc->is_emacb) WR4(sc, ETHB_UIO, RD4(sc, ETHB_UIO) & ~ETHB_UIO_CLKE); } /* * Change media according to request. */ static int ate_ifmedia_upd(struct ifnet *ifp) { struct ate_softc *sc = ifp->if_softc; struct mii_data *mii; mii = device_get_softc(sc->miibus); ATE_LOCK(sc); mii_mediachg(mii); ATE_UNLOCK(sc); return (0); } /* * Notify the world which media we're using. */ static void ate_ifmedia_sts(struct ifnet *ifp, struct ifmediareq *ifmr) { struct ate_softc *sc = ifp->if_softc; struct mii_data *mii; mii = device_get_softc(sc->miibus); ATE_LOCK(sc); mii_pollstat(mii); ifmr->ifm_active = mii->mii_media_active; ifmr->ifm_status = mii->mii_media_status; ATE_UNLOCK(sc); } static void ate_stat_update(struct ate_softc *sc, int active) { uint32_t reg; /* * The speed and full/half-duplex state needs to be reflected * in the ETH_CFG register. */ reg = RD4(sc, ETH_CFG); reg &= ~(ETH_CFG_SPD | ETH_CFG_FD); if (IFM_SUBTYPE(active) != IFM_10_T) reg |= ETH_CFG_SPD; if (active & IFM_FDX) reg |= ETH_CFG_FD; WR4(sc, ETH_CFG, reg); } static void ate_tick(void *xsc) { struct ate_softc *sc = xsc; struct ifnet *ifp = sc->ifp; struct mii_data *mii; int active; uint32_t c; /* * The KB920x boot loader tests ETH_SR & ETH_SR_LINK and will ask * the MII if there's a link if this bit is clear. Not sure if we * should do the same thing here or not. */ ATE_ASSERT_LOCKED(sc); if (sc->miibus != NULL) { mii = device_get_softc(sc->miibus); active = mii->mii_media_active; mii_tick(mii); if (mii->mii_media_status & IFM_ACTIVE && active != mii->mii_media_active) ate_stat_update(sc, mii->mii_media_active); } /* * Update the stats as best we can. When we're done, clear * the status counters and start over. We're supposed to read these * registers often enough that they won't overflow. Hopefully * once a second is often enough. Some don't map well to * the dot3Stats mib, so for those we just count them as general * errors. Stats for iframes, ibutes, oframes and obytes are * collected elsewhere. These registers zero on a read to prevent * races. For all the collision stats, also update the collision * stats for the interface. */ sc->mibdata.dot3StatsAlignmentErrors += RD4(sc, ETH_ALE); sc->mibdata.dot3StatsFCSErrors += RD4(sc, ETH_SEQE); c = RD4(sc, ETH_SCOL); if_inc_counter(ifp, IFCOUNTER_COLLISIONS, c); sc->mibdata.dot3StatsSingleCollisionFrames += c; c = RD4(sc, ETH_MCOL); sc->mibdata.dot3StatsMultipleCollisionFrames += c; if_inc_counter(ifp, IFCOUNTER_COLLISIONS, c); sc->mibdata.dot3StatsSQETestErrors += RD4(sc, ETH_SQEE); sc->mibdata.dot3StatsDeferredTransmissions += RD4(sc, ETH_DTE); c = RD4(sc, ETH_LCOL); sc->mibdata.dot3StatsLateCollisions += c; if_inc_counter(ifp, IFCOUNTER_COLLISIONS, c); c = RD4(sc, ETH_ECOL); sc->mibdata.dot3StatsExcessiveCollisions += c; if_inc_counter(ifp, IFCOUNTER_COLLISIONS, c); sc->mibdata.dot3StatsCarrierSenseErrors += RD4(sc, ETH_CSE); sc->mibdata.dot3StatsFrameTooLongs += RD4(sc, ETH_ELR); sc->mibdata.dot3StatsInternalMacReceiveErrors += RD4(sc, ETH_DRFC); /* * Not sure where to lump these, so count them against the errors * for the interface. */ if_inc_counter(sc->ifp, IFCOUNTER_OERRORS, RD4(sc, ETH_TUE)); if_inc_counter(sc->ifp, IFCOUNTER_IERRORS, RD4(sc, ETH_CDE) + RD4(sc, ETH_RJB) + RD4(sc, ETH_USF)); /* Schedule another timeout one second from now. */ callout_reset(&sc->tick_ch, hz, ate_tick, sc); } static void ate_set_mac(struct ate_softc *sc, u_char *eaddr) { WR4(sc, ETH_SA1L, (eaddr[3] << 24) | (eaddr[2] << 16) | (eaddr[1] << 8) | eaddr[0]); WR4(sc, ETH_SA1H, (eaddr[5] << 8) | (eaddr[4])); } static int ate_get_mac(struct ate_softc *sc, u_char *eaddr) { bus_size_t sa_low_reg[] = { ETH_SA1L, ETH_SA2L, ETH_SA3L, ETH_SA4L }; bus_size_t sa_high_reg[] = { ETH_SA1H, ETH_SA2H, ETH_SA3H, ETH_SA4H }; uint32_t low, high; int i; /* * The boot loader may setup the MAC with an address(es), grab the * first MAC address from the SA[1-4][HL] registers. */ for (i = 0; i < 4; i++) { low = RD4(sc, sa_low_reg[i]); high = RD4(sc, sa_high_reg[i]); if ((low | (high & 0xffff)) != 0) { eaddr[0] = low & 0xff; eaddr[1] = (low >> 8) & 0xff; eaddr[2] = (low >> 16) & 0xff; eaddr[3] = (low >> 24) & 0xff; eaddr[4] = high & 0xff; eaddr[5] = (high >> 8) & 0xff; return (0); } } return (ENXIO); } static void ate_intr(void *xsc) { struct ate_softc *sc = xsc; struct ifnet *ifp = sc->ifp; struct mbuf *mb; eth_rx_desc_t *rxdhead; uint32_t status, reg, idx; int remain, count, done; status = RD4(sc, ETH_ISR); if (status == 0) return; if (status & ETH_ISR_RCOM) { bus_dmamap_sync(sc->rx_desc_tag, sc->rx_desc_map, BUS_DMASYNC_POSTREAD); rxdhead = &sc->rx_descs[sc->rxhead]; while (rxdhead->addr & ETH_CPU_OWNER) { if (!sc->is_emacb) { /* * Simulate SAM9 FIRST/LAST bits for RM9200. * RM9200 EMAC has only on Rx buffer per packet. * But sometime we are handed a zero length packet. */ if ((rxdhead->status & ETH_LEN_MASK) == 0) rxdhead->status = 0; /* Mark error */ else rxdhead->status |= ETH_BUF_FIRST | ETH_BUF_LAST; } if ((rxdhead->status & ETH_BUF_FIRST) == 0) { /* Something went wrong during RX so release back to EMAC all buffers of invalid packets. */ rxdhead->status = 0; rxdhead->addr &= ~ETH_CPU_OWNER; sc->rxhead = NEXT_RX_IDX(sc, sc->rxhead); rxdhead = &sc->rx_descs[sc->rxhead]; continue; } /* Find end of packet or start of next */ idx = sc->rxhead; if ((sc->rx_descs[idx].status & ETH_BUF_LAST) == 0) { idx = NEXT_RX_IDX(sc, idx); while ((sc->rx_descs[idx].addr & ETH_CPU_OWNER) && ((sc->rx_descs[idx].status & (ETH_BUF_FIRST|ETH_BUF_LAST))== 0)) idx = NEXT_RX_IDX(sc, idx); } /* Packet NOT yet completely in memory; we are done */ if ((sc->rx_descs[idx].addr & ETH_CPU_OWNER) == 0 || ((sc->rx_descs[idx].status & (ETH_BUF_FIRST|ETH_BUF_LAST))== 0)) break; /* Packets with no end descriptor are invalid. */ if ((sc->rx_descs[idx].status & ETH_BUF_LAST) == 0) { rxdhead->status &= ~ETH_BUF_FIRST; continue; } /* FCS is not coppied into mbuf. */ remain = (sc->rx_descs[idx].status & ETH_LEN_MASK) - 4; /* Get an appropriately sized mbuf. */ mb = m_get2(remain + ETHER_ALIGN, M_NOWAIT, MT_DATA, M_PKTHDR); if (mb == NULL) { if_inc_counter(sc->ifp, IFCOUNTER_IQDROPS, 1); rxdhead->status = 0; continue; } mb->m_data += ETHER_ALIGN; mb->m_pkthdr.rcvif = ifp; WR4(sc, ETH_RSR, RD4(sc, ETH_RSR)); /* Reset status */ /* Now we process the buffers that make up the packet */ do { /* Last buffer may just be 1-4 bytes of FCS so remain * may be zero for last descriptor. */ if (remain > 0) { /* Make sure we get the current bytes */ bus_dmamap_sync(sc->rx_tag, sc->rx_map[sc->rxhead], BUS_DMASYNC_POSTREAD); count = MIN(remain, sc->rx_buf_size); /* XXX Performance robbing copy. Could * receive directly to mbufs if not an * RM9200. And even then we could likely * copy just the protocol headers. XXX */ m_append(mb, count, sc->rx_buf[sc->rxhead]); remain -= count; } done = (rxdhead->status & ETH_BUF_LAST) != 0; /* Return the descriptor to the EMAC */ rxdhead->status = 0; rxdhead->addr &= ~ETH_CPU_OWNER; bus_dmamap_sync(sc->rx_desc_tag, sc->rx_desc_map, BUS_DMASYNC_PREWRITE); /* Move on to next descriptor with wrap */ sc->rxhead = NEXT_RX_IDX(sc, sc->rxhead); rxdhead = &sc->rx_descs[sc->rxhead]; } while (!done); if_inc_counter(ifp, IFCOUNTER_IPACKETS, 1); (*ifp->if_input)(ifp, mb); } } if (status & ETH_ISR_TCOM) { bus_dmamap_sync(sc->tx_desc_tag, sc->tx_desc_map, BUS_DMASYNC_POSTREAD); ATE_LOCK(sc); /* XXX TSR register should be cleared */ if (!sc->is_emacb) { /* Simulate Transmit descriptor table */ /* First packet done */ if (sc->txtail < sc->txhead) sc->tx_descs[sc->txtail].status |= ETHB_TX_USED; /* Second Packet done */ if (sc->txtail + 1 < sc->txhead && RD4(sc, ETH_TSR) & ETH_TSR_IDLE) sc->tx_descs[sc->txtail + 1].status |= ETHB_TX_USED; } while ((sc->tx_descs[sc->txtail].status & ETHB_TX_USED) && sc->sent_mbuf[sc->txtail] != NULL) { bus_dmamap_sync(sc->mtag, sc->tx_map[sc->txtail], BUS_DMASYNC_POSTWRITE); bus_dmamap_unload(sc->mtag, sc->tx_map[sc->txtail]); m_freem(sc->sent_mbuf[sc->txtail]); sc->tx_descs[sc->txtail].addr = 0; sc->sent_mbuf[sc->txtail] = NULL; if_inc_counter(ifp, IFCOUNTER_OPACKETS, 1); sc->txtail = NEXT_TX_IDX(sc, sc->txtail); } /* Flush descriptors to EMAC */ bus_dmamap_sync(sc->tx_desc_tag, sc->tx_desc_map, BUS_DMASYNC_PREWRITE); /* * We're no longer busy, so clear the busy flag and call the * start routine to xmit more packets. */ sc->ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; atestart_locked(sc->ifp); ATE_UNLOCK(sc); } if (status & ETH_ISR_RBNA) { /* Workaround RM9200 Errata #11 */ if (bootverbose) device_printf(sc->dev, "RBNA workaround\n"); reg = RD4(sc, ETH_CTL); WR4(sc, ETH_CTL, reg & ~ETH_CTL_RE); BARRIER(sc, ETH_CTL, 4, BUS_SPACE_BARRIER_WRITE); WR4(sc, ETH_CTL, reg | ETH_CTL_RE); } /* XXX need to work around SAM9260 errata 43.2.4.1: * disable the mac, reset tx buffer, enable mac on TUND */ } /* * Reset and initialize the chip. */ static void ateinit_locked(void *xsc) { struct ate_softc *sc = xsc; struct ifnet *ifp = sc->ifp; struct mii_data *mii; uint8_t eaddr[ETHER_ADDR_LEN]; uint32_t reg; ATE_ASSERT_LOCKED(sc); /* * XXX TODO(3) * we need to turn on the EMAC clock in the pmc. With the * default boot loader, this is already turned on. However, we * need to think about how best to turn it on/off as the interface * is brought up/down, as well as dealing with the mii bus... * * We also need to multiplex the pins correctly (in board_xxx.c). */ /* * There are two different ways that the mii bus is connected * to this chip mii or rmii. */ if (!sc->is_emacb) { /* RM9200 */ reg = RD4(sc, ETH_CFG); if (sc->use_rmii) reg |= ETH_CFG_RMII; else reg &= ~ETH_CFG_RMII; WR4(sc, ETH_CFG, reg); } else { /* SAM9 */ reg = ETHB_UIO_CLKE; reg |= (sc->use_rmii) ? ETHB_UIO_RMII : 0; WR4(sc, ETHB_UIO, reg); } ate_rxfilter(sc); /* * Set the chip MAC address. */ bcopy(IF_LLADDR(ifp), eaddr, ETHER_ADDR_LEN); ate_set_mac(sc, eaddr); /* Make sure we know state of TX queue */ sc->txhead = sc->txtail = 0; if (sc->is_emacb) { /* Write the descriptor queue address. */ WR4(sc, ETHB_TBQP, sc->tx_desc_phys); } /* * Turn on MACs and interrupt processing. */ WR4(sc, ETH_CTL, RD4(sc, ETH_CTL) | ETH_CTL_TE | ETH_CTL_RE); WR4(sc, ETH_IER, ETH_ISR_RCOM | ETH_ISR_TCOM | ETH_ISR_RBNA); /* Enable big packets. */ WR4(sc, ETH_CFG, RD4(sc, ETH_CFG) | ETH_CFG_BIG); /* * Set 'running' flag, and clear output active flag * and attempt to start the output. */ ifp->if_drv_flags |= IFF_DRV_RUNNING; ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; mii = device_get_softc(sc->miibus); mii_pollstat(mii); ate_stat_update(sc, mii->mii_media_active); atestart_locked(ifp); callout_reset(&sc->tick_ch, hz, ate_tick, sc); } /* * Dequeue packets and transmit. */ static void atestart_locked(struct ifnet *ifp) { struct ate_softc *sc = ifp->if_softc; struct mbuf *m, *mdefrag; bus_dma_segment_t segs[1]; int nseg, e; ATE_ASSERT_LOCKED(sc); if (ifp->if_drv_flags & IFF_DRV_OACTIVE) return; while (sc->tx_descs[sc->txhead].status & ETHB_TX_USED) { /* * Check to see if there's room to put another packet into the * xmit queue. The old EMAC version has a ping-pong buffer for * xmit packets. We use OACTIVE to indicate "we can stuff more * into our buffers (clear) or not (set)." */ /* RM9200 has only two hardware entries */ if (!sc->is_emacb && (RD4(sc, ETH_TSR) & ETH_TSR_BNQ) == 0) { ifp->if_drv_flags |= IFF_DRV_OACTIVE; return; } IFQ_DRV_DEQUEUE(&ifp->if_snd, m); if (m == NULL) break; e = bus_dmamap_load_mbuf_sg(sc->mtag, sc->tx_map[sc->txhead], m, segs, &nseg, 0); if (e == EFBIG) { mdefrag = m_defrag(m, M_NOWAIT); if (mdefrag == NULL) { IFQ_DRV_PREPEND(&ifp->if_snd, m); return; } m = mdefrag; e = bus_dmamap_load_mbuf_sg(sc->mtag, sc->tx_map[sc->txhead], m, segs, &nseg, 0); } if (e != 0) { m_freem(m); continue; } /* * There's a small race between the loop in ate_intr finishing * and the check above to see if the packet was finished, as well * as when atestart gets called via other paths. Lose the race * gracefully and free the mbuf... */ if (sc->sent_mbuf[sc->txhead] != NULL) { bus_dmamap_sync(sc->mtag, sc->tx_map[sc->txtail], BUS_DMASYNC_POSTWRITE); bus_dmamap_unload(sc->mtag, sc->tx_map[sc->txtail]); m_free(sc->sent_mbuf[sc->txhead]); if_inc_counter(ifp, IFCOUNTER_OPACKETS, 1); } sc->sent_mbuf[sc->txhead] = m; bus_dmamap_sync(sc->mtag, sc->tx_map[sc->txhead], BUS_DMASYNC_PREWRITE); /* Tell the hardware to xmit the packet. */ if (!sc->is_emacb) { WR4(sc, ETH_TAR, segs[0].ds_addr); BARRIER(sc, ETH_TAR, 4, BUS_SPACE_BARRIER_WRITE); WR4(sc, ETH_TCR, segs[0].ds_len); } else { bus_dmamap_sync(sc->tx_desc_tag, sc->tx_desc_map, BUS_DMASYNC_POSTWRITE); sc->tx_descs[sc->txhead].addr = segs[0].ds_addr; sc->tx_descs[sc->txhead].status = segs[0].ds_len | (sc->tx_descs[sc->txhead].status & ETHB_TX_WRAP) | ETHB_TX_BUF_LAST; bus_dmamap_sync(sc->tx_desc_tag, sc->tx_desc_map, BUS_DMASYNC_PREWRITE); WR4(sc, ETH_CTL, RD4(sc, ETH_CTL) | ETHB_CTL_TGO); } sc->txhead = NEXT_TX_IDX(sc, sc->txhead); /* Tap off here if there is a bpf listener. */ BPF_MTAP(ifp, m); } if ((sc->tx_descs[sc->txhead].status & ETHB_TX_USED) == 0) ifp->if_drv_flags |= IFF_DRV_OACTIVE; } static void ateinit(void *xsc) { struct ate_softc *sc = xsc; ATE_LOCK(sc); ateinit_locked(sc); ATE_UNLOCK(sc); } static void atestart(struct ifnet *ifp) { struct ate_softc *sc = ifp->if_softc; ATE_LOCK(sc); atestart_locked(ifp); ATE_UNLOCK(sc); } /* * Turn off interrupts, and stop the NIC. Can be called with sc->ifp NULL, * so be careful. */ static void atestop(struct ate_softc *sc) { struct ifnet *ifp; int i; ATE_ASSERT_LOCKED(sc); ifp = sc->ifp; if (ifp) { //ifp->if_timer = 0; ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE); } callout_stop(&sc->tick_ch); /* * Enable some parts of the MAC that are needed always (like the * MII bus. This turns off the RE and TE bits, which will remain * off until ateinit() is called to turn them on. With RE and TE * turned off, there's no DMA to worry about after this write. */ WR4(sc, ETH_CTL, ETH_CTL_MPE); /* * Turn off all the configured options and revert to defaults. */ /* Make sure thate the MDIO clk is less than * 2.5 Mhz. Can no longer default to /32 since * SAM9 family may have MCK > 80 Mhz */ if (at91_master_clock <= 2000000) WR4(sc, ETH_CFG, ETH_CFG_CLK_8); else if (at91_master_clock <= 4000000) WR4(sc, ETH_CFG, ETH_CFG_CLK_16); else if (at91_master_clock <= 800000) WR4(sc, ETH_CFG, ETH_CFG_CLK_32); else WR4(sc, ETH_CFG, ETH_CFG_CLK_64); /* * Turn off all the interrupts, and ack any pending ones by reading * the ISR. */ WR4(sc, ETH_IDR, 0xffffffff); RD4(sc, ETH_ISR); /* * Clear out the Transmit and Receiver Status registers of any * errors they may be reporting */ WR4(sc, ETH_TSR, 0xffffffff); WR4(sc, ETH_RSR, 0xffffffff); /* Release TX resources. */ for (i = 0; i < ATE_MAX_TX_BUFFERS; i++) { if (sc->sent_mbuf[i] != NULL) { bus_dmamap_sync(sc->mtag, sc->tx_map[i], BUS_DMASYNC_POSTWRITE); bus_dmamap_unload(sc->mtag, sc->tx_map[i]); m_freem(sc->sent_mbuf[i]); sc->sent_mbuf[i] = NULL; } } /* Turn off transeiver input clock */ if (sc->is_emacb) WR4(sc, ETHB_UIO, RD4(sc, ETHB_UIO) & ~ETHB_UIO_CLKE); /* * XXX we should power down the EMAC if it isn't in use, after * putting it into loopback mode. This saves about 400uA according * to the datasheet. */ } static void ate_rxfilter(struct ate_softc *sc) { struct ifnet *ifp; uint32_t reg; int enabled; KASSERT(sc != NULL, ("[ate, %d]: sc is NULL!", __LINE__)); ATE_ASSERT_LOCKED(sc); ifp = sc->ifp; /* Wipe out old filter settings. */ reg = RD4(sc, ETH_CFG); reg &= ~(ETH_CFG_CAF | ETH_CFG_MTI | ETH_CFG_UNI); reg |= ETH_CFG_NBC; sc->flags &= ~ATE_FLAG_MULTICAST; /* Set new parameters. */ if ((ifp->if_flags & IFF_BROADCAST) != 0) reg &= ~ETH_CFG_NBC; if ((ifp->if_flags & IFF_PROMISC) != 0) { reg |= ETH_CFG_CAF; } else { enabled = ate_setmcast(sc); if (enabled != 0) { reg |= ETH_CFG_MTI; sc->flags |= ATE_FLAG_MULTICAST; } } WR4(sc, ETH_CFG, reg); } static int ateioctl(struct ifnet *ifp, u_long cmd, caddr_t data) { struct ate_softc *sc = ifp->if_softc; struct mii_data *mii; struct ifreq *ifr = (struct ifreq *)data; int drv_flags, flags; int mask, error, enabled; error = 0; flags = ifp->if_flags; drv_flags = ifp->if_drv_flags; switch (cmd) { case SIOCSIFFLAGS: ATE_LOCK(sc); if ((flags & IFF_UP) != 0) { if ((drv_flags & IFF_DRV_RUNNING) != 0) { if (((flags ^ sc->if_flags) & (IFF_PROMISC | IFF_ALLMULTI)) != 0) ate_rxfilter(sc); } else { if ((sc->flags & ATE_FLAG_DETACHING) == 0) ateinit_locked(sc); } } else if ((drv_flags & IFF_DRV_RUNNING) != 0) { ifp->if_drv_flags &= ~IFF_DRV_RUNNING; atestop(sc); } sc->if_flags = flags; ATE_UNLOCK(sc); break; case SIOCADDMULTI: case SIOCDELMULTI: if ((drv_flags & IFF_DRV_RUNNING) != 0) { ATE_LOCK(sc); enabled = ate_setmcast(sc); if (enabled != (sc->flags & ATE_FLAG_MULTICAST)) ate_rxfilter(sc); ATE_UNLOCK(sc); } break; case SIOCSIFMEDIA: case SIOCGIFMEDIA: mii = device_get_softc(sc->miibus); error = ifmedia_ioctl(ifp, ifr, &mii->mii_media, cmd); break; case SIOCSIFCAP: mask = ifp->if_capenable ^ ifr->ifr_reqcap; if (mask & IFCAP_VLAN_MTU) { ATE_LOCK(sc); if (ifr->ifr_reqcap & IFCAP_VLAN_MTU) { WR4(sc, ETH_CFG, RD4(sc, ETH_CFG) | ETH_CFG_BIG); ifp->if_capenable |= IFCAP_VLAN_MTU; } else { WR4(sc, ETH_CFG, RD4(sc, ETH_CFG) & ~ETH_CFG_BIG); ifp->if_capenable &= ~IFCAP_VLAN_MTU; } ATE_UNLOCK(sc); } default: error = ether_ioctl(ifp, cmd, data); break; } return (error); } static void ate_child_detached(device_t dev, device_t child) { struct ate_softc *sc; sc = device_get_softc(dev); if (child == sc->miibus) sc->miibus = NULL; } /* * MII bus support routines. */ static int ate_miibus_readreg(device_t dev, int phy, int reg) { struct ate_softc *sc; int val; /* * XXX if we implement aggressive power savings, then we need * XXX to make sure that the clock to the emac is on here */ sc = device_get_softc(dev); DELAY(1); /* Hangs w/o this delay really 30.5us atm */ WR4(sc, ETH_MAN, ETH_MAN_REG_RD(phy, reg)); while ((RD4(sc, ETH_SR) & ETH_SR_IDLE) == 0) continue; val = RD4(sc, ETH_MAN) & ETH_MAN_VALUE_MASK; return (val); } static int ate_miibus_writereg(device_t dev, int phy, int reg, int data) { struct ate_softc *sc; /* * XXX if we implement aggressive power savings, then we need * XXX to make sure that the clock to the emac is on here */ sc = device_get_softc(dev); WR4(sc, ETH_MAN, ETH_MAN_REG_WR(phy, reg, data)); while ((RD4(sc, ETH_SR) & ETH_SR_IDLE) == 0) continue; return (0); } static device_method_t ate_methods[] = { /* Device interface */ DEVMETHOD(device_probe, ate_probe), DEVMETHOD(device_attach, ate_attach), DEVMETHOD(device_detach, ate_detach), /* Bus interface */ DEVMETHOD(bus_child_detached, ate_child_detached), /* MII interface */ DEVMETHOD(miibus_readreg, ate_miibus_readreg), DEVMETHOD(miibus_writereg, ate_miibus_writereg), DEVMETHOD_END }; static driver_t ate_driver = { "ate", ate_methods, sizeof(struct ate_softc), }; #ifdef FDT DRIVER_MODULE(ate, simplebus, ate_driver, ate_devclass, NULL, NULL); #else DRIVER_MODULE(ate, atmelarm, ate_driver, ate_devclass, NULL, NULL); #endif DRIVER_MODULE(miibus, ate, miibus_driver, miibus_devclass, NULL, NULL); MODULE_DEPEND(ate, miibus, 1, 1, 1); MODULE_DEPEND(ate, ether, 1, 1, 1); Index: head/sys/arm/at91/if_atereg.h =================================================================== --- head/sys/arm/at91/if_atereg.h (revision 333141) +++ head/sys/arm/at91/if_atereg.h (revision 333142) @@ -1,216 +1,216 @@ /*- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD * - * Copyright (c) 2006 M. Warner Losh. All rights reserved. + * Copyright (c) 2006 M. Warner Losh. * * 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_IF_ATEREG_H #define ARM_AT91_IF_ATEREG_H /* Defines beginning ETHB_ are EMACB (newer SAM9 hardware) versions only. */ #define ETH_CTL 0x00 /* EMAC Control Register */ #define ETH_CFG 0x04 /* EMAC Configuration Register */ #define ETH_SR 0x08 /* EMAC STatus Register */ #define ETH_TAR 0x0c /* EMAC Transmit Address Register */ #define ETH_TCR 0x10 /* EMAC Transmit Control Register */ #define ETH_TSR 0x14 /* EMAC Transmit Status Register */ #define ETH_RBQP 0x18 /* EMAC Receive Buffer Queue Pointer */ #define ETHB_TBQP 0x1c /* reserved */ #define ETH_RSR 0x20 /* EMAC Receive Status Register */ #define ETH_ISR 0x24 /* EMAC Interrupt Status Register */ #define ETH_IER 0x28 /* EMAC Interrupt Enable Register */ #define ETH_IDR 0x2c /* EMAC Interrupt Disable Register */ #define ETH_IMR 0x30 /* EMAC Interrupt Mask Register */ #define ETH_MAN 0x34 /* EMAC PHY Maintenance Register */ /* 0x38 reserved */ /* 0x3c reserved */ #define ETH_FRA 0x40 /* Frames Transmitted OK Register */ #define ETH_SCOL 0x44 /* Single Collision Frame Register */ #define ETH_MCOL 0x48 /* Multiple Collision Frame Register */ #define ETH_OK 0x4c /* Frames Received OK Register */ #define ETH_SEQE 0x50 /* Frame Check Sequence Error Reg */ #define ETH_ALE 0x54 /* Alignment Error Register */ #define ETH_DTE 0x58 /* Deferred Transmittion Frame Reg */ #define ETH_LCOL 0x5c /* Late Collision Register */ #define ETH_ECOL 0x60 /* Excessive Collision Register */ #define ETH_TUE 0x64 /* Transmit Underrun Error Register */ #define ETH_CSE 0x68 /* Carrier Sense Error Register */ #define ETH_DRFC 0x6c /* Discarded RX Frame Register */ #define ETH_ROV 0x68 /* Receive Overrun Register */ #define ETH_CDE 0x64 /* Code Error Register */ #define ETH_ELR 0x78 /* Excessive Length Error Register */ #define ETH_RJB 0x7c /* Receive Jabber Register */ #define ETH_USF 0x80 /* Undersize Frame Register */ #define ETH_SQEE 0x84 /* SQE Test Error Register */ /* 0x88 reserved */ /* 0x8c reserved */ #define ETH_HSL 0x90 /* EMAC Hash Address Low [31:0] */ #define ETH_HSH 0x94 /* EMAC Hash Address High [63:32] */ #define ETH_SA1L 0x98 /* EMAC Specific Address 1 Low */ #define ETH_SA1H 0x9c /* EMAC Specific Address 1 High */ #define ETH_SA2L 0xa0 /* EMAC Specific Address 2 Low */ #define ETH_SA2H 0xa4 /* EMAC Specific Address 2 High */ #define ETH_SA3L 0xa8 /* EMAC Specific Address 3 Low */ #define ETH_SA3H 0xac /* EMAC Specific Address 3 High */ #define ETH_SA4L 0xb0 /* EMAC Specific Address 4 Low */ #define ETH_SA4H 0xb4 /* EMAC Specific Address 4 High */ #define ETHB_TID 0xb8 /* EMAC Type ID Checking */ #define ETHB_UIO 0xC0 /* EMAC User I/O Reg */ /* ETH_CTL */ #define ETH_CTL_LB (1U << 0) /* LB: Loopback */ #define ETH_CTL_LBL (1U << 1) /* LBL: Loopback Local */ #define ETH_CTL_RE (1U << 2) /* RE: Receive Enable */ #define ETH_CTL_TE (1U << 3) /* TE: Transmit Enable */ #define ETH_CTL_MPE (1U << 4) /* MPE: Management Port Enable */ #define ETH_CTL_CSR (1U << 5) /* CSR: Clear Statistics Registers */ #define ETH_CTL_ISR (1U << 6) /* ISR: Incremenet Statistics Regs */ #define ETH_CTL_WES (1U << 7) /* WES: Write Enable Statistics regs */ #define ETH_CTL_BP (1U << 8) /* BP: Back Pressure */ #define ETHB_CTL_TGO (1U << 9) /* TGO: Transmitter Start */ #define ETHB_CTL_TSTP (1U << 10) /* TSTP: Transmitter Stop */ /* ETH_CFG */ #define ETH_CFG_SPD (1U << 0) /* SPD: Speed 1 == 100: 0 == 10 */ #define ETH_CFG_FD (1U << 1) /* FD: Full duplex */ #define ETH_CFG_BR (1U << 2) /* BR: Bit Rate (optional?) */ /* bit 3 reserved */ #define ETH_CFG_CAF (1U << 4) /* CAF: Copy All Frames */ #define ETH_CFG_NBC (1U << 5) /* NBC: No Broadcast */ #define ETH_CFG_MTI (1U << 6) /* MTI: Multicast Hash Enable */ #define ETH_CFG_UNI (1U << 7) /* UNI: Unicast Hash Enable */ #define ETH_CFG_BIG (1U << 8) /* BIG: Receive 1522 Bytes */ #define ETH_CFG_EAE (1U << 9) /* EAE: External Address Match En */ #define ETH_CFG_CLK_8 (0U << 10) /* CLK: Clock / 8 */ #define ETH_CFG_CLK_16 (1U << 10) /* CLK: Clock / 16 */ #define ETH_CFG_CLK_32 (2U << 10) /* CLK: Clock / 32 */ #define ETH_CFG_CLK_64 (3U << 10) /* CLK: Clock / 64 */ #define ETH_CFG_RTY (1U << 12) /* RTY: Retry Test*/ #define ETH_CFG_RMII (1U << 13) /* RMII: Reduce MII */ #define ETHB_CFG_JBO (1U << 3) /* JBO: Jumbo Frames */ #define ETHB_CFG_PAE (1U << 13) /* PAE: Pause Enable */ #define ETHB_CFG_RBOF_0 (0U << 14) /* RBOF: Rx Buffer Offset */ #define ETHB_CFG_RBOF_1 (1U << 14) /* RBOF: Rx Buffer Offset */ #define ETHB_CFG_RBOF_2 (3U << 14) /* RBOF: Rx Buffer Offset */ #define ETHB_CFG_RBOF_3 (3U << 14) /* RBOF: Rx Buffer Offset */ #define ETHB_CFG_RCLE (1U << 16) /* RCLE: Rx Length Check Enable */ #define ETHB_CFG_DRFC (1U << 17) /* DRFC: Discard Rx FCS */ #define ETHB_CFG_RHD (1U << 18) /* RHD: RX TX'ed frame in half-duplex */ #define ETHB_CFG_IFCS (1U << 19) /* IFCS: Ignore bad RX FCS */ /* ETH_SR */ #define ETH_SR_LINK (1U << 0) /* Reserved! */ #define ETH_SR_MDIO (1U << 1) /* MDIO pin status */ #define ETH_SR_IDLE (1U << 2) /* IDLE (PHY logic) */ /* ETH_TCR */ #define ETH_TCR_NCRC (1U << 15) /* NCRC: No CRC */ /* ETH_TSR */ #define ETH_TSR_OVR (1U << 0) /* OVR: Ethernet Transmit Overrun */ #define ETH_TSR_COL (1U << 1) /* COL: Collision Occurred */ #define ETH_TSR_RLE (1U << 2) /* RLE: Retry Limit Exceeded */ #define ETH_TSR_IDLE (1U << 3) /* IDLE: Transmitter Idle */ #define ETH_TSR_BNQ (1U << 4) /* BNQ: Enet Tran Buff not Queued */ #define ETH_TSR_COMP (1U << 5) /* COMP: Transmit Complete */ #define ETH_TSR_UND (1U << 6) /* UND: Transmit Underrun */ #define ETH_TSR_WR_MASK (0x67) /* write 1 to clear bits */ /* ETH_RSR */ #define ETH_RSR_BNA (1U << 0) /* BNA: Buffer Not Available */ #define ETH_RSR_REC (1U << 1) /* REC: Frame Received */ #define ETH_RSR_OVR (1U << 2) /* OVR: RX Overrun */ /* ETH_ISR */ #define ETH_ISR_DONE (1U << 0) /* DONE: Management Done */ #define ETH_ISR_RCOM (1U << 1) /* RCOM: Receive Complete */ #define ETH_ISR_RBNA (1U << 2) /* RBNA: Receive Buffer Not Avail */ #define ETH_ISR_TOVR (1U << 3) /* TOVR: Transmit Buffer Overrun */ #define ETH_ISR_TUND (1U << 4) /* TUND: Transmit Buffer Underrun */ #define ETH_ISR_RTRY (1U << 5) /* RTRY: Retry Limit */ #define ETH_ISR_TBRE (1U << 6) /* TBRE: Trasnmit Buffer Reg empty */ #define ETH_ISR_TCOM (1U << 7) /* TCOM: Transmit Complete */ #define ETH_ISR_TIDLE (1U << 8) /* TIDLE: Transmit Idle */ #define ETH_ISR_LINK (1U << 9) /* LINK: Link pin delta (optional) */ #define ETH_ISR_ROVR (1U << 10) /* ROVR: RX Overrun */ #define ETH_ISR_ABT (1U << 11) /* ABT: Abort */ /* ETHB_UIO */ #define ETHB_UIO_RMII (1U << 0) /* RMII: Reduce MII */ #define ETHB_UIO_CLKE (1U << 1) /* CLKE: Clock Enable */ /* ETH_MAN */ #define ETH_MAN_BITS 0x40020000 /* HIGH and CODE bits */ #define ETH_MAN_READ (2U << 28) #define ETH_MAN_WRITE (1U << 28) #define ETH_MAN_PHYA_BIT 23 #define ETH_MAN_REGA_BIT 18 #define ETH_MAN_VALUE_MASK 0xffffU #define ETH_MAN_REG_WR(phy, reg, val) \ (ETH_MAN_BITS | ETH_MAN_WRITE | ((phy) << ETH_MAN_PHYA_BIT) | \ ((reg) << ETH_MAN_REGA_BIT) | ((val) & ETH_MAN_VALUE_MASK)) #define ETH_MAN_REG_RD(phy, reg) \ (ETH_MAN_BITS | ETH_MAN_READ | ((phy) << ETH_MAN_PHYA_BIT) | \ ((reg) << ETH_MAN_REGA_BIT)) typedef struct { uint32_t addr; #define ETH_CPU_OWNER (1U << 0) #define ETH_WRAP_BIT (1U << 1) #define ETH_ADR_MASK ~(EHT_CPU_OWNER | ETH_WRAP_BIT) uint32_t status; #define ETH_LEN_MASK 0x7ff #define ETH_BUF_FIRST (1U << 14) /* Packet matched addr 4 */ #define ETH_BUF_LAST (1U << 15) /* Packet matched addr 4 */ #define ETH_MAC_LOCAL_4 (1U << 23) /* Packet matched addr 4 */ #define ETH_MAC_LOCAL_3 (1U << 24) /* Packet matched addr 3 */ #define ETH_MAC_LOCAL_2 (1U << 25) /* Packet matched addr 2 */ #define ETH_MAC_LOCAL_1 (1U << 26) /* Packet matched addr 1 */ #define ETH_MAC_UNK (1U << 27) /* Unknown source address RFU */ #define ETH_MAC_EXT (1U << 28) /* External Address */ #define ETH_MAC_UCAST (1U << 29) /* Unicast hash match */ #define ETH_MAC_MCAST (1U << 30) /* Multicast hash match */ #define ETH_MAC_ONES (1U << 31) /* Global all ones bcast addr */ } eth_rx_desc_t; typedef struct { uint32_t addr; uint32_t status; #define ETHB_TX_LEN_MASK 0x7ff #define ETHB_TX_BUF_LAST (1U << 15) /* Last buffer in packet */ #define ETHB_TX_NOCRC (1U << 16) /* Don't xmit CRC*/ #define ETHB_TX_BUFE (1U << 27) /* Buffers exhausted mid frame */ #define ETHB_TX_TUND (1U << 28) /* Transmit Underrun */ #define ETHB_TX_RTRYE (1U << 29) /* Re-try limit exceeded */ #define ETHB_TX_WRAP (1U << 30) /* Last descritor in list */ #define ETHB_TX_USED (1U << 31) /* Packet Transmitted */ } eth_tx_desc_t; #endif /* ARM_AT91_IF_ATEREG_H */ Index: head/sys/arm/conf/genboardid.awk =================================================================== --- head/sys/arm/conf/genboardid.awk (revision 333141) +++ head/sys/arm/conf/genboardid.awk (revision 333142) @@ -1,57 +1,57 @@ #!/bin/awk # $FreeBSD$ #- # SPDX-License-Identifier: BSD-2-Clause-FreeBSD # -# Copyright (c) 2012 M. Warner Losh. All Rights Reserved. +# Copyright (c) 2012 M. Warner Losh. # # 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 THE 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 THE 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. # # # Generate FreeBSD's board ID's defines from Linux's # arm board list. # # You can grab a new copy any time with: # fetch -o sys/arm/conf/mach-types http://www.arm.linux.org.uk/developer/machines/download.php # BEGIN { nr = 0; boardid[nr] = "ARM_BOARD_ID_NONE"; num[nr++] = 0; } /^#/ { next; } /^[ ]*$/ { next; } NF == 4 { boardid[nr] = "ARM_BOARD_ID_"$3; num[nr] = $4; nr++ } END { printf("/* Arm board ID file generated automatically from Linux's mach-types file. */\n\n"); printf("#ifndef _SYS_ARM_ARM_BOARDID_H\n"); printf("#define _SYS_ARM_ARM_BOARDID_H\n\n"); for (i = 0; i < nr; i++) { printf("#define %-30s %d\n", boardid[i], num[i]); } printf("\n#endif /* _SYS_ARM_ARM_BOARDID_H */\n"); } Index: head/sys/arm/include/_bus.h =================================================================== --- head/sys/arm/include/_bus.h (revision 333141) +++ head/sys/arm/include/_bus.h (revision 333142) @@ -1,48 +1,47 @@ /*- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD * * Copyright (c) 2005 M. 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, * without modification, immediately at the beginning of the file. * 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 THE 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 THE 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_INCLUDE__BUS_H #define ARM_INCLUDE__BUS_H /* * Addresses (in bus space). */ typedef u_long bus_addr_t; typedef u_long bus_size_t; /* * Access methods for bus space. */ typedef struct bus_space *bus_space_tag_t; typedef u_long bus_space_handle_t; #endif /* ARM_INCLUDE__BUS_H */ Index: head/sys/arm/include/at91_gpio.h =================================================================== --- head/sys/arm/include/at91_gpio.h (revision 333141) +++ head/sys/arm/include/at91_gpio.h (revision 333142) @@ -1,110 +1,110 @@ /*- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD * - * Copyright (C) 2006 M. Warner Losh. All rights reserved. + * Copyright (C) 2006 M. Warner Losh. * Copyright (C) 2012 Ian Lepore. 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_GPIO_H #define _ARM_AT91_GPIO_H #ifndef _KERNEL #include #endif #include /* Userland GPIO API for Atmel AT91 series SOC. * * Open /dev/pioN (where N is 0 for PIOA, 1 for PIOB, etc), and use ioctl(2) * calls to configure the pin(s) as needed. * * The userland interrupt support allows you to use read(2) and/or select(2) to * get notified of interrupts on PIO pins for which you enabled interrupt * notifications. Each time an interrupt occurs on a given pin, that pin number * is written into a buffer as a uint8_t. Thus, reading from /dev/pioN delivers * info on which interrupt(s) have occurred since the last read. You can also * use select() to block until an interrupt occurs (you still need to read() to * consume the interrupt number bytes from the buffer.) */ struct at91_gpio_info { uint32_t output_status; /* Current state of output pins */ uint32_t input_status; /* 1->out 0->in bitmask */ uint32_t highz_status; /* 1->highz 0->driven bitmask */ uint32_t pullup_status; /* 1->floating 0->pullup engaged */ uint32_t glitch_status; /* 0-> no glitch filter 1->gf */ uint32_t enabled_status; /* 1->used for pio 0->other */ uint32_t periph_status; /* 0->A periph 1->B periph */ uint32_t intr_status; /* 1-> ISR enabled, 0->disabled */ uint32_t extra_status[8];/* Extra status info, device depend */ }; struct at91_gpio_cfg { uint32_t cfgmask; /* which things change */ #define AT91_GPIO_CFG_INPUT 0x01 /* configure input/output pins */ #define AT91_GPIO_CFG_HI_Z 0x02 /* HiZ */ #define AT91_GPIO_CFG_PULLUP 0x04 /* Enable/disable pullup resistors */ #define AT91_GPIO_CFG_GLITCH 0x08 /* Glitch filtering */ #define AT91_GPIO_CFG_GPIO 0x10 /* Use pin for PIO or peripheral */ #define AT91_GPIO_CFG_PERIPH 0x20 /* Select which peripheral to use */ #define AT91_GPIO_CFG_INTR 0x40 /* Select pin for interrupts */ uint32_t iomask; /* Mask of bits to change */ uint32_t input; /* or output */ uint32_t hi_z; /* Disable output */ uint32_t pullup; /* Enable pullup resistor */ uint32_t glitch; /* Glitch filtering */ uint32_t gpio; /* Enabled for PIO (1) or periph (0) */ uint32_t periph; /* Select periph A (0) or periph B (1) */ uint32_t intr; /* Enable interrupt (1), or not (0) */ }; struct at91_gpio_bang { uint32_t clockpin; /* clock pin MASK */ uint32_t datapin; /* Data pin MASK */ uint32_t bits; /* bits to clock out (all 32) */ }; struct at91_gpio_bang_many { uint32_t clockpin; /* clock pin MASK */ uint32_t datapin; /* Data pin MASK */ void *bits; /* bits to clock out */ uint32_t numbits; /* Number of bits to clock out */ }; #define AT91_GPIO_SET _IOW('g', 0, uint32_t) /* Turn bits on */ #define AT91_GPIO_CLR _IOW('g', 1, uint32_t) /* Turn bits off */ #define AT91_GPIO_READ _IOR('g', 2, uint32_t) /* Read input bit state */ #define AT91_GPIO_INFO _IOR('g', 3, struct at91_gpio_info) /* State of pio cfg */ #define AT91_GPIO_CFG _IOW('g', 4, struct at91_gpio_cfg) /* Configure pio */ #define AT91_GPIO_BANG _IOW('g', 5, struct at91_gpio_bang) /* bit bang 32 bits */ #define AT91_GPIO_BANG_MANY _IOW('g', 6, struct at91_gpio_bang_many)/* bit bang >32 bits */ #endif /* _ARM_AT91_GPIO_H */ Index: head/sys/arm/include/atags.h =================================================================== --- head/sys/arm/include/atags.h (revision 333141) +++ head/sys/arm/include/atags.h (revision 333142) @@ -1,131 +1,130 @@ /*- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD * * Copyright (c) 2012 M. 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 THE 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 THE 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 __MACHINE_ATAGS_H__ #define __MACHINE_ATAGS_H__ /* * Linux boot ABI compatable ATAG definitions. All these structures * assume tight packing, but since they are all uint32_t's, I've not * bothered to do the usual alignment dance. */ #define LBABI_MAX_COMMAND_LINE 1024 struct arm_lbabi_header { uint32_t size; /* Size of this node, including header */ uint32_t tag; /* Node type */ }; #define ATAG_NONE 0x00000000 /* End of atags list */ #define ATAG_CORE 0x54410001 /* List must start with ATAG_CORE */ #define ATAG_MEM 0x54410002 /* Multiple ATAG_MEM nodes possible */ #define ATAG_VIDEOTEXT 0x54410003 /* Video parameters */ #define ATAG_RAMDISK 0x54410004 /* Describes the ramdisk parameters */ #define ATAG_INITRD 0x54410005 /* Deprecated ramdisk -- used va not pa */ #define ATAG_INITRD2 0x54420005 /* compressed ramdisk image */ #define ATAG_SERIAL 0x54410006 /* 64-bits of serial number */ #define ATAG_REVISION 0x54410007 /* Board revision */ #define ATAG_VIDEOLFB 0x54410008 /* vesafb framebuffer */ #define ATAG_CMDLINE 0x54410009 /* Command line */ /* * ATAG_CORE data */ struct arm_lbabi_core { uint32_t flags; /* bit 0 == read-only */ uint32_t pagesize; uint32_t rootdev; }; /* * ATAG_MEM data -- Can be more than one to describe different * banks. */ struct arm_lbabi_mem32 { uint32_t size; uint32_t start; /* start of physical memory */ }; /* * ATAG_INITRD2 - Compressed ramdisk image details */ struct arm_lbabi_initrd { uint32_t start; /* pa of start */ uint32_t size; /* How big the ram disk is */ }; /* * ATAG_SERIAL - serial number */ struct arm_lbabi_serial_number { uint32_t low; uint32_t high; }; /* * ATAG_REVISION - board revision */ struct arm_lbabi_revision { uint32_t rev; }; /* * ATAG_CMDLINE - Command line from uboot */ struct arm_lbabi_command_line { char command[1]; /* Minimum command length */ }; struct arm_lbabi_tag { struct arm_lbabi_header tag_hdr; union { struct arm_lbabi_core tag_core; struct arm_lbabi_mem32 tag_mem; struct arm_lbabi_initrd tag_initrd; struct arm_lbabi_serial_number tag_sn; struct arm_lbabi_revision tag_rev; struct arm_lbabi_command_line tag_cmd; } u; }; #define ATAG_TAG(a) (a)->tag_hdr.tag #define ATAG_SIZE(a) ((a)->tag_hdr.size * sizeof(uint32_t)) #define ATAG_NEXT(a) (struct arm_lbabi_tag *)((char *)(a) + ATAG_SIZE(a)) #endif /* __MACHINE_ATAGS_H__ */ Index: head/sys/arm/include/board.h =================================================================== --- head/sys/arm/include/board.h (revision 333141) +++ head/sys/arm/include/board.h (revision 333142) @@ -1,64 +1,64 @@ /*- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD * - * Copyright (c) 2012 Warner Losh. All rights reserved. + * Copyright (c) 2012 M. Warner Losh. * * 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_INCLUDE_BOARD_H_ #define _ARM_INCLUDE_BOARD_H_ #include typedef long (arm_board_init_fn)(void); struct arm_board { int board_id; /* Board ID from the boot loader */ const char *board_name; /* Human readable name */ arm_board_init_fn *board_init; /* Board initialize code */ }; #if defined(ARM_MANY_BOARD) #include "board_id.h" #define ARM_BOARD(id, name) \ static struct arm_board this_board = { \ .board_id = ARM_BOARD_ID_ ## id, \ .board_name = name, \ .board_init = board_init, \ }; \ DATA_SET(arm_boards, this_board); #define BOARD_INIT static #else /* !ARM_MANY_BOARD */ #define ARM_BOARD(id, name) extern arm_board_init_fn board_init; #define BOARD_INIT #endif /* ARM_MANY_BOARD */ #endif /* _ARM_INCLUDE_BOARD_H_ */