summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorcognet <cognet@FreeBSD.org>2010-07-14 00:48:53 +0000
committercognet <cognet@FreeBSD.org>2010-07-14 00:48:53 +0000
commit9de4c6a9a1c39daabb84260eb8a8e4462290febe (patch)
treeec1c5e565c6153af8cb5a3611ba70ac768aa6521
parent2c68ec74a2e424c0c71c8da31650a45909f8222a (diff)
downloadFreeBSD-src-9de4c6a9a1c39daabb84260eb8a8e4462290febe.zip
FreeBSD-src-9de4c6a9a1c39daabb84260eb8a8e4462290febe.tar.gz
Import preliminary support for Atmel AT91SAM9G20 cpu, and the Hot-e HL201.
This fine work was done by Yohanes Nugroho <yohanes a gmail dot com> Many thanks to John Nicholls and Thinlinx for providing sample hardware.
-rw-r--r--sys/arm/at91/at91_aicreg.h51
-rw-r--r--sys/arm/at91/at91_pio_sam9.h291
-rw-r--r--sys/arm/at91/at91_pit.c233
-rw-r--r--sys/arm/at91/at91_pitreg.h45
-rw-r--r--sys/arm/at91/at91_pmc.c57
-rw-r--r--sys/arm/at91/at91_pmcreg.h16
-rw-r--r--sys/arm/at91/at91sam9.c717
-rw-r--r--sys/arm/at91/at91sam9_machdep.c420
-rw-r--r--sys/arm/at91/at91sam9g20reg.h254
-rw-r--r--sys/arm/at91/board_hl201.c42
-rw-r--r--sys/arm/at91/files.at91sam927
-rw-r--r--sys/arm/at91/if_macb.c1581
-rw-r--r--sys/arm/at91/if_macbreg.h106
-rw-r--r--sys/arm/at91/if_macbvar.h138
-rw-r--r--sys/arm/at91/std.at91sam96
-rw-r--r--sys/arm/at91/std.hl20111
-rw-r--r--sys/arm/conf/HL201133
-rw-r--r--sys/arm/conf/HL201.hints68
18 files changed, 4193 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
diff --git a/sys/arm/conf/HL201 b/sys/arm/conf/HL201
new file mode 100644
index 0000000..6524cc6
--- /dev/null
+++ b/sys/arm/conf/HL201
@@ -0,0 +1,133 @@
+# Kernel configuration for the AT91SAM9 based Hot-e configuration file
+#
+# For more information on this file, please read the handbook section on
+# Kernel Configuration Files:
+#
+# http://www.FreeBSD.org/doc/en_US.ISO8859-1/books/handbook/kernelconfig-config.html
+#
+# The handbook is also available locally in /usr/share/doc/handbook
+# if you've installed the doc distribution, otherwise always see the
+# FreeBSD World Wide Web server (http://www.FreeBSD.org/) for the
+# latest information.
+#
+# An exhaustive list of options and more detailed explanations of the
+# device lines is also present in the ../../conf/NOTES and NOTES files.
+# If you are in doubt as to the purpose or necessity of a line, check first
+# in NOTES.
+#
+# $FreeBSD$
+
+ident HL201
+
+include "../at91/std.hl201"
+
+#To statically compile in device wiring instead of /boot/device.hints
+hints "HL201.hints"
+makeoptions MODULES_OVERRIDE=""
+
+makeoptions DEBUG=-g #Build kernel with gdb(1) debug symbols
+options DDB
+options KDB
+
+options SCHED_4BSD #4BSD scheduler
+options INET #InterNETworking
+#options INET6 #IPv6 communications protocols
+options FFS #Berkeley Fast Filesystem
+#options SOFTUPDATES #Enable FFS soft updates support
+#options UFS_ACL #Support for access control lists
+#options UFS_DIRHASH #Improve performance on big directories
+#options MD_ROOT #MD is a potential root device
+#options MD_ROOT_SIZE=4096 # 3MB ram disk
+#options ROOTDEVNAME=\"ufs:/dev/mmcsd0s1a\"
+options NFSCLIENT #Network Filesystem Client
+#options NFSSERVER #Network Filesystem Server
+#options NFSLOCKD #Network Lock Manager
+options NFS_ROOT #NFS usable as /, requires NFSCLIENT
+options BOOTP_NFSROOT
+options BOOTP
+options BOOTP_NFSV3
+#options BOOTP_WIRED_TO=ate0
+options BOOTP_COMPAT
+
+options ALT_BREAK_TO_DEBUGGER
+
+#options MSDOSFS #MSDOS Filesystem
+#options CD9660 #ISO 9660 Filesystem
+#options PROCFS #Process filesystem (requires PSEUDOFS)
+options PSEUDOFS #Pseudo-filesystem framework
+#options SCSI_DELAY=5000 #Delay (in ms) before probing SCSI
+#options KTRACE #ktrace(1) support
+options SYSVSHM #SYSV-style shared memory
+options SYSVMSG #SYSV-style message queues
+options SYSVSEM #SYSV-style semaphores
+options _KPOSIX_PRIORITY_SCHEDULING #Posix P1003_1B real-time extensions
+#options SYSCTL_OMIT_DESCR
+options MUTEX_NOINLINE
+options RWLOCK_NOINLINE
+options NO_FFS_SNAPSHOT
+options NO_SWAPPING
+device random
+device pty
+device loop
+device ether
+device uart
+device macb
+device mii
+#device lxtphy
+
+# Debugging for use in -current
+#options INVARIANTS #Enable calls of extra sanity checking
+#options INVARIANT_SUPPORT #Extra sanity checks of internal structures, required by INVARIANTS
+#options WITNESS #Enable checks to detect deadlocks and cycles
+#options WITNESS_SKIPSPIN #Don't run witness on spinlocks for speed
+#options DIAGNOSTIC
+
+device md
+#device at91_twi # TWI: Two Wire Interface
+#device at91_spi # SPI:
+device spibus
+# MMC/SD
+#device at91_mci
+#device mmc
+#device mmcsd
+# iic
+device iic
+device iicbus
+device icee
+
+device bpf
+# USB support
+#device ohci # OHCI localbus->USB interface
+device usb # USB Bus (required)
+#device udbp # USB Double Bulk Pipe devices
+device uhid # "Human Interface Devices"
+#device ulpt # Printer
+device umass # Disks/Mass storage - Requires scbus and da
+
+# USB Ethernet, requires miibus
+device miibus
+#device aue # ADMtek USB Ethernet
+#device axe # ASIX Electronics USB Ethernet
+#device cdce # Generic USB over Ethernet
+#device cue # CATC USB Ethernet
+#device kue # Kawasaki LSI USB Ethernet
+#device rue # RealTek RTL8150 USB Ethernet
+device udav # Davicom DM9601E USB
+# USB Wireless
+#device rum # Ralink Technology RT2501USB wireless NICs
+#device uath # Atheros AR5523 wireless NICs
+#device ural # Ralink Technology RT2500USB wireless NICs
+#device zyd # ZyDAS zb1211/zb1211b wireless NICs
+# SCSI peripherals
+device scbus # SCSI bus (required for SCSI)
+device da # Direct Access (disks)
+device cd # CD
+device pass # Passthrough device (direct SCSI access)
+# Wireless NIC cards
+#device wlan # 802.11 support
+#device wlan_wep # 802.11 WEP support
+#device wlan_ccmp # 802.11 CCMP support
+#device wlan_tkip # 802.11 TKIP support
+#device wlan_amrr # AMRR transmit rate control algorithm
+options ROOTDEVNAME=\"ufs:da0s1a\"
+
diff --git a/sys/arm/conf/HL201.hints b/sys/arm/conf/HL201.hints
new file mode 100644
index 0000000..535001d
--- /dev/null
+++ b/sys/arm/conf/HL201.hints
@@ -0,0 +1,68 @@
+# $FreeBSD$
+#
+
+# These are the wiring for the at91sam9261. These are the built-in devices
+# for that cpu.
+
+# DBGU is unit 0
+hint.uart.0.at="apb"
+hint.uart.0.maddr="0xfffff200"
+hint.uart.0.flags=0x10
+# USART0 is unit 1
+hint.uart.1.at="apb"
+hint.uart.1.maddr="0xfffb0000"
+# USART1 is unit 2
+hint.uart.2.at="apb"
+hint.uart.2.maddr="0xfffb4000"
+# USART2 is unit 3
+hint.uart.3.at="apb"
+hint.uart.3.maddr="0xfffb8000"
+# USART3 is unit 4
+hint.uart.4.at="apb"
+hint.uart.4.maddr="0xfffbc000"
+
+# TC0, TC1, TC2
+hint.tc.0.at="apb"
+hint.tc.0.maddr="0xfffa0000"
+
+# USB Device
+hint.udp.0.at="apb"
+hint.udp.0.maddr="0xfffa4000"
+
+# MCI
+hint.mci.0.at="apb"
+hint.mci.0.maddr="0xfffa8000"
+
+# TWI
+hint.twi.0.at="apb"
+hint.twi.0.maddr="0xfffac000"
+
+# SSC0
+hint.ssc.0.at="apb"
+hint.ssc.0.maddr="0xfffbc000"
+# SSC1
+hint.ssc.1.at="apb"
+hint.ssc.1.maddr="0xfffc0000"
+# SSC2
+hint.ssc.1.at="apb"
+hint.ssc.1.maddr="0xfffc4000"
+
+# SPI0
+hint.spi.0.at="apb"
+hint.spi.0.maddr="0xfffc8000"
+# SSC1
+hint.spi.1.at="apb"
+hint.spi.1.maddr="0xfffcc000"
+
+# PMC
+hint.pmc.0.at="apb"
+hint.pmc.0.maddr="0xfffffc00"
+
+# USB host (ohci)
+#??? maybe this needs to be on asb instead of apb
+hint.ohci.at="apb"
+hint.ohci.maddr="0x00500000"
+# LCD controller
+hint.atlcd.at="apb"
+hint.atlcd.maddr="0x00600000"
+
OpenPOWER on IntegriCloud