diff options
Diffstat (limited to 'sys/arm/at91')
-rw-r--r-- | sys/arm/at91/at91_aicreg.h | 51 | ||||
-rw-r--r-- | sys/arm/at91/at91_pio_sam9.h | 291 | ||||
-rw-r--r-- | sys/arm/at91/at91_pit.c | 233 | ||||
-rw-r--r-- | sys/arm/at91/at91_pitreg.h | 45 | ||||
-rw-r--r-- | sys/arm/at91/at91_pmc.c | 57 | ||||
-rw-r--r-- | sys/arm/at91/at91_pmcreg.h | 16 | ||||
-rw-r--r-- | sys/arm/at91/at91sam9.c | 717 | ||||
-rw-r--r-- | sys/arm/at91/at91sam9_machdep.c | 420 | ||||
-rw-r--r-- | sys/arm/at91/at91sam9g20reg.h | 254 | ||||
-rw-r--r-- | sys/arm/at91/board_hl201.c | 42 | ||||
-rw-r--r-- | sys/arm/at91/files.at91sam9 | 27 | ||||
-rw-r--r-- | sys/arm/at91/if_macb.c | 1581 | ||||
-rw-r--r-- | sys/arm/at91/if_macbreg.h | 106 | ||||
-rw-r--r-- | sys/arm/at91/if_macbvar.h | 138 | ||||
-rw-r--r-- | sys/arm/at91/std.at91sam9 | 6 | ||||
-rw-r--r-- | sys/arm/at91/std.hl201 | 11 |
16 files changed, 3992 insertions, 3 deletions
diff --git a/sys/arm/at91/at91_aicreg.h b/sys/arm/at91/at91_aicreg.h new file mode 100644 index 0000000..f46f234 --- /dev/null +++ b/sys/arm/at91/at91_aicreg.h @@ -0,0 +1,51 @@ +/*- + * Copyright (c) 2009 Sylvestre Gallon. 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 ARM_AT91_AT91_AICREG_H +#define ARM_AT91_AT91_AICREG_H + +/* Interrupt Controller */ +#define IC_SMR (0) /* Source mode register */ +#define IC_SVR (128) /* Source vector register */ +#define IC_IVR (256) /* IRQ vector register */ +#define IC_FVR (260) /* FIQ vector register */ +#define IC_ISR (264) /* Interrupt status register */ +#define IC_IPR (268) /* Interrupt pending register */ +#define IC_IMR (272) /* Interrupt status register */ +#define IC_CISR (276) /* Core interrupt status register */ +#define IC_IECR (288) /* Interrupt enable command register */ +#define IC_IDCR (292) /* Interrupt disable command register */ +#define IC_ICCR (296) /* Interrupt clear command register */ +#define IC_ISCR (300) /* Interrupt set command register */ +#define IC_EOICR (304) /* End of interrupt command register */ +#define IC_SPU (308) /* Spurious vector register */ +#define IC_DCR (312) /* Debug control register */ +#define IC_FFER (320) /* Fast forcing enable register */ +#define IC_FFDR (324) /* Fast forcing disable register */ +#define IC_FFSR (328) /* Fast forcing status register */ + +#endif /*ARM_AT91_AT91_AICREG_H*/ diff --git a/sys/arm/at91/at91_pio_sam9.h b/sys/arm/at91/at91_pio_sam9.h new file mode 100644 index 0000000..d3c8f06 --- /dev/null +++ b/sys/arm/at91/at91_pio_sam9.h @@ -0,0 +1,291 @@ +/* + * Theses defines come from an atmel file that says specifically that it + * has no copyright. + */ + +/* $FreeBSD$ */ + +// ***************************************************************************** +// PIO DEFINITIONS FOR AT91SAM9261 +// ***************************************************************************** +#define AT91C_PIO_PA0 ((unsigned int) 1 << 0) // Pin Controlled by PA0 +#define AT91C_PA0_MISO0 ((unsigned int) AT91C_PIO_PA0) // SPI0 Master In Slave +#define AT91C_PA0_MCDA0 ((unsigned int) AT91C_PIO_PA0) // Multimedia Card A Data 0 +#define AT91C_PIO_PA1 ((unsigned int) 1 << 1) // Pin Controlled by PA1 +#define AT91C_PA1_MOSI0 ((unsigned int) AT91C_PIO_PA1) // SPI0 Master Out Slave +#define AT91C_PA1_MCCDA ((unsigned int) AT91C_PIO_PA1) // Multimedia Card A Command +#define AT91C_PIO_PA10 ((unsigned int) 1 << 10) // Pin Controlled by PA10 +#define AT91C_PA10_DTXD ((unsigned int) AT91C_PIO_PA10) // DBGU Debug Transmit Data +#define AT91C_PA10_PCK3 ((unsigned int) AT91C_PIO_PA10) // PMC Programmable clock Output 3 +#define AT91C_PIO_PA11 ((unsigned int) 1 << 11) // Pin Controlled by PA11 +#define AT91C_PA11_TSYNC ((unsigned int) AT91C_PIO_PA11) // Trace Synchronization Signal +#define AT91C_PA11_SCK1 ((unsigned int) AT91C_PIO_PA11) // USART1 Serial Clock +#define AT91C_PIO_PA12 ((unsigned int) 1 << 12) // Pin Controlled by PA12 +#define AT91C_PA12_TCLK ((unsigned int) AT91C_PIO_PA12) // Trace Clock +#define AT91C_PA12_RTS1 ((unsigned int) AT91C_PIO_PA12) // USART1 Ready To Send +#define AT91C_PIO_PA13 ((unsigned int) 1 << 13) // Pin Controlled by PA13 +#define AT91C_PA13_TPS0 ((unsigned int) AT91C_PIO_PA13) // Trace ARM Pipeline Status 0 +#define AT91C_PA13_CTS1 ((unsigned int) AT91C_PIO_PA13) // USART1 Clear To Send +#define AT91C_PIO_PA14 ((unsigned int) 1 << 14) // Pin Controlled by PA14 +#define AT91C_PA14_TPS1 ((unsigned int) AT91C_PIO_PA14) // Trace ARM Pipeline Status 1 +#define AT91C_PA14_SCK2 ((unsigned int) AT91C_PIO_PA14) // USART2 Serial Clock +#define AT91C_PIO_PA15 ((unsigned int) 1 << 15) // Pin Controlled by PA15 +#define AT91C_PA15_TPS2 ((unsigned int) AT91C_PIO_PA15) // Trace ARM Pipeline Status 2 +#define AT91C_PA15_RTS2 ((unsigned int) AT91C_PIO_PA15) // USART2 Ready To Send +#define AT91C_PIO_PA16 ((unsigned int) 1 << 16) // Pin Controlled by PA16 +#define AT91C_PA16_TPK0 ((unsigned int) AT91C_PIO_PA16) // Trace Packet Port 0 +#define AT91C_PA16_CTS2 ((unsigned int) AT91C_PIO_PA16) // USART2 Clear To Send +#define AT91C_PIO_PA17 ((unsigned int) 1 << 17) // Pin Controlled by PA17 +#define AT91C_PA17_TPK1 ((unsigned int) AT91C_PIO_PA17) // Trace Packet Port 1 +#define AT91C_PA17_TF1 ((unsigned int) AT91C_PIO_PA17) // SSC1 Transmit Frame Sync +#define AT91C_PIO_PA18 ((unsigned int) 1 << 18) // Pin Controlled by PA18 +#define AT91C_PA18_TPK2 ((unsigned int) AT91C_PIO_PA18) // Trace Packet Port 2 +#define AT91C_PA18_TK1 ((unsigned int) AT91C_PIO_PA18) // SSC1 Transmit Clock +#define AT91C_PIO_PA19 ((unsigned int) 1 << 19) // Pin Controlled by PA19 +#define AT91C_PA19_TPK3 ((unsigned int) AT91C_PIO_PA19) // Trace Packet Port 3 +#define AT91C_PA19_TD1 ((unsigned int) AT91C_PIO_PA19) // SSC1 Transmit Data +#define AT91C_PIO_PA2 ((unsigned int) 1 << 2) // Pin Controlled by PA2 +#define AT91C_PA2_SPCK0 ((unsigned int) AT91C_PIO_PA2) // SPI0 Serial Clock +#define AT91C_PA2_MCCK ((unsigned int) AT91C_PIO_PA2) // Multimedia Card Clock +#define AT91C_PIO_PA20 ((unsigned int) 1 << 20) // Pin Controlled by PA20 +#define AT91C_PA20_TPK4 ((unsigned int) AT91C_PIO_PA20) // Trace Packet Port 4 +#define AT91C_PA20_RD1 ((unsigned int) AT91C_PIO_PA20) // SSC1 Receive Data +#define AT91C_PIO_PA21 ((unsigned int) 1 << 21) // Pin Controlled by PA21 +#define AT91C_PA21_TPK5 ((unsigned int) AT91C_PIO_PA21) // Trace Packet Port 5 +#define AT91C_PA21_RK1 ((unsigned int) AT91C_PIO_PA21) // SSC1 Receive Clock +#define AT91C_PIO_PA22 ((unsigned int) 1 << 22) // Pin Controlled by PA22 +#define AT91C_PA22_TPK6 ((unsigned int) AT91C_PIO_PA22) // Trace Packet Port 6 +#define AT91C_PA22_RF1 ((unsigned int) AT91C_PIO_PA22) // SSC1 Receive Frame Sync +#define AT91C_PIO_PA23 ((unsigned int) 1 << 23) // Pin Controlled by PA23 +#define AT91C_PA23_TPK7 ((unsigned int) AT91C_PIO_PA23) // Trace Packet Port 7 +#define AT91C_PA23_RTS0 ((unsigned int) AT91C_PIO_PA23) // USART0 Ready To Send +#define AT91C_PIO_PA24 ((unsigned int) 1 << 24) // Pin Controlled by PA24 +#define AT91C_PA24_TPK8 ((unsigned int) AT91C_PIO_PA24) // Trace Packet Port 8 +#define AT91C_PA24_NPCS11 ((unsigned int) AT91C_PIO_PA24) // SPI1 Peripheral Chip Select 1 +#define AT91C_PIO_PA25 ((unsigned int) 1 << 25) // Pin Controlled by PA25 +#define AT91C_PA25_TPK9 ((unsigned int) AT91C_PIO_PA25) // Trace Packet Port 9 +#define AT91C_PA25_NPCS12 ((unsigned int) AT91C_PIO_PA25) // SPI1 Peripheral Chip Select 2 +#define AT91C_PIO_PA26 ((unsigned int) 1 << 26) // Pin Controlled by PA26 +#define AT91C_PA26_TPK10 ((unsigned int) AT91C_PIO_PA26) // Trace Packet Port 10 +#define AT91C_PA26_NPCS13 ((unsigned int) AT91C_PIO_PA26) // SPI1 Peripheral Chip Select 3 +#define AT91C_PIO_PA27 ((unsigned int) 1 << 27) // Pin Controlled by PA27 +#define AT91C_PA27_TPK11 ((unsigned int) AT91C_PIO_PA27) // Trace Packet Port 11 +#define AT91C_PA27_NPCS01 ((unsigned int) AT91C_PIO_PA27) // SPI0 Peripheral Chip Select 1 +#define AT91C_PIO_PA28 ((unsigned int) 1 << 28) // Pin Controlled by PA28 +#define AT91C_PA28_TPK12 ((unsigned int) AT91C_PIO_PA28) // Trace Packet Port 12 +#define AT91C_PA28_NPCS02 ((unsigned int) AT91C_PIO_PA28) // SPI0 Peripheral Chip Select 2 +#define AT91C_PIO_PA29 ((unsigned int) 1 << 29) // Pin Controlled by PA29 +#define AT91C_PA29_TPK13 ((unsigned int) AT91C_PIO_PA29) // Trace Packet Port 13 +#define AT91C_PA29_NPCS03 ((unsigned int) AT91C_PIO_PA29) // SPI0 Peripheral Chip Select 3 +#define AT91C_PIO_PA3 ((unsigned int) 1 << 3) // Pin Controlled by PA3 +#define AT91C_PA3_NPCS00 ((unsigned int) AT91C_PIO_PA3) // SPI0 Peripheral Chip Select 0 +#define AT91C_PIO_PA30 ((unsigned int) 1 << 30) // Pin Controlled by PA30 +#define AT91C_PA30_TPK14 ((unsigned int) AT91C_PIO_PA30) // Trace Packet Port 14 +#define AT91C_PA30_A23 ((unsigned int) AT91C_PIO_PA30) // Address Bus bit 23 +#define AT91C_PIO_PA31 ((unsigned int) 1 << 31) // Pin Controlled by PA31 +#define AT91C_PA31_TPK15 ((unsigned int) AT91C_PIO_PA31) // Trace Packet Port 15 +#define AT91C_PA31_A24 ((unsigned int) AT91C_PIO_PA31) // Address Bus bit 24 +#define AT91C_PIO_PA4 ((unsigned int) 1 << 4) // Pin Controlled by PA4 +#define AT91C_PA4_NPCS01 ((unsigned int) AT91C_PIO_PA4) // SPI0 Peripheral Chip Select 1 +#define AT91C_PA4_MCDA1 ((unsigned int) AT91C_PIO_PA4) // Multimedia Card A Data 1 +#define AT91C_PIO_PA5 ((unsigned int) 1 << 5) // Pin Controlled by PA5 +#define AT91C_PA5_NPCS02 ((unsigned int) AT91C_PIO_PA5) // SPI0 Peripheral Chip Select 2 +#define AT91C_PA5_MCDA2 ((unsigned int) AT91C_PIO_PA5) // Multimedia Card A Data 2 +#define AT91C_PIO_PA6 ((unsigned int) 1 << 6) // Pin Controlled by PA6 +#define AT91C_PA6_NPCS03 ((unsigned int) AT91C_PIO_PA6) // SPI0 Peripheral Chip Select 3 +#define AT91C_PA6_MCDA3 ((unsigned int) AT91C_PIO_PA6) // Multimedia Card A Data 3 +#define AT91C_PIO_PA7 ((unsigned int) 1 << 7) // Pin Controlled by PA7 +#define AT91C_PA7_TWD ((unsigned int) AT91C_PIO_PA7) // TWI Two-wire Serial Data +#define AT91C_PA7_PCK0 ((unsigned int) AT91C_PIO_PA7) // PMC Programmable clock Output 0 +#define AT91C_PIO_PA8 ((unsigned int) 1 << 8) // Pin Controlled by PA8 +#define AT91C_PA8_TWCK ((unsigned int) AT91C_PIO_PA8) // TWI Two-wire Serial Clock +#define AT91C_PA8_PCK1 ((unsigned int) AT91C_PIO_PA8) // PMC Programmable clock Output 1 +#define AT91C_PIO_PA9 ((unsigned int) 1 << 9) // Pin Controlled by PA9 +#define AT91C_PA9_DRXD ((unsigned int) AT91C_PIO_PA9) // DBGU Debug Receive Data +#define AT91C_PA9_PCK2 ((unsigned int) AT91C_PIO_PA9) // PMC Programmable clock Output 2 +#define AT91C_PIO_PB0 ((unsigned int) 1 << 0) // Pin Controlled by PB0 +#define AT91C_PB0_LCDVSYNC ((unsigned int) AT91C_PIO_PB0) // LCD Vertical Synchronization +#define AT91C_PIO_PB1 ((unsigned int) 1 << 1) // Pin Controlled by PB1 +#define AT91C_PB1_LCDHSYNC ((unsigned int) AT91C_PIO_PB1) // LCD Horizontal Synchronization +#define AT91C_PIO_PB10 ((unsigned int) 1 << 10) // Pin Controlled by PB10 +#define AT91C_PB10_LCDD5 ((unsigned int) AT91C_PIO_PB10) // LCD Data Bus Bit 5 +#define AT91C_PB10_LCDD10 ((unsigned int) AT91C_PIO_PB10) // LCD Data Bus Bit 10 +#define AT91C_PIO_PB11 ((unsigned int) 1 << 11) // Pin Controlled by PB11 +#define AT91C_PB11_LCDD6 ((unsigned int) AT91C_PIO_PB11) // LCD Data Bus Bit 6 +#define AT91C_PB11_LCDD11 ((unsigned int) AT91C_PIO_PB11) // LCD Data Bus Bit 11 +#define AT91C_PIO_PB12 ((unsigned int) 1 << 12) // Pin Controlled by PB12 +#define AT91C_PB12_LCDD7 ((unsigned int) AT91C_PIO_PB12) // LCD Data Bus Bit 7 +#define AT91C_PB12_LCDD12 ((unsigned int) AT91C_PIO_PB12) // LCD Data Bus Bit 12 +#define AT91C_PIO_PB13 ((unsigned int) 1 << 13) // Pin Controlled by PB13 +#define AT91C_PB13_LCDD8 ((unsigned int) AT91C_PIO_PB13) // LCD Data Bus Bit 8 +#define AT91C_PB13_LCDD13 ((unsigned int) AT91C_PIO_PB13) // LCD Data Bus Bit 13 +#define AT91C_PIO_PB14 ((unsigned int) 1 << 14) // Pin Controlled by PB14 +#define AT91C_PB14_LCDD9 ((unsigned int) AT91C_PIO_PB14) // LCD Data Bus Bit 9 +#define AT91C_PB14_LCDD14 ((unsigned int) AT91C_PIO_PB14) // LCD Data Bus Bit 14 +#define AT91C_PIO_PB15 ((unsigned int) 1 << 15) // Pin Controlled by PB15 +#define AT91C_PB15_LCDD10 ((unsigned int) AT91C_PIO_PB15) // LCD Data Bus Bit 10 +#define AT91C_PB15_LCDD15 ((unsigned int) AT91C_PIO_PB15) // LCD Data Bus Bit 15 +#define AT91C_PIO_PB16 ((unsigned int) 1 << 16) // Pin Controlled by PB16 +#define AT91C_PB16_LCDD11 ((unsigned int) AT91C_PIO_PB16) // LCD Data Bus Bit 11 +#define AT91C_PB16_LCDD19 ((unsigned int) AT91C_PIO_PB16) // LCD Data Bus Bit 19 +#define AT91C_PIO_PB17 ((unsigned int) 1 << 17) // Pin Controlled by PB17 +#define AT91C_PB17_LCDD12 ((unsigned int) AT91C_PIO_PB17) // LCD Data Bus Bit 12 +#define AT91C_PB17_LCDD20 ((unsigned int) AT91C_PIO_PB17) // LCD Data Bus Bit 20 +#define AT91C_PIO_PB18 ((unsigned int) 1 << 18) // Pin Controlled by PB18 +#define AT91C_PB18_LCDD13 ((unsigned int) AT91C_PIO_PB18) // LCD Data Bus Bit 13 +#define AT91C_PB18_LCDD21 ((unsigned int) AT91C_PIO_PB18) // LCD Data Bus Bit 21 +#define AT91C_PIO_PB19 ((unsigned int) 1 << 19) // Pin Controlled by PB19 +#define AT91C_PB19_LCDD14 ((unsigned int) AT91C_PIO_PB19) // LCD Data Bus Bit 14 +#define AT91C_PB19_LCDD22 ((unsigned int) AT91C_PIO_PB19) // LCD Data Bus Bit 22 +#define AT91C_PIO_PB2 ((unsigned int) 1 << 2) // Pin Controlled by PB2 +#define AT91C_PB2_LCDDOTCK ((unsigned int) AT91C_PIO_PB2) // LCD Dot Clock +#define AT91C_PB2_PCK0 ((unsigned int) AT91C_PIO_PB2) // PMC Programmable clock Output 0 +#define AT91C_PIO_PB20 ((unsigned int) 1 << 20) // Pin Controlled by PB20 +#define AT91C_PB20_LCDD15 ((unsigned int) AT91C_PIO_PB20) // LCD Data Bus Bit 15 +#define AT91C_PB20_LCDD23 ((unsigned int) AT91C_PIO_PB20) // LCD Data Bus Bit 23 +#define AT91C_PIO_PB21 ((unsigned int) 1 << 21) // Pin Controlled by PB21 +#define AT91C_PB21_TF0 ((unsigned int) AT91C_PIO_PB21) // SSC0 Transmit Frame Sync +#define AT91C_PB21_LCDD16 ((unsigned int) AT91C_PIO_PB21) // LCD Data Bus Bit 16 +#define AT91C_PIO_PB22 ((unsigned int) 1 << 22) // Pin Controlled by PB22 +#define AT91C_PB22_TK0 ((unsigned int) AT91C_PIO_PB22) // SSC0 Transmit Clock +#define AT91C_PB22_LCDD17 ((unsigned int) AT91C_PIO_PB22) // LCD Data Bus Bit 17 +#define AT91C_PIO_PB23 ((unsigned int) 1 << 23) // Pin Controlled by PB23 +#define AT91C_PB23_TD0 ((unsigned int) AT91C_PIO_PB23) // SSC0 Transmit Data +#define AT91C_PB23_LCDD18 ((unsigned int) AT91C_PIO_PB23) // LCD Data Bus Bit 18 +#define AT91C_PIO_PB24 ((unsigned int) 1 << 24) // Pin Controlled by PB24 +#define AT91C_PB24_RD0 ((unsigned int) AT91C_PIO_PB24) // SSC0 Receive Data +#define AT91C_PB24_LCDD19 ((unsigned int) AT91C_PIO_PB24) // LCD Data Bus Bit 19 +#define AT91C_PIO_PB25 ((unsigned int) 1 << 25) // Pin Controlled by PB25 +#define AT91C_PB25_RK0 ((unsigned int) AT91C_PIO_PB25) // SSC0 Receive Clock +#define AT91C_PB25_LCDD20 ((unsigned int) AT91C_PIO_PB25) // LCD Data Bus Bit 20 +#define AT91C_PIO_PB26 ((unsigned int) 1 << 26) // Pin Controlled by PB26 +#define AT91C_PB26_RF0 ((unsigned int) AT91C_PIO_PB26) // SSC0 Receive Frame Sync +#define AT91C_PB26_LCDD21 ((unsigned int) AT91C_PIO_PB26) // LCD Data Bus Bit 21 +#define AT91C_PIO_PB27 ((unsigned int) 1 << 27) // Pin Controlled by PB27 +#define AT91C_PB27_NPCS11 ((unsigned int) AT91C_PIO_PB27) // SPI1 Peripheral Chip Select 1 +#define AT91C_PB27_LCDD22 ((unsigned int) AT91C_PIO_PB27) // LCD Data Bus Bit 22 +#define AT91C_PIO_PB28 ((unsigned int) 1 << 28) // Pin Controlled by PB28 +#define AT91C_PB28_NPCS10 ((unsigned int) AT91C_PIO_PB28) // SPI1 Peripheral Chip Select 0 +#define AT91C_PB28_LCDD23 ((unsigned int) AT91C_PIO_PB28) // LCD Data Bus Bit 23 +#define AT91C_PIO_PB29 ((unsigned int) 1 << 29) // Pin Controlled by PB29 +#define AT91C_PB29_SPCK1 ((unsigned int) AT91C_PIO_PB29) // SPI1 Serial Clock +#define AT91C_PB29_IRQ2 ((unsigned int) AT91C_PIO_PB29) // Interrupt input 2 +#define AT91C_PIO_PB3 ((unsigned int) 1 << 3) // Pin Controlled by PB3 +#define AT91C_PB3_LCDDEN ((unsigned int) AT91C_PIO_PB3) // LCD Data Enable +#define AT91C_PIO_PB30 ((unsigned int) 1 << 30) // Pin Controlled by PB30 +#define AT91C_PB30_MISO1 ((unsigned int) AT91C_PIO_PB30) // SPI1 Master In Slave +#define AT91C_PB30_IRQ1 ((unsigned int) AT91C_PIO_PB30) // Interrupt input 1 +#define AT91C_PIO_PB31 ((unsigned int) 1 << 31) // Pin Controlled by PB31 +#define AT91C_PB31_MOSI1 ((unsigned int) AT91C_PIO_PB31) // SPI1 Master Out Slave +#define AT91C_PB31_PCK2 ((unsigned int) AT91C_PIO_PB31) // PMC Programmable clock Output 2 +#define AT91C_PIO_PB4 ((unsigned int) 1 << 4) // Pin Controlled by PB4 +#define AT91C_PB4_LCDCC ((unsigned int) AT91C_PIO_PB4) // LCD Contrast Control +#define AT91C_PB4_LCDD2 ((unsigned int) AT91C_PIO_PB4) // LCD Data Bus Bit 2 +#define AT91C_PIO_PB5 ((unsigned int) 1 << 5) // Pin Controlled by PB5 +#define AT91C_PB5_LCDD0 ((unsigned int) AT91C_PIO_PB5) // LCD Data Bus Bit 0 +#define AT91C_PB5_LCDD3 ((unsigned int) AT91C_PIO_PB5) // LCD Data Bus Bit 3 +#define AT91C_PIO_PB6 ((unsigned int) 1 << 6) // Pin Controlled by PB6 +#define AT91C_PB6_LCDD1 ((unsigned int) AT91C_PIO_PB6) // LCD Data Bus Bit 1 +#define AT91C_PB6_LCDD4 ((unsigned int) AT91C_PIO_PB6) // LCD Data Bus Bit 4 +#define AT91C_PIO_PB7 ((unsigned int) 1 << 7) // Pin Controlled by PB7 +#define AT91C_PB7_LCDD2 ((unsigned int) AT91C_PIO_PB7) // LCD Data Bus Bit 2 +#define AT91C_PB7_LCDD5 ((unsigned int) AT91C_PIO_PB7) // LCD Data Bus Bit 5 +#define AT91C_PIO_PB8 ((unsigned int) 1 << 8) // Pin Controlled by PB8 +#define AT91C_PB8_LCDD3 ((unsigned int) AT91C_PIO_PB8) // LCD Data Bus Bit 3 +#define AT91C_PB8_LCDD6 ((unsigned int) AT91C_PIO_PB8) // LCD Data Bus Bit 6 +#define AT91C_PIO_PB9 ((unsigned int) 1 << 9) // Pin Controlled by PB9 +#define AT91C_PB9_LCDD4 ((unsigned int) AT91C_PIO_PB9) // LCD Data Bus Bit 4 +#define AT91C_PB9_LCDD7 ((unsigned int) AT91C_PIO_PB9) // LCD Data Bus Bit 7 +#define AT91C_PIO_PC0 ((unsigned int) 1 << 0) // Pin Controlled by PC0 +#define AT91C_PC0_SMOE ((unsigned int) AT91C_PIO_PC0) // SmartMedia Output Enable +#define AT91C_PC0_NCS6 ((unsigned int) AT91C_PIO_PC0) // Chip Select 6 +#define AT91C_PIO_PC1 ((unsigned int) 1 << 1) // Pin Controlled by PC1 +#define AT91C_PC1_SMWE ((unsigned int) AT91C_PIO_PC1) // SmartMedia Write Enable +#define AT91C_PC1_NCS7 ((unsigned int) AT91C_PIO_PC1) // Chip Select 7 +#define AT91C_PIO_PC10 ((unsigned int) 1 << 10) // Pin Controlled by PC10 +#define AT91C_PC10_RTS0 ((unsigned int) AT91C_PIO_PC10) // USART0 Ready To Send +#define AT91C_PC10_SCK0 ((unsigned int) AT91C_PIO_PC10) // USART0 Serial Clock +#define AT91C_PIO_PC11 ((unsigned int) 1 << 11) // Pin Controlled by PC11 +#define AT91C_PC11_CTS0 ((unsigned int) AT91C_PIO_PC11) // USART0 Clear To Send +#define AT91C_PC11_FIQ ((unsigned int) AT91C_PIO_PC11) // AIC Fast Interrupt Input +#define AT91C_PIO_PC12 ((unsigned int) 1 << 12) // Pin Controlled by PC12 +#define AT91C_PC12_TXD1 ((unsigned int) AT91C_PIO_PC12) // USART1 Transmit Data +#define AT91C_PC12_NCS6 ((unsigned int) AT91C_PIO_PC12) // Chip Select 6 +#define AT91C_PIO_PC13 ((unsigned int) 1 << 13) // Pin Controlled by PC13 +#define AT91C_PC13_RXD1 ((unsigned int) AT91C_PIO_PC13) // USART1 Receive Data +#define AT91C_PC13_NCS7 ((unsigned int) AT91C_PIO_PC13) // Chip Select 7 +#define AT91C_PIO_PC14 ((unsigned int) 1 << 14) // Pin Controlled by PC14 +#define AT91C_PC14_TXD2 ((unsigned int) AT91C_PIO_PC14) // USART2 Transmit Data +#define AT91C_PC14_NPCS12 ((unsigned int) AT91C_PIO_PC14) // SPI1 Peripheral Chip Select 2 +#define AT91C_PIO_PC15 ((unsigned int) 1 << 15) // Pin Controlled by PC15 +#define AT91C_PC15_RXD2 ((unsigned int) AT91C_PIO_PC15) // USART2 Receive Data +#define AT91C_PC15_NPCS13 ((unsigned int) AT91C_PIO_PC15) // SPI1 Peripheral Chip Select 3 +#define AT91C_PIO_PC16 ((unsigned int) 1 << 16) // Pin Controlled by PC16 +#define AT91C_PC16_D16 ((unsigned int) AT91C_PIO_PC16) // Data Bus [16] +#define AT91C_PC16_TCLK0 ((unsigned int) AT91C_PIO_PC16) // Timer Counter 0 external clock input +#define AT91C_PIO_PC17 ((unsigned int) 1 << 17) // Pin Controlled by PC17 +#define AT91C_PC17_D17 ((unsigned int) AT91C_PIO_PC17) // Data Bus [17] +#define AT91C_PC17_TCLK1 ((unsigned int) AT91C_PIO_PC17) // Timer Counter 1 external clock input +#define AT91C_PIO_PC18 ((unsigned int) 1 << 18) // Pin Controlled by PC18 +#define AT91C_PC18_D18 ((unsigned int) AT91C_PIO_PC18) // Data Bus [18] +#define AT91C_PC18_TCLK2 ((unsigned int) AT91C_PIO_PC18) // Timer Counter 2 external clock input +#define AT91C_PIO_PC19 ((unsigned int) 1 << 19) // Pin Controlled by PC19 +#define AT91C_PC19_D19 ((unsigned int) AT91C_PIO_PC19) // Data Bus [19] +#define AT91C_PC19_TIOA0 ((unsigned int) AT91C_PIO_PC19) // Timer Counter 0 Multipurpose Timer I/O Pin A +#define AT91C_PIO_PC2 ((unsigned int) 1 << 2) // Pin Controlled by PC2 +#define AT91C_PC2_NWAIT ((unsigned int) AT91C_PIO_PC2) // NWAIT +#define AT91C_PC2_IRQ0 ((unsigned int) AT91C_PIO_PC2) // Interrupt input 0 +#define AT91C_PIO_PC20 ((unsigned int) 1 << 20) // Pin Controlled by PC20 +#define AT91C_PC20_D20 ((unsigned int) AT91C_PIO_PC20) // Data Bus [20] +#define AT91C_PC20_TIOB0 ((unsigned int) AT91C_PIO_PC20) // Timer Counter 0 Multipurpose Timer I/O Pin B +#define AT91C_PIO_PC21 ((unsigned int) 1 << 21) // Pin Controlled by PC21 +#define AT91C_PC21_D21 ((unsigned int) AT91C_PIO_PC21) // Data Bus [21] +#define AT91C_PC21_TIOA1 ((unsigned int) AT91C_PIO_PC21) // Timer Counter 1 Multipurpose Timer I/O Pin A +#define AT91C_PIO_PC22 ((unsigned int) 1 << 22) // Pin Controlled by PC22 +#define AT91C_PC22_D22 ((unsigned int) AT91C_PIO_PC22) // Data Bus [22] +#define AT91C_PC22_TIOB1 ((unsigned int) AT91C_PIO_PC22) // Timer Counter 1 Multipurpose Timer I/O Pin B +#define AT91C_PIO_PC23 ((unsigned int) 1 << 23) // Pin Controlled by PC23 +#define AT91C_PC23_D23 ((unsigned int) AT91C_PIO_PC23) // Data Bus [23] +#define AT91C_PC23_TIOA2 ((unsigned int) AT91C_PIO_PC23) // Timer Counter 2 Multipurpose Timer I/O Pin A +#define AT91C_PIO_PC24 ((unsigned int) 1 << 24) // Pin Controlled by PC24 +#define AT91C_PC24_D24 ((unsigned int) AT91C_PIO_PC24) // Data Bus [24] +#define AT91C_PC24_TIOB2 ((unsigned int) AT91C_PIO_PC24) // Timer Counter 2 Multipurpose Timer I/O Pin B +#define AT91C_PIO_PC25 ((unsigned int) 1 << 25) // Pin Controlled by PC25 +#define AT91C_PC25_D25 ((unsigned int) AT91C_PIO_PC25) // Data Bus [25] +#define AT91C_PC25_TF2 ((unsigned int) AT91C_PIO_PC25) // SSC2 Transmit Frame Sync +#define AT91C_PIO_PC26 ((unsigned int) 1 << 26) // Pin Controlled by PC26 +#define AT91C_PC26_D26 ((unsigned int) AT91C_PIO_PC26) // Data Bus [26] +#define AT91C_PC26_TK2 ((unsigned int) AT91C_PIO_PC26) // SSC2 Transmit Clock +#define AT91C_PIO_PC27 ((unsigned int) 1 << 27) // Pin Controlled by PC27 +#define AT91C_PC27_D27 ((unsigned int) AT91C_PIO_PC27) // Data Bus [27] +#define AT91C_PC27_TD2 ((unsigned int) AT91C_PIO_PC27) // SSC2 Transmit Data +#define AT91C_PIO_PC28 ((unsigned int) 1 << 28) // Pin Controlled by PC28 +#define AT91C_PC28_D28 ((unsigned int) AT91C_PIO_PC28) // Data Bus [28] +#define AT91C_PC28_RD2 ((unsigned int) AT91C_PIO_PC28) // SSC2 Receive Data +#define AT91C_PIO_PC29 ((unsigned int) 1 << 29) // Pin Controlled by PC29 +#define AT91C_PC29_D29 ((unsigned int) AT91C_PIO_PC29) // Data Bus [29] +#define AT91C_PC29_RK2 ((unsigned int) AT91C_PIO_PC29) // SSC2 Receive Clock +#define AT91C_PIO_PC3 ((unsigned int) 1 << 3) // Pin Controlled by PC3 +#define AT91C_PC3_A25_CFRNW ((unsigned int) AT91C_PIO_PC3) // Address Bus[25] / Compact Flash Read Not Write +#define AT91C_PIO_PC30 ((unsigned int) 1 << 30) // Pin Controlled by PC30 +#define AT91C_PC30_D30 ((unsigned int) AT91C_PIO_PC30) // Data Bus [30] +#define AT91C_PC30_RF2 ((unsigned int) AT91C_PIO_PC30) // SSC2 Receive Frame Sync +#define AT91C_PIO_PC31 ((unsigned int) 1 << 31) // Pin Controlled by PC31 +#define AT91C_PC31_D31 ((unsigned int) AT91C_PIO_PC31) // Data Bus [31] +#define AT91C_PC31_PCK1 ((unsigned int) AT91C_PIO_PC31) // PMC Programmable clock Output 1 +#define AT91C_PIO_PC4 ((unsigned int) 1 << 4) // Pin Controlled by PC4 +#define AT91C_PC4_NCS4_CFCS0 ((unsigned int) AT91C_PIO_PC4) // Chip Select 4 / CompactFlash Chip Select 0 +#define AT91C_PIO_PC5 ((unsigned int) 1 << 5) // Pin Controlled by PC5 +#define AT91C_PC5_NCS5_CFCS1 ((unsigned int) AT91C_PIO_PC5) // Chip Select 5 / CompactFlash Chip Select 1 +#define AT91C_PIO_PC6 ((unsigned int) 1 << 6) // Pin Controlled by PC6 +#define AT91C_PC6_CFCE1 ((unsigned int) AT91C_PIO_PC6) // CompactFlash Chip Enable 1 +#define AT91C_PIO_PC7 ((unsigned int) 1 << 7) // Pin Controlled by PC7 +#define AT91C_PC7_CFCE2 ((unsigned int) AT91C_PIO_PC7) // CompactFlash Chip Enable 2 +#define AT91C_PIO_PC8 ((unsigned int) 1 << 8) // Pin Controlled by PC8 +#define AT91C_PC8_TXD0 ((unsigned int) AT91C_PIO_PC8) // USART0 Transmit Data +#define AT91C_PC8_PCK2 ((unsigned int) AT91C_PIO_PC8) // PMC Programmable clock Output 2 +#define AT91C_PIO_PC9 ((unsigned int) 1 << 9) // Pin Controlled by PC9 +#define AT91C_PC9_RXD0 ((unsigned int) AT91C_PIO_PC9) // USART0 Receive Data +#define AT91C_PC9_PCK3 ((unsigned int) AT91C_PIO_PC9) // PMC Programmable clock Output 3 + + diff --git a/sys/arm/at91/at91_pit.c b/sys/arm/at91/at91_pit.c new file mode 100644 index 0000000..516b4d4 --- /dev/null +++ b/sys/arm/at91/at91_pit.c @@ -0,0 +1,233 @@ +/*- + * Copyright (c) 2010 Yohanes Nugroho. 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 <sys/cdefs.h> + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/kernel.h> +#include <sys/module.h> +#include <sys/time.h> +#include <sys/bus.h> +#include <sys/resource.h> +#include <sys/timetc.h> +#include <sys/watchdog.h> + +#include <machine/bus.h> +#include <machine/cpu.h> +#include <machine/cpufunc.h> +#include <machine/resource.h> +#include <machine/frame.h> +#include <machine/intr.h> + +#include <arm/at91/at91var.h> +#include <arm/at91/at91_pitreg.h> +#include <arm/at91/at91_pmcvar.h> +#include <arm/at91/at91sam9g20reg.h> + +__FBSDID("$FreeBSD$"); + +static struct at91pit_softc { + bus_space_tag_t sc_st; + bus_space_handle_t sc_sh; + device_t sc_dev; +} *pit_softc; + +#define RD4(off) \ + bus_space_read_4(pit_softc->sc_st, pit_softc->sc_sh, (off)) +#define WR4(off, val) \ + bus_space_write_4(pit_softc->sc_st, pit_softc->sc_sh, (off), (val)) + +static unsigned at91pit_get_timecount(struct timecounter *tc); +static int clock_intr(void *arg); + +static struct timecounter at91pit_timecounter = { + at91pit_get_timecount, /* get_timecount */ + NULL, /* no poll_pps */ + 0xffffffffu, /* counter mask */ + 0, /* frequency */ + "AT91SAM9261 timer", /* name */ + 1000 /* quality */ +}; + + +uint32_t +at91_pit_base(void); + +uint32_t +at91_pit_size(void); + +static int +at91pit_probe(device_t dev) +{ + device_set_desc(dev, "PIT"); + return (0); +} + +uint32_t +at91_pit_base(void) +{ + return (AT91SAM9G20_PIT_BASE); +} + +uint32_t +at91_pit_size(void) +{ + return (AT91SAM9G20_PIT_SIZE); +} + +static int pit_rate; +static int pit_cycle; +static int pit_counter; + +static int +at91pit_attach(device_t dev) +{ + struct at91_softc *sc = device_get_softc(device_get_parent(dev)); + struct resource *irq; + int rid = 0; + void *ih; + + pit_softc = device_get_softc(dev); + pit_softc->sc_st = sc->sc_st; + pit_softc->sc_dev = dev; + if (bus_space_subregion(sc->sc_st, sc->sc_sh, at91_pit_base(), + at91_pit_size(), &pit_softc->sc_sh) != 0) + panic("couldn't subregion pit registers"); + + irq = bus_alloc_resource(dev, SYS_RES_IRQ, &rid, 1, 1, 1, + RF_ACTIVE | RF_SHAREABLE); + if (!irq) + panic("Unable to allocate IRQ for the system timer"); + else + bus_setup_intr(dev, irq, INTR_TYPE_CLK, + clock_intr, NULL, NULL, &ih); + + + device_printf(dev, "AT91SAM9x pit registered\n"); + return (0); +} + +static device_method_t at91pit_methods[] = { + DEVMETHOD(device_probe, at91pit_probe), + DEVMETHOD(device_attach, at91pit_attach), + {0,0}, +}; + +static driver_t at91pit_driver = { + "at91_pit", + at91pit_methods, + sizeof(struct at91pit_softc), +}; + +static devclass_t at91pit_devclass; + +DRIVER_MODULE(at91_pit, atmelarm, at91pit_driver, at91pit_devclass, 0, 0); + +static int +clock_intr(void *arg) +{ + + struct trapframe *fp = arg; + + if (RD4(PIT_SR) & PIT_PITS_DONE) { + uint32_t pivr = RD4(PIT_PIVR); + if (PIT_CNT(pivr)>1) { + printf("cnt = %d\n", PIT_CNT(pivr)); + } + pit_counter += pit_cycle; + hardclock(TRAPF_USERMODE(fp), TRAPF_PC(fp)); + return (FILTER_HANDLED); + } + return (FILTER_STRAY); +} + +static unsigned +at91pit_get_timecount(struct timecounter *tc) +{ + return pit_counter; +} + +/*todo: review this*/ +void +DELAY(int n) +{ + u_int32_t start, end, cur; + + start = RD4(PIT_PIIR); + n = (n * 1000) / (at91_master_clock / 12); + if (n <= 0) + n = 1; + end = (start + n); + cur = start; + if (start > end) { + while (cur >= start || cur < end) + cur = RD4(PIT_PIIR); + } else { + while (cur < end) + cur = RD4(PIT_PIIR); + } +} + +/* + * The 3 next functions must be implement with the futur PLL code. + */ +void +cpu_startprofclock(void) +{ +} + +void +cpu_stopprofclock(void) +{ +} + +#define HZ 100 + +void +cpu_initclocks(void) +{ + struct at91_pmc_clock *master; + + master = at91_pmc_clock_ref("mck"); + pit_rate = master->hz / 16; + pit_cycle = (pit_rate + HZ/2) / HZ; + at91pit_timecounter.tc_frequency = pit_rate; + WR4(PIT_MR, 0); + + while (PIT_PIV(RD4(PIT_PIVR)) != 0); + + WR4(PIT_MR, (pit_cycle - 1) | PIT_IEN | PIT_EN); + tc_init(&at91pit_timecounter); +} + +void +cpu_reset(void) +{ + *(volatile int *)(AT91SAM9G20_BASE + AT91SAM9G20_RSTC_BASE + + RSTC_CR) = RSTC_PROCRST | RSTC_PERRST | RSTC_KEY; + while (1) + continue; +} diff --git a/sys/arm/at91/at91_pitreg.h b/sys/arm/at91/at91_pitreg.h new file mode 100644 index 0000000..333271e --- /dev/null +++ b/sys/arm/at91/at91_pitreg.h @@ -0,0 +1,45 @@ +/*- + * Copyright (c) 2009 Sylvestre Gallon. 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_AT91PITREG_H +#define ARM_AT91_AT91PITREG_H + +#define PIT_MR 0x0 +#define PIT_SR 0x4 +#define PIT_PIVR 0x8 +#define PIT_PIIR 0xc + +/* PIT_MR */ +#define PIT_PIV(x) (x & 0xfffff) /* periodic interval value */ +#define PIT_CNT(x) ((x >>20) & 0xfff) /* periodic interval counter */ +#define PIT_EN (1 << 24) /* pit enable */ +#define PIT_IEN (1 << 25) /* pit interrupt enable */ + +/* PIT_SR */ +#define PIT_PITS_DONE 1 /* interrupt done */ + +#endif /* ARM_AT91_AT91PITREG_H */ diff --git a/sys/arm/at91/at91_pmc.c b/sys/arm/at91/at91_pmc.c index f4784fa..78d33a0 100644 --- a/sys/arm/at91/at91_pmc.c +++ b/sys/arm/at91/at91_pmc.c @@ -45,6 +45,7 @@ __FBSDID("$FreeBSD$"); #include <machine/frame.h> #include <machine/intr.h> #include <arm/at91/at91rm92reg.h> +#include <arm/at91/at91sam9g20reg.h> #include <arm/at91/at91_pmcreg.h> #include <arm/at91/at91_pmcvar.h> @@ -119,20 +120,54 @@ static struct at91_pmc_clock mck = { .refcnt = 0, }; +#ifdef AT91SAM9G20 +#define IRQ_UDP AT91SAM9G20_IRQ_UDP +#define IRQ_UHP AT91SAM9G20_IRQ_UHP +#else +#define IRQ_UDP AT91RM92_IRQ_UDP +#define IRQ_UHP AT91RM92_IRQ_UHP +#endif /* AT91SAM9G20 */ + static struct at91_pmc_clock udc_clk = { .name = "udc_clk", .parent = &mck, - .pmc_mask = 1 << AT91RM92_IRQ_UDP, + .pmc_mask = 1 << IRQ_UDP, .set_mode = &at91_pmc_set_periph_mode }; static struct at91_pmc_clock ohci_clk = { .name = "ohci_clk", .parent = &mck, - .pmc_mask = 1 << AT91RM92_IRQ_UHP, + .pmc_mask = 1 << IRQ_UHP, + .set_mode = &at91_pmc_set_periph_mode +}; + +#ifdef AT91SAM9G20 +static struct at91_pmc_clock macb_clk = { + .name = "macb_clk", + .parent = &mck, + + .pmc_mask = 1 << 21, + .set_mode = &at91_pmc_set_periph_mode +}; + +static struct at91_pmc_clock spi0_clk = { + .name = "spi0_clk", + .parent = &mck, + + .pmc_mask = 1 << 12, + .set_mode = &at91_pmc_set_periph_mode +}; + +static struct at91_pmc_clock spi1_clk = { + .name = "spi1_clk", + .parent = &mck, + .pmc_mask = 1 << 13, .set_mode = &at91_pmc_set_periph_mode }; +#endif /* AT91SAM9G20 */ + static struct at91_pmc_clock *const clock_list[] = { &slck, &main_ck, @@ -142,6 +177,11 @@ static struct at91_pmc_clock *const clock_list[] = { &uhpck, &mck, &udc_clk, +#ifdef AT91SAM9G20 + &macb_clk, + &spi0_clk, + &spi1_clk, +#endif /* AT91SAM9G20 */ &ohci_clk }; @@ -257,15 +297,24 @@ at91_pmc_pll_rate(int freq, uint32_t reg, int is_pllb) uint32_t mul, div; div = reg & 0xff; +#ifdef AT91SAM9G20 + if (is_pllb) + mul = (reg >> 16) & 0x3f; + else + mul = (reg >> 16) & 0xff; +#else mul = (reg >> 16) & 0x7ff; +#endif if (div != 0 && mul != 0) { freq /= div; freq *= mul + 1; } else { freq = 0; } +#ifndef AT91SAM9G20 if (is_pllb && (reg & (1 << 28))) freq >>= 1; +#endif return (freq); } @@ -328,10 +377,12 @@ at91_pmc_init_clock(struct at91_pmc_softc *sc, unsigned int main_clock) */ sc->pllb_init = at91_pmc_pll_calc(main_clock, 48000000 * 2) |0x10000000; pllb.hz = at91_pmc_pll_rate(main_clock, sc->pllb_init, 1); - WR4(sc, PMC_PCDR, (1 << AT91RM92_IRQ_UHP) | (1 << AT91RM92_IRQ_UDP)); + WR4(sc, PMC_PCDR, (1 << IRQ_UHP) | (1 << IRQ_UDP)); WR4(sc, PMC_SCDR, PMC_SCER_UHP | PMC_SCER_UDP); WR4(sc, CKGR_PLLBR, 0); +#ifndef AT91SAM9G20 WR4(sc, PMC_SCER, PMC_SCER_MCKUDP); +#endif /* * MCK and PCU derive from one of the primary clocks. Initialize diff --git a/sys/arm/at91/at91_pmcreg.h b/sys/arm/at91/at91_pmcreg.h index dd1ca40..54de9f4 100644 --- a/sys/arm/at91/at91_pmcreg.h +++ b/sys/arm/at91/at91_pmcreg.h @@ -58,6 +58,21 @@ #define PMC_SR 0x68 /* Status Register */ #define PMC_IMR 0x6c /* Interrupt Mask Register */ +#ifdef AT91SAM9G20 +/* PMC Specific AT91SAM9G20 */ + +/* PMC System Clock Enable Register */ +/* PMC System Clock Disable Register */ +/* PMC System Clock StatusRegister */ +#define PMC_SCER_UHP (1UL << 6) /* UHP: USB Host Port Clock Enable */ +#define PMC_SCER_UDP (1UL << 7) /* UDP: USB Device 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 */ + +#else + /* PMC System Clock Enable Register */ /* PMC System Clock Disable Register */ /* PMC System Clock StatusRegister */ @@ -70,6 +85,7 @@ #define PMC_SCER_PCK2 (1UL << 11) /* PCK2: Programmable Clock out en */ #define PMC_SCER_PCK3 (1UL << 12) /* PCK3: Programmable Clock out en */ +#endif /* AT91SAM9G20 */ /* PMC Peripheral Clock Enable Register */ /* PMC Peripheral Clock Disable Register */ /* PMC Peripheral Clock Status Register */ diff --git a/sys/arm/at91/at91sam9.c b/sys/arm/at91/at91sam9.c new file mode 100644 index 0000000..a6510ea --- /dev/null +++ b/sys/arm/at91/at91sam9.c @@ -0,0 +1,717 @@ +/*- + * Copyright (c) 2005 Olivier Houchard. 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 <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/bus.h> +#include <sys/kernel.h> +#include <sys/malloc.h> +#include <sys/module.h> + +#include <vm/vm.h> +#include <vm/vm_kern.h> +#include <vm/pmap.h> +#include <vm/vm_page.h> +#include <vm/vm_extern.h> + +#define _ARM32_BUS_DMA_PRIVATE +#include <machine/bus.h> +#include <machine/intr.h> +#include <arm/at91/at91_aicreg.h> +#include <arm/at91/at91sam9g20reg.h> +#include <arm/at91/at91var.h> + +static struct at91_softc *at91_softc; + +static void at91_eoi(void *); + +uint32_t at91_master_clock = AT91C_MASTER_CLOCK; + +static int +at91_bs_map(void *t, bus_addr_t bpa, bus_size_t size, int flags, + bus_space_handle_t *bshp) +{ + vm_paddr_t pa, endpa; + + pa = trunc_page(bpa); + if (pa >= 0xfff00000) { + *bshp = pa - 0xf0000000 + 0xd0000000; + return (0); + } + if (pa >= 0xdff00000) + return (0); + endpa = round_page(bpa + size); + + *bshp = (vm_offset_t)pmap_mapdev(pa, endpa - pa); + + return (0); +} + +static void +at91_bs_unmap(void *t, bus_space_handle_t h, bus_size_t size) +{ + vm_offset_t va, endva; + + va = trunc_page((vm_offset_t)t); + endva = va + round_page(size); + + /* Free the kernel virtual mapping. */ + kmem_free(kernel_map, va, endva - va); +} + +static int +at91_bs_subregion(void *t, bus_space_handle_t bsh, bus_size_t offset, + bus_size_t size, bus_space_handle_t *nbshp) +{ + + *nbshp = bsh + offset; + return (0); +} + +static void +at91_barrier(void *t, bus_space_handle_t bsh, bus_size_t size, bus_size_t b, + int a) +{ +} + +bs_protos(generic); +bs_protos(generic_armv4); + +struct bus_space at91_bs_tag = { + /* cookie */ + (void *) 0, + + /* mapping/unmapping */ + at91_bs_map, + at91_bs_unmap, + at91_bs_subregion, + + /* allocation/deallocation */ + NULL, + NULL, + + /* barrier */ + at91_barrier, + + /* read (single) */ + generic_bs_r_1, + generic_armv4_bs_r_2, + generic_bs_r_4, + NULL, + + /* read multiple */ + generic_bs_rm_1, + generic_armv4_bs_rm_2, + generic_bs_rm_4, + NULL, + + /* read region */ + generic_bs_rr_1, + generic_armv4_bs_rr_2, + generic_bs_rr_4, + NULL, + + /* write (single) */ + generic_bs_w_1, + generic_armv4_bs_w_2, + generic_bs_w_4, + NULL, + + /* write multiple */ + generic_bs_wm_1, + generic_armv4_bs_wm_2, + generic_bs_wm_4, + NULL, + + /* write region */ + NULL, + generic_armv4_bs_wr_2, + generic_bs_wr_4, + NULL, + + /* set multiple */ + NULL, + NULL, + NULL, + NULL, + + /* set region */ + NULL, + generic_armv4_bs_sr_2, + generic_bs_sr_4, + NULL, + + /* copy */ + NULL, + generic_armv4_bs_c_2, + NULL, + NULL, + + /* read (single) stream */ + generic_bs_r_1, + generic_armv4_bs_r_2, + generic_bs_r_4, + NULL, + + /* read multiple stream */ + generic_bs_rm_1, + generic_armv4_bs_rm_2, + generic_bs_rm_4, + NULL, + + /* read region stream */ + generic_bs_rr_1, + generic_armv4_bs_rr_2, + generic_bs_rr_4, + NULL, + + /* write (single) stream */ + generic_bs_w_1, + generic_armv4_bs_w_2, + generic_bs_w_4, + NULL, + + /* write multiple stream */ + generic_bs_wm_1, + generic_armv4_bs_wm_2, + generic_bs_wm_4, + NULL, + + /* write region stream */ + NULL, + generic_armv4_bs_wr_2, + generic_bs_wr_4, + NULL, +}; + +static int +at91_probe(device_t dev) +{ + device_set_desc(dev, "AT91 device bus"); + arm_post_filter = at91_eoi; + return (0); +} + +static void +at91_identify(driver_t *drv, device_t parent) +{ + + BUS_ADD_CHILD(parent, 0, "atmelarm", 0); +} + +struct arm32_dma_range * +bus_dma_get_range(void) +{ + + return (NULL); +} + +int +bus_dma_get_range_nb(void) +{ + return (0); +} + +extern void irq_entry(void); + +static void +at91_add_child(device_t dev, int prio, const char *name, int unit, + bus_addr_t addr, bus_size_t size, int irq0, int irq1, int irq2) +{ + device_t kid; + struct at91_ivar *ivar; + + kid = device_add_child_ordered(dev, prio, name, unit); + if (kid == NULL) { + printf("Can't add child %s%d ordered\n", name, unit); + return; + } + ivar = malloc(sizeof(*ivar), M_DEVBUF, M_NOWAIT | M_ZERO); + if (ivar == NULL) { + device_delete_child(dev, kid); + printf("Can't add alloc ivar\n"); + return; + } + device_set_ivars(kid, ivar); + resource_list_init(&ivar->resources); + if (irq0 != -1) + bus_set_resource(kid, SYS_RES_IRQ, 0, irq0, 1); + if (irq1 != 0) + bus_set_resource(kid, SYS_RES_IRQ, 1, irq1, 1); + if (irq2 != 0) + bus_set_resource(kid, SYS_RES_IRQ, 2, irq2, 1); + if (addr != 0) + bus_set_resource(kid, SYS_RES_MEMORY, 0, addr, size); +} + +struct cpu_devs +{ + const char *name; + int unit; + bus_addr_t mem_base; + bus_size_t mem_len; + int irq0; + int irq1; + int irq2; +}; + +struct cpu_devs at91sam9_devs[] = +{ + { + "at91_pit", 0, + AT91SAM9G20_BASE + AT91SAM9G20_PIT_BASE, AT91SAM9G20_PIT_SIZE, + AT91SAM9G20_IRQ_SYSTEM + }, + { + "at91_wdt", 0, + AT91SAM9G20_BASE + AT91SAM9G20_WDT_BASE, AT91SAM9G20_WDT_SIZE, + AT91SAM9G20_IRQ_SYSTEM + }, + { + "at91_pmc", 0, + AT91SAM9G20_BASE + AT91SAM9G20_PMC_BASE, AT91SAM9G20_PMC_SIZE, + AT91SAM9G20_IRQ_SYSTEM + }, + { + "at91_pio", 0, + AT91SAM9G20_BASE + AT91SAM9G20_PIOA_BASE, AT91SAM9G20_PIO_SIZE, + AT91SAM9G20_IRQ_SYSTEM + }, + { + "at91_pio", 1, + AT91SAM9G20_BASE + AT91SAM9G20_PIOB_BASE, AT91SAM9G20_PIO_SIZE, + AT91SAM9G20_IRQ_SYSTEM + }, + { + "at91_pio", 2, + AT91SAM9G20_BASE + AT91SAM9G20_PIOC_BASE, AT91SAM9G20_PIO_SIZE, + AT91SAM9G20_IRQ_SYSTEM + }, + { + "uart", 0, + AT91SAM9G20_BASE + AT91SAM9G20_DBGU_BASE, AT91SAM9G20_DBGU_SIZE, + AT91SAM9G20_IRQ_SYSTEM + }, + { + "uart", 1, + AT91SAM9G20_BASE + AT91SAM9G20_USART0_BASE, AT91SAM9G20_USART_SIZE, + AT91SAM9G20_IRQ_USART0 + }, + { + "uart", 2, + AT91SAM9G20_BASE + AT91SAM9G20_USART1_BASE, AT91SAM9G20_USART_SIZE, + AT91SAM9G20_IRQ_USART1 + }, + { + "uart", 3, + AT91SAM9G20_BASE + AT91SAM9G20_USART2_BASE, AT91SAM9G20_USART_SIZE, + AT91SAM9G20_IRQ_USART2 + }, + { + "spi", 0, + AT91SAM9G20_BASE + AT91SAM9G20_SPI0_BASE, AT91SAM9G20_SPI0_SIZE, + AT91SAM9G20_IRQ_SPI0 + }, + { + "spi", 1, + AT91SAM9G20_BASE + AT91SAM9G20_SPI1_BASE, AT91SAM9G20_SPI1_SIZE, + AT91SAM9G20_IRQ_SPI1 + }, + { + "ohci", 0, + AT91SAM9G20_OHCI_BASE, AT91SAM9G20_OHCI_SIZE, + AT91SAM9G20_IRQ_UHP + }, + { + "macb", 0, + AT91SAM9G20_BASE + AT91SAM9G20_EMAC_BASE, AT91SAM9G20_EMAC_SIZE, + AT91SAM9G20_IRQ_EMAC + }, + { + "nand", 0, + AT91SAM9G20_NAND_BASE, AT91SAM9G20_NAND_SIZE, + -1 + }, + { 0, 0, 0, 0, 0 } +}; + +static void +at91_cpu_add_builtin_children(device_t dev, struct at91_softc *sc) +{ + int i; + struct cpu_devs *walker; + + // XXX should look at the device id in the DBGU register and + // XXX based on the CPU load in these devices + for (i = 0, walker = at91sam9_devs; walker->name; i++, walker++) { + at91_add_child(dev, i, walker->name, walker->unit, + walker->mem_base, walker->mem_len, walker->irq0, + walker->irq1, walker->irq2); + } +} + +#define NORMDEV 50 + +/* + * 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 int irq_prio[32] = +{ + 7, /* Advanced Interrupt Controller */ + 7, /* System Peripherals */ + 1, /* Parallel IO Controller A */ + 1, /* Parallel IO Controller B */ + 1, /* Parallel IO Controller C */ + 0, /* Analog-to-Digital Converter */ + 5, /* USART 0 */ + 5, /* USART 1 */ + 5, /* USART 2 */ + 0, /* Multimedia Card Interface */ + 2, /* USB Device Port */ + 6, /* Two-Wire Interface */ + 5, /* Serial Peripheral Interface 0 */ + 5, /* Serial Peripheral Interface 1 */ + 5, /* Serial Synchronous Controller */ + 0, + 0, + 0, /* Timer Counter 0 */ + 0, /* Timer Counter 1 */ + 0, /* Timer Counter 2 */ + 2, /* USB Host port */ + 3, /* Ethernet */ + 0, /* Image Sensor Interface */ + 5, /* USART 3 */ + 5, /* USART 4 */ + 5, /* USART 5 */ + 0, /* Timer Counter 3 */ + 0, /* Timer Counter 4 */ + 0, /* Timer Counter 5 */ + 0, /* Advanced Interrupt Controller */ + 0, /* Advanced Interrupt Controller */ + 0, /* Advanced Interrupt Controller */ +}; + +static int +at91_attach(device_t dev) +{ + struct at91_softc *sc = device_get_softc(dev); + int i; + + at91_softc = sc; + sc->sc_st = &at91_bs_tag; + sc->sc_sh = AT91SAM9G20_BASE; + sc->dev = dev; + if (bus_space_subregion(sc->sc_st, sc->sc_sh, AT91SAM9G20_SYS_BASE, + AT91SAM9G20_SYS_SIZE, &sc->sc_sys_sh) != 0) + panic("Enable to map IRQ registers"); + sc->sc_irq_rman.rm_type = RMAN_ARRAY; + sc->sc_irq_rman.rm_descr = "AT91 IRQs"; + sc->sc_mem_rman.rm_type = RMAN_ARRAY; + sc->sc_mem_rman.rm_descr = "AT91 Memory"; + if (rman_init(&sc->sc_irq_rman) != 0 || + rman_manage_region(&sc->sc_irq_rman, 1, 31) != 0) + panic("at91_attach: failed to set up IRQ rman"); + if (rman_init(&sc->sc_mem_rman) != 0 || + rman_manage_region(&sc->sc_mem_rman, 0xdff00000ul, + 0xdffffffful) != 0) + panic("at91_attach: failed to set up memory rman"); + if (rman_manage_region(&sc->sc_mem_rman, AT91SAM9G20_OHCI_BASE, + AT91SAM9G20_OHCI_BASE + AT91SAM9G20_OHCI_SIZE - 1) != 0) + panic("at91_attach: failed to set up ohci memory"); + + if (rman_manage_region(&sc->sc_mem_rman, AT91SAM9G20_NAND_BASE, + AT91SAM9G20_NAND_BASE + AT91SAM9G20_NAND_SIZE - 1) != 0) + panic("at91_attach: failed to set up ohci memory"); + + +#if 0 + if (rman_manage_region(&sc->sc_mem_rman, AT91SAM9G20_CF_BASE, + AT91SAM9G20_CF_BASE + AT91SAM9G20_CF_SIZE - 1) != 0) + panic("at91_attach: failed to set up CompactFlash ATA memory"); +#endif + + for (i = 0; i < 32; i++) { + bus_space_write_4(sc->sc_st, sc->sc_sys_sh, 0x1000 + IC_SVR + + i * 4, i); + /* Priority. */ + bus_space_write_4(sc->sc_st, sc->sc_sys_sh, 0x1000 + IC_SMR + i * 4, + irq_prio[i]); + if (i < 8) + bus_space_write_4(sc->sc_st, sc->sc_sys_sh, 0x1000 + IC_EOICR, + 1); + } + bus_space_write_4(sc->sc_st, sc->sc_sys_sh, 0x1000 + IC_SPU, 32); + /* No debug. */ + bus_space_write_4(sc->sc_st, sc->sc_sys_sh, 0x1000 + IC_DCR, 0); + /* Disable and clear all interrupts. */ + bus_space_write_4(sc->sc_st, sc->sc_sys_sh, 0x1000 + IC_IDCR, 0xffffffff); + bus_space_write_4(sc->sc_st, sc->sc_sys_sh, 0x1000 + IC_ICCR, 0xffffffff); + + /* XXX */ + /* Disable all interrupts for RTC (0xe24 == RTC_IDR) */ + //bus_space_write_4(sc->sc_st, sc->sc_sys_sh, 0xe24, 0xffffffff); + + /* DIsable all interrupts for DBGU */ + bus_space_write_4(sc->sc_st, sc->sc_sys_sh, 0x120c, 0xffffffff); + /* Disable all interrupts for the SDRAM controller */ + //bus_space_write_4(sc->sc_st, sc->sc_sys_sh, 0xfa8, 0xffffffff); + + + i = bus_space_read_4(sc->sc_st, + sc->sc_sys_sh, AT91SAM9G20_EBICSA); + + /*activate NAND*/ + bus_space_write_4(sc->sc_st, sc->sc_sys_sh, AT91SAM9G20_EBICSA, + i | AT91_MATRIX_EBI_CS3A_SMC_SMARTMEDIA); + + + at91_cpu_add_builtin_children(dev, sc); + + bus_generic_probe(dev); + bus_generic_attach(dev); + enable_interrupts(I32_bit | F32_bit); + return (0); +} + +static struct resource * +at91_alloc_resource(device_t dev, device_t child, int type, int *rid, + u_long start, u_long end, u_long count, u_int flags) +{ + struct at91_softc *sc = device_get_softc(dev); + struct resource_list_entry *rle; + struct at91_ivar *ivar = device_get_ivars(child); + struct resource_list *rl = &ivar->resources; + + if (device_get_parent(child) != dev) + return (BUS_ALLOC_RESOURCE(device_get_parent(dev), child, + type, rid, start, end, count, flags)); + + rle = resource_list_find(rl, type, *rid); + if (rle == NULL) + return (NULL); + if (rle->res) + panic("Resource rid %d type %d already in use", *rid, type); + if (start == 0UL && end == ~0UL) { + start = rle->start; + count = ulmax(count, rle->count); + end = ulmax(rle->end, start + count - 1); + } + switch (type) + { + case SYS_RES_IRQ: + rle->res = rman_reserve_resource(&sc->sc_irq_rman, + start, end, count, flags, child); + break; + case SYS_RES_MEMORY: + + rle->res = rman_reserve_resource(&sc->sc_mem_rman, + start, end, count, flags, child); + if (rle->res != NULL) { + rman_set_bustag(rle->res, &at91_bs_tag); + rman_set_bushandle(rle->res, start); + } + break; + } + if (rle->res) { + rle->start = rman_get_start(rle->res); + rle->end = rman_get_end(rle->res); + rle->count = count; + rman_set_rid(rle->res, *rid); + } + return (rle->res); +} + +static struct resource_list * +at91_get_resource_list(device_t dev, device_t child) +{ + struct at91_ivar *ivar; + + ivar = device_get_ivars(child); + return (&(ivar->resources)); +} + +static int +at91_release_resource(device_t dev, device_t child, int type, + int rid, struct resource *r) +{ + struct resource_list *rl; + struct resource_list_entry *rle; + + rl = at91_get_resource_list(dev, child); + if (rl == NULL) + return (EINVAL); + rle = resource_list_find(rl, type, rid); + if (rle == NULL) + return (EINVAL); + rman_release_resource(r); + rle->res = NULL; + return (0); +} + +static int +at91_setup_intr(device_t dev, device_t child, + struct resource *ires, int flags, driver_filter_t *filt, + driver_intr_t *intr, void *arg, void **cookiep) +{ + struct at91_softc *sc = device_get_softc(dev); + + if (rman_get_start(ires) == AT91SAM9G20_IRQ_SYSTEM && filt == NULL) + panic("All system interrupt ISRs must be FILTER"); + BUS_SETUP_INTR(device_get_parent(dev), child, ires, flags, filt, + intr, arg, cookiep); + bus_space_write_4(sc->sc_st, sc->sc_sys_sh, 0x1000 + IC_IECR, + 1 << rman_get_start(ires)); + return (0); +} + +static int +at91_teardown_intr(device_t dev, device_t child, struct resource *res, + void *cookie) +{ + struct at91_softc *sc = device_get_softc(dev); + + bus_space_write_4(sc->sc_st, sc->sc_sys_sh, 0x1000 + IC_IDCR, + 1 << rman_get_start(res)); + return (BUS_TEARDOWN_INTR(device_get_parent(dev), child, res, cookie)); +} + +static int +at91_activate_resource(device_t bus, device_t child, int type, int rid, + struct resource *r) +{ +#if 0 + u_long p; + int error; + + if (type == SYS_RES_MEMORY) { + error = bus_space_map(rman_get_bustag(r), + rman_get_bushandle(r), rman_get_size(r), 0, &p); + if (error) + return (error); + rman_set_bushandle(r, p); + } +#endif + return (rman_activate_resource(r)); +} + +static int +at91_print_child(device_t dev, device_t child) +{ + struct at91_ivar *ivars; + struct resource_list *rl; + int retval = 0; + + ivars = device_get_ivars(child); + rl = &ivars->resources; + + retval += bus_print_child_header(dev, child); + + retval += resource_list_print_type(rl, "port", SYS_RES_IOPORT, "%#lx"); + retval += resource_list_print_type(rl, "mem", SYS_RES_MEMORY, "%#lx"); + retval += resource_list_print_type(rl, "irq", SYS_RES_IRQ, "%ld"); + if (device_get_flags(dev)) + retval += printf(" flags %#x", device_get_flags(dev)); + + retval += bus_print_child_footer(dev, child); + + return (retval); +} + +void +arm_mask_irq(uintptr_t nb) +{ + + bus_space_write_4(at91_softc->sc_st, + at91_softc->sc_sys_sh, 0x1000 + IC_IDCR, 1 << nb); + +} + +int +arm_get_next_irq(int last __unused) +{ + int status; + int irq; + + irq = bus_space_read_4(at91_softc->sc_st, + at91_softc->sc_sys_sh, 0x1000 + IC_IVR); + status = bus_space_read_4(at91_softc->sc_st, + at91_softc->sc_sys_sh, 0x1000 + IC_ISR); + if (status == 0) { + bus_space_write_4(at91_softc->sc_st, + at91_softc->sc_sys_sh, 0x1000 + IC_EOICR, 1); + return (-1); + } + return (irq); +} + +void +arm_unmask_irq(uintptr_t nb) +{ + + bus_space_write_4(at91_softc->sc_st, + at91_softc->sc_sys_sh, 0x1000 + IC_IECR, 1 << nb); + bus_space_write_4(at91_softc->sc_st, at91_softc->sc_sys_sh, + 0x1000 + IC_EOICR, 0); + +} + +static void +at91_eoi(void *unused) +{ + bus_space_write_4(at91_softc->sc_st, at91_softc->sc_sys_sh, + 0x1000 + IC_EOICR, 0); +} + +static device_method_t at91_methods[] = { + DEVMETHOD(device_probe, at91_probe), + DEVMETHOD(device_attach, at91_attach), + DEVMETHOD(device_identify, at91_identify), + + DEVMETHOD(bus_alloc_resource, at91_alloc_resource), + DEVMETHOD(bus_setup_intr, at91_setup_intr), + DEVMETHOD(bus_teardown_intr, at91_teardown_intr), + DEVMETHOD(bus_activate_resource, at91_activate_resource), + DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource), + DEVMETHOD(bus_get_resource_list,at91_get_resource_list), + DEVMETHOD(bus_set_resource, bus_generic_rl_set_resource), + DEVMETHOD(bus_get_resource, bus_generic_rl_get_resource), + DEVMETHOD(bus_release_resource, at91_release_resource), + DEVMETHOD(bus_print_child, at91_print_child), + + {0, 0}, +}; + +static driver_t at91_driver = { + "atmelarm", + at91_methods, + sizeof(struct at91_softc), +}; +static devclass_t at91_devclass; + +DRIVER_MODULE(atmelarm, nexus, at91_driver, at91_devclass, 0, 0); diff --git a/sys/arm/at91/at91sam9_machdep.c b/sys/arm/at91/at91sam9_machdep.c new file mode 100644 index 0000000..c3e5613 --- /dev/null +++ b/sys/arm/at91/at91sam9_machdep.c @@ -0,0 +1,420 @@ +/*- + * Copyright (c) 1994-1998 Mark Brinicombe. + * Copyright (c) 1994 Brini. + * All rights reserved. + * + * This code is derived from software written for Brini by Mark Brinicombe + * + * 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. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Brini. + * 4. The name of the company nor the name of the author may be used to + * endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY BRINI ``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 BRINI 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. + * + * RiscBSD kernel project + * + * machdep.c + * + * Machine dependant functions for kernel setup + * + * This file needs a lot of work. + * + * Created : 17/09/94 + */ + +#include "opt_msgbuf.h" + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#define _ARM32_BUS_DMA_PRIVATE +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/sysproto.h> +#include <sys/signalvar.h> +#include <sys/imgact.h> +#include <sys/kernel.h> +#include <sys/ktr.h> +#include <sys/linker.h> +#include <sys/lock.h> +#include <sys/malloc.h> +#include <sys/mutex.h> +#include <sys/pcpu.h> +#include <sys/proc.h> +#include <sys/ptrace.h> +#include <sys/cons.h> +#include <sys/bio.h> +#include <sys/bus.h> +#include <sys/buf.h> +#include <sys/exec.h> +#include <sys/kdb.h> +#include <sys/msgbuf.h> +#include <machine/reg.h> +#include <machine/cpu.h> + +#include <vm/vm.h> +#include <vm/pmap.h> +#include <vm/vm_object.h> +#include <vm/vm_page.h> +#include <vm/vm_pager.h> +#include <vm/vm_map.h> +#include <machine/pmap.h> +#include <machine/vmparam.h> +#include <machine/pcb.h> +#include <machine/undefined.h> +#include <machine/machdep.h> +#include <machine/metadata.h> +#include <machine/armreg.h> +#include <machine/bus.h> +#include <sys/reboot.h> + +#include <arm/at91/at91board.h> +#include <arm/at91/at91sam9g20reg.h> +#include <arm/at91/at91_piovar.h> +#include <arm/at91/at91_pio_rm9200.h> + +#define KERNEL_PT_SYS 0 /* Page table for mapping proc0 zero page */ +#define KERNEL_PT_KERN 1 +#define KERNEL_PT_KERN_NUM 22 +#define KERNEL_PT_AFKERNEL KERNEL_PT_KERN + KERNEL_PT_KERN_NUM /* L2 table for mapping after kernel */ +#define KERNEL_PT_AFKERNEL_NUM 5 + +/* this should be evenly divisable by PAGE_SIZE / L2_TABLE_SIZE_REAL (or 4) */ +#define NUM_KERNEL_PTS (KERNEL_PT_AFKERNEL + KERNEL_PT_AFKERNEL_NUM) + +/* Define various stack sizes in pages */ +#define IRQ_STACK_SIZE 1 +#define ABT_STACK_SIZE 1 +#define UND_STACK_SIZE 1 + +extern u_int data_abort_handler_address; +extern u_int prefetch_abort_handler_address; +extern u_int undefined_handler_address; + +struct pv_addr kernel_pt_table[NUM_KERNEL_PTS]; + +extern void *_end; + +extern int *end; + +struct pcpu __pcpu; +struct pcpu *pcpup = &__pcpu; + +/* Physical and virtual addresses for some global pages */ + +vm_paddr_t phys_avail[10]; +vm_paddr_t dump_avail[4]; +vm_offset_t physical_pages; + +struct pv_addr systempage; +struct pv_addr msgbufpv; +struct pv_addr irqstack; +struct pv_addr undstack; +struct pv_addr abtstack; +struct pv_addr kernelstack; + +static void *boot_arg1; +static void *boot_arg2; + +static struct trapframe proc0_tf; + +/* Static device mappings. */ +static const struct pmap_devmap at91sam9_devmap[] = { + /* + * Map the on-board devices VA == PA so that we can access them + * with the MMU on or off. + */ + { + /* + * This at least maps the interrupt controller, the UART + * and the timer. Other devices should use newbus to + * map their memory anyway. + */ + 0xdff00000, + 0xfff00000, + 0x100000, + VM_PROT_READ|VM_PROT_WRITE, + PTE_NOCACHE, + }, + /* + * We can't just map the OHCI registers VA == PA, because + * AT91RM92_OHCI_BASE belongs to the userland address space. + * We could just choose a different virtual address, but a better + * solution would probably be to just use pmap_mapdev() to allocate + * KVA, as we don't need the OHCI controller before the vm + * initialization is done. However, the AT91 resource allocation + * system doesn't know how to use pmap_mapdev() yet. + */ + { + /* + * Add the ohci controller, and anything else that might be + * on this chip select for a VA/PA mapping. + */ + AT91SAM9G20_OHCI_BASE, + AT91SAM9G20_OHCI_PA_BASE, + AT91SAM9G20_OHCI_SIZE, + VM_PROT_READ|VM_PROT_WRITE, + PTE_NOCACHE, + }, + { + AT91SAM9G20_NAND_BASE, + AT91SAM9G20_NAND_PA_BASE, + AT91SAM9G20_NAND_SIZE, + VM_PROT_READ|VM_PROT_WRITE, + PTE_NOCACHE, + }, + { + 0, + 0, + 0, + 0, + 0, + } +}; + +long +at91_ramsize(void) +{ +#if 0 + uint32_t *SDRAMC = (uint32_t *)(AT91SAM9G20_BASE + AT91SAM9G20_SDRAMC_BASE); + uint32_t cr, mr; + int banks, rows, cols, bw; + + cr = SDRAMC[AT91SAM9G20_SDRAMC_CR / 4]; + mr = SDRAMC[AT91SAM9G20_SDRAMC_MR / 4]; + bw = (mr & AT91SAM9G20_SDRAMC_MR_DBW_16) ? 1 : 2; + banks = (cr & AT91SAM9G20_SDRAMC_CR_NB_4) ? 2 : 1; + rows = ((cr & AT91SAM9G20_SDRAMC_CR_NR_MASK) >> 2) + 11; + cols = (cr & AT91SAM9G20_SDRAMC_CR_NC_MASK) + 8; + return (1 << (cols + rows + banks + bw)); +#endif + return 64*1024*1024; +} + +void * +initarm(void *arg, void *arg2) +{ + struct pv_addr kernel_l1pt; + struct pv_addr dpcpu; + int loop, i; + u_int l1pagetable; + vm_offset_t freemempos; + vm_offset_t afterkern; + uint32_t memsize; + vm_offset_t lastaddr; + + boot_arg1 = arg; + boot_arg2 = arg2; + + + set_cpufuncs(); + lastaddr = fake_preload_metadata(); + pcpu_init(pcpup, 0, sizeof(struct pcpu)); + PCPU_SET(curthread, &thread0); + + freemempos = (lastaddr + PAGE_MASK) & ~PAGE_MASK; + /* Define a macro to simplify memory allocation */ +#define valloc_pages(var, np) \ + alloc_pages((var).pv_va, (np)); \ + (var).pv_pa = (var).pv_va + (KERNPHYSADDR - KERNVIRTADDR); + +#define alloc_pages(var, np) \ + (var) = freemempos; \ + freemempos += (np * PAGE_SIZE); \ + memset((char *)(var), 0, ((np) * PAGE_SIZE)); + + while (((freemempos - L1_TABLE_SIZE) & (L1_TABLE_SIZE - 1)) != 0) + freemempos += PAGE_SIZE; + valloc_pages(kernel_l1pt, L1_TABLE_SIZE / PAGE_SIZE); + for (loop = 0; loop < NUM_KERNEL_PTS; ++loop) { + if (!(loop % (PAGE_SIZE / L2_TABLE_SIZE_REAL))) { + valloc_pages(kernel_pt_table[loop], + L2_TABLE_SIZE / PAGE_SIZE); + } else { + kernel_pt_table[loop].pv_va = freemempos - + (loop % (PAGE_SIZE / L2_TABLE_SIZE_REAL)) * + L2_TABLE_SIZE_REAL; + kernel_pt_table[loop].pv_pa = + kernel_pt_table[loop].pv_va - KERNVIRTADDR + + KERNPHYSADDR; + } + i++; + } + /* + * Allocate a page for the system page mapped to V0x00000000 + * This page will just contain the system vectors and can be + * shared by all processes. + */ + valloc_pages(systempage, 1); + + /* Allocate dynamic per-cpu area. */ + valloc_pages(dpcpu, DPCPU_SIZE / PAGE_SIZE); + dpcpu_init((void *)dpcpu.pv_va, 0); + + /* Allocate stacks for all modes */ + valloc_pages(irqstack, IRQ_STACK_SIZE); + valloc_pages(abtstack, ABT_STACK_SIZE); + valloc_pages(undstack, UND_STACK_SIZE); + valloc_pages(kernelstack, KSTACK_PAGES); + valloc_pages(msgbufpv, round_page(MSGBUF_SIZE) / PAGE_SIZE); + + /* + * Now we start construction of the L1 page table + * We start by mapping the L2 page tables into the L1. + * This means that we can replace L1 mappings later on if necessary + */ + l1pagetable = kernel_l1pt.pv_va; + + /* Map the L2 pages tables in the L1 page table */ + pmap_link_l2pt(l1pagetable, ARM_VECTORS_HIGH, + &kernel_pt_table[KERNEL_PT_SYS]); + for (i = 0; i < KERNEL_PT_KERN_NUM; i++) + pmap_link_l2pt(l1pagetable, KERNBASE + i * L1_S_SIZE, + &kernel_pt_table[KERNEL_PT_KERN + i]); + pmap_map_chunk(l1pagetable, KERNBASE, PHYSADDR, + (((uint32_t)lastaddr - KERNBASE) + PAGE_SIZE) & ~(PAGE_SIZE - 1), + VM_PROT_READ|VM_PROT_WRITE, PTE_CACHE); + afterkern = round_page((lastaddr + L1_S_SIZE) & ~(L1_S_SIZE - 1)); + for (i = 0; i < KERNEL_PT_AFKERNEL_NUM; i++) { + pmap_link_l2pt(l1pagetable, afterkern + i * L1_S_SIZE, + &kernel_pt_table[KERNEL_PT_AFKERNEL + i]); + } + + /* Map the vector page. */ + pmap_map_entry(l1pagetable, ARM_VECTORS_HIGH, systempage.pv_pa, + VM_PROT_READ|VM_PROT_WRITE, PTE_CACHE); + + /* Map the DPCPU pages */ + pmap_map_chunk(l1pagetable, dpcpu.pv_va, dpcpu.pv_pa, DPCPU_SIZE, + VM_PROT_READ|VM_PROT_WRITE, PTE_CACHE); + + /* Map the stack pages */ + pmap_map_chunk(l1pagetable, irqstack.pv_va, irqstack.pv_pa, + IRQ_STACK_SIZE * PAGE_SIZE, VM_PROT_READ|VM_PROT_WRITE, PTE_CACHE); + pmap_map_chunk(l1pagetable, abtstack.pv_va, abtstack.pv_pa, + ABT_STACK_SIZE * PAGE_SIZE, VM_PROT_READ|VM_PROT_WRITE, PTE_CACHE); + pmap_map_chunk(l1pagetable, undstack.pv_va, undstack.pv_pa, + UND_STACK_SIZE * PAGE_SIZE, VM_PROT_READ|VM_PROT_WRITE, PTE_CACHE); + pmap_map_chunk(l1pagetable, kernelstack.pv_va, kernelstack.pv_pa, + KSTACK_PAGES * PAGE_SIZE, VM_PROT_READ|VM_PROT_WRITE, PTE_CACHE); + + pmap_map_chunk(l1pagetable, kernel_l1pt.pv_va, kernel_l1pt.pv_pa, + L1_TABLE_SIZE, VM_PROT_READ|VM_PROT_WRITE, PTE_PAGETABLE); + pmap_map_chunk(l1pagetable, msgbufpv.pv_va, msgbufpv.pv_pa, + MSGBUF_SIZE, VM_PROT_READ|VM_PROT_WRITE, PTE_CACHE); + + for (loop = 0; loop < NUM_KERNEL_PTS; ++loop) { + pmap_map_chunk(l1pagetable, kernel_pt_table[loop].pv_va, + kernel_pt_table[loop].pv_pa, L2_TABLE_SIZE, + VM_PROT_READ|VM_PROT_WRITE, PTE_PAGETABLE); + } + + pmap_devmap_bootstrap(l1pagetable, at91sam9_devmap); + cpu_domains((DOMAIN_CLIENT << (PMAP_DOMAIN_KERNEL*2)) | DOMAIN_CLIENT); + setttb(kernel_l1pt.pv_pa); + cpu_tlb_flushID(); + cpu_domains(DOMAIN_CLIENT << (PMAP_DOMAIN_KERNEL*2)); + cninit(); + memsize = board_init(); + physmem = memsize / PAGE_SIZE; + + /* + * Pages were allocated during the secondary bootstrap for the + * stacks for different CPU modes. + * We must now set the r13 registers in the different CPU modes to + * point to these stacks. + * Since the ARM stacks use STMFD etc. we must set r13 to the top end + * of the stack memory. + */ + cpu_control(CPU_CONTROL_MMU_ENABLE, CPU_CONTROL_MMU_ENABLE); + set_stackptr(PSR_IRQ32_MODE, + irqstack.pv_va + IRQ_STACK_SIZE * PAGE_SIZE); + set_stackptr(PSR_ABT32_MODE, + abtstack.pv_va + ABT_STACK_SIZE * PAGE_SIZE); + set_stackptr(PSR_UND32_MODE, + undstack.pv_va + UND_STACK_SIZE * PAGE_SIZE); + + /* + * We must now clean the cache again.... + * Cleaning may be done by reading new data to displace any + * dirty data in the cache. This will have happened in setttb() + * but since we are boot strapping the addresses used for the read + * may have just been remapped and thus the cache could be out + * of sync. A re-clean after the switch will cure this. + * After booting there are no gross relocations of the kernel thus + * this problem will not occur after initarm(). + */ + cpu_idcache_wbinv_all(); + + /* Set stack for exception handlers */ + + data_abort_handler_address = (u_int)data_abort_handler; + prefetch_abort_handler_address = (u_int)prefetch_abort_handler; + undefined_handler_address = (u_int)undefinedinstruction_bounce; + undefined_init(); + + proc_linkup0(&proc0, &thread0); + thread0.td_kstack = kernelstack.pv_va; + thread0.td_pcb = (struct pcb *) + (thread0.td_kstack + KSTACK_PAGES * PAGE_SIZE) - 1; + thread0.td_pcb->pcb_flags = 0; + thread0.td_frame = &proc0_tf; + pcpup->pc_curpcb = thread0.td_pcb; + + arm_vector_init(ARM_VECTORS_HIGH, ARM_VEC_ALL); + + pmap_curmaxkvaddr = afterkern + L1_S_SIZE * (KERNEL_PT_KERN_NUM - 1); + + /* + * ARM_USE_SMALL_ALLOC uses dump_avail, so it must be filled before + * calling pmap_bootstrap. + */ + dump_avail[0] = PHYSADDR; + dump_avail[1] = PHYSADDR + memsize; + dump_avail[2] = 0; + dump_avail[3] = 0; + + pmap_bootstrap(freemempos, + KERNVIRTADDR + 3 * memsize, + &kernel_l1pt); + msgbufp = (void*)msgbufpv.pv_va; + msgbufinit(msgbufp, MSGBUF_SIZE); + mutex_init(); + + i = 0; +#if PHYSADDR != KERNPHYSADDR + phys_avail[i++] = PHYSADDR; + phys_avail[i++] = KERNPHYSADDR; +#endif + phys_avail[i++] = virtual_avail - KERNVIRTADDR + KERNPHYSADDR; + phys_avail[i++] = PHYSADDR + memsize; + phys_avail[i++] = 0; + phys_avail[i++] = 0; + /* Do basic tuning, hz etc */ + init_param1(); + init_param2(physmem); + kdb_init(); + return ((void *)(kernelstack.pv_va + USPACE_SVC_STACK_TOP - + sizeof(struct pcb))); +} diff --git a/sys/arm/at91/at91sam9g20reg.h b/sys/arm/at91/at91sam9g20reg.h new file mode 100644 index 0000000..9194b11 --- /dev/null +++ b/sys/arm/at91/at91sam9g20reg.h @@ -0,0 +1,254 @@ +/*- + * Copyright (c) 2009 Sylvestre Gallon. 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 AT91SAM9G20REG_H_ +#define AT91SAM9G20REG_H_ + +/* + * Memory map, from datasheet : + * 0x00000000 - 0x0ffffffff : Internal Memories + * 0x10000000 - 0x1ffffffff : Chip Select 0 + * 0x20000000 - 0x2ffffffff : Chip Select 1 + * 0x30000000 - 0x3ffffffff : Chip Select 2 + * 0x40000000 - 0x4ffffffff : Chip Select 3 + * 0x50000000 - 0x5ffffffff : Chip Select 4 + * 0x60000000 - 0x6ffffffff : Chip Select 5 + * 0x70000000 - 0x7ffffffff : Chip Select 6 + * 0x80000000 - 0x8ffffffff : Chip Select 7 + * 0x90000000 - 0xeffffffff : Undefined (Abort) + * 0xf0000000 - 0xfffffffff : Peripherals + */ + +#define AT91_CHIPSELECT_0 0x10000000 +#define AT91_CHIPSELECT_1 0x20000000 +#define AT91_CHIPSELECT_2 0x30000000 +#define AT91_CHIPSELECT_3 0x40000000 +#define AT91_CHIPSELECT_4 0x50000000 +#define AT91_CHIPSELECT_5 0x60000000 +#define AT91_CHIPSELECT_6 0x70000000 +#define AT91_CHIPSELECT_7 0x80000000 + + +#define AT91SAM9G20_BASE 0xd0000000 + + +#define AT91SAM9G20_IRQ_EMAC 21 +#define AT91SAM9G20_EMAC_BASE 0xffc4000 +#define AT91SAM9G20_EMAC_SIZE 0x4000 + +#define AT91SAM9G20_RSTC_BASE 0xffffd00 + +#define RSTC_CR 0 +#define RSTC_PROCRST (1 << 0) +#define RSTC_PERRST (1 << 2) +#define RSTC_KEY (0xa5 << 24) + +/* USART*/ + +#define AT91SAM9G20_USART0_BASE 0xffb0000 +#define AT91SAM9G20_USART0_PDC 0xffb0100 +#define AT91SAM9G20_USART1_BASE 0xffb4000 +#define AT91SAM9G20_USART1_PDC 0xffb4100 +#define AT91SAM9G20_USART2_BASE 0xffb8000 +#define AT91SAM9G20_USART2_PDC 0xffb8100 +#define AT91SAM9G20_USART_SIZE 0x4000 + +/*TC*/ +#define AT91SAM9G20_TC0_BASE 0xffa0000 +#define AT91SAM9G20_TC0_SIZE 0x4000 +#define AT91SAM9G20_TC0C0_BASE 0xffa0000 +#define AT91SAM9G20_TC0C1_BASE 0xffa0040 +#define AT91SAM9G20_TC0C2_BASE 0xffa0080 + +#define AT91SAM9G20_TC1_BASE 0xffdc000 +#define AT91SAM9G20_TC1_SIZE 0x4000 + +/*SPI*/ + +#define AT91SAM9G20_SPI0_BASE 0xffc8000 + +#define AT91SAM9G20_SPI0_SIZE 0x4000 +#define AT91SAM9G20_IRQ_SPI0 12 + +#define AT91SAM9G20_SPI1_BASE 0xffcc000 +#define AT91SAM9G20_SPI1_SIZE 0x4000 +#define AT91SAM9G20_IRQ_SPI1 13 + +/* System Registers */ +#define AT91SAM9G20_SYS_BASE 0xfffe000 +#define AT91SAM9G20_SYS_SIZE 0x2000 + +#define AT91SAM9G20_MATRIX (0xe00) + +#define AT91SAM9G20_EBICSA (AT91SAM9G20_MATRIX + 0x011C) + +#define AT91_MATRIX_EBI_CS3A_SMC_SMARTMEDIA (1 << 3) + +#define DBGU 0x200 +#define DBGU_SIZE 0x200 +#define DBGU_C1R (0x200 + 64) /* Chip ID1 Register */ +#define DBGU_C2R (0x200 + 68) /* Chip ID2 Register */ +#define DBGU_FNTR (0x200 + 72) /* Force NTRST Register */ + +/* + * PIO + */ +#define AT91SAM9G20_PIOA_BASE 0xffff400 +#define AT91SAM9G20_PIO_SIZE 0x200 +#define AT91SAM9G20_PIOB_BASE 0xffff600 +#define AT91SAM9G20_PIOC_BASE 0xffff800 + +#define AT91RM92_PMC_BASE 0xffffc00 +#define AT91RM92_PMC_SIZE 0x100 +/* IRQs : */ +/* + * 0: AIC + * 1: System peripheral (System timer, RTC, DBGU) + * 2: PIO Controller A + * 3: PIO Controller B + * 4: PIO Controller C + * 5: - + * 6: USART 0 + * 7: USART 1 + * 8: USART 2 + * 9: MMC Interface + * 10: USB device port + * 11: Two-wirte interface + * 12: SPI + * 13: SPI + * 14: SSC + * 15: SSC + * 16: SSC + * 17: Timer Counter 0 + * 18: Timer Counter 1 + * 19: Timer Counter 2 + * 20: USB Host port + * 21: EMAC + * 22-28: - + * 29: AIC + * 30: AIC + * 31: AIC + */ + +#define AT91SAM9G20_IRQ_SYSTEM 1 +#define AT91SAM9G20_IRQ_PIOA 2 +#define AT91SAM9G20_IRQ_PIOB 3 +#define AT91SAM9G20_IRQ_PIOC 4 +#define AT91SAM9G20_IRQ_USART0 6 +#define AT91SAM9G20_IRQ_USART1 7 +#define AT91SAM9G20_IRQ_USART2 8 +#define AT91SAM9G20_IRQ_MCI 9 +#define AT91SAM9G20_IRQ_UDP 10 +#define AT91SAM9G20_IRQ_TWI 11 +#define AT91SAM9G20_IRQ_SPI0 12 +#define AT91SAM9G20_IRQ_SPI1 13 +#define AT91SAM9G20_IRQ_SSC0 14 +#define AT91SAM9G20_IRQ_SSC1 15 +#define AT91SAM9G20_IRQ_SSC2 16 +#define AT91SAM9G20_IRQ_TC0 17 +#define AT91SAM9G20_IRQ_TC1 18 +#define AT91SAM9G20_IRQ_TC2 19 +#define AT91SAM9G20_IRQ_UHP 20 +#define AT91SAM9G20_IRQ_AICBASE 29 + +/* Timer */ + +#define AT91SAM9G20_DBGU_BASE 0xffff200 +#define AT91SAM9G20_DBGU_SIZE 0x200 + +#define AT91SAM9G20_WDT_BASE 0xffffd40 +#define AT91SAM9G20_WDT_SIZE 0x10 + +#define AT91SAM9G20_PIT_BASE 0xffffd30 +#define AT91SAM9G20_PIT_SIZE 10 + +#define AT91SAM9G20_SMC_BASE 0xfffec00 +#define AT91SAM9G20_SMC_SIZE 0x200 + +#define AT91SAM9G20_PMC_BASE 0xffffc00 +#define AT91SAM9G20_PMC_SIZE 0x100 + +#define AT91SAM9G20_UDP_BASE 0xffa4000 +#define AT91SAM9G20_UDP_SIZE 0x4000 + +#define AT91SAM9G20_OHCI_BASE 0xdfe00000 +#define AT91SAM9G20_OHCI_PA_BASE 0x00500000 +#define AT91SAM9G20_OHCI_SIZE 0x00100000 + + +//#define AT91SAM9G20_NAND_BASE 0xdf100000 + +//#define AT91SAM9G20_NAND_BASE 0x40000000 + +#define AT91SAM9G20_NAND_BASE 0xe0000000 + +#define AT91SAM9G20_NAND_PA_BASE 0x40000000 +#define AT91SAM9G20_NAND_SIZE 0x10000000 +//#define AT91SAM9G20_NAND_SIZE 0x00900000 + +//#define AT91SAM9G20_OHCI_SIZE 0x0004000 + +/* SDRAMC */ +#define AT91SAM9G20_SDRAMC_BASE 0xfffea00 +#define AT91SAM9G20_SDRAMC_MR 0x00 +#define AT91SAM9G20_SDRAMC_MR_MODE_NORMAL 0 +#define AT91SAM9G20_SDRAMC_MR_MODE_NOP 1 +#define AT91SAM9G20_SDRAMC_MR_MODE_PRECHARGE 2 +#define AT91SAM9G20_SDRAMC_MR_MODE_LOAD_MODE_REGISTER 3 +#define AT91SAM9G20_SDRAMC_MR_MODE_REFRESH 4 +#define AT91SAM9G20_SDRAMC_TR 0x04 +#define AT91SAM9G20_SDRAMC_CR 0x08 +#define AT91SAM9G20_SDRAMC_CR_NC_8 0x0 +#define AT91SAM9G20_SDRAMC_CR_NC_9 0x1 +#define AT91SAM9G20_SDRAMC_CR_NC_10 0x2 +#define AT91SAM9G20_SDRAMC_CR_NC_11 0x3 +#define AT91SAM9G20_SDRAMC_CR_NC_MASK 0x00000003 +#define AT91SAM9G20_SDRAMC_CR_NR_11 0x0 +#define AT91SAM9G20_SDRAMC_CR_NR_12 0x4 +#define AT91SAM9G20_SDRAMC_CR_NR_13 0x8 +#define AT91SAM9G20_SDRAMC_CR_NR_RES 0xc +#define AT91SAM9G20_SDRAMC_CR_NR_MASK 0x0000000c +#define AT91SAM9G20_SDRAMC_CR_NB_2 0x00 +#define AT91SAM9G20_SDRAMC_CR_NB_4 0x10 +#define AT91SAM9G20_SDRAMC_CR_NB_MASK 0x00000010 +#define AT91SAM9G20_SDRAMC_CR_NCAS_MASK 0x00000060 +#define AT91SAM9G20_SDRAMC_CR_TWR_MASK 0x00000780 +#define AT91SAM9G20_SDRAMC_CR_TRC_MASK 0x00007800 +#define AT91SAM9G20_SDRAMC_CR_TRP_MASK 0x00078000 +#define AT91SAM9G20_SDRAMC_CR_TRCD_MASK 0x00780000 +#define AT91SAM9G20_SDRAMC_CR_TRAS_MASK 0x07800000 +#define AT91SAM9G20_SDRAMC_CR_TXSR_MASK 0x78000000 +#define AT91SAM9G20_SDRAMC_HSR 0x0c +#define AT91SAM9G20_SDRAMC_LPR 0x10 +#define AT91SAM9G20_SDRAMC_IER 0x14 +#define AT91SAM9G20_SDRAMC_IDR 0x18 +#define AT91SAM9G20_SDRAMC_IMR 0x1c +#define AT91SAM9G20_SDRAMC_ISR 0x20 +#define AT91SAM9G20_SDRAMC_MDR 0x24 + +#endif /* AT91SAM9G20REG_H_*/ + diff --git a/sys/arm/at91/board_hl201.c b/sys/arm/at91/board_hl201.c new file mode 100644 index 0000000..b4a0b59 --- /dev/null +++ b/sys/arm/at91/board_hl201.c @@ -0,0 +1,42 @@ +/*- + * Copyright (c) 2005-2008 Olivier Houchard. All rights reserved. + * Copyright (c) 2005-2008 Warner Losh. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); +#include <sys/param.h> +#include <sys/systm.h> + +#include <arm/at91/at91board.h> +#include <arm/at91/at91sam9g20reg.h> +#include <arm/at91/at91_piovar.h> +#include <arm/at91/at91_pio_sam9.h> + +long +board_init(void) +{ + + return (at91_ramsize()); +} diff --git a/sys/arm/at91/files.at91sam9 b/sys/arm/at91/files.at91sam9 new file mode 100644 index 0000000..fb61cb6 --- /dev/null +++ b/sys/arm/at91/files.at91sam9 @@ -0,0 +1,27 @@ +# $FreeBSD$ +arm/arm/cpufunc_asm_arm9.S standard +arm/arm/irq_dispatch.S standard +arm/at91/at91sam9_machdep.c standard +arm/at91/at91sam9.c standard +arm/at91/at91_cfata.c optional at91_cfata +#arm/at91/at91_pit.c standard +arm/at91/at91_mci.c optional at91_mci +arm/at91/at91_nand.c optional nand +arm/at91/at91_pio.c standard +arm/at91/at91_pmc.c standard +arm/at91/at91_pit.c standard +arm/at91/at91_rtc.c optional at91_rtc +arm/at91/at91_ssc.c optional at91_ssc +arm/at91/at91_spi.c optional at91_spi \ + dependency "spibus_if.h" +arm/at91/at91_tc.c optional at91_tc +arm/at91/at91_twi.c optional at91_twi +arm/at91/if_macb.c optional macb +arm/at91/uart_bus_at91usart.c optional uart +arm/at91/uart_cpu_at91rm9200usart.c optional uart +arm/at91/uart_dev_at91usart.c optional uart +# +# All the boards we support +# +arm/at91/board_hl201.c optional at91_board_hl201 +dev/usb/controller/ohci_atmelarm.c optional ohci diff --git a/sys/arm/at91/if_macb.c b/sys/arm/at91/if_macb.c new file mode 100644 index 0000000..7504c07 --- /dev/null +++ b/sys/arm/at91/if_macb.c @@ -0,0 +1,1581 @@ +/*- + * Copyright (c) 2010 Yohanes Nugroho <yohanes@gmail.com> + * 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 <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/bus.h> +#include <sys/kernel.h> +#include <sys/lock.h> +#include <sys/mbuf.h> +#include <sys/malloc.h> +#include <sys/module.h> +#include <sys/rman.h> +#include <sys/socket.h> +#include <sys/sockio.h> +#include <sys/sysctl.h> +#include <sys/taskqueue.h> + +#include <net/ethernet.h> +#include <net/if.h> +#include <net/if_arp.h> +#include <net/if_dl.h> +#include <net/if_media.h> +#include <net/if_types.h> +#include <net/if_vlan_var.h> + +#ifdef INET +#include <netinet/in.h> +#include <netinet/in_systm.h> +#include <netinet/in_var.h> +#include <netinet/ip.h> +#endif + +#include <net/bpf.h> +#include <net/bpfdesc.h> + +#include <dev/mii/mii.h> +#include <dev/mii/miivar.h> + +#include <arm/at91/at91_pmcvar.h> +#include <arm/at91/if_macbreg.h> +#include <arm/at91/if_macbvar.h> +#include <arm/at91/at91_piovar.h> + +#include <arm/at91/at91_pio_sam9.h> +#include <arm/at91/at91sam9g20reg.h> + +#include <machine/bus.h> +#include <machine/intr.h> + +/* "device miibus" required. See GENERIC if you get errors here. */ +#include "miibus_if.h" + + +#define MACB_LOCK(_sc) mtx_lock(&(_sc)->sc_mtx) +#define MACB_UNLOCK(_sc) mtx_unlock(&(_sc)->sc_mtx) +#define MACB_LOCK_INIT(_sc) \ + mtx_init(&_sc->sc_mtx, device_get_nameunit(_sc->dev), \ + MTX_NETWORK_LOCK, MTX_DEF) +#define MACB_LOCK_DESTROY(_sc) mtx_destroy(&_sc->sc_mtx); +#define MACB_LOCK_ASSERT(_sc) mtx_assert(&_sc->sc_mtx, MA_OWNED); +#define MACB_ASSERT_UNLOCKED(_sc) mtx_assert(&_sc->sc_mtx, MA_NOTOWNED); + + +static inline uint32_t +read_4(struct macb_softc *sc, bus_size_t off) +{ + + return (bus_read_4(sc->mem_res, off)); +} + +static inline void +write_4(struct macb_softc *sc, bus_size_t off, uint32_t val) +{ + + bus_write_4(sc->mem_res, off, val); +} + + +static devclass_t macb_devclass; + +/* ifnet entry points */ + +static void macbinit_locked(void *); +static void macbstart_locked(struct ifnet *); + +static void macbinit(void *); +static void macbstart(struct ifnet *); +static void macbstop(struct macb_softc *); +static int macbioctl(struct ifnet * ifp, u_long, caddr_t); + +/* bus entry points */ + +static int macb_probe(device_t dev); +static int macb_attach(device_t dev); +static int macb_detach(device_t dev); + +/* helper functions */ +static int +macb_new_rxbuf(struct macb_softc *sc, int index); + +static void +macb_free_desc_dma_tx(struct macb_softc *sc); + +static void +macb_free_desc_dma_rx(struct macb_softc *sc); + +static void +macb_init_desc_dma_tx(struct macb_softc *sc); + +static void +macb_watchdog(struct macb_softc *sc); + +static int macb_intr_rx_locked(struct macb_softc *sc, int count); +static void macb_intr_task(void *arg, int pending __unused); +static void macb_tx_task(void *arg, int pending __unused); +static void macb_intr(void *xsc); + +static void +macb_tx_cleanup(struct macb_softc *sc); + +static inline int +phy_write(struct macb_softc *sc, int phy, int reg, int data); + +static void macb_reset(struct macb_softc *sc); + +static void +macb_deactivate(device_t dev) +{ + struct macb_softc *sc; + + sc = device_get_softc(dev); + + macb_free_desc_dma_tx(sc); + macb_free_desc_dma_rx(sc); + +} + +static void +macb_getaddr(void *arg, bus_dma_segment_t *segs, int nsegs, int error) +{ + bus_addr_t *paddr; + + KASSERT(nsegs == 1, ("wrong number of segments, should be 1")); + paddr = arg; + *paddr = segs->ds_addr; +} + +static int +macb_alloc_desc_dma_tx(struct macb_softc *sc) +{ + int error, i; + + /* Allocate a busdma tag and DMA safe memory for TX/RX descriptors. */ + error = bus_dma_tag_create(sc->sc_parent_tag, /* parent */ + 16, 0, /* alignment, boundary */ + BUS_SPACE_MAXADDR, /* lowaddr */ + BUS_SPACE_MAXADDR, /* highaddr */ + NULL, NULL, /* filtfunc, filtfuncarg */ + sizeof(struct eth_tx_desc) * MACB_MAX_TX_BUFFERS, /* max size */ + 1, /* nsegments */ + sizeof(struct eth_tx_desc) * MACB_MAX_TX_BUFFERS, + 0, /* flags */ + NULL, NULL, /* lockfunc, lockfuncarg */ + &sc->dmatag_data_tx); /* dmat */ + if (error != 0) { + device_printf(sc->dev, + "Couldn't create TX descriptor dma tag\n"); + return (error); + } + /* Allocate memory for TX ring. */ + error = bus_dmamem_alloc(sc->dmatag_data_tx, + (void**)&(sc->desc_tx), BUS_DMA_NOWAIT | BUS_DMA_ZERO | + BUS_DMA_COHERENT, &sc->dmamap_ring_tx); + if (error != 0) { + device_printf(sc->dev, "failed to allocate TX dma memory\n"); + return (error); + } + /* Load Ring DMA. */ + error = bus_dmamap_load(sc->dmatag_data_tx, sc->dmamap_ring_tx, + sc->desc_tx, sizeof(struct eth_tx_desc) * MACB_MAX_TX_BUFFERS, + macb_getaddr, &sc->ring_paddr_tx, BUS_DMA_NOWAIT); + if (error != 0) { + device_printf(sc->dev, "can't load TX descriptor dma map\n"); + return (error); + } + /* Allocate a busdma tag for mbufs. No alignment restriction applys. */ + error = bus_dma_tag_create(sc->sc_parent_tag, /* parent */ + 1, 0, /* alignment, boundary */ + BUS_SPACE_MAXADDR, /* lowaddr */ + BUS_SPACE_MAXADDR, /* highaddr */ + NULL, NULL, /* filtfunc, filtfuncarg */ + MCLBYTES * MAX_FRAGMENT, /* maxsize */ + MAX_FRAGMENT, /* nsegments */ + MCLBYTES, 0, /* maxsegsz, flags */ + NULL, NULL, /* lockfunc, lockfuncarg */ + &sc->dmatag_ring_tx); /* dmat */ + if (error != 0) { + device_printf(sc->dev, "failed to create TX mbuf dma tag\n"); + return (error); + } + + for (i = 0; i < MACB_MAX_TX_BUFFERS; i++) { + /* Create dma map for each descriptor. */ + error = bus_dmamap_create(sc->dmatag_ring_tx, 0, + &sc->tx_desc[i].dmamap); + if (error != 0) { + device_printf(sc->dev, + "failed to create TX mbuf dma map\n"); + return (error); + } + } + return (0); +} + +static void +macb_free_desc_dma_tx(struct macb_softc *sc) +{ + struct tx_desc_info *td; + int i; + + /* TX buffers. */ + if (sc->dmatag_ring_tx != NULL) { + for (i = 0; i < MACB_MAX_TX_BUFFERS; i++) { + td = &sc->tx_desc[i]; + if (td->dmamap != NULL) { + bus_dmamap_destroy(sc->dmatag_ring_tx, + td->dmamap); + td->dmamap = NULL; + } + } + bus_dma_tag_destroy(sc->dmatag_ring_tx); + sc->dmatag_ring_tx = NULL; + } + + /* TX descriptor ring. */ + if (sc->dmatag_data_tx != NULL) { + if (sc->dmamap_ring_tx != NULL) + bus_dmamap_unload(sc->dmatag_data_tx, + sc->dmamap_ring_tx); + if (sc->dmamap_ring_tx != NULL && sc->desc_tx != NULL) + bus_dmamem_free(sc->dmatag_data_tx, sc->desc_tx, + sc->dmamap_ring_tx); + sc->dmamap_ring_tx = NULL; + sc->dmamap_ring_tx = NULL; + bus_dma_tag_destroy(sc->dmatag_data_tx); + sc->dmatag_data_tx = NULL; + } +} + +static void +macb_init_desc_dma_tx(struct macb_softc *sc) +{ + struct eth_tx_desc *desc; + int i; + + MACB_LOCK_ASSERT(sc); + + sc->tx_prod = 0; + sc->tx_cons = 0; + sc->tx_cnt = 0; + + desc = &sc->desc_tx[0]; + bzero(desc, sizeof(struct eth_tx_desc) * MACB_MAX_TX_BUFFERS); + + for (i = 0; i < MACB_MAX_TX_BUFFERS; i++) { + desc = &sc->desc_tx[i]; + if (i == MACB_MAX_TX_BUFFERS - 1) + desc->flags = TD_OWN | TD_WRAP_MASK; + else + desc->flags = TD_OWN; + } + + bus_dmamap_sync(sc->dmatag_data_tx, sc->dmamap_ring_tx, + BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); +} + +static int +macb_alloc_desc_dma_rx(struct macb_softc *sc) +{ + int error, i; + + /* Allocate a busdma tag and DMA safe memory for RX descriptors. */ + error = bus_dma_tag_create(sc->sc_parent_tag, /* parent */ + 16, 0, /* alignment, boundary */ + BUS_SPACE_MAXADDR, /* lowaddr */ + BUS_SPACE_MAXADDR, /* highaddr */ + NULL, NULL, /* filtfunc, filtfuncarg */ + /* maxsize, nsegments */ + sizeof(struct eth_rx_desc) * MACB_MAX_RX_BUFFERS, 1, + /* maxsegsz, flags */ + sizeof(struct eth_rx_desc) * MACB_MAX_RX_BUFFERS, 0, + NULL, NULL, /* lockfunc, lockfuncarg */ + &sc->dmatag_data_rx); /* dmat */ + if (error != 0) { + device_printf(sc->dev, + "Couldn't create RX descriptor dma tag\n"); + return (error); + } + /* Allocate RX ring. */ + error = bus_dmamem_alloc(sc->dmatag_data_rx, (void**)&(sc->desc_rx), + BUS_DMA_NOWAIT | BUS_DMA_ZERO | BUS_DMA_COHERENT, + &sc->dmamap_ring_rx); + if (error != 0) { + device_printf(sc->dev, + "failed to allocate RX descriptor dma memory\n"); + return (error); + } + + /* Load dmamap. */ + error = bus_dmamap_load(sc->dmatag_data_rx, sc->dmamap_ring_rx, + sc->desc_rx, sizeof(struct eth_rx_desc) * MACB_MAX_RX_BUFFERS, + macb_getaddr, &sc->ring_paddr_rx, BUS_DMA_NOWAIT); + if (error != 0) { + device_printf(sc->dev, "can't load RX descriptor dma map\n"); + return (error); + } + + /* Allocate a busdma tag for mbufs. */ + error = bus_dma_tag_create(sc->sc_parent_tag,/* parent */ + 16, 0, /* alignment, boundary */ + BUS_SPACE_MAXADDR, /* lowaddr */ + BUS_SPACE_MAXADDR, /* highaddr */ + NULL, NULL, /* filtfunc, filtfuncarg */ + MCLBYTES, 1, /* maxsize, nsegments */ + MCLBYTES, 0, /* maxsegsz, flags */ + NULL, NULL, /* lockfunc, lockfuncarg */ + &sc->dmatag_ring_rx); /* dmat */ + + if (error != 0) { + device_printf(sc->dev, "failed to create RX mbuf dma tag\n"); + return (error); + } + + for (i = 0; i < MACB_MAX_RX_BUFFERS; i++) { + error = bus_dmamap_create(sc->dmatag_ring_rx, 0, + &sc->rx_desc[i].dmamap); + if (error != 0) { + device_printf(sc->dev, + "failed to create RX mbuf dmamap\n"); + return (error); + } + } + + return (0); +} + +static void +macb_free_desc_dma_rx(struct macb_softc *sc) +{ + struct rx_desc_info *rd; + int i; + + /* RX buffers. */ + if (sc->dmatag_ring_rx != NULL) { + for (i = 0; i < MACB_MAX_RX_BUFFERS; i++) { + rd = &sc->rx_desc[i]; + if (rd->dmamap != NULL) { + bus_dmamap_destroy(sc->dmatag_ring_rx, + rd->dmamap); + rd->dmamap = NULL; + } + } + bus_dma_tag_destroy(sc->dmatag_ring_rx); + sc->dmatag_ring_rx = NULL; + } + /* RX descriptor ring. */ + if (sc->dmatag_data_rx != NULL) { + if (sc->dmamap_ring_rx != NULL) + bus_dmamap_unload(sc->dmatag_data_rx, + sc->dmamap_ring_rx); + if (sc->dmamap_ring_rx != NULL && + sc->desc_rx != NULL) + bus_dmamem_free(sc->dmatag_data_rx, sc->desc_rx, + sc->dmamap_ring_rx); + sc->desc_rx = NULL; + sc->dmamap_ring_rx = NULL; + bus_dma_tag_destroy(sc->dmatag_data_rx); + sc->dmatag_data_rx = NULL; + } +} + +static int +macb_init_desc_dma_rx(struct macb_softc *sc) +{ + struct eth_rx_desc *desc; + struct rx_desc_info *rd; + int i; + + MACB_LOCK_ASSERT(sc); + + sc->rx_cons = 0; + desc = &sc->desc_rx[0]; + bzero(desc, sizeof(struct eth_rx_desc) * MACB_MAX_RX_BUFFERS); + for (i = 0; i < MACB_MAX_RX_BUFFERS; i++) { + rd = &sc->rx_desc[i]; + rd->buff = NULL; + if (macb_new_rxbuf(sc, i) != 0) + return (ENOBUFS); + } + bus_dmamap_sync(sc->dmatag_ring_rx, sc->dmamap_ring_rx, + BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); + return (0); +} + +static int +macb_new_rxbuf(struct macb_softc *sc, int index) +{ + struct rx_desc_info *rd; + struct eth_rx_desc *desc; + struct mbuf *m; + bus_dma_segment_t seg[1]; + int error, nsegs; + + m = m_getcl(M_DONTWAIT, MT_DATA, M_PKTHDR); + if (m == NULL) + return (ENOBUFS); + m->m_len = m->m_pkthdr.len = MCLBYTES - ETHER_ALIGN; + rd = &sc->rx_desc[index]; + bus_dmamap_unload(sc->dmatag_ring_rx, rd->dmamap); + error = bus_dmamap_load_mbuf_sg(sc->dmatag_ring_rx, rd->dmamap, m, + seg, &nsegs, 0); + KASSERT(nsegs == 1, ("Too many segments returned!")); + if (error != 0) { + m_free(m); + return (error); + } + + bus_dmamap_sync(sc->dmatag_ring_rx, rd->dmamap, BUS_DMASYNC_PREREAD); + rd->buff = m; + + desc = &sc->desc_rx[index]; + desc->addr = seg[0].ds_addr; + + desc->flags = DATA_SIZE; + + if (index == MACB_MAX_RX_BUFFERS - 1) + desc->addr |= RD_WRAP_MASK; + + return (0); +} + +static int +macb_allocate_dma(struct macb_softc *sc) +{ + int error; + + /* Create parent tag for tx and rx */ + error = bus_dma_tag_create( + bus_get_dma_tag(sc->dev), /* parent */ + 1, 0, /* alignment, boundary */ + BUS_SPACE_MAXADDR_32BIT, /* lowaddr */ + BUS_SPACE_MAXADDR, /* highaddr */ + NULL, NULL, /* filter, filterarg */ + BUS_SPACE_MAXSIZE_32BIT, 0, /* maxsize, nsegments */ + BUS_SPACE_MAXSIZE_32BIT, /* maxsegsize */ + 0, /* flags */ + NULL, NULL, /* lockfunc, lockarg */ + &sc->sc_parent_tag); + if (error != 0) { + device_printf(sc->dev, "Couldn't create parent DMA tag\n"); + return (error); + } + + if ((error = macb_alloc_desc_dma_tx(sc)) != 0) + return (error); + if ((error = macb_alloc_desc_dma_rx(sc)) != 0) + return (error); + return (0); +} + + +static void +macb_tick(void *xsc) +{ + struct macb_softc *sc; + struct mii_data *mii; + + sc = xsc; + mii = device_get_softc(sc->miibus); + mii_tick(mii); + macb_watchdog(sc); + /* + * Schedule another timeout one second from now. + */ + callout_reset(&sc->tick_ch, hz, macb_tick, sc); +} + + +static void +macb_watchdog(struct macb_softc *sc) +{ + struct ifnet *ifp; + + MACB_LOCK_ASSERT(sc); + + if (sc->macb_watchdog_timer == 0 || --sc->macb_watchdog_timer) + return; + + ifp = sc->ifp; + if ((sc->flags & MACB_FLAG_LINK) == 0) { + if_printf(ifp, "watchdog timeout (missed link)\n"); + ifp->if_oerrors++; + return; + } + + if_printf(ifp, "watchdog timeout\n"); + ifp->if_oerrors++; + ifp->if_drv_flags &= ~IFF_DRV_RUNNING; + macbinit_locked(sc); + if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd)) + taskqueue_enqueue(sc->sc_tq, &sc->sc_tx_task); +} + + + +static void +macbinit_locked(void *xsc) +{ + struct macb_softc *sc; + struct ifnet *ifp; + int err; + uint32_t config; + struct mii_data *mii; + + sc = xsc; + ifp = sc->ifp; + + MACB_LOCK_ASSERT(sc); + + if ((ifp->if_drv_flags & IFF_DRV_RUNNING) != 0) + return; + + if ((err = macb_init_desc_dma_rx(sc)) != 0) { + device_printf(sc->dev, "no memory for RX buffers\n"); + //ecestop(sc); + return; + } + macb_init_desc_dma_tx(sc); + + config = read_4(sc, EMAC_NCFGR) | (sc->clock << 10); /*set clock*/ + config |= CFG_PAE; /* PAuse Enable */ + config |= CFG_DRFCS; /* Discard Rx FCS */ + config |= CFG_SPD; /* 100 mbps*/ + //config |= CFG_CAF; + config |= CFG_FD; + + config |= CFG_RBOF_2; /*offset +2*/ + + write_4(sc, EMAC_NCFGR, config); + + /* Initialize TX and RX buffers */ + write_4(sc, EMAC_RBQP, sc->ring_paddr_rx); + write_4(sc, EMAC_TBQP, sc->ring_paddr_tx); + + /* Enable TX and RX */ + write_4(sc, EMAC_NCR, RX_ENABLE | TX_ENABLE | MPE_ENABLE); + + + /* Enable interrupts */ + write_4(sc, EMAC_IER, (RCOMP_INTERRUPT | + RXUBR_INTERRUPT | + TUND_INTERRUPT | + RLE_INTERRUPT | + TXERR_INTERRUPT | + ROVR_INTERRUPT | + HRESP_INTERRUPT| + TCOMP_INTERRUPT + )); + + /* + * 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); + + sc->flags |= MACB_FLAG_LINK; + + mii_mediachg(mii); + + callout_reset(&sc->tick_ch, hz, macb_tick, sc); +} + + +static void +macb_tx_cleanup(struct macb_softc *sc) +{ + struct ifnet *ifp; + struct eth_tx_desc *desc; + struct tx_desc_info *td; + int flags; + int status; + int i; + + MACB_LOCK_ASSERT(sc); + + status = read_4(sc, EMAC_TSR); + + write_4(sc, EMAC_TSR, status); + + /*buffer underrun*/ + if ((status & TSR_UND) != 0) { + /*reset buffers*/ + printf("underrun\n"); + bus_dmamap_sync(sc->dmatag_data_tx, sc->dmamap_ring_tx, + BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); + sc->tx_cons = sc->tx_prod = 0; + for (i = 0; i < MACB_MAX_TX_BUFFERS; i++) { + desc = &sc->desc_tx[i]; + desc->flags = TD_OWN; + } + + for (i = 0; i < MACB_MAX_TX_BUFFERS; i++) { + td = &sc->tx_desc[i]; + if (td->buff != NULL) { + /* We are finished with this descriptor. */ + bus_dmamap_sync(sc->dmatag_ring_tx, td->dmamap, + BUS_DMASYNC_POSTWRITE); + /* ... and unload, so we can reuse. */ + bus_dmamap_unload(sc->dmatag_data_tx, + td->dmamap); + m_freem(td->buff); + td->buff = NULL; + } + } + } + + if ((status & TSR_COMP) == 0) + return; + + + if (sc->tx_cons == sc->tx_prod) + return; + + ifp = sc->ifp; + + /* Prepare to read the ring (owner bit). */ + bus_dmamap_sync(sc->dmatag_data_tx, sc->dmamap_ring_tx, + BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); + while (sc->tx_cons != sc->tx_prod) { + desc = &sc->desc_tx[sc->tx_cons]; + if ((desc->flags & TD_OWN) == 0) + break; + + td = &sc->tx_desc[sc->tx_cons]; + if (td->buff != NULL) { + /* We are finished with this descriptor. */ + bus_dmamap_sync(sc->dmatag_ring_tx, td->dmamap, + BUS_DMASYNC_POSTWRITE); + /* ... and unload, so we can reuse. */ + bus_dmamap_unload(sc->dmatag_data_tx, + td->dmamap); + m_freem(td->buff); + td->buff = NULL; + ifp->if_opackets++; + } + + do { + sc->tx_cnt--; + MACB_DESC_INC(sc->tx_cons, MACB_MAX_TX_BUFFERS); + ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; + flags = desc->flags; + desc->flags = TD_OWN; + desc = &sc->desc_tx[sc->tx_cons]; + if (flags & TD_LAST) { + break; + } + } while (sc->tx_cons != sc->tx_prod); + } + + /* Unarm watchog timer when there is no pending descriptors in queue. */ + if (sc->tx_cnt == 0) + sc->macb_watchdog_timer = 0; +} + +static void +macb_rx(struct macb_softc *sc) +{ + struct eth_rx_desc *rxdesc; + struct ifnet *ifp; + struct mbuf *m; + int rxbytes; + int flags; + int nsegs; + int first; + + rxdesc = &(sc->desc_rx[sc->rx_cons]); + + ifp = sc->ifp; + + bus_dmamap_sync(sc->dmatag_ring_rx, sc->dmamap_ring_rx, + BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); + + + nsegs = 0; + while (rxdesc->addr & RD_OWN) { + + if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) + break; + + flags = rxdesc->flags; + + rxbytes = flags & RD_LEN_MASK; + + m = sc->rx_desc[sc->rx_cons].buff; + + bus_dmamap_sync(sc->dmatag_ring_rx, + sc->rx_desc[sc->rx_cons].dmamap, BUS_DMASYNC_POSTREAD); + if (macb_new_rxbuf(sc, sc->rx_cons) != 0) { + ifp->if_iqdrops++; + first = sc->rx_cons; + + do { + rxdesc->flags = DATA_SIZE; + MACB_DESC_INC(sc->rx_cons, MACB_MAX_RX_BUFFERS); + if ((rxdesc->flags & RD_EOF) != 0) + break; + rxdesc = &(sc->desc_rx[sc->rx_cons]); + } while (sc->rx_cons != first); + + if (sc->macb_cdata.rxhead != NULL) { + m_freem(sc->macb_cdata.rxhead); + sc->macb_cdata.rxhead = NULL; + sc->macb_cdata.rxtail = NULL; + } + + break; + } + + nsegs++; + + /* Chain received mbufs. */ + if (sc->macb_cdata.rxhead == NULL) { + m->m_data += 2; + sc->macb_cdata.rxhead = m; + sc->macb_cdata.rxtail = m; + if (flags & RD_EOF) + m->m_len = rxbytes; + else + m->m_len = DATA_SIZE - 2; + } else { + m->m_flags &= ~M_PKTHDR; + m->m_len = DATA_SIZE; + sc->macb_cdata.rxtail->m_next = m; + sc->macb_cdata.rxtail = m; + } + + if (flags & RD_EOF) { + + if (nsegs > 1) { + sc->macb_cdata.rxtail->m_len = (rxbytes - + ((nsegs - 1) * DATA_SIZE)) + 2; + } + + m = sc->macb_cdata.rxhead; + m->m_flags |= M_PKTHDR; + m->m_pkthdr.len = rxbytes; + m->m_pkthdr.rcvif = ifp; + ifp->if_ipackets++; + + nsegs = 0; + MACB_UNLOCK(sc); + (*ifp->if_input)(ifp, m); + MACB_LOCK(sc); + sc->macb_cdata.rxhead = NULL; + sc->macb_cdata.rxtail = NULL; + + } + + rxdesc->addr &= ~RD_OWN; + + MACB_DESC_INC(sc->rx_cons, MACB_MAX_RX_BUFFERS); + + rxdesc = &(sc->desc_rx[sc->rx_cons]); + } + + write_4(sc, EMAC_IER, (RCOMP_INTERRUPT|RXUBR_INTERRUPT)); + +} + +static int +macb_intr_rx_locked(struct macb_softc *sc, int count) +{ + macb_rx(sc); + return (0); +} + +static void +macb_intr_task(void *arg, int pending __unused) +{ + struct macb_softc *sc; + + sc = arg; + MACB_LOCK(sc); + macb_intr_rx_locked(sc, -1); + MACB_UNLOCK(sc); +} + +static void +macb_intr(void *xsc) +{ + struct macb_softc *sc; + struct ifnet *ifp; + uint32_t status; + + sc = xsc; + ifp = sc->ifp; + if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) { + printf("not running\n"); + return; + } + + status = read_4(sc, EMAC_ISR); + + while (status) { + if (status & RCOMP_INTERRUPT) { + write_4(sc, EMAC_IDR, (RCOMP_INTERRUPT|RXUBR_INTERRUPT)); + taskqueue_enqueue(sc->sc_tq, &sc->sc_intr_task); + } + + if (status & TCOMP_INTERRUPT) { + MACB_LOCK(sc); + macb_tx_cleanup(sc); + MACB_UNLOCK(sc); + } + + status = read_4(sc, EMAC_ISR); + } + + if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd)) + taskqueue_enqueue(sc->sc_tq, &sc->sc_tx_task); +} + +static inline int +macb_encap(struct macb_softc *sc, struct mbuf **m_head) +{ + struct eth_tx_desc *desc; + struct tx_desc_info *txd, *txd_last; + struct mbuf *m; + bus_dma_segment_t segs[MAX_FRAGMENT]; + bus_dmamap_t map; + uint32_t csum_flags; + int error, i, nsegs, prod, si; + + M_ASSERTPKTHDR((*m_head)); + + prod = sc->tx_prod; + + m = *m_head; + + txd = txd_last = &sc->tx_desc[prod]; + error = bus_dmamap_load_mbuf_sg(sc->dmatag_ring_tx, txd->dmamap, + *m_head, segs, &nsegs, 0); + if (error == EFBIG) { + m = m_collapse(*m_head, M_DONTWAIT, MAX_FRAGMENT); + if (m == NULL) { + m_freem(*m_head); + *m_head = NULL; + return (ENOMEM); + } + *m_head = m; + error = bus_dmamap_load_mbuf_sg(sc->dmatag_ring_tx, txd->dmamap, + *m_head, segs, &nsegs, 0); + if (error != 0) { + m_freem(*m_head); + *m_head = NULL; + return (error); + } + } else if (error != 0) { + return (error); + } + /* Check for TX descriptor overruns. */ + if (sc->tx_cnt + nsegs > MACB_MAX_TX_BUFFERS - 1) { + bus_dmamap_unload(sc->dmatag_ring_tx, txd->dmamap); + return (ENOBUFS); + } + bus_dmamap_sync(sc->dmatag_ring_tx, txd->dmamap, BUS_DMASYNC_PREWRITE); + m = *m_head; + + /* TODO: VLAN hardware tag insertion. */ + + csum_flags = 0; + si = prod; + desc = NULL; + + for (i = 0; i < nsegs; i++) { + desc = &sc->desc_tx[prod]; + desc->addr = segs[i].ds_addr; + + if (i == 0 ) { + desc->flags = segs[i].ds_len | TD_OWN; + } else { + desc->flags = segs[i].ds_len; + } + + if (prod == MACB_MAX_TX_BUFFERS - 1) + desc->flags |= TD_WRAP_MASK; + + sc->tx_cnt++; + MACB_DESC_INC(prod, MACB_MAX_TX_BUFFERS); + } + /* + * Set EOP on the last fragment. + */ + + desc->flags |= TD_LAST; + desc = &sc->desc_tx[si]; + desc->flags &= ~TD_OWN; + + sc->tx_prod = prod; + + /* Swap the first dma map and the last. */ + map = txd_last->dmamap; + txd_last->dmamap = txd->dmamap; + txd->dmamap = map; + txd->buff = m; + + return (0); +} + + +static void +macbstart_locked(struct ifnet *ifp) +{ + + + + struct macb_softc *sc; + struct mbuf *m0; +#if 0 + struct mbuf *m_new; +#endif + int queued = 0; + + sc = ifp->if_softc; + + if ((ifp->if_drv_flags & (IFF_DRV_RUNNING | IFF_DRV_OACTIVE)) != + IFF_DRV_RUNNING || (sc->flags & MACB_FLAG_LINK) == 0) { + return; + } + + while (!IFQ_DRV_IS_EMPTY(&ifp->if_snd)) { + /* Get packet from the queue */ + IF_DEQUEUE(&ifp->if_snd, m0); + if (m0 == NULL) + break; +#if 0 + if (m0->m_next != NULL) { + /* Fragmented mbuf chain, collapse it. */ + m_new = m_defrag(m0, M_DONTWAIT); + if (m_new != NULL) { + /* Original frame freed. */ + m0 = m_new; + } else { + /* Defragmentation failed, just use the chain. */ + } + } +#endif + if (macb_encap(sc, &m0)) { + if (m0 == NULL) + break; + IF_PREPEND(&ifp->if_snd, m0); + ifp->if_drv_flags |= IFF_DRV_OACTIVE; + break; + } + queued++; + BPF_MTAP(ifp, m0); + } + if (IFQ_DRV_IS_EMPTY(&ifp->if_snd)) + ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; + if (queued) { + bus_dmamap_sync(sc->dmatag_data_tx, sc->dmamap_ring_tx, + BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); + write_4(sc, EMAC_NCR, read_4(sc, EMAC_NCR) | TRANSMIT_START); + sc->macb_watchdog_timer = MACB_TIMEOUT; + } +} + +static void +macbinit(void *xsc) +{ + struct macb_softc *sc = xsc; + + MACB_LOCK(sc); + macbinit_locked(sc); + MACB_UNLOCK(sc); +} + +static void +macbstart(struct ifnet *ifp) +{ + struct macb_softc *sc = ifp->if_softc; + MACB_ASSERT_UNLOCKED(sc); + MACB_LOCK(sc); + macbstart_locked(ifp); + MACB_UNLOCK(sc); + +} + + +static void +macb_tx_task(void *arg, int pending __unused) +{ + struct ifnet *ifp; + + ifp = (struct ifnet *)arg; + macbstart(ifp); +} + + +static void +macbstop(struct macb_softc *sc) +{ + struct ifnet *ifp = sc->ifp; + struct rx_desc_info *rd; + struct tx_desc_info *td; + int i; + + ifp = sc->ifp; + + ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE); + + macb_reset(sc); + + sc->flags &= ~MACB_FLAG_LINK; + callout_stop(&sc->tick_ch); + sc->macb_watchdog_timer = 0; + + /* Free TX/RX mbufs still in the queues. */ + for (i = 0; i < MACB_MAX_TX_BUFFERS; i++) { + td = &sc->tx_desc[i]; + if (td->buff != NULL) { + bus_dmamap_sync(sc->dmatag_ring_tx, td->dmamap, + BUS_DMASYNC_POSTWRITE); + bus_dmamap_unload(sc->dmatag_data_tx, td->dmamap); + m_freem(td->buff); + td->buff = NULL; + } + } + for (i = 0; i < MACB_MAX_RX_BUFFERS; i++) { + rd = &sc->rx_desc[i]; + if (rd->buff != NULL) { + bus_dmamap_sync(sc->dmatag_ring_rx, rd->dmamap, + BUS_DMASYNC_POSTREAD); + bus_dmamap_unload(sc->dmatag_data_rx, rd->dmamap); + m_freem(rd->buff); + rd->buff = NULL; + } + } +} + +static int +get_hash_index(uint8_t *mac) +{ + int i, j, k; + int result; + int bit; + + result = 0; + for (i = 0; i < 6; i++) { + bit = 0; + for (j = 0; j < 8; j++) { + k = j * 6 + i; + bit ^= (mac[k/8] & (1 << (k % 8)) ) != 0; + } + result |= bit; + } + return result; +} + +static void +set_mac_filter(uint32_t *filter, uint8_t *mac) +{ + int bits; + + bits = get_hash_index(mac); + filter[bits >> 5] |= 1 << (bits & 31); +} + +static void +set_filter(struct macb_softc *sc) +{ + struct ifnet *ifp; + struct ifmultiaddr *ifma; + int config; + int count; + uint32_t multicast_filter[2]; + + ifp = sc->ifp; + + config = read_4(sc, EMAC_NCFGR); + + config &= ~(CFG_CAF | CFG_MTI); + write_4(sc, EMAC_HRB, 0); + write_4(sc, EMAC_HRT, 0); + + if ((ifp->if_flags & (IFF_ALLMULTI |IFF_PROMISC)) != 0){ + if ((ifp->if_flags & IFF_ALLMULTI) != 0) { + write_4(sc, EMAC_HRB, ~0); + write_4(sc, EMAC_HRT, ~0); + config |= CFG_MTI; + } + if ((ifp->if_flags & IFF_PROMISC) != 0) { + config |= CFG_CAF; + } + write_4(sc, EMAC_NCFGR, config); + return; + } + + if_maddr_rlock(ifp); + count = 0; + multicast_filter[0] = 0; + multicast_filter[1] = 0; + + TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { + if (ifma->ifma_addr->sa_family != AF_LINK) + continue; + count++; + set_mac_filter(multicast_filter, + LLADDR((struct sockaddr_dl *)ifma->ifma_addr)); + } + if (count) { + write_4(sc, EMAC_HRB, multicast_filter[0]); + write_4(sc, EMAC_HRT, multicast_filter[1]); + write_4(sc, EMAC_NCFGR, config|CFG_MTI); + } + if_maddr_runlock(ifp); +} + +static int +macbioctl(struct ifnet * ifp, u_long cmd, caddr_t data) +{ + + struct macb_softc *sc = ifp->if_softc; + struct mii_data *mii; + struct ifreq *ifr = (struct ifreq *)data; + + int error = 0; + + switch (cmd) { + case SIOCSIFFLAGS: + MACB_LOCK(sc); + + if ((ifp->if_flags & IFF_UP) != 0) { + if ((ifp->if_drv_flags & IFF_DRV_RUNNING) != 0) { + if (((ifp->if_flags ^ sc->if_flags) + & (IFF_PROMISC | IFF_ALLMULTI)) != 0) + set_filter(sc); + } else { + macbinit_locked(sc); + } + } else if ((ifp->if_drv_flags & IFF_DRV_RUNNING) != 0) { + macbstop(sc); + } + sc->if_flags = ifp->if_flags; + MACB_UNLOCK(sc); + break; + case SIOCADDMULTI: + case SIOCDELMULTI: + MACB_LOCK(sc); + if ((ifp->if_drv_flags & IFF_DRV_RUNNING) != 0) + set_filter(sc); + + MACB_UNLOCK(sc); + break; + case SIOCSIFMEDIA: + case SIOCGIFMEDIA: + mii = device_get_softc(sc->miibus); + error = ifmedia_ioctl(ifp, ifr, &mii->mii_media, cmd); + break; + default: + error = ether_ioctl(ifp, cmd, data); + break; + } + return (error); + +} + +/* bus entry points */ + +static int +macb_probe(device_t dev) +{ + device_set_desc(dev, "macb"); + return (0); +} + +/* + * Change media according to request. + */ +static int +macb_ifmedia_upd(struct ifnet *ifp) +{ + struct macb_softc *sc = ifp->if_softc; + struct mii_data *mii; + + mii = device_get_softc(sc->miibus); + MACB_LOCK(sc); + mii_mediachg(mii); + MACB_UNLOCK(sc); + return (0); +} + +/* + * Notify the world which media we're using. + */ +static void +macb_ifmedia_sts(struct ifnet *ifp, struct ifmediareq *ifmr) +{ + struct macb_softc *sc = ifp->if_softc; + struct mii_data *mii; + + mii = device_get_softc(sc->miibus); + + MACB_LOCK(sc); + /* Don't report link state if driver is not running. */ + if ((ifp->if_flags & IFF_UP) == 0) { + MACB_UNLOCK(sc); + return; + } + mii_pollstat(mii); + ifmr->ifm_active = mii->mii_media_active; + ifmr->ifm_status = mii->mii_media_status; + MACB_UNLOCK(sc); +} + +static void +macb_reset(struct macb_softc *sc) +{ + /* + * Disable RX and TX + */ + write_4(sc, EMAC_NCR, 0); + + write_4(sc, EMAC_NCR, CLEAR_STAT); + + /* Clear all status flags */ + write_4(sc, EMAC_TSR, ~0UL); + write_4(sc, EMAC_RSR, ~0UL); + + /* Disable all interrupts */ + write_4(sc, EMAC_IDR, ~0UL); + read_4(sc, EMAC_ISR); + +} + + +static int +macb_get_mac(struct macb_softc *sc, u_char *eaddr) +{ + uint32_t bottom; + uint16_t top; + + bottom = read_4(sc, EMAC_SA1B); + top = read_4(sc, EMAC_SA1T); + + eaddr[0] = bottom & 0xff; + eaddr[1] = (bottom >> 8) & 0xff; + eaddr[2] = (bottom >> 16) & 0xff; + eaddr[3] = (bottom >> 24) & 0xff; + eaddr[4] = top & 0xff; + eaddr[5] = (top >> 8) & 0xff; + + return (0); +} + + +static int +macb_attach(device_t dev) +{ + struct macb_softc *sc; + struct ifnet *ifp = NULL; + struct sysctl_ctx_list *sctx; + struct sysctl_oid *soid; + int pclk_hz; + u_char eaddr[ETHER_ADDR_LEN]; + int rid; + int err; + struct at91_pmc_clock *master; + + + err = 0; + + sc = device_get_softc(dev); + sc->dev = dev; + + MACB_LOCK_INIT(sc); + + callout_init_mtx(&sc->tick_ch, &sc->sc_mtx, 0); + + /* + * Allocate resources. + */ + 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; + } + + 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 clock*/ + sc->clk = at91_pmc_clock_ref("macb_clk"); + at91_pmc_clock_enable(sc->clk); + + macb_reset(sc); + macb_get_mac(sc, eaddr); + + master = at91_pmc_clock_ref("mck"); + + pclk_hz = master->hz; + + sc->clock = CFG_CLK_8; + if (pclk_hz <= 20000000) + sc->clock = CFG_CLK_8; + else if (pclk_hz <= 40000000) + sc->clock = CFG_CLK_16; + else if (pclk_hz <= 80000000) + sc->clock = CFG_CLK_32; + else + sc->clock = CFG_CLK_64; + + sc->clock = sc->clock << 10; + + write_4(sc, EMAC_NCFGR, sc->clock); + write_4(sc, EMAC_USRIO, USRIO_CLOCK); //enable clock + + write_4(sc, EMAC_NCR, MPE_ENABLE); //enable MPE + + sc->ifp = ifp = if_alloc(IFT_ETHER); + if (mii_phy_probe(dev, &sc->miibus, macb_ifmedia_upd, macb_ifmedia_sts)) { + device_printf(dev, "Cannot find my PHY.\n"); + err = ENXIO; + goto out; + } + + if (macb_allocate_dma(sc) != 0) + goto out; + + /* Sysctls */ + sctx = device_get_sysctl_ctx(dev); + soid = device_get_sysctl_tree(dev); + + 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 = macbstart; + ifp->if_ioctl = macbioctl; + ifp->if_init = macbinit; + IFQ_SET_MAXLEN(&ifp->if_snd, IFQ_MAXLEN); + ifp->if_snd.ifq_drv_maxlen = IFQ_MAXLEN; + IFQ_SET_READY(&ifp->if_snd); + sc->if_flags = ifp->if_flags; + + TASK_INIT(&sc->sc_intr_task, 0, macb_intr_task, sc); + TASK_INIT(&sc->sc_tx_task, 0, macb_tx_task, ifp); + + sc->sc_tq = taskqueue_create_fast("macb_taskq", M_WAITOK, + taskqueue_thread_enqueue, &sc->sc_tq); + if (sc->sc_tq == NULL) { + device_printf(sc->dev, "could not create taskqueue\n"); + goto out; + } + + ether_ifattach(ifp, eaddr); + + /* + * Activate the interrupt. + */ + err = bus_setup_intr(dev, sc->irq_res, INTR_TYPE_NET | INTR_MPSAFE, + NULL, macb_intr, sc, &sc->intrhand); + if (err) { + device_printf(dev, "could not establish interrupt handler.\n"); + ether_ifdetach(ifp); + goto out; + } + + taskqueue_start_threads(&sc->sc_tq, 1, PI_NET, "%s taskq", + device_get_nameunit(sc->dev)); + + sc->macb_cdata.rxhead = 0; + sc->macb_cdata.rxtail = 0; + + phy_write(sc, 0, 0, 0x3300); //force autoneg + + return (0); +out: + + return (err); +} + +static int +macb_detach(device_t dev) +{ + struct macb_softc *sc; + + sc = device_get_softc(dev); + macbstop(sc); + macb_deactivate(dev); + + return (0); +} + +/*PHY related functions*/ +static inline int +phy_read(struct macb_softc *sc, int phy, int reg) +{ + int val; + + write_4(sc, EMAC_MAN, EMAC_MAN_REG_RD(phy, reg)); + while ((read_4(sc, EMAC_SR) & EMAC_SR_IDLE) == 0) + continue; + val = read_4(sc, EMAC_MAN) & EMAC_MAN_VALUE_MASK; + + return (val); +} + +static inline int +phy_write(struct macb_softc *sc, int phy, int reg, int data) +{ + + write_4(sc, EMAC_MAN, EMAC_MAN_REG_WR(phy, reg, data)); + while ((read_4(sc, EMAC_SR) & EMAC_SR_IDLE) == 0) + continue; + + return (0); +} + +/* + * MII bus support routines. + */ +static int +macb_miibus_readreg(device_t dev, int phy, int reg) +{ + struct macb_softc *sc; + sc = device_get_softc(dev); + return (phy_read(sc, phy, reg)); +} + +static int +macb_miibus_writereg(device_t dev, int phy, int reg, int data) +{ + struct macb_softc *sc; + sc = device_get_softc(dev); + return (phy_write(sc, phy, reg, data)); +} + +static void +macb_child_detached(device_t dev, device_t child) +{ + struct macb_softc *sc; + sc = device_get_softc(dev); + +} + +static void +macb_miibus_statchg(device_t dev) +{ + struct macb_softc *sc; + struct mii_data *mii; + int config; + + sc = device_get_softc(dev); + + mii = device_get_softc(sc->miibus); + + sc->flags &= ~MACB_FLAG_LINK; + + config = read_4(sc, EMAC_NCFGR); + + if ((mii->mii_media_status & IFM_AVALID) != 0) { + switch (IFM_SUBTYPE(mii->mii_media_active)) { + case IFM_10_T: + config &= ~(CFG_SPD); + sc->flags |= MACB_FLAG_LINK; + break; + case IFM_100_TX: + config |= CFG_SPD; + sc->flags |= MACB_FLAG_LINK; + break; + default: + break; + } + } + + config |= CFG_FD; + write_4(sc, EMAC_NCFGR, config); +} + +static device_method_t macb_methods[] = { + /* Device interface */ + DEVMETHOD(device_probe, macb_probe), + DEVMETHOD(device_attach, macb_attach), + DEVMETHOD(device_detach, macb_detach), + + /* Bus interface */ + DEVMETHOD(bus_child_detached, macb_child_detached), + + /* MII interface */ + DEVMETHOD(miibus_readreg, macb_miibus_readreg), + DEVMETHOD(miibus_writereg, macb_miibus_writereg), + DEVMETHOD(miibus_statchg, macb_miibus_statchg), + { 0, 0 } +}; + +static driver_t macb_driver = { + "macb", + macb_methods, + sizeof(struct macb_softc), +}; + + +DRIVER_MODULE(macb, atmelarm, macb_driver, macb_devclass, 0, 0); +DRIVER_MODULE(miibus, macb, miibus_driver, miibus_devclass, 0, 0); +MODULE_DEPEND(macb, miibus, 1, 1, 1); +MODULE_DEPEND(macb, ether, 1, 1, 1); diff --git a/sys/arm/at91/if_macbreg.h b/sys/arm/at91/if_macbreg.h new file mode 100644 index 0000000..163d79d --- /dev/null +++ b/sys/arm/at91/if_macbreg.h @@ -0,0 +1,106 @@ +/* + * $FreeBSD$ + */ + +#ifndef MACB_REG_H +#define MACB_REG_H + +#define EMAC_NCR 0x00 +#define EMAC_NCFGR 0x04 +#define EMAC_TSR 0x14 +#define EMAC_RSR 0x20 +#define EMAC_ISR 0x24 +#define EMAC_IER 0x28 +#define EMAC_IDR 0x2C +#define EMAC_IMR 0x30 + + + +#define EMAC_RBQP 0x18 +#define EMAC_TBQP 0x1C + +#define EMAC_HRB 0x90 +#define EMAC_HRT 0x94 + +#define EMAC_SA1B 0x98 +#define EMAC_SA1T 0x9C + +#define EMAC_USRIO 0xC0 + +#define EMAC_MAN 0x34 /* EMAC PHY Maintenance Register */ +#define EMAC_SR 0x08 /* EMAC STatus Register */ +#define EMAC_SR_LINK (1U << 0) /* Reserved! */ +#define EMAC_SR_MDIO (1U << 1) /* MDIO pin status */ +#define EMAC_SR_IDLE (1U << 2) /* IDLE (PHY logic) */ + +#define RX_ENABLE (1 << 2) +#define TX_ENABLE (1 << 3) +#define MPE_ENABLE (1 << 4) + + +/* EMAC_MAN */ +#define EMAC_MAN_BITS 0x40020000 /* HIGH and CODE bits */ +#define EMAC_MAN_READ (2U << 28) +#define EMAC_MAN_WRITE (1U << 28) +#define EMAC_MAN_PHYA_BIT 23 +#define EMAC_MAN_REGA_BIT 18 +#define EMAC_MAN_VALUE_MASK 0xffffU +#define EMAC_MAN_REG_WR(phy, reg, val) \ + (EMAC_MAN_BITS | EMAC_MAN_WRITE | ((phy) << EMAC_MAN_PHYA_BIT) | \ + ((reg) << EMAC_MAN_REGA_BIT) | ((val) & EMAC_MAN_VALUE_MASK)) + +#define EMAC_MAN_REG_RD(phy, reg) \ + (EMAC_MAN_BITS | EMAC_MAN_READ | ((phy) << EMAC_MAN_PHYA_BIT) | \ + ((reg) << EMAC_MAN_REGA_BIT)) + +#define RCOMP_INTERRUPT (1 << 1) +#define RXUBR_INTERRUPT (1 << 2) +#define TUBR_INTERRUPT (1 << 3) +#define TUND_INTERRUPT (1 << 4) +#define RLE_INTERRUPT (1 << 5) +#define TXERR_INTERRUPT (1 << 6) +#define ROVR_INTERRUPT (1 << 10) +#define HRESP_INTERRUPT (1 << 11) +#define TCOMP_INTERRUPT (1 << 7) + +#define CLEAR_STAT (1 << 5) + +#define TRANSMIT_START (1 << 9) +#define TRANSMIT_STOP (1 << 10) + +/*Transmit status register flags*/ +#define TSR_UND (1 << 6) +#define TSR_COMP (1 << 5) +#define TSR_BEX (1 << 4) +#define TSR_TGO (1 << 3) +#define TSR_RLE (1 << 2) +#define TSR_COL (1 << 1) +#define TSR_UBR (1 << 0) + +#define CFG_SPD (1 << 0) +#define CFG_FD (1 << 1) +#define CFG_CAF (1 << 4) +#define CFG_NBC (1 << 5) +#define CFG_MTI (1 << 6) +#define CFG_UNI (1 << 7) +#define CFG_BIG (1 << 8) + +#define CFG_CLK_8 (0) +#define CFG_CLK_16 (1) +#define CFG_CLK_32 (2) +#define CFG_CLK_64 (3) + +#define CFG_PAE (1 << 13) + +#define CFG_RBOF_0 (0 << 14) +#define CFG_RBOF_1 (1 << 14) +#define CFG_RBOF_2 (2 << 14) +#define CFG_RBOF_3 (3 << 14) + +#define CFG_DRFCS (1 << 17) + +#define USRIO_CLOCK (1 << 1) + + + +#endif diff --git a/sys/arm/at91/if_macbvar.h b/sys/arm/at91/if_macbvar.h new file mode 100644 index 0000000..9a187ae --- /dev/null +++ b/sys/arm/at91/if_macbvar.h @@ -0,0 +1,138 @@ +/* + * $FreeBSD$ + */ + +#ifndef _IF_MACB_H +#define _IF_MACB_H + +#define MACB_MAX_TX_BUFFERS 64 +#define MACB_MAX_RX_BUFFERS 256 + +#define MAX_FRAGMENT 20 +#define DATA_SIZE 128 + +#define MACB_DESC_INC(x, y) ((x) = ((x) + 1) % (y)) + +#define MACB_TIMEOUT 1000 + +struct eth_tx_desc { + uint32_t addr; + uint32_t flags; +#define TD_OWN (1 << 31) +#define TD_LAST (1 << 15) +#define TD_WRAP_MASK (1 << 30) +}; + +struct eth_rx_desc { + uint32_t addr; +#define RD_LEN_MASK 0x7ff +#define RD_WRAP_MASK 0x00000002 +#define RD_OWN 0x00000001 + + uint32_t flags; +#define RD_BROADCAST (1 << 31) +#define RD_MULTICAST (1 << 30) +#define RD_UNICAST (1 << 29) +#define RD_EXTERNAL (1 << 28) +#define RD_TYPE_ID (1 << 22) +#define RD_PRIORITY (1 << 20) +#define RD_VLAN (1 << 21) +#define RD_CONCAT (1 << 16) +#define RD_EOF (1 << 15) +#define RD_SOF (1 << 14) +#define RD_OFFSET_MASK (1 << 13)|(1 << 12) +#define RD_LENGTH_MASK (0x00000FFF) + +}; + + +struct rx_desc_info { + struct mbuf *buff; + bus_dmamap_t dmamap; +}; + +struct tx_desc_info { + struct mbuf *buff; + bus_dmamap_t dmamap; +}; + + +struct macb_chain_data{ + struct mbuf *rxhead; + struct mbuf *rxtail; +}; + +struct macb_softc +{ + struct ifnet *ifp; /* ifnet pointer */ + struct mtx sc_mtx; /* global mutex */ + + bus_dma_tag_t sc_parent_tag; /* parent bus DMA tag */ + + device_t dev; /* Myself */ + device_t miibus; /* My child miibus */ + void *intrhand; /* Interrupt handle */ + void *intrhand_qf; /* queue full */ + void *intrhand_tx; /* tx complete */ + void *intrhand_status; /* error status */ + + struct resource *irq_res; /* transmit */ + struct resource *irq_res_rec; /* receive */ + struct resource *irq_res_qf; /* queue full */ + struct resource *irq_res_status; /* status */ + + struct resource *mem_res; /* Memory resource */ + + struct callout tick_ch; /* Tick callout */ + + struct taskqueue *sc_tq; + struct task sc_intr_task; + struct task sc_tx_task; + struct task sc_link_task; + + bus_dmamap_t dmamap_ring_tx; + bus_dmamap_t dmamap_ring_rx; + + /*dma tag for ring*/ + bus_dma_tag_t dmatag_ring_tx; + bus_dma_tag_t dmatag_ring_rx; + + /*dma tag for data*/ + bus_dma_tag_t dmatag_data_tx; + bus_dma_tag_t dmatag_data_rx; + + /*the ring*/ + struct eth_tx_desc *desc_tx; + struct eth_rx_desc *desc_rx; + + /*ring physical address*/ + bus_addr_t ring_paddr_tx; + bus_addr_t ring_paddr_rx; + + /*index of last received descriptor*/ + int rx_cons; + struct rx_desc_info rx_desc[MACB_MAX_RX_BUFFERS]; + + /* tx producer index */ + uint32_t tx_prod; + /* tx consumer index */ + uint32_t tx_cons; + int tx_cnt; + + struct tx_desc_info tx_desc[MACB_MAX_TX_BUFFERS]; + + int macb_watchdog_timer; + +#define MACB_FLAG_LINK 0x0001 + + int flags; + int if_flags; + struct at91_pmc_clock *clk; + + struct macb_chain_data macb_cdata; + int clock; +}; + + + +#endif diff --git a/sys/arm/at91/std.at91sam9 b/sys/arm/at91/std.at91sam9 new file mode 100644 index 0000000..96aeb2b --- /dev/null +++ b/sys/arm/at91/std.at91sam9 @@ -0,0 +1,6 @@ +# $FreeBSD$ + +files "../at91/files.at91sam9" +cpu CPU_ARM9 +makeoptions CONF_CFLAGS="-mcpu=arm9 -DAT91SAM9G20" +options PHYSADDR=0x20000000 diff --git a/sys/arm/at91/std.hl201 b/sys/arm/at91/std.hl201 new file mode 100644 index 0000000..2d7d926 --- /dev/null +++ b/sys/arm/at91/std.hl201 @@ -0,0 +1,11 @@ +#$FreeBSD$ +include "../at91/std.at91sam9" + +options STARTUP_PAGETABLE_ADDR=0x20800000 +makeoptions KERNPHYSADDR=0x20000000 +makeoptions KERNVIRTADDR=0xc0000000 +options KERNPHYSADDR=0x20000000 +options KERNVIRTADDR=0xc0000000 +options AT91C_MASTER_CLOCK=132000000 + +device at91_board_hl201 |