[Zrouter-src-freebsd] ZRouter.org: push to FreeBSD HEAD tree

zrouter-src-freebsd at zrouter.org zrouter-src-freebsd at zrouter.org
Wed Aug 15 08:16:11 UTC 2012


details:   http://zrouter.org/hg/FreeBSD/head//rev/a301a330526b
changeset: 524:a301a330526b
user:      Aleksandr Rybalko <ray at ddteam.net>
date:      Wed Aug 15 11:16:36 2012 +0300
description:
Update arm to r239290.

diffstat:

 head/sys/arm/arm/bcopyinout.S                     |    79 +-
 head/sys/arm/arm/bcopyinout_xscale.S              |    35 +-
 head/sys/arm/arm/bus_space_asm_generic.S          |    18 +-
 head/sys/arm/arm/busdma_machdep-v6.c              |  1559 ++++++++
 head/sys/arm/arm/copystr.S                        |    37 +-
 head/sys/arm/arm/cpufunc.c                        |   542 ++-
 head/sys/arm/arm/cpufunc_asm.S                    |     6 +-
 head/sys/arm/arm/cpufunc_asm_arm11.S              |     7 +-
 head/sys/arm/arm/cpufunc_asm_armv7.S              |   277 +
 head/sys/arm/arm/cpufunc_asm_pj4b.S               |   202 +
 head/sys/arm/arm/elf_trampoline.c                 |   157 +-
 head/sys/arm/arm/fusu.S                           |   116 +-
 head/sys/arm/arm/genassym.c                       |    17 +-
 head/sys/arm/arm/gic.c                            |   307 +
 head/sys/arm/arm/identcpu.c                       |   267 +-
 head/sys/arm/arm/locore.S                         |   162 +-
 head/sys/arm/arm/machdep.c                        |    37 +-
 head/sys/arm/arm/mp_machdep.c                     |   393 ++
 head/sys/arm/arm/mpcore_timer.c                   |   431 ++
 head/sys/arm/arm/pl310.c                          |   321 +
 head/sys/arm/arm/pmap-v6.c                        |  3780 +++++++++++++++++++++
 head/sys/arm/arm/pmap.c                           |    14 +-
 head/sys/arm/arm/swtch.S                          |   159 +-
 head/sys/arm/arm/sys_machdep.c                    |    20 +-
 head/sys/arm/arm/trap.c                           |    13 +-
 head/sys/arm/arm/undefined.c                      |    12 +-
 head/sys/arm/arm/vfp.c                            |   260 +
 head/sys/arm/arm/vm_machdep.c                     |    19 +-
 head/sys/arm/at91/at91_machdep.c                  |     8 +-
 head/sys/arm/at91/at91_pmc.c                      |    59 +-
 head/sys/arm/at91/at91_pmcvar.h                   |     4 +-
 head/sys/arm/at91/at91sam9260.c                   |    23 +-
 head/sys/arm/at91/at91sam9g20.c                   |    30 +-
 head/sys/arm/at91/at91sam9g45.c                   |    21 +-
 head/sys/arm/at91/at91sam9x5.c                    |    30 +-
 head/sys/arm/at91/std.at91                        |     3 +-
 head/sys/arm/conf/ARMADAXP                        |   102 +
 head/sys/arm/conf/BEAGLEBONE                      |   126 +
 head/sys/arm/conf/EA3250                          |    96 +
 head/sys/arm/conf/EA3250.hints                    |     4 +
 head/sys/arm/conf/PANDABOARD                      |   144 +
 head/sys/arm/conf/PANDABOARD.hints                |    61 +
 head/sys/arm/econa/econa_machdep.c                |     8 +-
 head/sys/arm/econa/std.econa                      |     4 +-
 head/sys/arm/include/armreg.h                     |    88 +-
 head/sys/arm/include/asm.h                        |    53 +-
 head/sys/arm/include/asmacros.h                   |    88 +-
 head/sys/arm/include/atomic.h                     |   516 ++-
 head/sys/arm/include/cpuconf.h                    |    42 +-
 head/sys/arm/include/cpufunc.h                    |   105 +-
 head/sys/arm/include/fp.h                         |     9 +-
 head/sys/arm/include/intr.h                       |     7 +-
 head/sys/arm/include/md_var.h                     |     3 +-
 head/sys/arm/include/param.h                      |    12 +-
 head/sys/arm/include/pcb.h                        |     7 +-
 head/sys/arm/include/pcpu.h                       |    65 +-
 head/sys/arm/include/pl310.h                      |    38 +
 head/sys/arm/include/pmap.h                       |   146 +-
 head/sys/arm/include/pte.h                        |    44 +-
 head/sys/arm/include/smp.h                        |    31 +-
 head/sys/arm/include/sysarch.h                    |    11 +-
 head/sys/arm/include/vfp.h                        |   128 +
 head/sys/arm/include/vmparam.h                    |     4 +-
 head/sys/arm/lpc/files.lpc                        |    21 +
 head/sys/arm/lpc/if_lpe.c                         |  1231 ++++++
 head/sys/arm/lpc/if_lpereg.h                      |   208 +
 head/sys/arm/lpc/lpc_dmac.c                       |   288 +
 head/sys/arm/lpc/lpc_fb.c                         |   466 ++
 head/sys/arm/lpc/lpc_gpio.c                       |   547 +++
 head/sys/arm/lpc/lpc_intc.c                       |   243 +
 head/sys/arm/lpc/lpc_machdep.c                    |   641 +++
 head/sys/arm/lpc/lpc_mmc.c                        |   777 ++++
 head/sys/arm/lpc/lpc_ohci.c                       |   354 +
 head/sys/arm/lpc/lpc_pll.c                        |    28 +
 head/sys/arm/lpc/lpc_pwr.c                        |   126 +
 head/sys/arm/lpc/lpc_rtc.c                        |   147 +
 head/sys/arm/lpc/lpc_space.c                      |   147 +
 head/sys/arm/lpc/lpc_spi.c                        |   195 +
 head/sys/arm/lpc/lpc_timer.c                      |   320 +
 head/sys/arm/lpc/lpcreg.h                         |   661 +++
 head/sys/arm/lpc/lpcvar.h                         |    69 +
 head/sys/arm/lpc/ssd1289.c                        |   209 +
 head/sys/arm/lpc/std.lpc                          |    14 +
 head/sys/arm/mv/armadaxp/armadaxp.c               |    73 +
 head/sys/arm/mv/armadaxp/armadaxp_mp.c            |   208 +
 head/sys/arm/mv/armadaxp/files.armadaxp           |     6 +
 head/sys/arm/mv/armadaxp/std.armadaxp             |    15 +
 head/sys/arm/mv/armadaxp/std.mv78x60              |     5 +
 head/sys/arm/mv/common.c                          |   314 +-
 head/sys/arm/mv/discovery/files.db78xxx           |     4 +-
 head/sys/arm/mv/files.mv                          |     7 +-
 head/sys/arm/mv/kirkwood/files.kirkwood           |     3 +-
 head/sys/arm/mv/mpic.c                            |   304 +
 head/sys/arm/mv/mv_machdep.c                      |   174 +-
 head/sys/arm/mv/mv_pci.c                          |    14 +-
 head/sys/arm/mv/mvreg.h                           |   160 +-
 head/sys/arm/mv/mvvar.h                           |    31 +-
 head/sys/arm/mv/mvwin.h                           |   198 +-
 head/sys/arm/mv/orion/files.db88f5xxx             |     3 +-
 head/sys/arm/mv/orion/files.ts7800                |     3 +-
 head/sys/arm/mv/std-pj4b.mv                       |     6 +
 head/sys/arm/mv/timer.c                           |    47 +-
 head/sys/arm/s3c2xx0/s3c24x0_machdep.c            |     8 +-
 head/sys/arm/s3c2xx0/std.ln2410sbc                |     3 +-
 head/sys/arm/s3c2xx0/std.s3c2410                  |     3 +-
 head/sys/arm/sa11x0/assabet_machdep.c             |    10 +-
 head/sys/arm/sa11x0/std.sa11x0                    |     3 +-
 head/sys/arm/tegra/bus_space.c                    |   153 +
 head/sys/arm/tegra/common.c                       |    78 +
 head/sys/arm/tegra/files.tegra2                   |    19 +
 head/sys/arm/tegra/std.tegra2                     |    16 +
 head/sys/arm/tegra/tegra2_machdep.c               |   705 +++
 head/sys/arm/ti/aintc.c                           |   179 +
 head/sys/arm/ti/am335x/am335x_dmtimer.c           |   385 ++
 head/sys/arm/ti/am335x/am335x_pmic.c              |   176 +
 head/sys/arm/ti/am335x/am335x_prcm.c              |   568 +++
 head/sys/arm/ti/am335x/am335x_reg.h               |    41 +
 head/sys/arm/ti/am335x/am335x_scm_padconf.c       |   373 ++
 head/sys/arm/ti/am335x/files.am335x               |     9 +
 head/sys/arm/ti/am335x/files.beaglebone           |     3 +
 head/sys/arm/ti/am335x/std.am335x                 |    21 +
 head/sys/arm/ti/am335x/std.beaglebone             |     4 +
 head/sys/arm/ti/bus_space.c                       |   113 +
 head/sys/arm/ti/common.c                          |    98 +
 head/sys/arm/ti/cpsw/if_cpsw.c                    |  1251 ++++++
 head/sys/arm/ti/cpsw/if_cpswreg.h                 |   107 +
 head/sys/arm/ti/cpsw/if_cpswvar.h                 |   124 +
 head/sys/arm/ti/files.ti                          |    25 +
 head/sys/arm/ti/omap3/omap3_reg.h                 |   780 ++++
 head/sys/arm/ti/omap4/files.omap4                 |    19 +
 head/sys/arm/ti/omap4/omap4_l2cache.c             |    39 +
 head/sys/arm/ti/omap4/omap4_mp.c                  |    87 +
 head/sys/arm/ti/omap4/omap4_prcm_clks.c           |  1418 +++++++
 head/sys/arm/ti/omap4/omap4_reg.h                 |   586 +++
 head/sys/arm/ti/omap4/omap4_scm_padconf.c         |   405 ++
 head/sys/arm/ti/omap4/omap4_smc.h                 |    52 +
 head/sys/arm/ti/omap4/omap4var.h                  |    91 +
 head/sys/arm/ti/omap4/pandaboard/files.pandaboard |     3 +
 head/sys/arm/ti/omap4/pandaboard/pandaboard.c     |   210 +
 head/sys/arm/ti/omap4/pandaboard/std.pandaboard   |     4 +
 head/sys/arm/ti/omap4/std.omap4                   |    21 +
 head/sys/arm/ti/std.ti                            |     5 +
 head/sys/arm/ti/ti_cpuid.c                        |   285 +
 head/sys/arm/ti/ti_cpuid.h                        |    77 +
 head/sys/arm/ti/ti_edma3.c                        |   424 ++
 head/sys/arm/ti/ti_edma3.h                        |    81 +
 head/sys/arm/ti/ti_gpio.c                         |   802 ++++
 head/sys/arm/ti/ti_i2c.c                          |  1179 ++++++
 head/sys/arm/ti/ti_i2c.h                          |   115 +
 head/sys/arm/ti/ti_machdep.c                      |   618 +++
 head/sys/arm/ti/ti_mmchs.c                        |  1839 ++++++++++
 head/sys/arm/ti/ti_mmchs.h                        |   170 +
 head/sys/arm/ti/ti_prcm.c                         |   309 +
 head/sys/arm/ti/ti_prcm.h                         |   185 +
 head/sys/arm/ti/ti_scm.c                          |   493 ++
 head/sys/arm/ti/ti_scm.h                          |    84 +
 head/sys/arm/ti/ti_sdma.c                         |  1246 ++++++
 head/sys/arm/ti/ti_sdma.h                         |   111 +
 head/sys/arm/ti/ti_sdmareg.h                      |   133 +
 head/sys/arm/ti/ti_smc.S                          |    39 +
 head/sys/arm/ti/ti_smc.h                          |    33 +
 head/sys/arm/ti/tivar.h                           |    41 +
 head/sys/arm/ti/twl/twl.c                         |   464 ++
 head/sys/arm/ti/twl/twl.h                         |    39 +
 head/sys/arm/ti/twl/twl_clks.c                    |   675 +++
 head/sys/arm/ti/twl/twl_clks.h                    |    38 +
 head/sys/arm/ti/twl/twl_vreg.c                    |  1053 +++++
 head/sys/arm/ti/twl/twl_vreg.h                    |    36 +
 head/sys/arm/ti/usb/omap_ehci.c                   |  1024 +++++
 head/sys/arm/ti/usb/omap_usb.h                    |   264 +
 head/sys/arm/xscale/i80321/ep80219_machdep.c      |     5 +-
 head/sys/arm/xscale/i80321/iq31244_machdep.c      |     5 +-
 head/sys/arm/xscale/i8134x/crb_machdep.c          |     5 +-
 head/sys/arm/xscale/ixp425/avila_machdep.c        |     5 +-
 head/sys/arm/xscale/pxa/pxa_machdep.c             |     5 +-
 head/sys/arm/xscale/std.xscale                    |     3 +-
 176 files changed, 38672 insertions(+), 1042 deletions(-)

diffs (43192 lines):

diff -r 7fffa673adcd -r a301a330526b head/sys/arm/arm/bcopyinout.S
--- a/head/sys/arm/arm/bcopyinout.S	Wed Aug 15 11:15:12 2012 +0300
+++ b/head/sys/arm/arm/bcopyinout.S	Wed Aug 15 11:16:36 2012 +0300
@@ -46,7 +46,7 @@
 .L_min_memcpy_size:
 	.word	_C_LABEL(_min_memcpy_size)
 
-__FBSDID("$FreeBSD: head/sys/arm/arm/bcopyinout.S 239033 2012-08-04 05:38:25Z andrew $");
+__FBSDID("$FreeBSD: head/sys/arm/arm/bcopyinout.S 239268 2012-08-15 03:03:03Z gonzo $");
 #ifdef _ARM_ARCH_5E
 #include <arm/arm/bcopyinout_xscale.S>
 #else
@@ -54,14 +54,19 @@
 	.text
 	.align	0
 
-#ifdef MULTIPROCESSOR
-.Lcpu_info:
-	.word	_C_LABEL(cpu_info)
+#ifdef _ARM_ARCH_6
+#define GET_PCB(tmp) \
+	mrc p15, 0, tmp, c13, c0, 4; \
+	add	tmp, tmp, #(PC_CURPCB)
 #else
 .Lcurpcb:
-	.word _C_LABEL(__pcpu) + PC_CURPCB
+	.word	_C_LABEL(__pcpu) + PC_CURPCB
+
+#define GET_PCB(tmp) \
+	ldr	tmp, .Lcurpcb
 #endif
 
+
 #define SAVE_REGS	stmfd	sp!, {r4-r11}
 #define RESTORE_REGS	ldmfd	sp!, {r4-r11}
 		
@@ -111,18 +116,9 @@
 
 .Lnormal:
 	SAVE_REGS
-#ifdef MULTIPROCESSOR
-	/* XXX Probably not appropriate for non-Hydra SMPs */
-	stmfd	sp!, {r0-r2, r14}
-	bl	_C_LABEL(cpu_number)
-	ldr	r4, .Lcpu_info
-	ldr	r4, [r4, r0, lsl #2]
-	ldr	r4, [r4, #CI_CURPCB]
-	ldmfd	sp!, {r0-r2, r14}
-#else
-	ldr	r4, .Lcurpcb
+	GET_PCB(r4)
 	ldr	r4, [r4]
-#endif
+
 
 	ldr	r5, [r4, #PCB_ONFAULT]
 	adr	r3, .Lcopyfault
@@ -357,18 +353,8 @@
 
 .Lnormale:
 	SAVE_REGS
-#ifdef MULTIPROCESSOR
-	/* XXX Probably not appropriate for non-Hydra SMPs */
-	stmfd	sp!, {r0-r2, r14}
-	bl	_C_LABEL(cpu_number)
-	ldr	r4, .Lcpu_info
-	ldr	r4, [r4, r0, lsl #2]
-	ldr	r4, [r4, #CI_CURPCB]
-	ldmfd	sp!, {r0-r2, r14}
-#else
-	ldr	r4, .Lcurpcb
+	GET_PCB(r4)
 	ldr	r4, [r4]
-#endif
 
 	ldr	r5, [r4, #PCB_ONFAULT]
 	adr	r3, .Lcopyfault
@@ -561,18 +547,9 @@
  * else EFAULT if a page fault occurred.
  */
 ENTRY(badaddr_read_1)
-#ifdef MULTIPROCESSOR
-	/* XXX Probably not appropriate for non-Hydra SMPs */
-	stmfd	sp!, {r0-r1, r14}
-	bl	_C_LABEL(cpu_number)
-	ldr	r2, .Lcpu_info
-	ldr	r2, [r2, r0, lsl #2]
-	ldr	r2, [r2, #CI_CURPCB]
-	ldmfd	sp!, {r0-r1, r14}
-#else
-	ldr	r2, .Lcurpcb
+	GET_PCB(r2)
 	ldr	r2, [r2]
-#endif
+
 	ldr	ip, [r2, #PCB_ONFAULT]
 	adr	r3, 1f
 	str	r3, [r2, #PCB_ONFAULT]
@@ -595,18 +572,9 @@
  * else EFAULT if a page fault occurred.
  */
 ENTRY(badaddr_read_2)
-#ifdef MULTIPROCESSOR
-	/* XXX Probably not appropriate for non-Hydra SMPs */
-	stmfd	sp!, {r0-r1, r14}
-	bl	_C_LABEL(cpu_number)
-	ldr	r2, .Lcpu_info
-	ldr	r2, [r2, r0, lsl #2]
-	ldr	r2, [r2, #CI_CURPCB]
-	ldmfd	sp!, {r0-r1, r14}
-#else
-	ldr	r2, .Lcurpcb
+	GET_PCB(r2)
 	ldr	r2, [r2]
-#endif
+
 	ldr	ip, [r2, #PCB_ONFAULT]
 	adr	r3, 1f
 	str	r3, [r2, #PCB_ONFAULT]
@@ -629,18 +597,9 @@
  * else EFAULT if a page fault occurred.
  */
 ENTRY(badaddr_read_4)
-#ifdef MULTIPROCESSOR
-	/* XXX Probably not appropriate for non-Hydra SMPs */
-	stmfd	sp!, {r0-r1, r14}
-	bl	_C_LABEL(cpu_number)
-	ldr	r2, .Lcpu_info
-	ldr	r2, [r2, r0, lsl #2]
-	ldr	r2, [r2, #CI_CURPCB]
-	ldmfd	sp!, {r0-r1, r14}
-#else
-	ldr	r2, .Lcurpcb
+	GET_PCB(r2)
 	ldr	r2, [r2]
-#endif
+
 	ldr	ip, [r2, #PCB_ONFAULT]
 	adr	r3, 1f
 	str	r3, [r2, #PCB_ONFAULT]
diff -r 7fffa673adcd -r a301a330526b head/sys/arm/arm/bcopyinout_xscale.S
--- a/head/sys/arm/arm/bcopyinout_xscale.S	Wed Aug 15 11:15:12 2012 +0300
+++ b/head/sys/arm/arm/bcopyinout_xscale.S	Wed Aug 15 11:16:36 2012 +0300
@@ -36,17 +36,20 @@
  */
 
 #include <machine/asm.h>
-__FBSDID("$FreeBSD: head/sys/arm/arm/bcopyinout_xscale.S 239033 2012-08-04 05:38:25Z andrew $");
+__FBSDID("$FreeBSD: head/sys/arm/arm/bcopyinout_xscale.S 239268 2012-08-15 03:03:03Z gonzo $");
 
 	.text
 	.align	0
 
-#ifdef MULTIPROCESSOR
-.Lcpu_info:
-	.word	_C_LABEL(cpu_info)
+#ifdef _ARM_ARCH_6
+#define GET_PCB(tmp) \
+	mrc p15, 0, tmp, c13, c0, 4; \
+	add	tmp, tmp, #(PC_CURPCB)
 #else
 .Lcurpcb:
 	.word	_C_LABEL(__pcpu) + PC_CURPCB
+#define GET_PCB(tmp) \
+	ldr	tmp, .Lcurpcb
 #endif
 
 /*
@@ -85,18 +88,8 @@
 .Lnormal:
 	stmfd	sp!, {r10-r11, lr}
 
-#ifdef MULTIPROCESSOR
-	/* XXX Probably not appropriate for non-Hydra SMPs */
-	stmfd	sp!, {r0-r2}
-	bl	_C_LABEL(cpu_number)
-	ldr	r10, .Lcpu_info
-	ldmfd	sp!, {r0-r2}
-	ldr	r10, [r10, r0, lsl #2]
-	ldr	r10, [r10, #CI_CURPCB]
-#else
-	ldr	r10, .Lcurpcb
+	GET_PCB(r10)
 	ldr	r10, [r10]
-#endif
 
 	mov	r3, #0x00
 	adr	ip, .Lcopyin_fault
@@ -537,18 +530,8 @@
 .Lnormale:									
 	stmfd	sp!, {r10-r11, lr}
 
-#ifdef MULTIPROCESSOR
-	/* XXX Probably not appropriate for non-Hydra SMPs */
-	stmfd	sp!, {r0-r2}
-	bl	_C_LABEL(cpu_number)
-	ldr	r10, .Lcpu_info
-	ldmfd	sp!, {r0-r2}
-	ldr	r10, [r10, r0, lsl #2]
-	ldr	r10, [r10, #CI_CURPCB]
-#else
-	ldr	r10, .Lcurpcb
+	GET_PCB(r10)
 	ldr	r10, [r10]
-#endif
 
 	mov	r3, #0x00
 	adr	ip, .Lcopyout_fault
diff -r 7fffa673adcd -r a301a330526b head/sys/arm/arm/bus_space_asm_generic.S
--- a/head/sys/arm/arm/bus_space_asm_generic.S	Wed Aug 15 11:15:12 2012 +0300
+++ b/head/sys/arm/arm/bus_space_asm_generic.S	Wed Aug 15 11:16:36 2012 +0300
@@ -37,7 +37,7 @@
 
 #include <machine/asm.h>
 #include <machine/cpuconf.h>
-__FBSDID("$FreeBSD$");
+__FBSDID("$FreeBSD: head/sys/arm/arm/bus_space_asm_generic.S 239268 2012-08-15 03:03:03Z gonzo $");
 
 /*
  * Generic bus_space functions.
@@ -51,11 +51,9 @@
 	ldrb	r0, [r1, r2]
 	RET
 
-#if (ARM_ARCH_4 + ARM_ARCH_5) > 0
 ENTRY(generic_armv4_bs_r_2)
 	ldrh	r0, [r1, r2]
 	RET
-#endif
 
 ENTRY(generic_bs_r_4)
 	ldr	r0, [r1, r2]
@@ -69,11 +67,9 @@
 	strb	r3, [r1, r2]
 	RET
 
-#if (ARM_ARCH_4 + ARM_ARCH_5) > 0
 ENTRY(generic_armv4_bs_w_2)
 	strh	r3, [r1, r2]
 	RET
-#endif
 
 ENTRY(generic_bs_w_4)
 	str	r3, [r1, r2]
@@ -97,7 +93,6 @@
 
 	RET
 
-#if (ARM_ARCH_4 + ARM_ARCH_5) > 0
 ENTRY(generic_armv4_bs_rm_2)
 	add	r0, r1, r2
 	mov	r1, r3
@@ -111,7 +106,6 @@
 	bne	1b
 
 	RET
-#endif
 
 ENTRY(generic_bs_rm_4)
 	add	r0, r1, r2
@@ -145,7 +139,6 @@
 
 	RET
 
-#if (ARM_ARCH_4 + ARM_ARCH_5) > 0
 ENTRY(generic_armv4_bs_wm_2)
 	add	r0, r1, r2
 	mov	r1, r3
@@ -159,7 +152,6 @@
 	bne	1b
 
 	RET
-#endif
 
 ENTRY(generic_bs_wm_4)
 	add	r0, r1, r2
@@ -193,7 +185,6 @@
 
 	RET
 
-#if (ARM_ARCH_4 + ARM_ARCH_5) > 0
 ENTRY(generic_armv4_bs_rr_2)
 	add	r0, r1, r2
 	mov	r1, r3
@@ -207,7 +198,6 @@
 	bne	1b
 
 	RET
-#endif
 
 ENTRY(generic_bs_rr_4)
 	add	r0, r1, r2
@@ -241,7 +231,6 @@
 
 	RET
 
-#if (ARM_ARCH_4 + ARM_ARCH_5) > 0
 ENTRY(generic_armv4_bs_wr_2)
 	add	r0, r1, r2
 	mov	r1, r3
@@ -255,7 +244,6 @@
 	bne	1b
 
 	RET
-#endif
 
 ENTRY(generic_bs_wr_4)
 	add	r0, r1, r2
@@ -288,7 +276,6 @@
 
 	RET
 
-#if (ARM_ARCH_4 + ARM_ARCH_5) > 0
 ENTRY(generic_armv4_bs_sr_2)
 	add	r0, r1, r2
 	mov	r1, r3
@@ -301,7 +288,6 @@
 	bne	1b
 
 	RET
-#endif
 
 ENTRY(generic_bs_sr_4)
 	add	r0, r1, r2
@@ -320,7 +306,6 @@
  * copy region
  */
 
-#if (ARM_ARCH_4 + ARM_ARCH_5) > 0
 ENTRY(generic_armv4_bs_c_2)
 	add	r0, r1, r2
 	ldr	r2, [sp, #0]
@@ -350,4 +335,3 @@
 	bne	3b
 
 	RET
-#endif
diff -r 7fffa673adcd -r a301a330526b head/sys/arm/arm/busdma_machdep-v6.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/head/sys/arm/arm/busdma_machdep-v6.c	Wed Aug 15 11:16:36 2012 +0300
@@ -0,0 +1,1559 @@
+/*-
+ * Copyright (c) 2010 Mark Tinguely
+ * Copyright (c) 2004 Olivier Houchard
+ * Copyright (c) 2002 Peter Grehan
+ * Copyright (c) 1997, 1998 Justin T. Gibbs.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions, and the following disclaimer,
+ *    without modification, immediately at the beginning of the file.
+ * 2. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * 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.
+ *
+ *  From i386/busdma_machdep.c 191438 2009-04-23 20:24:19Z jhb
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: head/sys/arm/arm/busdma_machdep-v6.c 239268 2012-08-15 03:03:03Z gonzo $");
+
+#define _ARM32_BUS_DMA_PRIVATE
+#include <sys/param.h>
+#include <sys/kdb.h>
+#include <ddb/ddb.h>
+#include <ddb/db_output.h>
+#include <sys/systm.h>
+#include <sys/malloc.h>
+#include <sys/bus.h>
+#include <sys/interrupt.h>
+#include <sys/kernel.h>
+#include <sys/ktr.h>
+#include <sys/lock.h>
+#include <sys/proc.h>
+#include <sys/mutex.h>
+#include <sys/mbuf.h>
+#include <sys/uio.h>
+#include <sys/sysctl.h>
+
+#include <vm/vm.h>
+#include <vm/vm_page.h>
+#include <vm/vm_map.h>
+
+#include <machine/atomic.h>
+#include <machine/bus.h>
+#include <machine/cpufunc.h>
+#include <machine/md_var.h>
+
+#define MAX_BPAGES 64
+#define BUS_DMA_COULD_BOUNCE	BUS_DMA_BUS3
+#define BUS_DMA_MIN_ALLOC_COMP	BUS_DMA_BUS4
+
+#define FIX_DMAP_BUS_DMASYNC_POSTREAD
+
+struct bounce_zone;
+
+struct bus_dma_tag {
+	bus_dma_tag_t	  parent;
+	bus_size_t	  alignment;
+	bus_size_t	  boundary;
+	bus_addr_t	  lowaddr;
+	bus_addr_t	  highaddr;
+	bus_dma_filter_t *filter;
+	void		 *filterarg;
+	bus_size_t	  maxsize;
+	u_int		  nsegments;
+	bus_size_t	  maxsegsz;
+	int		  flags;
+	int		  ref_count;
+	int		  map_count;
+	bus_dma_lock_t	 *lockfunc;
+	void		 *lockfuncarg;
+	bus_dma_segment_t *segments;
+	struct bounce_zone *bounce_zone;
+	/*
+	 * DMA range for this tag.  If the page doesn't fall within
+	 * one of these ranges, an error is returned.  The caller
+	 * may then decide what to do with the transfer.  If the
+	 * range pointer is NULL, it is ignored.
+	 */
+	struct arm32_dma_range	*ranges;
+	int			_nranges;
+
+};
+
+struct bounce_page {
+	vm_offset_t	vaddr;		/* kva of bounce buffer */
+	bus_addr_t	busaddr;	/* Physical address */
+	vm_offset_t	datavaddr;	/* kva of client data */
+	bus_size_t	datacount;	/* client data count */
+	STAILQ_ENTRY(bounce_page) links;
+};
+
+struct sync_list {
+	vm_offset_t	vaddr;		/* kva of bounce buffer */
+	bus_addr_t	busaddr;	/* Physical address */
+	bus_size_t	datacount;	/* client data count */
+	STAILQ_ENTRY(sync_list) slinks;
+};
+
+int busdma_swi_pending;
+
+struct bounce_zone {
+	STAILQ_ENTRY(bounce_zone) links;
+	STAILQ_HEAD(bp_list, bounce_page) bounce_page_list;
+	int		total_bpages;
+	int		free_bpages;
+	int		reserved_bpages;
+	int		active_bpages;
+	int		total_bounced;
+	int		total_deferred;
+	int		map_count;
+	bus_size_t	alignment;
+	bus_addr_t	lowaddr;
+	char		zoneid[8];
+	char		lowaddrid[20];
+	struct sysctl_ctx_list sysctl_tree;
+	struct sysctl_oid *sysctl_tree_top;
+};
+
+static struct mtx bounce_lock;
+static int total_bpages;
+static int busdma_zonecount;
+static STAILQ_HEAD(, bounce_zone) bounce_zone_list;
+
+SYSCTL_NODE(_hw, OID_AUTO, busdma, CTLFLAG_RD, 0, "Busdma parameters");
+SYSCTL_INT(_hw_busdma, OID_AUTO, total_bpages, CTLFLAG_RD, &total_bpages, 0,
+	   "Total bounce pages");
+
+struct bus_dmamap {
+	struct bp_list	       bpages;
+	int		       pagesneeded;
+	int		       pagesreserved;
+	bus_dma_tag_t	       dmat;
+	void		      *buf;		/* unmapped buffer pointer */
+	bus_size_t	       buflen;		/* unmapped buffer length */
+	pmap_t		       pmap;
+	bus_dmamap_callback_t *callback;
+	void		      *callback_arg;
+	STAILQ_ENTRY(bus_dmamap) links;
+	STAILQ_HEAD(,sync_list)	slist;
+};
+
+static STAILQ_HEAD(, bus_dmamap) bounce_map_waitinglist;
+static STAILQ_HEAD(, bus_dmamap) bounce_map_callbacklist;
+
+static void init_bounce_pages(void *dummy);
+static int alloc_bounce_zone(bus_dma_tag_t dmat);
+static int alloc_bounce_pages(bus_dma_tag_t dmat, u_int numpages);
+static int reserve_bounce_pages(bus_dma_tag_t dmat, bus_dmamap_t map,
+				int commit);
+static bus_addr_t add_bounce_page(bus_dma_tag_t dmat, bus_dmamap_t map,
+				   vm_offset_t vaddr, bus_size_t size);
+static void free_bounce_page(bus_dma_tag_t dmat, struct bounce_page *bpage);
+int run_filter(bus_dma_tag_t dmat, bus_addr_t paddr);
+static int _bus_dmamap_count_pages(bus_dma_tag_t dmat, bus_dmamap_t map,
+    void *buf, bus_size_t buflen, int flags);
+
+static __inline int
+_bus_dma_can_bounce(vm_offset_t lowaddr, vm_offset_t highaddr)
+{
+	int i;
+	for (i = 0; phys_avail[i] && phys_avail[i + 1]; i += 2) {
+		if ((lowaddr >= phys_avail[i] && lowaddr <= phys_avail[i + 1])
+		    || (lowaddr < phys_avail[i] &&
+		    highaddr > phys_avail[i]))
+			return (1);
+	}
+	return (0);
+}
+
+static __inline struct arm32_dma_range *
+_bus_dma_inrange(struct arm32_dma_range *ranges, int nranges,
+    bus_addr_t curaddr)
+{
+	struct arm32_dma_range *dr;
+	int i;
+
+	for (i = 0, dr = ranges; i < nranges; i++, dr++) {
+		if (curaddr >= dr->dr_sysbase &&
+		    round_page(curaddr) <= (dr->dr_sysbase + dr->dr_len))
+			return (dr);
+	}
+
+	return (NULL);
+}
+
+/*
+ * Return true if a match is made.
+ *
+ * To find a match walk the chain of bus_dma_tag_t's looking for 'paddr'.
+ *
+ * If paddr is within the bounds of the dma tag then call the filter callback
+ * to check for a match, if there is no filter callback then assume a match.
+ */
+int
+run_filter(bus_dma_tag_t dmat, bus_addr_t paddr)
+{
+	int retval;
+
+	retval = 0;
+
+	do {
+		if (((paddr > dmat->lowaddr && paddr <= dmat->highaddr)
+		 || ((paddr & (dmat->alignment - 1)) != 0))
+		 && (dmat->filter == NULL
+		  || (*dmat->filter)(dmat->filterarg, paddr) != 0))
+			retval = 1;
+
+		dmat = dmat->parent;
+	} while (retval == 0 && dmat != NULL);
+	return (retval);
+}
+
+/*
+ * Convenience function for manipulating driver locks from busdma (during
+ * busdma_swi, for example).  Drivers that don't provide their own locks
+ * should specify &Giant to dmat->lockfuncarg.  Drivers that use their own
+ * non-mutex locking scheme don't have to use this at all.
+ */
+void
+busdma_lock_mutex(void *arg, bus_dma_lock_op_t op)
+{
+	struct mtx *dmtx;
+
+	dmtx = (struct mtx *)arg;
+	switch (op) {
+	case BUS_DMA_LOCK:
+		mtx_lock(dmtx);
+		break;
+	case BUS_DMA_UNLOCK:
+		mtx_unlock(dmtx);
+		break;
+	default:
+		panic("Unknown operation 0x%x for busdma_lock_mutex!", op);
+	}
+}
+
+/*
+ * dflt_lock should never get called.  It gets put into the dma tag when
+ * lockfunc == NULL, which is only valid if the maps that are associated
+ * with the tag are meant to never be defered.
+ * XXX Should have a way to identify which driver is responsible here.
+ */
+static void
+dflt_lock(void *arg, bus_dma_lock_op_t op)
+{
+	panic("driver error: busdma dflt_lock called");
+}
+
+/*
+ * Allocate a device specific dma_tag.
+ */
+int
+bus_dma_tag_create(bus_dma_tag_t parent, bus_size_t alignment,
+		   bus_size_t boundary, bus_addr_t lowaddr,
+		   bus_addr_t highaddr, bus_dma_filter_t *filter,
+		   void *filterarg, bus_size_t maxsize, int nsegments,
+		   bus_size_t maxsegsz, int flags, bus_dma_lock_t *lockfunc,
+		   void *lockfuncarg, bus_dma_tag_t *dmat)
+{
+	bus_dma_tag_t newtag;
+	int error = 0;
+
+#if 0
+	if (!parent)
+		parent = arm_root_dma_tag;
+#endif
+
+	/* Basic sanity checking */
+	if (boundary != 0 && boundary < maxsegsz)
+		maxsegsz = boundary;
+
+	/* Return a NULL tag on failure */
+	*dmat = NULL;
+
+	if (maxsegsz == 0) {
+		return (EINVAL);
+	}
+
+	newtag = (bus_dma_tag_t)malloc(sizeof(*newtag), M_DEVBUF,
+	    M_ZERO | M_NOWAIT);
+	if (newtag == NULL) {
+		CTR4(KTR_BUSDMA, "%s returned tag %p tag flags 0x%x error %d",
+		    __func__, newtag, 0, error);
+		return (ENOMEM);
+	}
+
+	newtag->parent = parent;
+	newtag->alignment = alignment;
+	newtag->boundary = boundary;
+	newtag->lowaddr = trunc_page((vm_paddr_t)lowaddr) + (PAGE_SIZE - 1);
+	newtag->highaddr = trunc_page((vm_paddr_t)highaddr) +
+	    (PAGE_SIZE - 1);
+	newtag->filter = filter;
+	newtag->filterarg = filterarg;
+	newtag->maxsize = maxsize;
+	newtag->nsegments = nsegments;
+	newtag->maxsegsz = maxsegsz;
+	newtag->flags = flags;
+	newtag->ref_count = 1; /* Count ourself */
+	newtag->map_count = 0;
+	newtag->ranges = bus_dma_get_range();
+	newtag->_nranges = bus_dma_get_range_nb();
+	if (lockfunc != NULL) {
+		newtag->lockfunc = lockfunc;
+		newtag->lockfuncarg = lockfuncarg;
+	} else {
+		newtag->lockfunc = dflt_lock;
+		newtag->lockfuncarg = NULL;
+	}
+	newtag->segments = NULL;
+
+	/* Take into account any restrictions imposed by our parent tag */
+	if (parent != NULL) {
+		newtag->lowaddr = MIN(parent->lowaddr, newtag->lowaddr);
+		newtag->highaddr = MAX(parent->highaddr, newtag->highaddr);
+		if (newtag->boundary == 0)
+			newtag->boundary = parent->boundary;
+		else if (parent->boundary != 0)
+			newtag->boundary = MIN(parent->boundary,
+					       newtag->boundary);
+		if ((newtag->filter != NULL) ||
+		    ((parent->flags & BUS_DMA_COULD_BOUNCE) != 0))
+			newtag->flags |= BUS_DMA_COULD_BOUNCE;
+		if (newtag->filter == NULL) {
+			/*
+			 * Short circuit looking at our parent directly
+			 * since we have encapsulated all of its information
+			 */
+			newtag->filter = parent->filter;
+			newtag->filterarg = parent->filterarg;
+			newtag->parent = parent->parent;
+		}
+		if (newtag->parent != NULL)
+			atomic_add_int(&parent->ref_count, 1);
+	}
+
+	if (_bus_dma_can_bounce(newtag->lowaddr, newtag->highaddr)
+	 || newtag->alignment > 1)
+		newtag->flags |= BUS_DMA_COULD_BOUNCE;
+
+	if (((newtag->flags & BUS_DMA_COULD_BOUNCE) != 0) &&
+	    (flags & BUS_DMA_ALLOCNOW) != 0) {
+		struct bounce_zone *bz;
+
+		/* Must bounce */
+
+		if ((error = alloc_bounce_zone(newtag)) != 0) {
+			free(newtag, M_DEVBUF);
+			return (error);
+		}
+		bz = newtag->bounce_zone;
+
+		if (ptoa(bz->total_bpages) < maxsize) {
+			int pages;
+
+			pages = atop(maxsize) - bz->total_bpages;
+
+			/* Add pages to our bounce pool */
+			if (alloc_bounce_pages(newtag, pages) < pages)
+				error = ENOMEM;
+		}
+		/* Performed initial allocation */
+		newtag->flags |= BUS_DMA_MIN_ALLOC_COMP;
+	} else
+		newtag->bounce_zone = NULL;
+
+	if (error != 0) {
+		free(newtag, M_DEVBUF);
+	} else {
+		*dmat = newtag;
+	}
+	CTR4(KTR_BUSDMA, "%s returned tag %p tag flags 0x%x error %d",
+	    __func__, newtag, (newtag != NULL ? newtag->flags : 0), error);
+	return (error);
+}
+
+int
+bus_dma_tag_destroy(bus_dma_tag_t dmat)
+{
+	bus_dma_tag_t dmat_copy;
+	int error;
+
+	error = 0;
+	dmat_copy = dmat;
+
+	if (dmat != NULL) {
+
+		if (dmat->map_count != 0) {
+			error = EBUSY;
+			goto out;
+		}
+
+		while (dmat != NULL) {
+			bus_dma_tag_t parent;
+
+			parent = dmat->parent;
+			atomic_subtract_int(&dmat->ref_count, 1);
+			if (dmat->ref_count == 0) {
+				if (dmat->segments != NULL)
+					free(dmat->segments, M_DEVBUF);
+				free(dmat, M_DEVBUF);
+				/*
+				 * Last reference count, so
+				 * release our reference
+				 * count on our parent.
+				 */
+				dmat = parent;
+			} else
+				dmat = NULL;
+		}
+	}
+out:
+	CTR3(KTR_BUSDMA, "%s tag %p error %d", __func__, dmat_copy, error);
+	return (error);
+}
+
+/*
+ * Allocate a handle for mapping from kva/uva/physical
+ * address space into bus device space.
+ */
+int
+bus_dmamap_create(bus_dma_tag_t dmat, int flags, bus_dmamap_t *mapp)
+{
+	int error;
+
+	error = 0;
+
+	*mapp = (bus_dmamap_t)malloc(sizeof(**mapp), M_DEVBUF,
+					     M_NOWAIT | M_ZERO);
+	if (*mapp == NULL) {
+		CTR3(KTR_BUSDMA, "%s: tag %p error %d", __func__, dmat, ENOMEM);
+		return (ENOMEM);
+	}
+	STAILQ_INIT(&((*mapp)->slist));
+
+	if (dmat->segments == NULL) {
+		dmat->segments = (bus_dma_segment_t *)malloc(
+		    sizeof(bus_dma_segment_t) * dmat->nsegments, M_DEVBUF,
+		    M_NOWAIT);
+		if (dmat->segments == NULL) {
+			CTR3(KTR_BUSDMA, "%s: tag %p error %d",
+			    __func__, dmat, ENOMEM);
+			free(*mapp, M_DEVBUF);
+			*mapp = NULL;
+			return (ENOMEM);
+		}
+	}
+	/*
+	 * Bouncing might be required if the driver asks for an active
+	 * exclusion region, a data alignment that is stricter than 1, and/or
+	 * an active address boundary.
+	 */
+	if (dmat->flags & BUS_DMA_COULD_BOUNCE) {
+
+		/* Must bounce */
+		struct bounce_zone *bz;
+		int maxpages;
+
+		if (dmat->bounce_zone == NULL) {
+			if ((error = alloc_bounce_zone(dmat)) != 0) {
+				free(*mapp, M_DEVBUF);
+				*mapp = NULL;
+				return (error);
+			}
+		}
+		bz = dmat->bounce_zone;
+
+		/* Initialize the new map */
+		STAILQ_INIT(&((*mapp)->bpages));
+
+		/*
+		 * Attempt to add pages to our pool on a per-instance
+		 * basis up to a sane limit.
+		 */
+		maxpages = MAX_BPAGES;
+		if ((dmat->flags & BUS_DMA_MIN_ALLOC_COMP) == 0
+		 || (bz->map_count > 0 && bz->total_bpages < maxpages)) {
+			int pages;
+
+			pages = MAX(atop(dmat->maxsize), 1);
+			pages = MIN(maxpages - bz->total_bpages, pages);
+			pages = MAX(pages, 1);
+			if (alloc_bounce_pages(dmat, pages) < pages)
+				error = ENOMEM;
+
+			if ((dmat->flags & BUS_DMA_MIN_ALLOC_COMP) == 0) {
+				if (error == 0)
+					dmat->flags |= BUS_DMA_MIN_ALLOC_COMP;
+			} else {
+				error = 0;
+			}
+		}
+		bz->map_count++;
+	}
+	if (error == 0)
+		dmat->map_count++;
+	CTR4(KTR_BUSDMA, "%s: tag %p tag flags 0x%x error %d",
+	    __func__, dmat, dmat->flags, error);
+	return (error);
+}
+
+/*
+ * Destroy a handle for mapping from kva/uva/physical
+ * address space into bus device space.
+ */
+int
+bus_dmamap_destroy(bus_dma_tag_t dmat, bus_dmamap_t map)
+{
+	if (STAILQ_FIRST(&map->bpages) != NULL ||
+	    STAILQ_FIRST(&map->slist) != NULL) {
+		CTR3(KTR_BUSDMA, "%s: tag %p error %d",
+		    __func__, dmat, EBUSY);
+		return (EBUSY);
+	}
+	if (dmat->bounce_zone)
+		dmat->bounce_zone->map_count--;
+	free(map, M_DEVBUF);
+	dmat->map_count--;
+	CTR2(KTR_BUSDMA, "%s: tag %p error 0", __func__, dmat);
+	return (0);
+}
+
+
+/*
+ * Allocate a piece of memory that can be efficiently mapped into
+ * bus device space based on the constraints lited in the dma tag.
+ * A dmamap to for use with dmamap_load is also allocated.
+ */
+int
+bus_dmamem_alloc(bus_dma_tag_t dmat, void** vaddr, int flags,
+		 bus_dmamap_t *mapp)
+{
+	int mflags, len;
+
+	if (flags & BUS_DMA_NOWAIT)
+		mflags = M_NOWAIT;
+	else
+		mflags = M_WAITOK;
+
+	/* ARM non-snooping caches need a map for the VA cache sync structure */
+
+	*mapp = (bus_dmamap_t)malloc(sizeof(**mapp), M_DEVBUF,
+					     M_NOWAIT | M_ZERO);
+	if (*mapp == NULL) {
+		CTR4(KTR_BUSDMA, "%s: tag %p tag flags 0x%x error %d",
+		    __func__, dmat, dmat->flags, ENOMEM);
+		return (ENOMEM);
+	}
+
+	STAILQ_INIT(&((*mapp)->slist));
+
+	if (dmat->segments == NULL) {
+		dmat->segments = (bus_dma_segment_t *)malloc(
+		    sizeof(bus_dma_segment_t) * dmat->nsegments, M_DEVBUF,
+		    mflags);
+		if (dmat->segments == NULL) {
+			CTR4(KTR_BUSDMA, "%s: tag %p tag flags 0x%x error %d",
+			    __func__, dmat, dmat->flags, ENOMEM);
+			free(*mapp, M_DEVBUF);
+			*mapp = NULL;
+			return (ENOMEM);
+		}
+	}
+
+	if (flags & BUS_DMA_ZERO)
+		mflags |= M_ZERO;
+
+	/* 
+	 * XXX:
+	 * (dmat->alignment < dmat->maxsize) is just a quick hack; the exact
+	 * alignment guarantees of malloc need to be nailed down, and the
+	 * code below should be rewritten to take that into account.
+	 *
+	 * In the meantime, we'll warn the user if malloc gets it wrong.
+	 *
+	 * allocate at least a cache line. This should help avoid cache
+	 * corruption.
+	 */
+	len = max(dmat->maxsize, arm_dcache_align);
+        if (len <= PAGE_SIZE &&
+	   (dmat->alignment < len) &&
+	   !_bus_dma_can_bounce(dmat->lowaddr, dmat->highaddr)) {
+		*vaddr = malloc(len, M_DEVBUF, mflags);
+	} else {
+		/*
+		 * XXX Use Contigmalloc until it is merged into this facility
+		 *     and handles multi-seg allocations.  Nobody is doing
+		 *     multi-seg allocations yet though.
+		 * XXX Certain AGP hardware does.
+		 */
+		*vaddr = contigmalloc(len, M_DEVBUF, mflags,
+		    0ul, dmat->lowaddr, dmat->alignment? dmat->alignment : 1ul,
+		    dmat->boundary);
+	}
+	if (*vaddr == NULL) {
+		CTR4(KTR_BUSDMA, "%s: tag %p tag flags 0x%x error %d",
+		    __func__, dmat, dmat->flags, ENOMEM);
+		free(*mapp, M_DEVBUF);
+		*mapp = NULL;
+		return (ENOMEM);
+	} else if ((uintptr_t)*vaddr & (dmat->alignment - 1)) {
+		printf("bus_dmamem_alloc failed to align memory properly.\n");
+	}
+	dmat->map_count++;
+
+	if (flags & BUS_DMA_COHERENT)
+		pmap_change_attr((vm_offset_t)*vaddr, len,
+		    BUS_DMA_NOCACHE);
+
+	CTR4(KTR_BUSDMA, "%s: tag %p tag flags 0x%x error %d",
+	    __func__, dmat, dmat->flags, 0);
+	return (0);
+}
+
+/*
+ * Free a piece of memory and it's allociated dmamap, that was allocated
+ * via bus_dmamem_alloc.  Make the same choice for free/contigfree.
+ */
+void
+bus_dmamem_free(bus_dma_tag_t dmat, void *vaddr, bus_dmamap_t map)
+{
+	int len;
+
+#ifdef mftnotyet
+	pmap_change_attr((vm_offset_t)vaddr, dmat->maxsize, ARM_WRITE_BACK);
+#endif
+	len = max(dmat->maxsize, arm_dcache_align);
+        if (len <= PAGE_SIZE &&
+	   (dmat->alignment < len) &&
+	   !_bus_dma_can_bounce(dmat->lowaddr, dmat->highaddr))
+		free(vaddr, M_DEVBUF);
+	else {
+		contigfree(vaddr, len, M_DEVBUF);
+	}
+	dmat->map_count--;
+	free(map, M_DEVBUF);
+	CTR3(KTR_BUSDMA, "%s: tag %p flags 0x%x", __func__, dmat, dmat->flags);
+}
+
+static int
+_bus_dmamap_count_pages(bus_dma_tag_t dmat, bus_dmamap_t map,
+    void *buf, bus_size_t buflen, int flags)
+{
+	vm_offset_t vaddr;
+	vm_offset_t vendaddr;
+	bus_addr_t paddr;
+
+	if (map->pagesneeded == 0) {
+		CTR5(KTR_BUSDMA, "lowaddr= %d, boundary= %d, alignment= %d"
+		    " map= %p, pagesneeded= %d",
+		    dmat->lowaddr, dmat->boundary, dmat->alignment,
+		    map, map->pagesneeded);
+		/*
+		 * Count the number of bounce pages
+		 * needed in order to complete this transfer
+		 */
+		vaddr = (vm_offset_t)buf;
+		vendaddr = (vm_offset_t)buf + buflen;
+
+		while (vaddr < vendaddr) {
+			if (__predict_true(map->pmap == pmap_kernel()))
+				paddr = pmap_kextract(vaddr);
+			else
+				paddr = pmap_extract(map->pmap, vaddr);
+			if (((dmat->flags & BUS_DMA_COULD_BOUNCE) != 0) &&
+			    run_filter(dmat, paddr) != 0) {
+				map->pagesneeded++;
+			}
+			vaddr += (PAGE_SIZE - ((vm_offset_t)vaddr & PAGE_MASK));
+
+		}
+		CTR1(KTR_BUSDMA, "pagesneeded= %d", map->pagesneeded);
+	}
+
+	/* Reserve Necessary Bounce Pages */
+	if (map->pagesneeded != 0) {
+		mtx_lock(&bounce_lock);
+		if (flags & BUS_DMA_NOWAIT) {
+			if (reserve_bounce_pages(dmat, map, 0) != 0) {
+				map->pagesneeded = 0;
+				mtx_unlock(&bounce_lock);
+				return (ENOMEM);
+			}
+		} else {
+			if (reserve_bounce_pages(dmat, map, 1) != 0) {
+				/* Queue us for resources */
+				map->dmat = dmat;
+				map->buf = buf;
+				map->buflen = buflen;
+				STAILQ_INSERT_TAIL(&bounce_map_waitinglist,
+				    map, links);
+				mtx_unlock(&bounce_lock);
+				return (EINPROGRESS);
+			}
+		}
+		mtx_unlock(&bounce_lock);
+	}
+
+	return (0);
+}
+
+/*
+ * Utility function to load a linear buffer. lastaddrp holds state
+ * between invocations (for multiple-buffer loads).  segp contains
+ * the starting segment on entrace, and the ending segment on exit.
+ * first indicates if this is the first invocation of this function.
+ */
+static __inline int
+_bus_dmamap_load_buffer(bus_dma_tag_t dmat,
+			bus_dmamap_t map,
+			void *buf, bus_size_t buflen,
+			int flags,
+			bus_addr_t *lastaddrp,
+			bus_dma_segment_t *segs,
+			int *segp,
+			int first)
+{
+	bus_size_t sgsize;
+	bus_addr_t curaddr, lastaddr, baddr, bmask;
+	vm_offset_t vaddr;
+	struct sync_list *sl;
+	int seg, error;
+
+	if ((dmat->flags & BUS_DMA_COULD_BOUNCE) != 0) {
+		error = _bus_dmamap_count_pages(dmat, map, buf, buflen, flags);
+		if (error)
+			return (error);
+	}
+
+	sl = NULL;
+	vaddr = (vm_offset_t)buf;
+	lastaddr = *lastaddrp;
+	bmask = ~(dmat->boundary - 1);
+
+	for (seg = *segp; buflen > 0 ; ) {
+		/*
+		 * Get the physical address for this segment.
+		 */
+		if (__predict_true(map->pmap == pmap_kernel()))
+			curaddr = pmap_kextract(vaddr);
+		else
+			curaddr = pmap_extract(map->pmap, vaddr);
+
+		/*
+		 * Compute the segment size, and adjust counts.
+		 */
+		sgsize = PAGE_SIZE - ((u_long)curaddr & PAGE_MASK);
+		if (sgsize > dmat->maxsegsz)
+			sgsize = dmat->maxsegsz;
+		if (buflen < sgsize)
+			sgsize = buflen;
+
+		/*
+		 * Make sure we don't cross any boundaries.
+		 */
+		if (dmat->boundary > 0) {
+			baddr = (curaddr + dmat->boundary) & bmask;
+			if (sgsize > (baddr - curaddr))
+				sgsize = (baddr - curaddr);
+		}
+
+		if (((dmat->flags & BUS_DMA_COULD_BOUNCE) != 0) &&
+		    map->pagesneeded != 0 && run_filter(dmat, curaddr)) {
+			curaddr = add_bounce_page(dmat, map, vaddr, sgsize);
+		} else {
+			/* add_sync_list(dmat, map, vaddr, sgsize, cflag); */
+			sl = (struct sync_list *)malloc(sizeof(struct sync_list),
+						M_DEVBUF, M_NOWAIT | M_ZERO);
+			if (sl == NULL)
+				goto cleanup;
+			STAILQ_INSERT_TAIL(&(map->slist), sl, slinks);
+			sl->vaddr = vaddr;
+			sl->datacount = sgsize;
+			sl->busaddr = curaddr;
+		}
+
+
+		if (dmat->ranges) {
+			struct arm32_dma_range *dr;
+
+			dr = _bus_dma_inrange(dmat->ranges, dmat->_nranges,
+			    curaddr);
+			if (dr == NULL) {
+				_bus_dmamap_unload(dmat, map);
+				return (EINVAL);
+			}
+			/*
+			 * In a valid DMA range.  Translate the physical
+			 * memory address to an address in the DMA window.
+			 */
+			curaddr = (curaddr - dr->dr_sysbase) + dr->dr_busbase;
+		}
+
+		/*
+		 * Insert chunk into a segment, coalescing with
+		 * previous segment if possible.
+		 */
+		if (first) {
+			segs[seg].ds_addr = curaddr;
+			segs[seg].ds_len = sgsize;
+			first = 0;
+		} else {
+			if (curaddr == lastaddr &&
+			    (segs[seg].ds_len + sgsize) <= dmat->maxsegsz &&
+			    (dmat->boundary == 0 ||
+			     (segs[seg].ds_addr & bmask) == (curaddr & bmask)))
+				segs[seg].ds_len += sgsize;
+			else {
+				if (++seg >= dmat->nsegments)
+					break;
+				segs[seg].ds_addr = curaddr;
+				segs[seg].ds_len = sgsize;
+			}
+		}
+
+		lastaddr = curaddr + sgsize;
+		vaddr += sgsize;
+		buflen -= sgsize;
+	}
+
+	*segp = seg;
+	*lastaddrp = lastaddr;
+cleanup:
+	/*
+	 * Did we fit?
+	 */
+	if (buflen != 0) {
+		_bus_dmamap_unload(dmat, map);
+		return(EFBIG); /* XXX better return value here? */
+	}
+	return (0);
+}
+
+/*
+ * Map the buffer buf into bus space using the dmamap map.
+ */
+int
+bus_dmamap_load(bus_dma_tag_t dmat, bus_dmamap_t map, void *buf,
+		bus_size_t buflen, bus_dmamap_callback_t *callback,
+		void *callback_arg, int flags)
+{
+	bus_addr_t		lastaddr = 0;
+	int			error, nsegs = 0;
+
+	flags |= BUS_DMA_WAITOK;
+	map->callback = callback;
+	map->callback_arg = callback_arg;
+	map->pmap = kernel_pmap;
+
+	error = _bus_dmamap_load_buffer(dmat, map, buf, buflen, flags,
+		     &lastaddr, dmat->segments, &nsegs, 1);
+
+	CTR5(KTR_BUSDMA, "%s: tag %p tag flags 0x%x error %d nsegs %d",
+	    __func__, dmat, dmat->flags, error, nsegs + 1);
+
+	if (error == EINPROGRESS) {
+		return (error);
+	}
+
+	if (error)
+		(*callback)(callback_arg, dmat->segments, 0, error);
+	else
+		(*callback)(callback_arg, dmat->segments, nsegs + 1, 0);
+
+	/*
+	 * Return ENOMEM to the caller so that it can pass it up the stack.
+	 * This error only happens when NOWAIT is set, so deferal is disabled.
+	 */
+	if (error == ENOMEM)
+		return (error);
+
+	return (0);
+}
+
+
+/*
+ * Like _bus_dmamap_load(), but for mbufs.
+ */
+static __inline int
+_bus_dmamap_load_mbuf_sg(bus_dma_tag_t dmat, bus_dmamap_t map,
+			struct mbuf *m0, bus_dma_segment_t *segs, int *nsegs,
+			int flags)
+{
+	int error;
+
+	M_ASSERTPKTHDR(m0);
+	map->pmap = kernel_pmap;
+
+	flags |= BUS_DMA_NOWAIT;
+	*nsegs = 0;
+	error = 0;
+	if (m0->m_pkthdr.len <= dmat->maxsize) {
+		int first = 1;
+		bus_addr_t lastaddr = 0;
+		struct mbuf *m;
+
+		for (m = m0; m != NULL && error == 0; m = m->m_next) {
+			if (m->m_len > 0) {
+				error = _bus_dmamap_load_buffer(dmat, map,
+						m->m_data, m->m_len,
+						flags, &lastaddr,
+						segs, nsegs, first);
+				first = 0;
+			}
+		}
+	} else {
+		error = EINVAL;
+	}
+
+	/* XXX FIXME: Having to increment nsegs is really annoying */
+	++*nsegs;
+	CTR5(KTR_BUSDMA, "%s: tag %p tag flags 0x%x error %d nsegs %d",
+	    __func__, dmat, dmat->flags, error, *nsegs);
+	return (error);
+}
+
+int
+bus_dmamap_load_mbuf(bus_dma_tag_t dmat, bus_dmamap_t map,
+		     struct mbuf *m0,
+		     bus_dmamap_callback2_t *callback, void *callback_arg,
+		     int flags)
+{
+	int nsegs, error;
+
+	error = _bus_dmamap_load_mbuf_sg(dmat, map, m0, dmat->segments, &nsegs,
+		    flags);
+
+	if (error) {
+		/* force "no valid mappings" in callback */
+		(*callback)(callback_arg, dmat->segments, 0, 0, error);
+	} else {
+		(*callback)(callback_arg, dmat->segments,
+			    nsegs, m0->m_pkthdr.len, error);
+	}
+	CTR5(KTR_BUSDMA, "%s: tag %p tag flags 0x%x error %d nsegs %d",
+	    __func__, dmat, dmat->flags, error, nsegs);
+
+	return (error);
+}
+
+int
+bus_dmamap_load_mbuf_sg(bus_dma_tag_t dmat, bus_dmamap_t map,
+			struct mbuf *m0, bus_dma_segment_t *segs, int *nsegs,
+			int flags)
+{
+	return (_bus_dmamap_load_mbuf_sg(dmat, map, m0, segs, nsegs, flags));
+}
+
+/*
+ * Like _bus_dmamap_load(), but for uios.
+ */
+int
+bus_dmamap_load_uio(bus_dma_tag_t dmat, bus_dmamap_t map,
+		    struct uio *uio,
+		    bus_dmamap_callback2_t *callback, void *callback_arg,
+		    int flags)
+{
+	bus_addr_t lastaddr;
+	int nsegs, error, first, i;
+	bus_size_t resid;
+	struct iovec *iov;
+
+	flags |= BUS_DMA_NOWAIT;
+	resid = uio->uio_resid;
+	iov = uio->uio_iov;
+
+	if (uio->uio_segflg == UIO_USERSPACE) {
+		KASSERT(uio->uio_td != NULL,
+			("bus_dmamap_load_uio: USERSPACE but no proc"));
+		map->pmap = vmspace_pmap(uio->uio_td->td_proc->p_vmspace);
+	} else
+		map->pmap = kernel_pmap;
+
+	nsegs = 0;
+	error = 0;
+	first = 1;
+	lastaddr = (bus_addr_t) 0;
+	for (i = 0; i < uio->uio_iovcnt && resid != 0 && !error; i++) {
+		/*
+		 * Now at the first iovec to load.  Load each iovec
+		 * until we have exhausted the residual count.
+		 */
+		bus_size_t minlen =
+			resid < iov[i].iov_len ? resid : iov[i].iov_len;
+		caddr_t addr = (caddr_t) iov[i].iov_base;
+
+		if (minlen > 0) {
+			error = _bus_dmamap_load_buffer(dmat, map,
+					addr, minlen, flags, &lastaddr,
+					dmat->segments, &nsegs, first);
+			first = 0;
+			resid -= minlen;
+		}
+	}
+
+	if (error) {
+		/* force "no valid mappings" in callback */
+		(*callback)(callback_arg, dmat->segments, 0, 0, error);
+	} else {
+		(*callback)(callback_arg, dmat->segments,
+			    nsegs+1, uio->uio_resid, error);
+	}
+	CTR5(KTR_BUSDMA, "%s: tag %p tag flags 0x%x error %d nsegs %d",
+	    __func__, dmat, dmat->flags, error, nsegs + 1);
+	return (error);
+}
+
+/*
+ * Release the mapping held by map.
+ */
+void
+_bus_dmamap_unload(bus_dma_tag_t dmat, bus_dmamap_t map)
+{
+	struct bounce_page *bpage;
+	struct bounce_zone *bz;
+	struct sync_list *sl;
+
+        while ((sl = STAILQ_FIRST(&map->slist)) != NULL) {
+                STAILQ_REMOVE_HEAD(&map->slist, slinks);
+                free(sl, M_DEVBUF);
+        }
+
+	if ((bz = dmat->bounce_zone) != NULL) {
+		while ((bpage = STAILQ_FIRST(&map->bpages)) != NULL) {
+			STAILQ_REMOVE_HEAD(&map->bpages, links);
+			free_bounce_page(dmat, bpage);
+		}
+
+		bz = dmat->bounce_zone;
+		bz->free_bpages += map->pagesreserved;
+		bz->reserved_bpages -= map->pagesreserved;
+		map->pagesreserved = 0;
+		map->pagesneeded = 0;
+	}
+}
+
+#ifdef notyetbounceuser
+	/* If busdma uses user pages, then the interrupt handler could
+	 * be use the kernel vm mapping. Both bounce pages and sync list
+	 * do not cross page boundaries.
+	 * Below is a rough sequence that a person would do to fix the
+	 * user page reference in the kernel vmspace. This would be
+	 * done in the dma post routine.
+	 */
+void
+_bus_dmamap_fix_user(vm_offset_t buf, bus_size_t len,
+			pmap_t pmap, int op)
+{
+	bus_size_t sgsize;
+	bus_addr_t curaddr;
+	vm_offset_t va;
+
+		/* each synclist entry is contained within a single page.
+		 *
+		 * this would be needed if BUS_DMASYNC_POSTxxxx was implemented
+		*/
+	curaddr = pmap_extract(pmap, buf);
+	va = pmap_dma_map(curaddr);
+	switch (op) {
+	case SYNC_USER_INV:
+		cpu_dcache_wb_range(va, sgsize);
+		break;
+
+	case SYNC_USER_COPYTO:
+		bcopy((void *)va, (void *)bounce, sgsize);
+		break;
+
+	case SYNC_USER_COPYFROM:
+		bcopy((void *) bounce, (void *)va, sgsize);
+		break;
+
+	default:
+		break;
+	}
+
+	pmap_dma_unmap(va);
+}
+#endif
+
+#ifdef ARM_L2_PIPT
+#define l2cache_wb_range(va, pa, size) cpu_l2cache_wb_range(pa, size)
+#define l2cache_wbinv_range(va, pa, size) cpu_l2cache_wbinv_range(pa, size)
+#define l2cache_inv_range(va, pa, size) cpu_l2cache_inv_range(pa, size)
+#else
+#define l2cache_wb_range(va, pa, size) cpu_l2cache_wb_range(va, size)
+#define l2cache_wbinv_range(va, pa, size) cpu_l2cache_wbinv_range(va, size)
+#define l2cache_inv_range(va, pa, size) cpu_l2cache_wbinv_range(va, size)
+#endif
+
+void
+_bus_dmamap_sync(bus_dma_tag_t dmat, bus_dmamap_t map, bus_dmasync_op_t op)
+{
+	struct bounce_page *bpage;
+	struct sync_list *sl;
+	bus_size_t len, unalign;
+	vm_offset_t buf, ebuf;
+#ifdef FIX_DMAP_BUS_DMASYNC_POSTREAD
+	vm_offset_t bbuf;
+	char _tmp_cl[arm_dcache_align], _tmp_clend[arm_dcache_align];
+#endif
+	int listcount = 0;
+
+		/* if buffer was from user space, it it possible that this
+		 * is not the same vm map. The fix is to map each page in
+		 * the buffer into the current address space (KVM) and then
+		 * do the bounce copy or sync list cache operation.
+		 *
+		 * The sync list entries are already broken into
+		 * their respective physical pages.
+		 */
+	if (!pmap_dmap_iscurrent(map->pmap))
+		printf("_bus_dmamap_sync: wrong user map: %p %x\n", map->pmap, op);
+
+	if ((bpage = STAILQ_FIRST(&map->bpages)) != NULL) {
+
+		/* Handle data bouncing. */
+		CTR4(KTR_BUSDMA, "%s: tag %p tag flags 0x%x op 0x%x "
+		    "performing bounce", __func__, dmat, dmat->flags, op);
+
+		if (op & BUS_DMASYNC_PREWRITE) {
+			while (bpage != NULL) {
+				bcopy((void *)bpage->datavaddr,
+				      (void *)bpage->vaddr,
+				      bpage->datacount);
+				cpu_dcache_wb_range((vm_offset_t)bpage->vaddr,
+					bpage->datacount);
+				l2cache_wb_range((vm_offset_t)bpage->vaddr,
+				    (vm_offset_t)bpage->busaddr, 
+				    bpage->datacount);
+				bpage = STAILQ_NEXT(bpage, links);
+			}
+			dmat->bounce_zone->total_bounced++;
+		}
+
+		if (op & BUS_DMASYNC_POSTREAD) {
+			if (!pmap_dmap_iscurrent(map->pmap))
+			    panic("_bus_dmamap_sync: wrong user map. apply fix");
+
+			cpu_dcache_inv_range((vm_offset_t)bpage->vaddr,
+					bpage->datacount);
+			l2cache_inv_range((vm_offset_t)bpage->vaddr,
+			    (vm_offset_t)bpage->busaddr,
+			    bpage->datacount);
+			while (bpage != NULL) {
+				vm_offset_t startv;
+				vm_paddr_t startp;
+				int len;
+
+				startv = bpage->vaddr &~ arm_dcache_align_mask;
+				startp = bpage->busaddr &~ arm_dcache_align_mask;
+				len = bpage->datacount;
+				
+				if (startv != bpage->vaddr)
+					len += bpage->vaddr & arm_dcache_align_mask;
+				if (len & arm_dcache_align_mask) 
+					len = (len -
+					    (len & arm_dcache_align_mask)) +
+					    arm_dcache_align;
+				cpu_dcache_inv_range(startv, len);
+				l2cache_inv_range(startv, startp, len);
+				bcopy((void *)bpage->vaddr,
+				      (void *)bpage->datavaddr,
+				      bpage->datacount);
+				bpage = STAILQ_NEXT(bpage, links);
+			}
+			dmat->bounce_zone->total_bounced++;
+		}
+	}
+
+	sl = STAILQ_FIRST(&map->slist);
+	while (sl) {
+		listcount++;
+		sl = STAILQ_NEXT(sl, slinks);
+	}
+	if ((sl = STAILQ_FIRST(&map->slist)) != NULL) {
+		/* ARM caches are not self-snooping for dma */
+
+		CTR4(KTR_BUSDMA, "%s: tag %p tag flags 0x%x op 0x%x "
+		    "performing sync", __func__, dmat, dmat->flags, op);
+
+		switch (op) {
+		case BUS_DMASYNC_PREWRITE:
+			while (sl != NULL) {
+			    cpu_dcache_wb_range(sl->vaddr, sl->datacount);
+			    l2cache_wb_range(sl->vaddr, sl->busaddr,
+				sl->datacount);
+			    sl = STAILQ_NEXT(sl, slinks);
+			}
+			break;
+
+		case BUS_DMASYNC_PREREAD:
+			while (sl != NULL) {
+					/* write back the unaligned portions */
+				vm_paddr_t physaddr = sl->busaddr, ephysaddr;
+				buf = sl->vaddr;
+				len = sl->datacount;
+				ebuf = buf + len;	/* end of buffer */
+				ephysaddr = physaddr + len;
+				unalign = buf & arm_dcache_align_mask;
+				if (unalign) {
+						/* wbinv leading fragment */
+					buf &= ~arm_dcache_align_mask;
+					physaddr &= ~arm_dcache_align_mask;
+					cpu_dcache_wbinv_range(buf,
+							arm_dcache_align);
+					l2cache_wbinv_range(buf, physaddr,
+					    arm_dcache_align);
+					buf += arm_dcache_align;
+					physaddr += arm_dcache_align;
+					/* number byte in buffer wbinv */
+					unalign = arm_dcache_align - unalign;
+					if (len > unalign)
+						len -= unalign;
+					else
+						len = 0;
+				}
+				unalign = ebuf & arm_dcache_align_mask;
+				if (ebuf > buf && unalign) {
+						/* wbinv trailing fragment */
+					len -= unalign;
+					ebuf -= unalign;
+					ephysaddr -= unalign;
+					cpu_dcache_wbinv_range(ebuf,
+							arm_dcache_align);
+					l2cache_wbinv_range(ebuf, ephysaddr,
+					    arm_dcache_align);
+				}
+				if (ebuf > buf) {
+					cpu_dcache_inv_range(buf, len);
+					l2cache_inv_range(buf, physaddr, len);
+				}
+				sl = STAILQ_NEXT(sl, slinks);
+			}
+			break;
+
+		case BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD:
+			while (sl != NULL) {
+				cpu_dcache_wbinv_range(sl->vaddr, sl->datacount);
+				l2cache_wbinv_range(sl->vaddr,
+				    sl->busaddr, sl->datacount);
+				sl = STAILQ_NEXT(sl, slinks);
+			}
+			break;
+
+#ifdef FIX_DMAP_BUS_DMASYNC_POSTREAD
+		case BUS_DMASYNC_POSTREAD:
+			if (!pmap_dmap_iscurrent(map->pmap))
+			     panic("_bus_dmamap_sync: wrong user map. apply fix");
+			while (sl != NULL) {
+					/* write back the unaligned portions */
+				vm_paddr_t physaddr;
+				buf = sl->vaddr;
+				len = sl->datacount;
+				physaddr = sl->busaddr;
+				bbuf = buf & ~arm_dcache_align_mask;
+				ebuf = buf + len;
+				physaddr = physaddr & ~arm_dcache_align_mask;
+				unalign = buf & arm_dcache_align_mask;
+				if (unalign) {
+					memcpy(_tmp_cl, (void *)bbuf, unalign);
+					len += unalign; /* inv entire cache line */
+				}
+				unalign = ebuf & arm_dcache_align_mask;
+				if (unalign) {
+					unalign = arm_dcache_align - unalign;
+					memcpy(_tmp_clend, (void *)ebuf, unalign);
+					len += unalign; /* inv entire cache line */
+				}
+					/* inv are cache length aligned */
+				cpu_dcache_inv_range(bbuf, len);
+				l2cache_inv_range(bbuf, physaddr, len);
+
+				unalign = (vm_offset_t)buf & arm_dcache_align_mask;
+				if (unalign) {
+					memcpy((void *)bbuf, _tmp_cl, unalign);
+				}
+				unalign = ebuf & arm_dcache_align_mask;
+				if (unalign) {
+					unalign = arm_dcache_align - unalign;
+					memcpy((void *)ebuf, _tmp_clend, unalign);
+				}
+				sl = STAILQ_NEXT(sl, slinks);
+			}
+				break;
+#endif /* FIX_DMAP_BUS_DMASYNC_POSTREAD */
+
+		default:
+			break;
+		}
+	}
+}
+
+static void
+init_bounce_pages(void *dummy __unused)
+{
+
+	total_bpages = 0;
+	STAILQ_INIT(&bounce_zone_list);
+	STAILQ_INIT(&bounce_map_waitinglist);
+	STAILQ_INIT(&bounce_map_callbacklist);
+	mtx_init(&bounce_lock, "bounce pages lock", NULL, MTX_DEF);
+}
+SYSINIT(bpages, SI_SUB_LOCK, SI_ORDER_ANY, init_bounce_pages, NULL);
+
+static struct sysctl_ctx_list *
+busdma_sysctl_tree(struct bounce_zone *bz)
+{
+	return (&bz->sysctl_tree);
+}
+
+static struct sysctl_oid *
+busdma_sysctl_tree_top(struct bounce_zone *bz)
+{
+	return (bz->sysctl_tree_top);
+}
+
+static int
+alloc_bounce_zone(bus_dma_tag_t dmat)
+{
+	struct bounce_zone *bz;
+
+	/* Check to see if we already have a suitable zone */
+	STAILQ_FOREACH(bz, &bounce_zone_list, links) {
+		if ((dmat->alignment <= bz->alignment)
+		 && (dmat->lowaddr >= bz->lowaddr)) {
+			dmat->bounce_zone = bz;
+			return (0);
+		}
+	}
+
+	if ((bz = (struct bounce_zone *)malloc(sizeof(*bz), M_DEVBUF,
+	    M_NOWAIT | M_ZERO)) == NULL)
+		return (ENOMEM);
+
+	STAILQ_INIT(&bz->bounce_page_list);
+	bz->free_bpages = 0;
+	bz->reserved_bpages = 0;
+	bz->active_bpages = 0;
+	bz->lowaddr = dmat->lowaddr;
+	bz->alignment = MAX(dmat->alignment, PAGE_SIZE);
+	bz->map_count = 0;
+	snprintf(bz->zoneid, 8, "zone%d", busdma_zonecount);
+	busdma_zonecount++;
+	snprintf(bz->lowaddrid, 18, "%#jx", (uintmax_t)bz->lowaddr);
+	STAILQ_INSERT_TAIL(&bounce_zone_list, bz, links);
+	dmat->bounce_zone = bz;
+
+	sysctl_ctx_init(&bz->sysctl_tree);
+	bz->sysctl_tree_top = SYSCTL_ADD_NODE(&bz->sysctl_tree,
+	    SYSCTL_STATIC_CHILDREN(_hw_busdma), OID_AUTO, bz->zoneid,
+	    CTLFLAG_RD, 0, "");
+	if (bz->sysctl_tree_top == NULL) {
+		sysctl_ctx_free(&bz->sysctl_tree);
+		return (0);	/* XXX error code? */
+	}
+
+	SYSCTL_ADD_INT(busdma_sysctl_tree(bz),
+	    SYSCTL_CHILDREN(busdma_sysctl_tree_top(bz)), OID_AUTO,
+	    "total_bpages", CTLFLAG_RD, &bz->total_bpages, 0,
+	    "Total bounce pages");
+	SYSCTL_ADD_INT(busdma_sysctl_tree(bz),
+	    SYSCTL_CHILDREN(busdma_sysctl_tree_top(bz)), OID_AUTO,
+	    "free_bpages", CTLFLAG_RD, &bz->free_bpages, 0,
+	    "Free bounce pages");
+	SYSCTL_ADD_INT(busdma_sysctl_tree(bz),
+	    SYSCTL_CHILDREN(busdma_sysctl_tree_top(bz)), OID_AUTO,
+	    "reserved_bpages", CTLFLAG_RD, &bz->reserved_bpages, 0,
+	    "Reserved bounce pages");
+	SYSCTL_ADD_INT(busdma_sysctl_tree(bz),
+	    SYSCTL_CHILDREN(busdma_sysctl_tree_top(bz)), OID_AUTO,
+	    "active_bpages", CTLFLAG_RD, &bz->active_bpages, 0,
+	    "Active bounce pages");
+	SYSCTL_ADD_INT(busdma_sysctl_tree(bz),
+	    SYSCTL_CHILDREN(busdma_sysctl_tree_top(bz)), OID_AUTO,
+	    "total_bounced", CTLFLAG_RD, &bz->total_bounced, 0,
+	    "Total bounce requests");
+	SYSCTL_ADD_INT(busdma_sysctl_tree(bz),
+	    SYSCTL_CHILDREN(busdma_sysctl_tree_top(bz)), OID_AUTO,
+	    "total_deferred", CTLFLAG_RD, &bz->total_deferred, 0,
+	    "Total bounce requests that were deferred");
+	SYSCTL_ADD_STRING(busdma_sysctl_tree(bz),
+	    SYSCTL_CHILDREN(busdma_sysctl_tree_top(bz)), OID_AUTO,
+	    "lowaddr", CTLFLAG_RD, bz->lowaddrid, 0, "");
+	SYSCTL_ADD_INT(busdma_sysctl_tree(bz),
+	    SYSCTL_CHILDREN(busdma_sysctl_tree_top(bz)), OID_AUTO,
+	    "alignment", CTLFLAG_RD, &bz->alignment, 0, "");
+
+	return (0);
+}
+
+static int
+alloc_bounce_pages(bus_dma_tag_t dmat, u_int numpages)
+{
+	struct bounce_zone *bz;
+	int count;
+
+	bz = dmat->bounce_zone;
+	count = 0;
+	while (numpages > 0) {
+		struct bounce_page *bpage;
+
+		bpage = (struct bounce_page *)malloc(sizeof(*bpage), M_DEVBUF,
+						     M_NOWAIT | M_ZERO);
+
+		if (bpage == NULL)
+			break;
+		bpage->vaddr = (vm_offset_t)contigmalloc(PAGE_SIZE, M_DEVBUF,
+							 M_NOWAIT, 0ul,
+							 bz->lowaddr,
+							 PAGE_SIZE,
+							 0);
+		if (bpage->vaddr == 0) {
+			free(bpage, M_DEVBUF);
+			break;
+		}
+		bpage->busaddr = pmap_kextract(bpage->vaddr);
+		mtx_lock(&bounce_lock);
+		STAILQ_INSERT_TAIL(&bz->bounce_page_list, bpage, links);
+		total_bpages++;
+		bz->total_bpages++;
+		bz->free_bpages++;
+		mtx_unlock(&bounce_lock);
+		count++;
+		numpages--;
+	}
+	return (count);
+}
+
+static int
+reserve_bounce_pages(bus_dma_tag_t dmat, bus_dmamap_t map, int commit)
+{
+	struct bounce_zone *bz;
+	int pages;
+
+	mtx_assert(&bounce_lock, MA_OWNED);
+	bz = dmat->bounce_zone;
+	pages = MIN(bz->free_bpages, map->pagesneeded - map->pagesreserved);
+	if (commit == 0 && map->pagesneeded > (map->pagesreserved + pages))
+		return (map->pagesneeded - (map->pagesreserved + pages));
+	bz->free_bpages -= pages;
+	bz->reserved_bpages += pages;
+	map->pagesreserved += pages;
+	pages = map->pagesneeded - map->pagesreserved;
+
+	return (pages);
+}
+
+static bus_addr_t
+add_bounce_page(bus_dma_tag_t dmat, bus_dmamap_t map, vm_offset_t vaddr,
+		bus_size_t size)
+{
+	struct bounce_zone *bz;
+	struct bounce_page *bpage;
+
+	printf("add bounce page\n");
+	KASSERT(dmat->bounce_zone != NULL, ("no bounce zone in dma tag"));
+	KASSERT(map != NULL,
+	    ("add_bounce_page: bad map %p", map));
+
+	bz = dmat->bounce_zone;
+	if (map->pagesneeded == 0)
+		panic("add_bounce_page: map doesn't need any pages");
+	map->pagesneeded--;
+
+	if (map->pagesreserved == 0)
+		panic("add_bounce_page: map doesn't need any pages");
+	map->pagesreserved--;
+
+	mtx_lock(&bounce_lock);
+	bpage = STAILQ_FIRST(&bz->bounce_page_list);
+	if (bpage == NULL)
+		panic("add_bounce_page: free page list is empty");
+
+	STAILQ_REMOVE_HEAD(&bz->bounce_page_list, links);
+	bz->reserved_bpages--;
+	bz->active_bpages++;
+	mtx_unlock(&bounce_lock);
+
+	if (dmat->flags & BUS_DMA_KEEP_PG_OFFSET) {
+		/* Page offset needs to be preserved. */
+		bpage->vaddr |= vaddr & PAGE_MASK;
+		bpage->busaddr |= vaddr & PAGE_MASK;
+	}
+	bpage->datavaddr = vaddr;
+	bpage->datacount = size;
+	STAILQ_INSERT_TAIL(&(map->bpages), bpage, links);
+	return (bpage->busaddr);
+}
+
+static void
+free_bounce_page(bus_dma_tag_t dmat, struct bounce_page *bpage)
+{
+	struct bus_dmamap *map;
+	struct bounce_zone *bz;
+
+	bz = dmat->bounce_zone;
+	bpage->datavaddr = 0;
+	bpage->datacount = 0;
+	if (dmat->flags & BUS_DMA_KEEP_PG_OFFSET) {
+		/*
+		 * Reset the bounce page to start at offset 0.  Other uses
+		 * of this bounce page may need to store a full page of
+		 * data and/or assume it starts on a page boundary.
+		 */
+		bpage->vaddr &= ~PAGE_MASK;
+		bpage->busaddr &= ~PAGE_MASK;
+	}
+
+	mtx_lock(&bounce_lock);
+	STAILQ_INSERT_HEAD(&bz->bounce_page_list, bpage, links);
+	bz->free_bpages++;
+	bz->active_bpages--;
+	if ((map = STAILQ_FIRST(&bounce_map_waitinglist)) != NULL) {
+		if (reserve_bounce_pages(map->dmat, map, 1) == 0) {
+			STAILQ_REMOVE_HEAD(&bounce_map_waitinglist, links);
+			STAILQ_INSERT_TAIL(&bounce_map_callbacklist,
+					   map, links);
+			busdma_swi_pending = 1;
+			bz->total_deferred++;
+			swi_sched(vm_ih, 0);
+		}
+	}
+	mtx_unlock(&bounce_lock);
+}
+
+void
+busdma_swi(void)
+{
+	bus_dma_tag_t dmat;
+	struct bus_dmamap *map;
+
+	mtx_lock(&bounce_lock);
+	while ((map = STAILQ_FIRST(&bounce_map_callbacklist)) != NULL) {
+		STAILQ_REMOVE_HEAD(&bounce_map_callbacklist, links);
+		mtx_unlock(&bounce_lock);
+		dmat = map->dmat;
+		(dmat->lockfunc)(dmat->lockfuncarg, BUS_DMA_LOCK);
+		bus_dmamap_load(map->dmat, map, map->buf, map->buflen,
+				map->callback, map->callback_arg, /*flags*/0);
+		(dmat->lockfunc)(dmat->lockfuncarg, BUS_DMA_UNLOCK);
+		mtx_lock(&bounce_lock);
+	}
+	mtx_unlock(&bounce_lock);
+}
diff -r 7fffa673adcd -r a301a330526b head/sys/arm/arm/copystr.S
--- a/head/sys/arm/arm/copystr.S	Wed Aug 15 11:15:12 2012 +0300
+++ b/head/sys/arm/arm/copystr.S	Wed Aug 15 11:16:36 2012 +0300
@@ -43,18 +43,23 @@
 #include <machine/asm.h>
 #include <machine/armreg.h>
 #include <machine/asmacros.h>
-__FBSDID("$FreeBSD$");
+__FBSDID("$FreeBSD: head/sys/arm/arm/copystr.S 239268 2012-08-15 03:03:03Z gonzo $");
 
 #include <sys/errno.h>
 
 	.text
 	.align	0
-#ifdef MULTIPROCESSOR
-.Lcpu_info:
-	.word	_C_LABEL(cpu_info)
+
+#ifdef _ARM_ARCH_6
+#define GET_PCB(tmp) \
+	mrc p15, 0, tmp, c13, c0, 4; \
+	add	tmp, tmp, #(PC_CURPCB)
 #else
 .Lpcb:
 	.word	_C_LABEL(__pcpu) + PC_CURPCB
+
+#define GET_PCB(tmp) \
+	ldr	tmp, .Lpcb
 #endif
 
 /*
@@ -108,18 +113,8 @@
 	moveq	r0, #ENAMETOOLONG
 	beq	2f
 
-#ifdef MULTIPROCESSOR
-	/* XXX Probably not appropriate for non-Hydra SMPs */
-	stmfd	sp!, {r0-r3, r14}
-	bl	_C_LABEL(cpu_number)
-	ldr	r4, .Lcpu_info
-	ldr	r4, [r4, r0, lsl #2]
-	ldr	r4, [r4, #CI_CURPCB]
-	ldmfd	sp!, {r0-r3, r14}
-#else
-	ldr	r4, .Lpcb
+	GET_PCB(r4)
 	ldr	r4, [r4]
-#endif
 
 #ifdef DIAGNOSTIC
 	teq	r4, #0x00000000
@@ -165,18 +160,8 @@
 	moveq	r0, #ENAMETOOLONG
 	beq	2f
 
-#ifdef MULTIPROCESSOR
-	/* XXX Probably not appropriate for non-Hydra SMPs */
-	stmfd	sp!, {r0-r3, r14}
-	bl	_C_LABEL(cpu_number)
-	ldr	r4, .Lcpu_info
-	ldr	r4, [r4, r0, lsl #2]
-	ldr	r4, [r4, #CI_CURPCB]
-	ldmfd	sp!, {r0-r3, r14}
-#else
-	ldr	r4, .Lpcb
+	GET_PCB(r4)
 	ldr	r4, [r4]
-#endif
 
 #ifdef DIAGNOSTIC
 	teq	r4, #0x00000000
diff -r 7fffa673adcd -r a301a330526b head/sys/arm/arm/cpufunc.c
--- a/head/sys/arm/arm/cpufunc.c	Wed Aug 15 11:15:12 2012 +0300
+++ b/head/sys/arm/arm/cpufunc.c	Wed Aug 15 11:16:36 2012 +0300
@@ -45,7 +45,7 @@
  * Created      : 30/01/97
  */
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD: head/sys/arm/arm/cpufunc.c 236991 2012-06-13 04:59:55Z imp $");
+__FBSDID("$FreeBSD: head/sys/arm/arm/cpufunc.c 239268 2012-08-15 03:03:03Z gonzo $");
 
 #include <sys/param.h>
 #include <sys/systm.h>
@@ -98,6 +98,10 @@
 int	arm_dcache_align;
 int	arm_dcache_align_mask;
 
+u_int	arm_cache_level;
+u_int	arm_cache_type[14];
+u_int	arm_cache_loc;
+
 /* 1 == use cpu_sleep(), 0 == don't */
 int cpu_do_powersave;
 int ctrl;
@@ -472,6 +476,126 @@
 };
 #endif /* CPU_ARM10 */
 
+#ifdef CPU_MV_PJ4B
+struct cpu_functions pj4bv7_cpufuncs = {
+	/* CPU functions */
+
+	cpufunc_id,			/* id			*/
+	arm11_drain_writebuf,		/* cpwait		*/
+
+	/* MMU functions */
+
+	cpufunc_control,		/* control		*/
+	cpufunc_domains,		/* Domain		*/
+	pj4b_setttb,			/* Setttb		*/
+	cpufunc_faultstatus,		/* Faultstatus		*/
+	cpufunc_faultaddress,		/* Faultaddress		*/
+
+	/* TLB functions */
+
+	armv7_tlb_flushID,		/* tlb_flushID		*/
+	armv7_tlb_flushID_SE,		/* tlb_flushID_SE	*/
+	armv7_tlb_flushID,		/* tlb_flushI		*/
+	armv7_tlb_flushID_SE,		/* tlb_flushI_SE	*/
+	armv7_tlb_flushID,		/* tlb_flushD		*/
+	armv7_tlb_flushID_SE,		/* tlb_flushD_SE	*/
+
+	/* Cache operations */
+	armv7_idcache_wbinv_all,	/* icache_sync_all	*/
+	armv7_icache_sync_range,	/* icache_sync_range	*/
+
+	armv7_dcache_wbinv_all,		/* dcache_wbinv_all	*/
+	armv7_dcache_wbinv_range,	/* dcache_wbinv_range	*/
+	armv7_dcache_inv_range,		/* dcache_inv_range	*/
+	armv7_dcache_wb_range,		/* dcache_wb_range	*/
+
+	armv7_idcache_wbinv_all,	/* idcache_wbinv_all	*/
+	armv7_idcache_wbinv_range,	/* idcache_wbinv_all	*/
+
+	(void *)cpufunc_nullop,		/* l2cache_wbinv_all	*/
+	(void *)cpufunc_nullop,		/* l2cache_wbinv_range	*/
+	(void *)cpufunc_nullop,		/* l2cache_inv_range	*/
+	(void *)cpufunc_nullop,		/* l2cache_wb_range	*/
+
+	/* Other functions */
+
+	pj4b_drain_readbuf,		/* flush_prefetchbuf	*/
+	arm11_drain_writebuf,		/* drain_writebuf	*/
+	pj4b_flush_brnchtgt_all,	/* flush_brnchtgt_C	*/
+	pj4b_flush_brnchtgt_va,		/* flush_brnchtgt_E	*/
+
+	(void *)cpufunc_nullop,		/* sleep		*/
+
+	/* Soft functions */
+
+	cpufunc_null_fixup,		/* dataabt_fixup	*/
+	cpufunc_null_fixup,		/* prefetchabt_fixup	*/
+
+	arm11_context_switch,		/* context_switch	*/
+
+	pj4bv7_setup			/* cpu setup		*/
+};
+
+struct cpu_functions pj4bv6_cpufuncs = {
+	/* CPU functions */
+
+	cpufunc_id,			/* id			*/
+	arm11_drain_writebuf,		/* cpwait		*/
+
+	/* MMU functions */
+
+	cpufunc_control,		/* control		*/
+	cpufunc_domains,		/* Domain		*/
+	pj4b_setttb,			/* Setttb		*/
+	cpufunc_faultstatus,		/* Faultstatus		*/
+	cpufunc_faultaddress,		/* Faultaddress		*/
+
+	/* TLB functions */
+
+	arm11_tlb_flushID,		/* tlb_flushID		*/
+	arm11_tlb_flushID_SE,		/* tlb_flushID_SE	*/
+	arm11_tlb_flushI,		/* tlb_flushI		*/
+	arm11_tlb_flushI_SE,		/* tlb_flushI_SE	*/
+	arm11_tlb_flushD,		/* tlb_flushD		*/
+	arm11_tlb_flushD_SE,		/* tlb_flushD_SE	*/
+
+	/* Cache operations */
+	armv6_icache_sync_all,		/* icache_sync_all	*/
+	pj4b_icache_sync_range,		/* icache_sync_range	*/
+
+	armv6_dcache_wbinv_all,		/* dcache_wbinv_all	*/
+	pj4b_dcache_wbinv_range,	/* dcache_wbinv_range	*/
+	pj4b_dcache_inv_range,		/* dcache_inv_range	*/
+	pj4b_dcache_wb_range,		/* dcache_wb_range	*/
+
+	armv6_idcache_wbinv_all,	/* idcache_wbinv_all	*/
+	pj4b_idcache_wbinv_range,	/* idcache_wbinv_all	*/
+
+	(void *)cpufunc_nullop,		/* l2cache_wbinv_all	*/
+	(void *)cpufunc_nullop,		/* l2cache_wbinv_range	*/
+	(void *)cpufunc_nullop,		/* l2cache_inv_range	*/
+	(void *)cpufunc_nullop,		/* l2cache_wb_range	*/
+
+	/* Other functions */
+
+	pj4b_drain_readbuf,		/* flush_prefetchbuf	*/
+	arm11_drain_writebuf,		/* drain_writebuf	*/
+	pj4b_flush_brnchtgt_all,	/* flush_brnchtgt_C	*/
+	pj4b_flush_brnchtgt_va,		/* flush_brnchtgt_E	*/
+
+	(void *)cpufunc_nullop,		/* sleep		*/
+
+	/* Soft functions */
+
+	cpufunc_null_fixup,		/* dataabt_fixup	*/
+	cpufunc_null_fixup,		/* prefetchabt_fixup	*/
+
+	arm11_context_switch,		/* context_switch	*/
+
+	pj4bv6_setup			/* cpu setup		*/
+};
+#endif /* CPU_MV_PJ4B */
+
 #ifdef CPU_SA110
 struct cpu_functions sa110_cpufuncs = {
 	/* CPU functions */
@@ -844,6 +968,70 @@
 };
 #endif	/* CPU_FA526 || CPU_FA626TE */
 
+#if defined(CPU_CORTEXA)
+struct cpu_functions cortexa_cpufuncs = {
+	/* CPU functions */
+	
+	cpufunc_id,                     /* id                   */
+	cpufunc_nullop,                 /* cpwait               */
+	
+	/* MMU functions */
+	
+	cpufunc_control,                /* control              */
+	cpufunc_domains,                /* Domain               */
+	armv7_setttb,                   /* Setttb               */
+	cpufunc_faultstatus,            /* Faultstatus          */
+	cpufunc_faultaddress,           /* Faultaddress         */
+	
+	/* TLB functions */
+	
+	arm11_tlb_flushID,              /* tlb_flushID          */
+	armv7_tlb_flushID_SE,           /* tlb_flushID_SE       */
+	arm11_tlb_flushI,               /* tlb_flushI           */
+	arm11_tlb_flushI_SE,            /* tlb_flushI_SE        */
+	arm11_tlb_flushD,               /* tlb_flushD           */
+	arm11_tlb_flushD_SE,            /* tlb_flushD_SE        */
+	
+	/* Cache operations */
+	
+	armv7_idcache_wbinv_all,         /* icache_sync_all      */
+	armv7_icache_sync_range,        /* icache_sync_range    */
+	
+	armv7_dcache_wbinv_all,         /* dcache_wbinv_all     */
+	armv7_dcache_wbinv_range,       /* dcache_wbinv_range   */
+	armv7_dcache_inv_range,         /* dcache_inv_range     */
+	armv7_dcache_wb_range,          /* dcache_wb_range      */
+	
+	armv7_idcache_wbinv_all,        /* idcache_wbinv_all    */
+	armv7_idcache_wbinv_range,      /* idcache_wbinv_range  */
+	
+	/* Note: From OMAP4 the L2 ops are filled in when the
+	 * L2 cache controller is actually enabled.
+	 */
+	cpufunc_nullop,                 /* l2cache_wbinv_all    */
+	(void *)cpufunc_nullop,         /* l2cache_wbinv_range  */
+	(void *)cpufunc_nullop,         /* l2cache_inv_range    */
+	(void *)cpufunc_nullop,         /* l2cache_wb_range     */
+	
+	/* Other functions */
+	
+	cpufunc_nullop,                 /* flush_prefetchbuf    */
+	arm11_drain_writebuf,           /* drain_writebuf       */
+	cpufunc_nullop,                 /* flush_brnchtgt_C     */
+	(void *)cpufunc_nullop,         /* flush_brnchtgt_E     */
+	
+	arm11_sleep,                    /* sleep                */
+	
+	/* Soft functions */
+	
+	cpufunc_null_fixup,             /* dataabt_fixup        */
+	cpufunc_null_fixup,             /* prefetchabt_fixup    */
+	
+	arm11_context_switch,           /* context_switch       */
+	
+	cortexa_setup                     /* cpu setup            */
+};
+#endif /* CPU_CORTEXA */
 
 /*
  * Global constants also used by locore.s
@@ -854,11 +1042,12 @@
 u_int cpu_reset_needs_v4_MMU_disable;	/* flag used in locore.s */
 
 #if defined(CPU_ARM7TDMI) || defined(CPU_ARM8) || defined(CPU_ARM9) ||	\
-  defined (CPU_ARM9E) || defined (CPU_ARM10) ||				\
+  defined (CPU_ARM9E) || defined (CPU_ARM10) || defined (CPU_ARM11) ||	\
   defined(CPU_XSCALE_80200) || defined(CPU_XSCALE_80321) ||		\
   defined(CPU_XSCALE_PXA2X0) || defined(CPU_XSCALE_IXP425) ||		\
-  defined(CPU_FA526) || defined(CPU_FA626TE) ||				\
-  defined(CPU_XSCALE_80219) || defined(CPU_XSCALE_81342)
+  defined(CPU_FA526) || defined(CPU_FA626TE) || defined(CPU_MV_PJ4B) ||			\
+  defined(CPU_XSCALE_80219) || defined(CPU_XSCALE_81342) || \
+  defined(CPU_CORTEXA)
 
 static void get_cachetype_cp15(void);
 
@@ -871,12 +1060,15 @@
 static void
 get_cachetype_cp15()
 {
-	u_int ctype, isize, dsize;
+	u_int ctype, isize, dsize, cpuid;
+	u_int clevel, csize, i, sel;
 	u_int multiplier;
+	u_char type;
 
 	__asm __volatile("mrc p15, 0, %0, c0, c0, 1"
 		: "=r" (ctype));
 
+	cpuid = cpufunc_id();
 	/*
 	 * ...and thus spake the ARM ARM:
 	 *
@@ -884,57 +1076,89 @@
 	 * reserved ID register is encountered, the System Control
 	 * processor returns the value of the main ID register.
 	 */
-	if (ctype == cpufunc_id())
+	if (ctype == cpuid)
 		goto out;
 
-	if ((ctype & CPU_CT_S) == 0)
-		arm_pcache_unified = 1;
-
-	/*
-	 * If you want to know how this code works, go read the ARM ARM.
-	 */
-
-	arm_pcache_type = CPU_CT_CTYPE(ctype);
-
-	if (arm_pcache_unified == 0) {
-		isize = CPU_CT_ISIZE(ctype);
-		multiplier = (isize & CPU_CT_xSIZE_M) ? 3 : 2;
-		arm_picache_line_size = 1U << (CPU_CT_xSIZE_LEN(isize) + 3);
-		if (CPU_CT_xSIZE_ASSOC(isize) == 0) {
-			if (isize & CPU_CT_xSIZE_M)
-				arm_picache_line_size = 0; /* not present */
+	if (CPU_CT_FORMAT(ctype) == CPU_CT_ARMV7) {
+		__asm __volatile("mrc p15, 1, %0, c0, c0, 1"
+		    : "=r" (clevel));
+		arm_cache_level = clevel;
+		arm_cache_loc = CPU_CLIDR_LOC(arm_cache_level);
+		i = 0;
+		while ((type = (clevel & 0x7)) && i < 7) {
+			if (type == CACHE_DCACHE || type == CACHE_UNI_CACHE ||
+			    type == CACHE_SEP_CACHE) {
+				sel = i << 1;
+				__asm __volatile("mcr p15, 2, %0, c0, c0, 0"
+				    : : "r" (sel));
+				__asm __volatile("mrc p15, 1, %0, c0, c0, 0"
+				    : "=r" (csize));
+				arm_cache_type[sel] = csize;
+				arm_dcache_align = 1 << 
+				    (CPUV7_CT_xSIZE_LEN(csize) + 4);
+				arm_dcache_align_mask = arm_dcache_align - 1;
+			}
+			if (type == CACHE_ICACHE || type == CACHE_SEP_CACHE) {
+				sel = (i << 1) | 1;
+				__asm __volatile("mcr p15, 2, %0, c0, c0, 0"
+				    : : "r" (sel));
+				__asm __volatile("mrc p15, 1, %0, c0, c0, 0"
+				    : "=r" (csize));
+				arm_cache_type[sel] = csize;
+			}
+			i++;
+			clevel >>= 3;
+		}
+	} else {
+		if ((ctype & CPU_CT_S) == 0)
+			arm_pcache_unified = 1;
+
+		/*
+		 * If you want to know how this code works, go read the ARM ARM.
+		 */
+
+		arm_pcache_type = CPU_CT_CTYPE(ctype);
+
+		if (arm_pcache_unified == 0) {
+			isize = CPU_CT_ISIZE(ctype);
+			multiplier = (isize & CPU_CT_xSIZE_M) ? 3 : 2;
+			arm_picache_line_size = 1U << (CPU_CT_xSIZE_LEN(isize) + 3);
+			if (CPU_CT_xSIZE_ASSOC(isize) == 0) {
+				if (isize & CPU_CT_xSIZE_M)
+					arm_picache_line_size = 0; /* not present */
+				else
+					arm_picache_ways = 1;
+			} else {
+				arm_picache_ways = multiplier <<
+				    (CPU_CT_xSIZE_ASSOC(isize) - 1);
+			}
+			arm_picache_size = multiplier << (CPU_CT_xSIZE_SIZE(isize) + 8);
+		}
+
+		dsize = CPU_CT_DSIZE(ctype);
+		multiplier = (dsize & CPU_CT_xSIZE_M) ? 3 : 2;
+		arm_pdcache_line_size = 1U << (CPU_CT_xSIZE_LEN(dsize) + 3);
+		if (CPU_CT_xSIZE_ASSOC(dsize) == 0) {
+			if (dsize & CPU_CT_xSIZE_M)
+				arm_pdcache_line_size = 0; /* not present */
 			else
-				arm_picache_ways = 1;
+				arm_pdcache_ways = 1;
 		} else {
-			arm_picache_ways = multiplier <<
-			    (CPU_CT_xSIZE_ASSOC(isize) - 1);
+			arm_pdcache_ways = multiplier <<
+			    (CPU_CT_xSIZE_ASSOC(dsize) - 1);
 		}
-		arm_picache_size = multiplier << (CPU_CT_xSIZE_SIZE(isize) + 8);
+		arm_pdcache_size = multiplier << (CPU_CT_xSIZE_SIZE(dsize) + 8);
+
+		arm_dcache_align = arm_pdcache_line_size;
+
+		arm_dcache_l2_assoc = CPU_CT_xSIZE_ASSOC(dsize) + multiplier - 2;
+		arm_dcache_l2_linesize = CPU_CT_xSIZE_LEN(dsize) + 3;
+		arm_dcache_l2_nsets = 6 + CPU_CT_xSIZE_SIZE(dsize) -
+		    CPU_CT_xSIZE_ASSOC(dsize) - CPU_CT_xSIZE_LEN(dsize);
+
+	out:
+		arm_dcache_align_mask = arm_dcache_align - 1;
 	}
-
-	dsize = CPU_CT_DSIZE(ctype);
-	multiplier = (dsize & CPU_CT_xSIZE_M) ? 3 : 2;
-	arm_pdcache_line_size = 1U << (CPU_CT_xSIZE_LEN(dsize) + 3);
-	if (CPU_CT_xSIZE_ASSOC(dsize) == 0) {
-		if (dsize & CPU_CT_xSIZE_M)
-			arm_pdcache_line_size = 0; /* not present */
-		else
-			arm_pdcache_ways = 1;
-	} else {
-		arm_pdcache_ways = multiplier <<
-		    (CPU_CT_xSIZE_ASSOC(dsize) - 1);
-	}
-	arm_pdcache_size = multiplier << (CPU_CT_xSIZE_SIZE(dsize) + 8);
-
-	arm_dcache_align = arm_pdcache_line_size;
-
-	arm_dcache_l2_assoc = CPU_CT_xSIZE_ASSOC(dsize) + multiplier - 2;
-	arm_dcache_l2_linesize = CPU_CT_xSIZE_LEN(dsize) + 3;
-	arm_dcache_l2_nsets = 6 + CPU_CT_xSIZE_SIZE(dsize) -
-	    CPU_CT_xSIZE_ASSOC(dsize) - CPU_CT_xSIZE_LEN(dsize);
-
- out:
-	arm_dcache_align_mask = arm_dcache_align - 1;
 }
 #endif /* ARM7TDMI || ARM8 || ARM9 || XSCALE */
 
@@ -1049,40 +1273,32 @@
 	}
 #endif /* CPU_ARM9 */
 #if defined(CPU_ARM9E) || defined(CPU_ARM10)
-	if (cputype == CPU_ID_ARM926EJS || cputype == CPU_ID_ARM1026EJS ||
-	    cputype == CPU_ID_MV88FR131 || cputype == CPU_ID_MV88FR571_VD ||
+	if (cputype == CPU_ID_MV88FR131 || cputype == CPU_ID_MV88FR571_VD ||
 	    cputype == CPU_ID_MV88FR571_41) {
-		if (cputype == CPU_ID_MV88FR131 ||
-		    cputype == CPU_ID_MV88FR571_VD ||
-		    cputype == CPU_ID_MV88FR571_41) {
-
-			cpufuncs = sheeva_cpufuncs;
-			/*
-			 * Workaround for Marvell MV78100 CPU: Cache prefetch
-			 * mechanism may affect the cache coherency validity,
-			 * so it needs to be disabled.
-			 *
-			 * Refer to errata document MV-S501058-00C.pdf (p. 3.1
-			 * L2 Prefetching Mechanism) for details.
-			 */
-			if (cputype == CPU_ID_MV88FR571_VD ||
-			    cputype == CPU_ID_MV88FR571_41) {
-				sheeva_control_ext(0xffffffff,
-				    FC_DCACHE_STREAM_EN | FC_WR_ALLOC_EN |
-				    FC_BRANCH_TARG_BUF_DIS | FC_L2CACHE_EN |
-				    FC_L2_PREF_DIS);
-			} else {
-				sheeva_control_ext(0xffffffff,
-				    FC_DCACHE_STREAM_EN | FC_WR_ALLOC_EN |
-				    FC_BRANCH_TARG_BUF_DIS | FC_L2CACHE_EN);
-			}
-
-			/* Use powersave on this CPU. */
-			cpu_do_powersave = 1;
-		} else
-			cpufuncs = armv5_ec_cpufuncs;
-
-		cpu_reset_needs_v4_MMU_disable = 1;	/* V4 or higher */
+		uint32_t sheeva_ctrl;
+
+		sheeva_ctrl = (MV_DC_STREAM_ENABLE | MV_BTB_DISABLE |
+		    MV_L2_ENABLE);
+		/*
+		 * Workaround for Marvell MV78100 CPU: Cache prefetch
+		 * mechanism may affect the cache coherency validity,
+		 * so it needs to be disabled.
+		 *
+		 * Refer to errata document MV-S501058-00C.pdf (p. 3.1
+		 * L2 Prefetching Mechanism) for details.
+		 */
+		if (cputype == CPU_ID_MV88FR571_VD ||
+		    cputype == CPU_ID_MV88FR571_41)
+			sheeva_ctrl |= MV_L2_PREFETCH_DISABLE;
+
+		sheeva_control_ext(0xffffffff & ~MV_WA_ENABLE, sheeva_ctrl);
+
+		cpufuncs = sheeva_cpufuncs;
+		get_cachetype_cp15();
+		pmap_pte_init_generic();
+		goto out;
+	} else if (cputype == CPU_ID_ARM926EJS || cputype == CPU_ID_ARM1026EJS) {
+		cpufuncs = armv5_ec_cpufuncs;
 		get_cachetype_cp15();
 		pmap_pte_init_generic();
 		goto out;
@@ -1108,6 +1324,45 @@
 		goto out;
 	}
 #endif /* CPU_ARM10 */
+#ifdef CPU_CORTEXA
+	if (cputype == CPU_ID_CORTEXA8R1 ||
+	    cputype == CPU_ID_CORTEXA8R2 ||
+	    cputype == CPU_ID_CORTEXA8R3 ||
+	    cputype == CPU_ID_CORTEXA9R1 ||
+	    cputype == CPU_ID_CORTEXA9R2) {
+		cpufuncs = cortexa_cpufuncs;
+		cpu_reset_needs_v4_MMU_disable = 1;     /* V4 or higher */
+		get_cachetype_cp15();
+		
+		pmap_pte_init_mmu_v6();
+		/* Use powersave on this CPU. */
+		cpu_do_powersave = 1;
+		goto out;
+	}
+#endif /* CPU_CORTEXA */
+		
+#if defined(CPU_MV_PJ4B)
+	if (cputype == CPU_ID_MV88SV581X_V6 ||
+	    cputype == CPU_ID_MV88SV581X_V7 ||
+	    cputype == CPU_ID_ARM_88SV581X_V6 ||
+	    cputype == CPU_ID_ARM_88SV581X_V7) {
+		if (cpu_pfr(0) & ARM_PFR0_THUMBEE_MASK)
+			cpufuncs = pj4bv7_cpufuncs;
+		else
+			cpufuncs = pj4bv6_cpufuncs;
+
+		get_cachetype_cp15();
+		pmap_pte_init_mmu_v6();
+		goto out;
+	} else if (cputype == CPU_ID_ARM_88SV584X ||
+	    cputype == CPU_ID_MV88SV584X) {
+		cpufuncs = pj4bv6_cpufuncs;
+		get_cachetype_cp15();
+		pmap_pte_init_mmu_v6();
+		goto out;
+	}
+
+#endif /* CPU_MV_PJ4B */
 #ifdef CPU_SA110
 	if (cputype == CPU_ID_SA110) {
 		cpufuncs = sa110_cpufuncs;
@@ -1970,7 +2225,6 @@
 	__asm __volatile ("mcr\tp15, 0, r0, c7, c7, 0" : : );
 
 	/* Set the control register */
-	curcpu()->ci_ctrl = cpuctrl;
 	cpu_control(0xffffffff, cpuctrl);
 
 	/* And again. */
@@ -1978,6 +2232,126 @@
 }
 #endif	/* CPU_ARM11 */
 
+#ifdef CPU_MV_PJ4B
+void
+pj4bv6_setup(char *args)
+{
+	int cpuctrl;
+
+	pj4b_config();
+
+	cpuctrl = CPU_CONTROL_MMU_ENABLE;
+#ifndef ARM32_DISABLE_ALIGNMENT_FAULTS
+	cpuctrl |= CPU_CONTROL_AFLT_ENABLE;
+#endif
+	cpuctrl |= CPU_CONTROL_DC_ENABLE;
+	cpuctrl |= (0xf << 3);
+#ifdef __ARMEB__
+	cpuctrl |= CPU_CONTROL_BEND_ENABLE;
+#endif
+	cpuctrl |= CPU_CONTROL_SYST_ENABLE;
+	cpuctrl |= CPU_CONTROL_BPRD_ENABLE;
+	cpuctrl |= CPU_CONTROL_IC_ENABLE;
+	if (vector_page == ARM_VECTORS_HIGH)
+		cpuctrl |= CPU_CONTROL_VECRELOC;
+	cpuctrl |= (0x5 << 16);
+	cpuctrl |= CPU_CONTROL_V6_EXTPAGE;
+	/* XXX not yet */
+	/* cpuctrl |= CPU_CONTROL_L2_ENABLE; */
+
+	/* Make sure caches are clean.  */
+	cpu_idcache_wbinv_all();
+	cpu_l2cache_wbinv_all();
+
+	/* Set the control register */
+	ctrl = cpuctrl;
+	cpu_control(0xffffffff, cpuctrl);
+
+	cpu_idcache_wbinv_all();
+	cpu_l2cache_wbinv_all();
+}
+
+void
+pj4bv7_setup(args)
+	char *args;
+{
+	int cpuctrl;
+
+	pj4b_config();
+
+	cpuctrl = CPU_CONTROL_MMU_ENABLE;
+#ifndef ARM32_DISABLE_ALIGNMENT_FAULTS
+	cpuctrl |= CPU_CONTROL_AFLT_ENABLE;
+#endif
+	cpuctrl |= CPU_CONTROL_DC_ENABLE;
+	cpuctrl |= (0xf << 3);
+	cpuctrl |= CPU_CONTROL_BPRD_ENABLE;
+	cpuctrl |= CPU_CONTROL_IC_ENABLE;
+	if (vector_page == ARM_VECTORS_HIGH)
+		cpuctrl |= CPU_CONTROL_VECRELOC;
+	cpuctrl |= (0x5 << 16) | (1 < 22);
+	cpuctrl |= CPU_CONTROL_V6_EXTPAGE;
+
+	/* Clear out the cache */
+	cpu_idcache_wbinv_all();
+
+	/* Set the control register */
+	ctrl = cpuctrl;
+	cpu_control(0xFFFFFFFF, cpuctrl);
+
+	/* And again. */
+	cpu_idcache_wbinv_all();
+}
+#endif /* CPU_MV_PJ4B */
+
+#ifdef CPU_CORTEXA
+
+void
+cortexa_setup(char *args)
+{
+	int cpuctrl, cpuctrlmask;
+	
+	cpuctrlmask = CPU_CONTROL_MMU_ENABLE |     /* MMU enable         [0] */
+	    CPU_CONTROL_AFLT_ENABLE |    /* Alignment fault    [1] */
+	    CPU_CONTROL_DC_ENABLE |      /* DCache enable      [2] */
+	    CPU_CONTROL_BPRD_ENABLE |    /* Branch prediction [11] */
+	    CPU_CONTROL_IC_ENABLE |      /* ICache enable     [12] */
+	    CPU_CONTROL_VECRELOC;        /* Vector relocation [13] */
+	
+	cpuctrl = CPU_CONTROL_MMU_ENABLE |
+	    CPU_CONTROL_IC_ENABLE |
+	    CPU_CONTROL_DC_ENABLE |
+	    CPU_CONTROL_BPRD_ENABLE;
+	
+#ifndef ARM32_DISABLE_ALIGNMENT_FAULTS
+	cpuctrl |= CPU_CONTROL_AFLT_ENABLE;
+#endif
+	
+	/* Switch to big endian */
+#ifdef __ARMEB__
+	cpuctrl |= CPU_CONTROL_BEND_ENABLE;
+#endif
+	
+	/* Check if the vector page is at the high address (0xffff0000) */
+	if (vector_page == ARM_VECTORS_HIGH)
+		cpuctrl |= CPU_CONTROL_VECRELOC;
+	
+	/* Clear out the cache */
+	cpu_idcache_wbinv_all();
+	
+	/* Set the control register */
+	ctrl = cpuctrl;
+	cpu_control(cpuctrlmask, cpuctrl);
+	
+	/* And again. */
+	cpu_idcache_wbinv_all();
+#ifdef SMP
+	armv7_auxctrl((1 << 6) | (1 << 0), (1 << 6) | (1 << 0)); /* Enable SMP + TLB broadcasting  */
+#endif
+}
+#endif  /* CPU_CORTEXA */
+
+
 #ifdef CPU_SA110
 struct cpu_option sa110_options[] = {
 #ifdef COMPAT_12
diff -r 7fffa673adcd -r a301a330526b head/sys/arm/arm/cpufunc_asm.S
--- a/head/sys/arm/arm/cpufunc_asm.S	Wed Aug 15 11:15:12 2012 +0300
+++ b/head/sys/arm/arm/cpufunc_asm.S	Wed Aug 15 11:16:36 2012 +0300
@@ -43,7 +43,7 @@
  */
 
 #include <machine/asm.h>
-__FBSDID("$FreeBSD: head/sys/arm/arm/cpufunc_asm.S 236991 2012-06-13 04:59:55Z imp $");
+__FBSDID("$FreeBSD: head/sys/arm/arm/cpufunc_asm.S 239268 2012-08-15 03:03:03Z gonzo $");
 
 	.text
 	.align	0
@@ -65,6 +65,10 @@
 	mrc	p15, 0, r0, c0, c0, 0
 	RET
 
+ENTRY(cpufunc_cpuid)
+	mrc	p15, 0, r0, c0, c0, 0
+	RET
+
 ENTRY(cpu_get_control)
 	mrc	p15, 0, r0, c1, c0, 0
 	RET
diff -r 7fffa673adcd -r a301a330526b head/sys/arm/arm/cpufunc_asm_arm11.S
--- a/head/sys/arm/arm/cpufunc_asm_arm11.S	Wed Aug 15 11:15:12 2012 +0300
+++ b/head/sys/arm/arm/cpufunc_asm_arm11.S	Wed Aug 15 11:16:36 2012 +0300
@@ -35,7 +35,7 @@
  */
 
 #include <machine/asm.h>
-__FBSDID("$FreeBSD: head/sys/arm/arm/cpufunc_asm_arm11.S 236991 2012-06-13 04:59:55Z imp $");
+__FBSDID("$FreeBSD: head/sys/arm/arm/cpufunc_asm_arm11.S 239268 2012-08-15 03:03:03Z gonzo $");
 
 /*
  * Functions to set the MMU Translation Table Base register
@@ -122,3 +122,8 @@
 ENTRY(arm11_drain_writebuf)
 	mcr	p15, 0, r0, c7, c10, 4	/* drain write buffer */
 	mov	pc, lr
+
+ENTRY_NP(arm11_sleep)
+	mov	r0, #0
+	mcr	p15, 0, r0, c7, c0, 4   /* wait for interrupt */
+	RET
diff -r 7fffa673adcd -r a301a330526b head/sys/arm/arm/cpufunc_asm_armv7.S
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/head/sys/arm/arm/cpufunc_asm_armv7.S	Wed Aug 15 11:16:36 2012 +0300
@@ -0,0 +1,277 @@
+/*-
+ * Copyright (C) 2011 MARVELL INTERNATIONAL LTD.
+ * All rights reserved.
+ *
+ * Developed by Semihalf.
+ *
+ * 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. Neither the name of MARVELL nor the names of contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * 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 <machine/asm.h>
+__FBSDID("$FreeBSD: head/sys/arm/arm/cpufunc_asm_armv7.S 239268 2012-08-15 03:03:03Z gonzo $");
+
+	.cpu cortex-a8
+
+.Lcoherency_level:
+	.word	_C_LABEL(arm_cache_loc)
+.Lcache_type:
+	.word	_C_LABEL(arm_cache_type)
+.Lway_mask:
+	.word	0x3ff
+.Lmax_index:
+	.word	0x7fff
+.Lpage_mask:
+	.word	0xfff
+
+#define PT_NOS          (1 << 5)
+#define PT_S 	        (1 << 1)
+#define PT_INNER_NC	0
+#define PT_INNER_WT	(1 << 0)
+#define PT_INNER_WB	((1 << 0) | (1 << 6))
+#define PT_INNER_WBWA	(1 << 6)
+#define PT_OUTER_NC	0
+#define PT_OUTER_WT	(2 << 3)
+#define PT_OUTER_WB	(3 << 3)
+#define PT_OUTER_WBWA	(1 << 3)
+	
+#ifdef SMP
+#define PT_ATTR	(PT_S|PT_INNER_WT|PT_OUTER_WT|PT_NOS)
+#else
+#define PT_ATTR	(PT_INNER_WT|PT_OUTER_WT)
+#endif
+
+ENTRY(armv7_setttb)
+	stmdb   sp!, {r0, lr}
+ 	bl      _C_LABEL(armv7_idcache_wbinv_all) /* clean the D cache */
+ 	ldmia   sp!, {r0, lr}
+ 	dsb
+				
+	orr 	r0, r0, #PT_ATTR
+ 	mcr	p15, 0, r0, c2, c0, 0	/* Translation Table Base Register 0 (TTBR0) */
+ 	mcr     p15, 0, r0, c8, c7, 0   /* invalidate I+D TLBs */
+ 	dsb
+ 	isb
+	RET
+
+ENTRY(armv7_tlb_flushID)
+	dsb
+#ifdef SMP
+	mcr 	p15, 0, r0, c8, c3, 0
+#else
+	mcr	p15, 0, r0, c8, c7, 0	/* flush I+D tlb */
+#endif
+	mcr	p15, 0, r0, c7, c5, 6	/* flush BTB */
+	dsb
+	isb
+	mov	pc, lr
+
+ENTRY(armv7_tlb_flushID_SE)
+	ldr	r1, .Lpage_mask
+	bic	r0, r0, r1
+#ifdef SMP
+	mcr	p15, 0, r0, c8, c3, 1	/* flush D tlb single entry */
+#else
+	mcr	p15, 0, r0, c8, c7, 1	/* flush D tlb single entry */
+#endif
+	mcr	p15, 0, r0, c7, c5, 6	/* flush BTB */
+	dsb
+	isb
+	mov	pc, lr
+
+/* Based on algorithm from ARM Architecture Reference Manual */
+ENTRY(armv7_dcache_wbinv_all)
+	stmdb	sp!, {r4, r5, r6, r7, r8, r9}
+
+	/* Get cache level */
+	ldr	r0, .Lcoherency_level
+	ldr	r3, [r0]
+	cmp	r3, #0
+	beq	Finished
+	/* For each cache level */
+	mov	r8, #0
+Loop1:
+	/* Get cache type for given level */
+	mov	r2, r8, lsl #2
+	add	r2, r2, r2
+	ldr	r0, .Lcache_type
+	ldr	r1, [r0, r2]
+
+	/* Get line size */
+	and	r2, r1, #7
+	add	r2, r2, #4
+
+	/* Get number of ways */
+	ldr	r4, .Lway_mask
+	ands	r4, r4, r1, lsr #3
+	clz	r5, r4
+
+	/* Get max index */
+	ldr	r7, .Lmax_index
+	ands	r7, r7, r1, lsr #13
+Loop2:
+	mov	r9, r4
+Loop3:
+	mov	r6, r8, lsl #1
+	orr	r6, r6, r9, lsl r5
+	orr	r6, r6, r7, lsl r2
+
+	/* Clean and invalidate data cache by way/index */
+	mcr	p15, 0, r6, c7, c14, 2
+	subs	r9, r9, #1
+	bge	Loop3
+	subs	r7, r7, #1
+	bge	Loop2
+Skip:
+	add	r8, r8, #1
+	cmp	r3, r8
+	bne Loop1
+Finished:
+	dsb
+	ldmia	sp!, {r4, r5, r6, r7, r8, r9}
+	RET
+
+ENTRY(armv7_idcache_wbinv_all)
+	stmdb	sp!, {lr}
+	bl armv7_dcache_wbinv_all
+	mcr	p15, 0, r0, c7, c5, 0	/* Invalidate all I caches to PoU (ICIALLU) */
+	dsb
+	isb
+	ldmia	sp!, {lr}
+	RET
+
+/* XXX Temporary set it to 32 for MV cores, however this value should be
+ * get from Cache Type register
+ */
+.Larmv7_line_size:
+	.word	32
+
+ENTRY(armv7_dcache_wb_range)
+	ldr	ip, .Larmv7_line_size
+	sub	r3, ip, #1
+	and	r2, r0, r3
+	add	r1, r1, r2
+	bic	r0, r0, r3
+.Larmv7_wb_next:
+	mcr	p15, 0, r0, c7, c10, 1	/* Clean D cache SE with VA */
+	add	r0, r0, ip
+	subs	r1, r1, ip
+	bhi	.Larmv7_wb_next
+	dsb				/* data synchronization barrier */
+	RET
+
+ENTRY(armv7_dcache_wbinv_range)
+	ldr	ip, .Larmv7_line_size
+	sub     r3, ip, #1
+	and     r2, r0, r3
+	add     r1, r1, r2
+	bic     r0, r0, r3
+.Larmv7_wbinv_next:
+	mcr	p15, 0, r0, c7, c14, 1	/* Purge D cache SE with VA */
+	add	r0, r0, ip
+	subs	r1, r1, ip
+	bhi	.Larmv7_wbinv_next
+	dsb				/* data synchronization barrier */
+	RET
+
+/*
+ * Note, we must not invalidate everything.  If the range is too big we
+ * must use wb-inv of the entire cache.
+ */
+ENTRY(armv7_dcache_inv_range)
+	ldr	ip, .Larmv7_line_size
+	sub     r3, ip, #1
+	and     r2, r0, r3
+	add     r1, r1, r2
+	bic     r0, r0, r3
+.Larmv7_inv_next:
+	mcr	p15, 0, r0, c7, c6, 1	/* Invalidate D cache SE with VA */
+	add	r0, r0, ip
+	subs	r1, r1, ip
+	bhi	.Larmv7_inv_next
+	dsb				/* data synchronization barrier */
+	RET
+
+ENTRY(armv7_idcache_wbinv_range)
+	ldr	ip, .Larmv7_line_size
+	sub     r3, ip, #1
+	and     r2, r0, r3
+	add     r1, r1, r2
+	bic     r0, r0, r3
+.Larmv7_id_wbinv_next:
+	mcr	p15, 0, r0, c7, c5, 1	/* Invalidate I cache SE with VA */
+	mcr	p15, 0, r0, c7, c14, 1	/* Purge D cache SE with VA */
+	add	r0, r0, ip
+	subs	r1, r1, ip
+	bhi	.Larmv7_id_wbinv_next
+	isb				/* instruction synchronization barrier */
+	dsb				/* data synchronization barrier */
+	RET
+
+ENTRY_NP(armv7_icache_sync_range)
+	ldr	ip, .Larmv7_line_size
+.Larmv7_sync_next:
+	mcr	p15, 0, r0, c7, c5, 1	/* Invalidate I cache SE with VA */
+	mcr	p15, 0, r0, c7, c10, 1	/* Clean D cache SE with VA */
+	add	r0, r0, ip
+	subs	r1, r1, ip
+	bhi	.Larmv7_sync_next
+	isb				/* instruction synchronization barrier */
+	dsb				/* data synchronization barrier */
+	RET
+
+ENTRY(armv7_cpu_sleep)
+	dsb				/* data synchronization barrier */
+	wfi  				/* wait for interrupt */
+	RET
+
+ENTRY(armv7_context_switch)
+	dsb
+	orr     r0, r0, #PT_ATTR
+			
+	mcr	p15, 0, r0, c2, c0, 0	/* set the new TTB */
+	mcr	p15, 0, r0, c8, c7, 0	/* and flush the I+D tlbs */
+	dsb
+	isb
+	RET
+
+ENTRY(armv7_drain_writebuf)
+	dsb
+	RET
+
+ENTRY(armv7_sev)
+	dsb
+	sev
+	nop
+	RET
+
+ENTRY(armv7_auxctrl)
+	mrc p15, 0, r2, c1, c0, 1
+	bic r3, r2, r0	/* Clear bits */
+	eor r3, r3, r1  /* XOR bits */
+
+	teq r2, r3
+	mcrne p15, 0, r3, c1, c0, 1
+	mov r0, r2
+	RET
diff -r 7fffa673adcd -r a301a330526b head/sys/arm/arm/cpufunc_asm_pj4b.S
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/head/sys/arm/arm/cpufunc_asm_pj4b.S	Wed Aug 15 11:16:36 2012 +0300
@@ -0,0 +1,202 @@
+/*-
+ * Copyright (C) 2011 MARVELL INTERNATIONAL LTD.
+ * All rights reserved.
+ *
+ * Developed by Semihalf.
+ *
+ * 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. Neither the name of MARVELL nor the names of contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * 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 <machine/asm.h>
+__FBSDID("$FreeBSD: head/sys/arm/arm/cpufunc_asm_pj4b.S 239268 2012-08-15 03:03:03Z gonzo $");
+
+#include <machine/param.h>
+
+.Lpj4b_cache_line_size:
+	.word	_C_LABEL(arm_pdcache_line_size)
+
+ENTRY(pj4b_setttb)
+	/* Cache synchronization is not required as this core has PIPT caches */
+	mcr	p15, 0, r1, c7, c10, 4	/* drain the write buffer */
+#ifdef SMP
+	orr 	r0, r0, #2		/* Set TTB shared memory flag */
+#endif
+	mcr	p15, 0, r0, c2, c0, 0	/* load new TTB */
+	mcr	p15, 0, r0, c8, c7, 0	/* invalidate I+D TLBs */
+	RET
+
+ENTRY_NP(armv6_icache_sync_all)
+	/*
+	 * We assume that the code here can never be out of sync with the
+	 * dcache, so that we can safely flush the Icache and fall through
+	 * into the Dcache cleaning code.
+	 */
+	mov	r0, #0
+	mcr	p15, 0, r0, c7, c5, 0	/* Invalidate ICache */
+	mcr	p15, 0, r0, c7, c10, 0	/* Clean (don't invalidate) DCache */
+	mcr	p15, 0, r0, c7, c10, 4	/* drain the write buffer */
+	RET
+
+ENTRY(pj4b_icache_sync_range)
+	sub	r1, r1, #1
+	add	r1, r0, r1
+	mcrr	p15, 0, r1, r0, c5	/* invalidate IC range */
+	mcrr	p15, 0, r1, r0, c12	/* clean DC range */
+	mcr	p15, 0, r0, c7, c10, 4	/* drain the write buffer */
+	RET
+
+ENTRY(pj4b_dcache_inv_range)
+	ldr	ip, .Lpj4b_cache_line_size
+	ldr	ip, [ip]
+	sub	r1, r1, #1		/* Don't overrun */
+	sub	r3, ip, #1
+	and	r2, r0, r3
+	add	r1, r1, r2
+	bic	r0, r0, r3
+
+	mcr	p15, 0, r0, c7, c10, 5  /* Data Memory Barrier err:4413 */
+1:
+	mcr	p15, 0, r0, c7, c6, 1
+	add	r0, r0, ip
+	subs	r1, r1, ip
+	bpl	1b
+	mcr	p15, 0, r0, c7, c10, 4	/* drain the write buffer */
+	RET
+
+ENTRY(armv6_idcache_wbinv_all)
+	mov	r0, #0
+	mcr	p15, 0, r0, c7, c5, 0	/* invalidate ICache */
+	mcr	p15, 0, r0, c7, c14, 0	/* clean and invalidate DCache */
+	mcr	p15, 0, r0, c7, c10, 4	/* drain the write buffer */
+	RET
+
+ENTRY(armv6_dcache_wbinv_all)
+	mov	r0, #0
+	mcr	p15, 0, r0, c7, c14, 0	/* clean and invalidate DCache */
+	mcr	p15, 0, r0, c7, c10, 4	/* drain the write buffer */
+	RET
+
+ENTRY(pj4b_idcache_wbinv_range)
+	ldr	ip, .Lpj4b_cache_line_size
+	ldr	ip, [ip]
+	sub	r1, r1, #1		/* Don't overrun */
+	sub	r3, ip, #1
+	and	r2, r0, r3
+	add	r1, r1, r2
+	bic	r0, r0, r3
+
+	mcr	p15, 0, r0, c7, c10, 5  /* Data Memory Barrier err:4611 */
+1:
+#ifdef SMP
+	/* Request for ownership */
+	ldr	r2, [r0]
+	str	r2, [r0]
+#endif
+	mcr	p15, 0, r0, c7, c5, 1
+	mcr	p15, 0, r0, c7, c14, 1	/* L2C clean and invalidate entry */
+	add	r0, r0, ip
+	subs	r1, r1, ip
+	bpl	1b
+	mcr	p15, 0, r0, c7, c10, 4	/* drain the write buffer */
+	RET
+
+ENTRY(pj4b_dcache_wbinv_range)
+	ldr	ip, .Lpj4b_cache_line_size
+	ldr	ip, [ip]
+	sub	r1, r1, #1		/* Don't overrun */
+	sub	r3, ip, #1
+	and	r2, r0, r3
+	add	r1, r1, r2
+	bic	r0, r0, r3
+
+	mcr	p15, 0, r0, c7, c10, 5  /* Data Memory Barrier err:4611 */
+1:
+#ifdef SMP
+	/* Request for ownership */
+	ldr	r2, [r0]
+	str	r2, [r0]
+#endif
+	mcr	p15, 0, r0, c7, c14, 1
+	add	r0, r0, ip
+	subs	r1, r1, ip
+	bpl	1b
+	mcr	p15, 0, r0, c7, c10, 4	/* drain the write buffer */
+	RET
+
+ENTRY(pj4b_dcache_wb_range)
+	ldr	ip, .Lpj4b_cache_line_size
+	ldr	ip, [ip]
+	sub	r1, r1, #1		/* Don't overrun */
+	sub	r3, ip, #1
+	and	r2, r0, r3
+	add	r1, r1, r2
+	bic	r0, r0, r3
+
+	mcr	p15, 0, r0, c7, c10, 5  /* Data Memory Barrier err:4611 */
+1:
+#ifdef SMP
+	/* Request for ownership */
+	ldr	r2, [r0]
+	str	r2, [r0]
+#endif
+	mcr	p15, 0, r0, c7, c10, 1	/* L2C clean single entry by MVA */
+	add	r0, r0, ip
+	subs	r1, r1, ip
+	bpl	1b
+	mcr	p15, 0, r0, c7, c10, 4	/* drain the write buffer */
+	RET
+
+ENTRY(pj4b_drain_readbuf)
+	mcr	p15, 0, r0, c7, c5, 4	/* flush prefetch buffers */
+	RET
+
+ENTRY(pj4b_flush_brnchtgt_all)
+	mcr	p15, 0, r0, c7, c5, 6	/* flush entrie branch target cache */
+	RET
+
+ENTRY(pj4b_flush_brnchtgt_va)
+	mcr	p15, 0, r0, c7, c5, 7	/* flush branch target cache by VA */
+	RET
+
+ENTRY(get_core_id)
+	mrc p15, 0, r0, c0, c0, 5
+	RET
+
+ENTRY(pj4b_config)
+	/* Set Auxiliary Debug Modes Control 2 register */
+	mrc	p15, 1, r0, c15, c1, 2
+	bic	r0, r0, #(1 << 23)
+	orr	r0, r0, #(1 << 25)
+	orr	r0, r0, #(1 << 27)
+	orr	r0, r0, #(1 << 29)
+	orr	r0, r0, #(1 << 30)
+	mcr	p15, 1, r0, c15, c1, 2
+#if defined(SMP)
+	/* Set SMP mode in Auxiliary Control Register */
+	mrc	p15, 0, r0, c1, c0, 1
+	orr	r0, r0, #(1 << 5)
+	mcr	p15, 0, r0, c1, c0, 1
+#endif
+	RET
diff -r 7fffa673adcd -r a301a330526b head/sys/arm/arm/elf_trampoline.c
--- a/head/sys/arm/arm/elf_trampoline.c	Wed Aug 15 11:15:12 2012 +0300
+++ b/head/sys/arm/arm/elf_trampoline.c	Wed Aug 15 11:16:36 2012 +0300
@@ -30,7 +30,7 @@
 #include "opt_kernname.h"
 
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD: head/sys/arm/arm/elf_trampoline.c 236991 2012-06-13 04:59:55Z imp $");
+__FBSDID("$FreeBSD: head/sys/arm/arm/elf_trampoline.c 239268 2012-08-15 03:03:03Z gonzo $");
 #include <machine/asm.h>
 #include <sys/param.h>
 #include <sys/elf32.h>
@@ -72,15 +72,25 @@
 #define cpu_idcache_wbinv_all	xscale_cache_purgeID
 #elif defined(CPU_XSCALE_81342)
 #define cpu_idcache_wbinv_all	xscalec3_cache_purgeID
+#elif defined(CPU_MV_PJ4B)
+#if !defined(SOC_MV_ARMADAXP)
+#define cpu_idcache_wbinv_all	armv6_idcache_wbinv_all
+#else
+#define cpu_idcache_wbinv_all()	armadaxp_idcache_wbinv_all
 #endif
+#endif /* CPU_MV_PJ4B */
 #ifdef CPU_XSCALE_81342
 #define cpu_l2cache_wbinv_all	xscalec3_l2cache_purge
 #elif defined(SOC_MV_KIRKWOOD) || defined(SOC_MV_DISCOVERY)
 #define cpu_l2cache_wbinv_all	sheeva_l2cache_wbinv_all
+#elif defined(CPU_CORTEXA)
+#define cpu_idcache_wbinv_all	armv7_idcache_wbinv_all
+#define cpu_l2cache_wbinv_all()
 #else
 #define cpu_l2cache_wbinv_all()	
 #endif
 
+static void armadaxp_idcache_wbinv_all(void);
 
 int     arm_picache_size;
 int     arm_picache_line_size;
@@ -96,6 +106,10 @@
 int     arm_dcache_align;
 int     arm_dcache_align_mask;
 
+u_int	arm_cache_level;
+u_int	arm_cache_type[14];
+u_int	arm_cache_loc;
+
 /* Additional cache information local to this file.  Log2 of some of the
       above numbers.  */
 static int      arm_dcache_l2_nsets;
@@ -221,8 +235,6 @@
 	if ((cpufunc_id() & 0x0000f000) == 0x00009000)
 		arm9_setup();
 #endif
-	cpu_idcache_wbinv_all();
-	cpu_l2cache_wbinv_all();
 #endif
 	__start();
 }
@@ -230,68 +242,102 @@
 static void
 get_cachetype_cp15()
 {
-	u_int ctype, isize, dsize;
+	u_int ctype, isize, dsize, cpuid;
+	u_int clevel, csize, i, sel;
 	u_int multiplier;
+	u_char type;
 
 	__asm __volatile("mrc p15, 0, %0, c0, c0, 1"
-	    : "=r" (ctype));
-	
+		: "=r" (ctype));
+
+	cpuid = cpufunc_id();
 	/*
 	 * ...and thus spake the ARM ARM:
 	 *
- 	 * If an <opcode2> value corresponding to an unimplemented or
+	 * If an <opcode2> value corresponding to an unimplemented or
 	 * reserved ID register is encountered, the System Control
 	 * processor returns the value of the main ID register.
 	 */
-	if (ctype == cpufunc_id())
+	if (ctype == cpuid)
 		goto out;
-	
-	if ((ctype & CPU_CT_S) == 0)
-		arm_pcache_unified = 1;
 
-	/*
-	 * If you want to know how this code works, go read the ARM ARM.
-	 */
-	
-	arm_pcache_type = CPU_CT_CTYPE(ctype);
-        if (arm_pcache_unified == 0) {
-		isize = CPU_CT_ISIZE(ctype);
-	    	multiplier = (isize & CPU_CT_xSIZE_M) ? 3 : 2;
-		arm_picache_line_size = 1U << (CPU_CT_xSIZE_LEN(isize) + 3);
-		if (CPU_CT_xSIZE_ASSOC(isize) == 0) {
-			if (isize & CPU_CT_xSIZE_M)
-				arm_picache_line_size = 0; /* not present */
+	if (CPU_CT_FORMAT(ctype) == CPU_CT_ARMV7) {
+		__asm __volatile("mrc p15, 1, %0, c0, c0, 1"
+		    : "=r" (clevel));
+		arm_cache_level = clevel;
+		arm_cache_loc = CPU_CLIDR_LOC(arm_cache_level) + 1;
+		i = 0;
+		while ((type = (clevel & 0x7)) && i < 7) {
+			if (type == CACHE_DCACHE || type == CACHE_UNI_CACHE ||
+			    type == CACHE_SEP_CACHE) {
+				sel = i << 1;
+				__asm __volatile("mcr p15, 2, %0, c0, c0, 0"
+				    : : "r" (sel));
+				__asm __volatile("mrc p15, 1, %0, c0, c0, 0"
+				    : "=r" (csize));
+				arm_cache_type[sel] = csize;
+			}
+			if (type == CACHE_ICACHE || type == CACHE_SEP_CACHE) {
+				sel = (i << 1) | 1;
+				__asm __volatile("mcr p15, 2, %0, c0, c0, 0"
+				    : : "r" (sel));
+				__asm __volatile("mrc p15, 1, %0, c0, c0, 0"
+				    : "=r" (csize));
+				arm_cache_type[sel] = csize;
+			}
+			i++;
+			clevel >>= 3;
+		}
+	} else {
+		if ((ctype & CPU_CT_S) == 0)
+			arm_pcache_unified = 1;
+
+		/*
+		 * If you want to know how this code works, go read the ARM ARM.
+		 */
+
+		arm_pcache_type = CPU_CT_CTYPE(ctype);
+
+		if (arm_pcache_unified == 0) {
+			isize = CPU_CT_ISIZE(ctype);
+			multiplier = (isize & CPU_CT_xSIZE_M) ? 3 : 2;
+			arm_picache_line_size = 1U << (CPU_CT_xSIZE_LEN(isize) + 3);
+			if (CPU_CT_xSIZE_ASSOC(isize) == 0) {
+				if (isize & CPU_CT_xSIZE_M)
+					arm_picache_line_size = 0; /* not present */
+				else
+					arm_picache_ways = 1;
+			} else {
+				arm_picache_ways = multiplier <<
+				    (CPU_CT_xSIZE_ASSOC(isize) - 1);
+			}
+			arm_picache_size = multiplier << (CPU_CT_xSIZE_SIZE(isize) + 8);
+		}
+
+		dsize = CPU_CT_DSIZE(ctype);
+		multiplier = (dsize & CPU_CT_xSIZE_M) ? 3 : 2;
+		arm_pdcache_line_size = 1U << (CPU_CT_xSIZE_LEN(dsize) + 3);
+		if (CPU_CT_xSIZE_ASSOC(dsize) == 0) {
+			if (dsize & CPU_CT_xSIZE_M)
+				arm_pdcache_line_size = 0; /* not present */
 			else
-				arm_picache_ways = 1;
+				arm_pdcache_ways = 1;
 		} else {
-			arm_picache_ways = multiplier <<
-			    (CPU_CT_xSIZE_ASSOC(isize) - 1);
+			arm_pdcache_ways = multiplier <<
+			    (CPU_CT_xSIZE_ASSOC(dsize) - 1);
 		}
-		arm_picache_size = multiplier << (CPU_CT_xSIZE_SIZE(isize) + 8);
+		arm_pdcache_size = multiplier << (CPU_CT_xSIZE_SIZE(dsize) + 8);
+
+		arm_dcache_align = arm_pdcache_line_size;
+
+		arm_dcache_l2_assoc = CPU_CT_xSIZE_ASSOC(dsize) + multiplier - 2;
+		arm_dcache_l2_linesize = CPU_CT_xSIZE_LEN(dsize) + 3;
+		arm_dcache_l2_nsets = 6 + CPU_CT_xSIZE_SIZE(dsize) -
+		    CPU_CT_xSIZE_ASSOC(dsize) - CPU_CT_xSIZE_LEN(dsize);
+
+	out:
+		arm_dcache_align_mask = arm_dcache_align - 1;
 	}
-	
-	dsize = CPU_CT_DSIZE(ctype);
-	multiplier = (dsize & CPU_CT_xSIZE_M) ? 3 : 2;
-	arm_pdcache_line_size = 1U << (CPU_CT_xSIZE_LEN(dsize) + 3);
-	if (CPU_CT_xSIZE_ASSOC(dsize) == 0) {
-		if (dsize & CPU_CT_xSIZE_M)
-			arm_pdcache_line_size = 0; /* not present */
-		else
-			arm_pdcache_ways = 1;
-	} else {
-		arm_pdcache_ways = multiplier <<
-		    (CPU_CT_xSIZE_ASSOC(dsize) - 1);
-	}
-	arm_pdcache_size = multiplier << (CPU_CT_xSIZE_SIZE(dsize) + 8);
-	
-	arm_dcache_align = arm_pdcache_line_size;
-	
-	arm_dcache_l2_assoc = CPU_CT_xSIZE_ASSOC(dsize) + multiplier - 2;
-	arm_dcache_l2_linesize = CPU_CT_xSIZE_LEN(dsize) + 3;
-	arm_dcache_l2_nsets = 6 + CPU_CT_xSIZE_SIZE(dsize) -
-	    CPU_CT_xSIZE_ASSOC(dsize) - CPU_CT_xSIZE_LEN(dsize);
- out:
-	arm_dcache_align_mask = arm_dcache_align - 1;
 }
 
 static void
@@ -306,7 +352,18 @@
 	arm9_dcache_index_max = 0U - arm9_dcache_index_inc;
 }
 
+static void
+armadaxp_idcache_wbinv_all(void)
+{
+	uint32_t feat;
 
+	__asm __volatile("mrc p15, 0, %0, c0, c1, 0" : "=r" (feat));
+	if (feat & ARM_PFR0_THUMBEE_MASK)
+		armv7_idcache_wbinv_all();
+	else
+		armv6_idcache_wbinv_all();
+
+}
 #ifdef KZIP
 static  unsigned char *orig_input, *i_input, *i_output;
 
diff -r 7fffa673adcd -r a301a330526b head/sys/arm/arm/fusu.S
--- a/head/sys/arm/arm/fusu.S	Wed Aug 15 11:15:12 2012 +0300
+++ b/head/sys/arm/arm/fusu.S	Wed Aug 15 11:16:36 2012 +0300
@@ -37,14 +37,17 @@
 #include <machine/asmacros.h>
 #include <machine/armreg.h>
 #include "assym.s"
-__FBSDID("$FreeBSD$");
+__FBSDID("$FreeBSD: head/sys/arm/arm/fusu.S 239268 2012-08-15 03:03:03Z gonzo $");
 
-#ifdef MULTIPROCESSOR
-.Lcpu_info:
-	.word	_C_LABEL(cpu_info)
+#ifdef _ARM_ARCH_6
+#define GET_PCB(tmp) \
+	mrc p15, 0, tmp, c13, c0, 4; \
+	add	tmp, tmp, #(PC_CURPCB)
 #else
 .Lcurpcb:
 	.word	_C_LABEL(__pcpu) + PC_CURPCB
+#define GET_PCB(tmp) \
+	ldr	tmp, .Lcurpcb
 #endif
 
 /*
@@ -54,18 +57,8 @@
 
 ENTRY_NP(casuword32)
 ENTRY(casuword)
-#ifdef MULTIPROCESSOR
-	/* XXX Probably not appropriate for non-Hydra SMPs */
-	stmfd	sp!, {r0, r14}
-	bl	_C_LABEL(cpu_number)
-	ldr	r2, .Lcpu_info
-	ldr	r2, [r2, r0, lsl #2]
-	ldr	r2, [r2, #CI_CURPCB]
-	ldmfd	sp!, {r0, r14}
-#else
-	ldr	r3, .Lcurpcb
+	GET_PCB(r3)
 	ldr	r3, [r3]
-#endif
 
 #ifdef DIAGNOSTIC
 	teq	r3, #0x00000000
@@ -101,18 +94,8 @@
 
 ENTRY_NP(fuword32)
 ENTRY(fuword)
-#ifdef MULTIPROCESSOR
-	/* XXX Probably not appropriate for non-Hydra SMPs */
-	stmfd	sp!, {r0, r14}
-	bl	_C_LABEL(cpu_number)
-	ldr	r2, .Lcpu_info
-	ldr	r2, [r2, r0, lsl #2]
-	ldr	r2, [r2, #CI_CURPCB]
-	ldmfd	sp!, {r0, r14}
-#else
-	ldr	r2, .Lcurpcb
+	GET_PCB(r2)
 	ldr	r2, [r2]
-#endif
 
 #ifdef DIAGNOSTIC
 	teq	r2, #0x00000000
@@ -135,18 +118,8 @@
  */
 
 ENTRY(fusword)
-#ifdef MULTIPROCESSOR
-	/* XXX Probably not appropriate for non-Hydra SMPs */
-	stmfd	sp!, {r0, r14}
-	bl	_C_LABEL(cpu_number)
-	ldr	r2, .Lcpu_info
-	ldr	r2, [r2, r0, lsl #2]
-	ldr	r2, [r2, #CI_CURPCB]
-	ldmfd	sp!, {r0, r14}
-#else
-	ldr	r2, .Lcurpcb
+	GET_PCB(r2)
 	ldr	r2, [r2]
-#endif
 
 #ifdef DIAGNOSTIC
 	teq	r2, #0x00000000
@@ -180,18 +153,8 @@
 	mvnne	r0, #0x00000000
 	RETne
 
-#ifdef MULTIPROCESSOR
-	/* XXX Probably not appropriate for non-Hydra SMPs */
-	stmfd	sp!, {r0, r14}
-	bl	_C_LABEL(cpu_number)
-	ldr	r2, .Lcpu_info
-	ldr	r2, [r2, r0, lsl #2]
-	ldr	r2, [r2, #CI_CURPCB]
-	ldmfd	sp!, {r0, r14}
-#else
-	ldr	r2, .Lcurpcb
+	GET_PCB(r2)
 	ldr	r2, [r2]
-#endif
 
 #ifdef DIAGNOSTIC
 	teq	r2, #0x00000000
@@ -229,18 +192,8 @@
  */
 
 ENTRY(fubyte)
-#ifdef MULTIPROCESSOR
-	/* XXX Probably not appropriate for non-Hydra SMPs */
-	stmfd	sp!, {r0, r14}
-	bl	_C_LABEL(cpu_number)
-	ldr	r2, .Lcpu_info
-	ldr	r2, [r2, r0, lsl #2]
-	ldr	r2, [r2, #CI_CURPCB]
-	ldmfd	sp!, {r0, r14}
-#else
-	ldr	r2, .Lcurpcb
+	GET_PCB(r2)
 	ldr	r2, [r2]
-#endif
 
 #ifdef DIAGNOSTIC
 	teq	r2, #0x00000000
@@ -303,18 +256,8 @@
 
 ENTRY_NP(suword32)
 ENTRY(suword)
-#ifdef MULTIPROCESSOR
-	/* XXX Probably not appropriate for non-Hydra SMPs */
-	stmfd	sp!, {r0, r1, r14}
-	bl	_C_LABEL(cpu_number)
-	ldr	r2, .Lcpu_info
-	ldr	r2, [r2, r0, lsl #2]
-	ldr	r2, [r2, #CI_CURPCB]
-	ldmfd	sp!, {r0, r1, r14}
-#else
-	ldr	r2, .Lcurpcb
+	GET_PCB(r2)
 	ldr	r2, [r2]
-#endif
 
 #ifdef DIAGNOSTIC
 	teq	r2, #0x00000000
@@ -343,17 +286,8 @@
 	mvnne	r0, #0x00000000
 	RETne
 
-#ifdef MULTIPROCESSOR
-	stmfd	sp!, {r0, r1, r14}
-	bl	_C_LABEL(cpu_number)
-	ldr	r2, .Lcpu_info
-	ldr	r2, [r2, r0, lsl #2]
-	ldr	r2, [r2, #CI_CURPCB]
-	ldmfd	sp!, {r0, r1, r14}
-#else
-	ldr	r2, .Lcurpcb
+	GET_PCB(r2)
 	ldr	r2, [r2]
-#endif
 
 #ifdef DIAGNOSTIC
 	teq	r2, #0x00000000
@@ -382,17 +316,8 @@
  */
 
 ENTRY(susword)
-#ifdef MULTIPROCESSOR
-	stmfd	sp!, {r0, r1, r14}
-	bl	_C_LABEL(cpu_number)
-	ldr	r2, .Lcpu_info
-	ldr	r2, [r2, r0, lsl #2]
-	ldr	r2, [r2, #CI_CURPCB]
-	ldmfd	sp!, {r0, r1, r14}
-#else
-	ldr	r2, .Lcurpcb
+	GET_PCB(r2)
 	ldr	r2, [r2]
-#endif
 
 #ifdef DIAGNOSTIC
 	teq	r2, #0x00000000
@@ -421,17 +346,8 @@
  */
 
 ENTRY(subyte)
-#ifdef MULTIPROCESSOR
-	stmfd	sp!, {r0, r1, r14}
-	bl	_C_LABEL(cpu_number)
-	ldr	r2, .Lcpu_info
-	ldr	r2, [r2, r0, lsl #2]
-	ldr	r2, [r2, #CI_CURPCB]
-	ldmfd	sp!, {r0, r1, r14}
-#else
-	ldr	r2, .Lcurpcb
+	GET_PCB(r2)
 	ldr	r2, [r2]
-#endif
 
 
 #ifdef DIAGNOSTIC
diff -r 7fffa673adcd -r a301a330526b head/sys/arm/arm/genassym.c
--- a/head/sys/arm/arm/genassym.c	Wed Aug 15 11:15:12 2012 +0300
+++ b/head/sys/arm/arm/genassym.c	Wed Aug 15 11:16:36 2012 +0300
@@ -26,7 +26,7 @@
  */
 
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD$");
+__FBSDID("$FreeBSD: head/sys/arm/arm/genassym.c 239268 2012-08-15 03:03:03Z gonzo $");
 #include <sys/param.h>
 #include <sys/systm.h>
 #include <sys/assym.h>
@@ -34,7 +34,9 @@
 #include <sys/mbuf.h>
 #include <sys/vmmeter.h>
 #include <vm/vm.h>
+#include <vm/vm_param.h>
 #include <vm/pmap.h>
+#include <vm/vm_map.h>
 #include <machine/vmparam.h>
 #include <machine/armreg.h>
 #include <machine/pcb.h>
@@ -105,9 +107,22 @@
 ASSYM(P_PID, offsetof(struct proc, p_pid));
 ASSYM(P_FLAG, offsetof(struct proc, p_flag));
 
+#ifdef ARM_TP_ADDRESS
 ASSYM(ARM_TP_ADDRESS, ARM_TP_ADDRESS);
 ASSYM(ARM_RAS_START, ARM_RAS_START);
 ASSYM(ARM_RAS_END, ARM_RAS_END);
+#endif
+
+#ifdef ARM_VFP_SUPPORT
+ASSYM(PCB_VFPSTATE, offsetof(struct pcb, pcb_vfpstate));
+ASSYM(PCB_VFPCPU, offsetof(struct pcb, pcb_vfpcpu));
+
+ASSYM(PC_VFPCTHREAD, offsetof(struct pcpu, pc_vfpcthread));
+ASSYM(PC_CPU, offsetof(struct pcpu, pc_cpu));
+
+ASSYM(PC_CURPMAP, offsetof(struct pcpu, pc_curpmap));
+#endif
+
 ASSYM(PAGE_SIZE, PAGE_SIZE);
 ASSYM(PDESIZE, PDESIZE);
 ASSYM(PMAP_DOMAIN_KERNEL, PMAP_DOMAIN_KERNEL);
diff -r 7fffa673adcd -r a301a330526b head/sys/arm/arm/gic.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/head/sys/arm/arm/gic.c	Wed Aug 15 11:16:36 2012 +0300
@@ -0,0 +1,307 @@
+/*-
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ *
+ * Developed by Damjan Marion <damjan.marion at gmail.com>
+ *
+ * Based on OMAP4 GIC code by Ben Gray
+ *
+ * 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. 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 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.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: head/sys/arm/arm/gic.c 239268 2012-08-15 03:03:03Z gonzo $");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/bus.h>
+#include <sys/kernel.h>
+#include <sys/ktr.h>
+#include <sys/module.h>
+#include <sys/rman.h>
+#include <sys/pcpu.h>
+#include <sys/proc.h>
+#include <sys/cpuset.h>
+#include <sys/lock.h>
+#include <sys/mutex.h>
+#include <machine/bus.h>
+#include <machine/intr.h>
+#include <machine/smp.h>
+
+#include <dev/fdt/fdt_common.h>
+#include <dev/ofw/openfirm.h>
+#include <dev/ofw/ofw_bus.h>
+#include <dev/ofw/ofw_bus_subr.h>
+
+/* We are using GICv2 register naming */
+
+/* Distributor Registers */
+#define GICD_CTLR		0x000			/* v1 ICDDCR */
+#define GICD_TYPER		0x004			/* v1 ICDICTR */
+#define GICD_IIDR		0x008			/* v1 ICDIIDR */
+#define GICD_IGROUPR(n)		(0x0080 + ((n) * 4))	/* v1 ICDISER */
+#define GICD_ISENABLER(n)	(0x0100 + ((n) * 4))	/* v1 ICDISER */
+#define GICD_ICENABLER(n)	(0x0180 + ((n) * 4))	/* v1 ICDICER */
+#define GICD_ISPENDR(n)		(0x0200 + ((n) * 4))	/* v1 ICDISPR */
+#define GICD_ICPENDR(n)		(0x0280 + ((n) * 4))	/* v1 ICDICPR */
+#define GICD_ICACTIVER(n)	(0x0380 + ((n) * 4))	/* v1 ICDABR */
+#define GICD_IPRIORITYR(n)	(0x0400 + ((n) * 4))	/* v1 ICDIPR */
+#define GICD_ITARGETSR(n)	(0x0800 + ((n) * 4))	/* v1 ICDIPTR */
+#define GICD_ICFGR(n)		(0x0C00 + ((n) * 4))	/* v1 ICDICFR */
+#define GICD_SGIR(n)		(0x0F00 + ((n) * 4))	/* v1 ICDSGIR */
+
+/* CPU Registers */
+#define GICC_CTLR		0x0000			/* v1 ICCICR */
+#define GICC_PMR		0x0004			/* v1 ICCPMR */
+#define GICC_BPR		0x0008			/* v1 ICCBPR */
+#define GICC_IAR		0x000C			/* v1 ICCIAR */
+#define GICC_EOIR		0x0010			/* v1 ICCEOIR */
+#define GICC_RPR		0x0014			/* v1 ICCRPR */
+#define GICC_HPPIR		0x0018			/* v1 ICCHPIR */
+#define GICC_ABPR		0x001C			/* v1 ICCABPR */
+#define GICC_IIDR		0x00FC			/* v1 ICCIIDR*/
+
+struct arm_gic_softc {
+	struct resource *	gic_res[3];
+	bus_space_tag_t		gic_c_bst;
+	bus_space_tag_t		gic_d_bst;
+	bus_space_handle_t	gic_c_bsh;
+	bus_space_handle_t	gic_d_bsh;
+	uint8_t			ver;
+};
+
+static struct resource_spec arm_gic_spec[] = {
+	{ SYS_RES_MEMORY,	0,	RF_ACTIVE },	/* Distributor registers */
+	{ SYS_RES_MEMORY,	1,	RF_ACTIVE },	/* CPU Interrupt Intf. registers */
+	{ -1, 0 }
+};
+
+static struct arm_gic_softc *arm_gic_sc = NULL;
+
+#define	gic_c_read_4(reg)		\
+    bus_space_read_4(arm_gic_sc->gic_c_bst, arm_gic_sc->gic_c_bsh, reg)
+#define	gic_c_write_4(reg, val)		\
+    bus_space_write_4(arm_gic_sc->gic_c_bst, arm_gic_sc->gic_c_bsh, reg, val)
+#define	gic_d_read_4(reg)		\
+    bus_space_read_4(arm_gic_sc->gic_d_bst, arm_gic_sc->gic_d_bsh, reg)
+#define	gic_d_write_4(reg, val)		\
+    bus_space_write_4(arm_gic_sc->gic_d_bst, arm_gic_sc->gic_d_bsh, reg, val)
+
+static void gic_post_filter(void *);
+
+static int
+arm_gic_probe(device_t dev)
+{
+	if (!ofw_bus_is_compatible(dev, "arm,gic"))
+		return (ENXIO);
+	device_set_desc(dev, "ARM Generic Interrupt Controller");
+	return (BUS_PROBE_DEFAULT);
+}
+
+void
+gic_init_secondary(void)
+{
+	int nirqs;
+	
+  	/* Get the number of interrupts */
+	nirqs = gic_d_read_4(GICD_TYPER);
+	nirqs = 32 * ((nirqs & 0x1f) + 1);
+			
+	for (int i = 0; i < nirqs; i += 4)
+		gic_d_write_4(GICD_IPRIORITYR(i >> 2), 0);
+	/* Enable CPU interface */
+	gic_c_write_4(GICC_CTLR, 1);
+
+	/* Enable interrupt distribution */
+	gic_d_write_4(GICD_CTLR, 0x01);
+		
+	/* Activate IRQ 29, ie private timer IRQ*/
+	gic_d_write_4(GICD_ISENABLER(29 >> 5), (1UL << (29 & 0x1F)));
+}
+
+static int
+arm_gic_attach(device_t dev)
+{
+	struct		arm_gic_softc *sc = device_get_softc(dev);
+	int		i;
+	uint32_t	icciidr;
+	uint32_t	nirqs;
+
+	if (arm_gic_sc)
+		return (ENXIO);
+
+	if (bus_alloc_resources(dev, arm_gic_spec, sc->gic_res)) {
+		device_printf(dev, "could not allocate resources\n");
+		return (ENXIO);
+	}
+
+	arm_post_filter = gic_post_filter;
+
+	/* Distributor Interface */
+	sc->gic_d_bst = rman_get_bustag(sc->gic_res[0]);
+	sc->gic_d_bsh = rman_get_bushandle(sc->gic_res[0]);
+
+	/* CPU Interface */
+	sc->gic_c_bst = rman_get_bustag(sc->gic_res[1]);
+	sc->gic_c_bsh = rman_get_bushandle(sc->gic_res[1]);
+
+	arm_gic_sc = sc;
+
+	/* Disable interrupt forwarding to the CPU interface */
+	gic_d_write_4(GICD_CTLR, 0x00);
+
+	/* Get the number of interrupts */
+	nirqs = gic_d_read_4(GICD_TYPER);
+	nirqs = 32 * ((nirqs & 0x1f) + 1);
+
+	icciidr = gic_c_read_4(GICC_IIDR);
+	device_printf(dev,"pn 0x%x, arch 0x%x, rev 0x%x, implementer 0x%x nirqs %u\n", 
+			icciidr>>20, (icciidr>>16) & 0xF, (icciidr>>12) & 0xf,
+			(icciidr & 0xfff), nirqs);
+
+	/* Set all global interrupts to be level triggered, active low. */
+	for (i = 32; i < nirqs; i += 32) {
+		gic_d_write_4(GICD_ICFGR(i >> 5), 0x00000000);
+	}
+
+	/* Disable all interrupts. */
+	for (i = 32; i < nirqs; i += 32) {
+		gic_d_write_4(GICD_ICENABLER(i >> 5), 0xFFFFFFFF);
+	}
+
+	for (i = 0; i < nirqs; i += 4) {
+		gic_d_write_4(GICD_IPRIORITYR(i >> 2),  0);
+		gic_d_write_4(GICD_ITARGETSR(i >> 2), 0xffffffff);
+	}
+
+	/* Enable CPU interface */
+	gic_c_write_4(GICC_CTLR, 1);
+
+	/* Enable interrupt distribution */
+	gic_d_write_4(GICD_CTLR, 0x01);
+
+	return (0);
+}
+
+static device_method_t arm_gic_methods[] = {
+	DEVMETHOD(device_probe,		arm_gic_probe),
+	DEVMETHOD(device_attach,	arm_gic_attach),
+	{ 0, 0 }
+};
+
+static driver_t arm_gic_driver = {
+	"gic",
+	arm_gic_methods,
+	sizeof(struct arm_gic_softc),
+};
+
+static devclass_t arm_gic_devclass;
+
+DRIVER_MODULE(gic, simplebus, arm_gic_driver, arm_gic_devclass, 0, 0);
+
+static void
+gic_post_filter(void *arg)
+{
+	uintptr_t irq = (uintptr_t) arg;
+
+	gic_c_write_4(GICC_EOIR, irq);
+}
+
+int
+arm_get_next_irq(int last_irq)
+{
+	uint32_t active_irq;
+
+	active_irq = gic_c_read_4(GICC_IAR);
+
+	/* 
+	 * Immediatly EOIR the SGIs, because doing so requires the other
+	 * bits (ie CPU number), not just the IRQ number, and we do not
+	 * have this information later.
+	 */
+	   
+	if ((active_irq & 0x3ff) < 16)
+		gic_c_write_4(GICC_EOIR, active_irq);
+	active_irq &= 0x3FF;
+
+	if (active_irq == 0x3FF) {
+		if (last_irq == -1)
+			printf("Spurious interrupt detected [0x%08x]\n", active_irq);
+		return -1;
+	}
+	        gic_c_write_4(GICC_EOIR, active_irq);
+
+	return active_irq;
+}
+
+void
+arm_mask_irq(uintptr_t nb)
+{
+	gic_d_write_4(GICD_ICENABLER(nb >> 5), (1UL << (nb & 0x1F)));
+}
+
+void
+arm_unmask_irq(uintptr_t nb)
+{
+	
+	gic_c_write_4(GICC_EOIR, nb);
+	gic_d_write_4(GICD_ISENABLER(nb >> 5), (1UL << (nb & 0x1F)));
+}
+
+#ifdef SMP
+void
+pic_ipi_send(cpuset_t cpus, u_int ipi)
+{
+	uint32_t val = 0, i;
+
+	for (i = 0; i < MAXCPU; i++)
+		if (CPU_ISSET(i, &cpus))
+			val |= 1 << (16 + i);
+	gic_d_write_4(GICD_SGIR(0), val | ipi);
+	
+}
+
+int
+pic_ipi_get(int i)
+{
+	
+	if (i != -1) {
+		/*
+		 * The intr code will automagically give the frame pointer
+		 * if the interrupt argument is 0.
+		 */
+		if ((unsigned int)i > 16) 
+			return (0);
+		return (i);
+	}
+	return (0x3ff);
+}
+
+void
+pic_ipi_clear(int ipi)
+{
+}
+#endif
+
diff -r 7fffa673adcd -r a301a330526b head/sys/arm/arm/identcpu.c
--- a/head/sys/arm/arm/identcpu.c	Wed Aug 15 11:15:12 2012 +0300
+++ b/head/sys/arm/arm/identcpu.c	Wed Aug 15 11:16:36 2012 +0300
@@ -42,7 +42,7 @@
  */
 
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD: head/sys/arm/arm/identcpu.c 235062 2012-05-05 17:20:12Z imp $");
+__FBSDID("$FreeBSD: head/sys/arm/arm/identcpu.c 239268 2012-08-15 03:03:03Z gonzo $");
 #include <sys/systm.h>
 #include <sys/param.h>
 #include <sys/malloc.h>
@@ -236,6 +236,17 @@
 	{ CPU_ID_ARM1026EJS,	CPU_CLASS_ARM10EJ,	"ARM1026EJ-S",
 	  generic_steppings },
 
+	{ CPU_ID_CORTEXA8R1,	CPU_CLASS_CORTEXA,	"Cortex A8-r1",
+	  generic_steppings },
+	{ CPU_ID_CORTEXA8R2,	CPU_CLASS_CORTEXA,	"Cortex A8-r2",
+	  generic_steppings },
+	{ CPU_ID_CORTEXA8R3,	CPU_CLASS_CORTEXA,	"Cortex A8-r3",
+	  generic_steppings },
+	{ CPU_ID_CORTEXA9R1,	CPU_CLASS_CORTEXA,	"Cortex A9-r1",
+	  generic_steppings },
+	{ CPU_ID_CORTEXA9R2,	CPU_CLASS_CORTEXA,	"Cortex A9-r2",
+	  generic_steppings },
+
 	{ CPU_ID_SA110,		CPU_CLASS_SA1,		"SA-110",
 	  sa110_steppings },
 	{ CPU_ID_SA1100,	CPU_CLASS_SA1,		"SA-1100",
@@ -302,8 +313,17 @@
 
 	{ CPU_ID_MV88FR571_VD,	CPU_CLASS_MARVELL,	"Feroceon 88FR571-VD",
 	  generic_steppings },
-
-	{ CPU_ID_MV88FR571_41,	CPU_CLASS_MARVELL,	"Early Feroceon 88FR571",
+	{ CPU_ID_MV88SV581X_V6,	CPU_CLASS_MARVELL,	"Sheeva 88SV581x",
+	  generic_steppings },
+	{ CPU_ID_ARM_88SV581X_V6, CPU_CLASS_MARVELL,	"Sheeva 88SV581x",
+	  generic_steppings },
+	{ CPU_ID_MV88SV581X_V7,	CPU_CLASS_MARVELL,	"Sheeva 88SV581x",
+	  generic_steppings },
+	{ CPU_ID_ARM_88SV581X_V7, CPU_CLASS_MARVELL,	"Sheeva 88SV581x",
+	  generic_steppings },
+	{ CPU_ID_MV88SV584X,	CPU_CLASS_MARVELL,	"Sheeva 88SV584x",
+	  generic_steppings },
+	{ CPU_ID_ARM_88SV584X,	CPU_CLASS_MARVELL,	"Sheeva 88SV584x",
 	  generic_steppings },
 
 	{ 0, CPU_CLASS_NONE, NULL, NULL }
@@ -328,6 +348,7 @@
 	{ "ARM9EJ-S",	"CPU_ARM9E" },		/* CPU_CLASS_ARM9EJS */
 	{ "ARM10E",	"CPU_ARM10" },		/* CPU_CLASS_ARM10E */
 	{ "ARM10EJ",	"CPU_ARM10" },		/* CPU_CLASS_ARM10EJ */
+	{ "Cortex-A",	"CPU_CORTEXA" },	/* CPU_CLASS_CORTEXA */
 	{ "SA-1",	"CPU_SA110" },		/* CPU_CLASS_SA1 */
 	{ "XScale",	"CPU_XSCALE_..." },	/* CPU_CLASS_XSCALE */
 	{ "ARM11J",	"CPU_ARM11" },		/* CPU_CLASS_ARM11J */
@@ -359,13 +380,81 @@
 	"**unknown 15**",
 };
 
+static void
+print_enadis(int enadis, char *s)
+{
+
+	printf(" %s %sabled", s, (enadis == 0) ? "dis" : "en");
+}
 
 extern int ctrl;
 enum cpu_class cpu_class = CPU_CLASS_NONE;
+
+u_int cpu_pfr(int num)
+{
+	u_int feat;
+
+	switch (num) {
+	case 0:
+		__asm __volatile("mrc p15, 0, %0, c0, c1, 0"
+		    : "=r" (feat));
+		break;
+	case 1:
+		__asm __volatile("mrc p15, 0, %0, c0, c1, 1"
+		    : "=r" (feat));
+		break;
+	default:
+		panic("Processor Feature Register %d not implemented", num);
+		break;
+	}
+
+	return (feat);
+}
+
+static
+void identify_armv7(void)
+{
+	u_int feature;
+
+	printf("Supported features:");
+	/* Get Processor Feature Register 0 */
+	feature = cpu_pfr(0);
+
+	if (feature & ARM_PFR0_ARM_ISA_MASK)
+		printf(" ARM_ISA");
+
+	if (feature & ARM_PFR0_THUMB2)
+		printf(" THUMB2");
+	else if (feature & ARM_PFR0_THUMB)
+		printf(" THUMB");
+
+	if (feature & ARM_PFR0_JAZELLE_MASK)
+		printf(" JAZELLE");
+
+	if (feature & ARM_PFR0_THUMBEE_MASK)
+		printf(" THUMBEE");
+
+
+	/* Get Processor Feature Register 1 */
+	feature = cpu_pfr(1);
+
+	if (feature & ARM_PFR1_ARMV4_MASK)
+		printf(" ARMv4");
+
+	if (feature & ARM_PFR1_SEC_EXT_MASK)
+		printf(" Security_Ext");
+
+	if (feature & ARM_PFR1_MICROCTRL_MASK)
+		printf(" M_profile");
+
+	printf("\n");
+}
+
 void
 identify_arm_cpu(void)
 {
-	u_int cpuid;
+	u_int cpuid, reg, size, sets, ways;
+	u_int8_t type, linesize;
 	int i;
 
 	cpuid = cpu_id();
@@ -389,74 +478,130 @@
 		printf("unknown CPU (ID = 0x%x)\n", cpuid);
 
 	printf(" ");
-	switch (cpu_class) {
-	case CPU_CLASS_ARM6:
-	case CPU_CLASS_ARM7:
-	case CPU_CLASS_ARM7TDMI:
-	case CPU_CLASS_ARM8:
-		if ((ctrl & CPU_CONTROL_IDC_ENABLE) == 0)
-			printf(" IDC disabled");
+
+	if ((cpuid & CPU_ID_ARCH_MASK) == CPU_ID_CPUID_SCHEME) {
+		identify_armv7();
+	} else {
+		if (ctrl & CPU_CONTROL_BEND_ENABLE)
+			printf(" Big-endian");
 		else
-			printf(" IDC enabled");
-		break;
-	case CPU_CLASS_ARM9TDMI:
-	case CPU_CLASS_ARM9ES:
-	case CPU_CLASS_ARM9EJS:
-	case CPU_CLASS_ARM10E:
-	case CPU_CLASS_ARM10EJ:
-	case CPU_CLASS_SA1:
-	case CPU_CLASS_XSCALE:
-	case CPU_CLASS_ARM11J:
-	case CPU_CLASS_MARVELL:
-		if ((ctrl & CPU_CONTROL_DC_ENABLE) == 0)
-			printf(" DC disabled");
-		else
-			printf(" DC enabled");
-		if ((ctrl & CPU_CONTROL_IC_ENABLE) == 0)
-			printf(" IC disabled");
-		else
-			printf(" IC enabled");
+			printf(" Little-endian");
+
+		switch (cpu_class) {
+		case CPU_CLASS_ARM6:
+		case CPU_CLASS_ARM7:
+		case CPU_CLASS_ARM7TDMI:
+		case CPU_CLASS_ARM8:
+			print_enadis(ctrl & CPU_CONTROL_IDC_ENABLE, "IDC");
+			break;
+		case CPU_CLASS_ARM9TDMI:
+		case CPU_CLASS_ARM9ES:
+		case CPU_CLASS_ARM9EJS:
+		case CPU_CLASS_ARM10E:
+		case CPU_CLASS_ARM10EJ:
+		case CPU_CLASS_SA1:
+		case CPU_CLASS_XSCALE:
+		case CPU_CLASS_ARM11J:
+		case CPU_CLASS_MARVELL:
+			print_enadis(ctrl & CPU_CONTROL_DC_ENABLE, "DC");
+			print_enadis(ctrl & CPU_CONTROL_IC_ENABLE, "IC");
 #ifdef CPU_XSCALE_81342
-		if ((ctrl & CPU_CONTROL_L2_ENABLE) == 0)
-			printf(" L2 disabled");
-		else
-			printf(" L2 enabled");
+			print_enadis(ctrl & CPU_CONTROL_L2_ENABLE, "L2");
 #endif
-		break;
-	default:
-		break;
+#if defined(SOC_MV_KIRKWOOD) || defined(SOC_MV_DISCOVERY)
+			i = sheeva_control_ext(0, 0);
+			print_enadis(i & MV_WA_ENABLE, "WA");
+			print_enadis(i & MV_DC_STREAM_ENABLE, "DC streaming");
+			printf("\n ");
+			print_enadis((i & MV_BTB_DISABLE) == 0, "BTB");
+			print_enadis(i & MV_L2_ENABLE, "L2");
+			print_enadis((i & MV_L2_PREFETCH_DISABLE) == 0,
+			    "L2 prefetch");
+			printf("\n ");
+#endif
+			break;
+		default:
+			break;
+		}
 	}
-	if ((ctrl & CPU_CONTROL_WBUF_ENABLE) == 0)
-		printf(" WB disabled");
-	else
-		printf(" WB enabled");
 
+	print_enadis(ctrl & CPU_CONTROL_WBUF_ENABLE, "WB");
 	if (ctrl & CPU_CONTROL_LABT_ENABLE)
 		printf(" LABT");
 	else
 		printf(" EABT");
 
-	if (ctrl & CPU_CONTROL_BPRD_ENABLE)
-		printf(" branch prediction enabled");
+	print_enadis(ctrl & CPU_CONTROL_BPRD_ENABLE, "branch prediction");
+	printf("\n");
 
-	printf("\n");
-	/* Print cache info. */
-	if (arm_picache_line_size == 0 && arm_pdcache_line_size == 0)
-		return;
-	
-	if (arm_pcache_unified) {
- 		printf("  %dKB/%dB %d-way %s unified cache\n",
-		    arm_pdcache_size / 1024,
-		    arm_pdcache_line_size, arm_pdcache_ways,
-		    wtnames[arm_pcache_type]);
+	if (arm_cache_level) {
+		printf("LoUU:%d LoC:%d LoUIS:%d \n", CPU_CLIDR_LOUU(arm_cache_level) + 1,
+		    arm_cache_loc, CPU_CLIDR_LOUIS(arm_cache_level) + 1);
+		i = 0;
+		while (((type = CPU_CLIDR_CTYPE(arm_cache_level, i)) != 0) && i < 7) {
+			printf("Cache level %d: \n", i + 1);
+			if (type == CACHE_DCACHE || type == CACHE_UNI_CACHE ||
+			    type == CACHE_SEP_CACHE) {
+				reg = arm_cache_type[2 * i];
+				ways = CPUV7_CT_xSIZE_ASSOC(reg) + 1;
+				sets = CPUV7_CT_xSIZE_SET(reg) + 1;
+				linesize = 1 << (CPUV7_CT_xSIZE_LEN(reg) + 4);
+				size = (ways * sets * linesize) / 1024;
+
+				if (type == CACHE_UNI_CACHE)
+					printf(" %dKB/%dB %d-way unified cache", size, linesize,ways);
+				else
+					printf(" %dKB/%dB %d-way data cache", size, linesize, ways);
+				if (reg & CPUV7_CT_CTYPE_WT)
+					printf(" WT");
+				if (reg & CPUV7_CT_CTYPE_WB)
+					printf(" WB");
+				if (reg & CPUV7_CT_CTYPE_RA)
+					printf(" Read-Alloc");
+				if (reg & CPUV7_CT_CTYPE_WA)
+					printf(" Write-Alloc");
+				printf("\n");
+			}
+
+			if (type == CACHE_ICACHE || type == CACHE_SEP_CACHE) {
+				reg = arm_cache_type[(2 * i) + 1];
+
+				ways = CPUV7_CT_xSIZE_ASSOC(reg) + 1;
+				sets = CPUV7_CT_xSIZE_SET(reg) + 1;
+				linesize = 1 << (CPUV7_CT_xSIZE_LEN(reg) + 4);
+				size = (ways * sets * linesize) / 1024;
+
+				printf(" %dKB/%dB %d-way instruction cache", size, linesize, ways);
+				if (reg & CPUV7_CT_CTYPE_WT)
+					printf(" WT");
+				if (reg & CPUV7_CT_CTYPE_WB)
+					printf(" WB");
+				if (reg & CPUV7_CT_CTYPE_RA)
+					printf(" Read-Alloc");
+				if (reg & CPUV7_CT_CTYPE_WA)
+					printf(" Write-Alloc");
+				printf("\n");
+			}
+			i++;
+		}
 	} else {
-		printf("  %dKB/%dB %d-way Instruction cache\n",
-		    arm_picache_size / 1024,
-		    arm_picache_line_size, arm_picache_ways);
-		printf("  %dKB/%dB %d-way %s Data cache\n",
-		    arm_pdcache_size / 1024,
-		    arm_pdcache_line_size, arm_pdcache_ways,
-		    wtnames[arm_pcache_type]);
+		/* Print cache info. */
+		if (arm_picache_line_size == 0 && arm_pdcache_line_size == 0)
+			return;
+
+		if (arm_pcache_unified) {
+			printf("  %dKB/%dB %d-way %s unified cache\n",
+			    arm_pdcache_size / 1024,
+			    arm_pdcache_line_size, arm_pdcache_ways,
+			    wtnames[arm_pcache_type]);
+		} else {
+			printf("  %dKB/%dB %d-way instruction cache\n",
+			    arm_picache_size / 1024,
+			    arm_picache_line_size, arm_picache_ways);
+			printf("  %dKB/%dB %d-way %s data cache\n",
+			    arm_pdcache_size / 1024,
+			    arm_pdcache_line_size, arm_pdcache_ways,
+			    wtnames[arm_pcache_type]);
+		}
 	}
 }
-
diff -r 7fffa673adcd -r a301a330526b head/sys/arm/arm/locore.S
--- a/head/sys/arm/arm/locore.S	Wed Aug 15 11:15:12 2012 +0300
+++ b/head/sys/arm/arm/locore.S	Wed Aug 15 11:16:36 2012 +0300
@@ -1,6 +1,7 @@
 /*	$NetBSD: locore.S,v 1.14 2003/04/20 16:21:40 thorpej Exp $	*/
 
 /*-
+ * Copyright 2011 Semihalf
  * Copyright (C) 1994-1997 Mark Brinicombe
  * Copyright (C) 1994 Brini
  * All rights reserved.
@@ -38,10 +39,10 @@
 #include <machine/armreg.h>
 #include <machine/pte.h>
 
-__FBSDID("$FreeBSD: head/sys/arm/arm/locore.S 236524 2012-06-03 18:34:32Z imp $");
+__FBSDID("$FreeBSD: head/sys/arm/arm/locore.S 239268 2012-08-15 03:03:03Z gonzo $");
 
 /* What size should this really be ? It is only used by initarm() */
-#define INIT_ARM_STACK_SIZE	2048
+#define INIT_ARM_STACK_SIZE	(2048 * 4)
 
 #define	CPWAIT_BRANCH							 \
 	sub	pc, pc, #4
@@ -161,15 +162,26 @@
 	orrne	r5, r5, #PHYSADDR
 	movne	pc, r5
 
+#if defined(SMP)
+	orr 	r0, r0, #2		/* Set TTB shared memory flag */
+#endif
 	mcr	p15, 0, r0, c2, c0, 0	/* Set TTB */
 	mcr	p15, 0, r0, c8, c7, 0	/* Flush TLB */
 
+#if defined(CPU_ARM11) || defined(CPU_CORTEXA) || defined(CPU_MV_PJ4B)
+	mov	r0, #0
+	mcr	p15, 0, r0, c13, c0, 1	/* Set ASID to 0 */
+#endif
+
 	/* Set the Domain Access register.  Very important! */
 	mov     r0, #((DOMAIN_CLIENT << (PMAP_DOMAIN_KERNEL*2)) | DOMAIN_CLIENT)
 	mcr	p15, 0, r0, c3, c0, 0
 	/* Enable MMU */
 	mrc	p15, 0, r0, c1, c0, 0
-	orr	r0, r0, #CPU_CONTROL_MMU_ENABLE
+#if defined(CPU_ARM11) || defined(CPU_CORTEXA) || defined(CPU_MV_PJ4B)
+	orr	r0, r0, #CPU_CONTROL_V6_EXTPAGE
+#endif
+	orr	r0, r0, #(CPU_CONTROL_MMU_ENABLE | CPU_CONTROL_DC_ENABLE)
 	mcr	p15, 0, r0, c1, c0, 0
 	nop
 	nop
@@ -225,13 +237,23 @@
 	.word	_edata
 Lstartup_pagetable:
 	.word	STARTUP_PAGETABLE_ADDR
+#ifdef SMP
+Lstartup_pagetable_secondary:
+	.word	temp_pagetable
+#endif
 mmu_init_table:
 	/* fill all table VA==PA */
 	/* map SDRAM VA==PA, WT cacheable */
+#if !defined(SMP)
 	MMU_INIT(PHYSADDR, PHYSADDR , 64, L1_TYPE_S|L1_S_C|L1_S_AP(AP_KRW))
 	/* map VA 0xc0000000..0xc3ffffff to PA */
 	MMU_INIT(KERNBASE, PHYSADDR, 64, L1_TYPE_S|L1_S_C|L1_S_AP(AP_KRW))
-
+#else
+	MMU_INIT(PHYSADDR, PHYSADDR , 64, L1_TYPE_S|L1_SHARED|L1_S_C|L1_S_AP(AP_KRW))
+	/* map VA 0xc0000000..0xc3ffffff to PA */
+	MMU_INIT(KERNBASE, PHYSADDR, 64, L1_TYPE_S|L1_SHARED|L1_S_C|L1_S_AP(AP_KRW))
+	MMU_INIT(0x48000000, 0x48000000, 1, L1_TYPE_S|L1_SHARED|L1_S_C|L1_S_AP(AP_KRW))
+#endif
 	.word 0	/* end of table */
 #endif
 .Lstart:
@@ -241,6 +263,11 @@
 
 .Lvirt_done:
 	.word	virt_done
+#if defined(SMP)
+.Lmpvirt_done:
+	.word	mpvirt_done
+#endif
+
 .Lmainreturned:
 	.asciz	"main() returned"
 	.align	0
@@ -255,6 +282,133 @@
 .Lcpufuncs:
 	.word	_C_LABEL(cpufuncs)
 
+#if defined(SMP)
+Lsramaddr:
+	.word	0xffff0080
+
+#if 0
+#define	AP_DEBUG(tmp)			\
+	mrc	p15, 0, r1, c0, c0, 5;	\
+	ldr	r0, Lsramaddr;		\
+	add	r0, r1, lsl #2;		\
+	mov	r1, tmp;		\
+	str	r1, [r0], #0x0000;
+#else
+#define AP_DEBUG(tmp)
+#endif
+
+
+ASENTRY_NP(mptramp)
+	mov	r0, #0
+	mcr	p15, 0, r0, c7, c7, 0
+
+	AP_DEBUG(#1)
+
+	mrs	r3, cpsr_all
+	bic	r3, r3, #(PSR_MODE)
+	orr	r3, r3, #(PSR_SVC32_MODE)
+        msr	cpsr_all, r3
+
+	mrc	p15, 0, r0, c0, c0, 5
+	and	r0, #0x0f		/* Get CPU ID */
+
+	/* Read boot address for CPU */
+	mov	r1, #0x100
+	mul	r2, r0, r1
+	ldr	r1, Lpmureg
+	add	r0, r2, r1
+	ldr	r1, [r0], #0x00
+
+	mov pc, r1
+
+Lpmureg:
+        .word   0xd0022124
+
+ASENTRY_NP(mpentry)
+
+	AP_DEBUG(#2)
+
+	/* Make sure interrupts are disabled. */
+	mrs	r7, cpsr
+	orr	r7, r7, #(I32_bit|F32_bit)
+	msr	cpsr_c, r7
+
+
+	adr     r7, Ltag
+	bic     r7, r7, #0xf0000000
+	orr     r7, r7, #PHYSADDR
+			
+	/* Disable MMU for a while */
+	mrc	p15, 0, r2, c1, c0, 0
+	bic	r2, r2, #(CPU_CONTROL_MMU_ENABLE | CPU_CONTROL_DC_ENABLE |\
+	    CPU_CONTROL_WBUF_ENABLE)
+	bic	r2, r2, #(CPU_CONTROL_IC_ENABLE)
+	bic	r2, r2, #(CPU_CONTROL_BPRD_ENABLE)
+	mcr	p15, 0, r2, c1, c0, 0
+
+	nop
+	nop
+	nop
+
+	AP_DEBUG(#3)
+
+Ltag:
+	ldr	r0, Lstartup_pagetable_secondary
+	bic	r0, r0, #0xf0000000
+	orr	r0, r0, #PHYSADDR
+	ldr	r0, [r0]
+#if defined(SMP)
+	orr 	r0, r0, #0		/* Set TTB shared memory flag */
+#endif
+	mcr	p15, 0, r0, c2, c0, 0	/* Set TTB */
+	mcr	p15, 0, r0, c8, c7, 0	/* Flush TLB */
+
+#if defined(CPU_ARM11) || defined(CPU_MV_PJ4B) || defined(CPU_CORTEXA)
+	mov	r0, #0
+	mcr	p15, 0, r0, c13, c0, 1	/* Set ASID to 0 */
+#endif
+
+	AP_DEBUG(#4)
+
+	/* Set the Domain Access register.  Very important! */
+	mov	r0, #((DOMAIN_CLIENT << (PMAP_DOMAIN_KERNEL*2)) | DOMAIN_CLIENT)
+	mcr	p15, 0, r0, c3, c0, 0
+	/* Enable MMU */
+	mrc	p15, 0, r0, c1, c0, 0
+#if defined(CPU_ARM11) || defined(CPU_MV_PJ4B) || defined(CPU_CORTEXA)
+	orr	r0, r0, #CPU_CONTROL_V6_EXTPAGE
+#endif
+	orr	r0, r0, #(CPU_CONTROL_MMU_ENABLE | CPU_CONTROL_DC_ENABLE)
+	mcr	p15, 0, r0, c1, c0, 0
+	nop
+	nop
+	nop
+	CPWAIT(r0)
+
+	adr	r1, .Lstart
+	ldmia	r1, {r1, r2, sp}	/* Set initial stack and */
+	mrc	p15, 0, r0, c0, c0, 5
+	and	r0, r0, #15
+	mov	r1, #2048
+	mul	r2, r1, r0
+	sub	sp, sp, r2
+	str	r1, [sp]
+	ldr	pc, .Lmpvirt_done
+
+mpvirt_done:
+
+	mov	fp, #0			/* trace back starts here */
+	bl	_C_LABEL(init_secondary)	/* Off we go */
+
+	adr	r0, .Lmpreturned
+	b	_C_LABEL(panic)
+	/* NOTREACHED */
+
+.Lmpreturned:
+	.asciz	"main() returned"
+	.align	0
+#endif
+
 ENTRY_NP(cpu_halt)
 	mrs     r2, cpsr
 	bic	r2, r2, #(PSR_MODE)
diff -r 7fffa673adcd -r a301a330526b head/sys/arm/arm/machdep.c
--- a/head/sys/arm/arm/machdep.c	Wed Aug 15 11:15:12 2012 +0300
+++ b/head/sys/arm/arm/machdep.c	Wed Aug 15 11:16:36 2012 +0300
@@ -44,9 +44,10 @@
 
 #include "opt_compat.h"
 #include "opt_ddb.h"
+#include "opt_timer.h"
 
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD: head/sys/arm/arm/machdep.c 237118 2012-06-15 07:26:39Z imp $");
+__FBSDID("$FreeBSD: head/sys/arm/arm/machdep.c 239268 2012-08-15 03:03:03Z gonzo $");
 
 #include <sys/param.h>
 #include <sys/proc.h>
@@ -93,8 +94,10 @@
 #include <machine/vmparam.h>
 #include <machine/sysarch.h>
 
+struct pcpu __pcpu[MAXCPU];
+struct pcpu *pcpup = &__pcpu[0];
+
 static struct trapframe proc0_tf;
-
 uint32_t cpu_reset_address = 0;
 int cold = 1;
 vm_offset_t vector_page;
@@ -278,9 +281,11 @@
 cpu_startup(void *dummy)
 {
 	struct pcb *pcb = thread0.td_pcb;
+#ifdef ARM_TP_ADDRESS
 #ifndef ARM_CACHE_LOCK_ENABLE
 	vm_page_t m;
 #endif
+#endif
 
 	cpu_setup("");
 	identify_arm_cpu();
@@ -322,6 +327,7 @@
 	vector_page_setprot(VM_PROT_READ);
 	pmap_set_pcb_pagedir(pmap_kernel(), pcb);
 	pmap_postinit();
+#ifdef ARM_TP_ADDRESS
 #ifdef ARM_CACHE_LOCK_ENABLE
 	pmap_kenter_user(ARM_TP_ADDRESS, ARM_TP_ADDRESS);
 	arm_lock_cache_line(ARM_TP_ADDRESS);
@@ -331,6 +337,7 @@
 #endif
 	*(uint32_t *)ARM_RAS_START = 0;
 	*(uint32_t *)ARM_RAS_END = 0xffffffff;
+#endif
 }
 
 SYSINIT(cpu, SI_SUB_CPU, SI_ORDER_FIRST, cpu_startup, NULL);
@@ -358,7 +365,20 @@
 void
 cpu_idle(int busy)
 {
+	
+#ifndef NO_EVENTTIMERS
+	if (!busy) {
+		critical_enter();
+		cpu_idleclock();
+	}
+#endif
 	cpu_sleep(0);
+#ifndef NO_EVENTTIMERS
+	if (!busy) {
+		cpu_activeclock();
+		critical_exit();
+	}
+#endif
 }
 
 int
@@ -768,6 +788,19 @@
 	return (lastaddr);
 }
 
+void
+pcpu0_init(void)
+{
+#if ARM_ARCH_7A || defined(CPU_MV_PJ4B)
+	set_pcpu(pcpup);
+#endif
+	pcpu_init(pcpup, 0, sizeof(struct pcpu));
+	PCPU_SET(curthread, &thread0);
+#ifdef ARM_VFP_SUPPORT
+	PCPU_SET(cpu, 0);
+#endif
+}
+
 #if defined(LINUX_BOOT_ABI)
 vm_offset_t
 linux_parse_boot_param(struct arm_boot_params *abp)
diff -r 7fffa673adcd -r a301a330526b head/sys/arm/arm/mp_machdep.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/head/sys/arm/arm/mp_machdep.c	Wed Aug 15 11:16:36 2012 +0300
@@ -0,0 +1,393 @@
+/*-
+ * Copyright (c) 2011 Semihalf.
+ * 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.
+ */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: head/sys/arm/arm/mp_machdep.c 239268 2012-08-15 03:03:03Z gonzo $");
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/bus.h>
+#include <sys/kernel.h>
+#include <sys/lock.h>
+#include <sys/mutex.h>
+#include <sys/proc.h>
+#include <sys/pcpu.h>
+#include <sys/sched.h>
+#include <sys/smp.h>
+#include <sys/ktr.h>
+#include <sys/malloc.h>
+
+#include <vm/vm.h>
+#include <vm/vm_extern.h>
+#include <vm/vm_kern.h>
+#include <vm/pmap.h>
+
+#include <machine/cpu.h>
+#include <machine/smp.h>
+#include <machine/pcb.h>
+#include <machine/pte.h>
+#include <machine/intr.h>
+#include <machine/vmparam.h>
+
+#include "opt_smp.h"
+
+void *temp_pagetable;
+extern struct pcpu __pcpu[];
+/* used to hold the AP's until we are ready to release them */
+struct mtx ap_boot_mtx;
+struct pcb stoppcbs[MAXCPU];
+
+/* # of Applications processors */
+volatile int mp_naps;
+
+/* Set to 1 once we're ready to let the APs out of the pen. */
+volatile int aps_ready = 0;
+
+static int ipi_handler(void *arg);
+void set_stackptrs(int cpu);
+
+/* Temporary variables for init_secondary()  */
+void *dpcpu[MAXCPU - 1];
+
+/* Determine if we running MP machine */
+int
+cpu_mp_probe(void)
+{
+	CPU_SETOF(0, &all_cpus);
+
+	return (platform_mp_probe());
+}
+
+/* Start Application Processor via platform specific function */
+static int
+check_ap(void)
+{
+	uint32_t ms;
+
+	for (ms = 0; ms < 2000; ++ms) {
+		if ((mp_naps + 1) == mp_ncpus)
+			return (0);		/* success */
+		else
+			DELAY(1000);
+	}
+
+	return (-2);
+}
+
+extern unsigned char _end[];
+
+/* Initialize and fire up non-boot processors */
+void
+cpu_mp_start(void)
+{
+	int error, i;
+	vm_offset_t temp_pagetable_va;
+	vm_paddr_t addr, addr_end;
+
+	mtx_init(&ap_boot_mtx, "ap boot", NULL, MTX_SPIN);
+
+	/* Reserve memory for application processors */
+	for(i = 0; i < (mp_ncpus - 1); i++)
+		dpcpu[i] = (void *)kmem_alloc(kernel_map, DPCPU_SIZE);
+	temp_pagetable_va = (vm_offset_t)contigmalloc(L1_TABLE_SIZE,
+	    M_TEMP, 0, 0x0, 0xffffffff, L1_TABLE_SIZE, 0);
+	addr = KERNPHYSADDR;
+	addr_end = (vm_offset_t)&_end - KERNVIRTADDR + KERNPHYSADDR;
+	addr_end &= ~L1_S_OFFSET;
+	addr_end += L1_S_SIZE;
+	bzero((void *)temp_pagetable_va,  L1_TABLE_SIZE);
+	for (addr = KERNPHYSADDR; addr <= addr_end; addr += L1_S_SIZE) { 
+		((int *)(temp_pagetable_va))[addr >> L1_S_SHIFT] =
+		    L1_TYPE_S|L1_SHARED|L1_S_C|L1_S_AP(AP_KRW)|L1_S_DOM(PMAP_DOMAIN_KERNEL)|addr;
+		((int *)(temp_pagetable_va))[(addr -
+			KERNPHYSADDR + KERNVIRTADDR) >> L1_S_SHIFT] = 
+		    L1_TYPE_S|L1_SHARED|L1_S_C|L1_S_AP(AP_KRW)|L1_S_DOM(PMAP_DOMAIN_KERNEL)|addr;
+	}
+	temp_pagetable = (void*)(vtophys(temp_pagetable_va));
+	cpu_idcache_wbinv_all();
+	cpu_l2cache_wbinv_all();
+
+	/* Initialize boot code and start up processors */
+	platform_mp_start_ap();
+
+	/*  Check if ap's started properly */
+	error = check_ap();
+	if (error)
+		printf("WARNING: Some AP's failed to start\n");
+	else
+		for (i = 1; i < mp_ncpus; i++)
+			CPU_SET(i, &all_cpus);
+
+	contigfree((void *)temp_pagetable_va, L1_TABLE_SIZE, M_TEMP);
+}
+
+/* Introduce rest of cores to the world */
+void
+cpu_mp_announce(void)
+{
+
+}
+
+extern vm_paddr_t pmap_pa;
+void
+init_secondary(int cpu)
+{
+	struct pcpu *pc;
+	uint32_t loop_counter;
+	int start = 0, end = 0;
+
+	cpu_setup(NULL);
+	setttb(pmap_pa);
+	cpu_tlb_flushID();
+
+	pc = &__pcpu[cpu];
+	set_pcpu(pc);
+	pcpu_init(pc, cpu, sizeof(struct pcpu));
+
+	dpcpu_init(dpcpu[cpu - 1], cpu);
+
+	/* Provide stack pointers for other processor modes. */
+	set_stackptrs(cpu);
+
+	/* Signal our startup to BSP */
+	atomic_add_rel_32(&mp_naps, 1);
+
+	/* Spin until the BSP releases the APs */
+	while (!aps_ready)
+		;
+
+	/* Initialize curthread */
+	KASSERT(PCPU_GET(idlethread) != NULL, ("no idle thread"));
+	pc->pc_curthread = pc->pc_idlethread;
+	pc->pc_curpcb = pc->pc_idlethread->td_pcb;
+
+	mtx_lock_spin(&ap_boot_mtx);
+
+	atomic_add_rel_32(&smp_cpus, 1);
+
+	if (smp_cpus == mp_ncpus) {
+		/* enable IPI's, tlb shootdown, freezes etc */
+		atomic_store_rel_int(&smp_started, 1);
+		smp_active = 1;
+	}
+
+	mtx_unlock_spin(&ap_boot_mtx);
+
+	/* Enable ipi */
+#ifdef IPI_IRQ_START
+	start = IPI_IRQ_START;
+#ifdef IPI_IRQ_END
+  	end = IPI_IRQ_END;
+#else
+	end = IPI_IRQ_START;
+#endif
+#endif
+				
+	for (int i = start; i <= end; i++)
+		arm_unmask_irq(i);
+	enable_interrupts(I32_bit);
+
+	loop_counter = 0;
+	while (smp_started == 0) {
+		DELAY(100);
+		loop_counter++;
+		if (loop_counter == 1000)
+			CTR0(KTR_SMP, "AP still wait for smp_started");
+	}
+	/* Start per-CPU event timers. */
+	cpu_initclocks_ap();
+
+	CTR0(KTR_SMP, "go into scheduler");
+	platform_mp_init_secondary();
+
+	/* Enter the scheduler */
+	sched_throw(NULL);
+
+	panic("scheduler returned us to %s", __func__);
+	/* NOTREACHED */
+}
+
+static int
+ipi_handler(void *arg)
+{
+	u_int	cpu, ipi;
+
+	cpu = PCPU_GET(cpuid);
+
+	ipi = pic_ipi_get((int)arg);
+
+	while ((ipi != 0x3ff)) {
+		switch (ipi) {
+		case IPI_RENDEZVOUS:
+			CTR0(KTR_SMP, "IPI_RENDEZVOUS");
+			smp_rendezvous_action();
+			break;
+
+		case IPI_AST:
+			CTR0(KTR_SMP, "IPI_AST");
+			break;
+
+		case IPI_STOP:
+		case IPI_STOP_HARD:
+			/*
+			 * IPI_STOP_HARD is mapped to IPI_STOP so it is not
+			 * necessary to add it in the switch.
+			 */
+			CTR0(KTR_SMP, "IPI_STOP or IPI_STOP_HARD");
+
+			savectx(&stoppcbs[cpu]);
+
+			/* Indicate we are stopped */
+			CPU_SET_ATOMIC(cpu, &stopped_cpus);
+
+			/* Wait for restart */
+			while (!CPU_ISSET(cpu, &started_cpus))
+				cpu_spinwait();
+
+			CPU_CLR_ATOMIC(cpu, &started_cpus);
+			CPU_CLR_ATOMIC(cpu, &stopped_cpus);
+			CTR0(KTR_SMP, "IPI_STOP (restart)");
+			break;
+		case IPI_PREEMPT:
+			CTR1(KTR_SMP, "%s: IPI_PREEMPT", __func__);
+			sched_preempt(curthread);
+			break;
+		case IPI_HARDCLOCK:
+			CTR1(KTR_SMP, "%s: IPI_HARDCLOCK", __func__);
+			hardclockintr();
+			break;
+		case IPI_TLB:
+			CTR1(KTR_SMP, "%s: IPI_TLB", __func__);
+			cpufuncs.cf_tlb_flushID();
+			break;
+		default:
+			panic("Unknown IPI 0x%0x on cpu %d", ipi, curcpu);
+		}
+
+		pic_ipi_clear(ipi);
+		ipi = pic_ipi_get(-1);
+	}
+
+	return (FILTER_HANDLED);
+}
+
+static void
+release_aps(void *dummy __unused)
+{
+	uint32_t loop_counter;
+	int start = 0, end = 0;
+
+	if (mp_ncpus == 1)
+		return;
+#ifdef IPI_IRQ_START
+	start = IPI_IRQ_START;
+#ifdef IPI_IRQ_END
+	end = IPI_IRQ_END;
+#else
+	end = IPI_IRQ_START;
+#endif
+#endif
+
+	for (int i = start; i <= end; i++) {
+		/*
+		 * IPI handler
+		 */
+		/* 
+		 * Use 0xdeadbeef as the argument value for irq 0,
+		 * if we used 0, the intr code will give the trap frame
+		 * pointer instead.
+		 */
+		arm_setup_irqhandler("ipi", ipi_handler, NULL, (void *)i, i,
+		    INTR_TYPE_MISC | INTR_EXCL, NULL);
+
+		/* Enable ipi */
+		arm_unmask_irq(i);
+	}
+	atomic_store_rel_int(&aps_ready, 1);
+
+	printf("Release APs\n");
+
+	for (loop_counter = 0; loop_counter < 2000; loop_counter++) {
+		if (smp_started)
+			return;
+		DELAY(1000);
+	}
+	printf("AP's not started\n");
+}
+
+SYSINIT(start_aps, SI_SUB_SMP, SI_ORDER_FIRST, release_aps, NULL);
+
+struct cpu_group *
+cpu_topo(void)
+{
+
+	return (smp_topo_1level(CG_SHARE_L2, 1, 0));
+}
+
+void
+cpu_mp_setmaxid(void)
+{
+
+	platform_mp_setmaxid();
+}
+
+/* Sending IPI */
+void
+ipi_all_but_self(u_int ipi)
+{
+	cpuset_t other_cpus;
+
+	other_cpus = all_cpus;
+	CPU_CLR(PCPU_GET(cpuid), &other_cpus);
+	CTR2(KTR_SMP, "%s: ipi: %x", __func__, ipi);
+	platform_ipi_send(other_cpus, ipi);
+}
+
+void
+ipi_cpu(int cpu, u_int ipi)
+{
+	cpuset_t cpus;
+
+	CPU_ZERO(&cpus);
+	CPU_SET(cpu, &cpus);
+
+	CTR3(KTR_SMP, "%s: cpu: %d, ipi: %x", __func__, cpu, ipi);
+	platform_ipi_send(cpus, ipi);
+}
+
+void
+ipi_selected(cpuset_t cpus, u_int ipi)
+{
+
+	CTR2(KTR_SMP, "%s: ipi: %x", __func__, ipi);
+	platform_ipi_send(cpus, ipi);
+}
+
+void
+tlb_broadcast(int ipi)
+{
+
+	if (smp_started)
+		ipi_all_but_self(ipi);
+}
diff -r 7fffa673adcd -r a301a330526b head/sys/arm/arm/mpcore_timer.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/head/sys/arm/arm/mpcore_timer.c	Wed Aug 15 11:16:36 2012 +0300
@@ -0,0 +1,431 @@
+/*-
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ *
+ * Developed by Ben Gray <ben.r.gray at gmail.com>
+ *
+ * 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. 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 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.
+ */
+
+/**
+ *	The ARM Cortex-A9 core can support a global timer plus a private and
+ *	watchdog timer per core.  This driver reserves memory and interrupt
+ *	resources for accessing both timer register sets, these resources are
+ *	stored globally and used to setup the timecount and eventtimer.
+ *
+ *	The timecount timer uses the global 64-bit counter, whereas the
+ *	per-CPU eventtimer uses the private 32-bit counters.
+ *
+ *
+ *	REF: ARM Cortex-A9 MPCore, Technical Reference Manual (rev. r2p2)
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: head/sys/arm/arm/mpcore_timer.c 239268 2012-08-15 03:03:03Z gonzo $");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/bus.h>
+#include <sys/kernel.h>
+#include <sys/module.h>
+#include <sys/malloc.h>
+#include <sys/rman.h>
+#include <sys/timeet.h>
+#include <sys/timetc.h>
+#include <sys/watchdog.h>
+#include <machine/bus.h>
+#include <machine/cpu.h>
+#include <machine/frame.h>
+#include <machine/intr.h>
+
+#include <dev/fdt/fdt_common.h>
+#include <dev/ofw/openfirm.h>
+#include <dev/ofw/ofw_bus.h>
+#include <dev/ofw/ofw_bus_subr.h>
+
+#include <machine/bus.h>
+#include <machine/fdt.h>
+
+/* Private (per-CPU) timer register map */
+#define PRV_TIMER_LOAD                 0x0000
+#define PRV_TIMER_COUNT                0x0004
+#define PRV_TIMER_CTRL                 0x0008
+#define PRV_TIMER_INTR                 0x000C
+
+#define PRV_TIMER_CTR_PRESCALER_SHIFT  8
+#define PRV_TIMER_CTRL_IRQ_ENABLE      (1UL << 2)
+#define PRV_TIMER_CTRL_AUTO_RELOAD     (1UL << 1)
+#define PRV_TIMER_CTRL_TIMER_ENABLE    (1UL << 0)
+
+#define PRV_TIMER_INTR_EVENT           (1UL << 0)
+
+/* Global timer register map */
+#define GBL_TIMER_COUNT_LOW            0x0000
+#define GBL_TIMER_COUNT_HIGH           0x0004
+#define GBL_TIMER_CTRL                 0x0008
+#define GBL_TIMER_INTR                 0x000C
+
+#define GBL_TIMER_CTR_PRESCALER_SHIFT  8
+#define GBL_TIMER_CTRL_AUTO_INC        (1UL << 3)
+#define GBL_TIMER_CTRL_IRQ_ENABLE      (1UL << 2)
+#define GBL_TIMER_CTRL_COMP_ENABLE     (1UL << 1)
+#define GBL_TIMER_CTRL_TIMER_ENABLE    (1UL << 0)
+
+#define GBL_TIMER_INTR_EVENT           (1UL << 0)
+
+struct arm_tmr_softc {
+	struct resource *	tmr_res[4];
+	bus_space_tag_t		prv_bst;
+	bus_space_tag_t		gbl_bst;
+	bus_space_handle_t	prv_bsh;
+	bus_space_handle_t	gbl_bsh;
+	uint32_t		clkfreq;
+	struct eventtimer	et;
+};
+
+static struct resource_spec arm_tmr_spec[] = {
+	{ SYS_RES_MEMORY,	0,	RF_ACTIVE },	/* Global registers */
+	{ SYS_RES_IRQ,		0,	RF_ACTIVE },    /* Global timer interrupt (unused) */
+	{ SYS_RES_MEMORY,	1,	RF_ACTIVE },	/* Private (per-CPU) registers */
+	{ SYS_RES_IRQ,		1,	RF_ACTIVE },    /* Private timer interrupt */
+	{ -1, 0 }
+};
+
+static struct arm_tmr_softc *arm_tmr_sc = NULL;
+
+#define	tmr_prv_read_4(reg)		\
+    bus_space_read_4(arm_tmr_sc->prv_bst, arm_tmr_sc->prv_bsh, reg)
+#define	tmr_prv_write_4(reg, val)		\
+    bus_space_write_4(arm_tmr_sc->prv_bst, arm_tmr_sc->prv_bsh, reg, val)
+#define	tmr_gbl_read_4(reg)		\
+    bus_space_read_4(arm_tmr_sc->gbl_bst, arm_tmr_sc->gbl_bsh, reg)
+#define	tmr_gbl_write_4(reg, val)		\
+    bus_space_write_4(arm_tmr_sc->gbl_bst, arm_tmr_sc->gbl_bsh, reg, val)
+
+
+static timecounter_get_t arm_tmr_get_timecount;
+
+static struct timecounter arm_tmr_timecount = {
+	.tc_name           = "ARM MPCore Timecouter",
+	.tc_get_timecount  = arm_tmr_get_timecount,
+	.tc_poll_pps       = NULL,
+	.tc_counter_mask   = ~0u,
+	.tc_frequency      = 0,
+	.tc_quality        = 1000,
+};
+
+/**
+ *	arm_tmr_get_timecount - reads the timecount (global) timer
+ *	@tc: pointer to arm_tmr_timecount struct
+ *
+ *	We only read the lower 32-bits, the timecount stuff only uses 32-bits
+ *	so (for now?) ignore the upper 32-bits.
+ *
+ *	RETURNS
+ *	The lower 32-bits of the counter.
+ */
+static unsigned
+arm_tmr_get_timecount(struct timecounter *tc)
+{
+	return (tmr_gbl_read_4(GBL_TIMER_COUNT_LOW));
+}
+
+/**
+ *	arm_tmr_start - starts the eventtimer (private) timer
+ *	@et: pointer to eventtimer struct
+ *	@first: the number of seconds and fractional sections to trigger in
+ *	@period: the period (in seconds and fractional sections) to set
+ *
+ *	If the eventtimer is required to be in oneshot mode, period will be
+ *	NULL and first will point to the time to trigger.  If in periodic mode
+ *	period will contain the time period and first may optionally contain
+ *	the time for the first period.
+ *
+ *	RETURNS
+ *	Always returns 0
+ */
+static int
+arm_tmr_start(struct eventtimer *et, struct bintime *first,
+              struct bintime *period)
+{
+	struct arm_tmr_softc *sc = (struct arm_tmr_softc *)et->et_priv;
+	uint32_t load, count;
+	uint32_t ctrl;
+
+	ctrl = PRV_TIMER_CTRL_IRQ_ENABLE | PRV_TIMER_CTRL_TIMER_ENABLE;
+
+	if (period != NULL) {
+		load = (et->et_frequency * (period->frac >> 32)) >> 32;
+		if (period->sec > 0)
+			load += et->et_frequency * period->sec;
+		ctrl |= PRV_TIMER_CTRL_AUTO_RELOAD;
+	} else {
+		load = 0;
+	}
+
+	if (first != NULL) {
+		count = (sc->et.et_frequency * (first->frac >> 32)) >> 32;
+		if (first->sec != 0)
+			count += sc->et.et_frequency * first->sec;
+	} else {
+		count = load;
+	}
+
+	tmr_prv_write_4(PRV_TIMER_LOAD, load);
+	tmr_prv_write_4(PRV_TIMER_COUNT, count);
+
+	tmr_prv_write_4(PRV_TIMER_CTRL, ctrl);
+	return (0);
+}
+
+/**
+ *	arm_tmr_stop - stops the eventtimer (private) timer
+ *	@et: pointer to eventtimer struct
+ *
+ *	Simply stops the private timer by clearing all bits in the ctrl register.
+ *
+ *	RETURNS
+ *	Always returns 0
+ */
+static int
+arm_tmr_stop(struct eventtimer *et)
+{
+	tmr_prv_write_4(PRV_TIMER_CTRL, 0);
+	return (0);
+}
+
+/**
+ *	arm_tmr_intr - ISR for the eventtimer (private) timer
+ *	@arg: pointer to arm_tmr_softc struct
+ *
+ *	Clears the event register and then calls the eventtimer callback.
+ *
+ *	RETURNS
+ *	Always returns FILTER_HANDLED
+ */
+static int
+arm_tmr_intr(void *arg)
+{
+	struct arm_tmr_softc *sc = (struct arm_tmr_softc *)arg;
+
+	tmr_prv_write_4(PRV_TIMER_INTR, PRV_TIMER_INTR_EVENT);
+
+	if (sc->et.et_active)
+		sc->et.et_event_cb(&sc->et, sc->et.et_arg);
+
+	return (FILTER_HANDLED);
+}
+
+
+
+
+/**
+ *	arm_tmr_probe - timer probe routine
+ *	@dev: new device
+ *
+ *	The probe function returns success when probed with the fdt compatible
+ *	string set to "arm,mpcore-timers".
+ *
+ *	RETURNS
+ *	BUS_PROBE_DEFAULT if the fdt device is compatible, otherwise ENXIO.
+ */
+static int
+arm_tmr_probe(device_t dev)
+{
+	if (!ofw_bus_is_compatible(dev, "arm,mpcore-timers"))
+		return (ENXIO);
+
+	device_set_desc(dev, "ARM Generic MPCore Timers");
+	return (BUS_PROBE_DEFAULT);
+}
+
+/**
+ *	arm_tmr_attach - attaches the timer to the simplebus
+ *	@dev: new device
+ *
+ *	Reserves memory and interrupt resources, stores the softc structure
+ *	globally and registers both the timecount and eventtimer objects.
+ *
+ *	RETURNS
+ *	Zero on sucess or ENXIO if an error occuried.
+ */
+static int
+arm_tmr_attach(device_t dev)
+{
+	struct arm_tmr_softc *sc = device_get_softc(dev);
+	phandle_t node;
+	pcell_t clock;
+	void *ihl;
+
+	if (arm_tmr_sc)
+		return (ENXIO);
+
+	/* Get the base clock frequency */
+	node = ofw_bus_get_node(dev);
+	if ((OF_getprop(node, "clock-frequency", &clock, sizeof(clock))) <= 0) {
+		device_printf(dev, "missing clock-frequency attribute in FDT\n");
+		return (ENXIO);
+	}
+	sc->clkfreq = fdt32_to_cpu(clock);
+
+
+	if (bus_alloc_resources(dev, arm_tmr_spec, sc->tmr_res)) {
+		device_printf(dev, "could not allocate resources\n");
+		return (ENXIO);
+	}
+
+	/* Global timer interface */
+	sc->gbl_bst = rman_get_bustag(sc->tmr_res[0]);
+	sc->gbl_bsh = rman_get_bushandle(sc->tmr_res[0]);
+
+	/* Private per-CPU timer interface */
+	sc->prv_bst = rman_get_bustag(sc->tmr_res[2]);
+	sc->prv_bsh = rman_get_bushandle(sc->tmr_res[2]);
+
+	arm_tmr_sc = sc;
+
+	/* Disable both timers to start off */
+	tmr_prv_write_4(PRV_TIMER_CTRL, 0x00000000);
+	tmr_gbl_write_4(GBL_TIMER_CTRL, 0x00000000);
+
+	/* Setup and enable the global timer to use as the timecounter */
+	tmr_gbl_write_4(GBL_TIMER_CTRL, (0x00 << GBL_TIMER_CTR_PRESCALER_SHIFT) | 
+					GBL_TIMER_CTRL_TIMER_ENABLE);
+
+	arm_tmr_timecount.tc_frequency = sc->clkfreq;
+	tc_init(&arm_tmr_timecount);
+
+	/* Setup and enable the timer */
+	if (bus_setup_intr(dev, sc->tmr_res[3], INTR_TYPE_CLK, arm_tmr_intr,
+			NULL, sc, &ihl) != 0) {
+		bus_release_resources(dev, arm_tmr_spec, sc->tmr_res);
+		device_printf(dev, "Unable to setup the clock irq handler.\n");
+		return (ENXIO);
+	}
+
+	sc->et.et_name = "ARM MPCore Eventtimer";
+	sc->et.et_flags = ET_FLAGS_PERIODIC | ET_FLAGS_ONESHOT | ET_FLAGS_PERCPU;
+	sc->et.et_quality = 1000;
+
+	sc->et.et_frequency = sc->clkfreq;
+	sc->et.et_min_period.sec = 0;
+	sc->et.et_min_period.frac =
+            ((0x00000002LLU << 32) / sc->et.et_frequency) << 32;
+	sc->et.et_max_period.sec = 0xfffffff0U / sc->et.et_frequency;
+	sc->et.et_max_period.frac =
+            ((0xfffffffeLLU << 32) / sc->et.et_frequency) << 32;
+	sc->et.et_start = arm_tmr_start;
+	sc->et.et_stop = arm_tmr_stop;
+	sc->et.et_priv = sc;
+	et_register(&sc->et);
+
+	return (0);
+}
+
+static device_method_t arm_tmr_methods[] = {
+	DEVMETHOD(device_probe,		arm_tmr_probe),
+	DEVMETHOD(device_attach,	arm_tmr_attach),
+	{ 0, 0 }
+};
+
+static driver_t arm_tmr_driver = {
+	"mp_tmr",
+	arm_tmr_methods,
+	sizeof(struct arm_tmr_softc),
+};
+
+static devclass_t arm_tmr_devclass;
+
+DRIVER_MODULE(mp_tmr, simplebus, arm_tmr_driver, arm_tmr_devclass, 0, 0);
+
+/**
+ *	cpu_initclocks - called by system to initialise the cpu clocks
+ *
+ *	This is a boilerplat function, most of the setup has already been done
+ *	when the driver was attached.  Therefore this function must only be called
+ *	after the driver is attached.
+ *
+ *	RETURNS
+ *	nothing
+ */
+void
+cpu_initclocks(void)
+{
+	if (PCPU_GET(cpuid) == 0)
+		cpu_initclocks_bsp();
+	else
+		cpu_initclocks_ap();
+}
+
+/**
+ *	DELAY - Delay for at least usec microseconds.
+ *	@usec: number of microseconds to delay by
+ *
+ *	This function is called all over the kernel and is suppose to provide a
+ *	consistent delay.  This function may also be called before the console 
+ *	is setup so no printf's can be called here.
+ *
+ *	RETURNS:
+ *	nothing
+ */
+void
+DELAY(int usec)
+{
+	int32_t counts_per_usec;
+	int32_t counts;
+	uint32_t first, last;
+
+	/* Check the timers are setup, if not just use a for loop for the meantime */
+	if (arm_tmr_sc == NULL) {
+		for (; usec > 0; usec--)
+			for (counts = 200; counts > 0; counts--)
+				cpufunc_nullop();	/* Prevent gcc from optimizing
+							 * out the loop
+							 */
+		return;
+	}
+
+	/* Get the number of times to count */
+	counts_per_usec = ((arm_tmr_timecount.tc_frequency / 1000000) + 1);
+
+	/*
+	 * Clamp the timeout at a maximum value (about 32 seconds with
+	 * a 66MHz clock). *Nobody* should be delay()ing for anywhere
+	 * near that length of time and if they are, they should be hung
+	 * out to dry.
+	 */
+	if (usec >= (0x80000000U / counts_per_usec))
+		counts = (0x80000000U / counts_per_usec) - 1;
+	else
+		counts = usec * counts_per_usec;
+
+	first = tmr_gbl_read_4(GBL_TIMER_COUNT_LOW);
+
+	while (counts > 0) {
+		last = tmr_gbl_read_4(GBL_TIMER_COUNT_LOW);
+		counts -= (int32_t)(last - first);
+		first = last;
+	}
+}
diff -r 7fffa673adcd -r a301a330526b head/sys/arm/arm/pl310.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/head/sys/arm/arm/pl310.c	Wed Aug 15 11:16:36 2012 +0300
@@ -0,0 +1,321 @@
+/*-
+ * Copyright (c) 2012 Olivier Houchard <cognet at FreeBSD.org>
+ * Copyright (c) 2011
+ *	Ben Gray <ben.r.gray at 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.
+ * 3. 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 BEN GRAY ``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 BEN GRAY 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: head/sys/arm/arm/pl310.c 239268 2012-08-15 03:03:03Z gonzo $");
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/bus.h>
+#include <sys/kernel.h>
+#include <sys/rman.h>
+#include <sys/module.h>
+#include <sys/lock.h>
+#include <sys/mutex.h>
+#include <machine/intr.h>
+#include <vm/vm.h>
+#include <vm/pmap.h>
+#include <machine/pl310.h>
+#include <machine/bus.h>
+
+#include <dev/fdt/fdt_common.h>
+#include <dev/ofw/openfirm.h>
+#include <dev/ofw/ofw_bus.h>
+#include <dev/ofw/ofw_bus_subr.h>
+
+/**
+ *	PL310 - L2 Cache Controller register offsets.
+ *
+ */
+#define PL310_CACHE_ID              0x000
+#define PL310_CACHE_TYPE            0x004
+#define PL310_CTRL                  0x100
+#define PL310_AUX_CTRL              0x104
+#define PL310_EVENT_COUNTER_CTRL    0x200
+#define PL310_EVENT_COUNTER1_CONF   0x204
+#define PL310_EVENT_COUNTER0_CONF   0x208
+#define PL310_EVENT_COUNTER1_VAL    0x20C
+#define PL310_EVENT_COUNTER0_VAL    0x210
+#define PL310_INTR_MASK             0x214
+#define PL310_MASKED_INTR_STAT      0x218
+#define PL310_RAW_INTR_STAT         0x21C
+#define PL310_INTR_CLEAR            0x220
+#define PL310_CACHE_SYNC            0x730
+#define PL310_INV_LINE_PA           0x770
+#define PL310_INV_WAY               0x77C
+#define PL310_CLEAN_LINE_PA         0x7B0
+#define PL310_CLEAN_LINE_IDX        0x7B8
+#define PL310_CLEAN_WAY             0x7BC
+#define PL310_CLEAN_INV_LINE_PA     0x7F0
+#define PL310_CLEAN_INV_LINE_IDX    0x7F8
+#define PL310_CLEAN_INV_WAY         0x7FC
+#define PL310_LOCKDOWN_D_WAY(x)    (0x900 + ((x) * 8))
+#define PL310_LOCKDOWN_I_WAY(x)    (0x904 + ((x) * 8))
+#define PL310_LOCKDOWN_LINE_ENABLE  0x950
+#define PL310_UNLOCK_ALL_LINES_WAY  0x954
+#define PL310_ADDR_FILTER_START     0xC00
+#define PL310_ADDR_FILTER_END       0xC04
+#define PL310_DEBUG_CTRL            0xF40
+
+
+#define PL310_AUX_CTRL_MASK                      0xc0000fff
+#define PL310_AUX_CTRL_ASSOCIATIVITY_SHIFT       16
+#define PL310_AUX_CTRL_WAY_SIZE_SHIFT            17
+#define PL310_AUX_CTRL_WAY_SIZE_MASK             (0x7 << 17)
+#define PL310_AUX_CTRL_SHARE_OVERRIDE_SHIFT      22
+#define PL310_AUX_CTRL_NS_LOCKDOWN_SHIFT         26
+#define PL310_AUX_CTRL_NS_INT_CTRL_SHIFT         27
+#define PL310_AUX_CTRL_DATA_PREFETCH_SHIFT       28
+#define PL310_AUX_CTRL_INSTR_PREFETCH_SHIFT      29
+#define PL310_AUX_CTRL_EARLY_BRESP_SHIFT         30
+
+
+void omap4_l2cache_wbinv_range(vm_paddr_t physaddr, vm_size_t size);
+void omap4_l2cache_inv_range(vm_paddr_t physaddr, vm_size_t size);
+void omap4_l2cache_wb_range(vm_paddr_t physaddr, vm_size_t size);
+void omap4_l2cache_wbinv_all(void);
+void omap4_l2cache_inv_all(void);
+void omap4_l2cache_wb_all(void);
+
+static uint32_t g_l2cache_way_mask;
+
+static const uint32_t g_l2cache_line_size = 32;
+static const uint32_t g_l2cache_align_mask = (32 - 1);
+
+static uint32_t g_l2cache_size;
+
+static struct pl310_softc *pl310_softc;
+
+/**
+ *	pl310_read4 - read a 32-bit value from the PL310 registers
+ *	pl310_write4 - write a 32-bit value from the PL310 registers
+ *	@off: byte offset within the register set to read from
+ *	@val: the value to write into the register
+ *	
+ *
+ *	LOCKING:
+ *	None
+ *
+ *	RETURNS:
+ *	nothing in case of write function, if read function returns the value read.
+ */
+static __inline uint32_t
+pl310_read4(bus_size_t off)
+{
+	return bus_read_4(pl310_softc->sc_mem_res, off);
+}
+static __inline void
+pl310_write4(bus_size_t off, uint32_t val)
+{
+	bus_write_4(pl310_softc->sc_mem_res, off, val);
+}
+
+static __inline void
+pl310_wait_background_op(uint32_t off, uint32_t mask)
+{
+	while (pl310_read4(off) & mask);
+}
+
+
+/**
+ *	pl310_cache_sync - performs a cache sync operation
+ * 
+ *	According to the TRM:
+ *
+ *  "Before writing to any other register you must perform an explicit
+ *   Cache Sync operation. This is particularly important when the cache is
+ *   enabled and changes to how the cache allocates new lines are to be made."
+ *
+ *
+ */
+static __inline void
+pl310_cache_sync(void)
+{
+	pl310_write4(PL310_CACHE_SYNC, 0);
+}
+
+
+static void
+pl310_wbinv_all(void)
+{
+#if 1
+	pl310_write4(PL310_DEBUG_CTRL, 3);
+#endif
+	pl310_write4(PL310_CLEAN_INV_WAY, g_l2cache_way_mask);
+	pl310_wait_background_op(PL310_CLEAN_INV_WAY, g_l2cache_way_mask);
+	pl310_cache_sync();
+#if 1
+	pl310_write4(PL310_DEBUG_CTRL, 0);
+#endif
+		
+}
+
+static void
+pl310_wbinv_range(vm_paddr_t start, vm_size_t size)
+{
+	
+	if (size & g_l2cache_align_mask) {
+		size &= ~g_l2cache_align_mask;
+		size += g_l2cache_line_size;
+	}
+#if 1
+
+	pl310_write4(PL310_DEBUG_CTRL, 3);
+#endif
+	while (size > 0) {
+#if 1
+		/* 
+		 * Errata 588369 says that clean + inv may keep the 
+		 * cache line if it was clean, the recommanded workaround
+		 * is to clean then invalidate the cache line, with
+		 * write-back and cache linefill disabled
+		 */
+		   
+		pl310_write4(PL310_CLEAN_LINE_PA, start);
+		pl310_write4(PL310_INV_LINE_PA, start);
+#else
+		pl310_write4(PL310_CLEAN_INV_LINE_PA, start);
+#endif
+		start += g_l2cache_line_size;
+		size -= g_l2cache_line_size;
+	}
+#if 1
+	pl310_write4(PL310_DEBUG_CTRL, 0);
+#endif
+	pl310_wait_background_op(PL310_CLEAN_INV_LINE_PA, 1);
+	pl310_cache_sync();
+		
+}
+
+static void
+pl310_wb_range(vm_paddr_t start, vm_size_t size)
+{
+	
+	if (size & g_l2cache_align_mask) {
+		size &= ~g_l2cache_align_mask;
+		size += g_l2cache_line_size;
+	}
+	while (size > 0) {
+		pl310_write4(PL310_CLEAN_LINE_PA, start);
+		start += g_l2cache_line_size;
+		size -= g_l2cache_line_size;
+	}
+	pl310_cache_sync();
+	pl310_wait_background_op(PL310_CLEAN_LINE_PA, 1);
+
+}
+
+static void
+pl310_inv_range(vm_paddr_t start, vm_size_t size)
+{
+
+	if (size & g_l2cache_align_mask) {
+		size &= ~g_l2cache_align_mask;
+		size += g_l2cache_line_size;
+	}
+	while (size > 0) {
+		pl310_write4(PL310_INV_LINE_PA, start);
+		start += g_l2cache_line_size;
+		size -= g_l2cache_line_size;
+	}
+	pl310_cache_sync();
+	pl310_wait_background_op(PL310_INV_LINE_PA, 1);
+
+}
+
+static int
+pl310_probe(device_t dev)
+{
+	
+	if (!ofw_bus_is_compatible(dev, "arm,pl310"))
+		return (ENXIO);
+	device_set_desc(dev, "PL310 L2 cache controller");
+	return (0);
+}
+
+static int
+pl310_attach(device_t dev)
+{
+	struct pl310_softc *sc = device_get_softc(dev);
+	int rid = 0;
+	uint32_t aux_value;
+	uint32_t way_size;
+	uint32_t ways_assoc;
+	uint32_t ctrl_value;
+
+	sc->sc_mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, 
+	    RF_ACTIVE);
+	if (sc->sc_mem_res == NULL)
+		panic("%s: Cannot map registers", device_get_name(dev));
+	pl310_softc = sc;
+
+	platform_init_pl310(sc);
+	aux_value = pl310_read4(PL310_AUX_CTRL);
+	way_size = (aux_value & PL310_AUX_CTRL_WAY_SIZE_MASK) >>
+	    PL310_AUX_CTRL_WAY_SIZE_SHIFT;
+	way_size = 1 << (way_size + 13);
+	if (aux_value & (1 << PL310_AUX_CTRL_ASSOCIATIVITY_SHIFT))
+		ways_assoc = 16;
+	else
+		ways_assoc = 8;
+	g_l2cache_way_mask = (1 << ways_assoc) - 1;
+	g_l2cache_size = way_size * ways_assoc;
+	/* Print the information */
+	printf("  L2 Cache: %uKB/%dB %d ways\n", (g_l2cache_size / 1024),
+	       g_l2cache_line_size, ways_assoc);
+	ctrl_value = pl310_read4(PL310_CTRL);
+	if (!(ctrl_value & 0x1)) {
+		/* Enable the L2 cache if disabled */
+		pl310_write4(PL310_CTRL, ctrl_value & 0x1);
+	}
+	pl310_wbinv_all();
+	
+	/* Set the l2 functions in the set of cpufuncs */
+	cpufuncs.cf_l2cache_wbinv_all = pl310_wbinv_all;
+	cpufuncs.cf_l2cache_wbinv_range = pl310_wbinv_range;
+	cpufuncs.cf_l2cache_inv_range = pl310_inv_range;
+	cpufuncs.cf_l2cache_wb_range = pl310_wb_range;
+	return (0);
+}
+
+static device_method_t pl310_methods[] = {
+	DEVMETHOD(device_probe, pl310_probe),
+	DEVMETHOD(device_attach, pl310_attach),
+	{0, 0},
+};
+
+static driver_t pl310_driver = {
+        "l2cache",
+        pl310_methods,
+        sizeof(struct pl310_softc),
+};
+static devclass_t pl310_devclass;
+
+DRIVER_MODULE(pl310, simplebus, pl310_driver, pl310_devclass, 0, 0);
+
diff -r 7fffa673adcd -r a301a330526b head/sys/arm/arm/pmap-v6.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/head/sys/arm/arm/pmap-v6.c	Wed Aug 15 11:16:36 2012 +0300
@@ -0,0 +1,3780 @@
+/* From: $NetBSD: pmap.c,v 1.148 2004/04/03 04:35:48 bsh Exp $ */
+/*-
+ * Copyright 2011 Semihalf
+ * Copyright 2004 Olivier Houchard.
+ * Copyright 2003 Wasabi Systems, Inc.
+ * All rights reserved.
+ *
+ * Written by Steve C. Woodford for Wasabi Systems, Inc.
+ *
+ * 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 for the NetBSD Project by
+ *      Wasabi Systems, Inc.
+ * 4. The name of Wasabi Systems, Inc. may not be used to endorse
+ *    or promote products derived from this software without specific prior
+ *    written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``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 WASABI SYSTEMS, INC
+ * 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.
+ *
+ * From: FreeBSD: src/sys/arm/arm/pmap.c,v 1.113 2009/07/24 13:50:29
+ */
+
+/*-
+ * Copyright (c) 2002-2003 Wasabi Systems, Inc.
+ * Copyright (c) 2001 Richard Earnshaw
+ * Copyright (c) 2001-2002 Christopher Gilbert
+ * All rights reserved.
+ *
+ * 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. 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 THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR 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.
+ */
+/*-
+ * Copyright (c) 1999 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Charles M. Hannum.
+ *
+ * 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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.
+ */
+
+/*-
+ * 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 Mark Brinicombe.
+ * 4. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ *
+ * RiscBSD kernel project
+ *
+ * pmap.c
+ *
+ * Machine dependant vm stuff
+ *
+ * Created      : 20/09/94
+ */
+
+/*
+ * Special compilation symbols
+ * PMAP_DEBUG           - Build in pmap_debug_level code
+ */
+/* Include header files */
+
+#include "opt_vm.h"
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: head/sys/arm/arm/pmap-v6.c 239268 2012-08-15 03:03:03Z gonzo $");
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/ktr.h>
+#include <sys/proc.h>
+#include <sys/malloc.h>
+#include <sys/msgbuf.h>
+#include <sys/vmmeter.h>
+#include <sys/mman.h>
+#include <sys/smp.h>
+#include <sys/sched.h>
+
+#include <vm/vm.h>
+#include <vm/uma.h>
+#include <vm/pmap.h>
+#include <vm/vm_kern.h>
+#include <vm/vm_object.h>
+#include <vm/vm_map.h>
+#include <vm/vm_page.h>
+#include <vm/vm_pageout.h>
+#include <vm/vm_param.h>
+#include <vm/vm_extern.h>
+#include <sys/lock.h>
+#include <sys/mutex.h>
+#include <machine/md_var.h>
+#include <machine/vmparam.h>
+#include <machine/cpu.h>
+#include <machine/cpufunc.h>
+#include <machine/pcb.h>
+
+#ifdef PMAP_DEBUG
+#define PDEBUG(_lev_,_stat_) \
+        if (pmap_debug_level >= (_lev_)) \
+                ((_stat_))
+#define dprintf printf
+
+int pmap_debug_level = 0;
+#define PMAP_INLINE
+#else   /* PMAP_DEBUG */
+#define PDEBUG(_lev_,_stat_) /* Nothing */
+#define dprintf(x, arg...)
+#define PMAP_INLINE __inline
+#endif  /* PMAP_DEBUG */
+
+extern struct pv_addr systempage;
+
+/*
+ * Internal function prototypes
+ */
+static void pmap_free_pv_entry (pv_entry_t);
+static pv_entry_t pmap_get_pv_entry(void);
+
+static void		pmap_enter_locked(pmap_t, vm_offset_t, vm_page_t,
+    vm_prot_t, boolean_t, int);
+static void		pmap_alloc_l1(pmap_t);
+static void		pmap_free_l1(pmap_t);
+
+static int		pmap_clearbit(struct vm_page *, u_int);
+
+static struct l2_bucket *pmap_get_l2_bucket(pmap_t, vm_offset_t);
+static struct l2_bucket *pmap_alloc_l2_bucket(pmap_t, vm_offset_t);
+static void		pmap_free_l2_bucket(pmap_t, struct l2_bucket *, u_int);
+static vm_offset_t	kernel_pt_lookup(vm_paddr_t);
+
+static MALLOC_DEFINE(M_VMPMAP, "pmap", "PMAP L1");
+
+vm_offset_t virtual_avail;	/* VA of first avail page (after kernel bss) */
+vm_offset_t virtual_end;	/* VA of last avail page (end of kernel AS) */
+vm_offset_t pmap_curmaxkvaddr;
+vm_paddr_t kernel_l1pa;
+
+extern void *end;
+vm_offset_t kernel_vm_end = 0;
+
+struct pmap kernel_pmap_store;
+
+static pt_entry_t *csrc_pte, *cdst_pte;
+static vm_offset_t csrcp, cdstp;
+static struct mtx cmtx;
+
+static void		pmap_init_l1(struct l1_ttable *, pd_entry_t *);
+/*
+ * These routines are called when the CPU type is identified to set up
+ * the PTE prototypes, cache modes, etc.
+ *
+ * The variables are always here, just in case LKMs need to reference
+ * them (though, they shouldn't).
+ */
+static void pmap_set_prot(pt_entry_t *pte, vm_prot_t prot, uint8_t user);
+pt_entry_t	pte_l1_s_cache_mode;
+pt_entry_t	pte_l1_s_cache_mode_pt;
+
+pt_entry_t	pte_l2_l_cache_mode;
+pt_entry_t	pte_l2_l_cache_mode_pt;
+
+pt_entry_t	pte_l2_s_cache_mode;
+pt_entry_t	pte_l2_s_cache_mode_pt;
+
+/*
+ * Which pmap is currently 'live' in the cache
+ *
+ * XXXSCW: Fix for SMP ...
+ */
+union pmap_cache_state *pmap_cache_state;
+
+struct msgbuf *msgbufp = 0;
+
+/*
+ * Crashdump maps.
+ */
+static caddr_t crashdumpmap;
+
+extern void bcopy_page(vm_offset_t, vm_offset_t);
+extern void bzero_page(vm_offset_t);
+
+extern vm_offset_t alloc_firstaddr;
+
+char *_tmppt;
+
+/*
+ * Metadata for L1 translation tables.
+ */
+struct l1_ttable {
+	/* Entry on the L1 Table list */
+	SLIST_ENTRY(l1_ttable) l1_link;
+
+	/* Entry on the L1 Least Recently Used list */
+	TAILQ_ENTRY(l1_ttable) l1_lru;
+
+	/* Track how many domains are allocated from this L1 */
+	volatile u_int l1_domain_use_count;
+
+	/*
+	 * A free-list of domain numbers for this L1.
+	 * We avoid using ffs() and a bitmap to track domains since ffs()
+	 * is slow on ARM.
+	 */
+	u_int8_t l1_domain_first;
+	u_int8_t l1_domain_free[PMAP_DOMAINS];
+
+	/* Physical address of this L1 page table */
+	vm_paddr_t l1_physaddr;
+
+	/* KVA of this L1 page table */
+	pd_entry_t *l1_kva;
+};
+
+/*
+ * Convert a virtual address into its L1 table index. That is, the
+ * index used to locate the L2 descriptor table pointer in an L1 table.
+ * This is basically used to index l1->l1_kva[].
+ *
+ * Each L2 descriptor table represents 1MB of VA space.
+ */
+#define	L1_IDX(va)		(((vm_offset_t)(va)) >> L1_S_SHIFT)
+
+/*
+ * L1 Page Tables are tracked using a Least Recently Used list.
+ *  - New L1s are allocated from the HEAD.
+ *  - Freed L1s are added to the TAIl.
+ *  - Recently accessed L1s (where an 'access' is some change to one of
+ *    the userland pmaps which owns this L1) are moved to the TAIL.
+ */
+static TAILQ_HEAD(, l1_ttable) l1_lru_list;
+/*
+ * A list of all L1 tables
+ */
+static SLIST_HEAD(, l1_ttable) l1_list;
+static struct mtx l1_lru_lock;
+
+/*
+ * The l2_dtable tracks L2_BUCKET_SIZE worth of L1 slots.
+ *
+ * This is normally 16MB worth L2 page descriptors for any given pmap.
+ * Reference counts are maintained for L2 descriptors so they can be
+ * freed when empty.
+ */
+struct l2_dtable {
+	/* The number of L2 page descriptors allocated to this l2_dtable */
+	u_int l2_occupancy;
+
+	/* List of L2 page descriptors */
+	struct l2_bucket {
+		pt_entry_t *l2b_kva;	/* KVA of L2 Descriptor Table */
+		vm_paddr_t l2b_phys;	/* Physical address of same */
+		u_short l2b_l1idx;	/* This L2 table's L1 index */
+		u_short l2b_occupancy;	/* How many active descriptors */
+	} l2_bucket[L2_BUCKET_SIZE];
+};
+
+/* pmap_kenter_internal flags */
+#define KENTER_CACHE	0x1
+#define KENTER_USER	0x2
+
+/*
+ * Given an L1 table index, calculate the corresponding l2_dtable index
+ * and bucket index within the l2_dtable.
+ */
+#define	L2_IDX(l1idx)		(((l1idx) >> L2_BUCKET_LOG2) & \
+				 (L2_SIZE - 1))
+#define	L2_BUCKET(l1idx)	((l1idx) & (L2_BUCKET_SIZE - 1))
+
+/*
+ * Given a virtual address, this macro returns the
+ * virtual address required to drop into the next L2 bucket.
+ */
+#define	L2_NEXT_BUCKET(va)	(((va) & L1_S_FRAME) + L1_S_SIZE)
+
+/*
+ * L2 allocation.
+ */
+#define	pmap_alloc_l2_dtable()		\
+		(void*)uma_zalloc(l2table_zone, M_NOWAIT|M_USE_RESERVE)
+#define	pmap_free_l2_dtable(l2)		\
+		uma_zfree(l2table_zone, l2)
+
+/*
+ * We try to map the page tables write-through, if possible.  However, not
+ * all CPUs have a write-through cache mode, so on those we have to sync
+ * the cache when we frob page tables.
+ *
+ * We try to evaluate this at compile time, if possible.  However, it's
+ * not always possible to do that, hence this run-time var.
+ */
+int	pmap_needs_pte_sync;
+
+/*
+ * Macro to determine if a mapping might be resident in the
+ * instruction cache and/or TLB
+ */
+#define	PV_BEEN_EXECD(f)  (((f) & (PVF_REF | PVF_EXEC)) == (PVF_REF | PVF_EXEC))
+
+/*
+ * Macro to determine if a mapping might be resident in the
+ * data cache and/or TLB
+ */
+#define	PV_BEEN_REFD(f)   (((f) & PVF_REF) != 0)
+
+#ifndef PMAP_SHPGPERPROC
+#define PMAP_SHPGPERPROC 200
+#endif
+
+#define pmap_is_current(pm)	((pm) == pmap_kernel() || \
+            curproc->p_vmspace->vm_map.pmap == (pm))
+static uma_zone_t pvzone = NULL;
+uma_zone_t l2zone;
+static uma_zone_t l2table_zone;
+static vm_offset_t pmap_kernel_l2dtable_kva;
+static vm_offset_t pmap_kernel_l2ptp_kva;
+static vm_paddr_t pmap_kernel_l2ptp_phys;
+static struct vm_object pvzone_obj;
+static int pv_entry_count=0, pv_entry_max=0, pv_entry_high_water=0;
+
+int l1_mem_types[] = {
+	ARM_L1S_STRONG_ORD,
+	ARM_L1S_DEVICE_NOSHARE,
+	ARM_L1S_DEVICE_SHARE,
+	ARM_L1S_NRML_NOCACHE,
+	ARM_L1S_NRML_IWT_OWT,
+	ARM_L1S_NRML_IWB_OWB,
+	ARM_L1S_NRML_IWBA_OWBA
+};
+
+int l2l_mem_types[] = {
+	ARM_L2L_STRONG_ORD,
+	ARM_L2L_DEVICE_NOSHARE,
+	ARM_L2L_DEVICE_SHARE,
+	ARM_L2L_NRML_NOCACHE,
+	ARM_L2L_NRML_IWT_OWT,
+	ARM_L2L_NRML_IWB_OWB,
+	ARM_L2L_NRML_IWBA_OWBA
+};
+
+int l2s_mem_types[] = {
+	ARM_L2S_STRONG_ORD,
+	ARM_L2S_DEVICE_NOSHARE,
+	ARM_L2S_DEVICE_SHARE,
+	ARM_L2S_NRML_NOCACHE,
+	ARM_L2S_NRML_IWT_OWT,
+	ARM_L2S_NRML_IWB_OWB,
+	ARM_L2S_NRML_IWBA_OWBA
+};
+
+/*
+ * This list exists for the benefit of pmap_map_chunk().  It keeps track
+ * of the kernel L2 tables during bootstrap, so that pmap_map_chunk() can
+ * find them as necessary.
+ *
+ * Note that the data on this list MUST remain valid after initarm() returns,
+ * as pmap_bootstrap() uses it to contruct L2 table metadata.
+ */
+SLIST_HEAD(, pv_addr) kernel_pt_list = SLIST_HEAD_INITIALIZER(kernel_pt_list);
+
+static void
+pmap_init_l1(struct l1_ttable *l1, pd_entry_t *l1pt)
+{
+	int i;
+
+	l1->l1_kva = l1pt;
+	l1->l1_domain_use_count = 0;
+	l1->l1_domain_first = 0;
+
+	for (i = 0; i < PMAP_DOMAINS; i++)
+		l1->l1_domain_free[i] = i + 1;
+
+	/*
+	 * Copy the kernel's L1 entries to each new L1.
+	 */
+	if (l1pt != pmap_kernel()->pm_l1->l1_kva)
+		memcpy(l1pt, pmap_kernel()->pm_l1->l1_kva, L1_TABLE_SIZE);
+
+	if ((l1->l1_physaddr = pmap_extract(pmap_kernel(), (vm_offset_t)l1pt)) == 0)
+		panic("pmap_init_l1: can't get PA of L1 at %p", l1pt);
+	SLIST_INSERT_HEAD(&l1_list, l1, l1_link);
+	TAILQ_INSERT_TAIL(&l1_lru_list, l1, l1_lru);
+}
+
+static vm_offset_t
+kernel_pt_lookup(vm_paddr_t pa)
+{
+	struct pv_addr *pv;
+
+	SLIST_FOREACH(pv, &kernel_pt_list, pv_list) {
+		if (pv->pv_pa == pa)
+			return (pv->pv_va);
+	}
+	return (0);
+}
+
+void
+pmap_pte_init_mmu_v6(void)
+{
+
+	if (PTE_PAGETABLE >= 3)
+		pmap_needs_pte_sync = 1;
+	pte_l1_s_cache_mode = l1_mem_types[PTE_CACHE];
+	pte_l2_l_cache_mode = l2l_mem_types[PTE_CACHE];
+	pte_l2_s_cache_mode = l2s_mem_types[PTE_CACHE];
+
+	pte_l1_s_cache_mode_pt = l1_mem_types[PTE_PAGETABLE];
+	pte_l2_l_cache_mode_pt = l2l_mem_types[PTE_PAGETABLE];
+	pte_l2_s_cache_mode_pt = l2s_mem_types[PTE_PAGETABLE];
+
+}
+
+/*
+ * Allocate an L1 translation table for the specified pmap.
+ * This is called at pmap creation time.
+ */
+static void
+pmap_alloc_l1(pmap_t pm)
+{
+	struct l1_ttable *l1;
+	u_int8_t domain;
+
+	/*
+	 * Remove the L1 at the head of the LRU list
+	 */
+	mtx_lock(&l1_lru_lock);
+	l1 = TAILQ_FIRST(&l1_lru_list);
+	TAILQ_REMOVE(&l1_lru_list, l1, l1_lru);
+
+	/*
+	 * Pick the first available domain number, and update
+	 * the link to the next number.
+	 */
+	domain = l1->l1_domain_first;
+	l1->l1_domain_first = l1->l1_domain_free[domain];
+
+	/*
+	 * If there are still free domain numbers in this L1,
+	 * put it back on the TAIL of the LRU list.
+	 */
+	if (++l1->l1_domain_use_count < PMAP_DOMAINS)
+		TAILQ_INSERT_TAIL(&l1_lru_list, l1, l1_lru);
+
+	mtx_unlock(&l1_lru_lock);
+
+	/*
+	 * Fix up the relevant bits in the pmap structure
+	 */
+	pm->pm_l1 = l1;
+	pm->pm_domain = domain + 1;
+}
+
+/*
+ * Free an L1 translation table.
+ * This is called at pmap destruction time.
+ */
+static void
+pmap_free_l1(pmap_t pm)
+{
+	struct l1_ttable *l1 = pm->pm_l1;
+
+	mtx_lock(&l1_lru_lock);
+
+	/*
+	 * If this L1 is currently on the LRU list, remove it.
+	 */
+	if (l1->l1_domain_use_count < PMAP_DOMAINS)
+		TAILQ_REMOVE(&l1_lru_list, l1, l1_lru);
+
+	/*
+	 * Free up the domain number which was allocated to the pmap
+	 */
+	l1->l1_domain_free[pm->pm_domain - 1] = l1->l1_domain_first;
+	l1->l1_domain_first = pm->pm_domain - 1;
+	l1->l1_domain_use_count--;
+
+	/*
+	 * The L1 now must have at least 1 free domain, so add
+	 * it back to the LRU list. If the use count is zero,
+	 * put it at the head of the list, otherwise it goes
+	 * to the tail.
+	 */
+	if (l1->l1_domain_use_count == 0) {
+		TAILQ_INSERT_HEAD(&l1_lru_list, l1, l1_lru);
+	}	else
+		TAILQ_INSERT_TAIL(&l1_lru_list, l1, l1_lru);
+
+	mtx_unlock(&l1_lru_lock);
+}
+
+/*
+ * Returns a pointer to the L2 bucket associated with the specified pmap
+ * and VA, or NULL if no L2 bucket exists for the address.
+ */
+static PMAP_INLINE struct l2_bucket *
+pmap_get_l2_bucket(pmap_t pm, vm_offset_t va)
+{
+	struct l2_dtable *l2;
+	struct l2_bucket *l2b;
+	u_short l1idx;
+
+	l1idx = L1_IDX(va);
+
+	if ((l2 = pm->pm_l2[L2_IDX(l1idx)]) == NULL ||
+	    (l2b = &l2->l2_bucket[L2_BUCKET(l1idx)])->l2b_kva == NULL)
+		return (NULL);
+
+	return (l2b);
+}
+
+/*
+ * Returns a pointer to the L2 bucket associated with the specified pmap
+ * and VA.
+ *
+ * If no L2 bucket exists, perform the necessary allocations to put an L2
+ * bucket/page table in place.
+ *
+ * Note that if a new L2 bucket/page was allocated, the caller *must*
+ * increment the bucket occupancy counter appropriately *before*
+ * releasing the pmap's lock to ensure no other thread or cpu deallocates
+ * the bucket/page in the meantime.
+ */
+static struct l2_bucket *
+pmap_alloc_l2_bucket(pmap_t pm, vm_offset_t va)
+{
+	struct l2_dtable *l2;
+	struct l2_bucket *l2b;
+	u_short l1idx;
+
+	l1idx = L1_IDX(va);
+
+	PMAP_ASSERT_LOCKED(pm);
+	mtx_assert(&vm_page_queue_mtx, MA_OWNED);
+	if ((l2 = pm->pm_l2[L2_IDX(l1idx)]) == NULL) {
+		/*
+		 * No mapping at this address, as there is
+		 * no entry in the L1 table.
+		 * Need to allocate a new l2_dtable.
+		 */
+again_l2table:
+		PMAP_UNLOCK(pm);
+		vm_page_unlock_queues();
+		if ((l2 = pmap_alloc_l2_dtable()) == NULL) {
+			vm_page_lock_queues();
+			PMAP_LOCK(pm);
+			return (NULL);
+		}
+		vm_page_lock_queues();
+		PMAP_LOCK(pm);
+		if (pm->pm_l2[L2_IDX(l1idx)] != NULL) {
+			PMAP_UNLOCK(pm);
+			vm_page_unlock_queues();
+			uma_zfree(l2table_zone, l2);
+			vm_page_lock_queues();
+			PMAP_LOCK(pm);
+			l2 = pm->pm_l2[L2_IDX(l1idx)];
+			if (l2 == NULL)
+				goto again_l2table;
+			/*
+			 * Someone already allocated the l2_dtable while
+			 * we were doing the same.
+			 */
+		} else {
+			bzero(l2, sizeof(*l2));
+			/*
+			 * Link it into the parent pmap
+			 */
+			pm->pm_l2[L2_IDX(l1idx)] = l2;
+		}
+	}
+
+	l2b = &l2->l2_bucket[L2_BUCKET(l1idx)];
+
+	/*
+	 * Fetch pointer to the L2 page table associated with the address.
+	 */
+	if (l2b->l2b_kva == NULL) {
+		pt_entry_t *ptep;
+
+		/*
+		 * No L2 page table has been allocated. Chances are, this
+		 * is because we just allocated the l2_dtable, above.
+		 */
+again_ptep:
+		PMAP_UNLOCK(pm);
+		vm_page_unlock_queues();
+		ptep = (void*)uma_zalloc(l2zone, M_NOWAIT|M_USE_RESERVE);
+		vm_page_lock_queues();
+		PMAP_LOCK(pm);
+		if (l2b->l2b_kva != 0) {
+			/* We lost the race. */
+			PMAP_UNLOCK(pm);
+			vm_page_unlock_queues();
+			uma_zfree(l2zone, ptep);
+			vm_page_lock_queues();
+			PMAP_LOCK(pm);
+			if (l2b->l2b_kva == 0)
+				goto again_ptep;
+			return (l2b);
+		}
+		l2b->l2b_phys = vtophys(ptep);
+		if (ptep == NULL) {
+			/*
+			 * Oops, no more L2 page tables available at this
+			 * time. We may need to deallocate the l2_dtable
+			 * if we allocated a new one above.
+			 */
+			if (l2->l2_occupancy == 0) {
+				pm->pm_l2[L2_IDX(l1idx)] = NULL;
+				pmap_free_l2_dtable(l2);
+			}
+			return (NULL);
+		}
+
+		l2->l2_occupancy++;
+		l2b->l2b_kva = ptep;
+		l2b->l2b_l1idx = l1idx;
+	}
+
+	return (l2b);
+}
+
+static PMAP_INLINE void
+pmap_free_l2_ptp(pt_entry_t *l2)
+{
+	uma_zfree(l2zone, l2);
+}
+/*
+ * One or more mappings in the specified L2 descriptor table have just been
+ * invalidated.
+ *
+ * Garbage collect the metadata and descriptor table itself if necessary.
+ *
+ * The pmap lock must be acquired when this is called (not necessary
+ * for the kernel pmap).
+ */
+static void
+pmap_free_l2_bucket(pmap_t pm, struct l2_bucket *l2b, u_int count)
+{
+	struct l2_dtable *l2;
+	pd_entry_t *pl1pd, l1pd;
+	pt_entry_t *ptep;
+	u_short l1idx;
+
+
+	/*
+	 * Update the bucket's reference count according to how many
+	 * PTEs the caller has just invalidated.
+	 */
+	l2b->l2b_occupancy -= count;
+
+	/*
+	 * Note:
+	 *
+	 * Level 2 page tables allocated to the kernel pmap are never freed
+	 * as that would require checking all Level 1 page tables and
+	 * removing any references to the Level 2 page table. See also the
+	 * comment elsewhere about never freeing bootstrap L2 descriptors.
+	 *
+	 * We make do with just invalidating the mapping in the L2 table.
+	 *
+	 * This isn't really a big deal in practice and, in fact, leads
+	 * to a performance win over time as we don't need to continually
+	 * alloc/free.
+	 */
+	if (l2b->l2b_occupancy > 0 || pm == pmap_kernel())
+		return;
+
+	/*
+	 * There are no more valid mappings in this level 2 page table.
+	 * Go ahead and NULL-out the pointer in the bucket, then
+	 * free the page table.
+	 */
+	l1idx = l2b->l2b_l1idx;
+	ptep = l2b->l2b_kva;
+	l2b->l2b_kva = NULL;
+
+	pl1pd = &pm->pm_l1->l1_kva[l1idx];
+
+	/*
+	 * If the L1 slot matches the pmap's domain
+	 * number, then invalidate it.
+	 */
+	l1pd = *pl1pd & (L1_TYPE_MASK | L1_C_DOM_MASK);
+	if (l1pd == (L1_C_DOM(pm->pm_domain) | L1_TYPE_C)) {
+		*pl1pd = 0;
+		PTE_SYNC(pl1pd);
+	}
+
+	/*
+	 * Release the L2 descriptor table back to the pool cache.
+	 */
+	pmap_free_l2_ptp(ptep);
+
+	/*
+	 * Update the reference count in the associated l2_dtable
+	 */
+	l2 = pm->pm_l2[L2_IDX(l1idx)];
+	if (--l2->l2_occupancy > 0)
+		return;
+
+	/*
+	 * There are no more valid mappings in any of the Level 1
+	 * slots managed by this l2_dtable. Go ahead and NULL-out
+	 * the pointer in the parent pmap and free the l2_dtable.
+	 */
+	pm->pm_l2[L2_IDX(l1idx)] = NULL;
+	pmap_free_l2_dtable(l2);
+}
+
+/*
+ * Pool cache constructors for L2 descriptor tables, metadata and pmap
+ * structures.
+ */
+static int
+pmap_l2ptp_ctor(void *mem, int size, void *arg, int flags)
+{
+	struct l2_bucket *l2b;
+	pt_entry_t *ptep, pte;
+	vm_offset_t va = (vm_offset_t)mem & ~PAGE_MASK;
+
+	/*
+	 * The mappings for these page tables were initially made using
+	 * pmap_kenter() by the pool subsystem. Therefore, the cache-
+	 * mode will not be right for page table mappings. To avoid
+	 * polluting the pmap_kenter() code with a special case for
+	 * page tables, we simply fix up the cache-mode here if it's not
+	 * correct.
+	 */
+	l2b = pmap_get_l2_bucket(pmap_kernel(), va);
+	ptep = &l2b->l2b_kva[l2pte_index(va)];
+	pte = *ptep;
+
+	cpu_idcache_wbinv_range(va, PAGE_SIZE);
+#ifdef ARM_L2_PIPT
+	cpu_l2cache_wbinv_range(pte & L2_S_FRAME, PAGE_SIZE);
+#else
+	cpu_l2cache_wbinv_range(va, PAGE_SIZE);
+#endif
+	if ((pte & L2_S_CACHE_MASK) != pte_l2_s_cache_mode_pt) {
+		/*
+		 * Page tables must have the cache-mode set to
+		 * Write-Thru.
+		 */
+		*ptep = (pte & ~L2_S_CACHE_MASK) | pte_l2_s_cache_mode_pt;
+		PTE_SYNC(ptep);
+		cpu_tlb_flushD_SE(va);
+		cpu_cpwait();
+	}
+
+	memset(mem, 0, L2_TABLE_SIZE_REAL);
+	return (0);
+}
+
+/*
+ * Modify pte bits for all ptes corresponding to the given physical address.
+ * We use `maskbits' rather than `clearbits' because we're always passing
+ * constants and the latter would require an extra inversion at run-time.
+ */
+static int
+pmap_clearbit(struct vm_page *pg, u_int maskbits)
+{
+	struct l2_bucket *l2b;
+	struct pv_entry *pv;
+	pt_entry_t *ptep, npte, opte;
+	pmap_t pm;
+	vm_offset_t va;
+	u_int oflags;
+	int count = 0;
+
+	vm_page_lock_queues();
+
+	if (maskbits & PVF_WRITE)
+		maskbits |= PVF_MOD;
+	/*
+	 * Clear saved attributes (modify, reference)
+	 */
+	pg->md.pvh_attrs &= ~(maskbits & (PVF_MOD | PVF_REF));
+
+	if (TAILQ_EMPTY(&pg->md.pv_list)) {
+		vm_page_unlock_queues();
+		return (0);
+	}
+
+	/*
+	 * Loop over all current mappings setting/clearing as appropos
+	 */
+	TAILQ_FOREACH(pv, &pg->md.pv_list, pv_list) {
+		va = pv->pv_va;
+		pm = pv->pv_pmap;
+		oflags = pv->pv_flags;
+		pv->pv_flags &= ~maskbits;
+
+		PMAP_LOCK(pm);
+
+		l2b = pmap_get_l2_bucket(pm, va);
+
+		ptep = &l2b->l2b_kva[l2pte_index(va)];
+		npte = opte = *ptep;
+
+		if ((maskbits & (PVF_WRITE|PVF_MOD)) && L2_S_WRITABLE(opte)) {
+			vm_page_dirty(pg);
+
+			/* make the pte read only */
+			npte |= L2_APX;
+		}
+
+		if (maskbits & PVF_REF) {
+			/*
+			 * Make the PTE invalid so that we will take a
+			 * page fault the next time the mapping is
+			 * referenced.
+			 */
+			npte &= ~L2_TYPE_MASK;
+			npte |= L2_TYPE_INV;
+		}
+
+		CTR4(KTR_PMAP,"clearbit: pmap:%p bits:%x pte:%x->%x",
+		    pm, maskbits, opte, npte);
+		if (npte != opte) {
+			count++;
+			*ptep = npte;
+			PTE_SYNC(ptep);
+			/* Flush the TLB entry if a current pmap. */
+			if (PV_BEEN_EXECD(oflags))
+				cpu_tlb_flushID_SE(pv->pv_va);
+			else if (PV_BEEN_REFD(oflags))
+				cpu_tlb_flushD_SE(pv->pv_va);
+		}
+
+		PMAP_UNLOCK(pm);
+
+	}
+
+	if (maskbits & PVF_WRITE)
+		vm_page_aflag_clear(pg, PGA_WRITEABLE);
+	vm_page_unlock_queues();
+	return (count);
+}
+
+/*
+ * main pv_entry manipulation functions:
+ *   pmap_enter_pv: enter a mapping onto a vm_page list
+ *   pmap_remove_pv: remove a mappiing from a vm_page list
+ *
+ * NOTE: pmap_enter_pv expects to lock the pvh itself
+ *       pmap_remove_pv expects te caller to lock the pvh before calling
+ */
+
+/*
+ * pmap_enter_pv: enter a mapping onto a vm_page lst
+ *
+ * => caller should hold the proper lock on pmap_main_lock
+ * => caller should have pmap locked
+ * => we will gain the lock on the vm_page and allocate the new pv_entry
+ * => caller should adjust ptp's wire_count before calling
+ * => caller should not adjust pmap's wire_count
+ */
+static void
+pmap_enter_pv(struct vm_page *pg, struct pv_entry *pve, pmap_t pm,
+    vm_offset_t va, u_int flags)
+{
+
+	mtx_assert(&vm_page_queue_mtx, MA_OWNED);
+
+	PMAP_ASSERT_LOCKED(pm);
+	pve->pv_pmap = pm;
+	pve->pv_va = va;
+	pve->pv_flags = flags;
+
+	TAILQ_INSERT_HEAD(&pg->md.pv_list, pve, pv_list);
+	TAILQ_INSERT_HEAD(&pm->pm_pvlist, pve, pv_plist);
+	pg->md.pvh_attrs |= flags & (PVF_REF | PVF_MOD);
+	if (pve->pv_flags & PVF_WIRED)
+		++pm->pm_stats.wired_count;
+	vm_page_aflag_set(pg, PGA_REFERENCED);
+}
+
+/*
+ *
+ * pmap_find_pv: Find a pv entry
+ *
+ * => caller should hold lock on vm_page
+ */
+static PMAP_INLINE struct pv_entry *
+pmap_find_pv(struct vm_page *pg, pmap_t pm, vm_offset_t va)
+{
+	struct pv_entry *pv;
+
+	mtx_assert(&vm_page_queue_mtx, MA_OWNED);
+	TAILQ_FOREACH(pv, &pg->md.pv_list, pv_list)
+	    if (pm == pv->pv_pmap && va == pv->pv_va)
+		    break;
+	return (pv);
+}
+
+/*
+ * vector_page_setprot:
+ *
+ *	Manipulate the protection of the vector page.
+ */
+void
+vector_page_setprot(int prot)
+{
+	struct l2_bucket *l2b;
+	pt_entry_t *ptep;
+
+	l2b = pmap_get_l2_bucket(pmap_kernel(), vector_page);
+
+	ptep = &l2b->l2b_kva[l2pte_index(vector_page)];
+
+	pmap_set_prot(ptep, prot|VM_PROT_EXECUTE, 0);
+
+	cpu_tlb_flushD_SE(vector_page);
+	cpu_cpwait();
+}
+
+static void
+pmap_set_prot(pt_entry_t *ptep, vm_prot_t prot, uint8_t user)
+{
+
+	*ptep &= ~L2_S_PROT_MASK;
+
+	if (!(prot & VM_PROT_EXECUTE))
+		*ptep |= L2_XN;
+
+	*ptep |= L2_S_PROT_R;
+
+	if (user)
+		*ptep |= L2_S_PROT_U;
+
+	if (prot & VM_PROT_WRITE)
+		*ptep &= ~(L2_APX);
+}
+
+/*
+ * pmap_remove_pv: try to remove a mapping from a pv_list
+ *
+ * => caller should hold proper lock on pmap_main_lock
+ * => pmap should be locked
+ * => caller should hold lock on vm_page [so that attrs can be adjusted]
+ * => caller should adjust ptp's wire_count and free PTP if needed
+ * => caller should NOT adjust pmap's wire_count
+ * => we return the removed pve
+ */
+
+static void
+pmap_nuke_pv(struct vm_page *pg, pmap_t pm, struct pv_entry *pve)
+{
+
+	mtx_assert(&vm_page_queue_mtx, MA_OWNED);
+	PMAP_ASSERT_LOCKED(pm);
+
+	TAILQ_REMOVE(&pg->md.pv_list, pve, pv_list);
+	TAILQ_REMOVE(&pm->pm_pvlist, pve, pv_plist);
+
+	if (pve->pv_flags & PVF_WIRED)
+		--pm->pm_stats.wired_count;
+
+	if (pg->md.pvh_attrs & PVF_MOD)
+		vm_page_dirty(pg);
+
+	if (TAILQ_FIRST(&pg->md.pv_list) == NULL)
+		pg->md.pvh_attrs &= ~PVF_REF;
+	else
+		vm_page_aflag_set(pg, PGA_REFERENCED);
+
+	if (pve->pv_flags & PVF_WRITE) {
+		TAILQ_FOREACH(pve, &pg->md.pv_list, pv_list)
+		    if (pve->pv_flags & PVF_WRITE)
+			    break;
+		if (!pve) {
+			pg->md.pvh_attrs &= ~PVF_MOD;
+			vm_page_aflag_clear(pg, PGA_WRITEABLE);
+		}
+	}
+}
+
+static struct pv_entry *
+pmap_remove_pv(struct vm_page *pg, pmap_t pm, vm_offset_t va)
+{
+	struct pv_entry *pve;
+
+	mtx_assert(&vm_page_queue_mtx, MA_OWNED);
+	pve = TAILQ_FIRST(&pg->md.pv_list);
+
+	while (pve) {
+		if (pve->pv_pmap == pm && pve->pv_va == va) {	/* match? */
+			pmap_nuke_pv(pg, pm, pve);
+			break;
+		}
+		pve = TAILQ_NEXT(pve, pv_list);
+	}
+
+	return(pve);				/* return removed pve */
+}
+
+/*
+ *
+ * pmap_modify_pv: Update pv flags
+ *
+ * => caller should hold lock on vm_page [so that attrs can be adjusted]
+ * => caller should NOT adjust pmap's wire_count
+ * => we return the old flags
+ *
+ * Modify a physical-virtual mapping in the pv table
+ */
+static u_int
+pmap_modify_pv(struct vm_page *pg, pmap_t pm, vm_offset_t va,
+    u_int clr_mask, u_int set_mask)
+{
+	struct pv_entry *npv;
+	u_int flags, oflags;
+
+	PMAP_ASSERT_LOCKED(pm);
+	mtx_assert(&vm_page_queue_mtx, MA_OWNED);
+	if ((npv = pmap_find_pv(pg, pm, va)) == NULL)
+		return (0);
+
+	/*
+	 * There is at least one VA mapping this page.
+	 */
+
+	if (clr_mask & (PVF_REF | PVF_MOD))
+		pg->md.pvh_attrs |= set_mask & (PVF_REF | PVF_MOD);
+
+	oflags = npv->pv_flags;
+	npv->pv_flags = flags = (oflags & ~clr_mask) | set_mask;
+
+	if ((flags ^ oflags) & PVF_WIRED) {
+		if (flags & PVF_WIRED)
+			++pm->pm_stats.wired_count;
+		else
+			--pm->pm_stats.wired_count;
+	}
+	if ((oflags & PVF_WRITE) && !(flags & PVF_WRITE)) {
+		TAILQ_FOREACH(npv, &pg->md.pv_list, pv_list) {
+			if (npv->pv_flags & PVF_WRITE)
+				break;
+		}
+		if (!npv) {
+			pg->md.pvh_attrs &= ~PVF_MOD;
+			vm_page_aflag_clear(pg, PGA_WRITEABLE);
+		}
+	}
+
+	return (oflags);
+}
+
+/* Function to set the debug level of the pmap code */
+#ifdef PMAP_DEBUG
+void
+pmap_debug(int level)
+{
+	pmap_debug_level = level;
+	dprintf("pmap_debug: level=%d\n", pmap_debug_level);
+}
+#endif  /* PMAP_DEBUG */
+
+void
+pmap_pinit0(struct pmap *pmap)
+{
+	PDEBUG(1, printf("pmap_pinit0: pmap = %08x\n", (u_int32_t) pmap));
+
+	dprintf("pmap_pinit0: pmap = %08x, pm_pdir = %08x\n",
+		(u_int32_t) pmap, (u_int32_t) pmap->pm_pdir);
+	bcopy(kernel_pmap, pmap, sizeof(*pmap));
+	bzero(&pmap->pm_mtx, sizeof(pmap->pm_mtx));
+	PMAP_LOCK_INIT(pmap);
+}
+
+/*
+ *	Initialize a vm_page's machine-dependent fields.
+ */
+void
+pmap_page_init(vm_page_t m)
+{
+
+	TAILQ_INIT(&m->md.pv_list);
+}
+
+/*
+ *      Initialize the pmap module.
+ *      Called by vm_init, to initialize any structures that the pmap
+ *      system needs to map virtual memory.
+ */
+void
+pmap_init(void)
+{
+	int shpgperproc = PMAP_SHPGPERPROC;
+
+	PDEBUG(1, printf("pmap_init: phys_start = %08x\n", PHYSADDR));
+
+	/*
+	 * init the pv free list
+	 */
+	pvzone = uma_zcreate("PV ENTRY", sizeof (struct pv_entry), NULL, NULL,
+	    NULL, NULL, UMA_ALIGN_PTR, UMA_ZONE_VM | UMA_ZONE_NOFREE);
+	/*
+	 * Now it is safe to enable pv_table recording.
+	 */
+	PDEBUG(1, printf("pmap_init: done!\n"));
+
+	TUNABLE_INT_FETCH("vm.pmap.shpgperproc", &shpgperproc);
+
+	pv_entry_max = shpgperproc * maxproc + cnt.v_page_count;
+	pv_entry_high_water = 9 * (pv_entry_max / 10);
+	l2zone = uma_zcreate("L2 Table", L2_TABLE_SIZE_REAL, pmap_l2ptp_ctor,
+	    NULL, NULL, NULL, UMA_ALIGN_PTR, UMA_ZONE_VM | UMA_ZONE_NOFREE);
+	l2table_zone = uma_zcreate("L2 Table", sizeof(struct l2_dtable),
+	    NULL, NULL, NULL, NULL, UMA_ALIGN_PTR,
+	    UMA_ZONE_VM | UMA_ZONE_NOFREE);
+
+	uma_zone_set_obj(pvzone, &pvzone_obj, pv_entry_max);
+
+}
+
+int
+pmap_fault_fixup(pmap_t pm, vm_offset_t va, vm_prot_t ftype, int user)
+{
+	struct l2_dtable *l2;
+	struct l2_bucket *l2b;
+	pd_entry_t *pl1pd, l1pd;
+	pt_entry_t *ptep, pte;
+	vm_paddr_t pa;
+	u_int l1idx;
+	int rv = 0;
+
+	l1idx = L1_IDX(va);
+	vm_page_lock_queues();
+	PMAP_LOCK(pm);
+
+	/*
+	 * If there is no l2_dtable for this address, then the process
+	 * has no business accessing it.
+	 *
+	 * Note: This will catch userland processes trying to access
+	 * kernel addresses.
+	 */
+	l2 = pm->pm_l2[L2_IDX(l1idx)];
+	if (l2 == NULL)
+		goto out;
+
+	/*
+	 * Likewise if there is no L2 descriptor table
+	 */
+	l2b = &l2->l2_bucket[L2_BUCKET(l1idx)];
+	if (l2b->l2b_kva == NULL)
+		goto out;
+
+	/*
+	 * Check the PTE itself.
+	 */
+	ptep = &l2b->l2b_kva[l2pte_index(va)];
+	pte = *ptep;
+	if (pte == 0)
+		goto out;
+
+	/*
+	 * Catch a userland access to the vector page mapped at 0x0
+	 */
+	if (user && ((pte & L2_S_PROT_MASK) == L2_S_PROT_U))
+		goto out;
+	if (va == vector_page)
+		goto out;
+
+	pa = l2pte_pa(pte);
+	CTR5(KTR_PMAP, "pmap_fault_fix: pmap:%p va:%x pte:0x%x ftype:%x user:%x",
+	    pm, va, pte, ftype, user);
+	if ((ftype & VM_PROT_WRITE) && !(L2_S_WRITABLE(pte))) {
+		/*
+		 * This looks like a good candidate for "page modified"
+		 * emulation...
+		 */
+		struct pv_entry *pv;
+		struct vm_page *pg;
+
+		/* Extract the physical address of the page */
+		if ((pg = PHYS_TO_VM_PAGE(pa)) == NULL) {
+			goto out;
+		}
+		/* Get the current flags for this page. */
+
+		pv = pmap_find_pv(pg, pm, va);
+		if (pv == NULL) {
+			goto out;
+		}
+
+		/*
+		 * Do the flags say this page is writable? If not then it
+		 * is a genuine write fault. If yes then the write fault is
+		 * our fault as we did not reflect the write access in the
+		 * PTE. Now we know a write has occurred we can correct this
+		 * and also set the modified bit
+		 */
+		if ((pv->pv_flags & PVF_WRITE) == 0) {
+			goto out;
+		}
+		pg->md.pvh_attrs |= PVF_REF | PVF_MOD;
+		vm_page_dirty(pg);
+		pv->pv_flags |= PVF_REF | PVF_MOD;
+
+		/* Re-enable write permissions for the page */
+		*ptep = (pte & ~L2_TYPE_MASK) | L2_S_PROTO;
+		pmap_set_prot(ptep, VM_PROT_WRITE, *ptep & L2_S_PROT_U);
+		CTR1(KTR_PMAP, "pmap_fault_fix: new pte:0x%x", pte);
+		PTE_SYNC(ptep);
+		rv = 1;
+	} else if ((pte & L2_TYPE_MASK) == L2_TYPE_INV) {
+		/*
+		 * This looks like a good candidate for "page referenced"
+		 * emulation.
+		 */
+		struct pv_entry *pv;
+		struct vm_page *pg;
+
+		/* Extract the physical address of the page */
+		if ((pg = PHYS_TO_VM_PAGE(pa)) == NULL)
+			goto out;
+		/* Get the current flags for this page. */
+
+		pv = pmap_find_pv(pg, pm, va);
+		if (pv == NULL)
+			goto out;
+
+		pg->md.pvh_attrs |= PVF_REF;
+		pv->pv_flags |= PVF_REF;
+
+
+		*ptep = (pte & ~L2_TYPE_MASK) | L2_S_PROTO;
+		PTE_SYNC(ptep);
+		rv = 1;
+	}
+
+	/*
+	 * We know there is a valid mapping here, so simply
+	 * fix up the L1 if necessary.
+	 */
+	pl1pd = &pm->pm_l1->l1_kva[l1idx];
+	l1pd = l2b->l2b_phys | L1_C_DOM(pm->pm_domain) | L1_C_PROTO;
+	if (*pl1pd != l1pd) {
+		*pl1pd = l1pd;
+		PTE_SYNC(pl1pd);
+		rv = 1;
+	}
+
+#ifdef DEBUG
+	/*
+	 * If 'rv == 0' at this point, it generally indicates that there is a
+	 * stale TLB entry for the faulting address. This happens when two or
+	 * more processes are sharing an L1. Since we don't flush the TLB on
+	 * a context switch between such processes, we can take domain faults
+	 * for mappings which exist at the same VA in both processes. EVEN IF
+	 * WE'VE RECENTLY FIXED UP THE CORRESPONDING L1 in pmap_enter(), for
+	 * example.
+	 *
+	 * This is extremely likely to happen if pmap_enter() updated the L1
+	 * entry for a recently entered mapping. In this case, the TLB is
+	 * flushed for the new mapping, but there may still be TLB entries for
+	 * other mappings belonging to other processes in the 1MB range
+	 * covered by the L1 entry.
+	 *
+	 * Since 'rv == 0', we know that the L1 already contains the correct
+	 * value, so the fault must be due to a stale TLB entry.
+	 *
+	 * Since we always need to flush the TLB anyway in the case where we
+	 * fixed up the L1, or frobbed the L2 PTE, we effectively deal with
+	 * stale TLB entries dynamically.
+	 *
+	 * However, the above condition can ONLY happen if the current L1 is
+	 * being shared. If it happens when the L1 is unshared, it indicates
+	 * that other parts of the pmap are not doing their job WRT managing
+	 * the TLB.
+	 */
+	if (rv == 0 && pm->pm_l1->l1_domain_use_count == 1) {
+		extern int last_fault_code;
+		printf("fixup: pm %p, va 0x%lx, ftype %d - nothing to do!\n",
+		    pm, va, ftype);
+		printf("fixup: l2 %p, l2b %p, ptep %p, pl1pd %p\n",
+		    l2, l2b, ptep, pl1pd);
+		printf("fixup: pte 0x%x, l1pd 0x%x, last code 0x%x\n",
+		    pte, l1pd, last_fault_code);
+#ifdef DDB
+		Debugger();
+#endif
+	}
+#endif
+
+	cpu_tlb_flushID_SE(va);
+	cpu_cpwait();
+
+	rv = 1;
+
+out:
+	vm_page_unlock_queues();
+	PMAP_UNLOCK(pm);
+	return (rv);
+}
+
+void
+pmap_postinit(void)
+{
+	struct l2_bucket *l2b;
+	struct l1_ttable *l1;
+	pd_entry_t *pl1pt;
+	pt_entry_t *ptep, pte;
+	vm_offset_t va, eva;
+	u_int loop, needed;
+
+	needed = (maxproc / PMAP_DOMAINS) + ((maxproc % PMAP_DOMAINS) ? 1 : 0);
+	needed -= 1;
+	l1 = malloc(sizeof(*l1) * needed, M_VMPMAP, M_WAITOK);
+
+	for (loop = 0; loop < needed; loop++, l1++) {
+		/* Allocate a L1 page table */
+		va = (vm_offset_t)contigmalloc(L1_TABLE_SIZE, M_VMPMAP, 0, 0x0,
+		    0xffffffff, L1_TABLE_SIZE, 0);
+
+		if (va == 0)
+			panic("Cannot allocate L1 KVM");
+
+		eva = va + L1_TABLE_SIZE;
+		pl1pt = (pd_entry_t *)va;
+
+		while (va < eva) {
+				l2b = pmap_get_l2_bucket(pmap_kernel(), va);
+				ptep = &l2b->l2b_kva[l2pte_index(va)];
+				pte = *ptep;
+				pte = (pte & ~L2_S_CACHE_MASK) | pte_l2_s_cache_mode_pt;
+				*ptep = pte;
+				PTE_SYNC(ptep);
+				cpu_tlb_flushD_SE(va);
+
+				va += PAGE_SIZE;
+		}
+		pmap_init_l1(l1, pl1pt);
+	}
+#ifdef DEBUG
+	printf("pmap_postinit: Allocated %d static L1 descriptor tables\n",
+	    needed);
+#endif
+}
+
+/*
+ * This is used to stuff certain critical values into the PCB where they
+ * can be accessed quickly from cpu_switch() et al.
+ */
+void
+pmap_set_pcb_pagedir(pmap_t pm, struct pcb *pcb)
+{
+	struct l2_bucket *l2b;
+
+	pcb->pcb_pagedir = pm->pm_l1->l1_physaddr;
+	pcb->pcb_dacr = (DOMAIN_CLIENT << (PMAP_DOMAIN_KERNEL * 2)) |
+	    (DOMAIN_CLIENT << (pm->pm_domain * 2));
+
+	if (vector_page < KERNBASE) {
+		pcb->pcb_pl1vec = &pm->pm_l1->l1_kva[L1_IDX(vector_page)];
+		l2b = pmap_get_l2_bucket(pm, vector_page);
+		pcb->pcb_l1vec = l2b->l2b_phys | L1_C_PROTO |
+		    L1_C_DOM(pm->pm_domain) | L1_C_DOM(PMAP_DOMAIN_KERNEL);
+	} else
+		pcb->pcb_pl1vec = NULL;
+}
+
+void
+pmap_activate(struct thread *td)
+{
+	pmap_t pm;
+	struct pcb *pcb;
+
+	pm = vmspace_pmap(td->td_proc->p_vmspace);
+	pcb = td->td_pcb;
+
+	critical_enter();
+	pmap_set_pcb_pagedir(pm, pcb);
+
+	if (td == curthread) {
+		u_int cur_dacr, cur_ttb;
+
+		__asm __volatile("mrc p15, 0, %0, c2, c0, 0" : "=r"(cur_ttb));
+		__asm __volatile("mrc p15, 0, %0, c3, c0, 0" : "=r"(cur_dacr));
+
+		cur_ttb &= ~(L1_TABLE_SIZE - 1);
+
+		if (cur_ttb == (u_int)pcb->pcb_pagedir &&
+		    cur_dacr == pcb->pcb_dacr) {
+			/*
+			 * No need to switch address spaces.
+			 */
+			critical_exit();
+			return;
+		}
+
+
+		/*
+		 * We MUST, I repeat, MUST fix up the L1 entry corresponding
+		 * to 'vector_page' in the incoming L1 table before switching
+		 * to it otherwise subsequent interrupts/exceptions (including
+		 * domain faults!) will jump into hyperspace.
+		 */
+		if (pcb->pcb_pl1vec) {
+			*pcb->pcb_pl1vec = pcb->pcb_l1vec;
+		}
+
+		cpu_domains(pcb->pcb_dacr);
+		cpu_setttb(pcb->pcb_pagedir);
+	}
+	critical_exit();
+}
+
+static int
+pmap_set_pt_cache_mode(pd_entry_t *kl1, vm_offset_t va)
+{
+	pd_entry_t *pdep, pde;
+	pt_entry_t *ptep, pte;
+	vm_offset_t pa;
+	int rv = 0;
+
+	/*
+	 * Make sure the descriptor itself has the correct cache mode
+	 */
+	pdep = &kl1[L1_IDX(va)];
+	pde = *pdep;
+
+	if (l1pte_section_p(pde)) {
+		if ((pde & L1_S_CACHE_MASK) != pte_l1_s_cache_mode_pt) {
+			*pdep = (pde & ~L1_S_CACHE_MASK) |
+			    pte_l1_s_cache_mode_pt;
+			PTE_SYNC(pdep);
+			rv = 1;
+		}
+	} else {
+		pa = (vm_paddr_t)(pde & L1_C_ADDR_MASK);
+		ptep = (pt_entry_t *)kernel_pt_lookup(pa);
+		if (ptep == NULL)
+			panic("pmap_bootstrap: No L2 for L2 @ va %p\n", ptep);
+
+		ptep = &ptep[l2pte_index(va)];
+		pte = *ptep;
+		if ((pte & L2_S_CACHE_MASK) != pte_l2_s_cache_mode_pt) {
+			*ptep = (pte & ~L2_S_CACHE_MASK) |
+			    pte_l2_s_cache_mode_pt;
+			PTE_SYNC(ptep);
+			rv = 1;
+		}
+	}
+
+	return (rv);
+}
+
+static void
+pmap_alloc_specials(vm_offset_t *availp, int pages, vm_offset_t *vap,
+    pt_entry_t **ptep)
+{
+	vm_offset_t va = *availp;
+	struct l2_bucket *l2b;
+
+	if (ptep) {
+		l2b = pmap_get_l2_bucket(pmap_kernel(), va);
+		if (l2b == NULL)
+			panic("pmap_alloc_specials: no l2b for 0x%x", va);
+
+		*ptep = &l2b->l2b_kva[l2pte_index(va)];
+	}
+
+	*vap = va;
+	*availp = va + (PAGE_SIZE * pages);
+}
+
+/*
+ *	Bootstrap the system enough to run with virtual memory.
+ *
+ *	On the arm this is called after mapping has already been enabled
+ *	and just syncs the pmap module with what has already been done.
+ *	[We can't call it easily with mapping off since the kernel is not
+ *	mapped with PA == VA, hence we would have to relocate every address
+ *	from the linked base (virtual) address "KERNBASE" to the actual
+ *	(physical) address starting relative to 0]
+ */
+#define PMAP_STATIC_L2_SIZE 16
+
+void
+pmap_bootstrap(vm_offset_t firstaddr, vm_offset_t lastaddr, struct pv_addr *l1pt)
+{
+	static struct l1_ttable static_l1;
+	static struct l2_dtable static_l2[PMAP_STATIC_L2_SIZE];
+	struct l1_ttable *l1 = &static_l1;
+	struct l2_dtable *l2;
+	struct l2_bucket *l2b;
+	pd_entry_t pde;
+	pd_entry_t *kernel_l1pt = (pd_entry_t *)l1pt->pv_va;
+	pt_entry_t *ptep;
+	vm_paddr_t pa;
+	vm_offset_t va;
+	vm_size_t size;
+	int l1idx, l2idx, l2next = 0;
+
+	PDEBUG(1, printf("firstaddr = %08x, lastaddr = %08x\n",
+	    firstaddr, lastaddr));
+
+	virtual_avail = firstaddr;
+	kernel_pmap->pm_l1 = l1;
+	kernel_l1pa = l1pt->pv_pa;
+
+	/*
+	 * Scan the L1 translation table created by initarm() and create
+	 * the required metadata for all valid mappings found in it.
+	 */
+	for (l1idx = 0; l1idx < (L1_TABLE_SIZE / sizeof(pd_entry_t)); l1idx++) {
+		pde = kernel_l1pt[l1idx];
+
+		/*
+		 * We're only interested in Coarse mappings.
+		 * pmap_extract() can deal with section mappings without
+		 * recourse to checking L2 metadata.
+		 */
+		if ((pde & L1_TYPE_MASK) != L1_TYPE_C)
+			continue;
+
+		/*
+		 * Lookup the KVA of this L2 descriptor table
+		 */
+		pa = (vm_paddr_t)(pde & L1_C_ADDR_MASK);
+		ptep = (pt_entry_t *)kernel_pt_lookup(pa);
+
+		if (ptep == NULL) {
+			panic("pmap_bootstrap: No L2 for va 0x%x, pa 0x%lx",
+			    (u_int)l1idx << L1_S_SHIFT, (long unsigned int)pa);
+		}
+
+		/*
+		 * Fetch the associated L2 metadata structure.
+		 * Allocate a new one if necessary.
+		 */
+		if ((l2 = kernel_pmap->pm_l2[L2_IDX(l1idx)]) == NULL) {
+			if (l2next == PMAP_STATIC_L2_SIZE)
+				panic("pmap_bootstrap: out of static L2s");
+			kernel_pmap->pm_l2[L2_IDX(l1idx)] = l2 =
+			    &static_l2[l2next++];
+		}
+
+		/*
+		 * One more L1 slot tracked...
+		 */
+		l2->l2_occupancy++;
+
+		/*
+		 * Fill in the details of the L2 descriptor in the
+		 * appropriate bucket.
+		 */
+		l2b = &l2->l2_bucket[L2_BUCKET(l1idx)];
+		l2b->l2b_kva = ptep;
+		l2b->l2b_phys = pa;
+		l2b->l2b_l1idx = l1idx;
+
+		/*
+		 * Establish an initial occupancy count for this descriptor
+		 */
+		for (l2idx = 0;
+		    l2idx < (L2_TABLE_SIZE_REAL / sizeof(pt_entry_t));
+		    l2idx++) {
+			if ((ptep[l2idx] & L2_TYPE_MASK) != L2_TYPE_INV) {
+				l2b->l2b_occupancy++;
+			}
+		}
+
+		/*
+		 * Make sure the descriptor itself has the correct cache mode.
+		 * If not, fix it, but whine about the problem. Port-meisters
+		 * should consider this a clue to fix up their initarm()
+		 * function. :)
+		 */
+		if (pmap_set_pt_cache_mode(kernel_l1pt, (vm_offset_t)ptep)) {
+			printf("pmap_bootstrap: WARNING! wrong cache mode for "
+			    "L2 pte @ %p\n", ptep);
+		}
+	}
+
+
+	/*
+	 * Ensure the primary (kernel) L1 has the correct cache mode for
+	 * a page table. Bitch if it is not correctly set.
+	 */
+	for (va = (vm_offset_t)kernel_l1pt;
+	    va < ((vm_offset_t)kernel_l1pt + L1_TABLE_SIZE); va += PAGE_SIZE) {
+		if (pmap_set_pt_cache_mode(kernel_l1pt, va))
+			printf("pmap_bootstrap: WARNING! wrong cache mode for "
+			    "primary L1 @ 0x%x\n", va);
+	}
+
+	cpu_dcache_wbinv_all();
+	cpu_l2cache_wbinv_all();
+	cpu_tlb_flushID();
+	cpu_cpwait();
+
+	PMAP_LOCK_INIT(kernel_pmap);
+	CPU_FILL(&kernel_pmap->pm_active);
+	kernel_pmap->pm_domain = PMAP_DOMAIN_KERNEL;
+	TAILQ_INIT(&kernel_pmap->pm_pvlist);
+
+	/*
+	 * Reserve some special page table entries/VA space for temporary
+	 * mapping of pages.
+	 */
+
+	pmap_alloc_specials(&virtual_avail, 1, &csrcp, &csrc_pte);
+	pmap_set_pt_cache_mode(kernel_l1pt, (vm_offset_t)csrc_pte);
+	pmap_alloc_specials(&virtual_avail, 1, &cdstp, &cdst_pte);
+	pmap_set_pt_cache_mode(kernel_l1pt, (vm_offset_t)cdst_pte);
+	size = ((lastaddr - pmap_curmaxkvaddr) + L1_S_OFFSET) / L1_S_SIZE;
+	pmap_alloc_specials(&virtual_avail,
+	    round_page(size * L2_TABLE_SIZE_REAL) / PAGE_SIZE,
+	    &pmap_kernel_l2ptp_kva, NULL);
+
+	size = (size + (L2_BUCKET_SIZE - 1)) / L2_BUCKET_SIZE;
+	pmap_alloc_specials(&virtual_avail,
+	    round_page(size * sizeof(struct l2_dtable)) / PAGE_SIZE,
+	    &pmap_kernel_l2dtable_kva, NULL);
+
+	pmap_alloc_specials(&virtual_avail,
+	    1, (vm_offset_t*)&_tmppt, NULL);
+	pmap_alloc_specials(&virtual_avail,
+	    MAXDUMPPGS, (vm_offset_t *)&crashdumpmap, NULL);
+	SLIST_INIT(&l1_list);
+	TAILQ_INIT(&l1_lru_list);
+	mtx_init(&l1_lru_lock, "l1 list lock", NULL, MTX_DEF);
+	pmap_init_l1(l1, kernel_l1pt);
+	cpu_dcache_wbinv_all();
+	cpu_l2cache_wbinv_all();
+
+	virtual_avail = round_page(virtual_avail);
+	virtual_end = lastaddr;
+	kernel_vm_end = pmap_curmaxkvaddr;
+	arm_nocache_startaddr = lastaddr;
+	mtx_init(&cmtx, "TMP mappings mtx", NULL, MTX_DEF);
+
+	pmap_set_pcb_pagedir(kernel_pmap, thread0.td_pcb);
+}
+
+/***************************************************
+ * Pmap allocation/deallocation routines.
+ ***************************************************/
+
+/*
+ * Release any resources held by the given physical map.
+ * Called when a pmap initialized by pmap_pinit is being released.
+ * Should only be called if the map contains no valid mappings.
+ */
+void
+pmap_release(pmap_t pmap)
+{
+	struct pcb *pcb;
+
+	cpu_idcache_wbinv_all();
+	cpu_l2cache_wbinv_all();
+	cpu_tlb_flushID();
+	cpu_cpwait();
+	if (vector_page < KERNBASE) {
+		struct pcb *curpcb = PCPU_GET(curpcb);
+		pcb = thread0.td_pcb;
+		if (pmap_is_current(pmap)) {
+			/*
+			 * Frob the L1 entry corresponding to the vector
+			 * page so that it contains the kernel pmap's domain
+			 * number. This will ensure pmap_remove() does not
+			 * pull the current vector page out from under us.
+			 */
+			critical_enter();
+			*pcb->pcb_pl1vec = pcb->pcb_l1vec;
+			cpu_domains(pcb->pcb_dacr);
+			cpu_setttb(pcb->pcb_pagedir);
+			critical_exit();
+		}
+		pmap_remove(pmap, vector_page, vector_page + PAGE_SIZE);
+		/*
+		 * Make sure cpu_switch(), et al, DTRT. This is safe to do
+		 * since this process has no remaining mappings of its own.
+		 */
+		curpcb->pcb_pl1vec = pcb->pcb_pl1vec;
+		curpcb->pcb_l1vec = pcb->pcb_l1vec;
+		curpcb->pcb_dacr = pcb->pcb_dacr;
+		curpcb->pcb_pagedir = pcb->pcb_pagedir;
+
+	}
+	pmap_free_l1(pmap);
+	PMAP_LOCK_DESTROY(pmap);
+
+	dprintf("pmap_release()\n");
+}
+
+
+
+/*
+ * Helper function for pmap_grow_l2_bucket()
+ */
+static __inline int
+pmap_grow_map(vm_offset_t va, pt_entry_t cache_mode, vm_paddr_t *pap)
+{
+	struct l2_bucket *l2b;
+	pt_entry_t *ptep;
+	vm_paddr_t pa;
+	struct vm_page *pg;
+
+	pg = vm_page_alloc(NULL, 0, VM_ALLOC_NOOBJ | VM_ALLOC_WIRED);
+	if (pg == NULL)
+		return (1);
+	pa = VM_PAGE_TO_PHYS(pg);
+
+	if (pap)
+		*pap = pa;
+
+	l2b = pmap_get_l2_bucket(pmap_kernel(), va);
+
+	ptep = &l2b->l2b_kva[l2pte_index(va)];
+	*ptep = L2_S_PROTO | pa | cache_mode;
+	pmap_set_prot(ptep, VM_PROT_READ | VM_PROT_WRITE, 0);
+	PTE_SYNC(ptep);
+
+	return (0);
+}
+
+/*
+ * This is the same as pmap_alloc_l2_bucket(), except that it is only
+ * used by pmap_growkernel().
+ */
+static __inline struct l2_bucket *
+pmap_grow_l2_bucket(pmap_t pm, vm_offset_t va)
+{
+	struct l2_dtable *l2;
+	struct l2_bucket *l2b;
+	struct l1_ttable *l1;
+	pd_entry_t *pl1pd;
+	u_short l1idx;
+	vm_offset_t nva;
+
+	l1idx = L1_IDX(va);
+
+	if ((l2 = pm->pm_l2[L2_IDX(l1idx)]) == NULL) {
+		/*
+		 * No mapping at this address, as there is
+		 * no entry in the L1 table.
+		 * Need to allocate a new l2_dtable.
+		 */
+		nva = pmap_kernel_l2dtable_kva;
+		if ((nva & PAGE_MASK) == 0) {
+			/*
+			 * Need to allocate a backing page
+			 */
+			if (pmap_grow_map(nva, pte_l2_s_cache_mode, NULL))
+				return (NULL);
+		}
+
+		l2 = (struct l2_dtable *)nva;
+		nva += sizeof(struct l2_dtable);
+
+		if ((nva & PAGE_MASK) < (pmap_kernel_l2dtable_kva &
+		    PAGE_MASK)) {
+			/*
+			 * The new l2_dtable straddles a page boundary.
+			 * Map in another page to cover it.
+			 */
+			if (pmap_grow_map(nva, pte_l2_s_cache_mode, NULL))
+				return (NULL);
+		}
+
+		pmap_kernel_l2dtable_kva = nva;
+
+		/*
+		 * Link it into the parent pmap
+		 */
+		pm->pm_l2[L2_IDX(l1idx)] = l2;
+		memset(l2, 0, sizeof(*l2));
+	}
+
+	l2b = &l2->l2_bucket[L2_BUCKET(l1idx)];
+
+	/*
+	 * Fetch pointer to the L2 page table associated with the address.
+	 */
+	if (l2b->l2b_kva == NULL) {
+		pt_entry_t *ptep;
+
+		/*
+		 * No L2 page table has been allocated. Chances are, this
+		 * is because we just allocated the l2_dtable, above.
+		 */
+		nva = pmap_kernel_l2ptp_kva;
+		ptep = (pt_entry_t *)nva;
+		if ((nva & PAGE_MASK) == 0) {
+			/*
+			 * Need to allocate a backing page
+			 */
+			if (pmap_grow_map(nva, pte_l2_s_cache_mode_pt,
+			    &pmap_kernel_l2ptp_phys))
+				return (NULL);
+		}
+		memset(ptep, 0, L2_TABLE_SIZE_REAL);
+		l2->l2_occupancy++;
+		l2b->l2b_kva = ptep;
+		l2b->l2b_l1idx = l1idx;
+		l2b->l2b_phys = pmap_kernel_l2ptp_phys;
+
+		pmap_kernel_l2ptp_kva += L2_TABLE_SIZE_REAL;
+		pmap_kernel_l2ptp_phys += L2_TABLE_SIZE_REAL;
+	}
+
+	/* Distribute new L1 entry to all other L1s */
+	SLIST_FOREACH(l1, &l1_list, l1_link) {
+			pl1pd = &l1->l1_kva[L1_IDX(va)];
+			*pl1pd = l2b->l2b_phys | L1_C_DOM(PMAP_DOMAIN_KERNEL) |
+			    L1_C_PROTO;
+			PTE_SYNC(pl1pd);
+	}
+
+	return (l2b);
+}
+
+
+/*
+ * grow the number of kernel page table entries, if needed
+ */
+void
+pmap_growkernel(vm_offset_t addr)
+{
+	pmap_t kpm = pmap_kernel();
+
+	if (addr <= pmap_curmaxkvaddr)
+		return;		/* we are OK */
+
+	/*
+	 * whoops!   we need to add kernel PTPs
+	 */
+
+	/* Map 1MB at a time */
+	for (; pmap_curmaxkvaddr < addr; pmap_curmaxkvaddr += L1_S_SIZE)
+		pmap_grow_l2_bucket(kpm, pmap_curmaxkvaddr);
+
+	/*
+	 * flush out the cache, expensive but growkernel will happen so
+	 * rarely
+	 */
+	cpu_dcache_wbinv_all();
+	cpu_l2cache_wbinv_all();
+	cpu_tlb_flushD();
+	cpu_cpwait();
+	kernel_vm_end = pmap_curmaxkvaddr;
+}
+
+
+/*
+ * Remove all pages from specified address space
+ * this aids process exit speeds.  Also, this code
+ * is special cased for current process only, but
+ * can have the more generic (and slightly slower)
+ * mode enabled.  This is much faster than pmap_remove
+ * in the case of running down an entire address space.
+ */
+void
+pmap_remove_pages(pmap_t pmap)
+{
+	struct pv_entry *pv, *npv;
+	struct l2_bucket *l2b = NULL;
+	vm_page_t m;
+	pt_entry_t *pt;
+
+	vm_page_lock_queues();
+	PMAP_LOCK(pmap);
+	for (pv = TAILQ_FIRST(&pmap->pm_pvlist); pv; pv = npv) {
+		if (pv->pv_flags & PVF_WIRED) {
+			/* Cannot remove wired pages now. */
+			npv = TAILQ_NEXT(pv, pv_plist);
+			continue;
+		}
+		pmap->pm_stats.resident_count--;
+		l2b = pmap_get_l2_bucket(pmap, pv->pv_va);
+		KASSERT(l2b != NULL, ("No L2 bucket in pmap_remove_pages"));
+		pt = &l2b->l2b_kva[l2pte_index(pv->pv_va)];
+		m = PHYS_TO_VM_PAGE(*pt & L2_ADDR_MASK);
+		KASSERT((vm_offset_t)m >= KERNBASE, ("Trying to access non-existent page va %x pte %x", pv->pv_va, *pt));
+		*pt = 0;
+		PTE_SYNC(pt);
+		npv = TAILQ_NEXT(pv, pv_plist);
+		pmap_nuke_pv(m, pmap, pv);
+		if (TAILQ_EMPTY(&m->md.pv_list))
+			vm_page_aflag_clear(m, PGA_WRITEABLE);
+		pmap_free_pv_entry(pv);
+		pmap_free_l2_bucket(pmap, l2b, 1);
+	}
+	vm_page_unlock_queues();
+	cpu_tlb_flushID();
+	cpu_cpwait();
+	PMAP_UNLOCK(pmap);
+}
+
+
+/***************************************************
+ * Low level mapping routines.....
+ ***************************************************/
+
+#ifdef ARM_HAVE_SUPERSECTIONS
+/* Map a super section into the KVA. */
+
+void
+pmap_kenter_supersection(vm_offset_t va, uint64_t pa, int flags)
+{
+	pd_entry_t pd = L1_S_PROTO | L1_S_SUPERSEC | (pa & L1_SUP_FRAME) |
+	    (((pa >> 32) & 0xf) << 20) | L1_S_PROT(PTE_KERNEL,
+	    VM_PROT_READ|VM_PROT_WRITE) | L1_S_DOM(PMAP_DOMAIN_KERNEL);
+	struct l1_ttable *l1;
+	vm_offset_t va0, va_end;
+
+	KASSERT(((va | pa) & L1_SUP_OFFSET) == 0,
+	    ("Not a valid super section mapping"));
+	if (flags & SECTION_CACHE)
+		pd |= pte_l1_s_cache_mode;
+	else if (flags & SECTION_PT)
+		pd |= pte_l1_s_cache_mode_pt;
+
+	va0 = va & L1_SUP_FRAME;
+	va_end = va + L1_SUP_SIZE;
+	SLIST_FOREACH(l1, &l1_list, l1_link) {
+		va = va0;
+		for (; va < va_end; va += L1_S_SIZE) {
+			l1->l1_kva[L1_IDX(va)] = pd;
+			PTE_SYNC(&l1->l1_kva[L1_IDX(va)]);
+		}
+	}
+}
+#endif
+
+/* Map a section into the KVA. */
+
+void
+pmap_kenter_section(vm_offset_t va, vm_offset_t pa, int flags)
+{
+	pd_entry_t pd = L1_S_PROTO | pa | L1_S_PROT(PTE_KERNEL,
+	    VM_PROT_READ|VM_PROT_WRITE) | L1_S_DOM(PMAP_DOMAIN_KERNEL);
+	struct l1_ttable *l1;
+
+	KASSERT(((va | pa) & L1_S_OFFSET) == 0,
+	    ("Not a valid section mapping"));
+	if (flags & SECTION_CACHE)
+		pd |= pte_l1_s_cache_mode;
+	else if (flags & SECTION_PT)
+		pd |= pte_l1_s_cache_mode_pt;
+
+	SLIST_FOREACH(l1, &l1_list, l1_link) {
+		l1->l1_kva[L1_IDX(va)] = pd;
+		PTE_SYNC(&l1->l1_kva[L1_IDX(va)]);
+	}
+}
+
+/*
+ * Make a temporary mapping for a physical address.  This is only intended
+ * to be used for panic dumps.
+ */
+void *
+pmap_kenter_temp(vm_paddr_t pa, int i)
+{
+	vm_offset_t va;
+
+	va = (vm_offset_t)crashdumpmap + (i * PAGE_SIZE);
+	pmap_kenter(va, pa);
+	return ((void *)crashdumpmap);
+}
+
+/*
+ * add a wired page to the kva
+ * note that in order for the mapping to take effect -- you
+ * should do a invltlb after doing the pmap_kenter...
+ */
+static PMAP_INLINE void
+pmap_kenter_internal(vm_offset_t va, vm_offset_t pa, int flags)
+{
+	struct l2_bucket *l2b;
+	pt_entry_t *pte;
+	pt_entry_t opte;
+
+	PDEBUG(1, printf("pmap_kenter: va = %08x, pa = %08x\n",
+	    (uint32_t) va, (uint32_t) pa));
+
+
+	l2b = pmap_get_l2_bucket(pmap_kernel(), va);
+	if (l2b == NULL)
+		l2b = pmap_grow_l2_bucket(pmap_kernel(), va);
+	KASSERT(l2b != NULL, ("No L2 Bucket"));
+
+	pte = &l2b->l2b_kva[l2pte_index(va)];
+	opte = *pte;
+	if (l2pte_valid(opte)) {
+		cpu_tlb_flushD_SE(va);
+		cpu_cpwait();
+	} else {
+		if (opte == 0)
+			l2b->l2b_occupancy++;
+	}
+
+	if (flags & KENTER_CACHE) {
+		*pte = L2_S_PROTO | pa | pte_l2_s_cache_mode;
+		pmap_set_prot(pte, VM_PROT_READ | VM_PROT_WRITE,
+		    flags & KENTER_USER);
+	} else {
+		*pte = L2_S_PROTO | pa;
+		pmap_set_prot(pte, VM_PROT_READ|VM_PROT_WRITE|VM_PROT_EXECUTE,
+		    0);
+	}
+
+	PDEBUG(1, printf("pmap_kenter: pte = %08x, opte = %08x, npte = %08x\n",
+	    (uint32_t) pte, opte, *pte));
+	PTE_SYNC(pte);
+	cpu_cpwait();
+}
+
+void
+pmap_kenter(vm_offset_t va, vm_paddr_t pa)
+{
+	pmap_kenter_internal(va, pa, KENTER_CACHE);
+}
+
+void
+pmap_kenter_nocache(vm_offset_t va, vm_paddr_t pa)
+{
+
+	pmap_kenter_internal(va, pa, 0);
+}
+
+void
+pmap_kenter_user(vm_offset_t va, vm_paddr_t pa)
+{
+
+	pmap_kenter_internal(va, pa, KENTER_CACHE|KENTER_USER);
+	/*
+	 * Call pmap_fault_fixup now, to make sure we'll have no exception
+	 * at the first use of the new address, or bad things will happen,
+	 * as we use one of these addresses in the exception handlers.
+	 */
+	pmap_fault_fixup(pmap_kernel(), va, VM_PROT_READ|VM_PROT_WRITE, 1);
+}
+
+/*
+ * remove a page from the kernel pagetables
+ */
+void
+pmap_kremove(vm_offset_t va)
+{
+	struct l2_bucket *l2b;
+	pt_entry_t *pte, opte;
+
+	l2b = pmap_get_l2_bucket(pmap_kernel(), va);
+	if (!l2b)
+		return;
+	KASSERT(l2b != NULL, ("No L2 Bucket"));
+	pte = &l2b->l2b_kva[l2pte_index(va)];
+	opte = *pte;
+	if (l2pte_valid(opte)) {
+		va = va & ~PAGE_MASK;
+		cpu_tlb_flushD_SE(va);
+		cpu_cpwait();
+		*pte = 0;
+	}
+}
+
+
+/*
+ *	Used to map a range of physical addresses into kernel
+ *	virtual address space.
+ *
+ *	The value passed in '*virt' is a suggested virtual address for
+ *	the mapping. Architectures which can support a direct-mapped
+ *	physical to virtual region can return the appropriate address
+ *	within that region, leaving '*virt' unchanged. Other
+ *	architectures should map the pages starting at '*virt' and
+ *	update '*virt' with the first usable address after the mapped
+ *	region.
+ */
+vm_offset_t
+pmap_map(vm_offset_t *virt, vm_offset_t start, vm_offset_t end, int prot)
+{
+	vm_offset_t sva = *virt;
+	vm_offset_t va = sva;
+
+	PDEBUG(1, printf("pmap_map: virt = %08x, start = %08x, end = %08x, "
+	    "prot = %d\n", (uint32_t) *virt, (uint32_t) start, (uint32_t) end,
+	    prot));
+
+	while (start < end) {
+		pmap_kenter(va, start);
+		va += PAGE_SIZE;
+		start += PAGE_SIZE;
+	}
+	*virt = va;
+	return (sva);
+}
+
+/*
+ * Add a list of wired pages to the kva
+ * this routine is only used for temporary
+ * kernel mappings that do not need to have
+ * page modification or references recorded.
+ * Note that old mappings are simply written
+ * over.  The page *must* be wired.
+ */
+void
+pmap_qenter(vm_offset_t va, vm_page_t *m, int count)
+{
+	int i;
+
+	for (i = 0; i < count; i++) {
+		pmap_kenter_internal(va, VM_PAGE_TO_PHYS(m[i]),
+		    KENTER_CACHE);
+		va += PAGE_SIZE;
+	}
+}
+
+
+/*
+ * this routine jerks page mappings from the
+ * kernel -- it is meant only for temporary mappings.
+ */
+void
+pmap_qremove(vm_offset_t va, int count)
+{
+	int i;
+
+	for (i = 0; i < count; i++) {
+		if (vtophys(va))
+			pmap_kremove(va);
+
+		va += PAGE_SIZE;
+	}
+}
+
+
+/*
+ * pmap_object_init_pt preloads the ptes for a given object
+ * into the specified pmap.  This eliminates the blast of soft
+ * faults on process startup and immediately after an mmap.
+ */
+void
+pmap_object_init_pt(pmap_t pmap, vm_offset_t addr, vm_object_t object,
+    vm_pindex_t pindex, vm_size_t size)
+{
+
+	VM_OBJECT_LOCK_ASSERT(object, MA_OWNED);
+	KASSERT(object->type == OBJT_DEVICE || object->type == OBJT_SG,
+	    ("pmap_object_init_pt: non-device object"));
+}
+
+
+/*
+ *	pmap_is_prefaultable:
+ *
+ *	Return whether or not the specified virtual address is elgible
+ *	for prefault.
+ */
+boolean_t
+pmap_is_prefaultable(pmap_t pmap, vm_offset_t addr)
+{
+	pd_entry_t *pde;
+	pt_entry_t *pte;
+
+	if (!pmap_get_pde_pte(pmap, addr, &pde, &pte))
+		return (FALSE);
+	KASSERT(pte != NULL, ("Valid mapping but no pte ?"));
+	if (*pte == 0)
+		return (TRUE);
+	return (FALSE);
+}
+
+/*
+ * Fetch pointers to the PDE/PTE for the given pmap/VA pair.
+ * Returns TRUE if the mapping exists, else FALSE.
+ *
+ * NOTE: This function is only used by a couple of arm-specific modules.
+ * It is not safe to take any pmap locks here, since we could be right
+ * in the middle of debugging the pmap anyway...
+ *
+ * It is possible for this routine to return FALSE even though a valid
+ * mapping does exist. This is because we don't lock, so the metadata
+ * state may be inconsistent.
+ *
+ * NOTE: We can return a NULL *ptp in the case where the L1 pde is
+ * a "section" mapping.
+ */
+boolean_t
+pmap_get_pde_pte(pmap_t pm, vm_offset_t va, pd_entry_t **pdp, pt_entry_t **ptp)
+{
+	struct l2_dtable *l2;
+	pd_entry_t *pl1pd, l1pd;
+	pt_entry_t *ptep;
+	u_short l1idx;
+
+	if (pm->pm_l1 == NULL)
+		return (FALSE);
+
+	l1idx = L1_IDX(va);
+	*pdp = pl1pd = &pm->pm_l1->l1_kva[l1idx];
+	l1pd = *pl1pd;
+
+	if (l1pte_section_p(l1pd)) {
+		*ptp = NULL;
+		return (TRUE);
+	}
+
+	if (pm->pm_l2 == NULL)
+		return (FALSE);
+
+	l2 = pm->pm_l2[L2_IDX(l1idx)];
+
+	if (l2 == NULL ||
+	    (ptep = l2->l2_bucket[L2_BUCKET(l1idx)].l2b_kva) == NULL) {
+		return (FALSE);
+	}
+
+	*ptp = &ptep[l2pte_index(va)];
+	return (TRUE);
+}
+
+/*
+ *      Routine:        pmap_remove_all
+ *      Function:
+ *              Removes this physical page from
+ *              all physical maps in which it resides.
+ *              Reflects back modify bits to the pager.
+ *
+ *      Notes:
+ *              Original versions of this routine were very
+ *              inefficient because they iteratively called
+ *              pmap_remove (slow...)
+ */
+void
+pmap_remove_all(vm_page_t m)
+{
+	pv_entry_t pv;
+	pt_entry_t *ptep;
+	struct l2_bucket *l2b;
+	boolean_t flush = FALSE;
+	pmap_t curpm;
+	int flags = 0;
+
+	KASSERT((m->flags & PG_FICTITIOUS) == 0,
+	    ("pmap_remove_all: page %p is fictitious", m));
+
+	if (TAILQ_EMPTY(&m->md.pv_list))
+		return;
+	vm_page_lock_queues();
+	pmap_remove_write(m);
+	curpm = vmspace_pmap(curproc->p_vmspace);
+	while ((pv = TAILQ_FIRST(&m->md.pv_list)) != NULL) {
+		if (flush == FALSE && (pv->pv_pmap == curpm ||
+		    pv->pv_pmap == pmap_kernel()))
+			flush = TRUE;
+
+		PMAP_LOCK(pv->pv_pmap);
+		l2b = pmap_get_l2_bucket(pv->pv_pmap, pv->pv_va);
+		KASSERT(l2b != NULL, ("No l2 bucket"));
+		ptep = &l2b->l2b_kva[l2pte_index(pv->pv_va)];
+		*ptep = 0;
+		if (pmap_is_current(pv->pv_pmap))
+			PTE_SYNC(ptep);
+		pmap_free_l2_bucket(pv->pv_pmap, l2b, 1);
+		pv->pv_pmap->pm_stats.resident_count--;
+		flags |= pv->pv_flags;
+		pmap_nuke_pv(m, pv->pv_pmap, pv);
+		PMAP_UNLOCK(pv->pv_pmap);
+		pmap_free_pv_entry(pv);
+	}
+
+	if (flush) {
+		if (PV_BEEN_EXECD(flags))
+			cpu_tlb_flushID();
+		else
+			cpu_tlb_flushD();
+	}
+	vm_page_aflag_clear(m, PGA_WRITEABLE);
+	vm_page_unlock_queues();
+}
+
+int
+pmap_change_attr(vm_offset_t sva, vm_size_t len, int mode)
+{
+	vm_offset_t base, offset, tmpva;
+	vm_size_t size;
+	struct l2_bucket *l2b;
+	pt_entry_t *ptep, pte;
+	vm_offset_t next_bucket;
+
+	PMAP_LOCK(kernel_pmap);
+
+	base = trunc_page(sva);
+	offset = sva & PAGE_MASK;
+	size = roundup(offset + len, PAGE_SIZE);
+
+#ifdef checkit
+	/*
+	 * Only supported on kernel virtual addresses, including the direct
+	 * map but excluding the recursive map.
+	 */
+	if (base < DMAP_MIN_ADDRESS)
+		return (EINVAL);
+#endif
+	for (tmpva = base; tmpva < base + size; ) {
+		next_bucket = L2_NEXT_BUCKET(tmpva);
+		if (next_bucket > base + size)
+			next_bucket = base + size;
+
+		l2b = pmap_get_l2_bucket(kernel_pmap, tmpva);
+		if (l2b == NULL) {
+			tmpva = next_bucket;
+			continue;
+		}
+
+		ptep = &l2b->l2b_kva[l2pte_index(tmpva)];
+
+		if (*ptep == 0)
+			return(EINVAL);
+
+		pte = *ptep &~ L2_S_CACHE_MASK;
+		cpu_idcache_wbinv_range(tmpva, PAGE_SIZE);
+#ifdef ARM_L2_PIPT
+		cpu_l2cache_wbinv_range(pte & L2_S_FRAME, PAGE_SIZE);
+#else
+		cpu_l2cache_wbinv_range(tmpva, PAGE_SIZE);
+#endif
+		*ptep = pte;
+		cpu_tlb_flushID_SE(tmpva);
+
+		dprintf("%s: for va:%x ptep:%x pte:%x\n",
+		    __func__, tmpva, (uint32_t)ptep, pte);
+		tmpva += PAGE_SIZE;
+	}
+
+	PMAP_UNLOCK(kernel_pmap);
+
+	return (0);
+}
+
+/*
+ *	Set the physical protection on the
+ *	specified range of this map as requested.
+ */
+void
+pmap_protect(pmap_t pm, vm_offset_t sva, vm_offset_t eva, vm_prot_t prot)
+{
+	struct l2_bucket *l2b;
+	pt_entry_t *ptep, pte;
+	vm_offset_t next_bucket;
+	u_int flags;
+	int flush;
+
+	if ((prot & VM_PROT_READ) == 0) {
+		pmap_remove(pm, sva, eva);
+		return;
+	}
+
+	if (prot & VM_PROT_WRITE) {
+		/*
+		 * If this is a read->write transition, just ignore it and let
+		 * vm_fault() take care of it later.
+		 */
+		return;
+	}
+
+	vm_page_lock_queues();
+	PMAP_LOCK(pm);
+
+	/*
+	 * OK, at this point, we know we're doing write-protect operation.
+	 * If the pmap is active, write-back the range.
+	 */
+
+	flush = ((eva - sva) >= (PAGE_SIZE * 4)) ? 0 : -1;
+	flags = 0;
+
+	while (sva < eva) {
+		next_bucket = L2_NEXT_BUCKET(sva);
+		if (next_bucket > eva)
+			next_bucket = eva;
+
+		l2b = pmap_get_l2_bucket(pm, sva);
+		if (l2b == NULL) {
+			sva = next_bucket;
+			continue;
+		}
+
+		ptep = &l2b->l2b_kva[l2pte_index(sva)];
+
+		while (sva < next_bucket) {
+			if ((pte = *ptep) != 0 && L2_S_WRITABLE(pte)) {
+				struct vm_page *pg;
+				u_int f;
+
+				pg = PHYS_TO_VM_PAGE(l2pte_pa(pte));
+				pmap_set_prot(ptep, prot, !(pm == pmap_kernel()));
+				PTE_SYNC(ptep);
+
+				f = pmap_modify_pv(pg, pm, sva,
+				    PVF_WRITE, 0);
+				if (f & PVF_WRITE)
+					vm_page_dirty(pg);
+
+				if (flush >= 0) {
+					flush++;
+					flags |= f;
+				} else
+				if (PV_BEEN_EXECD(f))
+					cpu_tlb_flushID_SE(sva);
+				else
+				if (PV_BEEN_REFD(f))
+					cpu_tlb_flushD_SE(sva);
+			}
+
+			sva += PAGE_SIZE;
+			ptep++;
+		}
+	}
+
+
+	if (flush) {
+		if (PV_BEEN_EXECD(flags))
+			cpu_tlb_flushID();
+		else
+		if (PV_BEEN_REFD(flags))
+			cpu_tlb_flushD();
+	}
+	vm_page_unlock_queues();
+
+	PMAP_UNLOCK(pm);
+}
+
+
+/*
+ *	Insert the given physical page (p) at
+ *	the specified virtual address (v) in the
+ *	target physical map with the protection requested.
+ *
+ *	If specified, the page will be wired down, meaning
+ *	that the related pte can not be reclaimed.
+ *
+ *	NB:  This is the only routine which MAY NOT lazy-evaluate
+ *	or lose information.  That is, this routine must actually
+ *	insert this page into the given map NOW.
+ */
+
+void
+pmap_enter(pmap_t pmap, vm_offset_t va, vm_prot_t access, vm_page_t m,
+    vm_prot_t prot, boolean_t wired)
+{
+
+	vm_page_lock_queues();
+	PMAP_LOCK(pmap);
+	pmap_enter_locked(pmap, va, m, prot, wired, M_WAITOK);
+	PMAP_UNLOCK(pmap);
+	vm_page_unlock_queues();
+}
+
+/*
+ *	The page queues and pmap must be locked.
+ */
+static void
+pmap_enter_locked(pmap_t pmap, vm_offset_t va, vm_page_t m, vm_prot_t prot,
+    boolean_t wired, int flags)
+{
+	struct l2_bucket *l2b = NULL;
+	struct vm_page *opg;
+	struct pv_entry *pve = NULL;
+	pt_entry_t *ptep, npte, opte;
+	u_int nflags;
+	u_int oflags;
+	vm_paddr_t pa;
+	u_char user;
+
+	PMAP_ASSERT_LOCKED(pmap);
+	mtx_assert(&vm_page_queue_mtx, MA_OWNED);
+	if (va == vector_page) {
+		pa = systempage.pv_pa;
+		m = NULL;
+	} else {
+		KASSERT((m->oflags & (VPO_UNMANAGED | VPO_BUSY)) != 0 ||
+		    (flags & M_NOWAIT) != 0,
+		    ("pmap_enter_locked: page %p is not busy", m));
+		pa = VM_PAGE_TO_PHYS(m);
+	}
+
+	user = 0;
+	/*
+	 * Make sure userland mappings get the right permissions
+	 */
+	if (pmap != pmap_kernel() && va != vector_page)
+		user = 1;
+
+	nflags = 0;
+
+	if (prot & VM_PROT_WRITE)
+		nflags |= PVF_WRITE;
+	if (prot & VM_PROT_EXECUTE)
+		nflags |= PVF_EXEC;
+	if (wired)
+		nflags |= PVF_WIRED;
+
+	PDEBUG(1, printf("pmap_enter: pmap = %08x, va = %08x, m = %08x, prot = %x, "
+	    "wired = %x\n", (uint32_t) pmap, va, (uint32_t) m, prot, wired));
+
+	if (pmap == pmap_kernel()) {
+		l2b = pmap_get_l2_bucket(pmap, va);
+		if (l2b == NULL)
+			l2b = pmap_grow_l2_bucket(pmap, va);
+	} else {
+do_l2b_alloc:
+		l2b = pmap_alloc_l2_bucket(pmap, va);
+		if (l2b == NULL) {
+			if (flags & M_WAITOK) {
+				PMAP_UNLOCK(pmap);
+				vm_page_unlock_queues();
+				VM_WAIT;
+				vm_page_lock_queues();
+				PMAP_LOCK(pmap);
+				goto do_l2b_alloc;
+			}
+			return;
+		}
+	}
+
+	ptep = &l2b->l2b_kva[l2pte_index(va)];
+
+	opte = *ptep;
+	npte = pa;
+	oflags = 0;
+	if (opte) {
+		/*
+		 * There is already a mapping at this address.
+		 * If the physical address is different, lookup the
+		 * vm_page.
+		 */
+		if (l2pte_pa(opte) != pa)
+			opg = PHYS_TO_VM_PAGE(l2pte_pa(opte));
+		else
+			opg = m;
+	} else
+		opg = NULL;
+
+	if ((prot & (VM_PROT_ALL)) ||
+	    (!m || m->md.pvh_attrs & PVF_REF)) {
+		/*
+		 * - The access type indicates that we don't need
+		 *   to do referenced emulation.
+		 * OR
+		 * - The physical page has already been referenced
+		 *   so no need to re-do referenced emulation here.
+		 */
+		npte |= L2_S_PROTO;
+#ifdef SMP
+		npte |= L2_SHARED;
+#endif
+
+		nflags |= PVF_REF;
+
+		if (m && ((prot & VM_PROT_WRITE) != 0 ||
+		    (m->md.pvh_attrs & PVF_MOD))) {
+			/*
+			 * This is a writable mapping, and the
+			 * page's mod state indicates it has
+			 * already been modified. Make it
+			 * writable from the outset.
+			 */
+			nflags |= PVF_MOD;
+			if (!(m->md.pvh_attrs & PVF_MOD))
+				vm_page_dirty(m);
+		}
+		if (m && opte)
+			vm_page_aflag_set(m, PGA_REFERENCED);
+	} else {
+		/*
+		 * Need to do page referenced emulation.
+		 */
+		npte |= L2_TYPE_INV;
+	}
+
+	npte |= L2_S_PROT_R;
+
+	if (prot & VM_PROT_WRITE) {
+		npte &= ~(L2_APX);
+
+		if (m != NULL &&
+		    (m->oflags & VPO_UNMANAGED) == 0)
+			vm_page_aflag_set(m, PGA_WRITEABLE);
+	}
+
+	if (user)
+		npte |= L2_S_PROT_U;
+
+
+	if (!(prot & VM_PROT_EXECUTE) && m)
+		npte |= L2_XN;
+
+	npte |= pte_l2_s_cache_mode;
+
+	if (m && m == opg) {
+		/*
+		 * We're changing the attrs of an existing mapping.
+		 */
+		oflags = pmap_modify_pv(m, pmap, va,
+		    PVF_WRITE | PVF_EXEC | PVF_WIRED |
+		    PVF_MOD | PVF_REF, nflags);
+	} else {
+		/*
+		 * New mapping, or changing the backing page
+		 * of an existing mapping.
+		 */
+		if (opg) {
+			/*
+			 * Replacing an existing mapping with a new one.
+			 * It is part of our managed memory so we
+			 * must remove it from the PV list
+			 */
+			if ((pve = pmap_remove_pv(opg, pmap, va))) {
+			    oflags = pve->pv_flags;
+
+			    if (m && ((m->oflags & VPO_UNMANAGED))) {
+				pmap_free_pv_entry(pve);
+				pve = NULL;
+			    }
+			}
+		}
+
+		if ((m && !(m->oflags & VPO_UNMANAGED))) {
+			if ((!pve) && (pve = pmap_get_pv_entry()) == NULL)
+				panic("pmap_enter: no pv entries");
+
+			KASSERT(va < kmi.clean_sva || va >= kmi.clean_eva,
+			("pmap_enter: managed mapping within the clean submap"));
+			KASSERT(pve != NULL, ("No pv"));
+			pmap_enter_pv(m, pve, pmap, va, nflags);
+		}
+	}
+
+	/*
+	 * Keep the stats up to date
+	 */
+	if (opte == 0) {
+		l2b->l2b_occupancy++;
+		pmap->pm_stats.resident_count++;
+	}
+
+	CTR5(KTR_PMAP,"enter: pmap:%p va:%x prot:%x pte:%x->%x",
+	    pmap, va, prot, opte, npte);
+	/*
+	 * If this is just a wiring change, the two PTEs will be
+	 * identical, so there's no need to update the page table.
+	 */
+	if (npte != opte) {
+		boolean_t is_cached = pmap_is_current(pmap);
+
+		*ptep = npte;
+		PTE_SYNC(ptep);
+		if (is_cached) {
+			/*
+			 * We only need to frob the cache/tlb if this pmap
+			 * is current
+			 */
+			if (L1_IDX(va) != L1_IDX(vector_page) &&
+			    l2pte_valid(npte)) {
+				/*
+				 * This mapping is likely to be accessed as
+				 * soon as we return to userland. Fix up the
+				 * L1 entry to avoid taking another
+				 * page/domain fault.
+				 */
+				pd_entry_t *pl1pd, l1pd;
+
+				pl1pd = &pmap->pm_l1->l1_kva[L1_IDX(va)];
+				l1pd = l2b->l2b_phys | L1_C_DOM(pmap->pm_domain) |
+				    L1_C_PROTO;
+				if (*pl1pd != l1pd) {
+					*pl1pd = l1pd;
+					PTE_SYNC(pl1pd);
+				}
+			}
+		}
+
+		if (PV_BEEN_EXECD(oflags))
+			cpu_tlb_flushID_SE(va);
+		else if (PV_BEEN_REFD(oflags))
+			cpu_tlb_flushD_SE(va);
+	}
+}
+
+/*
+ * Maps a sequence of resident pages belonging to the same object.
+ * The sequence begins with the given page m_start.  This page is
+ * mapped at the given virtual address start.  Each subsequent page is
+ * mapped at a virtual address that is offset from start by the same
+ * amount as the page is offset from m_start within the object.  The
+ * last page in the sequence is the page with the largest offset from
+ * m_start that can be mapped at a virtual address less than the given
+ * virtual address end.  Not every virtual page between start and end
+ * is mapped; only those for which a resident page exists with the
+ * corresponding offset from m_start are mapped.
+ */
+void
+pmap_enter_object(pmap_t pmap, vm_offset_t start, vm_offset_t end,
+    vm_page_t m_start, vm_prot_t prot)
+{
+	vm_page_t m;
+	vm_pindex_t diff, psize;
+
+	psize = atop(end - start);
+	m = m_start;
+	vm_page_lock_queues();
+	PMAP_LOCK(pmap);
+	while (m != NULL && (diff = m->pindex - m_start->pindex) < psize) {
+		pmap_enter_locked(pmap, start + ptoa(diff), m, prot &
+		    (VM_PROT_READ | VM_PROT_EXECUTE), FALSE, M_NOWAIT);
+		m = TAILQ_NEXT(m, listq);
+	}
+	PMAP_UNLOCK(pmap);
+	vm_page_unlock_queues();
+}
+
+/*
+ * this code makes some *MAJOR* assumptions:
+ * 1. Current pmap & pmap exists.
+ * 2. Not wired.
+ * 3. Read access.
+ * 4. No page table pages.
+ * but is *MUCH* faster than pmap_enter...
+ */
+
+void
+pmap_enter_quick(pmap_t pmap, vm_offset_t va, vm_page_t m, vm_prot_t prot)
+{
+
+	vm_page_lock_queues();
+	PMAP_LOCK(pmap);
+	pmap_enter_locked(pmap, va, m, prot & (VM_PROT_READ | VM_PROT_EXECUTE),
+	    FALSE, M_NOWAIT);
+	PMAP_UNLOCK(pmap);
+	vm_page_unlock_queues();
+}
+
+/*
+ *	Routine:	pmap_change_wiring
+ *	Function:	Change the wiring attribute for a map/virtual-address
+ *			pair.
+ *	In/out conditions:
+ *			The mapping must already exist in the pmap.
+ */
+void
+pmap_change_wiring(pmap_t pmap, vm_offset_t va, boolean_t wired)
+{
+	struct l2_bucket *l2b;
+	pt_entry_t *ptep, pte;
+	vm_page_t pg;
+
+	vm_page_lock_queues();
+	PMAP_LOCK(pmap);
+	l2b = pmap_get_l2_bucket(pmap, va);
+	KASSERT(l2b, ("No l2b bucket in pmap_change_wiring"));
+	ptep = &l2b->l2b_kva[l2pte_index(va)];
+	pte = *ptep;
+	pg = PHYS_TO_VM_PAGE(l2pte_pa(pte));
+	if (pg)
+		pmap_modify_pv(pg, pmap, va, PVF_WIRED, wired);
+	vm_page_unlock_queues();
+	PMAP_UNLOCK(pmap);
+}
+
+
+/*
+ *	Copy the range specified by src_addr/len
+ *	from the source map to the range dst_addr/len
+ *	in the destination map.
+ *
+ *	This routine is only advisory and need not do anything.
+ */
+void
+pmap_copy(pmap_t dst_pmap, pmap_t src_pmap, vm_offset_t dst_addr,
+    vm_size_t len, vm_offset_t src_addr)
+{
+}
+
+
+/*
+ *	Routine:	pmap_extract
+ *	Function:
+ *		Extract the physical page address associated
+ *		with the given map/virtual_address pair.
+ */
+vm_paddr_t
+pmap_extract(pmap_t pm, vm_offset_t va)
+{
+	struct l2_dtable *l2;
+	pd_entry_t l1pd;
+	pt_entry_t *ptep, pte;
+	vm_paddr_t pa;
+	u_int l1idx;
+	l1idx = L1_IDX(va);
+
+	PMAP_LOCK(pm);
+	l1pd = pm->pm_l1->l1_kva[l1idx];
+	if (l1pte_section_p(l1pd)) {
+		/*
+		 * These should only happen for pmap_kernel()
+		 */
+		KASSERT(pm == pmap_kernel(), ("huh"));
+		/* XXX: what to do about the bits > 32 ? */
+		if (l1pd & L1_S_SUPERSEC)
+			pa = (l1pd & L1_SUP_FRAME) | (va & L1_SUP_OFFSET);
+		else
+			pa = (l1pd & L1_S_FRAME) | (va & L1_S_OFFSET);
+	} else {
+		/*
+		 * Note that we can't rely on the validity of the L1
+		 * descriptor as an indication that a mapping exists.
+		 * We have to look it up in the L2 dtable.
+		 */
+		l2 = pm->pm_l2[L2_IDX(l1idx)];
+
+		if (l2 == NULL ||
+		    (ptep = l2->l2_bucket[L2_BUCKET(l1idx)].l2b_kva) == NULL) {
+			PMAP_UNLOCK(pm);
+			return (0);
+		}
+
+		ptep = &ptep[l2pte_index(va)];
+		pte = *ptep;
+
+		if (pte == 0) {
+			PMAP_UNLOCK(pm);
+			return (0);
+		}
+
+		switch (pte & L2_TYPE_MASK) {
+		case L2_TYPE_L:
+			pa = (pte & L2_L_FRAME) | (va & L2_L_OFFSET);
+			break;
+
+		default:
+			pa = (pte & L2_S_FRAME) | (va & L2_S_OFFSET);
+			break;
+		}
+	}
+
+	PMAP_UNLOCK(pm);
+	return (pa);
+}
+
+/*
+ * Atomically extract and hold the physical page with the given
+ * pmap and virtual address pair if that mapping permits the given
+ * protection.
+ *
+ */
+vm_page_t
+pmap_extract_and_hold(pmap_t pmap, vm_offset_t va, vm_prot_t prot)
+{
+	struct l2_dtable *l2;
+	pd_entry_t l1pd;
+	pt_entry_t *ptep, pte;
+	vm_paddr_t pa, paddr;
+	vm_page_t m = NULL;
+	u_int l1idx;
+	l1idx = L1_IDX(va);
+	paddr = 0;
+
+	PMAP_LOCK(pmap);
+retry:
+	l1pd = pmap->pm_l1->l1_kva[l1idx];
+	if (l1pte_section_p(l1pd)) {
+		/*
+		 * These should only happen for pmap_kernel()
+		 */
+		KASSERT(pmap == pmap_kernel(), ("huh"));
+		/* XXX: what to do about the bits > 32 ? */
+		if (l1pd & L1_S_SUPERSEC)
+			pa = (l1pd & L1_SUP_FRAME) | (va & L1_SUP_OFFSET);
+		else
+			pa = (l1pd & L1_S_FRAME) | (va & L1_S_OFFSET);
+		if (vm_page_pa_tryrelock(pmap, pa & PG_FRAME, &paddr))
+			goto retry;
+		if (L1_S_WRITABLE(l1pd) || (prot & VM_PROT_WRITE) == 0) {
+			m = PHYS_TO_VM_PAGE(pa);
+			vm_page_hold(m);
+		}
+	} else {
+		/*
+		 * Note that we can't rely on the validity of the L1
+		 * descriptor as an indication that a mapping exists.
+		 * We have to look it up in the L2 dtable.
+		 */
+		l2 = pmap->pm_l2[L2_IDX(l1idx)];
+
+		if (l2 == NULL ||
+		    (ptep = l2->l2_bucket[L2_BUCKET(l1idx)].l2b_kva) == NULL) {
+			PMAP_UNLOCK(pmap);
+			return (NULL);
+		}
+
+		ptep = &ptep[l2pte_index(va)];
+		pte = *ptep;
+
+		if (pte == 0) {
+			PMAP_UNLOCK(pmap);
+			return (NULL);
+		} else if ((prot & VM_PROT_WRITE) && (pte & L2_APX)) {
+			PMAP_UNLOCK(pmap);
+			return (NULL);
+		} else {
+			switch (pte & L2_TYPE_MASK) {
+			case L2_TYPE_L:
+				panic("extract and hold section mapping");
+				break;
+			default:
+				pa = (pte & L2_S_FRAME) | (va & L2_S_OFFSET);
+				break;
+			}
+			if (vm_page_pa_tryrelock(pmap, pa & PG_FRAME, &paddr))
+				goto retry;
+			m = PHYS_TO_VM_PAGE(pa);
+			vm_page_hold(m);
+		}
+
+	}
+
+	PMAP_UNLOCK(pmap);
+	PA_UNLOCK_COND(paddr);
+	return (m);
+}
+
+/*
+ * Initialize a preallocated and zeroed pmap structure,
+ * such as one in a vmspace structure.
+ */
+
+int
+pmap_pinit(pmap_t pmap)
+{
+	PDEBUG(1, printf("pmap_pinit: pmap = %08x\n", (uint32_t) pmap));
+
+	PMAP_LOCK_INIT(pmap);
+	pmap_alloc_l1(pmap);
+	bzero(pmap->pm_l2, sizeof(pmap->pm_l2));
+
+	CPU_ZERO(&pmap->pm_active);
+
+	TAILQ_INIT(&pmap->pm_pvlist);
+	bzero(&pmap->pm_stats, sizeof pmap->pm_stats);
+	pmap->pm_stats.resident_count = 1;
+	if (vector_page < KERNBASE) {
+		pmap_enter(pmap, vector_page,
+		    VM_PROT_READ, PHYS_TO_VM_PAGE(systempage.pv_pa),
+		    VM_PROT_READ, 1);
+	}
+	return (1);
+}
+
+
+/***************************************************
+ * page management routines.
+ ***************************************************/
+
+
+static void
+pmap_free_pv_entry(pv_entry_t pv)
+{
+	pv_entry_count--;
+	uma_zfree(pvzone, pv);
+}
+
+
+/*
+ * get a new pv_entry, allocating a block from the system
+ * when needed.
+ * the memory allocation is performed bypassing the malloc code
+ * because of the possibility of allocations at interrupt time.
+ */
+static pv_entry_t
+pmap_get_pv_entry(void)
+{
+	pv_entry_t ret_value;
+
+	pv_entry_count++;
+	if (pv_entry_count > pv_entry_high_water)
+		pagedaemon_wakeup();
+	ret_value = uma_zalloc(pvzone, M_NOWAIT);
+	return ret_value;
+}
+
+/*
+ *	Remove the given range of addresses from the specified map.
+ *
+ *	It is assumed that the start and end are properly
+ *	rounded to the page size.
+ */
+#define	PMAP_REMOVE_CLEAN_LIST_SIZE	3
+void
+pmap_remove(pmap_t pm, vm_offset_t sva, vm_offset_t eva)
+{
+	struct l2_bucket *l2b;
+	vm_offset_t next_bucket;
+	pt_entry_t *ptep;
+	u_int total;
+	u_int mappings, is_exec, is_refd;
+	int flushall = 0;
+
+
+	/*
+	 * we lock in the pmap => pv_head direction
+	 */
+
+	vm_page_lock_queues();
+	PMAP_LOCK(pm);
+	total = 0;
+	while (sva < eva) {
+		/*
+		 * Do one L2 bucket's worth at a time.
+		 */
+		next_bucket = L2_NEXT_BUCKET(sva);
+		if (next_bucket > eva)
+			next_bucket = eva;
+
+		l2b = pmap_get_l2_bucket(pm, sva);
+		if (l2b == NULL) {
+			sva = next_bucket;
+			continue;
+		}
+
+		ptep = &l2b->l2b_kva[l2pte_index(sva)];
+		mappings = 0;
+
+		while (sva < next_bucket) {
+			struct vm_page *pg;
+			pt_entry_t pte;
+			vm_paddr_t pa;
+
+			pte = *ptep;
+
+			if (pte == 0) {
+				/*
+				 * Nothing here, move along
+				 */
+				sva += PAGE_SIZE;
+				ptep++;
+				continue;
+			}
+
+			pm->pm_stats.resident_count--;
+			pa = l2pte_pa(pte);
+			is_exec = 0;
+			is_refd = 1;
+
+			/*
+			 * Update flags. In a number of circumstances,
+			 * we could cluster a lot of these and do a
+			 * number of sequential pages in one go.
+			 */
+			if ((pg = PHYS_TO_VM_PAGE(pa)) != NULL) {
+				struct pv_entry *pve;
+
+				pve = pmap_remove_pv(pg, pm, sva);
+				if (pve) {
+					is_exec = PV_BEEN_EXECD(pve->pv_flags);
+					is_refd = PV_BEEN_REFD(pve->pv_flags);
+					pmap_free_pv_entry(pve);
+				}
+			}
+
+			if (pmap_is_current(pm)) {
+				total++;
+				if (total < PMAP_REMOVE_CLEAN_LIST_SIZE) {
+					if (is_exec)
+						cpu_tlb_flushID_SE(sva);
+					else if (is_refd)
+						cpu_tlb_flushD_SE(sva);
+				} else if (total == PMAP_REMOVE_CLEAN_LIST_SIZE) {
+					flushall = 1;
+				}
+			}
+			*ptep = 0;
+			PTE_SYNC(ptep);
+
+			sva += PAGE_SIZE;
+			ptep++;
+			mappings++;
+		}
+
+		pmap_free_l2_bucket(pm, l2b, mappings);
+	}
+
+	vm_page_unlock_queues();
+	if (flushall)
+		cpu_tlb_flushID();
+	PMAP_UNLOCK(pm);
+}
+
+/*
+ * pmap_zero_page()
+ *
+ * Zero a given physical page by mapping it at a page hook point.
+ * In doing the zero page op, the page we zero is mapped cachable, as with
+ * StrongARM accesses to non-cached pages are non-burst making writing
+ * _any_ bulk data very slow.
+ */
+static void
+pmap_zero_page_gen(vm_page_t pg, int off, int size)
+{
+
+	vm_paddr_t phys = VM_PAGE_TO_PHYS(pg);
+	if (!TAILQ_EMPTY(&pg->md.pv_list))
+		panic("pmap_zero_page: page has mappings");
+
+	mtx_lock(&cmtx);
+	/*
+	 * Hook in the page, zero it, invalidate the TLB as needed.
+	 *
+	 * Note the temporary zero-page mapping must be a non-cached page in
+	 * order to work without corruption when write-allocate is enabled.
+	 */
+	*cdst_pte = L2_S_PROTO | phys | pte_l2_s_cache_mode;
+	pmap_set_prot(cdst_pte, VM_PROT_WRITE, 0);
+	PTE_SYNC(cdst_pte);
+	cpu_tlb_flushD_SE(cdstp);
+	cpu_cpwait();
+	if (off || size != PAGE_SIZE)
+		bzero((void *)(cdstp + off), size);
+	else
+		bzero_page(cdstp);
+
+	mtx_unlock(&cmtx);
+}
+
+/*
+ *	pmap_zero_page zeros the specified hardware page by mapping
+ *	the page into KVM and using bzero to clear its contents.
+ */
+void
+pmap_zero_page(vm_page_t m)
+{
+	pmap_zero_page_gen(m, 0, PAGE_SIZE);
+}
+
+
+/*
+ *	pmap_zero_page_area zeros the specified hardware page by mapping
+ *	the page into KVM and using bzero to clear its contents.
+ *
+ *	off and size may not cover an area beyond a single hardware page.
+ */
+void
+pmap_zero_page_area(vm_page_t m, int off, int size)
+{
+
+	pmap_zero_page_gen(m, off, size);
+}
+
+
+/*
+ *	pmap_zero_page_idle zeros the specified hardware page by mapping
+ *	the page into KVM and using bzero to clear its contents.  This
+ *	is intended to be called from the vm_pagezero process only and
+ *	outside of Giant.
+ */
+void
+pmap_zero_page_idle(vm_page_t m)
+{
+
+	pmap_zero_page(m);
+}
+
+/*
+ *	pmap_copy_page copies the specified (machine independent)
+ *	page by mapping the page into virtual memory and using
+ *	bcopy to copy the page, one machine dependent page at a
+ *	time.
+ */
+
+/*
+ * pmap_copy_page()
+ *
+ * Copy one physical page into another, by mapping the pages into
+ * hook points. The same comment regarding cachability as in
+ * pmap_zero_page also applies here.
+ */
+void
+pmap_copy_page_generic(vm_paddr_t src, vm_paddr_t dst)
+{
+	/*
+	 * Hold the source page's lock for the duration of the copy
+	 * so that no other mappings can be created while we have a
+	 * potentially aliased mapping.
+	 * Map the pages into the page hook points, copy them, and purge
+	 * the cache for the appropriate page. Invalidate the TLB
+	 * as required.
+	 */
+	mtx_lock(&cmtx);
+
+	/* For ARMv6 using System bit is deprecated and mapping with AP
+	 * bits set to 0x0 makes page not accessible. csrc_pte is mapped
+	 * read/write until proper mapping defines are created for ARMv6.
+	 */
+	*csrc_pte = L2_S_PROTO | src | pte_l2_s_cache_mode;
+	pmap_set_prot(csrc_pte, VM_PROT_READ, 0);
+	PTE_SYNC(csrc_pte);
+
+	*cdst_pte = L2_S_PROTO | dst | pte_l2_s_cache_mode;
+	pmap_set_prot(cdst_pte, VM_PROT_READ | VM_PROT_WRITE, 0);
+	PTE_SYNC(cdst_pte);
+	cpu_tlb_flushD_SE(csrcp);
+	cpu_tlb_flushD_SE(cdstp);
+	cpu_cpwait();
+
+	bcopy_page(csrcp, cdstp);
+
+	mtx_unlock(&cmtx);
+}
+
+void
+pmap_copy_page(vm_page_t src, vm_page_t dst)
+{
+
+	if (_arm_memcpy && PAGE_SIZE >= _min_memcpy_size &&
+	    _arm_memcpy((void *)VM_PAGE_TO_PHYS(dst),
+	    (void *)VM_PAGE_TO_PHYS(src), PAGE_SIZE, IS_PHYSICAL) == 0)
+		return;
+
+	pmap_copy_page_generic(VM_PAGE_TO_PHYS(src), VM_PAGE_TO_PHYS(dst));
+}
+
+/*
+ * this routine returns true if a physical page resides
+ * in the given pmap.
+ */
+boolean_t
+pmap_page_exists_quick(pmap_t pmap, vm_page_t m)
+{
+	pv_entry_t pv;
+	int loops = 0;
+	boolean_t rv;
+
+	KASSERT((m->oflags & VPO_UNMANAGED) == 0,
+	    ("pmap_page_exists_quick: page %p is not managed", m));
+	rv = FALSE;
+	vm_page_lock_queues();
+	TAILQ_FOREACH(pv, &m->md.pv_list, pv_list) {
+		if (pv->pv_pmap == pmap) {
+			rv = TRUE;
+			break;
+		}
+		loops++;
+		if (loops >= 16)
+			break;
+	}
+
+	vm_page_unlock_queues();
+	return (rv);
+}
+
+/*
+ *	pmap_page_wired_mappings:
+ *
+ *	Return the number of managed mappings to the given physical page
+ *	that are wired.
+ */
+int
+pmap_page_wired_mappings(vm_page_t m)
+{
+	pv_entry_t pv;
+	int count;
+
+	count = 0;
+	if ((m->flags & PG_FICTITIOUS) != 0)
+		return (count);
+	vm_page_lock_queues();
+	TAILQ_FOREACH(pv, &m->md.pv_list, pv_list)
+		if ((pv->pv_flags & PVF_WIRED) != 0)
+			count++;
+	vm_page_unlock_queues();
+	return (count);
+}
+
+/*
+ *	pmap_is_referenced:
+ *
+ *	Return whether or not the specified physical page was referenced
+ *	in any physical maps.
+ */
+boolean_t
+pmap_is_referenced(vm_page_t m)
+{
+
+	KASSERT((m->oflags & VPO_UNMANAGED) == 0,
+	    ("pmap_is_referenced: page %p is not managed", m));
+	return ((m->md.pvh_attrs & PVF_REF) != 0);
+}
+
+/*
+ *	pmap_ts_referenced:
+ *
+ *	Return the count of reference bits for a page, clearing all of them.
+ */
+int
+pmap_ts_referenced(vm_page_t m)
+{
+
+	KASSERT((m->oflags & VPO_UNMANAGED) == 0,
+	    ("pmap_ts_referenced: page %p is not managed", m));
+	return (pmap_clearbit(m, PVF_REF));
+}
+
+
+boolean_t
+pmap_is_modified(vm_page_t m)
+{
+
+	KASSERT((m->oflags & VPO_UNMANAGED) == 0,
+	    ("pmap_is_modified: page %p is not managed", m));
+	if (m->md.pvh_attrs & PVF_MOD)
+		return (TRUE);
+
+	return(FALSE);
+}
+
+
+/*
+ *	Clear the modify bits on the specified physical page.
+ */
+void
+pmap_clear_modify(vm_page_t m)
+{
+
+	KASSERT((m->oflags & VPO_UNMANAGED) == 0,
+	    ("pmap_clear_modify: page %p is not managed", m));
+	VM_OBJECT_LOCK_ASSERT(m->object, MA_OWNED);
+	KASSERT((m->oflags & VPO_BUSY) == 0,
+	    ("pmap_clear_modify: page %p is busy", m));
+
+	/*
+	 * If the page is not PGA_WRITEABLE, then no mappings can be modified.
+	 * If the object containing the page is locked and the page is not
+	 * VPO_BUSY, then PGA_WRITEABLE cannot be concurrently set.
+	 */
+	if ((m->aflags & PGA_WRITEABLE) == 0)
+		return;
+
+	if (m->md.pvh_attrs & PVF_MOD)
+		pmap_clearbit(m, PVF_MOD);
+}
+
+
+/*
+ *	pmap_clear_reference:
+ *
+ *	Clear the reference bit on the specified physical page.
+ */
+void
+pmap_clear_reference(vm_page_t m)
+{
+
+	KASSERT((m->oflags & VPO_UNMANAGED) == 0,
+	    ("pmap_clear_reference: page %p is not managed", m));
+	if (m->md.pvh_attrs & PVF_REF)
+		pmap_clearbit(m, PVF_REF);
+}
+
+
+/*
+ * Clear the write and modified bits in each of the given page's mappings.
+ */
+void
+pmap_remove_write(vm_page_t m)
+{
+	KASSERT((m->oflags & VPO_UNMANAGED) == 0,
+	    ("pmap_remove_write: page %p is not managed", m));
+
+	/*
+	 * If the page is not VPO_BUSY, then PGA_WRITEABLE cannot be set by
+	 * another thread while the object is locked.  Thus, if PGA_WRITEABLE
+	 * is clear, no page table entries need updating.
+	 */
+	VM_OBJECT_LOCK_ASSERT(m->object, MA_OWNED);
+	if ((m->oflags & VPO_BUSY) != 0 ||
+	    (m->aflags & PGA_WRITEABLE) != 0)
+		pmap_clearbit(m, PVF_WRITE);
+}
+
+
+/*
+ * perform the pmap work for mincore
+ */
+int
+pmap_mincore(pmap_t pmap, vm_offset_t addr, vm_paddr_t *locked_pa)
+{
+	printf("pmap_mincore()\n");
+
+	return (0);
+}
+
+void
+pmap_sync_icache(pmap_t pm, vm_offset_t va, vm_size_t sz)
+{
+}
+
+/*
+ *	Increase the starting virtual address of the given mapping if a
+ *	different alignment might result in more superpage mappings.
+ */
+void
+pmap_align_superpage(vm_object_t object, vm_ooffset_t offset,
+    vm_offset_t *addr, vm_size_t size)
+{
+}
+
+
+/*
+ * Map a set of physical memory pages into the kernel virtual
+ * address space. Return a pointer to where it is mapped. This
+ * routine is intended to be used for mapping device memory,
+ * NOT real memory.
+ */
+void *
+pmap_mapdev(vm_offset_t pa, vm_size_t size)
+{
+	vm_offset_t va, tmpva, offset;
+
+	offset = pa & PAGE_MASK;
+	size = roundup(size, PAGE_SIZE);
+
+	GIANT_REQUIRED;
+
+	va = kmem_alloc_nofault(kernel_map, size);
+	if (!va)
+		panic("pmap_mapdev: Couldn't alloc kernel virtual memory");
+	for (tmpva = va; size > 0;) {
+		pmap_kenter_internal(tmpva, pa, 0);
+		size -= PAGE_SIZE;
+		tmpva += PAGE_SIZE;
+		pa += PAGE_SIZE;
+	}
+
+	return ((void *)(va + offset));
+}
+
+/*
+ * pmap_map_section:
+ *
+ *	Create a single section mapping.
+ */
+void
+pmap_map_section(vm_offset_t l1pt, vm_offset_t va, vm_offset_t pa,
+    int prot, int cache)
+{
+	pd_entry_t *pde = (pd_entry_t *) l1pt;
+	pd_entry_t fl;
+
+	KASSERT(((va | pa) & L1_S_OFFSET) == 0, ("ouin2"));
+
+	fl = l1_mem_types[cache];
+
+	pde[va >> L1_S_SHIFT] = L1_S_PROTO | pa |
+	    L1_S_PROT(PTE_KERNEL, prot) | fl | L1_S_DOM(PMAP_DOMAIN_KERNEL);
+	PTE_SYNC(&pde[va >> L1_S_SHIFT]);
+}
+
+/*
+ * pmap_link_l2pt:
+ *
+ *	Link the L2 page table specified by l2pv.pv_pa into the L1
+ *	page table at the slot for "va".
+ */
+void
+pmap_link_l2pt(vm_offset_t l1pt, vm_offset_t va, struct pv_addr *l2pv)
+{
+	pd_entry_t *pde = (pd_entry_t *) l1pt, proto;
+	u_int slot = va >> L1_S_SHIFT;
+
+	proto = L1_S_DOM(PMAP_DOMAIN_KERNEL) | L1_C_PROTO;
+
+#ifdef VERBOSE_INIT_ARM
+	printf("pmap_link_l2pt: pa=0x%x va=0x%x\n", l2pv->pv_pa, l2pv->pv_va);
+#endif
+
+	pde[slot + 0] = proto | (l2pv->pv_pa + 0x000);
+	PTE_SYNC(&pde[slot]);
+
+	SLIST_INSERT_HEAD(&kernel_pt_list, l2pv, pv_list);
+
+}
+
+/*
+ * pmap_map_entry
+ *
+ *	Create a single page mapping.
+ */
+void
+pmap_map_entry(vm_offset_t l1pt, vm_offset_t va, vm_offset_t pa, int prot,
+    int cache)
+{
+	pd_entry_t *pde = (pd_entry_t *) l1pt;
+	pt_entry_t fl;
+	pt_entry_t *pte;
+
+	KASSERT(((va | pa) & PAGE_MASK) == 0, ("ouin"));
+
+	fl = l2s_mem_types[cache];
+
+	if ((pde[va >> L1_S_SHIFT] & L1_TYPE_MASK) != L1_TYPE_C)
+		panic("pmap_map_entry: no L2 table for VA 0x%08x", va);
+
+	pte = (pt_entry_t *) kernel_pt_lookup(pde[L1_IDX(va)] & L1_C_ADDR_MASK);
+
+	if (pte == NULL)
+		panic("pmap_map_entry: can't find L2 table for VA 0x%08x", va);
+
+	pte[l2pte_index(va)] = L2_S_PROTO | pa | fl;
+	pmap_set_prot(&pte[l2pte_index(va)], prot, 0);
+	PTE_SYNC(&pte[l2pte_index(va)]);
+}
+
+/*
+ * pmap_map_chunk:
+ *
+ *	Map a chunk of memory using the most efficient mappings
+ *	possible (section. large page, small page) into the
+ *	provided L1 and L2 tables at the specified virtual address.
+ */
+vm_size_t
+pmap_map_chunk(vm_offset_t l1pt, vm_offset_t va, vm_offset_t pa,
+    vm_size_t size, int prot, int type)
+{
+	pd_entry_t *pde = (pd_entry_t *) l1pt;
+	pt_entry_t *pte, f1, f2s, f2l;
+	vm_size_t resid;
+	int i;
+
+	resid = (size + (PAGE_SIZE - 1)) & ~(PAGE_SIZE - 1);
+
+	if (l1pt == 0)
+		panic("pmap_map_chunk: no L1 table provided");
+
+#ifdef VERBOSE_INIT_ARM
+	printf("pmap_map_chunk: pa=0x%x va=0x%x size=0x%x resid=0x%x "
+	    "prot=0x%x type=%d\n", pa, va, size, resid, prot, type);
+#endif
+
+	f1 = l1_mem_types[type];
+	f2l = l2l_mem_types[type];
+	f2s = l2s_mem_types[type];
+
+	size = resid;
+
+	while (resid > 0) {
+		/* See if we can use a section mapping. */
+		if (L1_S_MAPPABLE_P(va, pa, resid)) {
+#ifdef VERBOSE_INIT_ARM
+			printf("S");
+#endif
+			pde[va >> L1_S_SHIFT] = L1_S_PROTO | pa |
+			    L1_S_PROT(PTE_KERNEL, prot) | f1 |
+			    L1_S_DOM(PMAP_DOMAIN_KERNEL);
+			PTE_SYNC(&pde[va >> L1_S_SHIFT]);
+			va += L1_S_SIZE;
+			pa += L1_S_SIZE;
+			resid -= L1_S_SIZE;
+			continue;
+		}
+
+		/*
+		 * Ok, we're going to use an L2 table.  Make sure
+		 * one is actually in the corresponding L1 slot
+		 * for the current VA.
+		 */
+		if ((pde[va >> L1_S_SHIFT] & L1_TYPE_MASK) != L1_TYPE_C)
+			panic("pmap_map_chunk: no L2 table for VA 0x%08x", va);
+
+		pte = (pt_entry_t *) kernel_pt_lookup(
+		    pde[L1_IDX(va)] & L1_C_ADDR_MASK);
+		if (pte == NULL)
+			panic("pmap_map_chunk: can't find L2 table for VA"
+			    "0x%08x", va);
+		/* See if we can use a L2 large page mapping. */
+		if (L2_L_MAPPABLE_P(va, pa, resid)) {
+#ifdef VERBOSE_INIT_ARM
+			printf("L");
+#endif
+			for (i = 0; i < 16; i++) {
+				pte[l2pte_index(va) + i] =
+				    L2_L_PROTO | pa |
+				    L2_L_PROT(PTE_KERNEL, prot) | f2l;
+				PTE_SYNC(&pte[l2pte_index(va) + i]);
+			}
+			va += L2_L_SIZE;
+			pa += L2_L_SIZE;
+			resid -= L2_L_SIZE;
+			continue;
+		}
+
+		/* Use a small page mapping. */
+#ifdef VERBOSE_INIT_ARM
+		printf("P");
+#endif
+		pte[l2pte_index(va)] = L2_S_PROTO | pa | f2s;
+		pmap_set_prot(&pte[l2pte_index(va)], prot, 0);
+		PTE_SYNC(&pte[l2pte_index(va)]);
+		va += PAGE_SIZE;
+		pa += PAGE_SIZE;
+		resid -= PAGE_SIZE;
+	}
+#ifdef VERBOSE_INIT_ARM
+	printf("\n");
+#endif
+	return (size);
+
+}
+
+/********************** Static device map routines ***************************/
+
+static const struct pmap_devmap *pmap_devmap_table;
+
+/*
+ * Register the devmap table.  This is provided in case early console
+ * initialization needs to register mappings created by bootstrap code
+ * before pmap_devmap_bootstrap() is called.
+ */
+void
+pmap_devmap_register(const struct pmap_devmap *table)
+{
+
+	pmap_devmap_table = table;
+}
+
+/*
+ * Map all of the static regions in the devmap table, and remember
+ * the devmap table so other parts of the kernel can look up entries
+ * later.
+ */
+void
+pmap_devmap_bootstrap(vm_offset_t l1pt, const struct pmap_devmap *table)
+{
+	int i;
+
+	pmap_devmap_table = table;
+
+	for (i = 0; pmap_devmap_table[i].pd_size != 0; i++) {
+#ifdef VERBOSE_INIT_ARM
+		printf("devmap: %08x -> %08x @ %08x\n",
+		    pmap_devmap_table[i].pd_pa,
+		    pmap_devmap_table[i].pd_pa +
+			pmap_devmap_table[i].pd_size - 1,
+		    pmap_devmap_table[i].pd_va);
+#endif
+		pmap_map_chunk(l1pt, pmap_devmap_table[i].pd_va,
+		    pmap_devmap_table[i].pd_pa,
+		    pmap_devmap_table[i].pd_size,
+		    pmap_devmap_table[i].pd_prot,
+		    pmap_devmap_table[i].pd_cache);
+	}
+}
+
+const struct pmap_devmap *
+pmap_devmap_find_pa(vm_paddr_t pa, vm_size_t size)
+{
+	int i;
+
+	if (pmap_devmap_table == NULL)
+		return (NULL);
+
+	for (i = 0; pmap_devmap_table[i].pd_size != 0; i++) {
+		if (pa >= pmap_devmap_table[i].pd_pa &&
+		    pa + size <= pmap_devmap_table[i].pd_pa +
+				 pmap_devmap_table[i].pd_size)
+			return (&pmap_devmap_table[i]);
+	}
+
+	return (NULL);
+}
+
+const struct pmap_devmap *
+pmap_devmap_find_va(vm_offset_t va, vm_size_t size)
+{
+	int i;
+
+	if (pmap_devmap_table == NULL)
+		return (NULL);
+
+	for (i = 0; pmap_devmap_table[i].pd_size != 0; i++) {
+		if (va >= pmap_devmap_table[i].pd_va &&
+		    va + size <= pmap_devmap_table[i].pd_va +
+				 pmap_devmap_table[i].pd_size)
+			return (&pmap_devmap_table[i]);
+	}
+
+	return (NULL);
+}
+
+int
+pmap_dmap_iscurrent(pmap_t pmap)
+{
+	return(pmap_is_current(pmap));
+}
+
diff -r 7fffa673adcd -r a301a330526b head/sys/arm/arm/pmap.c
--- a/head/sys/arm/arm/pmap.c	Wed Aug 15 11:15:12 2012 +0300
+++ b/head/sys/arm/arm/pmap.c	Wed Aug 15 11:16:36 2012 +0300
@@ -140,7 +140,7 @@
 #include "opt_vm.h"
 
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD: head/sys/arm/arm/pmap.c 239065 2012-08-05 14:11:42Z kib $");
+__FBSDID("$FreeBSD: head/sys/arm/arm/pmap.c 239268 2012-08-15 03:03:03Z gonzo $");
 #include <sys/param.h>
 #include <sys/systm.h>
 #include <sys/kernel.h>
@@ -3243,15 +3243,13 @@
 				*ptep = pte;
 				PTE_SYNC(ptep);
 
-				if (pg != NULL) {
-					if (!(pg->oflags & VPO_UNMANAGED)) {
-						f = pmap_modify_pv(pg, pm, sva,
-						    PVF_WRITE, 0);
+				if (!(pg->oflags & VPO_UNMANAGED)) {
+					f = pmap_modify_pv(pg, pm, sva,
+					    PVF_WRITE, 0);
+					if (f & PVF_WRITE)
 						vm_page_dirty(pg);
-					} else
-						f = 0;
 				} else
-					f = PVF_REF | PVF_EXEC;
+					f = 0;
 
 				if (flush >= 0) {
 					flush++;
diff -r 7fffa673adcd -r a301a330526b head/sys/arm/arm/swtch.S
--- a/head/sys/arm/arm/swtch.S	Wed Aug 15 11:15:12 2012 +0300
+++ b/head/sys/arm/arm/swtch.S	Wed Aug 15 11:16:36 2012 +0300
@@ -83,66 +83,57 @@
 #include <machine/asm.h>
 #include <machine/asmacros.h>
 #include <machine/armreg.h>
-__FBSDID("$FreeBSD: head/sys/arm/arm/swtch.S 236991 2012-06-13 04:59:55Z imp $");
-
-
-/*
- * New experimental definitions of IRQdisable and IRQenable
- * These keep FIQ's enabled since FIQ's are special.
- */
+__FBSDID("$FreeBSD: head/sys/arm/arm/swtch.S 239268 2012-08-15 03:03:03Z gonzo $");
 
 #define DOMAIN_CLIENT	0x01
-#define IRQdisable \
-	mrs	r14, cpsr ; \
-	orr	r14, r14, #(I32_bit) ; \
-	msr	cpsr_c, r14 ; \
 
-#define IRQenable \
-	mrs	r14, cpsr ; \
-	bic	r14, r14, #(I32_bit) ; \
-	msr	cpsr_c, r14 ; \
+#ifdef _ARM_ARCH_6
+#define GET_PCPU(tmp) \
+	mrc p15, 0, tmp, c13, c0, 4;
+#else
+.Lcurpcpu:
+	.word	_C_LABEL(__pcpu)
 
-/*
- * These are used for switching the translation table/DACR.
- * Since the vector page can be invalid for a short time, we must
- * disable both regular IRQs *and* FIQs.
- *
- * XXX: This is not necessary if the vector table is relocated.
- */
-#define IRQdisableALL \
-	mrs	r14, cpsr ; \
-	orr	r14, r14, #(I32_bit | F32_bit) ; \
-	msr	cpsr_c, r14
+#define GET_PCPU(tmp) \
+	ldr	tmp, .Lcurpcpu
+#endif
 
-#define IRQenableALL \
-	mrs	r14, cpsr ; \
-	bic	r14, r14, #(I32_bit | F32_bit) ; \
-	msr	cpsr_c, r14
-	
-.Lcurpcb:
-	.word	_C_LABEL(__pcpu) + PC_CURPCB
 .Lcpufuncs:	
 	.word	_C_LABEL(cpufuncs)
-.Lblock_userspace_access:
-	.word	_C_LABEL(block_userspace_access)
-.Lcpu_do_powersave:
-	.word	_C_LABEL(cpu_do_powersave)
 .Lblocked_lock:
 	.word	_C_LABEL(blocked_lock)
+
 ENTRY(cpu_throw)
 	mov	r5, r1
 
 	/*
+	 * r0 = oldtd
 	 * r5 = newtd
 	 */
 
+	GET_PCPU(r7)
+
+#ifdef ARM_VFP_SUPPORT
+	/*
+	 * vfp_discard will clear pcpu->pc_vfpcthread, and modify
+	 * and modify the control as needed.
+	 */
+	ldr     r4, [r7, #(PC_VFPCTHREAD)]      /* this thread using vfp? */
+	cmp     r0, r4
+	bne     3f
+	bl      _C_LABEL(vfp_discard)           /* yes, shut down vfp */
+3:
+#endif		/* ARM_VFP_SUPPORT */
+
 	ldr	r7, [r5, #(TD_PCB)]		/* r7 = new thread's PCB */
-
+  
 	/* Switch to lwp0 context */
 
 	ldr	r9, .Lcpufuncs
+#if !defined(CPU_ARM11) && !defined(CPU_CORTEXA) && !defined(CPU_MV_PJ4B)
 	mov	lr, pc
 	ldr	pc, [r9, #CF_IDCACHE_WBINV_ALL]
+#endif
 	ldr	r0, [r7, #(PCB_PL1VEC)]
 	ldr	r1, [r7, #(PCB_DACR)]
 	/*
@@ -200,21 +191,24 @@
 #endif
 
 	/* We have a new curthread now so make a note it */
-	ldr	r6, .Lcurthread
+	GET_CURTHREAD_PTR(r6)
 	str	r5, [r6]
 
 	/* Set the new tp */
 	ldr	r6, [r5, #(TD_MD + MD_TP)]
+#ifdef ARM_TP_ADDRESS
 	ldr	r4, =ARM_TP_ADDRESS
 	str	r6, [r4]
 	ldr	r6, [r5, #(TD_MD + MD_RAS_START)]
 	str	r6, [r4, #4] /* ARM_RAS_START */
 	ldr	r6, [r5, #(TD_MD + MD_RAS_END)]
 	str	r6, [r4, #8] /* ARM_RAS_END */
-
+#else
+	mcr p15, 0, r6, c13, c0, 3
+#endif
 	/* Hook in a new pcb */
-	ldr	r6, .Lcurpcb
-	str	r7, [r6]
+	GET_PCPU(r6)
+	str	r7, [r6, #PC_CURPCB]
 
 	ldmfd	sp!, {r4-r7, pc}
 
@@ -226,22 +220,15 @@
 	/* rem: r0 = old lwp */
 	/* rem: interrupts are disabled */
 
-#ifdef MULTIPROCESSOR
-	/* XXX use curcpu() */
-	ldr	r2, .Lcpu_info_store
-	str	r2, [r6, #(L_CPU)]
-#endif
-
 	/* Process is now on a processor. */
-
 	/* We have a new curthread now so make a note it */
-	ldr	r7, .Lcurthread
+	GET_CURTHREAD_PTR(r7)
 	str	r1, [r7]
 
 	/* Hook in a new pcb */
-	ldr	r7, .Lcurpcb
+	GET_PCPU(r7)
 	ldr	r2, [r1, #TD_PCB]
-	str	r2, [r7]
+	str	r2, [r7, #PC_CURPCB]
 
 	/* rem: r1 = new process */
 	/* rem: interrupts are enabled */
@@ -267,6 +254,7 @@
 	 * NOTE: We can now use r8-r13 until it is time to restore
 	 * them for the new process.
 	 */
+#ifdef ARM_TP_ADDRESS
 	/* Store the old tp */
 	ldr	r3, =ARM_TP_ADDRESS
 	ldr	r9, [r3]
@@ -283,12 +271,19 @@
 	str	r9, [r3, #4]
 	ldr	r9, [r1, #(TD_MD + MD_RAS_END)]
 	str	r9, [r3, #8]
+#else
+	/* Store the old tp */
+	mrc p15, 0, r9, c13, c0, 3
+	str	r9, [r0, #(TD_MD + MD_TP)]
 
+	/* Set the new tp */
+	ldr	r9, [r1, #(TD_MD + MD_TP)]
+	mcr p15, 0, r9, c13, c0, 3
+#endif
+	
 	/* Get the user structure for the new process in r9 */
 	ldr	r9, [r1, #(TD_PCB)]
 
-	/* r1 now free! */
-
         mrs	r3, cpsr
 	/*
 	 * We can do that, since
@@ -300,15 +295,39 @@
 	str	sp, [r2, #(PCB_UND_SP)]
 
         msr	cpsr_c, r3		/* Restore the old mode */
-	/* rem: r8 = old PCB */
+	/* rem: r2 = old PCB */
 	/* rem: r9 = new PCB */
 	/* rem: interrupts are enabled */
 
-	/* What else needs to be saved  Only FPA stuff when that is supported */
+#ifdef ARM_VFP_SUPPORT
+	/*
+	 * vfp_store will clear pcpu->pc_vfpcthread, save 
+	 * registers and state, and modify the control as needed.
+	 * a future exception will bounce the backup settings in the fp unit.
+	 * XXX vfp_store can't change r4
+	 */
+	GET_PCPU(r7)
+	ldr	r8, [r7, #(PC_VFPCTHREAD)]
+	cmp	r4, r8				/* old thread used vfp? */
+	bne	1f				/* no, don't save */
+	cmp	r1, r4				/* same thread ? */
+	beq	1f				/* yes, skip vfp store */
+#ifdef SMP
+	ldr	r8, [r7, #(PC_CPU)]		/* last used on this cpu? */
+	ldr	r3, [r2, #(PCB_VFPCPU)]
+	cmp	r8, r3		/* last cpu to use these registers? */
+	bne	1f		/* no. these values are stale */
+#endif
+	add	r0, r2, #(PCB_VFPSTATE)
+	bl	_C_LABEL(vfp_store)
+1:
+#endif		/* ARM_VFP_SUPPORT */
+
+	/* r1 now free! */
 
 	/* Third phase : restore saved context */
 
-	/* rem: r8 = old PCB */
+	/* rem: r2 = old PCB */
 	/* rem: r9 = new PCB */
 	/* rem: interrupts are enabled */
 
@@ -333,6 +352,7 @@
 	cmpeq	r0, r5				/* Same DACR? */
 	beq	.Lcs_context_switched		/* yes! */
 
+#if !defined(CPU_ARM11) && !defined(CPU_CORTEXA) && !defined(CPU_MV_PJ4B)
 	/*
 	 * Definately need to flush the cache.
 	 */
@@ -340,6 +360,7 @@
 	ldr	r1, .Lcpufuncs
 	mov	lr, pc
 	ldr	pc, [r1, #CF_IDCACHE_WBINV_ALL]
+#endif
 .Lcs_cache_purge_skipped:
 	/* rem: r6 = lock */
 	/* rem: r9 = new PCB */
@@ -408,8 +429,7 @@
 	/* Release the old thread */
 	str	r6, [r4, #TD_LOCK]
 	ldr	r6, .Lblocked_lock
-	ldr	r3, .Lcurthread
-	ldr	r3, [r3]
+	GET_CURTHREAD_PTR(r3)
 
 1:
 	ldr	r4, [r3, #TD_LOCK]
@@ -484,6 +504,27 @@
 	/* Store all the registers in the process's pcb */
 	add	r2, r0, #(PCB_R8)
 	stmia	r2, {r8-r13}
+#ifdef ARM_VFP_SUPPORT
+	/*
+	 * vfp_store will clear pcpu->pc_vfpcthread, save 
+	 * registers and state, and modify the control as needed.
+	 * a future exception will bounce the backup settings in the fp unit.
+	 */
+	GET_PCPU(r7)
+	ldr	r4, [r7, #(PC_VFPCTHREAD)]      /* vfp thread */
+	ldr	r2, [r7, #(PC_CURTHREAD)]       /* current thread */
+	cmp	r4, r2
+	bne	1f
+#ifdef SMP
+	ldr	r2, [r7, #(PC_CPU)]     /* last used on this cpu? */
+	ldr	r3, [r0, #(PCB_VFPCPU)]
+	cmp	r2, r3
+	bne	1f              /* no. these values are stale */
+#endif
+	add	r0, r0, #(PCB_VFPSTATE)
+	bl	_C_LABEL(vfp_store)
+1:
+#endif		/* ARM_VFP_SUPPORT */
 	ldmfd	sp!, {r4-r7, pc}
 
 ENTRY(fork_trampoline)
diff -r 7fffa673adcd -r a301a330526b head/sys/arm/arm/sys_machdep.c
--- a/head/sys/arm/arm/sys_machdep.c	Wed Aug 15 11:15:12 2012 +0300
+++ b/head/sys/arm/arm/sys_machdep.c	Wed Aug 15 11:16:36 2012 +0300
@@ -34,7 +34,7 @@
  */
 
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD: head/sys/arm/arm/sys_machdep.c 236991 2012-06-13 04:59:55Z imp $");
+__FBSDID("$FreeBSD: head/sys/arm/arm/sys_machdep.c 239268 2012-08-15 03:03:03Z gonzo $");
 
 #include "opt_capsicum.h"
 
@@ -88,7 +88,14 @@
 arm32_set_tp(struct thread *td, void *args)
 {
 
-	td->td_md.md_tp = (register_t)args;
+	if (td != curthread)
+		td->td_md.md_tp = (register_t)args;
+	else 
+#ifndef ARM_TP_ADDRESS
+		set_tls(args);
+#else
+		*(register_t *)ARM_TP_ADDRESS = (register_t)args;
+#endif
 	return (0);
 }
 
@@ -96,7 +103,14 @@
 arm32_get_tp(struct thread *td, void *args)
 {
 
-	td->td_retval[0] = td->td_md.md_tp;
+	if (td != curthread)
+		td->td_retval[0] = td->td_md.md_tp;
+	else
+#ifndef ARM_TP_ADDRESS
+		td->td_retval[0] = (register_t)get_tls();
+#else
+		td->td_retval[0] = *(register_t *)ARM_TP_ADDRESS;
+#endif
 	return (0);
 }
 
diff -r 7fffa673adcd -r a301a330526b head/sys/arm/arm/trap.c
--- a/head/sys/arm/arm/trap.c	Wed Aug 15 11:15:12 2012 +0300
+++ b/head/sys/arm/arm/trap.c	Wed Aug 15 11:16:36 2012 +0300
@@ -82,7 +82,7 @@
 #include "opt_ktrace.h"
 
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD: head/sys/arm/arm/trap.c 236991 2012-06-13 04:59:55Z imp $");
+__FBSDID("$FreeBSD: head/sys/arm/arm/trap.c 239191 2012-08-11 05:58:56Z andrew $");
 
 #include <sys/param.h>
 #include <sys/systm.h>
@@ -900,14 +900,13 @@
 #include "../../kern/subr_syscall.c"
 
 static void
-syscall(struct thread *td, trapframe_t *frame, u_int32_t insn)
+syscall(struct thread *td, trapframe_t *frame)
 {
 	struct syscall_args sa;
 	int error;
 
-	td->td_frame = frame;
-	sa.insn = insn;
-	switch (insn & SWI_OS_MASK) {
+	sa.insn = *(uint32_t *)(frame->tf_pc - INSN_SIZE);
+	switch (sa.insn & SWI_OS_MASK) {
 	case 0: /* XXX: we need our own one. */
 		sa.nap = 4;
 		break;
@@ -927,7 +926,6 @@
 swi_handler(trapframe_t *frame)
 {
 	struct thread *td = curthread;
-	uint32_t insn;
 
 	td->td_frame = frame;
 	
@@ -941,7 +939,6 @@
 		userret(td, frame);
 		return;
 	}
-	insn = *(u_int32_t *)(frame->tf_pc - INSN_SIZE);
 	/*
 	 * Enable interrupts if they were enabled before the exception.
 	 * Since all syscalls *should* come from user mode it will always
@@ -954,6 +951,6 @@
 			enable_interrupts(F32_bit);
 	}
 
-	syscall(td, frame, insn);
+	syscall(td, frame);
 }
 
diff -r 7fffa673adcd -r a301a330526b head/sys/arm/arm/undefined.c
--- a/head/sys/arm/arm/undefined.c	Wed Aug 15 11:15:12 2012 +0300
+++ b/head/sys/arm/arm/undefined.c	Wed Aug 15 11:16:36 2012 +0300
@@ -48,7 +48,7 @@
 #include "opt_ddb.h"
 
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD: head/sys/arm/arm/undefined.c 236991 2012-06-13 04:59:55Z imp $");
+__FBSDID("$FreeBSD: head/sys/arm/arm/undefined.c 239268 2012-08-15 03:03:03Z gonzo $");
 
 #include <sys/param.h>
 #include <sys/malloc.h>
@@ -237,10 +237,16 @@
 	 * instruction trap.
 	 */
 
+	coprocessor = 0;
 	if ((fault_instruction & (1 << 27)) != 0)
 		coprocessor = (fault_instruction >> 8) & 0x0f;
-	else
-		coprocessor = 0;
+#ifdef ARM_VFP_SUPPORT
+	else {          /* check for special instructions */
+		if (((fault_instruction & 0xfe000000) == 0xf2000000) ||
+		    ((fault_instruction & 0xff100000) == 0xf4000000))
+			coprocessor = 10;       /* vfp / simd */
+	}
+#endif	/* ARM_VFP_SUPPORT */
 
 	if ((frame->tf_spsr & PSR_MODE) == PSR_USR32_MODE) {
 		/*
diff -r 7fffa673adcd -r a301a330526b head/sys/arm/arm/vfp.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/head/sys/arm/arm/vfp.c	Wed Aug 15 11:16:36 2012 +0300
@@ -0,0 +1,260 @@
+/*
+ * Copyright (c) 2012 Mark Tinguely
+ *
+ * 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.
+ */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: head/sys/arm/arm/vfp.c 239268 2012-08-15 03:03:03Z gonzo $");
+
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/proc.h>
+#include <sys/kernel.h>
+
+#include <machine/fp.h>
+#include <machine/pcb.h>
+#include <machine/undefined.h>
+#include <machine/vfp.h>
+
+/* function prototypes */
+unsigned int get_coprocessorACR(void);
+int	vfp_bounce(u_int, u_int, struct trapframe *, int);
+void	vfp_discard(void);
+void	vfp_enable(void);
+void	vfp_init(void);
+void	vfp_restore(struct vfp_state *);
+void	vfp_store(struct vfp_state *);
+void	set_coprocessorACR(u_int);
+
+boolean_t vfp_exists;
+static struct undefined_handler vfp10_uh, vfp11_uh;
+
+/* The VFMXR command using coprocessor commands */
+#define fmxr(reg, val) \
+	__asm __volatile("mcr p10, 7, %0, " #reg " , c0, 0" :: "r" (val));
+
+/* The VFMRX command using coprocessor commands */
+#define fmrx(reg) \
+({ u_int val = 0;\
+	__asm __volatile("mrc p10, 7, %0, " #reg " , c0, 0" : "=r" (val));\
+	val; \
+})
+
+u_int
+get_coprocessorACR(void)
+{
+	u_int val;
+	__asm __volatile("mrc p15, 0, %0, c1, c0, 2" : "=r" (val) : : "cc");
+	return val;
+}
+
+void
+set_coprocessorACR(u_int val)
+{
+	__asm __volatile("mcr p15, 0, %0, c1, c0, 2\n\t"
+			 "isb\n\t"
+	 : : "r" (val) : "cc");
+}
+
+
+	/* called for each cpu */
+void
+vfp_init(void)
+{
+	u_int fpsid, fpexc, tmp;
+	u_int coproc;
+
+	coproc = get_coprocessorACR();
+	coproc |= COPROC10 | COPROC11;
+	set_coprocessorACR(coproc);
+	
+	fpsid = fmrx(cr0);		/* read the vfp system id */
+	fpexc = fmrx(cr8);		/* read the vfp exception reg */
+
+	if (!(fpsid & VFPSID_HARDSOFT_IMP)) {
+		vfp_exists = 1;
+		PCPU_SET(vfpsid, fpsid);	/* save the VFPSID */
+		if ((fpsid & VFPSID_SUBVERSION2_MASK) == VFP_ARCH3) {
+			tmp = fmrx(cr7);	/* extended registers */
+			PCPU_SET(vfpmvfr0, tmp);
+			tmp = fmrx(cr6);	/* extended registers */
+			PCPU_SET(vfpmvfr1, tmp);
+		}
+		/* initialize the coprocess 10 and 11 calls
+		 * These are called to restore the registers and enable
+		 * the VFP hardware.
+		 */
+		if (vfp10_uh.uh_handler == NULL) {
+			vfp10_uh.uh_handler = vfp_bounce;
+			vfp11_uh.uh_handler = vfp_bounce;
+			install_coproc_handler_static(10, &vfp10_uh);
+			install_coproc_handler_static(11, &vfp11_uh);
+		}
+	}
+}
+
+SYSINIT(vfp, SI_SUB_CPU, SI_ORDER_ANY, vfp_init, NULL);
+
+
+/* start VFP unit, restore the vfp registers from the PCB  and retry
+ * the instruction
+ */
+int
+vfp_bounce(u_int addr, u_int insn, struct trapframe *frame, int code)
+{
+	u_int fpexc;
+	struct pcb *curpcb;
+	struct thread *vfptd;
+
+	if (!vfp_exists)
+		return 1;		/* vfp does not exist */
+	fpexc = fmrx(cr8);		/* read the vfp exception reg */
+	if (fpexc & VFPEXC_EN) {
+		vfptd = PCPU_GET(vfpcthread);
+		/* did the kernel call the vfp or exception that expect us
+		 * to emulate the command. Newer hardware does not require
+		 * emulation, so we don't emulate yet.
+		 */
+#ifdef SMP
+		/* don't save if newer registers are on another processor */
+		if (vfptd /* && (vfptd == curthread) */ &&
+		   (vfptd->td_pcb->pcb_vfpcpu == PCPU_GET(vfpcpu))
+#else
+		/* someone did not save their registers, */
+		if (vfptd /* && (vfptd == curthread) */)
+#endif
+			vfp_store(&vfptd->td_pcb->pcb_vfpstate);
+
+		fpexc &= ~VFPEXC_EN;
+		fmxr(cr8, fpexc);	/* turn vfp hardware off */
+		if (vfptd == curthread) {
+			/* kill the process - we do not handle emulation */
+			killproc(curthread->td_proc, "vfp emulation");
+			return 1;
+		}
+		/* should not happen. someone did not save their context */
+		printf("vfp_bounce: vfpcthread: %p curthread: %p\n",
+			vfptd, curthread);
+	}
+	fpexc |= VFPEXC_EN;
+	fmxr(cr8, fpexc);	/* enable the vfp and repeat command */
+	curpcb = PCPU_GET(curpcb);
+	/* If we were the last process to use the VFP, the process did not
+	 * use a VFP on another processor, then the registers in the VFP
+	 * will still be ours and are current. Eventually, we will make the
+	 * restore smarter.
+	 */
+	vfp_restore(&curpcb->pcb_vfpstate);
+#ifdef SMP
+	curpcb->pcb_cpu = PCPU_GET(cpu);
+#endif
+	PCPU_SET(vfpcthread, PCPU_GET(curthread));
+	return 0;
+}
+
+/* vfs_store is called from from a VFP command to restore the registers and
+ * turn on the VFP hardware.
+ * Eventually we will use the information that this process was the last
+ * to use the VFP hardware and bypass the restore, just turn on the hardware.
+ */
+void
+vfp_restore(struct vfp_state *vfpsave)
+{
+	u_int vfpscr = 0;
+
+	if (vfpsave) {
+		__asm __volatile("ldc	p10, c0, [%0], #128\n" /* d0-d31 */
+#ifndef VFPv2
+			"ldcl	p11, c0, [%0], #128\n"	/* d16-d31 */
+#else
+			"add	%0, %0, #128\n"		/* slip missing regs */
+#endif
+			"ldr	%1, [%0]\n"		/* set old vfpscr */
+			"mcr	p10, 7, %1, cr1, c0, 0\n"
+				:: "r" (vfpsave), "r" (vfpscr));
+		PCPU_SET(vfpcthread, PCPU_GET(curthread));
+	}
+}
+
+/* vfs_store is called from switch to save the vfp hardware registers
+ * into the pcb before switching to another process.
+ * we already know that the new process is different from this old
+ * process and that this process last used the VFP registers.
+ * Below we check to see if the VFP has been enabled since the last
+ * register save.
+ * This routine will exit with the VFP turned off. The next VFP user
+ * will trap to restore its registers and turn on the VFP hardware.
+ */
+void
+vfp_store(struct vfp_state *vfpsave)
+{
+	u_int tmp, vfpscr = 0;
+
+	tmp = fmrx(cr8);		/* Is the vfp enabled? */
+	if (vfpsave && tmp & VFPEXC_EN) {
+		__asm __volatile("stc	p11, c0, [%1], #128\n" /* d0-d31 */
+#ifndef VFPv2
+			"stcl	p11, c0, [%1], #128\n"
+#else
+			"add	%1, %1, #128\n"
+#endif
+			"mrc	p10, 7, %0, cr1, c0, 0\n"
+			"str	%0, [%1]\n"
+			:  "=&r" (vfpscr) : "r" (vfpsave));
+	}
+#ifndef SMP
+		/* eventually we will use this information for UP also */
+	PCPU_SET(vfpcthread, 0);
+#endif
+	tmp &= ~VFPEXC_EN;	/* disable the vfp hardware */
+	fmxr(cr8 , tmp);
+}
+
+/* discard the registers at cpu_thread_free() when fpcurthread == td.
+ * Turn off the VFP hardware.
+ */
+void
+vfp_discard()
+{
+	u_int tmp = 0;
+
+	PCPU_SET(vfpcthread, 0);	/* permanent forget about reg */
+	tmp = fmrx(cr8);
+	tmp &= ~VFPEXC_EN;		/* turn off VFP hardware */
+	fmxr(cr8, tmp);
+}
+
+/* Enable the VFP hardware without restoring registers.
+ * Called when the registers are still in the VFP unit
+ */
+void
+vfp_enable()
+{
+	u_int tmp = 0;
+
+	tmp = fmrx(cr8);
+	tmp |= VFPEXC_EN;
+	fmxr(cr8 , tmp);
+}
diff -r 7fffa673adcd -r a301a330526b head/sys/arm/arm/vm_machdep.c
--- a/head/sys/arm/arm/vm_machdep.c	Wed Aug 15 11:15:12 2012 +0300
+++ b/head/sys/arm/arm/vm_machdep.c	Wed Aug 15 11:16:36 2012 +0300
@@ -41,7 +41,7 @@
  */
 
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD: head/sys/arm/arm/vm_machdep.c 236991 2012-06-13 04:59:55Z imp $");
+__FBSDID("$FreeBSD: head/sys/arm/arm/vm_machdep.c 239268 2012-08-15 03:03:03Z gonzo $");
 
 #include <sys/param.h>
 #include <sys/systm.h>
@@ -146,7 +146,11 @@
 	/* Setup to release spin count in fork_exit(). */
 	td2->td_md.md_spinlock_count = 1;
 	td2->td_md.md_saved_cspr = 0;
+#ifdef ARM_TP_ADDRESS
 	td2->td_md.md_tp = *(register_t *)ARM_TP_ADDRESS;
+#else
+	td2->td_md.md_tp = (register_t) get_tls();
+#endif
 }
 				
 void
@@ -369,11 +373,14 @@
 cpu_set_user_tls(struct thread *td, void *tls_base)
 {
 
-	if (td != curthread)
-		td->td_md.md_tp = (register_t)tls_base;
-	else {
+	td->td_md.md_tp = (register_t)tls_base;
+	if (td == curthread) {
 		critical_enter();
+#ifdef ARM_TP_ADDRESS
 		*(register_t *)ARM_TP_ADDRESS = (register_t)tls_base;
+#else
+		set_tls((void *)tls_base);
+#endif
 		critical_exit();
 	}
 	return (0);
@@ -485,7 +492,11 @@
 		for (; tomap < (vm_offset_t)ret + size; tomap += PAGE_SIZE,
 		    vaddr += PAGE_SIZE, physaddr += PAGE_SIZE, i++) {
 			cpu_idcache_wbinv_range(vaddr, PAGE_SIZE);
+#ifdef ARM_L2_PIPT
+			cpu_l2cache_wbinv_range(physaddr, PAGE_SIZE);
+#else
 			cpu_l2cache_wbinv_range(vaddr, PAGE_SIZE);
+#endif
 			pmap_kenter_nocache(tomap, physaddr);
 			cpu_tlb_flushID_SE(vaddr);
 			arm_nocache_allocated[i / BITS_PER_INT] |= 1 << (i %
diff -r 7fffa673adcd -r a301a330526b head/sys/arm/at91/at91_machdep.c
--- a/head/sys/arm/at91/at91_machdep.c	Wed Aug 15 11:15:12 2012 +0300
+++ b/head/sys/arm/at91/at91_machdep.c	Wed Aug 15 11:16:36 2012 +0300
@@ -44,7 +44,7 @@
  */
 
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD: head/sys/arm/at91/at91_machdep.c 238788 2012-07-26 08:01:25Z andrew $");
+__FBSDID("$FreeBSD: head/sys/arm/at91/at91_machdep.c 239268 2012-08-15 03:03:03Z gonzo $");
 
 #define _ARM32_BUS_DMA_PRIVATE
 #include <sys/param.h>
@@ -118,9 +118,6 @@
 
 struct pv_addr kernel_pt_table[NUM_KERNEL_PTS];
 
-struct pcpu __pcpu;
-struct pcpu *pcpup = &__pcpu;
-
 /* Physical and virtual addresses for some global pages */
 
 vm_paddr_t phys_avail[10];
@@ -471,8 +468,7 @@
 
 	lastaddr = parse_boot_param(abp);
 	set_cpufuncs();
-	pcpu_init(pcpup, 0, sizeof(struct pcpu));
-	PCPU_SET(curthread, &thread0);
+	pcpu0_init();
 
 	/* Do basic tuning, hz etc */
 	init_param1();
diff -r 7fffa673adcd -r a301a330526b head/sys/arm/at91/at91_pmc.c
--- a/head/sys/arm/at91/at91_pmc.c	Wed Aug 15 11:15:12 2012 +0300
+++ b/head/sys/arm/at91/at91_pmc.c	Wed Aug 15 11:16:36 2012 +0300
@@ -25,7 +25,7 @@
  */
 
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD: head/sys/arm/at91/at91_pmc.c 239168 2012-08-10 04:48:06Z imp $");
+__FBSDID("$FreeBSD: head/sys/arm/at91/at91_pmc.c 239190 2012-08-11 05:45:19Z imp $");
 
 #include <sys/param.h>
 #include <sys/systm.h>
@@ -71,7 +71,7 @@
 static void at91_pmc_clock_alias(const char *name, const char *alias);
 
 static struct at91_pmc_clock slck = {
-	.name = "slck",		// 32,768 Hz slow clock
+	.name = "slck",		/* 32,768 Hz slow clock */
 	.hz = 32768,
 	.refcnt = 1,
 	.id = 0,
@@ -83,7 +83,7 @@
  * are now created automatically. Only "system" clocks need be defined here.
  */
 static struct at91_pmc_clock main_ck = {
-	.name = "main",		// Main clock
+	.name = "main",		/* Main clock */
 	.refcnt = 0,
 	.id = 1,
 	.primary = 1,
@@ -91,7 +91,7 @@
 };
 
 static struct at91_pmc_clock plla = {
-	.name = "plla",		// PLLA Clock, used for CPU clocking
+	.name = "plla",		/* PLLA Clock, used for CPU clocking */
 	.parent = &main_ck,
 	.refcnt = 1,
 	.id = 0,
@@ -101,7 +101,7 @@
 };
 
 static struct at91_pmc_clock pllb = {
-	.name = "pllb",		// PLLB Clock, used for USB functions
+	.name = "pllb",		/* PLLB Clock, used for USB functions */
 	.parent = &main_ck,
 	.refcnt = 0,
 	.id = 0,
@@ -113,7 +113,7 @@
 
 /* Used by USB on at91sam9g45 */
 static struct at91_pmc_clock upll = {
-	.name = "upll",		// UTMI PLL, used for USB functions on 9G45
+	.name = "upll",		/* UTMI PLL, used for USB functions on 9G45 family */
 	.parent = &main_ck,
 	.refcnt = 0,
 	.id = 0,
@@ -138,13 +138,13 @@
 };
 
 static struct at91_pmc_clock mck = {
-	.name = "mck",		// Master (Peripheral) Clock
+	.name = "mck",		/* Master (Peripheral) Clock */
 	.pmc_mask = PMC_IER_MCKRDY,
 	.refcnt = 0,
 };
 
 static struct at91_pmc_clock cpu = {
-	.name = "cpu",		// CPU Clock
+	.name = "cpu",		/* CPU Clock */
 	.parent = &plla,
 	.pmc_mask = PMC_SCER_PCK,
 	.refcnt = 0,
@@ -187,6 +187,40 @@
 		bus_write_4(sc->mem_res, off, val);
 }
 
+/*
+ * The following is unused currently since we don't ever set the PLLA
+ * frequency of the device.  If we did, we'd have to also pay attention
+ * to the ICPLLA bit in the PMC_PLLICPR register for frequencies lower
+ * than ~600MHz, which the PMC code doesn't do right now.
+ */
+uint32_t
+at91_pmc_800mhz_plla_outb(int freq)
+{
+	uint32_t outa;
+
+	/*
+	 * Set OUTA, per the data sheet.  See Table 46-16 titled
+	 * PLLA Frequency Regarding ICPLLA and OUTA in the SAM9X25 doc,
+	 * Table 46-17 in the SAM9G20 doc, or Table 46-16 in the SAM9G45 doc.
+	 * Note: the frequencies overlap by 5MHz, so we add 3 here to
+	 * center shoot the transition.
+	 */
+
+	freq /= 1000000;		/* MHz */
+	if (freq >= 800)
+		freq = 800;
+	freq += 3;			/* Allow for overlap. */
+	outa = 3 - ((freq / 50) & 3);	/* 750 / 50 = 7, see table */
+	return (1 << 29)| (outa << 14);
+}
+
+uint32_t
+at91_pmc_800mhz_pllb_outb(int freq)
+{
+
+	return (0);
+}
+
 void
 at91_pmc_set_pllb_mode(struct at91_pmc_clock *clk, int on)
 {
@@ -329,7 +363,6 @@
 			return (clock_list[i]);
 	}
 
-	//printf("at91_pmc: Warning - did not find clock '%s'", name);
 	return (NULL);
 }
 
@@ -510,9 +543,11 @@
 	mckr = RD4(sc, PMC_MCKR);
 	main_ck.hz = main_clock;
 
-	// Note: this means outa calc code for plla never used since
-	// we never change it.  If we did, we'd also have to mind
-	// ICPLLA to get the charge pump current right.
+	/*
+	 * Note: this means outa calc code for plla never used since
+	 * we never change it.  If we did, we'd also have to mind
+	 * ICPLLA to get the charge pump current right.
+	 */
 	at91_pmc_pll_rate(&plla, RD4(sc, CKGR_PLLAR));
 
 	if (at91_cpu_is(AT91_T_SAM9G45) && (mckr & PMC_MCKR_PLLADIV2))
diff -r 7fffa673adcd -r a301a330526b head/sys/arm/at91/at91_pmcvar.h
--- a/head/sys/arm/at91/at91_pmcvar.h	Wed Aug 15 11:15:12 2012 +0300
+++ b/head/sys/arm/at91/at91_pmcvar.h	Wed Aug 15 11:16:36 2012 +0300
@@ -23,7 +23,7 @@
  * SUCH DAMAGE.
  */
 
-/* $FreeBSD: head/sys/arm/at91/at91_pmcvar.h 237745 2012-06-29 06:06:19Z imp $ */
+/* $FreeBSD: head/sys/arm/at91/at91_pmcvar.h 239190 2012-08-11 05:45:19Z imp $ */
 
 #ifndef ARM_AT91_AT91_PMCVAR_H
 #define ARM_AT91_AT91_PMCVAR_H
@@ -62,4 +62,6 @@
 void at91_pmc_clock_enable(struct at91_pmc_clock *);
 void at91_pmc_clock_disable(struct at91_pmc_clock *);
 
+uint32_t at91_pmc_800mhz_plla_outb(int freq);
+uint32_t at91_pmc_800mhz_pllb_outb(int freq);
 #endif /* ARM_AT91_AT91_PMCVAR_H */
diff -r 7fffa673adcd -r a301a330526b head/sys/arm/at91/at91sam9260.c
--- a/head/sys/arm/at91/at91sam9260.c	Wed Aug 15 11:15:12 2012 +0300
+++ b/head/sys/arm/at91/at91sam9260.c	Wed Aug 15 11:16:36 2012 +0300
@@ -25,7 +25,7 @@
  */
 
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD: head/sys/arm/at91/at91sam9260.c 238397 2012-07-12 13:45:58Z imp $");
+__FBSDID("$FreeBSD: head/sys/arm/at91/at91sam9260.c 239189 2012-08-11 05:12:46Z imp $");
 
 #include <sys/param.h>
 #include <sys/systm.h>
@@ -122,21 +122,30 @@
 	{ 0, 0, 0, 0, 0 }
 };
 
+/*
+ * The following is unused currently since we don't ever set the PLLA
+ * frequency of the device.
+ */
 static uint32_t
 at91_pll_outa(int freq)
 {
+	uint32_t outa = 0;
 
-	if (freq > 195000000)
-		return (0x20000000);
-	else
-		return (0x20008000);
+	/*
+	 * Set OUTA, per the data sheet.  See Table 40-15 titled
+	 * PLLA Characteristics in the SAM9260 doc.
+	 */
+
+	if (freq > 155000000)
+		outa = 2 << 14;
+	return ((1 << 29) | outa);
 }
 
 static uint32_t
 at91_pll_outb(int freq)
 {
 
-	return (0x4000);
+	return (1 << 14);
 }
 
 static void
@@ -173,7 +182,7 @@
 	 * to be near the optimal 2 MHz per datasheet.  We know
 	 * we are going to be using this for the USB clock at 96 MHz.
 	 * Causes no extra frequency deviation for all recomended crystal
-	 * values.
+	 * values.  See Note 1, table 40-16 SAM9260 doc.
 	 */
 	clk = at91_pmc_clock_ref("pllb");
 	clk->pll_min_in    = SAM9260_PLL_B_MIN_IN_FREQ;		/*   1 MHz */
diff -r 7fffa673adcd -r a301a330526b head/sys/arm/at91/at91sam9g20.c
--- a/head/sys/arm/at91/at91sam9g20.c	Wed Aug 15 11:15:12 2012 +0300
+++ b/head/sys/arm/at91/at91sam9g20.c	Wed Aug 15 11:16:36 2012 +0300
@@ -25,7 +25,7 @@
  */
 
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD: head/sys/arm/at91/at91sam9g20.c 238397 2012-07-12 13:45:58Z imp $");
+__FBSDID("$FreeBSD: head/sys/arm/at91/at91sam9g20.c 239190 2012-08-11 05:45:19Z imp $");
 
 #include <sys/param.h>
 #include <sys/systm.h>
@@ -122,30 +122,6 @@
 	{ 0, 0, 0, 0, 0 }
 };
 
-static uint32_t
-at91_pll_outa(int freq)
-{
-
-	switch (freq / 10000000) {
-		case 747 ... 801: return ((1 << 29) | (0 << 14));
-		case 697 ... 746: return ((1 << 29) | (1 << 14));
-		case 647 ... 696: return ((1 << 29) | (2 << 14));
-		case 597 ... 646: return ((1 << 29) | (3 << 14));
-		case 547 ... 596: return ((1 << 29) | (1 << 14));
-		case 497 ... 546: return ((1 << 29) | (2 << 14));
-		case 447 ... 496: return ((1 << 29) | (3 << 14));
-		case 397 ... 446: return ((1 << 29) | (4 << 14));
-		default: return (1 << 29);
-	}
-}
-
-static uint32_t
-at91_pll_outb(int freq)
-{
-
-	return (0);
-}
-
 static void
 at91_clock_init(void)
 {
@@ -171,7 +147,7 @@
 	clk->pll_mul_mask  = SAM9G20_PLL_A_MUL_MASK;
 	clk->pll_div_shift = SAM9G20_PLL_A_DIV_SHIFT;
 	clk->pll_div_mask  = SAM9G20_PLL_A_DIV_MASK;
-	clk->set_outb      = at91_pll_outa;
+	clk->set_outb      = at91_pmc_800mhz_plla_outb;
 	at91_pmc_clock_deref(clk);
 
 	clk = at91_pmc_clock_ref("pllb");
@@ -183,7 +159,7 @@
 	clk->pll_mul_mask  = SAM9G20_PLL_B_MUL_MASK;
 	clk->pll_div_shift = SAM9G20_PLL_B_DIV_SHIFT;
 	clk->pll_div_mask  = SAM9G20_PLL_B_DIV_MASK;
-	clk->set_outb      = at91_pll_outb;
+	clk->set_outb      = at91_pmc_800mhz_pllb_outb;
 	at91_pmc_clock_deref(clk);
 }
 
diff -r 7fffa673adcd -r a301a330526b head/sys/arm/at91/at91sam9g45.c
--- a/head/sys/arm/at91/at91sam9g45.c	Wed Aug 15 11:15:12 2012 +0300
+++ b/head/sys/arm/at91/at91sam9g45.c	Wed Aug 15 11:16:36 2012 +0300
@@ -26,7 +26,7 @@
  */
 
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD: head/sys/arm/at91/at91sam9g45.c 238788 2012-07-26 08:01:25Z andrew $");
+__FBSDID("$FreeBSD: head/sys/arm/at91/at91sam9g45.c 239190 2012-08-11 05:45:19Z imp $");
 
 #include <sys/param.h>
 #include <sys/systm.h>
@@ -125,23 +125,6 @@
 	{ 0, 0, 0, 0, 0 }
 };
 
-static uint32_t
-at91_pll_outa(int freq)
-{
-
-	switch (freq / 10000000) {
-		case 747 ... 801: return ((1 << 29) | (0 << 14));
-		case 697 ... 746: return ((1 << 29) | (1 << 14));
-		case 647 ... 696: return ((1 << 29) | (2 << 14));
-		case 597 ... 646: return ((1 << 29) | (3 << 14));
-		case 547 ... 596: return ((1 << 29) | (4 << 14));
-		case 497 ... 546: return ((1 << 29) | (5 << 14));
-		case 447 ... 496: return ((1 << 29) | (6 << 14));
-		case 397 ... 446: return ((1 << 29) | (7 << 14));
-		default: return (1 << 29);
-	}
-}
-
 static void
 at91_clock_init(void)
 {
@@ -162,7 +145,7 @@
 	clk->pll_mul_mask  = SAM9G45_PLL_A_MUL_MASK;
 	clk->pll_div_shift = SAM9G45_PLL_A_DIV_SHIFT;
 	clk->pll_div_mask  = SAM9G45_PLL_A_DIV_MASK;
-	clk->set_outb      = at91_pll_outa;
+	clk->set_outb      = at91_pmc_800mhz_plla_outb;
 	at91_pmc_clock_deref(clk);
 }
 
diff -r 7fffa673adcd -r a301a330526b head/sys/arm/at91/at91sam9x5.c
--- a/head/sys/arm/at91/at91sam9x5.c	Wed Aug 15 11:15:12 2012 +0300
+++ b/head/sys/arm/at91/at91sam9x5.c	Wed Aug 15 11:16:36 2012 +0300
@@ -26,7 +26,7 @@
  */
 
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD: head/sys/arm/at91/at91sam9x5.c 238922 2012-07-30 21:30:43Z imp $");
+__FBSDID("$FreeBSD: head/sys/arm/at91/at91sam9x5.c 239190 2012-08-11 05:45:19Z imp $");
 
 #include <sys/param.h>
 #include <sys/systm.h>
@@ -125,30 +125,6 @@
 	{ 0, 0, 0, 0, 0 }
 };
 
-static uint32_t
-at91_pll_outa(int freq)
-{
-
-	switch (freq / 10000000) {
-		case 747 ... 801: return ((1 << 29) | (0 << 14));
-		case 697 ... 746: return ((1 << 29) | (1 << 14));
-		case 647 ... 696: return ((1 << 29) | (2 << 14));
-		case 597 ... 646: return ((1 << 29) | (3 << 14));
-		case 547 ... 596: return ((1 << 29) | (1 << 14));
-		case 497 ... 546: return ((1 << 29) | (2 << 14));
-		case 447 ... 496: return ((1 << 29) | (3 << 14));
-		case 397 ... 446: return ((1 << 29) | (4 << 14));
-		default: return (1 << 29);
-	}
-}
-
-static uint32_t
-at91_pll_outb(int freq)
-{
-
-	return (0);
-}
-
 static void
 at91_clock_init(void)
 {
@@ -174,7 +150,7 @@
 	clk->pll_mul_mask  = SAM9X25_PLL_A_MUL_MASK;
 	clk->pll_div_shift = SAM9X25_PLL_A_DIV_SHIFT;
 	clk->pll_div_mask  = SAM9X25_PLL_A_DIV_MASK;
-	clk->set_outb      = at91_pll_outa;
+	clk->set_outb      = at91_pmc_800mhz_plla_outb;
 	at91_pmc_clock_deref(clk);
 
 	clk = at91_pmc_clock_ref("pllb");
@@ -186,7 +162,7 @@
 	clk->pll_mul_mask  = SAM9X25_PLL_B_MUL_MASK;
 	clk->pll_div_shift = SAM9X25_PLL_B_DIV_SHIFT;
 	clk->pll_div_mask  = SAM9X25_PLL_B_DIV_MASK;
-	clk->set_outb      = at91_pll_outb;
+	clk->set_outb      = at91_pmc_800mhz_pllb_outb;
 	at91_pmc_clock_deref(clk);
 }
 
diff -r 7fffa673adcd -r a301a330526b head/sys/arm/at91/std.at91
--- a/head/sys/arm/at91/std.at91	Wed Aug 15 11:15:12 2012 +0300
+++ b/head/sys/arm/at91/std.at91	Wed Aug 15 11:16:36 2012 +0300
@@ -1,9 +1,10 @@
-# $FreeBSD: head/sys/arm/at91/std.at91 237881 2012-07-01 06:34:17Z imp $
+# $FreeBSD: head/sys/arm/at91/std.at91 239268 2012-08-15 03:03:03Z gonzo $
 
 files		"../at91/files.at91"
 cpu		CPU_ARM9
 makeoptions	CONF_CFLAGS=-mcpu=arm9
 options 	PHYSADDR=0x20000000
+options		NO_EVENTTIMERS
 
 # For now, just do the AT91RM9200
 device		at91rm9200
diff -r 7fffa673adcd -r a301a330526b head/sys/arm/conf/ARMADAXP
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/head/sys/arm/conf/ARMADAXP	Wed Aug 15 11:16:36 2012 +0300
@@ -0,0 +1,102 @@
+#
+# Custom kernel for Marvell Armada XP
+#
+# $FreeBSD: head/sys/arm/conf/ARMADAXP 239279 2012-08-15 05:55:16Z gonzo $
+#
+
+ident		MV-88F78XX0
+include		"../mv/armadaxp/std.mv78x60"
+
+options 	SOC_MV_ARMADAXP
+makeoptions	MODULES_OVERRIDE=""
+
+makeoptions	DEBUG=-g		#Build kernel with gdb(1) debug symbols
+makeoptions	WERROR="-Werror"
+
+#options 	SCHED_ULE		#ULE scheduler
+options 	SCHED_4BSD		#4BSD scheduler
+options 	INET			#InterNETworking
+options 	INET6			#IPv6 communications protocols
+options 	FFS			#Berkeley Fast Filesystem
+options 	NFSCL			#Network Filesystem Client
+options 	NFSLOCKD		#Network Lock Manager
+options 	NFS_ROOT		#NFS usable as /, requires NFSCLIENT
+options 	BOOTP
+options 	BOOTP_NFSROOT
+options 	BOOTP_NFSV3
+options 	BOOTP_WIRED_TO=mge0
+
+options 	GEOM_PART_GPT
+options 	ROOTDEVNAME=\"ufs:/dev/da0p1\"
+
+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 	MUTEX_NOINLINE
+options 	RWLOCK_NOINLINE
+options 	NO_FFS_SNAPSHOT
+options 	NO_SWAPPING
+
+options 	SMP
+
+# Debugging
+#options 	VERBOSE_SYSINIT
+options 	ALT_BREAK_TO_DEBUGGER
+options 	DDB
+options 	GDB
+#options 	DIAGNOSTIC
+#options 	INVARIANTS		#Enable calls of extra sanity checking
+#options 	INVARIANT_SUPPORT	#Extra sanity checks of internal structures, required by INVARIANTS
+options 	KDB
+options 	KDB_TRACE
+#options 	KTR
+#options 	KTR_VERBOSE=0
+#options 	KTR_ENTRIES=16384
+#options 	KTR_MASK=(KTR_SPARE2)
+#options 	KTR_COMPILE=KTR_ALL
+#options 	WITNESS			#Enable checks to detect deadlocks and cycles
+#options 	WITNESS_SKIPSPIN	#Don't run witness on spinlocks for speed
+#options 	WITNESS_KDB
+
+# Pseudo devices
+device		random
+device		pty
+device		loop
+device		md
+
+# USB
+options 	USB_DEBUG		# enable debug msgs
+device		usb
+device		ehci
+device		umass
+device		scbus
+device		pass
+device		da
+
+# SATA
+device		ata
+device		atadisk
+#device		mvs
+
+# Serial ports
+device		uart
+
+# I2C (TWSI)
+device		iic
+device		iicbus
+
+#Network
+device		ether
+device		mge			# Marvell Gigabit Ethernet controller
+device		mii
+device		e1000phy
+device		bpf
+options		HZ=1000
+options		DEVICE_POLLING
+device		vlan
+
+#FDT
+options 	FDT
+options 	FDT_DTB_STATIC
+makeoptions	FDT_DTS_FILE=db88f78160.dts
diff -r 7fffa673adcd -r a301a330526b head/sys/arm/conf/BEAGLEBONE
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/head/sys/arm/conf/BEAGLEBONE	Wed Aug 15 11:16:36 2012 +0300
@@ -0,0 +1,126 @@
+# BEAGLEBONE -- Custom configuration for the BeagleBone ARM development
+# platform, check out http://www.beagleboard.org/bone
+#
+# 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: head/sys/arm/conf/BEAGLEBONE 239281 2012-08-15 06:31:32Z gonzo $
+
+ident		BEAGLEBONE
+
+include		"../ti/am335x/std.beaglebone"
+
+makeoptions	MODULES_OVERRIDE=""
+makeoptions	WITHOUT_MODULES="ahc"
+
+options		HZ=100
+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		MSDOSFS			#MSDOS Filesystem
+options		CD9660			#ISO 9660 Filesystem
+options		PROCFS			#Process filesystem (requires PSEUDOFS)
+options		PSEUDOFS		#Pseudo-filesystem framework
+options		COMPAT_43		#Compatible with BSD 4.3 [KEEP THIS!]
+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		KBD_INSTALL_CDEV	# install a CDEV entry in /dev
+options		PREEMPTION
+
+# Debugging
+makeoptions	DEBUG=-g		#Build kernel with gdb(1) debug symbols
+options		BREAK_TO_DEBUGGER
+#options	VERBOSE_SYSINIT		#Enable verbose sysinit messages
+options		KDB
+options		DDB			#Enable the kernel debugger
+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
+
+# NFS support
+#options	NFSCL
+#options	NFSSERVER		#Network Filesystem Server
+#options	NFSCLIENT		#Network Filesystem Client
+
+# Uncomment this for NFS root
+#options	NFS_ROOT		#NFS usable as /, requires NFSCLIENT
+#options	BOOTP_NFSROOT
+#options	BOOTP_COMPAT
+#options	BOOTP
+#options	BOOTP_NFSV3
+#options	BOOTP_WIRED_TO=cpsw0
+
+
+# MMC/SD/SDIO card slot support
+device		mmc			# mmc/sd bus
+device		mmcsd			# mmc/sd flash cards
+
+# Boot device is 2nd slice on MMC/SD card
+options		ROOTDEVNAME=\"ufs:mmcsd0s2\"
+
+# Console and misc
+device		uart
+device		uart_ns8250
+device		pty
+device		snp
+device		md
+device		random			# Entropy device
+
+# I2C support
+device		iicbus
+device		iic
+device		ti_i2c
+device		am335x_pmic		# AM335x Power Management IC (TPC65217)
+
+# GPIO
+device		gpio
+
+# USB support
+device		usb
+options		USB_DEBUG
+#options	USB_REQ_DEBUG
+#options	USB_VERBOSE
+device		musb
+device		umass
+device		scbus			# SCSI bus (required for SCSI)
+device		da			# Direct Access (disks)
+
+# Ethernet
+device		loop
+device		ether
+device		mii
+device		smscphy
+device		cpsw
+device		bpf
+
+# USB ethernet support, requires miibus
+device		miibus
+device		axe			# ASIX Electronics USB Ethernet
+
+# Flattened Device Tree
+options         FDT
+options         FDT_DTB_STATIC
+makeoptions     FDT_DTS_FILE=beaglebone.dts
+
diff -r 7fffa673adcd -r a301a330526b head/sys/arm/conf/EA3250
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/head/sys/arm/conf/EA3250	Wed Aug 15 11:16:36 2012 +0300
@@ -0,0 +1,96 @@
+#
+# Custom kernel for EA3250 boards.
+#
+# $FreeBSD: head/sys/arm/conf/EA3250 239279 2012-08-15 05:55:16Z gonzo $
+#
+
+ident		EA3250
+include		"../lpc/std.lpc"
+hints		"EA3250.hints"
+
+makeoptions	MODULES_OVERRIDE=""
+
+#makeoptions	DEBUG=-g		#Build kernel with gdb(1) debug symbols
+makeoptions	WERROR="-Werror"
+
+options 	SCHED_4BSD		#4BSD scheduler
+options 	INET			#InterNETworking
+options 	INET6			#IPv6 communications protocols
+options 	FFS			#Berkeley Fast Filesystem
+options 	NFSCL			#Network Filesystem Client
+options 	NFSLOCKD		#Network Lock Manager
+options 	NFS_ROOT		#NFS usable as /, requires NFSCLIENT
+options 	MSDOSFS
+options 	BOOTP
+options 	BOOTP_NFSROOT
+options 	BOOTP_NFSV3
+options 	BOOTP_WIRED_TO=lpe0
+
+#options 	ROOTDEVNAME=\"ufs:/dev/da0a\"
+
+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 	MUTEX_NOINLINE
+options 	RWLOCK_NOINLINE
+options 	NO_FFS_SNAPSHOT
+options 	NO_SWAPPING
+
+# Debugging
+options 	ALT_BREAK_TO_DEBUGGER
+options 	DDB
+#options 	DEADLKRES		#Enable the deadlock resolver
+options 	DIAGNOSTIC
+#options 	INVARIANTS		#Enable calls of extra sanity checking
+#options 	INVARIANT_SUPPORT	#Extra sanity checks of internal structures, required by INVARIANTS
+options 	KDB
+options 	WITNESS			#Enable checks to detect deadlocks and cycles
+options 	WITNESS_SKIPSPIN	#Don't run witness on spinlocks for speed
+#options 	WITNESS_KDB
+
+# Pseudo devices
+device		loop
+device		md
+device		pty
+device		random
+
+# Serial ports
+device		uart
+
+# Networking
+device		ether
+device		mii
+device		bpf
+device		lpe
+
+# USB
+options		USB_DEBUG
+device		usb
+device		ohci
+device		umass
+device		scbus
+device		pass
+device		da
+
+device		mmc
+device		mmcsd
+device		lpcmmc
+
+device		gpio
+device		gpioled
+device		lpcgpio
+
+device		spibus
+device		lpcspi
+device		ssd1289
+
+device		lpcfb
+
+# DMAC
+device		dmac
+
+# Flattened Device Tree
+options 	FDT
+options 	FDT_DTB_STATIC
+makeoptions	FDT_DTS_FILE=ea3250.dts
diff -r 7fffa673adcd -r a301a330526b head/sys/arm/conf/EA3250.hints
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/head/sys/arm/conf/EA3250.hints	Wed Aug 15 11:16:36 2012 +0300
@@ -0,0 +1,4 @@
+# $FreeBSD: head/sys/arm/conf/EA3250.hints 239279 2012-08-15 05:55:16Z gonzo $
+
+hint.ssd1289.0.at="spibus0"
+hint.ssd1289.0.cs=26
diff -r 7fffa673adcd -r a301a330526b head/sys/arm/conf/PANDABOARD
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/head/sys/arm/conf/PANDABOARD	Wed Aug 15 11:16:36 2012 +0300
@@ -0,0 +1,144 @@
+# PANDABOARD -- Custom configuration for the PandaBoard ARM development
+# platform, check out www.pandaboard.org
+#
+# 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: head/sys/arm/conf/PANDABOARD 239281 2012-08-15 06:31:32Z gonzo $
+
+ident		PANDABOARD
+
+
+
+# This probably wants to move somewhere else.  Maybe we can create a basic
+# OMAP4340 config, then make a PANDABOARD config that includes the basic one,
+# adds the start addresses and custom devices plus pulls in this hints file.
+
+hints       "PANDABOARD.hints"
+
+include     "../ti/omap4/pandaboard/std.pandaboard"
+
+#To statically compile in device wiring instead of /boot/device.hints
+makeoptions	MODULES_OVERRIDE=""
+makeoptions WITHOUT_MODULES="ahc"
+
+makeoptions	DEBUG=-g		#Build kernel with gdb(1) debug symbols
+options 	HZ=100
+
+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 	NFSCLIENT		#Network Filesystem Client
+device		snp
+#options		NFSCL
+#options 	NFSSERVER		#Network Filesystem Server
+options 	NFS_ROOT		#NFS usable as /, requires NFSCLIENT
+options		BREAK_TO_DEBUGGER
+options		BOOTP_NFSROOT
+options		BOOTP_COMPAT
+options		BOOTP
+options		BOOTP_NFSV3
+options		BOOTP_WIRED_TO=ue0
+options 	MSDOSFS			#MSDOS Filesystem
+#options 	CD9660			#ISO 9660 Filesystem
+#options 	PROCFS			#Process filesystem (requires PSEUDOFS)
+options 	PSEUDOFS		#Pseudo-filesystem framework
+options 	COMPAT_43		#Compatible with BSD 4.3 [KEEP THIS!]
+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 	KBD_INSTALL_CDEV	# install a CDEV entry in /dev
+
+options 	PREEMPTION
+
+# MMC/SD/SDIO Card slot support
+device		mmc				# mmc/sd bus
+device		mmcsd			# mmc/sd flash cards
+
+# I2C support
+device		iicbus
+device		iic
+device		ti_i2c
+
+device		loop
+device		ether
+device		mii
+device		smc
+device		smcphy
+device		uart
+device		uart_ns8250
+
+device		gpio
+
+device		pty
+
+device		pl310			#  PL310 L2 cache controller
+# Debugging for use in -current
+#options		VERBOSE_SYSINIT		#Enable verbose sysinit messages
+options 	KDB
+options 	DDB			#Enable the kernel debugger
+#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
+
+# The following enables MFS as root, this seems similar to an initramfs or initrd
+# as used in Linux.
+# options		MD_ROOT
+# options		MD_ROOT_SIZE=7560
+
+device		random		# Entropy device
+
+# USB support
+device		usb
+options 	USB_DEBUG
+#options	USB_REQ_DEBUG
+#options		USB_VERBOSE
+device		ohci
+device		ehci
+device		umass
+device		scbus		# SCSI bus (required for SCSI)
+device		da		# Direct Access (disks)
+
+
+# USB Ethernet support, requires miibus
+device		miibus
+# device		axe			# ASIX Electronics USB Ethernet
+device		smsc		# SMSC LAN95xx USB Ethernet
+
+
+# OMAP-specific devices
+device		ti_sdma
+device		twl
+device		twl_vreg
+device		twl_clks
+
+# Flattened Device Tree
+options         FDT
+options         FDT_DTB_STATIC
+makeoptions     FDT_DTS_FILE=pandaboard.dts
+
+# device		vfp			# vfp/neon
+# options		ARM_VFP_SUPPORT		# vfp/neon
diff -r 7fffa673adcd -r a301a330526b head/sys/arm/conf/PANDABOARD.hints
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/head/sys/arm/conf/PANDABOARD.hints	Wed Aug 15 11:16:36 2012 +0300
@@ -0,0 +1,61 @@
+# $FreeBSD: head/sys/arm/conf/PANDABOARD.hints 239281 2012-08-15 06:31:32Z gonzo $
+
+# USB ECHI 
+
+#
+# TI OMAP Power Management and System Companion Device sitting on the I2C bus
+# hint.tps65950.0.at="iicbus0"
+# hint.tps65950.0.addr=0xd0
+
+
+#
+# Defines the GPIO pin used to detect the Write Protect stat of the MMC/SD card.
+#hint.omap_mmc.0.wp_gpio="23"
+
+
+#
+# If 'phy_reset" is set, then the accompaning PHY is reset using one of the
+# GPIO pins. If the reset GPIO pin is not -1 then the pin will be toggled when
+# the USB driver is loaded.
+hint.ehci.0.phy_reset="0"
+
+#
+# Sets the PHY mode for the individual ports, the following values are allowed
+#   - EHCI_HCD_OMAP3_MODE_UNKNOWN   0
+#   - EHCI_HCD_OMAP3_MODE_PHY       1
+#   - EHCI_HCD_OMAP3_MODE_TLL       2
+hint.ehci.0.phy_mode_0="1"
+hint.ehci.0.phy_mode_1="0"
+hint.ehci.0.phy_mode_2="0"
+
+#
+# If specified the value indicates a pin that is toggled as a heart-beat. The
+# heart beat pusle is triggered every 500ms using the system tick timer.
+hint.omap_clk.0.heartbeat_gpio="150"
+
+
+#
+# Padconf (pinmux) settings - typically this would be set by the boot-loader
+# but can be overridden here.  These hints are applied to the H/W when the
+# SCM module is initialised.
+#
+# The format is:
+#     hint.omap_scm.0.padconf.<padname>=<muxmode:options>
+#
+# Where the options can be one of the following:
+#     output, input, input_pullup, input_pulldown
+#
+
+# Setup the pin settings for the HS USB Host (PHY mode)
+hint.omap4.0.padconf.ag19="usbb1_ulpiphy_stp:output"
+hint.omap4.0.padconf.ae18="usbb1_ulpiphy_clk:input_pulldown"
+hint.omap4.0.padconf.af19="usbb1_ulpiphy_dir:input_pulldown"
+hint.omap4.0.padconf.ae19="usbb1_ulpiphy_nxt:input_pulldown"
+hint.omap4.0.padconf.af18="usbb1_ulpiphy_dat0:input_pulldown"
+hint.omap4.0.padconf.ag18="usbb1_ulpiphy_dat1:input_pulldown"
+hint.omap4.0.padconf.ae17="usbb1_ulpiphy_dat2:input_pulldown"
+hint.omap4.0.padconf.af17="usbb1_ulpiphy_dat3:input_pulldown"
+hint.omap4.0.padconf.ah17="usbb1_ulpiphy_dat4:input_pulldown"
+hint.omap4.0.padconf.ae16="usbb1_ulpiphy_dat5:input_pulldown"
+hint.omap4.0.padconf.af16="usbb1_ulpiphy_dat6:input_pulldown"
+hint.omap4.0.padconf.ag16="usbb1_ulpiphy_dat7:input_pulldown"
diff -r 7fffa673adcd -r a301a330526b head/sys/arm/econa/econa_machdep.c
--- a/head/sys/arm/econa/econa_machdep.c	Wed Aug 15 11:15:12 2012 +0300
+++ b/head/sys/arm/econa/econa_machdep.c	Wed Aug 15 11:16:36 2012 +0300
@@ -36,7 +36,7 @@
  */
 
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD: head/sys/arm/econa/econa_machdep.c 238329 2012-07-10 01:49:50Z imp $");
+__FBSDID("$FreeBSD: head/sys/arm/econa/econa_machdep.c 239268 2012-08-15 03:03:03Z gonzo $");
 
 #define	_ARM32_BUS_DMA_PRIVATE
 #include <sys/param.h>
@@ -103,9 +103,6 @@
 
 struct pv_addr kernel_pt_table[NUM_KERNEL_PTS];
 
-struct pcpu __pcpu;
-struct pcpu *pcpup = &__pcpu;
-
 /* Physical and virtual addresses for some global pages */
 
 vm_paddr_t phys_avail[10];
@@ -191,8 +188,7 @@
 	boothowto = RB_VERBOSE;
 	lastaddr = parse_boot_param(abp);
 	set_cpufuncs();
-	pcpu_init(pcpup, 0, sizeof(struct pcpu));
-	PCPU_SET(curthread, &thread0);
+	pcpu0_init();
 
 	/* Do basic tuning, hz etc */
       	init_param1();
diff -r 7fffa673adcd -r a301a330526b head/sys/arm/econa/std.econa
--- a/head/sys/arm/econa/std.econa	Wed Aug 15 11:15:12 2012 +0300
+++ b/head/sys/arm/econa/std.econa	Wed Aug 15 11:16:36 2012 +0300
@@ -1,4 +1,4 @@
-# $FreeBSD$
+# $FreeBSD: head/sys/arm/econa/std.econa 239268 2012-08-15 03:03:03Z gonzo $
 
 files	"../econa/files.econa"
 cpu		CPU_FA526
@@ -12,3 +12,5 @@
 options	FLASHADDR=0xD0000000
 options	LOADERRAMADDR=0x00000000
 options	STARTUP_PAGETABLE_ADDR=0x00100000
+
+options	NO_EVENTTIMERS
diff -r 7fffa673adcd -r a301a330526b head/sys/arm/include/armreg.h
--- a/head/sys/arm/include/armreg.h	Wed Aug 15 11:15:12 2012 +0300
+++ b/head/sys/arm/include/armreg.h	Wed Aug 15 11:16:36 2012 +0300
@@ -35,7 +35,7 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $FreeBSD: head/sys/arm/include/armreg.h 236992 2012-06-13 05:02:51Z imp $
+ * $FreeBSD: head/sys/arm/include/armreg.h 239268 2012-08-15 03:03:03Z gonzo $
  */
 
 #ifndef MACHINE_ARMREG_H
@@ -93,6 +93,7 @@
 #define CPU_ID_ARCH_V5TE	0x00050000
 #define CPU_ID_ARCH_V5TEJ	0x00060000
 #define CPU_ID_ARCH_V6		0x00070000
+#define CPU_ID_CPUID_SCHEME	0x000f0000
 #define CPU_ID_VARIANT_MASK	0x00f00000
 
 /* Next three nybbles are part number */
@@ -145,12 +146,36 @@
 #define CPU_ID_ARM1026EJS	0x4106a260
 #define CPU_ID_ARM1136JS	0x4107b360
 #define CPU_ID_ARM1136JSR1	0x4117b360
+#define CPU_ID_CORTEXA8R1	0x411fc080
+#define CPU_ID_CORTEXA8R2	0x412fc080
+#define CPU_ID_CORTEXA8R3	0x413fc080
+#define CPU_ID_CORTEXA9R1	0x411fc090
+#define CPU_ID_CORTEXA9R2	0x412fc090
 #define CPU_ID_SA110		0x4401a100
 #define CPU_ID_SA1100		0x4401a110
 #define	CPU_ID_TI925T		0x54029250
 #define CPU_ID_MV88FR131	0x56251310 /* Marvell Feroceon 88FR131 Core */
+#define CPU_ID_MV88FR331	0x56153310 /* Marvell Feroceon 88FR331 Core */
 #define CPU_ID_MV88FR571_VD	0x56155710 /* Marvell Feroceon 88FR571-VD Core (ID from datasheet) */
-#define	CPU_ID_MV88FR571_41	0x41159260 /* Marvell Feroceon 88FR571-VD Core (actual ID from CPU reg) */
+
+/*
+ * LokiPlus core has also ID set to 0x41159260 and this define cause execution of unsupported
+ * L2-cache instructions so need to disable it. 0x41159260 is a generic ARM926E-S ID.
+ */
+#ifdef SOC_MV_LOKIPLUS
+#define CPU_ID_MV88FR571_41	0x00000000
+#else
+#define CPU_ID_MV88FR571_41	0x41159260 /* Marvell Feroceon 88FR571-VD Core (actual ID from CPU reg) */
+#endif
+
+#define CPU_ID_MV88SV581X_V6		0x560F5810 /* Marvell Sheeva 88SV581x v6 Core */
+#define CPU_ID_MV88SV581X_V7		0x561F5810 /* Marvell Sheeva 88SV581x v7 Core */
+#define CPU_ID_MV88SV584X		0x561F5840 /* Marvell Sheeva 88SV584x v6 Core */
+/* Marvell's CPUIDs with ARM ID in implementor field */
+#define CPU_ID_ARM_88SV581X_V6		0x410fb760 /* Marvell Sheeva 88SV581x v6 Core */
+#define CPU_ID_ARM_88SV581X_V7		0x413FC080 /* Marvell Sheeva 88SV581x v7 Core */
+#define CPU_ID_ARM_88SV584X		0x410FB024 /* Marvell Sheeva 88SV584x v6 Core */
+
 #define	CPU_ID_FA526		0x66015260
 #define	CPU_ID_FA626TE		0x66056260
 #define CPU_ID_SA1110		0x6901b110
@@ -191,6 +216,20 @@
 #define ARM3_CTL_SHARED		0x00000002
 #define ARM3_CTL_MONITOR	0x00000004
 
+/* CPUID registers */
+#define ARM_PFR0_ARM_ISA_MASK	0x0000000f
+
+#define ARM_PFR0_THUMB_MASK	0x000000f0
+#define ARM_PFR0_THUMB		0x10
+#define ARM_PFR0_THUMB2		0x30
+
+#define ARM_PFR0_JAZELLE_MASK	0x00000f00
+#define ARM_PFR0_THUMBEE_MASK	0x0000f000
+
+#define ARM_PFR1_ARMV4_MASK	0x0000000f
+#define ARM_PFR1_SEC_EXT_MASK	0x000000f0
+#define ARM_PFR1_MICROCTRL_MASK	0x00000f00
+
 /*
  * Post-ARM3 CP15 registers:
  *
@@ -244,6 +283,7 @@
 #define CPU_CONTROL_VECRELOC	0x00002000 /* V: Vector relocation */
 #define CPU_CONTROL_ROUNDROBIN	0x00004000 /* RR: Predictable replacement */
 #define CPU_CONTROL_V4COMPAT	0x00008000 /* L4: ARMv4 compat LDR R15 etc */
+#define CPU_CONTROL_V6_EXTPAGE	0x00800000 /* XP: ARMv6 extended page tables */
 #define CPU_CONTROL_L2_ENABLE	0x04000000 /* L2 Cache enabled */
 
 #define CPU_CONTROL_IDC_ENABLE	CPU_CONTROL_DC_ENABLE
@@ -260,23 +300,24 @@
 /* Xscale Core 3 only */
 #define XSCALE_AUXCTL_LLR	0x00000400 /* Enable L2 for LLR Cache */
 
-/* Marvell Feroceon Extra Features Register (CP15 register 1, opcode2 0) */
-#define FC_DCACHE_REPL_LOCK	0x80000000 /* Replace DCache Lock */
-#define FC_DCACHE_STREAM_EN	0x20000000 /* DCache Streaming Switch */
-#define FC_WR_ALLOC_EN		0x10000000 /* Enable Write Allocate */
-#define FC_L2_PREF_DIS		0x01000000 /* L2 Cache Prefetch Disable */
-#define FC_L2_INV_EVICT_LINE	0x00800000 /* L2 Invalidates Uncorrectable Error Line Eviction */
-#define FC_L2CACHE_EN		0x00400000 /* L2 enable */
-#define FC_ICACHE_REPL_LOCK	0x00080000 /* Replace ICache Lock */
-#define FC_GLOB_HIST_REG_EN	0x00040000 /* Branch Global History Register Enable */
-#define FC_BRANCH_TARG_BUF_DIS	0x00020000 /* Branch Target Buffer Disable */
-#define FC_L1_PAR_ERR_EN	0x00010000 /* L1 Parity Error Enable */
+/* Marvell Extra Features Register (CP15 register 1, opcode2 0) */
+#define MV_DC_REPLACE_LOCK	0x80000000 /* Replace DCache Lock */
+#define MV_DC_STREAM_ENABLE	0x20000000 /* DCache Streaming Switch */
+#define MV_WA_ENABLE		0x10000000 /* Enable Write Allocate */
+#define MV_L2_PREFETCH_DISABLE	0x01000000 /* L2 Cache Prefetch Disable */
+#define MV_L2_INV_EVICT_ERR	0x00800000 /* L2 Invalidates Uncorrectable Error Line Eviction */
+#define MV_L2_ENABLE		0x00400000 /* L2 Cache enable */
+#define MV_IC_REPLACE_LOCK	0x00080000 /* Replace ICache Lock */
+#define MV_BGH_ENABLE		0x00040000 /* Branch Global History Register Enable */
+#define MV_BTB_DISABLE		0x00020000 /* Branch Target Buffer Disable */
+#define MV_L1_PARERR_ENABLE	0x00010000 /* L1 Parity Error Enable */
 
 /* Cache type register definitions */
 #define	CPU_CT_ISIZE(x)		((x) & 0xfff)		/* I$ info */
 #define	CPU_CT_DSIZE(x)		(((x) >> 12) & 0xfff)	/* D$ info */
 #define	CPU_CT_S		(1U << 24)		/* split cache */
 #define	CPU_CT_CTYPE(x)		(((x) >> 25) & 0xf)	/* cache type */
+#define	CPU_CT_FORMAT(x)	((x) >> 29)
 
 #define	CPU_CT_CTYPE_WT		0	/* write-through */
 #define	CPU_CT_CTYPE_WB1	1	/* write-back, clean w/ read */
@@ -289,6 +330,27 @@
 #define	CPU_CT_xSIZE_ASSOC(x)	(((x) >> 3) & 0x7)	/* associativity */
 #define	CPU_CT_xSIZE_SIZE(x)	(((x) >> 6) & 0x7)	/* size */
 
+#define	CPU_CT_ARMV7		0x4
+/* ARM v7 Cache type definitions */
+#define	CPUV7_CT_CTYPE_WT	(1 << 31)
+#define	CPUV7_CT_CTYPE_WB	(1 << 30)
+#define	CPUV7_CT_CTYPE_RA	(1 << 29)
+#define	CPUV7_CT_CTYPE_WA	(1 << 28)
+
+#define	CPUV7_CT_xSIZE_LEN(x)	((x) & 0x7)		/* line size */
+#define	CPUV7_CT_xSIZE_ASSOC(x)	(((x) >> 3) & 0x3ff)	/* associativity */
+#define	CPUV7_CT_xSIZE_SET(x)	(((x) >> 13) & 0x7fff)	/* num sets */
+
+#define	CPU_CLIDR_CTYPE(reg,x)	(((reg) >> ((x) * 3)) & 0x7)
+#define	CPU_CLIDR_LOUIS(reg)	(((reg) >> 21) & 0x7)
+#define	CPU_CLIDR_LOC(reg)	(((reg) >> 24) & 0x7)
+#define	CPU_CLIDR_LOUU(reg)	(((reg) >> 27) & 0x7)
+
+#define	CACHE_ICACHE		1
+#define	CACHE_DCACHE		2
+#define	CACHE_SEP_CACHE		3
+#define	CACHE_UNI_CACHE		4
+
 /* Fault status register definitions */
 
 #define FAULT_TYPE_MASK 0x0f
diff -r 7fffa673adcd -r a301a330526b head/sys/arm/include/asm.h
--- a/head/sys/arm/include/asm.h	Wed Aug 15 11:15:12 2012 +0300
+++ b/head/sys/arm/include/asm.h	Wed Aug 15 11:16:36 2012 +0300
@@ -33,7 +33,7 @@
  *
  *	from: @(#)asm.h	5.5 (Berkeley) 5/7/91
  *
- * $FreeBSD$
+ * $FreeBSD: head/sys/arm/include/asm.h 239268 2012-08-15 03:03:03Z gonzo $
  */
 
 #ifndef _MACHINE_ASM_H_
@@ -130,45 +130,52 @@
 	.stabs __STRING(_/**/sym),1,0,0,0
 #endif /* __STDC__ */
 
-
-#if defined (__ARM_ARCH_6__) || defined (__ARM_ARCH_6J__)
-#define _ARM_ARCH_6
+/* Exactly one of the __ARM_ARCH_*__ macros will be defined by the compiler. */
+/* The _ARM_ARCH_* macros are deprecated and will be removed soon. */
+/* This should be moved into another header so it can be used in
+ * both asm and C code. machine/asm.h cannot be included in C code. */
+#if defined (__ARM_ARCH_7__) || defined (__ARM_ARCH_7A__)
+#define _ARM_ARCH_7
+#define _HAVE_ARMv7_INSTRUCTIONS 1
 #endif
 
-#if defined (_ARM_ARCH_6) || defined (__ARM_ARCH_5__) || \
-    defined (__ARM_ARCH_5T__) || defined (__ARM_ARCH_5TE__) || \
-    defined (__ARM_ARCH_5TEJ__) || defined (__ARM_ARCH_5E__)
-#define _ARM_ARCH_5
+#if defined (_HAVE_ARMv7_INSTRUCTIONS) || defined (__ARM_ARCH_6__) || \
+	defined (__ARM_ARCH_6J__) || defined (__ARM_ARCH_6K__) || \
+	defined (__ARM_ARCH_6Z__) || defined (__ARM_ARCH_6ZK__)
+#define _ARM_ARCH_6
+#define _HAVE_ARMv6_INSTRUCTIONS 1
 #endif
 
-#if defined (_ARM_ARCH_6) || defined(__ARM_ARCH_5TE__) || \
-    defined(__ARM_ARCH_5TEJ__) || defined(__ARM_ARCH_5E__)
+#if defined (_HAVE_ARMv6_INSTRUCTIONS) || defined (__ARM_ARCH_5TE__) || \
+    defined (__ARM_ARCH_5TEJ__) || defined (__ARM_ARCH_5E__)
 #define _ARM_ARCH_5E
+#define _HAVE_ARMv5E_INSTRUCTIONS 1
 #endif
 
-#if defined (_ARM_ARCH_5) || defined (__ARM_ARCH_4T__)
-#define _ARM_ARCH_4T
+#if defined (_HAVE_ARMv5E_INSTRUCTIONS) || defined (__ARM_ARCH_5__) || \
+    defined (__ARM_ARCH_5T__)
+#define _ARM_ARCH_5
+#define _HAVE_ARMv5_INSTRUCTIONS 1
 #endif
 
+#if defined (_HAVE_ARMv5_INSTRUCTIONS) || defined (__ARM_ARCH_4T__)
+#define _ARM_ARCH_4T
+#define _HAVE_ARMv4T_INSTRUCTIONS 1
+#endif
 
-#if defined (_ARM_ARCH_4T)
+/* FreeBSD requires ARMv4, so this is always set. */
+#define _HAVE_ARMv4_INSTRUCTIONS 1
+
+#if defined (_HAVE_ARMv4T_INSTRUCTIONS)
 # define RET	bx	lr
 # define RETeq	bxeq	lr
 # define RETne	bxne	lr
-# ifdef __STDC__
-#  define RETc(c) bx##c	lr
-# else
-#  define RETc(c) bx/**/c	lr
-# endif
+# define RETc(c) bx##c	lr
 #else
 # define RET	mov	pc, lr
 # define RETeq	moveq	pc, lr
 # define RETne	movne	pc, lr
-# ifdef __STDC__
-#  define RETc(c) mov##c	pc, lr
-# else
-#  define RETc(c) mov/**/c	pc, lr
-# endif
+# define RETc(c) mov##c	pc, lr
 #endif
 
 #endif /* !_MACHINE_ASM_H_ */
diff -r 7fffa673adcd -r a301a330526b head/sys/arm/include/asmacros.h
--- a/head/sys/arm/include/asmacros.h	Wed Aug 15 11:15:12 2012 +0300
+++ b/head/sys/arm/include/asmacros.h	Wed Aug 15 11:16:36 2012 +0300
@@ -34,15 +34,18 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $FreeBSD: head/sys/arm/include/asmacros.h 236992 2012-06-13 05:02:51Z imp $
+ * $FreeBSD: head/sys/arm/include/asmacros.h 239268 2012-08-15 03:03:03Z gonzo $
  */
 
 #ifndef	_MACHINE_ASMACROS_H_
 #define	_MACHINE_ASMACROS_H_
 
+#include <machine/asm.h>
+
 #ifdef _KERNEL
 
 #ifdef LOCORE
+#include "opt_global.h"
 
 /*
  * ASM macros for pushing and pulling trapframes from the stack
@@ -58,7 +61,7 @@
  * NOTE: r13 and r14 are stored separately as a work around for the
  * SA110 rev 2 STM^ bug
  */
-
+#ifdef ARM_TP_ADDRESS
 #define PUSHFRAME							   \
 	str	lr, [sp, #-4]!;		/* Push the return address */	   \
 	sub	sp, sp, #(4*17);	/* Adjust the stack pointer */	   \
@@ -73,12 +76,24 @@
 	str	r1, [r0];						   \
 	mov	r1, #0xffffffff;					   \
 	str	r1, [r0, #4];
+#else
+#define PUSHFRAME							   \
+	str	lr, [sp, #-4]!;		/* Push the return address */	   \
+	sub	sp, sp, #(4*17);	/* Adjust the stack pointer */	   \
+	stmia	sp, {r0-r12};		/* Push the user mode registers */ \
+	add	r0, sp, #(4*13);	/* Adjust the stack pointer */	   \
+	stmia	r0, {r13-r14}^;		/* Push the user mode registers */ \
+        mov     r0, r0;                 /* NOP for previous instruction */ \
+	mrs	r0, spsr_all;		/* Put the SPSR on the stack */	   \
+	str	r0, [sp, #-4]!;
+#endif
 
 /*
  * PULLFRAME - macro to pull a trap frame from the stack in the current mode
  * Since the current mode is used, the SVC lr field is ignored.
  */
 
+#ifdef ARM_TP_ADDRESS
 #define PULLFRAME							   \
         ldr     r0, [sp], #0x0004;      /* Get the SPSR from stack */	   \
         msr     spsr_all, r0;						   \
@@ -86,6 +101,16 @@
         mov     r0, r0;                 /* NOP for previous instruction */ \
 	add	sp, sp, #(4*17);	/* Adjust the stack pointer */	   \
  	ldr	lr, [sp], #0x0004;	/* Pull the return address */
+#else 
+#define PULLFRAME							   \
+        ldr     r0, [sp], #0x0004;      /* Get the SPSR from stack */	   \
+        msr     spsr_all, r0;						   \
+	clrex;								   \
+        ldmia   sp, {r0-r14}^;		/* Restore registers (usr mode) */ \
+        mov     r0, r0;                 /* NOP for previous instruction */ \
+	add	sp, sp, #(4*17);	/* Adjust the stack pointer */	   \
+ 	ldr	lr, [sp], #0x0004;	/* Pull the return address */
+#endif
 
 /*
  * PUSHFRAMEINSVC - macro to push a trap frame on the stack in SVC32 mode
@@ -97,7 +122,7 @@
  * NOTE: r13 and r14 are stored separately as a work around for the
  * SA110 rev 2 STM^ bug
  */
-
+#ifdef ARM_TP_ADDRESS
 #define PUSHFRAMEINSVC							   \
 	stmdb	sp, {r0-r3};		/* Save 4 registers */		   \
 	mov	r0, lr;			/* Save xxx32 r14 */		   \
@@ -132,6 +157,30 @@
 	strhi   r3, [r0, #16];          /* the RAS_START location.      */ \
 	mrs     r0, spsr_all;                                              \
 	str     r0, [sp, #-4]!
+#else
+#define PUSHFRAMEINSVC							   \
+	stmdb	sp, {r0-r3};		/* Save 4 registers */		   \
+	mov	r0, lr;			/* Save xxx32 r14 */		   \
+	mov	r1, sp;			/* Save xxx32 sp */		   \
+	mrs	r3, spsr;		/* Save xxx32 spsr */		   \
+	mrs     r2, cpsr;		/* Get the CPSR */		   \
+	bic     r2, r2, #(PSR_MODE);	/* Fix for SVC mode */		   \
+	orr     r2, r2, #(PSR_SVC32_MODE);				   \
+	msr     cpsr_c, r2;		/* Punch into SVC mode */	   \
+	mov	r2, sp;			/* Save	SVC sp */		   \
+	str	r0, [sp, #-4]!;		/* Push return address */	   \
+	str	lr, [sp, #-4]!;		/* Push SVC lr */		   \
+	str	r2, [sp, #-4]!;		/* Push SVC sp */		   \
+	msr     spsr_all, r3;		/* Restore correct spsr */	   \
+	ldmdb	r1, {r0-r3};		/* Restore 4 regs from xxx mode */ \
+	sub	sp, sp, #(4*15);	/* Adjust the stack pointer */	   \
+	stmia	sp, {r0-r12};		/* Push the user mode registers */ \
+	add	r0, sp, #(4*13);	/* Adjust the stack pointer */	   \
+	stmia	r0, {r13-r14}^;		/* Push the user mode registers */ \
+        mov     r0, r0;                 /* NOP for previous instruction */ \
+	mrs	r0, spsr_all;		/* Put the SPSR on the stack */	   \
+	str	r0, [sp, #-4]!
+#endif
 
 /*
  * PULLFRAMEFROMSVCANDEXIT - macro to pull a trap frame from the stack
@@ -140,6 +189,7 @@
  * exit.
  */
 
+#ifdef ARM_TP_ADDRESS
 #define PULLFRAMEFROMSVCANDEXIT						   \
         ldr     r0, [sp], #0x0004;	/* Get the SPSR from stack */	   \
         msr     spsr_all, r0;		/* restore SPSR */		   \
@@ -147,6 +197,16 @@
         mov     r0, r0;	  		/* NOP for previous instruction */ \
 	add	sp, sp, #(4*15);	/* Adjust the stack pointer */	   \
 	ldmia	sp, {sp, lr, pc}^	/* Restore lr and exit */
+#else 
+#define PULLFRAMEFROMSVCANDEXIT						   \
+        ldr     r0, [sp], #0x0004;	/* Get the SPSR from stack */	   \
+        msr     spsr_all, r0;		/* restore SPSR */		   \
+	clrex;								   \
+        ldmia   sp, {r0-r14}^;		/* Restore registers (usr mode) */ \
+        mov     r0, r0;	  		/* NOP for previous instruction */ \
+	add	sp, sp, #(4*15);	/* Adjust the stack pointer */	   \
+	ldmia	sp, {sp, lr, pc}^	/* Restore lr and exit */
+#endif 
 
 #define	DATA(name) \
 	.data ; \
@@ -155,9 +215,20 @@
 	.type	name, %object ; \
 name:
 
-#define	EMPTY
+#ifdef _ARM_ARCH_6
+#define	AST_LOCALS
+#define GET_CURTHREAD_PTR(tmp) \
+	mrc p15, 0, tmp, c13, c0, 4; \
+	add	tmp, tmp, #(PC_CURTHREAD)
+#else
+#define	AST_LOCALS							;\
+.Lcurthread:								;\
+	.word	_C_LABEL(__pcpu) + PC_CURTHREAD
 
-		
+#define GET_CURTHREAD_PTR(tmp) \
+	ldr	tmp, .Lcurthread
+#endif
+
 #define	DO_AST								\
 	ldr	r0, [sp]		/* Get the SPSR from stack */	;\
 	mrs	r4, cpsr		/* save CPSR */			;\
@@ -167,7 +238,7 @@
 	teq	r0, #(PSR_USR32_MODE)					;\
 	bne	2f			/* Nope, get out now */		;\
 	bic	r4, r4, #(I32_bit|F32_bit)				;\
-1:	ldr	r5, .Lcurthread						;\
+1:	GET_CURTHREAD_PTR(r5)						;\
 	ldr	r5, [r5]						;\
 	ldr	r1, [r5, #(TD_FLAGS)]					;\
 	and	r1, r1, #(TDF_ASTPENDING|TDF_NEEDRESCHED)		;\
@@ -181,11 +252,6 @@
 	b	1b							;\
 2:
 
-
-#define	AST_LOCALS							;\
-.Lcurthread:								;\
-	.word	_C_LABEL(__pcpu) + PC_CURTHREAD
-
 #endif /* LOCORE */
 
 #endif /* _KERNEL */
diff -r 7fffa673adcd -r a301a330526b head/sys/arm/include/atomic.h
--- a/head/sys/arm/include/atomic.h	Wed Aug 15 11:15:12 2012 +0300
+++ b/head/sys/arm/include/atomic.h	Wed Aug 15 11:16:36 2012 +0300
@@ -33,23 +33,23 @@
  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  *
- * $FreeBSD: head/sys/arm/include/atomic.h 238347 2012-07-10 14:21:25Z imp $
+ * $FreeBSD: head/sys/arm/include/atomic.h 239268 2012-08-15 03:03:03Z gonzo $
  */
 
 #ifndef	_MACHINE_ATOMIC_H_
 #define	_MACHINE_ATOMIC_H_
 
-#ifndef _LOCORE
-
 #include <sys/types.h>
 
 #ifndef _KERNEL
 #include <machine/sysarch.h>
+#else
+#include <machine/cpuconf.h>
 #endif
 
-#define	mb()
-#define	wmb()
-#define	rmb()
+#define mb()
+#define wmb()
+#define rmb()
 
 #ifndef I32_bit
 #define I32_bit (1 << 7)        /* IRQ disable */
@@ -58,6 +58,356 @@
 #define F32_bit (1 << 6)        /* FIQ disable */
 #endif
 
+/*
+ * It would be nice to use _HAVE_ARMv6_INSTRUCTIONS from machine/asm.h
+ * here, but that header can't be included here because this is C
+ * code.  I would like to move the _HAVE_ARMv6_INSTRUCTIONS definition
+ * out of asm.h so it can be used in both asm and C code. - kientzle@
+ */
+#if defined (__ARM_ARCH_7__) || \
+	defined (__ARM_ARCH_7A__) || \
+	defined (__ARM_ARCH_6__) || \
+	defined (__ARM_ARCH_6J__) || \
+	defined (__ARM_ARCH_6K__) || \
+	defined (__ARM_ARCH_6Z__) || \
+	defined (__ARM_ARCH_6ZK__)
+static __inline void
+__do_dmb(void)
+{
+
+#if defined (__ARM_ARCH_7__) || defined (__ARM_ARCH_7A__)
+	__asm __volatile("dmb" : : : "memory");
+#else
+	__asm __volatile("mcr p15, 0, r0, c7, c10, 5" : : : "memory");
+#endif
+}
+
+#define ATOMIC_ACQ_REL_LONG(NAME)					\
+static __inline void							\
+atomic_##NAME##_acq_long(__volatile u_long *p, u_long v)		\
+{									\
+	atomic_##NAME##_long(p, v);					\
+	__do_dmb();							\
+}									\
+									\
+static __inline  void							\
+atomic_##NAME##_rel_long(__volatile u_long *p, u_long v)		\
+{									\
+	__do_dmb();							\
+	atomic_##NAME##_long(p, v);					\
+}
+
+#define	ATOMIC_ACQ_REL(NAME, WIDTH)					\
+static __inline  void							\
+atomic_##NAME##_acq_##WIDTH(__volatile uint##WIDTH##_t *p, uint##WIDTH##_t v)\
+{									\
+	atomic_##NAME##_##WIDTH(p, v);					\
+	__do_dmb();							\
+}									\
+									\
+static __inline  void							\
+atomic_##NAME##_rel_##WIDTH(__volatile uint##WIDTH##_t *p, uint##WIDTH##_t v)\
+{									\
+	__do_dmb();							\
+	atomic_##NAME##_##WIDTH(p, v);					\
+}
+
+static __inline void
+atomic_set_32(volatile uint32_t *address, uint32_t setmask)
+{
+	uint32_t tmp = 0, tmp2 = 0;
+
+	__asm __volatile("1: ldrex %0, [%2]\n"
+	    		    "orr %0, %0, %3\n"
+			    "strex %1, %0, [%2]\n"
+			    "cmp %1, #0\n"
+			    "bne	1b\n"
+			   : "=&r" (tmp), "+r" (tmp2)
+			   , "+r" (address), "+r" (setmask) : : "memory");
+			     
+}
+
+static __inline void
+atomic_set_long(volatile u_long *address, u_long setmask)
+{
+	u_long tmp = 0, tmp2 = 0;
+
+	__asm __volatile("1: ldrex %0, [%2]\n"
+	    		    "orr %0, %0, %3\n"
+			    "strex %1, %0, [%2]\n"
+			    "cmp %1, #0\n"
+			    "bne	1b\n"
+			   : "=&r" (tmp), "+r" (tmp2)
+			   , "+r" (address), "+r" (setmask) : : "memory");
+			     
+}
+
+static __inline void
+atomic_clear_32(volatile uint32_t *address, uint32_t setmask)
+{
+	uint32_t tmp = 0, tmp2 = 0;
+
+	__asm __volatile("1: ldrex %0, [%2]\n"
+	    		    "bic %0, %0, %3\n"
+			    "strex %1, %0, [%2]\n"
+			    "cmp %1, #0\n"
+			    "bne	1b\n"
+			   : "=&r" (tmp), "+r" (tmp2)
+			   ,"+r" (address), "+r" (setmask) : : "memory");
+}
+
+static __inline void
+atomic_clear_long(volatile u_long *address, u_long setmask)
+{
+	u_long tmp = 0, tmp2 = 0;
+
+	__asm __volatile("1: ldrex %0, [%2]\n"
+	    		    "bic %0, %0, %3\n"
+			    "strex %1, %0, [%2]\n"
+			    "cmp %1, #0\n"
+			    "bne	1b\n"
+			   : "=&r" (tmp), "+r" (tmp2)
+			   ,"+r" (address), "+r" (setmask) : : "memory");
+}
+
+static __inline u_int32_t
+atomic_cmpset_32(volatile u_int32_t *p, volatile u_int32_t cmpval, volatile u_int32_t newval)
+{
+	uint32_t ret;
+	
+	__asm __volatile("1: ldrex %0, [%1]\n"
+	                 "cmp %0, %2\n"
+			 "movne %0, #0\n"
+			 "bne 2f\n"
+			 "strex %0, %3, [%1]\n"
+			 "cmp %0, #0\n"
+			 "bne	1b\n"
+			 "moveq %0, #1\n"
+			 "2:"
+			 : "=&r" (ret)
+			 ,"+r" (p), "+r" (cmpval), "+r" (newval) : : "memory");
+	return (ret);
+}
+
+static __inline u_long
+atomic_cmpset_long(volatile u_long *p, volatile u_long cmpval, volatile u_long newval)
+{
+	u_long ret;
+	
+	__asm __volatile("1: ldrex %0, [%1]\n"
+	                 "cmp %0, %2\n"
+			 "movne %0, #0\n"
+			 "bne 2f\n"
+			 "strex %0, %3, [%1]\n"
+			 "cmp %0, #0\n"
+			 "bne	1b\n"
+			 "moveq %0, #1\n"
+			 "2:"
+			 : "=&r" (ret)
+			 ,"+r" (p), "+r" (cmpval), "+r" (newval) : : "memory");
+	return (ret);
+}
+
+static __inline u_int32_t
+atomic_cmpset_acq_32(volatile u_int32_t *p, volatile u_int32_t cmpval, volatile u_int32_t newval)
+{
+	u_int32_t ret = atomic_cmpset_32(p, cmpval, newval);
+
+	__do_dmb();
+	return (ret);
+}
+
+static __inline u_long
+atomic_cmpset_acq_long(volatile u_long *p, volatile u_long cmpval, volatile u_long newval)
+{
+	u_long ret = atomic_cmpset_long(p, cmpval, newval);
+
+	__do_dmb();
+	return (ret);
+}
+
+static __inline u_int32_t
+atomic_cmpset_rel_32(volatile u_int32_t *p, volatile u_int32_t cmpval, volatile u_int32_t newval)
+{
+	
+	__do_dmb();
+	return (atomic_cmpset_32(p, cmpval, newval));
+}
+
+static __inline u_long
+atomic_cmpset_rel_long(volatile u_long *p, volatile u_long cmpval, volatile u_long newval)
+{
+	
+	__do_dmb();
+	return (atomic_cmpset_long(p, cmpval, newval));
+}
+
+
+static __inline void
+atomic_add_32(volatile u_int32_t *p, u_int32_t val)
+{
+	uint32_t tmp = 0, tmp2 = 0;
+
+	__asm __volatile("1: ldrex %0, [%2]\n"
+	    		    "add %0, %0, %3\n"
+			    "strex %1, %0, [%2]\n"
+			    "cmp %1, #0\n"
+			    "bne	1b\n"
+			    : "=&r" (tmp), "+r" (tmp2)
+			    ,"+r" (p), "+r" (val) : : "memory");
+}
+
+static __inline void
+atomic_add_long(volatile u_long *p, u_long val)
+{
+	u_long tmp = 0, tmp2 = 0;
+
+	__asm __volatile("1: ldrex %0, [%2]\n"
+	    		    "add %0, %0, %3\n"
+			    "strex %1, %0, [%2]\n"
+			    "cmp %1, #0\n"
+			    "bne	1b\n"
+			    : "=&r" (tmp), "+r" (tmp2)
+			    ,"+r" (p), "+r" (val) : : "memory");
+}
+
+static __inline void
+atomic_subtract_32(volatile u_int32_t *p, u_int32_t val)
+{
+	uint32_t tmp = 0, tmp2 = 0;
+
+	__asm __volatile("1: ldrex %0, [%2]\n"
+	    		    "sub %0, %0, %3\n"
+			    "strex %1, %0, [%2]\n"
+			    "cmp %1, #0\n"
+			    "bne	1b\n"
+			    : "=&r" (tmp), "+r" (tmp2)
+			    ,"+r" (p), "+r" (val) : : "memory");
+}
+
+static __inline void
+atomic_subtract_long(volatile u_long *p, u_long val)
+{
+	u_long tmp = 0, tmp2 = 0;
+
+	__asm __volatile("1: ldrex %0, [%2]\n"
+	    		    "sub %0, %0, %3\n"
+			    "strex %1, %0, [%2]\n"
+			    "cmp %1, #0\n"
+			    "bne	1b\n"
+			    : "=&r" (tmp), "+r" (tmp2)
+			    ,"+r" (p), "+r" (val) : : "memory");
+}
+
+ATOMIC_ACQ_REL(clear, 32)
+ATOMIC_ACQ_REL(add, 32)
+ATOMIC_ACQ_REL(subtract, 32)
+ATOMIC_ACQ_REL(set, 32)
+ATOMIC_ACQ_REL_LONG(clear)
+ATOMIC_ACQ_REL_LONG(add)
+ATOMIC_ACQ_REL_LONG(subtract)
+ATOMIC_ACQ_REL_LONG(set)
+
+#undef ATOMIC_ACQ_REL
+#undef ATOMIC_ACQ_REL_LONG
+
+static __inline uint32_t
+atomic_fetchadd_32(volatile uint32_t *p, uint32_t val)
+{
+	uint32_t tmp = 0, tmp2 = 0, ret = 0;
+
+	__asm __volatile("1: ldrex %0, [%3]\n"
+	    		    "add %1, %0, %4\n"
+			    "strex %2, %1, [%3]\n"
+			    "cmp %2, #0\n"
+			    "bne	1b\n"
+			   : "+r" (ret), "=&r" (tmp), "+r" (tmp2)
+			   ,"+r" (p), "+r" (val) : : "memory");
+	return (ret);
+}
+
+static __inline uint32_t
+atomic_readandclear_32(volatile u_int32_t *p)
+{
+	uint32_t ret, tmp = 0, tmp2 = 0;
+
+	__asm __volatile("1: ldrex %0, [%3]\n"
+	    		 "mov %1, #0\n"
+			 "strex %2, %1, [%3]\n"
+			 "cmp %2, #0\n"
+			 "bne 1b\n"
+			 : "=r" (ret), "=&r" (tmp), "+r" (tmp2)
+			 ,"+r" (p) : : "memory");
+	return (ret);
+}
+
+static __inline uint32_t
+atomic_load_acq_32(volatile uint32_t *p)
+{
+	uint32_t v;
+
+	v = *p;
+	__do_dmb();
+	return (v);
+}
+
+static __inline void
+atomic_store_rel_32(volatile uint32_t *p, uint32_t v)
+{
+	
+	__do_dmb();
+	*p = v;
+}
+
+static __inline u_long
+atomic_fetchadd_long(volatile u_long *p, u_long val)
+{
+	u_long tmp = 0, tmp2 = 0, ret = 0;
+
+	__asm __volatile("1: ldrex %0, [%3]\n"
+	    		    "add %1, %0, %4\n"
+			    "strex %2, %1, [%3]\n"
+			    "cmp %2, #0\n"
+			    "bne	1b\n"
+			   : "+r" (ret), "=&r" (tmp), "+r" (tmp2)
+			   ,"+r" (p), "+r" (val) : : "memory");
+	return (ret);
+}
+
+static __inline u_long
+atomic_readandclear_long(volatile u_long *p)
+{
+	u_long ret, tmp = 0, tmp2 = 0;
+
+	__asm __volatile("1: ldrex %0, [%3]\n"
+	    		 "mov %1, #0\n"
+			 "strex %2, %1, [%3]\n"
+			 "cmp %2, #0\n"
+			 "bne 1b\n"
+			 : "=r" (ret), "=&r" (tmp), "+r" (tmp2)
+			 ,"+r" (p) : : "memory");
+	return (ret);
+}
+
+static __inline u_long
+atomic_load_acq_long(volatile u_long *p)
+{
+	u_long v;
+
+	v = *p;
+	__do_dmb();
+	return (v);
+}
+
+static __inline void
+atomic_store_rel_long(volatile u_long *p, u_long v)
+{
+	
+	__do_dmb();
+	*p = v;
+}
+#else /* < armv6 */
+
 #define __with_interrupts_disabled(expr) \
 	do {						\
 		u_int cpsr_save, tmp;			\
@@ -287,6 +637,83 @@
 
 #endif /* _KERNEL */
 
+
+static __inline uint32_t
+atomic_readandclear_32(volatile u_int32_t *p)
+{
+
+	return (__swp(0, p));
+}
+
+#define atomic_cmpset_rel_32	atomic_cmpset_32
+#define atomic_cmpset_acq_32	atomic_cmpset_32
+#define atomic_set_rel_32	atomic_set_32
+#define atomic_set_acq_32	atomic_set_32
+#define atomic_clear_rel_32	atomic_clear_32
+#define atomic_clear_acq_32	atomic_clear_32
+#define atomic_add_rel_32	atomic_add_32
+#define atomic_add_acq_32	atomic_add_32
+#define atomic_subtract_rel_32	atomic_subtract_32
+#define atomic_subtract_acq_32	atomic_subtract_32
+#define atomic_store_rel_32	atomic_store_32
+#define atomic_store_rel_long	atomic_store_long
+#define atomic_load_acq_32	atomic_load_32
+#define atomic_load_acq_long	atomic_load_long
+#undef __with_interrupts_disabled
+
+static __inline void
+atomic_add_long(volatile u_long *p, u_long v)
+{
+
+	atomic_add_32((volatile uint32_t *)p, v);
+}
+
+static __inline void
+atomic_clear_long(volatile u_long *p, u_long v)
+{
+
+	atomic_clear_32((volatile uint32_t *)p, v);
+}
+
+static __inline int
+atomic_cmpset_long(volatile u_long *dst, u_long old, u_long newe)
+{
+
+	return (atomic_cmpset_32((volatile uint32_t *)dst, old, newe));
+}
+
+static __inline u_long
+atomic_fetchadd_long(volatile u_long *p, u_long v)
+{
+
+	return (atomic_fetchadd_32((volatile uint32_t *)p, v));
+}
+
+static __inline void
+atomic_readandclear_long(volatile u_long *p)
+{
+
+	atomic_readandclear_32((volatile uint32_t *)p);
+}
+
+static __inline void
+atomic_set_long(volatile u_long *p, u_long v)
+{
+
+	atomic_set_32((volatile uint32_t *)p, v);
+}
+
+static __inline void
+atomic_subtract_long(volatile u_long *p, u_long v)
+{
+
+	atomic_subtract_32((volatile uint32_t *)p, v);
+}
+
+
+
+#endif /* Arch >= v6 */
+
 static __inline int
 atomic_load_32(volatile uint32_t *v)
 {
@@ -300,88 +727,57 @@
 	*dst = src;
 }
 
-static __inline uint32_t
-atomic_readandclear_32(volatile u_int32_t *p)
+static __inline int
+atomic_load_long(volatile u_long *v)
 {
 
-	return (__swp(0, p));
+	return (*v);
 }
 
-#undef __with_interrupts_disabled
+static __inline void
+atomic_store_long(volatile u_long *dst, u_long src)
+{
+	*dst = src;
+}
 
-#endif /* _LOCORE */
-
-#define	atomic_add_long(p, v) \
-	atomic_add_32((volatile u_int *)(p), (u_int)(v))
 #define atomic_add_acq_long		atomic_add_long
 #define atomic_add_rel_long		atomic_add_long
-#define	atomic_subtract_long(p, v) \
-	atomic_subtract_32((volatile u_int *)(p), (u_int)(v))
 #define atomic_subtract_acq_long	atomic_subtract_long
 #define atomic_subtract_rel_long	atomic_subtract_long
-#define	atomic_clear_long(p, v) \
-	atomic_clear_32((volatile u_int *)(p), (u_int)(v))
 #define atomic_clear_acq_long		atomic_clear_long
 #define atomic_clear_rel_long		atomic_clear_long
-#define	atomic_set_long(p, v) \
-	atomic_set_32((volatile u_int *)(p), (u_int)(v))
 #define atomic_set_acq_long		atomic_set_long
 #define atomic_set_rel_long		atomic_set_long
-#define	atomic_cmpset_long(dst, old, new) \
-	atomic_cmpset_32((volatile u_int *)(dst), (u_int)(old), (u_int)(new))
 #define atomic_cmpset_acq_long		atomic_cmpset_long
 #define atomic_cmpset_rel_long		atomic_cmpset_long
-#define	atomic_fetchadd_long(p, v) \
-	atomic_fetchadd_32((volatile u_int *)(p), (u_int)(v))
-#define	atomic_readandclear_long(p) \
-	atomic_readandclear_long((volatile u_int *)(p))
-#define	atomic_load_long(p) \
-	atomic_load_32((volatile u_int *)(p))
 #define atomic_load_acq_long		atomic_load_long
-#define	atomic_store_rel_long(p, v) \
-	atomic_store_rel_32((volatile u_int *)(p), (u_int)(v))
-
 
 #define atomic_clear_ptr		atomic_clear_32
 #define atomic_set_ptr			atomic_set_32
-#define	atomic_cmpset_ptr(dst, old, new)	\
-    atomic_cmpset_32((volatile u_int *)(dst), (u_int)(old), (u_int)(new))
-#define atomic_cmpset_rel_ptr		atomic_cmpset_ptr
-#define atomic_cmpset_acq_ptr		atomic_cmpset_ptr
+#define atomic_cmpset_ptr		atomic_cmpset_32
+#define atomic_cmpset_rel_ptr		atomic_cmpset_rel_32
+#define atomic_cmpset_acq_ptr		atomic_cmpset_acq_32
 #define atomic_store_ptr		atomic_store_32
 #define atomic_store_rel_ptr		atomic_store_ptr
 
 #define atomic_add_int			atomic_add_32
-#define atomic_add_acq_int		atomic_add_int
-#define atomic_add_rel_int		atomic_add_int
+#define atomic_add_acq_int		atomic_add_acq_32
+#define atomic_add_rel_int		atomic_add_rel_32
 #define atomic_subtract_int		atomic_subtract_32
-#define atomic_subtract_acq_int		atomic_subtract_int
-#define atomic_subtract_rel_int		atomic_subtract_int
+#define atomic_subtract_acq_int		atomic_subtract_acq_32
+#define atomic_subtract_rel_int		atomic_subtract_rel_32
 #define atomic_clear_int		atomic_clear_32
-#define atomic_clear_acq_int		atomic_clear_int
-#define atomic_clear_rel_int		atomic_clear_int
+#define atomic_clear_acq_int		atomic_clear_acq_32
+#define atomic_clear_rel_int		atomic_clear_rel_32
 #define atomic_set_int			atomic_set_32
-#define atomic_set_acq_int		atomic_set_int
-#define atomic_set_rel_int		atomic_set_int
+#define atomic_set_acq_int		atomic_set_acq_32
+#define atomic_set_rel_int		atomic_set_rel_32
 #define atomic_cmpset_int		atomic_cmpset_32
-#define atomic_cmpset_acq_int		atomic_cmpset_int
-#define atomic_cmpset_rel_int		atomic_cmpset_int
+#define atomic_cmpset_acq_int		atomic_cmpset_acq_32
+#define atomic_cmpset_rel_int		atomic_cmpset_rel_32
 #define atomic_fetchadd_int		atomic_fetchadd_32
 #define atomic_readandclear_int		atomic_readandclear_32
-#define atomic_load_acq_int		atomic_load_32
-#define atomic_store_rel_int		atomic_store_32
-
-#define atomic_add_acq_32		atomic_add_32
-#define atomic_add_rel_32		atomic_add_32
-#define atomic_subtract_acq_32		atomic_subtract_32
-#define atomic_subtract_rel_32		atomic_subtract_32
-#define atomic_clear_acq_32		atomic_clear_32
-#define atomic_clear_rel_32		atomic_clear_32
-#define atomic_set_acq_32		atomic_set_32
-#define atomic_set_rel_32		atomic_set_32
-#define atomic_cmpset_acq_32		atomic_cmpset_32
-#define atomic_cmpset_rel_32		atomic_cmpset_32
-#define atomic_load_acq_32		atomic_load_32
-#define atomic_store_rel_32		atomic_store_32
+#define atomic_load_acq_int		atomic_load_acq_32
+#define atomic_store_rel_int		atomic_store_rel_32
 
 #endif /* _MACHINE_ATOMIC_H_ */
diff -r 7fffa673adcd -r a301a330526b head/sys/arm/include/cpuconf.h
--- a/head/sys/arm/include/cpuconf.h	Wed Aug 15 11:15:12 2012 +0300
+++ b/head/sys/arm/include/cpuconf.h	Wed Aug 15 11:16:36 2012 +0300
@@ -34,7 +34,7 @@
  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  * POSSIBILITY OF SUCH DAMAGE.
  *
- * $FreeBSD$
+ * $FreeBSD: head/sys/arm/include/cpuconf.h 239268 2012-08-15 03:03:03Z gonzo $
  *
  */
 
@@ -63,7 +63,9 @@
 			 defined(CPU_XSCALE_PXA2X0) +			\
 			 defined(CPU_FA526) +				\
 			 defined(CPU_FA626TE) +				\
-			 defined(CPU_XSCALE_IXP425))
+			 defined(CPU_XSCALE_IXP425)) +			\
+			 defined(CPU_CORTEXA) +				\
+			 defined(CPU_MV_PJ4B)
 
 /*
  * Step 2: Determine which ARM architecture versions are configured.
@@ -86,18 +88,26 @@
 #define	ARM_ARCH_5	0
 #endif
 
-#if defined(CPU_ARM11)
+#if !defined(ARM_ARCH_6)
+#if defined(CPU_ARM11) || defined(CPU_MV_PJ4B)
 #define ARM_ARCH_6	1
 #else
 #define ARM_ARCH_6	0
 #endif
+#endif
 
-#define	ARM_NARCH	(ARM_ARCH_4 + ARM_ARCH_5 + ARM_ARCH_6)
+#if defined(CPU_CORTEXA)
+#define ARM_ARCH_7A	1
+#else
+#define ARM_ARCH_7A	0
+#endif
+
+#define	ARM_NARCH	(ARM_ARCH_4 + ARM_ARCH_5 + ARM_ARCH_6 | ARM_ARCH_7A)
 #if ARM_NARCH == 0 && !defined(KLD_MODULE) && defined(_KERNEL)
 #error ARM_NARCH is 0
 #endif
 
-#if ARM_ARCH_5 || ARM_ARCH_6
+#if ARM_ARCH_5 || ARM_ARCH_6 || ARM_ARCH_7A
 /*
  * We could support Thumb code on v4T, but the lack of clean interworking
  * makes that hard.
@@ -113,6 +123,10 @@
  *
  *	ARM_MMU_GENERIC		Generic ARM MMU, compatible with ARM6.
  *
+ *	ARM_MMU_V6		ARMv6 MMU.
+ *
+ *	ARM_MMU_V7		ARMv7 MMU.
+ *
  *	ARM_MMU_SA1		StrongARM SA-1 MMU.  Compatible with generic
  *				ARM MMU, but has no write-through cache mode.
  *
@@ -128,13 +142,25 @@
 
 #if (defined(CPU_ARM6) || defined(CPU_ARM7) || defined(CPU_ARM7TDMI) ||	\
      defined(CPU_ARM8) || defined(CPU_ARM9) || defined(CPU_ARM9E) ||	\
-     defined(CPU_ARM10) || defined(CPU_ARM11) || defined(CPU_FA526) ||	\
+     defined(CPU_ARM10) || defined(CPU_FA526) ||	\
      defined(CPU_FA626TE))
 #define	ARM_MMU_GENERIC		1
 #else
 #define	ARM_MMU_GENERIC		0
 #endif
 
+#if defined(CPU_ARM11) || defined(CPU_MV_PJ4B)
+#define ARM_MMU_V6		1
+#else
+#define ARM_MMU_V6		0
+#endif
+
+#if defined(CPU_CORTEXA)
+#define ARM_MMU_V7		1
+#else
+#define ARM_MMU_V7		0
+#endif
+
 #if (defined(CPU_SA110) || defined(CPU_SA1100) || defined(CPU_SA1110) ||\
      defined(CPU_IXP12X0))
 #define	ARM_MMU_SA1		1
@@ -150,8 +176,8 @@
 #define	ARM_MMU_XSCALE		0
 #endif
 
-#define	ARM_NMMUS		(ARM_MMU_MEMC + ARM_MMU_GENERIC +	\
-				 ARM_MMU_SA1 + ARM_MMU_XSCALE)
+#define	ARM_NMMUS		(ARM_MMU_MEMC + ARM_MMU_GENERIC + ARM_MMU_V6 + \
+				 ARM_MMU_V7 + ARM_MMU_SA1 + ARM_MMU_XSCALE)
 #if ARM_NMMUS == 0 && !defined(KLD_MODULE) && defined(_KERNEL)
 #error ARM_NMMUS is 0
 #endif
diff -r 7fffa673adcd -r a301a330526b head/sys/arm/include/cpufunc.h
--- a/head/sys/arm/include/cpufunc.h	Wed Aug 15 11:15:12 2012 +0300
+++ b/head/sys/arm/include/cpufunc.h	Wed Aug 15 11:16:36 2012 +0300
@@ -38,7 +38,7 @@
  *
  * Prototypes for cpu, mmu and tlb related functions.
  *
- * $FreeBSD: head/sys/arm/include/cpufunc.h 236992 2012-06-13 05:02:51Z imp $
+ * $FreeBSD: head/sys/arm/include/cpufunc.h 239268 2012-08-15 03:03:03Z gonzo $
  */
 
 #ifndef _MACHINE_CPUFUNC_H_
@@ -176,6 +176,8 @@
 #define cpu_faultstatus()	cpufuncs.cf_faultstatus()
 #define cpu_faultaddress()	cpufuncs.cf_faultaddress()
 
+#ifndef SMP
+
 #define	cpu_tlb_flushID()	cpufuncs.cf_tlb_flushID()
 #define	cpu_tlb_flushID_SE(e)	cpufuncs.cf_tlb_flushID_SE(e)
 #define	cpu_tlb_flushI()	cpufuncs.cf_tlb_flushI()
@@ -183,6 +185,51 @@
 #define	cpu_tlb_flushD()	cpufuncs.cf_tlb_flushD()
 #define	cpu_tlb_flushD_SE(e)	cpufuncs.cf_tlb_flushD_SE(e)
 
+#else
+void tlb_broadcast(int);
+
+#ifdef CPU_CORTEXA
+#define TLB_BROADCAST	/* No need to explicitely send an IPI */
+#else
+#define TLB_BROADCAST	tlb_broadcast(7)
+#endif
+
+#define	cpu_tlb_flushID() do { \
+	cpufuncs.cf_tlb_flushID(); \
+	TLB_BROADCAST; \
+} while(0)
+
+#define	cpu_tlb_flushID_SE(e) do { \
+	cpufuncs.cf_tlb_flushID_SE(e); \
+	TLB_BROADCAST; \
+} while(0)
+
+
+#define	cpu_tlb_flushI() do { \
+	cpufuncs.cf_tlb_flushI(); \
+	TLB_BROADCAST; \
+} while(0)
+
+
+#define	cpu_tlb_flushI_SE(e) do { \
+	cpufuncs.cf_tlb_flushI_SE(e); \
+	TLB_BROADCAST; \
+} while(0)
+
+
+#define	cpu_tlb_flushD() do { \
+	cpufuncs.cf_tlb_flushD(); \
+	TLB_BROADCAST; \
+} while(0)
+
+
+#define	cpu_tlb_flushD_SE(e) do { \
+	cpufuncs.cf_tlb_flushD_SE(e); \
+	TLB_BROADCAST; \
+} while(0)
+
+#endif
+
 #define	cpu_icache_sync_all()	cpufuncs.cf_icache_sync_all()
 #define	cpu_icache_sync_range(a, s) cpufuncs.cf_icache_sync_range((a), (s))
 
@@ -222,10 +269,12 @@
 int	early_abort_fixup	(void *);
 int	late_abort_fixup	(void *);
 u_int	cpufunc_id		(void);
+u_int	cpufunc_cpuid		(void);
 u_int	cpufunc_control		(u_int clear, u_int bic);
 void	cpufunc_domains		(u_int domains);
 u_int	cpufunc_faultstatus	(void);
 u_int	cpufunc_faultaddress	(void);
+u_int	cpu_pfr			(int);
 
 #ifdef CPU_ARM3
 u_int	arm3_control		(u_int clear, u_int bic);
@@ -413,8 +462,9 @@
 void	sheeva_l2cache_wbinv_all	(void);
 #endif
 
-#ifdef CPU_ARM11
+#if defined(CPU_ARM11) || defined(CPU_MV_PJ4B) || defined(CPU_CORTEXA)
 void	arm11_setttb		(u_int);
+void	arm11_sleep		(int);
 
 void	arm11_tlb_flushID_SE	(u_int);
 void	arm11_tlb_flushI_SE	(u_int);
@@ -428,6 +478,51 @@
 void	arm11_tlb_flushD_SE	(u_int va);
 
 void	arm11_drain_writebuf	(void);
+
+void	pj4b_setttb			(u_int);
+
+void	pj4b_icache_sync_range		(vm_offset_t, vm_size_t);
+
+void	pj4b_dcache_wbinv_range		(vm_offset_t, vm_size_t);
+void	pj4b_dcache_inv_range		(vm_offset_t, vm_size_t);
+void	pj4b_dcache_wb_range		(vm_offset_t, vm_size_t);
+
+void	pj4b_idcache_wbinv_range	(vm_offset_t, vm_size_t);
+
+void	pj4b_drain_readbuf		(void);
+void	pj4b_flush_brnchtgt_all		(void);
+void	pj4b_flush_brnchtgt_va		(u_int);
+void	pj4b_sleep			(int);
+
+void	armv6_icache_sync_all		(void);
+void	armv6_dcache_wbinv_all		(void);
+void	armv6_idcache_wbinv_all		(void);
+
+void	armv7_setttb			(u_int);
+void	armv7_tlb_flushID		(void);
+void	armv7_tlb_flushID_SE		(u_int);
+void	armv7_icache_sync_range		(vm_offset_t, vm_size_t);
+void	armv7_idcache_wbinv_range	(vm_offset_t, vm_size_t);
+void	armv7_dcache_wbinv_all		(void);
+void	armv7_idcache_wbinv_all		(void);
+void	armv7_dcache_wbinv_range	(vm_offset_t, vm_size_t);
+void	armv7_dcache_inv_range		(vm_offset_t, vm_size_t);
+void	armv7_dcache_wb_range		(vm_offset_t, vm_size_t);
+void	armv7_cpu_sleep			(int);
+void	armv7_setup			(char *string);
+void	armv7_context_switch		(void);
+void	armv7_drain_writebuf		(void);
+void	armv7_sev			(void);
+u_int	armv7_auxctrl			(u_int, u_int);
+void	pj4bv7_setup			(char *string);
+void	pj4bv6_setup			(char *string);
+void	pj4b_config			(void);
+
+int	get_core_id			(void);
+
+void	armadaxp_idcache_wbinv_all	(void);
+
+void 	cortexa_setup			(char *);
 #endif
 
 #if defined(CPU_ARM9E) || defined (CPU_ARM10)
@@ -445,7 +540,7 @@
 void	armv5_ec_idcache_wbinv_range(vm_offset_t, vm_size_t);
 #endif
 
-#if defined (CPU_ARM10) || defined (CPU_ARM11)
+#if defined (CPU_ARM10)
 void	armv5_setttb(u_int);
 
 void	armv5_icache_sync_all(void);
@@ -636,6 +731,10 @@
 extern int	arm_dcache_align;
 extern int	arm_dcache_align_mask;
 
+extern u_int	arm_cache_level;
+extern u_int	arm_cache_loc;
+extern u_int	arm_cache_type[14];
+
 #endif	/* _KERNEL */
 #endif	/* _MACHINE_CPUFUNC_H_ */
 
diff -r 7fffa673adcd -r a301a330526b head/sys/arm/include/fp.h
--- a/head/sys/arm/include/fp.h	Wed Aug 15 11:15:12 2012 +0300
+++ b/head/sys/arm/include/fp.h	Wed Aug 15 11:16:36 2012 +0300
@@ -42,7 +42,7 @@
  *
  * Created      : 10/10/95
  *
- * $FreeBSD: head/sys/arm/include/fp.h 236992 2012-06-13 05:02:51Z imp $
+ * $FreeBSD: head/sys/arm/include/fp.h 239268 2012-08-15 03:03:03Z gonzo $
  */
 
 #ifndef _MACHINE_FP_H
@@ -66,12 +66,19 @@
  * This needs to move and be hidden from userland.
  */
 
+#ifdef ARM_VFP_SUPPORT
+struct vfp_state {
+	u_int64_t reg[32];
+	u_int32_t fpscr;
+};
+#else
 struct fpe_sp_state {
 	unsigned int fp_flags;
 	unsigned int fp_sr;
 	unsigned int fp_cr;
 	fp_reg_t fp_registers[16];
 };
+#endif
 
 /*
  * Type for a saved FP context, if we want to translate the context to a
diff -r 7fffa673adcd -r a301a330526b head/sys/arm/include/intr.h
--- a/head/sys/arm/include/intr.h	Wed Aug 15 11:15:12 2012 +0300
+++ b/head/sys/arm/include/intr.h	Wed Aug 15 11:16:36 2012 +0300
@@ -32,7 +32,7 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $FreeBSD: head/sys/arm/include/intr.h 236992 2012-06-13 05:02:51Z imp $
+ * $FreeBSD: head/sys/arm/include/intr.h 239268 2012-08-15 03:03:03Z gonzo $
  *
  */
 
@@ -50,6 +50,8 @@
 #elif defined(CPU_ARM9) || defined(SOC_MV_KIRKWOOD) || \
     defined(CPU_XSCALE_IXP435)
 #define NIRQ		64
+#elif defined(CPU_CORTEXA)
+#define NIRQ		128
 #else
 #define NIRQ		32
 #endif
@@ -63,4 +65,7 @@
     void *, int, int, void **);
 int arm_remove_irqhandler(int, void *);
 extern void (*arm_post_filter)(void *);
+
+void gic_init_secondary(void);
+
 #endif	/* _MACHINE_INTR_H */
diff -r 7fffa673adcd -r a301a330526b head/sys/arm/include/md_var.h
--- a/head/sys/arm/include/md_var.h	Wed Aug 15 11:15:12 2012 +0300
+++ b/head/sys/arm/include/md_var.h	Wed Aug 15 11:16:36 2012 +0300
@@ -27,7 +27,7 @@
  * SUCH DAMAGE.
  *
  *	from: FreeBSD: src/sys/i386/include/md_var.h,v 1.40 2001/07/12
- * $FreeBSD$
+ * $FreeBSD: head/sys/arm/include/md_var.h 239268 2012-08-15 03:03:03Z gonzo $
  */
 
 #ifndef	_MACHINE_MD_VAR_H_
@@ -62,6 +62,7 @@
 	CPU_CLASS_ARM9EJS,
 	CPU_CLASS_ARM10E,
 	CPU_CLASS_ARM10EJ,
+	CPU_CLASS_CORTEXA,
 	CPU_CLASS_SA1,
 	CPU_CLASS_XSCALE,
 	CPU_CLASS_ARM11J,
diff -r 7fffa673adcd -r a301a330526b head/sys/arm/include/param.h
--- a/head/sys/arm/include/param.h	Wed Aug 15 11:15:12 2012 +0300
+++ b/head/sys/arm/include/param.h	Wed Aug 15 11:16:36 2012 +0300
@@ -35,7 +35,7 @@
  * SUCH DAMAGE.
  *
  *	from: @(#)param.h	5.8 (Berkeley) 6/28/91
- * $FreeBSD: head/sys/arm/include/param.h 236992 2012-06-13 05:02:51Z imp $
+ * $FreeBSD: head/sys/arm/include/param.h 239268 2012-08-15 03:03:03Z gonzo $
  */
 
 #ifndef _ARM_INCLUDE_PARAM_H_
@@ -56,17 +56,25 @@
 #define	MACHINE		"arm"
 #endif
 #ifndef MACHINE_ARCH
+#ifdef __FreeBSD_ARCH_armv6__
+#ifdef __ARMEB__
+#define	MACHINE_ARCH	"armv6eb"
+#else
+#define	MACHINE_ARCH	"armv6"
+#endif
+#else
 #ifdef __ARMEB__
 #define	MACHINE_ARCH	"armeb"
 #else
 #define	MACHINE_ARCH	"arm"
 #endif
 #endif
+#endif
 #define	MID_MACHINE	MID_ARM6
 
 #if defined(SMP) || defined(KLD_MODULE)
 #ifndef MAXCPU
-#define	MAXCPU		2
+#define	MAXCPU		4
 #endif
 #else
 #define	MAXCPU		1
diff -r 7fffa673adcd -r a301a330526b head/sys/arm/include/pcb.h
--- a/head/sys/arm/include/pcb.h	Wed Aug 15 11:15:12 2012 +0300
+++ b/head/sys/arm/include/pcb.h	Wed Aug 15 11:16:36 2012 +0300
@@ -32,7 +32,7 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $FreeBSD: head/sys/arm/include/pcb.h 234785 2012-04-29 11:04:31Z dim $
+ * $FreeBSD: head/sys/arm/include/pcb.h 239268 2012-08-15 03:03:03Z gonzo $
  */
 
 #ifndef	_MACHINE_PCB_H_
@@ -80,7 +80,12 @@
 #define PCB_NOALIGNFLT	0x00000002
 	caddr_t	pcb_onfault;			/* On fault handler */
 	struct	pcb_arm32 un_32;
+#ifdef ARM_VFP_SUPPORT
+	struct vfp_state pcb_vfpstate;          /* VP/NEON state */
+	u_int pcb_vfpcpu;                       /* VP/NEON last cpu */
+#else
 	struct	fpe_sp_state pcb_fpstate;	/* Floating Point state */
+#endif
 };
 
 /*
diff -r 7fffa673adcd -r a301a330526b head/sys/arm/include/pcpu.h
--- a/head/sys/arm/include/pcpu.h	Wed Aug 15 11:15:12 2012 +0300
+++ b/head/sys/arm/include/pcpu.h	Wed Aug 15 11:16:36 2012 +0300
@@ -24,7 +24,7 @@
  * SUCH DAMAGE.
  *
  *	from: FreeBSD: src/sys/i386/include/globaldata.h,v 1.27 2001/04/27
- * $FreeBSD$
+ * $FreeBSD: head/sys/arm/include/pcpu.h 239268 2012-08-15 03:03:03Z gonzo $
  */
 
 #ifndef	_MACHINE_PCPU_H_
@@ -32,6 +32,7 @@
 
 #ifdef _KERNEL
 
+#include <machine/cpuconf.h>
 #include <machine/frame.h>
 
 #define	ALT_STACK_SIZE	128
@@ -40,7 +41,18 @@
 
 #endif	/* _KERNEL */
 
-#define	PCPU_MD_FIELDS
+#ifdef ARM_VFP_SUPPORT
+#define PCPU_MD_FIELDS							\
+	unsigned int pc_cpu;						\
+	unsigned int pc_vfpsid;						\
+	unsigned int pc_vfpmvfr0;					\
+	unsigned int pc_vfpmvfr1;					\
+	struct thread *pc_vfpcthread;					\
+	struct pmap *pc_curpmap;
+#else
+#define PCPU_MD_FIELDS
+#endif
+
 
 #ifdef _KERNEL
 
@@ -48,19 +60,50 @@
 struct pcpu;
 
 extern struct pcpu *pcpup;
-extern struct pcpu __pcpu;
+#if ARM_ARCH_6 || ARM_ARCH_7A
+/* or ARM_TP_ADDRESS 	mark REMOVE ME NOTE */
+static inline struct pcpu *
+get_pcpu(void)
+{
+	void *pcpu;
 
-#define	PCPU_GET(member)	(__pcpu.pc_ ## member)
+	__asm __volatile("mrc p15, 0, %0, c13, c0, 4" : "=r" (pcpu));
+	return (pcpu);
+}
 
-/*
- * XXX The implementation of this operation should be made atomic
- * with respect to preemption.
- */
-#define	PCPU_ADD(member, value)	(__pcpu.pc_ ## member += (value))
+static inline void
+set_pcpu(void *pcpu)
+{
+
+	__asm __volatile("mcr p15, 0, %0, c13, c0, 4" : : "r" (pcpu));
+}
+
+static inline void *
+get_tls(void)
+{
+	void *tls;
+
+	__asm __volatile("mrc p15, 0, %0, c13, c0, 3" : "=r" (tls));
+	return (tls);
+}
+
+static inline void
+set_tls(void *tls)
+{
+
+	__asm __volatile("mcr p15, 0, %0, c13, c0, 3" : : "r" (tls));
+}
+#else
+#define get_pcpu()	pcpup
+#endif
+
+#define	PCPU_GET(member)	(get_pcpu()->pc_ ## member)
+#define	PCPU_ADD(member, value)	(get_pcpu()->pc_ ## member += (value))
 #define	PCPU_INC(member)	PCPU_ADD(member, 1)
-#define	PCPU_PTR(member)	(&__pcpu.pc_ ## member)
-#define	PCPU_SET(member,value)	(__pcpu.pc_ ## member = (value))
+#define	PCPU_PTR(member)	(&pcpup->pc_ ## member)
+#define	PCPU_SET(member,value)	(pcpup->pc_ ## member = (value))
 
+void pcpu0_init(void);
 #endif	/* _KERNEL */
 
 #endif	/* !_MACHINE_PCPU_H_ */
diff -r 7fffa673adcd -r a301a330526b head/sys/arm/include/pl310.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/head/sys/arm/include/pl310.h	Wed Aug 15 11:16:36 2012 +0300
@@ -0,0 +1,38 @@
+/*-
+ * Copyright (c) 2012 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 THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+/*
+ * $FreeBSD: head/sys/arm/include/pl310.h 239268 2012-08-15 03:03:03Z gonzo $
+ */
+
+#ifndef PL310_H_
+#define PL310_H_
+struct pl310_softc {
+	struct resource *sc_mem_res;
+};
+
+void platform_init_pl310(struct pl310_softc *sc);
+
+#endif /* PL310_H_ */
diff -r 7fffa673adcd -r a301a330526b head/sys/arm/include/pmap.h
--- a/head/sys/arm/include/pmap.h	Wed Aug 15 11:15:12 2012 +0300
+++ b/head/sys/arm/include/pmap.h	Wed Aug 15 11:16:36 2012 +0300
@@ -44,7 +44,7 @@
  *      from: @(#)pmap.h        7.4 (Berkeley) 5/12/91
  * 	from: FreeBSD: src/sys/i386/include/pmap.h,v 1.70 2000/11/30
  *
- * $FreeBSD: head/sys/arm/include/pmap.h 237168 2012-06-16 18:56:19Z alc $
+ * $FreeBSD: head/sys/arm/include/pmap.h 239268 2012-08-15 03:03:03Z gonzo $
  */
 
 #ifndef _MACHINE_PMAP_H_
@@ -55,9 +55,30 @@
 /*
  * Pte related macros
  */
-#define PTE_NOCACHE	0
-#define PTE_CACHE	1
-#define PTE_PAGETABLE	2
+#if ARM_ARCH_6 || ARM_ARCH_7A
+#ifdef SMP
+#define PTE_NOCACHE	2
+#else
+#define PTE_NOCACHE	1
+#endif
+#define PTE_CACHE	4
+#define PTE_DEVICE	2
+#define PTE_PAGETABLE	4
+#else
+#define PTE_NOCACHE	1
+#define PTE_CACHE	2
+#define PTE_PAGETABLE	3
+#endif
+
+enum mem_type {
+	STRONG_ORD = 0,
+	DEVICE_NOSHARE,
+	DEVICE_SHARE,
+	NRML_NOCACHE,
+	NRML_IWT_OWT,
+	NRML_IWB_OWB,
+	NRML_IWBA_OWBA
+};
 
 #ifndef LOCORE
 
@@ -209,6 +230,7 @@
 extern vm_offset_t virtual_end;
 
 void	pmap_bootstrap(vm_offset_t, vm_offset_t, struct pv_addr *);
+int	pmap_change_attr(vm_offset_t, vm_size_t, int);
 void	pmap_kenter(vm_offset_t va, vm_paddr_t pa);
 void	pmap_kenter_nocache(vm_offset_t va, vm_paddr_t pa);
 void	*pmap_kenter_temp(vm_paddr_t pa, int i);
@@ -225,6 +247,7 @@
 pmap_map_entry(vm_offset_t l1pt, vm_offset_t va, vm_offset_t pa, int prot,
     int cache);
 int pmap_fault_fixup(pmap_t, vm_offset_t, vm_prot_t, int);
+int pmap_dmap_iscurrent(pmap_t pmap);
 
 /*
  * Definitions for MMU domains
@@ -251,18 +274,11 @@
  * We use these macros since we use different bits on different processor
  * models.
  */
-#define	L1_S_PROT_U		(L1_S_AP(AP_U))
-#define	L1_S_PROT_W		(L1_S_AP(AP_W))
-#define	L1_S_PROT_MASK		(L1_S_PROT_U|L1_S_PROT_W)
 
 #define	L1_S_CACHE_MASK_generic	(L1_S_B|L1_S_C)
 #define	L1_S_CACHE_MASK_xscale	(L1_S_B|L1_S_C|L1_S_XSCALE_TEX(TEX_XSCALE_X)|\
     				L1_S_XSCALE_TEX(TEX_XSCALE_T))
 
-#define	L2_L_PROT_U		(L2_AP(AP_U))
-#define	L2_L_PROT_W		(L2_AP(AP_W))
-#define	L2_L_PROT_MASK		(L2_L_PROT_U|L2_L_PROT_W)
-
 #define	L2_L_CACHE_MASK_generic	(L2_B|L2_C)
 #define	L2_L_CACHE_MASK_xscale	(L2_B|L2_C|L2_XSCALE_L_TEX(TEX_XSCALE_X) | \
     				L2_XSCALE_L_TEX(TEX_XSCALE_T))
@@ -293,6 +309,11 @@
 /*
  * User-visible names for the ones that vary with MMU class.
  */
+#if (ARM_MMU_V6 + ARM_MMU_V7) != 0
+#define	L2_AP(x)	(L2_AP0(x))
+#else
+#define	L2_AP(x)	(L2_AP0(x) | L2_AP1(x) | L2_AP2(x) | L2_AP3(x))
+#endif
 
 #if ARM_NMMUS > 1
 /* More than one MMU class configured; use variables. */
@@ -334,6 +355,77 @@
 #define	L1_C_PROTO		L1_C_PROTO_xscale
 #define	L2_S_PROTO		L2_S_PROTO_xscale
 
+#elif (ARM_MMU_V6 + ARM_MMU_V7) != 0
+
+#define	L2_S_PROT_U		(L2_AP0(2))		/* user access */
+#define	L2_S_PROT_R		(L2_APX|L2_AP0(1))	/* read access */
+
+#define	L2_S_PROT_MASK		(L2_S_PROT_U|L2_S_PROT_R)
+#define	L2_S_WRITABLE(pte)	(!(pte & L2_APX))
+
+#ifndef SMP
+#define	L1_S_CACHE_MASK		(L1_S_TEX_MASK|L1_S_B|L1_S_C)
+#define	L2_L_CACHE_MASK		(L2_L_TEX_MASK|L2_B|L2_C)
+#define	L2_S_CACHE_MASK		(L2_S_TEX_MASK|L2_B|L2_C)
+#else
+#define	L1_S_CACHE_MASK		(L1_S_TEX_MASK|L1_S_B|L1_S_C|L1_SHARED)
+#define	L2_L_CACHE_MASK		(L2_L_TEX_MASK|L2_B|L2_C|L2_SHARED)
+#define	L2_S_CACHE_MASK		(L2_S_TEX_MASK|L2_B|L2_C|L2_SHARED)
+#endif  /* SMP */
+
+#define	L1_S_PROTO		(L1_TYPE_S)
+#define	L1_C_PROTO		(L1_TYPE_C)
+#define	L2_S_PROTO		(L2_TYPE_S)
+
+#ifndef SMP
+#define ARM_L1S_STRONG_ORD	(0)
+#define ARM_L1S_DEVICE_NOSHARE	(L1_S_TEX(2))
+#define ARM_L1S_DEVICE_SHARE	(L1_S_B)
+#define ARM_L1S_NRML_NOCACHE	(L1_S_TEX(1))
+#define ARM_L1S_NRML_IWT_OWT	(L1_S_C)
+#define ARM_L1S_NRML_IWB_OWB	(L1_S_C|L1_S_B)
+#define ARM_L1S_NRML_IWBA_OWBA	(L1_S_TEX(1)|L1_S_C|L1_S_B)
+
+#define ARM_L2L_STRONG_ORD	(0)
+#define ARM_L2L_DEVICE_NOSHARE	(L2_L_TEX(2))
+#define ARM_L2L_DEVICE_SHARE	(L2_B)
+#define ARM_L2L_NRML_NOCACHE	(L2_L_TEX(1))
+#define ARM_L2L_NRML_IWT_OWT	(L2_C)
+#define ARM_L2L_NRML_IWB_OWB	(L2_C|L2_B)
+#define ARM_L2L_NRML_IWBA_OWBA	(L2_L_TEX(1)|L2_C|L2_B)
+
+#define ARM_L2S_STRONG_ORD	(0)
+#define ARM_L2S_DEVICE_NOSHARE	(L2_S_TEX(2))
+#define ARM_L2S_DEVICE_SHARE	(L2_B)
+#define ARM_L2S_NRML_NOCACHE	(L2_S_TEX(1))
+#define ARM_L2S_NRML_IWT_OWT	(L2_C)
+#define ARM_L2S_NRML_IWB_OWB	(L2_C|L2_B)
+#define ARM_L2S_NRML_IWBA_OWBA	(L2_S_TEX(1)|L2_C|L2_B)
+#else
+#define ARM_L1S_STRONG_ORD	(0)
+#define ARM_L1S_DEVICE_NOSHARE	(L1_S_TEX(2))
+#define ARM_L1S_DEVICE_SHARE	(L1_S_B)
+#define ARM_L1S_NRML_NOCACHE	(L1_S_TEX(1)|L1_SHARED)
+#define ARM_L1S_NRML_IWT_OWT	(L1_S_C|L1_SHARED)
+#define ARM_L1S_NRML_IWB_OWB	(L1_S_C|L1_S_B|L1_SHARED)
+#define ARM_L1S_NRML_IWBA_OWBA	(L1_S_TEX(1)|L1_S_C|L1_S_B|L1_SHARED)
+
+#define ARM_L2L_STRONG_ORD	(0)
+#define ARM_L2L_DEVICE_NOSHARE	(L2_L_TEX(2))
+#define ARM_L2L_DEVICE_SHARE	(L2_B)
+#define ARM_L2L_NRML_NOCACHE	(L2_L_TEX(1)|L2_SHARED)
+#define ARM_L2L_NRML_IWT_OWT	(L2_C|L2_SHARED)
+#define ARM_L2L_NRML_IWB_OWB	(L2_C|L2_B|L2_SHARED)
+#define ARM_L2L_NRML_IWBA_OWBA	(L2_L_TEX(1)|L2_C|L2_B|L2_SHARED)
+
+#define ARM_L2S_STRONG_ORD	(0)
+#define ARM_L2S_DEVICE_NOSHARE	(L2_S_TEX(2))
+#define ARM_L2S_DEVICE_SHARE	(L2_B)
+#define ARM_L2S_NRML_NOCACHE	(L2_S_TEX(1)|L2_SHARED)
+#define ARM_L2S_NRML_IWT_OWT	(L2_C|L2_SHARED)
+#define ARM_L2S_NRML_IWB_OWB	(L2_C|L2_B|L2_SHARED)
+#define ARM_L2S_NRML_IWBA_OWBA	(L2_S_TEX(1)|L2_C|L2_B|L2_SHARED)
+#endif /* SMP */
 #endif /* ARM_NMMUS > 1 */
 
 #if (ARM_MMU_SA1 == 1) && (ARM_NMMUS == 1)
@@ -350,14 +442,41 @@
  * These macros return various bits based on kernel/user and protection.
  * Note that the compiler will usually fold these at compile time.
  */
+#if (ARM_MMU_V6 + ARM_MMU_V7) == 0
+
+#define	L1_S_PROT_U		(L1_S_AP(AP_U))
+#define	L1_S_PROT_W		(L1_S_AP(AP_W))
+#define	L1_S_PROT_MASK		(L1_S_PROT_U|L1_S_PROT_W)
+#define	L1_S_WRITABLE(pd)	((pd) & L1_S_PROT_W)
+
 #define	L1_S_PROT(ku, pr)	((((ku) == PTE_USER) ? L1_S_PROT_U : 0) | \
 				 (((pr) & VM_PROT_WRITE) ? L1_S_PROT_W : 0))
 
+#define	L2_L_PROT_U		(L2_AP(AP_U))
+#define	L2_L_PROT_W		(L2_AP(AP_W))
+#define	L2_L_PROT_MASK		(L2_L_PROT_U|L2_L_PROT_W)
+
 #define	L2_L_PROT(ku, pr)	((((ku) == PTE_USER) ? L2_L_PROT_U : 0) | \
 				 (((pr) & VM_PROT_WRITE) ? L2_L_PROT_W : 0))
 
 #define	L2_S_PROT(ku, pr)	((((ku) == PTE_USER) ? L2_S_PROT_U : 0) | \
 				 (((pr) & VM_PROT_WRITE) ? L2_S_PROT_W : 0))
+#else
+#define	L1_S_PROT_U		(L1_S_AP(AP_U))
+#define	L1_S_PROT_MASK		(L1_S_APX|L1_S_AP(0x3))
+#define	L1_S_WRITABLE(pd)	(!((pd) & L1_S_APX))
+
+#define	L1_S_PROT(ku, pr)	(L1_S_PROT_MASK & ~((((ku) == PTE_KERNEL) ? L1_S_PROT_U : 0) | \
+				 (((pr) & VM_PROT_WRITE) ? L1_S_APX : 0)))
+
+#define	L2_L_PROT_MASK		(L2_APX|L2_AP0(0x3))
+#define	L2_L_PROT(ku, pr)	(L2_L_PROT_MASK & ~((((ku) == PTE_KERNEL) ? L2_S_PROT_U : 0) | \
+				 (((pr) & VM_PROT_WRITE) ? L2_APX : 0)))
+
+#define	L2_S_PROT(ku, pr)	(L2_S_PROT_MASK & ~((((ku) == PTE_KERNEL) ? L2_S_PROT_U : 0) | \
+				 (((pr) & VM_PROT_WRITE) ? L2_APX : 0)))
+
+#endif
 
 /*
  * Macros to test if a mapping is mappable with an L1 Section mapping
@@ -422,7 +541,7 @@
 extern void (*pmap_copy_page_func)(vm_paddr_t, vm_paddr_t);
 extern void (*pmap_zero_page_func)(vm_paddr_t, int, int);
 
-#if (ARM_MMU_GENERIC + ARM_MMU_SA1) != 0 || defined(CPU_XSCALE_81342)
+#if (ARM_MMU_GENERIC + ARM_MMU_V6 + ARM_MMU_V7 + ARM_MMU_SA1) != 0 || defined(CPU_XSCALE_81342)
 void	pmap_copy_page_generic(vm_paddr_t, vm_paddr_t);
 void	pmap_zero_page_generic(vm_paddr_t, int, int);
 
@@ -436,6 +555,9 @@
 #if defined(CPU_ARM10)
 void	pmap_pte_init_arm10(void);
 #endif /* CPU_ARM10 */
+#if (ARM_MMU_V6 + ARM_MMU_V7) != 0
+void	pmap_pte_init_mmu_v6(void);
+#endif /* CPU_ARM11 */
 #endif /* (ARM_MMU_GENERIC + ARM_MMU_SA1) != 0 */
 
 #if /* ARM_MMU_SA1 == */1
diff -r 7fffa673adcd -r a301a330526b head/sys/arm/include/pte.h
--- a/head/sys/arm/include/pte.h	Wed Aug 15 11:15:12 2012 +0300
+++ b/head/sys/arm/include/pte.h	Wed Aug 15 11:16:36 2012 +0300
@@ -31,24 +31,17 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $FreeBSD: head/sys/arm/include/pte.h 236992 2012-06-13 05:02:51Z imp $
+ * $FreeBSD: head/sys/arm/include/pte.h 239268 2012-08-15 03:03:03Z gonzo $
  */
 
 #ifndef _MACHINE_PTE_H_
 #define _MACHINE_PTE_H_
 
-#define PDSHIFT		20		/* LOG2(NBPDR) */
-#define NBPD		(1 << PDSHIFT)	/* bytes/page dir */
-#define NPTEPD		(NBPD / PAGE_SIZE)
-
 #ifndef LOCORE
 typedef	uint32_t	pd_entry_t;		/* page directory entry */
 typedef	uint32_t	pt_entry_t;		/* page table entry */
 #endif
 
-#define PD_MASK		0xfff00000	/* page directory address bits */
-#define PT_MASK		0x000ff000	/* page table address bits */
-
 #define PG_FRAME	0xfffff000
 
 /* The PT_SIZE definition is misleading... A page table is only 0x400
@@ -73,27 +66,6 @@
 #define L2_MASK		0x03	/* Mask for L2 entry type */
 #define L2_INVAL	0x00	/* L2 invalid type */
 
-/* PTE construction macros */
-#define	L2_LPTE(p, a, f)	((p) | PT_AP(a) | L2_LPAGE | (f))
-#define L2_SPTE(p, a, f)	((p) | PT_AP(a) | L2_SPAGE | (f))
-#define L2_PTE(p, a)		L2_SPTE((p), (a), PT_CACHEABLE)
-#define L2_PTE_NC(p, a)		L2_SPTE((p), (a), PT_B)
-#define L2_PTE_NC_NB(p, a)	L2_SPTE((p), (a), 0)
-#define L1_SECPTE(p, a, f)	((p) | ((a) << AP_SECTION_SHIFT) | (f) \
-				| L1_SECTION | PT_U)
-
-#define L1_PTE(p)	((p) | 0x00 | L1_PAGE | PT_U)
-#define L1_SEC(p, c)	L1_SECPTE((p), AP_KRW, (c))
-
-#define L1_SEC_SIZE	(1 << PDSHIFT)
-#define L2_LPAGE_SIZE	(NBPG * 16)
-
-/* Domain types */
-#define DOMAIN_FAULT		0x00
-#define DOMAIN_CLIENT		0x01
-#define DOMAIN_RESERVED		0x02
-#define DOMAIN_MANAGER		0x03
-
 /* L1 and L2 address masks */
 #define L1_ADDR_MASK		0xfffffc00
 #define L2_ADDR_MASK		0xfffff000
@@ -205,7 +177,10 @@
 #define	L1_S_DOM_MASK	L1_S_DOM(0xf)
 #define	L1_S_AP(x)	((x) << 10)	/* access permissions */
 #define	L1_S_ADDR_MASK	0xfff00000	/* phys address of section */
-#define L1_SHARED	(1 << 16)
+#define	L1_S_TEX(x)	(((x) & 0x7) << 12)	/* Type Extension */
+#define	L1_S_TEX_MASK	(0x7 << 12)	/* Type Extension */
+#define	L1_S_APX	(1 << 15)
+#define	L1_SHARED	(1 << 16)
 
 #define	L1_S_XSCALE_P	0x00000200	/* ECC enable for this section */
 #define	L1_S_XSCALE_TEX(x) ((x) << 12)	/* Type Extension */
@@ -256,7 +231,14 @@
 #define	L2_AP1(x)	((x) << 6)	/* access permissions (sp 1) */
 #define	L2_AP2(x)	((x) << 8)	/* access permissions (sp 2) */
 #define	L2_AP3(x)	((x) << 10)	/* access permissions (sp 3) */
-#define	L2_AP(x)	(L2_AP0(x) | L2_AP1(x) | L2_AP2(x) | L2_AP3(x))
+
+#define	L2_SHARED	(1 << 10)
+#define	L2_APX		(1 << 9)
+#define	L2_XN		(1 << 0)
+#define	L2_L_TEX_MASK	(0x7 << 12)	/* Type Extension */
+#define	L2_L_TEX(x)	(((x) & 0x7) << 12)
+#define	L2_S_TEX_MASK	(0x7 << 6)	/* Type Extension */
+#define	L2_S_TEX(x)	(((x) & 0x7) << 6)
 
 #define	L2_XSCALE_L_TEX(x) ((x) << 12)	/* Type Extension */
 #define L2_XSCALE_L_S(x)   (1 << 15)	/* Shared */
diff -r 7fffa673adcd -r a301a330526b head/sys/arm/include/smp.h
--- a/head/sys/arm/include/smp.h	Wed Aug 15 11:15:12 2012 +0300
+++ b/head/sys/arm/include/smp.h	Wed Aug 15 11:16:36 2012 +0300
@@ -1,6 +1,35 @@
-/* $FreeBSD$ */
+/* $FreeBSD: head/sys/arm/include/smp.h 239268 2012-08-15 03:03:03Z gonzo $ */
 
 #ifndef _MACHINE_SMP_H_
 #define _MACHINE_SMP_H_
 
+#include <sys/_cpuset.h>
+
+#define IPI_AST		0
+#define IPI_PREEMPT	2
+#define IPI_RENDEZVOUS	3
+#define IPI_STOP	4
+#define IPI_STOP_HARD	5
+#define IPI_HARDCLOCK	6
+#define IPI_TLB		7
+
+void	init_secondary(int cpu);
+
+void	ipi_all_but_self(u_int ipi);
+void	ipi_cpu(int cpu, u_int ipi);
+void	ipi_selected(cpuset_t cpus, u_int ipi);
+
+/* PIC interface */
+void	pic_ipi_send(cpuset_t cpus, u_int ipi);
+void	pic_ipi_clear(int ipi);
+int	pic_ipi_get(int arg);
+
+/* Platform interface */
+void	platform_mp_setmaxid(void);
+int	platform_mp_probe(void);
+void	platform_mp_start_ap(void);
+void	platform_mp_init_secondary(void);
+
+void	platform_ipi_send(cpuset_t cpus, u_int ipi);
+
 #endif /* !_MACHINE_SMP_H_ */
diff -r 7fffa673adcd -r a301a330526b head/sys/arm/include/sysarch.h
--- a/head/sys/arm/include/sysarch.h	Wed Aug 15 11:15:12 2012 +0300
+++ b/head/sys/arm/include/sysarch.h	Wed Aug 15 11:16:36 2012 +0300
@@ -32,7 +32,7 @@
  * SUCH DAMAGE.
  */
 
-/* $FreeBSD: head/sys/arm/include/sysarch.h 234337 2012-04-16 09:38:20Z andrew $ */
+/* $FreeBSD: head/sys/arm/include/sysarch.h 239268 2012-08-15 03:03:03Z gonzo $ */
 
 #ifndef _ARM_SYSARCH_H_
 #define _ARM_SYSARCH_H_
@@ -50,9 +50,18 @@
  * if ARM_RAS_END moves in relation to ARM_RAS_START (look for occurrances
  * of ldr/str rm,[rn, #4]).
  */
+
+/* ARM_TP_ADDRESS is needed for processors that don't support
+ * the exclusive-access opcodes introduced with ARMv6K. */
+/* TODO: #if !defined(_HAVE_ARMv6K_INSTRUCTIONS) */
+#if !defined (__ARM_ARCH_7__) && \
+	!defined (__ARM_ARCH_7A__) && \
+	!defined (__ARM_ARCH_6K__) &&  \
+	!defined (__ARM_ARCH_6ZK__)
 #define ARM_TP_ADDRESS		(ARM_VECTORS_HIGH + 0x1000)
 #define ARM_RAS_START		(ARM_TP_ADDRESS + 4)
 #define ARM_RAS_END		(ARM_TP_ADDRESS + 8)
+#endif
 
 #ifndef LOCORE
 #ifndef __ASSEMBLER__
diff -r 7fffa673adcd -r a301a330526b head/sys/arm/include/vfp.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/head/sys/arm/include/vfp.h	Wed Aug 15 11:16:36 2012 +0300
@@ -0,0 +1,128 @@
+/*
+ * Copyright (c) 2012 Mark Tinguely
+ *
+ * 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: head/sys/arm/include/vfp.h 239268 2012-08-15 03:03:03Z gonzo $
+ */
+
+
+#ifndef _MACHINE__VFP_H_
+#define _MACHINE__VFP_H_
+
+/* fpsid, fpscr, fpexc are defined in the newer gas */
+#define	VFPSID			cr0
+#define	VFPSCR			cr1
+#define	VMVFR1			cr6
+#define	VMVFR0			cr7
+#define	VFPEXC			cr8
+#define	VFPINST			cr9	/* vfp 1 and 2 except instruction */
+#define	VFPINST2		cr10 	/* vfp 2? */
+
+/* VFPSID */
+#define	VFPSID_IMPLEMENTOR_OFF	24
+#define	VFPSID_IMPLEMENTOR_MASK	(0xff000000)
+#define	VFPSID_HARDSOFT_IMP	(0x00800000)
+#define	VFPSID_SINGLE_PREC	20	 /* version 1 and 2 */
+#define	VFPSID_SUBVERSION_OFF	16
+#define	VFPSID_SUBVERSION2_MASK	(0x000f0000)	 /* version 1 and 2 */
+#define	VFPSID_SUBVERSION3_MASK	(0x007f0000)	 /* version 3 */
+#define VFP_ARCH3		(0x00030000)
+#define	VFPSID_PARTNUMBER_OFF	8
+#define	VFPSID_PARTNUMBER_MASK	(0x0000ff00)
+#define	VFPSID_VARIANT_OFF	4
+#define	VFPSID_VARIANT_MASK	(0x000000f0)
+#define	VFPSID_REVISION_MASK	0x0f
+
+/* VFPSCR */
+#define	VFPSCR_CC_N		(0x80000000)	/* comparison less than */
+#define	VFPSCR_CC_Z		(0x40000000)	/* comparison equal */
+#define	VFPSCR_CC_C		(0x20000000)	/* comparison = > unordered */
+#define	VFPSCR_CC_V		(0x10000000)	/* comparison unordered */
+#define	VFPSCR_QC		(0x08000000)	/* saturation cululative */
+#define	VFPSCR_DN		(0x02000000)	/* default NaN enable */
+#define	VFPSCR_FZ		(0x01000000)	/* flush to zero enabled */
+
+#define	VFPSCR_RMODE_OFF	22		/* rounding mode offset */
+#define	VFPSCR_RMODE_MASK	(0x00c00000)	/* rounding mode mask */
+#define	VFPSCR_RMODE_RN		(0x00000000)	/* round nearest */
+#define	VFPSCR_RMODE_RPI	(0x00400000)	/* round to plus infinity */
+#define	VFPSCR_RMODE_RNI	(0x00800000)	/* round to neg infinity */
+#define	VFPSCR_RMODE_RM		(0x00c00000)	/* round to zero */
+
+#define	VFPSCR_STRIDE_OFF	20		/* vector stride -1 */
+#define	VFPSCR_STRIDE_MASK	(0x00300000)
+#define	VFPSCR_LEN_OFF		16		/* vector length -1 */
+#define	VFPSCR_LEN_MASK		(0x00070000)
+#define	VFPSCR_IDE		(0x00008000)	/* input subnormal exc enable */
+#define	VFPSCR_IXE		(0x00001000)	/* inexact exception enable */
+#define	VFPSCR_UFE		(0x00000800)	/* underflow exception enable */
+#define	VFPSCR_OFE		(0x00000400)	/* overflow exception enable */
+#define	VFPSCR_DNZ		(0x00000200)	/* div by zero exception en */
+#define	VFPSCR_IOE		(0x00000100)	/* invalid op exec enable */
+#define	VFPSCR_IDC		(0x00000080)	/* input subnormal cumul */
+#define	VFPSCR_IXC		(0x00000010)	/* Inexact cumulative flag */
+#define	VFPSCR_UFC		(0x00000008)	/* underflow cumulative flag */
+#define	VFPSCR_OFC		(0x00000004)	/* overflow cumulative flag */
+#define	VFPSCR_DZC		(0x00000002)	/* division by zero flag */
+#define	VFPSCR_IOC		(0x00000001)	/* invalid operation cumul */
+
+/* VFPEXC */
+#define	VFPEXC_EX 		(0x80000000)	/* exception v1 v2 */
+#define	VFPEXC_EN		(0x40000000)	/* vfp enable */
+
+/* version 3 registers */
+/* VMVFR0 */
+#define	VMVFR0_RM_OFF		28
+#define	VMVFR0_RM_MASK 		(0xf0000000)	/* VFP rounding modes */
+
+#define	VMVFR0_SV_OFF		24
+#define	VMVFR0_SV_MASK		(0x0f000000)	/* VFP short vector supp */
+#define	VMVFR0_SR_OFF		20
+#define	VMVFR0_SR		(0x00f00000)	/* VFP hw sqrt supp */
+#define	VMVFR0_D_OFF		16
+#define	VMVFR0_D_MASK		(0x000f0000)	/* VFP divide supp */
+#define	VMVFR0_TE_OFF		12
+#define	VMVFR0_TE_MASK		(0x0000f000)	/* VFP trap exception supp */
+#define	VMVFR0_DP_OFF		8
+#define	VMVFR0_DP_MASK		(0x00000f00)	/* VFP double prec support */
+#define	VMVFR0_SP_OFF		4
+#define	VMVFR0_SP_MASK		(0x000000f0)	/* VFP single prec support */
+#define	VMVFR0_RB_MASK		(0x0000000f)	/* VFP 64 bit media support */
+
+/* VMVFR1 */
+#define	VMVFR1_SP_OFF		16
+#define	VMVFR1_SP_MASK 		(0x000f0000)	/* Neon single prec support */
+#define VMVFR1_I_OFF		12
+#define	VMVFR1_I_MASK		(0x0000f000)	/* Neon integer support */
+#define VMVFR1_LS_OFF		8
+#define	VMVFR1_LS_MASK		(0x00000f00)	/* Neon ld/st instr support */
+#define VMVFR1_DN_OFF		4
+#define	VMVFR1_DN_MASK		(0x000000f0)	/* Neon prop NaN support */
+#define	VMVFR1_FZ_MASK		(0x0000000f)	/* Neon denormal arith supp */
+
+#define COPROC10		(0x3 << 20)
+#define COPROC11		(0x3 << 22)
+
+
+#endif
diff -r 7fffa673adcd -r a301a330526b head/sys/arm/include/vmparam.h
--- a/head/sys/arm/include/vmparam.h	Wed Aug 15 11:15:12 2012 +0300
+++ b/head/sys/arm/include/vmparam.h	Wed Aug 15 11:16:36 2012 +0300
@@ -28,7 +28,7 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $FreeBSD: head/sys/arm/include/vmparam.h 236992 2012-06-13 05:02:51Z imp $
+ * $FreeBSD: head/sys/arm/include/vmparam.h 239268 2012-08-15 03:03:03Z gonzo $
  */
 
 #ifndef	_MACHINE_VMPARAM_H_
@@ -116,7 +116,9 @@
 #endif
 #define VM_MAXUSER_ADDRESS	KERNBASE - ARM_KERN_DIRECTMAP
 #else /* ARM_USE_SMALL_ALLOC */
+#ifndef VM_MAXUSER_ADDRESS
 #define VM_MAXUSER_ADDRESS      KERNBASE
+#endif /* VM_MAXUSER_ADDRESS */
 #endif /* ARM_USE_SMALL_ALLOC */
 #define VM_MAX_ADDRESS          VM_MAXUSER_ADDRESS
 
diff -r 7fffa673adcd -r a301a330526b head/sys/arm/lpc/files.lpc
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/head/sys/arm/lpc/files.lpc	Wed Aug 15 11:16:36 2012 +0300
@@ -0,0 +1,21 @@
+# $FreeBSD: head/sys/arm/lpc/files.lpc 239278 2012-08-15 05:37:10Z gonzo $
+arm/arm/bus_space_generic.c		standard
+arm/arm/irq_dispatch.S			standard
+arm/arm/cpufunc_asm_arm9.S		standard
+arm/arm/cpufunc_asm_armv5.S		standard
+arm/lpc/lpc_machdep.c			standard
+arm/lpc/lpc_space.c			standard
+arm/lpc/lpc_pwr.c			standard
+arm/lpc/lpc_intc.c			standard
+arm/lpc/lpc_timer.c			standard
+arm/lpc/lpc_rtc.c			standard
+arm/lpc/if_lpe.c			optional	lpe
+arm/lpc/lpc_ohci.c			optional	ohci
+arm/lpc/lpc_mmc.c			optional	lpcmmc
+arm/lpc/lpc_fb.c			optional	lpcfb
+arm/lpc/lpc_gpio.c			optional	lpcgpio
+arm/lpc/lpc_spi.c			optional	lpcspi
+arm/lpc/lpc_dmac.c			optional	dmac
+arm/lpc/ssd1289.c			optional	ssd1289
+dev/uart/uart_dev_lpc.c			optional	uart
+kern/kern_clocksource.c			standard
diff -r 7fffa673adcd -r a301a330526b head/sys/arm/lpc/if_lpe.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/head/sys/arm/lpc/if_lpe.c	Wed Aug 15 11:16:36 2012 +0300
@@ -0,0 +1,1231 @@
+/*-
+ * Copyright (c) 2011 Jakub Wojciech Klama <jceel at FreeBSD.org>
+ * 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.
+ *
+ */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: head/sys/arm/lpc/if_lpe.c 239278 2012-08-15 05:37:10Z gonzo $");
+
+#include <sys/param.h>
+#include <sys/endian.h>
+#include <sys/systm.h>
+#include <sys/sockio.h>
+#include <sys/mbuf.h>
+#include <sys/malloc.h>
+#include <sys/kernel.h>
+#include <sys/module.h>
+#include <sys/lock.h>
+#include <sys/mutex.h>
+#include <sys/rman.h>
+#include <sys/bus.h>
+#include <sys/socket.h>
+#include <machine/bus.h>
+#include <machine/intr.h>
+
+#include <net/if.h>
+#include <net/if_arp.h>
+#include <net/ethernet.h>
+#include <net/if_dl.h>
+#include <net/if_media.h>
+#include <net/if_types.h>
+
+#include <net/bpf.h>
+
+#include <dev/ofw/ofw_bus.h>
+#include <dev/ofw/ofw_bus_subr.h>
+
+#include <dev/mii/mii.h>
+#include <dev/mii/miivar.h>
+
+#include <arm/lpc/lpcreg.h>
+#include <arm/lpc/lpcvar.h>
+#include <arm/lpc/if_lpereg.h>
+
+#include "miibus_if.h"
+
+#define	DEBUG
+#undef	DEBUG
+
+#ifdef DEBUG
+#define debugf(fmt, args...) do { printf("%s(): ", __func__);   \
+    printf(fmt,##args); } while (0)
+#else
+#define debugf(fmt, args...)
+#endif
+
+struct lpe_dmamap_arg {
+	bus_addr_t		lpe_dma_busaddr;
+};
+
+struct lpe_rxdesc {
+	struct mbuf *		lpe_rxdesc_mbuf;
+	bus_dmamap_t		lpe_rxdesc_dmamap;
+};
+
+struct lpe_txdesc {
+	int			lpe_txdesc_first;
+	struct mbuf *		lpe_txdesc_mbuf;
+	bus_dmamap_t		lpe_txdesc_dmamap;
+};
+
+struct lpe_chain_data {
+	bus_dma_tag_t		lpe_parent_tag;
+	bus_dma_tag_t		lpe_tx_ring_tag;
+	bus_dmamap_t		lpe_tx_ring_map;
+	bus_dma_tag_t		lpe_tx_status_tag;
+	bus_dmamap_t		lpe_tx_status_map;
+	bus_dma_tag_t		lpe_tx_buf_tag;
+	bus_dma_tag_t		lpe_rx_ring_tag;
+	bus_dmamap_t		lpe_rx_ring_map;
+	bus_dma_tag_t		lpe_rx_status_tag;
+	bus_dmamap_t		lpe_rx_status_map;
+	bus_dma_tag_t		lpe_rx_buf_tag;
+	struct lpe_rxdesc	lpe_rx_desc[LPE_RXDESC_NUM];
+	struct lpe_txdesc	lpe_tx_desc[LPE_TXDESC_NUM];
+	int			lpe_tx_prod;
+	int			lpe_tx_last;
+	int			lpe_tx_used;
+};
+
+struct lpe_ring_data {
+	struct lpe_hwdesc *	lpe_rx_ring;
+	struct lpe_hwstatus *	lpe_rx_status;
+	bus_addr_t		lpe_rx_ring_phys;
+	bus_addr_t		lpe_rx_status_phys;
+	struct lpe_hwdesc *	lpe_tx_ring;
+	struct lpe_hwstatus *	lpe_tx_status;
+	bus_addr_t		lpe_tx_ring_phys;
+	bus_addr_t		lpe_tx_status_phys;
+};
+
+struct lpe_softc {
+	struct ifnet *		lpe_ifp;
+	struct mtx		lpe_mtx;
+	phandle_t		lpe_ofw;
+	device_t		lpe_dev;
+	device_t		lpe_miibus;
+	uint8_t			lpe_enaddr[6];
+	struct resource	*	lpe_mem_res;
+	struct resource *	lpe_irq_res;
+	void *			lpe_intrhand;
+	bus_space_tag_t		lpe_bst;
+	bus_space_handle_t	lpe_bsh;
+#define	LPE_FLAG_LINK		(1 << 0)
+	uint32_t		lpe_flags;
+	int			lpe_watchdog_timer;
+	struct callout		lpe_tick;
+	struct lpe_chain_data	lpe_cdata;
+	struct lpe_ring_data	lpe_rdata;
+};
+
+static int lpe_probe(device_t);
+static int lpe_attach(device_t);
+static int lpe_detach(device_t);
+static int lpe_miibus_readreg(device_t, int, int);
+static int lpe_miibus_writereg(device_t, int, int, int);
+static void lpe_miibus_statchg(device_t);
+
+static void lpe_reset(struct lpe_softc *);
+static void lpe_init(void *);
+static void lpe_init_locked(struct lpe_softc *);
+static void lpe_start(struct ifnet *);
+static void lpe_start_locked(struct ifnet *);
+static void lpe_stop(struct lpe_softc *);
+static void lpe_stop_locked(struct lpe_softc *);
+static int lpe_ioctl(struct ifnet *, u_long, caddr_t);
+static void lpe_set_rxmode(struct lpe_softc *);
+static void lpe_set_rxfilter(struct lpe_softc *);
+static void lpe_intr(void *);
+static void lpe_rxintr(struct lpe_softc *);
+static void lpe_txintr(struct lpe_softc *);
+static void lpe_tick(void *);
+static void lpe_watchdog(struct lpe_softc *);
+static int lpe_encap(struct lpe_softc *, struct mbuf **);
+static int lpe_dma_alloc(struct lpe_softc *);
+static int lpe_dma_alloc_rx(struct lpe_softc *);
+static int lpe_dma_alloc_tx(struct lpe_softc *);
+static int lpe_init_rx(struct lpe_softc *);
+static int lpe_init_rxbuf(struct lpe_softc *, int);
+static void lpe_discard_rxbuf(struct lpe_softc *, int);
+static void lpe_dmamap_cb(void *, bus_dma_segment_t *, int, int);
+static int lpe_ifmedia_upd(struct ifnet *);
+static void lpe_ifmedia_sts(struct ifnet *, struct ifmediareq *);
+
+#define	lpe_lock(_sc)		mtx_lock(&(_sc)->lpe_mtx)
+#define	lpe_unlock(_sc)		mtx_unlock(&(_sc)->lpe_mtx)
+#define	lpe_lock_assert(sc)	mtx_assert(&(_sc)->lpe_mtx, MA_OWNED)
+
+#define	lpe_read_4(_sc, _reg)		\
+    bus_space_read_4((_sc)->lpe_bst, (_sc)->lpe_bsh, (_reg))
+#define	lpe_write_4(_sc, _reg, _val)	\
+    bus_space_write_4((_sc)->lpe_bst, (_sc)->lpe_bsh, (_reg), (_val))
+
+#define	LPE_HWDESC_RXERRS	(LPE_HWDESC_CRCERROR | LPE_HWDESC_SYMBOLERROR | \
+    LPE_HWDESC_LENGTHERROR | LPE_HWDESC_ALIGNERROR | LPE_HWDESC_OVERRUN | \
+    LPE_HWDESC_RXNODESCR)
+
+#define	LPE_HWDESC_TXERRS	(LPE_HWDESC_EXCDEFER | LPE_HWDESC_EXCCOLL | \
+    LPE_HWDESC_LATECOLL | LPE_HWDESC_UNDERRUN | LPE_HWDESC_TXNODESCR)
+
+static int
+lpe_probe(device_t dev)
+{
+
+	if (!ofw_bus_is_compatible(dev, "lpc,ethernet"))
+		return (ENXIO);
+
+	device_set_desc(dev, "LPC32x0 10/100 Ethernet");
+	return (BUS_PROBE_DEFAULT);
+}
+
+static int
+lpe_attach(device_t dev)
+{
+	struct lpe_softc *sc = device_get_softc(dev);
+	struct ifnet *ifp;
+	int rid, i;
+	uint32_t val;
+
+	sc->lpe_dev = dev;
+	sc->lpe_ofw = ofw_bus_get_node(dev);
+
+	i = OF_getprop(sc->lpe_ofw, "local-mac-address", (void *)&sc->lpe_enaddr, 6);
+	if (i != 6) {
+		sc->lpe_enaddr[0] = 0x00;
+		sc->lpe_enaddr[1] = 0x11;
+		sc->lpe_enaddr[2] = 0x22;
+		sc->lpe_enaddr[3] = 0x33;
+		sc->lpe_enaddr[4] = 0x44;
+		sc->lpe_enaddr[5] = 0x55;
+	}
+
+	mtx_init(&sc->lpe_mtx, device_get_nameunit(dev), MTX_NETWORK_LOCK,
+	    MTX_DEF);
+
+	callout_init_mtx(&sc->lpe_tick, &sc->lpe_mtx, 0);
+
+	rid = 0;
+	sc->lpe_mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid,
+	    RF_ACTIVE);
+	if (!sc->lpe_mem_res) {
+		device_printf(dev, "cannot allocate memory window\n");
+		goto fail;
+	}
+
+	sc->lpe_bst = rman_get_bustag(sc->lpe_mem_res);
+	sc->lpe_bsh = rman_get_bushandle(sc->lpe_mem_res);
+
+	rid = 0;
+	sc->lpe_irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid,
+	    RF_ACTIVE);
+	if (!sc->lpe_irq_res) {
+		device_printf(dev, "cannot allocate interrupt\n");
+		goto fail;
+	}
+
+	sc->lpe_ifp = if_alloc(IFT_ETHER);
+	if (!sc->lpe_ifp) {
+		device_printf(dev, "cannot allocated ifnet\n");
+		goto fail;
+	}
+
+	ifp = sc->lpe_ifp;
+
+	if_initname(ifp, device_get_name(dev), device_get_unit(dev));
+	ifp->if_softc = sc;
+	ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
+	ifp->if_start = lpe_start;
+	ifp->if_ioctl = lpe_ioctl;
+	ifp->if_init = lpe_init;
+	IFQ_SET_MAXLEN(&ifp->if_snd, IFQ_MAXLEN);
+	ifp->if_snd.ifq_drv_maxlen = IFQ_MAXLEN;
+	IFQ_SET_READY(&ifp->if_snd);
+
+	ether_ifattach(ifp, sc->lpe_enaddr);
+
+	if (bus_setup_intr(dev, sc->lpe_irq_res, INTR_TYPE_NET, NULL,
+	    lpe_intr, sc, &sc->lpe_intrhand)) {
+		device_printf(dev, "cannot establish interrupt handler\n");
+		ether_ifdetach(ifp);
+		goto fail;
+	}
+
+	/* Enable Ethernet clock */
+	lpc_pwr_write(dev, LPC_CLKPWR_MACCLK_CTRL,
+	    LPC_CLKPWR_MACCLK_CTRL_REG |
+	    LPC_CLKPWR_MACCLK_CTRL_SLAVE |
+	    LPC_CLKPWR_MACCLK_CTRL_MASTER |
+	    LPC_CLKPWR_MACCLK_CTRL_HDWINF(3));
+
+	/* Reset chip */
+	lpe_reset(sc);
+
+	/* Initialize MII */
+	val = lpe_read_4(sc, LPE_COMMAND);
+	lpe_write_4(sc, LPE_COMMAND, val | LPE_COMMAND_RMII);
+
+	if (mii_attach(dev, &sc->lpe_miibus, ifp, lpe_ifmedia_upd,
+	    lpe_ifmedia_sts, BMSR_DEFCAPMASK, 0x01, 
+	    MII_OFFSET_ANY, 0)) {
+		device_printf(dev, "cannot find PHY\n");
+		goto fail;
+	}
+
+	lpe_dma_alloc(sc);
+
+	return (0);
+
+fail:
+	if (sc->lpe_ifp)
+		if_free(sc->lpe_ifp);
+	if (sc->lpe_intrhand)
+		bus_teardown_intr(dev, sc->lpe_irq_res, sc->lpe_intrhand);
+	if (sc->lpe_irq_res)
+		bus_release_resource(dev, SYS_RES_IRQ, 0, sc->lpe_irq_res);
+	if (sc->lpe_mem_res)
+		bus_release_resource(dev, SYS_RES_MEMORY, 0, sc->lpe_mem_res);
+	return (ENXIO);
+}
+
+static int
+lpe_detach(device_t dev)
+{
+	struct lpe_softc *sc = device_get_softc(dev);
+
+	lpe_stop(sc);
+
+	if_free(sc->lpe_ifp);
+	bus_teardown_intr(dev, sc->lpe_irq_res, sc->lpe_intrhand);
+	bus_release_resource(dev, SYS_RES_IRQ, 0, sc->lpe_irq_res);
+	bus_release_resource(dev, SYS_RES_MEMORY, 0, sc->lpe_mem_res);
+
+	return (0);
+}
+
+static int
+lpe_miibus_readreg(device_t dev, int phy, int reg)
+{
+	struct lpe_softc *sc = device_get_softc(dev);
+	uint32_t val;
+	int result;
+
+	lpe_write_4(sc, LPE_MCMD, LPE_MCMD_READ);
+	lpe_write_4(sc, LPE_MADR, 
+	    (reg & LPE_MADR_REGMASK) << LPE_MADR_REGSHIFT |
+	    (phy & LPE_MADR_PHYMASK) << LPE_MADR_PHYSHIFT);
+
+	val = lpe_read_4(sc, LPE_MIND);
+
+	/* Wait until request is completed */
+	while (val & LPE_MIND_BUSY) {
+		val = lpe_read_4(sc, LPE_MIND);
+		DELAY(10);
+	}
+
+	if (val & LPE_MIND_INVALID)
+		return (0);
+
+	lpe_write_4(sc, LPE_MCMD, 0);
+	result = (lpe_read_4(sc, LPE_MRDD) & LPE_MRDD_DATAMASK);
+	debugf("phy=%d reg=%d result=0x%04x\n", phy, reg, result);
+
+	return (result);
+}
+
+static int
+lpe_miibus_writereg(device_t dev, int phy, int reg, int data)
+{
+	struct lpe_softc *sc = device_get_softc(dev);
+	uint32_t val;
+
+	debugf("phy=%d reg=%d data=0x%04x\n", phy, reg, data);
+
+	lpe_write_4(sc, LPE_MCMD, LPE_MCMD_WRITE);
+	lpe_write_4(sc, LPE_MADR, 
+	    (reg & LPE_MADR_REGMASK) << LPE_MADR_REGSHIFT |
+	    (phy & LPE_MADR_PHYMASK) << LPE_MADR_PHYSHIFT);
+
+	lpe_write_4(sc, LPE_MWTD, (data & LPE_MWTD_DATAMASK));
+
+	val = lpe_read_4(sc, LPE_MIND);
+
+	/* Wait until request is completed */
+	while (val & LPE_MIND_BUSY) {
+		val = lpe_read_4(sc, LPE_MIND);
+		DELAY(10);
+	}
+
+	return (0);
+}
+
+static void
+lpe_miibus_statchg(device_t dev)
+{
+	struct lpe_softc *sc = device_get_softc(dev);
+	struct mii_data *mii = device_get_softc(sc->lpe_miibus);
+
+	lpe_lock(sc);
+
+	if ((mii->mii_media_status & IFM_ACTIVE) &&
+	    (mii->mii_media_status & IFM_AVALID))
+		sc->lpe_flags |= LPE_FLAG_LINK;
+	else
+		sc->lpe_flags &= ~LPE_FLAG_LINK;
+
+	lpe_unlock(sc);
+}
+
+static void
+lpe_reset(struct lpe_softc *sc)
+{
+	uint32_t mac1;
+
+	/* Enter soft reset mode */
+	mac1 = lpe_read_4(sc, LPE_MAC1);
+	lpe_write_4(sc, LPE_MAC1, mac1 | LPE_MAC1_SOFTRESET | LPE_MAC1_RESETTX |
+	    LPE_MAC1_RESETMCSTX | LPE_MAC1_RESETRX | LPE_MAC1_RESETMCSRX);
+
+	/* Reset registers, Tx path and Rx path */
+	lpe_write_4(sc, LPE_COMMAND, LPE_COMMAND_REGRESET |
+	    LPE_COMMAND_TXRESET | LPE_COMMAND_RXRESET);
+
+	/* Set station address */
+	lpe_write_4(sc, LPE_SA2, sc->lpe_enaddr[1] << 8 | sc->lpe_enaddr[0]);
+	lpe_write_4(sc, LPE_SA1, sc->lpe_enaddr[3] << 8 | sc->lpe_enaddr[2]);
+	lpe_write_4(sc, LPE_SA0, sc->lpe_enaddr[5] << 8 | sc->lpe_enaddr[4]);
+
+	/* Leave soft reset mode */
+	mac1 = lpe_read_4(sc, LPE_MAC1);
+	lpe_write_4(sc, LPE_MAC1, mac1 & ~(LPE_MAC1_SOFTRESET | LPE_MAC1_RESETTX |
+	    LPE_MAC1_RESETMCSTX | LPE_MAC1_RESETRX | LPE_MAC1_RESETMCSRX));
+}
+
+static void
+lpe_init(void *arg)
+{
+	struct lpe_softc *sc = (struct lpe_softc *)arg;
+
+	lpe_lock(sc);
+	lpe_init_locked(sc);
+	lpe_unlock(sc);
+}
+
+static void
+lpe_init_locked(struct lpe_softc *sc)
+{
+	struct ifnet *ifp = sc->lpe_ifp;
+	uint32_t cmd, mac1;
+
+	lpe_lock_assert(sc);
+
+	if (ifp->if_drv_flags & IFF_DRV_RUNNING)
+		return;
+
+	/* Enable Tx and Rx */
+	cmd = lpe_read_4(sc, LPE_COMMAND);
+	lpe_write_4(sc, LPE_COMMAND, cmd | LPE_COMMAND_RXENABLE |
+	    LPE_COMMAND_TXENABLE | LPE_COMMAND_PASSRUNTFRAME);
+
+	/* Enable receive */
+	mac1 = lpe_read_4(sc, LPE_MAC1);
+	lpe_write_4(sc, LPE_MAC1, /*mac1 |*/ LPE_MAC1_RXENABLE | LPE_MAC1_PASSALL);
+
+	lpe_write_4(sc, LPE_MAC2, LPE_MAC2_CRCENABLE | LPE_MAC2_PADCRCENABLE |
+	    LPE_MAC2_FULLDUPLEX);
+
+	lpe_write_4(sc, LPE_MCFG, LPE_MCFG_CLKSEL(7));
+
+	/* Set up Rx filter */
+	lpe_set_rxmode(sc);
+
+	/* Enable interrupts */
+	lpe_write_4(sc, LPE_INTENABLE, LPE_INT_RXOVERRUN | LPE_INT_RXERROR |
+	    LPE_INT_RXFINISH | LPE_INT_RXDONE | LPE_INT_TXUNDERRUN | 
+	    LPE_INT_TXERROR | LPE_INT_TXFINISH | LPE_INT_TXDONE);
+
+	sc->lpe_cdata.lpe_tx_prod = 0;
+	sc->lpe_cdata.lpe_tx_last = 0;
+	sc->lpe_cdata.lpe_tx_used = 0;
+
+	lpe_init_rx(sc);
+
+	/* Initialize Rx packet and status descriptor heads */
+	lpe_write_4(sc, LPE_RXDESC, sc->lpe_rdata.lpe_rx_ring_phys);
+	lpe_write_4(sc, LPE_RXSTATUS, sc->lpe_rdata.lpe_rx_status_phys);
+	lpe_write_4(sc, LPE_RXDESC_NUMBER, LPE_RXDESC_NUM - 1);
+	lpe_write_4(sc, LPE_RXDESC_CONS, 0);
+
+	/* Initialize Tx packet and status descriptor heads */
+	lpe_write_4(sc, LPE_TXDESC, sc->lpe_rdata.lpe_tx_ring_phys);
+	lpe_write_4(sc, LPE_TXSTATUS, sc->lpe_rdata.lpe_tx_status_phys);
+	lpe_write_4(sc, LPE_TXDESC_NUMBER, LPE_TXDESC_NUM - 1);
+	lpe_write_4(sc, LPE_TXDESC_PROD, 0);
+
+	ifp->if_drv_flags |= IFF_DRV_RUNNING;
+	ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
+
+	callout_reset(&sc->lpe_tick, hz, lpe_tick, sc);
+}
+
+static void
+lpe_start(struct ifnet *ifp)
+{
+	struct lpe_softc *sc = (struct lpe_softc *)ifp->if_softc;
+
+	lpe_lock(sc);
+	lpe_start_locked(ifp);
+	lpe_unlock(sc);
+}
+
+static void
+lpe_start_locked(struct ifnet *ifp)
+{
+	struct lpe_softc *sc = (struct lpe_softc *)ifp->if_softc;
+	struct mbuf *m_head;
+	int encap = 0;
+
+	lpe_lock_assert(sc);
+
+	while (!IFQ_DRV_IS_EMPTY(&ifp->if_snd)) {
+		if (lpe_read_4(sc, LPE_TXDESC_PROD) ==
+		    lpe_read_4(sc, LPE_TXDESC_CONS) - 5)
+			break;
+
+		/* Dequeue first packet */
+		IFQ_DRV_DEQUEUE(&ifp->if_snd, m_head);
+		if (!m_head)
+			break;
+
+		lpe_encap(sc, &m_head);
+
+		encap++;
+	}
+
+	/* Submit new descriptor list */
+	if (encap) {
+		lpe_write_4(sc, LPE_TXDESC_PROD, sc->lpe_cdata.lpe_tx_prod);
+		sc->lpe_watchdog_timer = 5;
+	}
+	
+}
+
+static int
+lpe_encap(struct lpe_softc *sc, struct mbuf **m_head)
+{
+	struct lpe_txdesc *txd;
+	struct lpe_hwdesc *hwd;
+	bus_dma_segment_t segs[LPE_MAXFRAGS];
+	int i, err, nsegs, prod;
+
+	lpe_lock_assert(sc);
+	M_ASSERTPKTHDR((*m_head));
+
+	prod = sc->lpe_cdata.lpe_tx_prod;
+	txd = &sc->lpe_cdata.lpe_tx_desc[prod];
+
+	debugf("starting with prod=%d\n", prod);
+
+	err = bus_dmamap_load_mbuf_sg(sc->lpe_cdata.lpe_tx_buf_tag,
+	    txd->lpe_txdesc_dmamap, *m_head, segs, &nsegs, BUS_DMA_NOWAIT);
+
+	if (err)
+		return (err);
+
+	if (nsegs == 0) {
+		m_freem(*m_head);
+		*m_head = NULL;
+		return (EIO);
+	}
+
+        bus_dmamap_sync(sc->lpe_cdata.lpe_tx_buf_tag, txd->lpe_txdesc_dmamap,
+          BUS_DMASYNC_PREREAD);
+        bus_dmamap_sync(sc->lpe_cdata.lpe_tx_ring_tag, sc->lpe_cdata.lpe_tx_ring_map,
+            BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
+
+	txd->lpe_txdesc_first = 1;
+	txd->lpe_txdesc_mbuf = *m_head;
+
+	for (i = 0; i < nsegs; i++) {
+		hwd = &sc->lpe_rdata.lpe_tx_ring[prod];
+		hwd->lhr_data = segs[i].ds_addr;
+		hwd->lhr_control = segs[i].ds_len - 1;
+
+		if (i == nsegs - 1) {
+			hwd->lhr_control |= LPE_HWDESC_LASTFLAG;
+			hwd->lhr_control |= LPE_HWDESC_INTERRUPT;
+			hwd->lhr_control |= LPE_HWDESC_CRC;
+			hwd->lhr_control |= LPE_HWDESC_PAD;
+		}
+
+		LPE_INC(prod, LPE_TXDESC_NUM);
+	}
+
+	bus_dmamap_sync(sc->lpe_cdata.lpe_tx_ring_tag, sc->lpe_cdata.lpe_tx_ring_map,
+	    BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
+
+	sc->lpe_cdata.lpe_tx_used += nsegs;
+	sc->lpe_cdata.lpe_tx_prod = prod;
+
+	return (0);
+}
+
+static void
+lpe_stop(struct lpe_softc *sc)
+{
+	lpe_lock(sc);
+	lpe_stop_locked(sc);
+	lpe_unlock(sc);
+}
+
+static void
+lpe_stop_locked(struct lpe_softc *sc)
+{
+	lpe_lock_assert(sc);
+
+	callout_stop(&sc->lpe_tick);
+
+	/* Disable interrupts */
+	lpe_write_4(sc, LPE_INTCLEAR, 0xffffffff);
+
+	/* Stop EMAC */
+	lpe_write_4(sc, LPE_MAC1, 0);
+	lpe_write_4(sc, LPE_MAC2, 0);
+	lpe_write_4(sc, LPE_COMMAND, 0);
+
+	sc->lpe_ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
+	sc->lpe_ifp->if_drv_flags &= ~IFF_DRV_RUNNING;
+}
+
+static int
+lpe_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
+{
+	struct lpe_softc *sc = ifp->if_softc;
+	struct mii_data *mii = device_get_softc(sc->lpe_miibus);
+	struct ifreq *ifr = (struct ifreq *)data;
+	int err = 0;
+
+	switch (cmd) {
+	case SIOCSIFFLAGS:
+		lpe_lock(sc);
+		if (ifp->if_flags & IFF_UP) {
+			if (ifp->if_drv_flags & IFF_DRV_RUNNING) {
+				lpe_set_rxmode(sc);
+				lpe_set_rxfilter(sc);
+			} else
+				lpe_init_locked(sc);
+		} else
+			lpe_stop(sc);
+		lpe_unlock(sc);
+		break;
+	case SIOCADDMULTI:
+	case SIOCDELMULTI:
+		if (ifp->if_drv_flags & IFF_DRV_RUNNING) {
+			lpe_lock(sc);
+			lpe_set_rxfilter(sc);
+			lpe_unlock(sc);
+		}
+		break;
+	case SIOCGIFMEDIA:
+	case SIOCSIFMEDIA:
+		err = ifmedia_ioctl(ifp, ifr, &mii->mii_media, cmd);
+		break;
+	default:
+		err = ether_ioctl(ifp, cmd, data);
+		break;
+	}
+
+	return (err);
+}
+
+static void lpe_set_rxmode(struct lpe_softc *sc)
+{
+	struct ifnet *ifp = sc->lpe_ifp;
+	uint32_t rxfilt;
+
+	rxfilt = LPE_RXFILTER_UNIHASH | LPE_RXFILTER_MULTIHASH | LPE_RXFILTER_PERFECT;
+
+	if (ifp->if_flags & IFF_BROADCAST)
+		rxfilt |= LPE_RXFILTER_BROADCAST;
+
+	if (ifp->if_flags & IFF_PROMISC)
+		rxfilt |= LPE_RXFILTER_UNICAST | LPE_RXFILTER_MULTICAST;
+
+	if (ifp->if_flags & IFF_ALLMULTI)
+		rxfilt |= LPE_RXFILTER_MULTICAST;
+
+	lpe_write_4(sc, LPE_RXFILTER_CTRL, rxfilt);
+}
+
+static void lpe_set_rxfilter(struct lpe_softc *sc)
+{
+	struct ifnet *ifp = sc->lpe_ifp;
+	struct ifmultiaddr *ifma;
+	int index;
+	uint32_t hashl, hashh;
+
+	hashl = 0;
+	hashh = 0;
+
+	if_maddr_rlock(ifp);
+	TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {
+		if (ifma->ifma_addr->sa_family != AF_LINK)
+			continue;
+
+		index = ether_crc32_be(LLADDR((struct sockaddr_dl *)
+		    ifma->ifma_addr), ETHER_ADDR_LEN) >> 23 & 0x3f;
+
+		if (index > 31)
+			hashh |= (1 << (index - 32));
+		else
+			hashl |= (1 << index);
+	}
+	if_maddr_runlock(ifp);
+
+	/* Program new hash filter */
+	lpe_write_4(sc, LPE_HASHFILTER_L, hashl);
+	lpe_write_4(sc, LPE_HASHFILTER_H, hashh);
+}
+
+static void
+lpe_intr(void *arg)
+{
+	struct lpe_softc *sc = (struct lpe_softc *)arg;
+	uint32_t intstatus;
+
+	debugf("status=0x%08x\n", lpe_read_4(sc, LPE_INTSTATUS));
+
+	lpe_lock(sc);
+
+	while ((intstatus = lpe_read_4(sc, LPE_INTSTATUS))) {
+		if (intstatus & LPE_INT_RXDONE)
+			lpe_rxintr(sc);
+
+		if (intstatus & LPE_INT_TXDONE)
+			lpe_txintr(sc);
+	
+		lpe_write_4(sc, LPE_INTCLEAR, 0xffff);
+	}
+
+	lpe_unlock(sc);
+}
+
+static void
+lpe_rxintr(struct lpe_softc *sc)
+{
+	struct ifnet *ifp = sc->lpe_ifp;
+	struct lpe_hwdesc *hwd;
+	struct lpe_hwstatus *hws;
+	struct lpe_rxdesc *rxd;
+	struct mbuf *m;
+	int prod, cons;
+
+	for (;;) {
+		prod = lpe_read_4(sc, LPE_RXDESC_PROD);
+		cons = lpe_read_4(sc, LPE_RXDESC_CONS);
+		
+		if (prod == cons)
+			break;
+
+		rxd = &sc->lpe_cdata.lpe_rx_desc[cons];
+		hwd = &sc->lpe_rdata.lpe_rx_ring[cons];
+		hws = &sc->lpe_rdata.lpe_rx_status[cons];
+
+		/* Check received frame for errors */
+		if (hws->lhs_info & LPE_HWDESC_RXERRS) {
+			ifp->if_ierrors++;
+			lpe_discard_rxbuf(sc, cons);
+			lpe_init_rxbuf(sc, cons);
+			goto skip;
+		}
+
+		m = rxd->lpe_rxdesc_mbuf;
+		m->m_pkthdr.rcvif = ifp;
+		m->m_data += 2;
+
+		ifp->if_ipackets++;
+
+		lpe_unlock(sc);
+		(*ifp->if_input)(ifp, m);	
+		lpe_lock(sc);
+
+		lpe_init_rxbuf(sc, cons);
+skip:
+		LPE_INC(cons, LPE_RXDESC_NUM);
+		lpe_write_4(sc, LPE_RXDESC_CONS, cons);
+	}
+}
+
+static void
+lpe_txintr(struct lpe_softc *sc)
+{
+	struct ifnet *ifp = sc->lpe_ifp;
+	struct lpe_hwdesc *hwd;
+	struct lpe_hwstatus *hws;
+	struct lpe_txdesc *txd;
+	int cons, last;
+
+	for (;;) {
+		cons = lpe_read_4(sc, LPE_TXDESC_CONS);
+		last = sc->lpe_cdata.lpe_tx_last;
+		
+		if (cons == last)
+			break;
+
+		txd = &sc->lpe_cdata.lpe_tx_desc[last];
+		hwd = &sc->lpe_rdata.lpe_tx_ring[last];
+		hws = &sc->lpe_rdata.lpe_tx_status[last];
+
+		bus_dmamap_sync(sc->lpe_cdata.lpe_tx_buf_tag,
+		    txd->lpe_txdesc_dmamap, BUS_DMASYNC_POSTWRITE);
+
+		ifp->if_collisions += LPE_HWDESC_COLLISIONS(hws->lhs_info);
+
+		if (hws->lhs_info & LPE_HWDESC_TXERRS)
+			ifp->if_oerrors++;
+		else
+			ifp->if_opackets++;
+
+		if (txd->lpe_txdesc_first) {
+			bus_dmamap_unload(sc->lpe_cdata.lpe_tx_buf_tag,
+			    txd->lpe_txdesc_dmamap);	
+
+			m_freem(txd->lpe_txdesc_mbuf);
+			txd->lpe_txdesc_mbuf = NULL;
+			txd->lpe_txdesc_first = 0;
+		}
+
+		sc->lpe_cdata.lpe_tx_used--;
+		LPE_INC(sc->lpe_cdata.lpe_tx_last, LPE_TXDESC_NUM);
+	}
+
+	if (!sc->lpe_cdata.lpe_tx_used)
+		sc->lpe_watchdog_timer = 0;
+}
+
+static void
+lpe_tick(void *arg)
+{
+	struct lpe_softc *sc = (struct lpe_softc *)arg;
+	struct mii_data *mii = device_get_softc(sc->lpe_miibus);
+
+	lpe_lock_assert(sc);
+	
+	mii_tick(mii);
+	lpe_watchdog(sc);
+
+	callout_reset(&sc->lpe_tick, hz, lpe_tick, sc);
+}
+
+static void
+lpe_watchdog(struct lpe_softc *sc)
+{
+	struct ifnet *ifp = sc->lpe_ifp;
+
+	lpe_lock_assert(sc);
+
+	if (sc->lpe_watchdog_timer == 0 || sc->lpe_watchdog_timer--)
+		return;
+
+	/* Chip has stopped responding */
+	device_printf(sc->lpe_dev, "WARNING: chip hangup, restarting...\n");
+	lpe_stop_locked(sc);
+	lpe_init_locked(sc);
+
+	/* Try to resend packets */
+	if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd))
+		lpe_start_locked(ifp);
+}
+
+static int
+lpe_dma_alloc(struct lpe_softc *sc)
+{
+	int err;
+
+	/* Create parent DMA tag */
+	err = bus_dma_tag_create(
+	    bus_get_dma_tag(sc->lpe_dev),
+	    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, 0,	/* maxsegsize, flags */
+	    NULL, NULL,			/* lockfunc, lockarg */
+	    &sc->lpe_cdata.lpe_parent_tag);
+
+	if (err) {
+		device_printf(sc->lpe_dev, "cannot create parent DMA tag\n");
+		return (err);
+	}
+
+	err = lpe_dma_alloc_rx(sc);
+	if (err)
+		return (err);
+
+	err = lpe_dma_alloc_tx(sc);
+	if (err)
+		return (err);
+
+	return (0);
+}
+
+static int
+lpe_dma_alloc_rx(struct lpe_softc *sc)
+{
+	struct lpe_rxdesc *rxd;
+	struct lpe_dmamap_arg ctx;
+	int err, i;
+
+	/* Create tag for Rx ring */
+	err = bus_dma_tag_create(
+	    sc->lpe_cdata.lpe_parent_tag,
+	    LPE_DESC_ALIGN, 0,		/* alignment, boundary */
+	    BUS_SPACE_MAXADDR,		/* lowaddr */
+	    BUS_SPACE_MAXADDR,		/* highaddr */
+	    NULL, NULL,			/* filter, filterarg */
+	    LPE_RXDESC_SIZE, 1,		/* maxsize, nsegments */
+	    LPE_RXDESC_SIZE, 0,		/* maxsegsize, flags */
+	    NULL, NULL,			/* lockfunc, lockarg */
+	    &sc->lpe_cdata.lpe_rx_ring_tag);
+
+	if (err) {
+		device_printf(sc->lpe_dev, "cannot create Rx ring DMA tag\n");
+		goto fail;
+	}
+
+	/* Create tag for Rx status ring */
+	err = bus_dma_tag_create(
+	    sc->lpe_cdata.lpe_parent_tag,
+	    LPE_DESC_ALIGN, 0,		/* alignment, boundary */
+	    BUS_SPACE_MAXADDR,		/* lowaddr */
+	    BUS_SPACE_MAXADDR,		/* highaddr */
+	    NULL, NULL,			/* filter, filterarg */
+	    LPE_RXSTATUS_SIZE, 1,	/* maxsize, nsegments */
+	    LPE_RXSTATUS_SIZE, 0,	/* maxsegsize, flags */
+	    NULL, NULL,			/* lockfunc, lockarg */
+	    &sc->lpe_cdata.lpe_rx_status_tag);
+
+	if (err) {
+		device_printf(sc->lpe_dev, "cannot create Rx status ring DMA tag\n");
+		goto fail;
+	}
+
+	/* Create tag for Rx buffers */
+	err = bus_dma_tag_create(
+	    sc->lpe_cdata.lpe_parent_tag,
+	    LPE_DESC_ALIGN, 0,		/* alignment, boundary */
+	    BUS_SPACE_MAXADDR,		/* lowaddr */
+	    BUS_SPACE_MAXADDR,		/* highaddr */
+	    NULL, NULL,			/* filter, filterarg */
+	    MCLBYTES * LPE_RXDESC_NUM,	/* maxsize */
+	    LPE_RXDESC_NUM,		/* segments */
+	    MCLBYTES, 0,		/* maxsegsize, flags */
+	    NULL, NULL,			/* lockfunc, lockarg */
+	    &sc->lpe_cdata.lpe_rx_buf_tag);
+
+	if (err) {
+		device_printf(sc->lpe_dev, "cannot create Rx buffers DMA tag\n");
+		goto fail;
+	}
+
+	/* Allocate Rx DMA ring */
+	err = bus_dmamem_alloc(sc->lpe_cdata.lpe_rx_ring_tag,
+	    (void **)&sc->lpe_rdata.lpe_rx_ring, BUS_DMA_WAITOK | BUS_DMA_COHERENT |
+	    BUS_DMA_ZERO, &sc->lpe_cdata.lpe_rx_ring_map);
+
+	err = bus_dmamap_load(sc->lpe_cdata.lpe_rx_ring_tag, 
+	    sc->lpe_cdata.lpe_rx_ring_map, sc->lpe_rdata.lpe_rx_ring,
+	    LPE_RXDESC_SIZE, lpe_dmamap_cb, &ctx, 0);
+
+	sc->lpe_rdata.lpe_rx_ring_phys = ctx.lpe_dma_busaddr;
+
+	/* Allocate Rx status ring */
+	err = bus_dmamem_alloc(sc->lpe_cdata.lpe_rx_status_tag,
+	    (void **)&sc->lpe_rdata.lpe_rx_status, BUS_DMA_WAITOK | BUS_DMA_COHERENT |
+	    BUS_DMA_ZERO, &sc->lpe_cdata.lpe_rx_status_map);
+
+	err = bus_dmamap_load(sc->lpe_cdata.lpe_rx_status_tag, 
+	    sc->lpe_cdata.lpe_rx_status_map, sc->lpe_rdata.lpe_rx_status,
+	    LPE_RXDESC_SIZE, lpe_dmamap_cb, &ctx, 0);
+
+	sc->lpe_rdata.lpe_rx_status_phys = ctx.lpe_dma_busaddr;
+
+
+	/* Create Rx buffers DMA map */
+	for (i = 0; i < LPE_RXDESC_NUM; i++) {
+		rxd = &sc->lpe_cdata.lpe_rx_desc[i];
+		rxd->lpe_rxdesc_mbuf = NULL;
+		rxd->lpe_rxdesc_dmamap = NULL;
+
+		err = bus_dmamap_create(sc->lpe_cdata.lpe_rx_buf_tag, 0,
+		    &rxd->lpe_rxdesc_dmamap);
+
+		if (err) {
+			device_printf(sc->lpe_dev, "cannot create Rx DMA map\n");
+			return (err);
+		}
+	}
+
+	return (0);
+fail:
+	return (err);
+}
+
+static int
+lpe_dma_alloc_tx(struct lpe_softc *sc)
+{
+	struct lpe_txdesc *txd;
+	struct lpe_dmamap_arg ctx;
+	int err, i;
+
+	/* Create tag for Tx ring */
+	err = bus_dma_tag_create(
+	    sc->lpe_cdata.lpe_parent_tag,
+	    LPE_DESC_ALIGN, 0,		/* alignment, boundary */
+	    BUS_SPACE_MAXADDR,		/* lowaddr */
+	    BUS_SPACE_MAXADDR,		/* highaddr */
+	    NULL, NULL,			/* filter, filterarg */
+	    LPE_TXDESC_SIZE, 1,		/* maxsize, nsegments */
+	    LPE_TXDESC_SIZE, 0,		/* maxsegsize, flags */
+	    NULL, NULL,			/* lockfunc, lockarg */
+	    &sc->lpe_cdata.lpe_tx_ring_tag);
+
+	if (err) {
+		device_printf(sc->lpe_dev, "cannot create Tx ring DMA tag\n");
+		goto fail;
+	}
+
+	/* Create tag for Tx status ring */
+	err = bus_dma_tag_create(
+	    sc->lpe_cdata.lpe_parent_tag,
+	    LPE_DESC_ALIGN, 0,		/* alignment, boundary */
+	    BUS_SPACE_MAXADDR,		/* lowaddr */
+	    BUS_SPACE_MAXADDR,		/* highaddr */
+	    NULL, NULL,			/* filter, filterarg */
+	    LPE_TXSTATUS_SIZE, 1,	/* maxsize, nsegments */
+	    LPE_TXSTATUS_SIZE, 0,	/* maxsegsize, flags */
+	    NULL, NULL,			/* lockfunc, lockarg */
+	    &sc->lpe_cdata.lpe_tx_status_tag);
+
+	if (err) {
+		device_printf(sc->lpe_dev, "cannot create Tx status ring DMA tag\n");
+		goto fail;
+	}
+
+	/* Create tag for Tx buffers */
+	err = bus_dma_tag_create(
+	    sc->lpe_cdata.lpe_parent_tag,
+	    LPE_DESC_ALIGN, 0,		/* alignment, boundary */
+	    BUS_SPACE_MAXADDR,		/* lowaddr */
+	    BUS_SPACE_MAXADDR,		/* highaddr */
+	    NULL, NULL,			/* filter, filterarg */
+	    MCLBYTES * LPE_TXDESC_NUM,	/* maxsize */
+	    LPE_TXDESC_NUM,		/* segments */
+	    MCLBYTES, 0,		/* maxsegsize, flags */
+	    NULL, NULL,			/* lockfunc, lockarg */
+	    &sc->lpe_cdata.lpe_tx_buf_tag);
+
+	if (err) {
+		device_printf(sc->lpe_dev, "cannot create Tx buffers DMA tag\n");
+		goto fail;
+	}
+
+	/* Allocate Tx DMA ring */
+	err = bus_dmamem_alloc(sc->lpe_cdata.lpe_tx_ring_tag,
+	    (void **)&sc->lpe_rdata.lpe_tx_ring, BUS_DMA_WAITOK | BUS_DMA_COHERENT |
+	    BUS_DMA_ZERO, &sc->lpe_cdata.lpe_tx_ring_map);
+
+	err = bus_dmamap_load(sc->lpe_cdata.lpe_tx_ring_tag, 
+	    sc->lpe_cdata.lpe_tx_ring_map, sc->lpe_rdata.lpe_tx_ring,
+	    LPE_RXDESC_SIZE, lpe_dmamap_cb, &ctx, 0);
+
+	sc->lpe_rdata.lpe_tx_ring_phys = ctx.lpe_dma_busaddr;
+
+	/* Allocate Tx status ring */
+	err = bus_dmamem_alloc(sc->lpe_cdata.lpe_tx_status_tag,
+	    (void **)&sc->lpe_rdata.lpe_tx_status, BUS_DMA_WAITOK | BUS_DMA_COHERENT |
+	    BUS_DMA_ZERO, &sc->lpe_cdata.lpe_tx_status_map);
+
+	err = bus_dmamap_load(sc->lpe_cdata.lpe_tx_status_tag, 
+	    sc->lpe_cdata.lpe_tx_status_map, sc->lpe_rdata.lpe_tx_status,
+	    LPE_RXDESC_SIZE, lpe_dmamap_cb, &ctx, 0);
+
+	sc->lpe_rdata.lpe_tx_status_phys = ctx.lpe_dma_busaddr;
+
+
+	/* Create Tx buffers DMA map */
+	for (i = 0; i < LPE_TXDESC_NUM; i++) {
+		txd = &sc->lpe_cdata.lpe_tx_desc[i];
+		txd->lpe_txdesc_mbuf = NULL;
+		txd->lpe_txdesc_dmamap = NULL;
+		txd->lpe_txdesc_first = 0;
+
+		err = bus_dmamap_create(sc->lpe_cdata.lpe_tx_buf_tag, 0,
+		    &txd->lpe_txdesc_dmamap);
+
+		if (err) {
+			device_printf(sc->lpe_dev, "cannot create Tx DMA map\n");
+			return (err);
+		}
+	}
+
+	return (0);
+fail:
+	return (err);
+}
+
+static int
+lpe_init_rx(struct lpe_softc *sc)
+{
+	int i, err;
+
+	for (i = 0; i < LPE_RXDESC_NUM; i++) {
+		err = lpe_init_rxbuf(sc, i);
+		if (err)
+			return (err);
+	}
+
+	return (0);
+}
+
+static int
+lpe_init_rxbuf(struct lpe_softc *sc, int n)
+{
+	struct lpe_rxdesc *rxd;
+	struct lpe_hwdesc *hwd;
+	struct lpe_hwstatus *hws;
+	struct mbuf *m;
+	bus_dma_segment_t segs[1];
+	int nsegs;
+
+	rxd = &sc->lpe_cdata.lpe_rx_desc[n];
+	hwd = &sc->lpe_rdata.lpe_rx_ring[n];
+	hws = &sc->lpe_rdata.lpe_rx_status[n];
+	m = m_getcl(M_DONTWAIT, MT_DATA, M_PKTHDR);
+
+	if (!m) {
+		device_printf(sc->lpe_dev, "WARNING: mbufs exhausted!\n");
+		return (ENOBUFS);
+	}
+
+	m->m_len = m->m_pkthdr.len = MCLBYTES;
+
+	bus_dmamap_unload(sc->lpe_cdata.lpe_rx_buf_tag, rxd->lpe_rxdesc_dmamap);
+
+	if (bus_dmamap_load_mbuf_sg(sc->lpe_cdata.lpe_rx_buf_tag, 
+	    rxd->lpe_rxdesc_dmamap, m, segs, &nsegs, 0)) {
+		m_freem(m);
+		return (ENOBUFS);
+	}
+
+	bus_dmamap_sync(sc->lpe_cdata.lpe_rx_buf_tag, rxd->lpe_rxdesc_dmamap, 
+	    BUS_DMASYNC_PREREAD);
+
+	rxd->lpe_rxdesc_mbuf = m;
+	hwd->lhr_data = segs[0].ds_addr + 2;
+	hwd->lhr_control = (segs[0].ds_len - 1) | LPE_HWDESC_INTERRUPT;
+
+	return (0);
+}
+
+static void
+lpe_discard_rxbuf(struct lpe_softc *sc, int n)
+{
+	struct lpe_rxdesc *rxd;
+	struct lpe_hwdesc *hwd;
+
+	rxd = &sc->lpe_cdata.lpe_rx_desc[n];
+	hwd = &sc->lpe_rdata.lpe_rx_ring[n];
+
+	bus_dmamap_unload(sc->lpe_cdata.lpe_rx_buf_tag, rxd->lpe_rxdesc_dmamap);
+
+	hwd->lhr_data = 0;
+	hwd->lhr_control = 0;
+
+	if (rxd->lpe_rxdesc_mbuf) {
+		m_freem(rxd->lpe_rxdesc_mbuf); 
+		rxd->lpe_rxdesc_mbuf = NULL;
+	}
+}
+
+static void
+lpe_dmamap_cb(void *arg, bus_dma_segment_t *segs, int nseg, int error)
+{
+	struct lpe_dmamap_arg *ctx;
+
+	if (error)
+		return;
+
+	ctx = (struct lpe_dmamap_arg *)arg;
+	ctx->lpe_dma_busaddr = segs[0].ds_addr;
+}
+
+static int
+lpe_ifmedia_upd(struct ifnet *ifp)
+{
+	return (0);
+}
+
+static void
+lpe_ifmedia_sts(struct ifnet *ifp, struct ifmediareq *ifmr)
+{
+	struct lpe_softc *sc = ifp->if_softc;
+	struct mii_data *mii = device_get_softc(sc->lpe_miibus);
+
+	lpe_lock(sc);
+	mii_pollstat(mii);
+	ifmr->ifm_active = mii->mii_media_active;
+	ifmr->ifm_status = mii->mii_media_status;
+	lpe_unlock(sc);
+}
+
+static device_method_t lpe_methods[] = {
+	/* Device interface */
+	DEVMETHOD(device_probe,		lpe_probe),
+	DEVMETHOD(device_attach,	lpe_attach),
+	DEVMETHOD(device_detach,	lpe_detach),
+
+	/* Bus interface */
+	DEVMETHOD(bus_print_child,	bus_generic_print_child),
+
+	/* MII interface */
+	DEVMETHOD(miibus_readreg,	lpe_miibus_readreg),
+	DEVMETHOD(miibus_writereg,	lpe_miibus_writereg),
+	DEVMETHOD(miibus_statchg,	lpe_miibus_statchg),
+	{ 0, 0 }
+};
+
+static driver_t lpe_driver = {
+	"lpe",
+	lpe_methods,
+	sizeof(struct lpe_softc),
+};
+
+static devclass_t lpe_devclass;
+
+DRIVER_MODULE(lpe, simplebus, lpe_driver, lpe_devclass, 0, 0);
+DRIVER_MODULE(miibus, lpe, miibus_driver, miibus_devclass, 0, 0);
+MODULE_DEPEND(lpe, obio, 1, 1, 1);
+MODULE_DEPEND(lpe, miibus, 1, 1, 1);
+MODULE_DEPEND(lpe, ether, 1, 1, 1);
diff -r 7fffa673adcd -r a301a330526b head/sys/arm/lpc/if_lpereg.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/head/sys/arm/lpc/if_lpereg.h	Wed Aug 15 11:16:36 2012 +0300
@@ -0,0 +1,208 @@
+/*-
+ * Copyright (c) 2011 Jakub Wojciech Klama <jceel at FreeBSD.org>
+ * 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: head/sys/arm/lpc/if_lpereg.h 239278 2012-08-15 05:37:10Z gonzo $
+ */
+
+#ifndef	_ARM_LPC_IF_LPEREG_H
+#define	_ARM_LPC_IF_LPEREG_H
+
+#define	LPE_MAC1		0x000
+#define	LPE_MAC1_RXENABLE	(1 << 0)
+#define	LPE_MAC1_PASSALL	(1 << 1)
+#define	LPE_MAC1_RXFLOWCTRL	(1 << 2)
+#define	LPE_MAC1_TXFLOWCTRL	(1 << 3)
+#define	LPE_MAC1_LOOPBACK	(1 << 4)
+#define	LPE_MAC1_RESETTX	(1 << 8)
+#define	LPE_MAC1_RESETMCSTX	(1 << 9)
+#define	LPE_MAC1_RESETRX	(1 << 10)
+#define	LPE_MAC1_RESETMCSRX	(1 << 11)
+#define	LPE_MAC1_SIMRESET	(1 << 14)
+#define	LPE_MAC1_SOFTRESET	(1 << 15)
+#define	LPE_MAC2		0x004
+#define	LPE_MAC2_FULLDUPLEX	(1 << 0)
+#define	LPE_MAC2_FRAMELENCHECK	(1 << 1)
+#define	LPE_MAC2_HUGEFRAME	(1 << 2)
+#define	LPE_MAC2_DELAYEDCRC	(1 << 3)
+#define	LPE_MAC2_CRCENABLE	(1 << 4)
+#define	LPE_MAC2_PADCRCENABLE	(1 << 5)
+#define	LPE_MAC2_VLANPADENABLE	(1 << 6)
+#define	LPE_MAC2_AUTOPADENABLE	(1 << 7)
+#define	LPE_MAC2_PUREPREAMBLE	(1 << 8)
+#define	LPE_MAC2_LONGPREAMBLE	(1 << 9)
+#define	LPE_MAC2_NOBACKOFF	(1 << 12)
+#define	LPE_MAC2_BACKPRESSURE	(1 << 13)
+#define	LPE_MAC2_EXCESSDEFER	(1 << 14)
+#define	LPE_IPGT		0x008
+#define	LPE_IPGR		0x00c
+#define	LPE_CLRT		0x010
+#define	LPE_MAXF		0x014
+#define	LPE_SUPP		0x018
+#define	LPE_SUPP_SPEED		(1 << 8)
+#define	LPE_TEST		0x01c
+#define	LPE_MCFG		0x020
+#define	LPE_MCFG_SCANINCR	(1 << 0)
+#define	LPE_MCFG_SUPPREAMBLE	(1 << 1)
+#define	LPE_MCFG_CLKSEL(_n)	((_n & 0x7) << 2)
+#define	LPC_MCFG_RESETMII	(1 << 15)
+#define	LPE_MCMD		0x024
+#define	LPE_MCMD_READ		(1 << 0)
+#define	LPE_MCMD_WRITE		(0 << 0)
+#define	LPE_MCMD_SCAN		(1 << 1)
+#define	LPE_MADR		0x028
+#define	LPE_MADR_REGMASK	0x1f
+#define	LPE_MADR_REGSHIFT	0
+#define	LPE_MADR_PHYMASK	0x1f
+#define	LPE_MADR_PHYSHIFT	8
+#define	LPE_MWTD		0x02c
+#define	LPE_MWTD_DATAMASK	0xffff
+#define	LPE_MRDD		0x030
+#define	LPE_MRDD_DATAMASK	0xffff
+#define	LPE_MIND		0x034
+#define	LPE_MIND_BUSY		(1 << 0)
+#define	LPE_MIND_SCANNING	(1 << 1)
+#define	LPE_MIND_INVALID	(1 << 2)
+#define	LPE_MIND_MIIFAIL	(1 << 3)
+#define	LPE_SA0			0x040
+#define	LPE_SA1			0x044
+#define	LPE_SA2			0x048
+#define	LPE_COMMAND		0x100
+#define	LPE_COMMAND_RXENABLE	(1 << 0)
+#define	LPE_COMMAND_TXENABLE	(1 << 1)
+#define	LPE_COMMAND_REGRESET	(1 << 3)
+#define	LPE_COMMAND_TXRESET	(1 << 4)
+#define	LPE_COMMAND_RXRESET	(1 << 5)
+#define	LPE_COMMAND_PASSRUNTFRAME	(1 << 6)
+#define	LPE_COMMAND_PASSRXFILTER	(1 << 7)
+#define	LPE_COMMAND_TXFLOWCTL		(1 << 8)
+#define	LPE_COMMAND_RMII		(1 << 9)
+#define	LPE_COMMAND_FULLDUPLEX		(1 << 10)
+#define	LPE_STATUS		0x104
+#define	LPE_STATUS_RXACTIVE		(1 << 0)
+#define	LPE_STATUS_TXACTIVE		(1 << 1)
+#define	LPE_RXDESC		0x108
+#define	LPE_RXSTATUS		0x10c
+#define	LPE_RXDESC_NUMBER	0x110
+#define	LPE_RXDESC_PROD		0x114
+#define	LPE_RXDESC_CONS		0x118
+#define	LPE_TXDESC		0x11c
+#define	LPE_TXSTATUS		0x120
+#define	LPE_TXDESC_NUMBER	0x124
+#define	LPE_TXDESC_PROD		0x128
+#define	LPE_TXDESC_CONS		0x12c
+#define	LPE_TSV0		0x158
+#define	LPE_TSV1		0x15c
+#define	LPE_RSV			0x160
+#define	LPE_FLOWCONTROL_COUNTER	0x170
+#define	LPE_FLOWCONTROL_STATUS	0x174
+#define	LPE_RXFILTER_CTRL	0x200
+#define	LPE_RXFILTER_UNICAST	(1 << 0)
+#define	LPE_RXFILTER_BROADCAST	(1 << 1)
+#define LPE_RXFILTER_MULTICAST	(1 << 2)
+#define	LPE_RXFILTER_UNIHASH	(1 << 3)
+#define	LPE_RXFILTER_MULTIHASH	(1 << 4)
+#define	LPE_RXFILTER_PERFECT	(1 << 5)
+#define	LPE_RXFILTER_WOL	(1 << 12)
+#define	LPE_RXFILTER_FILTWOL	(1 << 13)
+#define	LPE_RXFILTER_WOL_STATUS	0x204
+#define	LPE_RXFILTER_WOL_CLEAR	0x208
+#define	LPE_HASHFILTER_L	0x210
+#define	LPE_HASHFILTER_H	0x214
+#define	LPE_INTSTATUS		0xfe0
+#define	LPE_INTENABLE		0xfe4
+#define	LPE_INTCLEAR		0xfe8
+#define	LPE_INTSET		0xfec
+#define	LPE_INT_RXOVERRUN	(1 << 0)
+#define	LPE_INT_RXERROR		(1 << 1)
+#define	LPE_INT_RXFINISH	(1 << 2)
+#define	LPE_INT_RXDONE		(1 << 3)
+#define	LPE_INT_TXUNDERRUN	(1 << 4)
+#define	LPE_INT_TXERROR		(1 << 5)
+#define	LPE_INT_TXFINISH	(1 << 6)
+#define	LPE_INT_TXDONE		(1 << 7)
+#define	LPE_INT_SOFTINT		(1 << 12)
+#define	LPE_INTWAKEUPINT	(1 << 13)
+#define	LPE_POWERDOWN		0xff4
+
+#define	LPE_DESC_ALIGN		8
+#define	LPE_TXDESC_NUM		128
+#define	LPE_RXDESC_NUM		128
+#define	LPE_TXDESC_SIZE		(LPE_TXDESC_NUM * sizeof(struct lpe_hwdesc))
+#define	LPE_RXDESC_SIZE		(LPE_RXDESC_NUM * sizeof(struct lpe_hwdesc))
+#define	LPE_TXSTATUS_SIZE	(LPE_TXDESC_NUM * sizeof(struct lpe_hwstatus))
+#define	LPE_RXSTATUS_SIZE	(LPE_RXDESC_NUM * sizeof(struct lpe_hwstatus))
+#define	LPE_MAXFRAGS		8
+
+struct lpe_hwdesc {
+	uint32_t	lhr_data;
+	uint32_t	lhr_control;
+};
+
+struct lpe_hwstatus {
+	uint32_t	lhs_info;
+	uint32_t	lhs_crc;
+};
+
+#define	LPE_INC(x, y)		(x) = ((x) == ((y)-1)) ? 0 : (x)+1
+
+/* These are valid for both Rx and Tx descriptors */
+#define	LPE_HWDESC_SIZE_MASK	(1 << 10)
+#define	LPE_HWDESC_INTERRUPT	(1 << 31)
+
+/* These are valid for Tx descriptors */
+#define	LPE_HWDESC_LAST		(1 << 30)
+#define	LPE_HWDESC_CRC		(1 << 29)
+#define	LPE_HWDESC_PAD		(1 << 28)
+#define	LPE_HWDESC_HUGE		(1 << 27)
+#define	LPE_HWDESC_OVERRIDE	(1 << 26)
+
+/* These are valid for Tx status descriptors */
+#define	LPE_HWDESC_COLLISIONS(_n) (((_n) >> 21) & 0x7)
+#define	LPE_HWDESC_DEFER	(1 << 25)
+#define	LPE_HWDESC_EXCDEFER	(1 << 26)
+#define	LPE_HWDESC_EXCCOLL	(1 << 27)
+#define	LPE_HWDESC_LATECOLL	(1 << 28)
+#define	LPE_HWDESC_UNDERRUN	(1 << 29)
+#define	LPE_HWDESC_TXNODESCR	(1 << 30)
+#define	LPE_HWDESC_ERROR	(1 << 31)
+
+/* These are valid for Rx status descriptors */
+#define	LPE_HWDESC_CONTROL	(1 << 18)
+#define	LPE_HWDESC_VLAN		(1 << 19)
+#define	LPE_HWDESC_FAILFILTER	(1 << 20)
+#define	LPE_HWDESC_MULTICAST	(1 << 21)
+#define	LPE_HWDESC_BROADCAST	(1 << 22)
+#define	LPE_HWDESC_CRCERROR	(1 << 23)
+#define	LPE_HWDESC_SYMBOLERROR	(1 << 24)
+#define	LPE_HWDESC_LENGTHERROR	(1 << 25)
+#define	LPE_HWDESC_RANGEERROR	(1 << 26)
+#define	LPE_HWDESC_ALIGNERROR	(1 << 27)
+#define	LPE_HWDESC_OVERRUN	(1 << 28)
+#define	LPE_HWDESC_RXNODESCR	(1 << 29)
+#define	LPE_HWDESC_LASTFLAG	(1 << 30)
+#define	LPE_HWDESC_ERROR	(1 << 31)
+
+
+#endif	/* _ARM_LPC_IF_LPEREG_H */
diff -r 7fffa673adcd -r a301a330526b head/sys/arm/lpc/lpc_dmac.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/head/sys/arm/lpc/lpc_dmac.c	Wed Aug 15 11:16:36 2012 +0300
@@ -0,0 +1,288 @@
+/*-
+ * Copyright (c) 2011 Jakub Wojciech Klama <jceel at FreeBSD.org>
+ * 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.
+ *
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: head/sys/arm/lpc/lpc_dmac.c 239278 2012-08-15 05:37:10Z gonzo $");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/bio.h>
+#include <sys/bus.h>
+#include <sys/conf.h>
+#include <sys/endian.h>
+#include <sys/kernel.h>
+#include <sys/kthread.h>
+#include <sys/lock.h>
+#include <sys/malloc.h>
+#include <sys/module.h>
+#include <sys/mutex.h>
+#include <sys/queue.h>
+#include <sys/resource.h>
+#include <sys/rman.h>
+#include <sys/time.h>
+#include <sys/timetc.h>
+#include <sys/watchdog.h>
+
+#include <sys/kdb.h>
+
+#include <dev/ofw/ofw_bus.h>
+#include <dev/ofw/ofw_bus_subr.h>
+
+#include <arm/lpc/lpcreg.h>
+#include <arm/lpc/lpcvar.h>
+
+struct lpc_dmac_channel
+{
+	struct lpc_dmac_channel_config *ldc_config;
+	int			ldc_flags;
+};
+
+struct lpc_dmac_softc
+{
+	device_t		ld_dev;
+	struct mtx		ld_mtx;
+	struct resource *	ld_mem_res;
+	struct resource *	ld_irq_res;
+	bus_space_tag_t		ld_bst;
+	bus_space_handle_t	ld_bsh;
+	void *			ld_intrhand;
+	struct lpc_dmac_channel	ld_channels[8];
+};
+
+static struct lpc_dmac_softc *lpc_dmac_sc = NULL;
+
+static int lpc_dmac_probe(device_t);
+static int lpc_dmac_attach(device_t);
+static void lpc_dmac_intr(void *);
+
+#define	lpc_dmac_read_4(_sc, _reg) \
+    bus_space_read_4(_sc->ld_bst, _sc->ld_bsh, _reg)
+#define	lpc_dmac_write_4(_sc, _reg, _value) \
+    bus_space_write_4(_sc->ld_bst, _sc->ld_bsh, _reg, _value)
+#define	lpc_dmac_read_ch_4(_sc, _n, _reg) \
+    bus_space_read_4(_sc->ld_bst, _sc->ld_bsh, (_reg + LPC_DMAC_CHADDR(_n)))
+#define	lpc_dmac_write_ch_4(_sc, _n, _reg, _value) \
+    bus_space_write_4(_sc->ld_bst, _sc->ld_bsh, (_reg + LPC_DMAC_CHADDR(_n)), _value)
+
+static int lpc_dmac_probe(device_t dev)
+{
+	if (!ofw_bus_is_compatible(dev, "lpc,dmac"))
+		return (ENXIO);
+
+	device_set_desc(dev, "LPC32x0 General Purpose DMA controller");
+	return (BUS_PROBE_DEFAULT);
+}
+
+static int lpc_dmac_attach(device_t dev)
+{
+	struct lpc_dmac_softc *sc = device_get_softc(dev);
+	int rid;
+
+	rid = 0;
+	sc->ld_mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid,
+	    RF_ACTIVE);
+	if (!sc->ld_mem_res) {
+		device_printf(dev, "cannot allocate memory window\n");
+		return (ENXIO);
+	}
+
+	sc->ld_bst = rman_get_bustag(sc->ld_mem_res);
+	sc->ld_bsh = rman_get_bushandle(sc->ld_mem_res);
+
+	rid = 0;
+	sc->ld_irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid,
+	    RF_ACTIVE);
+	if (!sc->ld_irq_res) {
+		device_printf(dev, "cannot allocate cmd interrupt\n");
+		bus_release_resource(dev, SYS_RES_MEMORY, 0, sc->ld_mem_res);
+		return (ENXIO);
+	}
+
+	if (bus_setup_intr(dev, sc->ld_irq_res, INTR_TYPE_MISC | INTR_MPSAFE,
+	    NULL, lpc_dmac_intr, sc, &sc->ld_intrhand))
+	{
+		bus_release_resource(dev, SYS_RES_MEMORY, 0, sc->ld_mem_res);
+		bus_release_resource(dev, SYS_RES_IRQ, 0, sc->ld_irq_res);
+		device_printf(dev, "cannot setup interrupt handler\n");
+		return (ENXIO);
+	}
+
+	lpc_dmac_sc = sc;
+
+	lpc_pwr_write(dev, LPC_CLKPWR_DMACLK_CTRL, LPC_CLKPWR_DMACLK_CTRL_EN);
+	lpc_dmac_write_4(sc, LPC_DMAC_CONFIG, LPC_DMAC_CONFIG_ENABLE);
+
+	lpc_dmac_write_4(sc, LPC_DMAC_INTTCCLEAR, 0xff);
+	lpc_dmac_write_4(sc, LPC_DMAC_INTERRCLEAR, 0xff);
+
+	return (0);
+}
+
+static void lpc_dmac_intr(void *arg)
+{
+	struct lpc_dmac_softc *sc = (struct lpc_dmac_softc *)arg;
+	struct lpc_dmac_channel *ch;
+	uint32_t intstat, tcstat, errstat;
+	int i;
+
+	do {
+		intstat = lpc_dmac_read_4(sc, LPC_DMAC_INTSTAT);
+
+		for (i = 0; i < LPC_DMAC_CHNUM; i++) {
+			if ((intstat & (1 << i)) == 0)
+				continue;
+	
+			ch = &sc->ld_channels[i];
+			tcstat = lpc_dmac_read_4(sc, LPC_DMAC_INTTCSTAT);
+			errstat = lpc_dmac_read_4(sc, LPC_DMAC_INTERRSTAT);
+
+			if (tcstat & (1 << i)) {
+				ch->ldc_config->ldc_success_handler(
+				    ch->ldc_config->ldc_handler_arg);
+				lpc_dmac_write_4(sc, LPC_DMAC_INTTCCLEAR, (1 << i));
+			}
+
+			if (errstat & (1 << i)) {
+				ch->ldc_config->ldc_error_handler(
+				    ch->ldc_config->ldc_handler_arg);
+				lpc_dmac_write_4(sc, LPC_DMAC_INTERRCLEAR, (1 << i));
+			}
+		}
+
+	} while (intstat);
+}
+
+int
+lpc_dmac_config_channel(device_t dev, int chno, struct lpc_dmac_channel_config *cfg)
+{
+	struct lpc_dmac_softc *sc = lpc_dmac_sc;
+	struct lpc_dmac_channel *ch;
+
+	if (sc == NULL)
+		return (ENXIO);
+
+	ch = &sc->ld_channels[chno];
+	ch->ldc_config = cfg;
+
+	return 0;
+}
+
+int
+lpc_dmac_setup_transfer(device_t dev, int chno, bus_addr_t src, bus_addr_t dst,
+    bus_size_t size, int flags)
+{
+	struct lpc_dmac_softc *sc = lpc_dmac_sc;
+	struct lpc_dmac_channel *ch;
+	uint32_t ctrl, cfg;
+
+	if (sc == NULL)
+		return (ENXIO);
+
+	ch = &sc->ld_channels[chno];
+
+	ctrl = LPC_DMAC_CH_CONTROL_I |
+	    (ch->ldc_config->ldc_dst_incr ? LPC_DMAC_CH_CONTROL_DI : 0) | 
+	    (ch->ldc_config->ldc_src_incr ? LPC_DMAC_CH_CONTROL_SI : 0) |
+	    LPC_DMAC_CH_CONTROL_DWIDTH(ch->ldc_config->ldc_dst_width) |
+	    LPC_DMAC_CH_CONTROL_SWIDTH(ch->ldc_config->ldc_src_width) |
+	    LPC_DMAC_CH_CONTROL_DBSIZE(ch->ldc_config->ldc_dst_burst) |
+	    LPC_DMAC_CH_CONTROL_SBSIZE(ch->ldc_config->ldc_src_burst) |
+	    size;
+
+	cfg = LPC_DMAC_CH_CONFIG_ITC | LPC_DMAC_CH_CONFIG_IE |
+	    LPC_DMAC_CH_CONFIG_FLOWCNTL(ch->ldc_config->ldc_fcntl) |
+	    LPC_DMAC_CH_CONFIG_DESTP(ch->ldc_config->ldc_dst_periph) |
+	    LPC_DMAC_CH_CONFIG_SRCP(ch->ldc_config->ldc_src_periph) | LPC_DMAC_CH_CONFIG_E;
+	lpc_dmac_write_ch_4(sc, chno, LPC_DMAC_CH_SRCADDR, src);
+	lpc_dmac_write_ch_4(sc, chno, LPC_DMAC_CH_DSTADDR, dst);
+	lpc_dmac_write_ch_4(sc, chno, LPC_DMAC_CH_LLI, 0);
+	lpc_dmac_write_ch_4(sc, chno, LPC_DMAC_CH_CONTROL, ctrl);
+	lpc_dmac_write_ch_4(sc, chno, LPC_DMAC_CH_CONFIG, cfg);
+
+	return 0;
+}
+
+int
+lpc_dmac_enable_channel(device_t dev, int chno)
+{
+	struct lpc_dmac_softc *sc = lpc_dmac_sc;
+	uint32_t cfg;
+
+	if (sc == NULL)
+		return (ENXIO);
+
+	cfg = lpc_dmac_read_ch_4(sc, chno, LPC_DMAC_CH_CONFIG);
+	cfg |= LPC_DMAC_CH_CONFIG_E;
+
+	lpc_dmac_write_ch_4(sc, chno, LPC_DMAC_CH_CONFIG, cfg);
+
+	return 0;
+}
+
+int
+lpc_dmac_disable_channel(device_t dev, int chno)
+{
+	struct lpc_dmac_softc *sc = lpc_dmac_sc;
+	uint32_t cfg;
+
+	if (sc == NULL)
+		return (ENXIO);
+
+	cfg = lpc_dmac_read_ch_4(sc, chno, LPC_DMAC_CH_CONFIG);
+	cfg &= ~LPC_DMAC_CH_CONFIG_E;
+
+	lpc_dmac_write_ch_4(sc, chno, LPC_DMAC_CH_CONFIG, cfg);
+
+	return 0;
+}
+
+int
+lpc_dmac_start_burst(device_t dev, int id)
+{
+	struct lpc_dmac_softc *sc = lpc_dmac_sc;
+
+	lpc_dmac_write_4(sc, LPC_DMAC_SOFTBREQ, (1 << id));
+	return (0);
+}
+
+static device_method_t lpc_dmac_methods[] = {
+	/* Device interface */
+	DEVMETHOD(device_probe,		lpc_dmac_probe),
+	DEVMETHOD(device_attach,	lpc_dmac_attach),
+
+	{ 0, 0 },
+};
+
+static devclass_t lpc_dmac_devclass;
+
+static driver_t lpc_dmac_driver = {
+	"dmac",
+	lpc_dmac_methods,
+	sizeof(struct lpc_dmac_softc),
+};
+
+DRIVER_MODULE(dmac, simplebus, lpc_dmac_driver, lpc_dmac_devclass, 0, 0);
diff -r 7fffa673adcd -r a301a330526b head/sys/arm/lpc/lpc_fb.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/head/sys/arm/lpc/lpc_fb.c	Wed Aug 15 11:16:36 2012 +0300
@@ -0,0 +1,466 @@
+/*-
+ * Copyright (c) 2011 Jakub Wojciech Klama <jceel at FreeBSD.org>
+ * 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.
+ *
+ */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: head/sys/arm/lpc/lpc_fb.c 239278 2012-08-15 05:37:10Z gonzo $");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/bio.h>
+#include <sys/bus.h>
+#include <sys/conf.h>
+#include <sys/endian.h>
+#include <sys/kernel.h>
+#include <sys/kthread.h>
+#include <sys/lock.h>
+#include <sys/malloc.h>
+#include <sys/module.h>
+#include <sys/mutex.h>
+#include <sys/queue.h>
+#include <sys/resource.h>
+#include <sys/rman.h>
+#include <sys/time.h>
+#include <sys/timetc.h>
+#include <sys/watchdog.h>
+
+#include <sys/kdb.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 <dev/fdt/fdt_common.h>
+#include <dev/ofw/ofw_bus.h>
+#include <dev/ofw/ofw_bus_subr.h>
+
+#include <arm/lpc/lpcreg.h>
+#include <arm/lpc/lpcvar.h>
+
+
+struct lpc_fb_dmamap_arg {
+	bus_addr_t		lf_dma_busaddr;
+};
+
+struct lpc_lcd_config {
+	int			lc_xres;
+	int			lc_yres;
+	int			lc_bpp;
+	uint32_t		lc_pixelclock;
+	int			lc_left_margin;
+	int			lc_right_margin;
+	int			lc_upper_margin;
+	int			lc_lower_margin;
+	int			lc_hsync_len;
+	int			lc_vsync_len;
+};
+
+struct lpc_fb_softc {
+	device_t		lf_dev;
+	struct cdev *		lf_cdev;
+	struct mtx		lf_mtx;
+	struct resource *	lf_mem_res;
+	struct resource *	lf_irq_res;
+	bus_space_tag_t		lf_bst;
+	bus_space_handle_t	lf_bsh;
+	void *			lf_intrhand;
+	bus_dma_tag_t		lf_dma_tag;
+	bus_dmamap_t		lf_dma_map;
+	void *			lf_buffer;
+	bus_addr_t		lf_buffer_phys;
+	bus_size_t		lf_buffer_size;
+	struct lpc_lcd_config	lf_lcd_config;
+	int			lf_initialized;
+	int			lf_opened;
+};
+
+extern void ssd1289_configure(void);
+
+#define	lpc_fb_lock(_sc)	mtx_lock(&(_sc)->lf_mtx)
+#define	lpc_fb_unlock(_sc)	mtx_unlock(&(_sc)->lf_mtx)
+#define	lpc_fb_lock_assert(sc)	mtx_assert(&(_sc)->lf_mtx, MA_OWNED)
+
+#define	lpc_fb_read_4(_sc, _reg)		\
+    bus_space_read_4((_sc)->lf_bst, (_sc)->lf_bsh, (_reg))
+#define	lpc_fb_write_4(_sc, _reg, _val)		\
+    bus_space_write_4((_sc)->lf_bst, (_sc)->lf_bsh, (_reg), (_val))
+
+
+
+static int lpc_fb_probe(device_t);
+static int lpc_fb_attach(device_t);
+static void lpc_fb_intr(void *);
+static void lpc_fb_dmamap_cb(void *arg, bus_dma_segment_t *segs, int nseg, int err);
+
+static int lpc_fb_fdt_read(phandle_t, const char *, uint32_t *);
+static int lpc_fb_read_lcd_config(phandle_t, struct lpc_lcd_config *);
+
+static int lpc_fb_open(struct cdev *, int, int, struct thread *);
+static int lpc_fb_close(struct cdev *, int, int, struct thread *);
+static int lpc_fb_ioctl(struct cdev *, u_long, caddr_t, int, struct thread *);
+static int lpc_fb_mmap(struct cdev *, vm_ooffset_t, vm_paddr_t *, int, vm_memattr_t *);
+
+static void lpc_fb_blank(struct lpc_fb_softc *);
+
+static struct cdevsw lpc_fb_cdevsw = {
+	.d_open		= lpc_fb_open,
+	.d_close	= lpc_fb_close,
+	.d_ioctl	= lpc_fb_ioctl,
+	.d_mmap		= lpc_fb_mmap,
+	.d_name		= "lpcfb",
+	.d_version	= D_VERSION,
+};
+
+static int
+lpc_fb_probe(device_t dev)
+{
+	if (!ofw_bus_is_compatible(dev, "lpc,fb"))
+		return (ENXIO);
+
+	device_set_desc(dev, "LPC32x0 framebuffer device");
+	return (BUS_PROBE_DEFAULT);
+}
+
+static int
+lpc_fb_attach(device_t dev)
+{
+	struct lpc_fb_softc *sc = device_get_softc(dev);
+	struct lpc_fb_dmamap_arg ctx;
+	phandle_t node;
+	int mode, rid, err = 0;
+
+	sc->lf_dev = dev;
+	mtx_init(&sc->lf_mtx, "lpcfb", "fb", MTX_DEF);
+
+	rid = 0;
+	sc->lf_mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid,
+	    RF_ACTIVE);
+	if (!sc->lf_mem_res) {
+		device_printf(dev, "cannot allocate memory window\n");
+		return (ENXIO);
+	}
+
+	sc->lf_bst = rman_get_bustag(sc->lf_mem_res);
+	sc->lf_bsh = rman_get_bushandle(sc->lf_mem_res);
+
+	rid = 0;
+	sc->lf_irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid,
+	    RF_ACTIVE);
+	if (!sc->lf_irq_res) {
+		device_printf(dev, "cannot allocate interrupt\n");
+		bus_release_resource(dev, SYS_RES_MEMORY, 0, sc->lf_mem_res);
+		return (ENXIO);
+	}
+
+	if (bus_setup_intr(dev, sc->lf_irq_res, INTR_TYPE_MISC | INTR_MPSAFE,
+	    NULL, lpc_fb_intr, sc, &sc->lf_intrhand))
+	{
+		bus_release_resource(dev, SYS_RES_MEMORY, 0, sc->lf_mem_res);
+		bus_release_resource(dev, SYS_RES_IRQ, 1, sc->lf_irq_res);
+		device_printf(dev, "cannot setup interrupt handler\n");
+		return (ENXIO);
+	}
+
+	node = ofw_bus_get_node(dev);
+
+	err = lpc_fb_read_lcd_config(node, &sc->lf_lcd_config);
+	if (err) {
+		device_printf(dev, "cannot read LCD configuration\n");
+		goto fail;
+	}
+
+	sc->lf_buffer_size = sc->lf_lcd_config.lc_xres * 
+	    sc->lf_lcd_config.lc_yres *
+	    (sc->lf_lcd_config.lc_bpp == 24 ? 3 : 2);
+
+	device_printf(dev, "%dx%d LCD, %d bits per pixel, %dkHz pixel clock\n",
+	    sc->lf_lcd_config.lc_xres, sc->lf_lcd_config.lc_yres,
+	    sc->lf_lcd_config.lc_bpp, sc->lf_lcd_config.lc_pixelclock / 1000);
+
+	err = bus_dma_tag_create(
+	    bus_get_dma_tag(sc->lf_dev),
+	    4, 0,			/* alignment, boundary */
+	    BUS_SPACE_MAXADDR_32BIT,	/* lowaddr */
+	    BUS_SPACE_MAXADDR,		/* highaddr */
+	    NULL, NULL,			/* filter, filterarg */
+	    sc->lf_buffer_size, 1,	/* maxsize, nsegments */
+	    sc->lf_buffer_size, 0,	/* maxsegsize, flags */
+	    NULL, NULL,			/* lockfunc, lockarg */
+	    &sc->lf_dma_tag);
+
+	err = bus_dmamem_alloc(sc->lf_dma_tag, (void **)&sc->lf_buffer,
+	    0, &sc->lf_dma_map);
+	if (err) {
+		device_printf(dev, "cannot allocate framebuffer\n");
+		goto fail;
+	}
+
+	err = bus_dmamap_load(sc->lf_dma_tag, sc->lf_dma_map, sc->lf_buffer,
+	    sc->lf_buffer_size, lpc_fb_dmamap_cb, &ctx, BUS_DMA_NOWAIT);
+	if (err) {
+		device_printf(dev, "cannot load DMA map\n");
+		goto fail;
+	}
+
+	switch (sc->lf_lcd_config.lc_bpp) {
+	case 12:
+		mode = LPC_CLKPWR_LCDCLK_CTRL_MODE_12;
+		break;
+	case 15:
+		mode = LPC_CLKPWR_LCDCLK_CTRL_MODE_15;
+		break;
+	case 16:
+		mode = LPC_CLKPWR_LCDCLK_CTRL_MODE_16;
+		break;
+	case 24:
+		mode = LPC_CLKPWR_LCDCLK_CTRL_MODE_24;
+		break;
+	default:
+		panic("unsupported bpp");
+	}
+
+	lpc_pwr_write(sc->lf_dev, LPC_CLKPWR_LCDCLK_CTRL,
+	    LPC_CLKPWR_LCDCLK_CTRL_MODE(mode) |
+	    LPC_CLKPWR_LCDCLK_CTRL_HCLKEN);
+
+	sc->lf_buffer_phys = ctx.lf_dma_busaddr;
+	sc->lf_cdev = make_dev(&lpc_fb_cdevsw, 0, UID_ROOT, GID_WHEEL,
+	    0600, "lpcfb");
+
+	sc->lf_cdev->si_drv1 = sc;
+
+	return (0);
+fail:
+	return (ENXIO);
+}
+
+static void
+lpc_fb_dmamap_cb(void *arg, bus_dma_segment_t *segs, int nseg, int err)
+{
+	struct lpc_fb_dmamap_arg *ctx;
+
+	if (err)
+		return;
+
+	ctx = (struct lpc_fb_dmamap_arg *)arg;
+	ctx->lf_dma_busaddr = segs[0].ds_addr;
+}
+
+static void
+lpc_fb_intr(void *arg)
+{
+}
+
+static int
+lpc_fb_fdt_read(phandle_t node, const char *name, uint32_t *ret)
+{
+	if (OF_getprop(node, name, ret, sizeof(uint32_t)) <= 0)
+		return (ENOENT);
+
+	*ret = fdt32_to_cpu(*ret);
+	return (0);
+}
+
+static int
+lpc_fb_read_lcd_config(phandle_t node, struct lpc_lcd_config *cfg)
+{
+	if (lpc_fb_fdt_read(node, "horizontal-resolution", &cfg->lc_xres))
+		return (ENXIO);
+
+	if (lpc_fb_fdt_read(node, "vertical-resolution", &cfg->lc_yres))
+		return (ENXIO);
+
+	if (lpc_fb_fdt_read(node, "bits-per-pixel", &cfg->lc_bpp))
+		return (ENXIO);
+
+	if (lpc_fb_fdt_read(node, "pixel-clock", &cfg->lc_pixelclock))
+		return (ENXIO);
+
+	if (lpc_fb_fdt_read(node, "left-margin", &cfg->lc_left_margin))
+		return (ENXIO);
+
+	if (lpc_fb_fdt_read(node, "right-margin", &cfg->lc_right_margin))
+		return (ENXIO);
+
+	if (lpc_fb_fdt_read(node, "upper-margin", &cfg->lc_upper_margin))
+		return (ENXIO);
+
+	if (lpc_fb_fdt_read(node, "lower-margin", &cfg->lc_lower_margin))
+		return (ENXIO);
+
+	if (lpc_fb_fdt_read(node, "hsync-len", &cfg->lc_hsync_len))
+		return (ENXIO);
+
+	if (lpc_fb_fdt_read(node, "vsync-len", &cfg->lc_vsync_len))
+		return (ENXIO);
+
+	return (0);
+}
+
+static void
+lpc_fb_setup(struct lpc_fb_softc *sc)
+{
+	struct lpc_lcd_config *cfg = &sc->lf_lcd_config;
+	uint32_t bpp;
+
+	lpc_fb_write_4(sc, LPC_LCD_TIMH,
+	    LPC_LCD_TIMH_PPL(cfg->lc_xres) |
+	    LPC_LCD_TIMH_HSW(cfg->lc_hsync_len - 1) |
+	    LPC_LCD_TIMH_HFP(cfg->lc_right_margin - 1) |
+	    LPC_LCD_TIMH_HBP(cfg->lc_left_margin - 1));
+
+	lpc_fb_write_4(sc, LPC_LCD_TIMV,
+	    LPC_LCD_TIMV_LPP(cfg->lc_yres - 1) |
+	    LPC_LCD_TIMV_VSW(cfg->lc_vsync_len - 1) |
+	    LPC_LCD_TIMV_VFP(cfg->lc_lower_margin) |
+	    LPC_LCD_TIMV_VBP(cfg->lc_upper_margin));
+
+	/* XXX LPC_LCD_POL_PCD_LO */
+	lpc_fb_write_4(sc, LPC_LCD_POL,
+	    LPC_LCD_POL_IHS | LPC_LCD_POL_IVS |
+	    LPC_LCD_POL_CPL(cfg->lc_xres - 1) |
+	    LPC_LCD_POL_PCD_LO(4));
+	
+	lpc_fb_write_4(sc, LPC_LCD_UPBASE, sc->lf_buffer_phys);
+	
+	switch (cfg->lc_bpp) {
+	case 1:
+		bpp = LPC_LCD_CTRL_BPP1;
+		break;
+	case 2:
+		bpp = LPC_LCD_CTRL_BPP2;
+		break;
+	case 4:
+		bpp = LPC_LCD_CTRL_BPP4;
+		break;
+	case 8:
+		bpp = LPC_LCD_CTRL_BPP8;
+		break;
+	case 12:
+		bpp = LPC_LCD_CTRL_BPP12_444;
+		break;
+	case 15:
+		bpp = LPC_LCD_CTRL_BPP16;
+		break;
+	case 16:
+		bpp = LPC_LCD_CTRL_BPP16_565;
+		break;
+	case 24:
+		bpp = LPC_LCD_CTRL_BPP24;
+		break;
+	default:
+		panic("LCD unknown bpp: %d", cfg->lc_bpp);
+	}
+
+	lpc_fb_write_4(sc, LPC_LCD_CTRL,
+	    LPC_LCD_CTRL_LCDVCOMP(1) |
+	    LPC_LCD_CTRL_LCDPWR |
+	    LPC_LCD_CTRL_BGR |
+	    LPC_LCD_CTRL_LCDTFT |
+	    LPC_LCD_CTRL_LCDBPP(bpp) |
+	    LPC_LCD_CTRL_LCDEN);
+}
+
+
+static int
+lpc_fb_open(struct cdev *cdev, int oflags, int devtype, struct thread *td)
+{
+	struct lpc_fb_softc *sc = cdev->si_drv1;
+
+	lpc_fb_lock(sc);
+
+	if (sc->lf_opened)
+		return (EBUSY);
+
+	sc->lf_opened = 1;
+
+	lpc_fb_unlock(sc);
+
+	if (!sc->lf_initialized) {
+		ssd1289_configure();
+		lpc_fb_setup(sc);
+		lpc_fb_blank(sc);
+		sc->lf_initialized = 1;
+	}
+
+	return (0);
+}
+
+static int
+lpc_fb_close(struct cdev *cdev, int fflag, int devtype, struct thread *td)
+{	
+	struct lpc_fb_softc *sc = cdev->si_drv1;
+
+	lpc_fb_lock(sc);
+	sc->lf_opened = 0;
+	lpc_fb_unlock(sc);
+
+	return (0);
+}
+
+static int
+lpc_fb_ioctl(struct cdev *cdev, u_long cmd, caddr_t data, int x,
+    struct thread *td)
+{
+	
+	return (EINVAL);
+}
+
+static int
+lpc_fb_mmap(struct cdev *cdev, vm_ooffset_t offset, vm_paddr_t *paddr,
+    int nprot, vm_memattr_t *memattr)
+{
+	struct lpc_fb_softc *sc = cdev->si_drv1;
+
+	*paddr = (vm_paddr_t)(sc->lf_buffer_phys + offset);
+	return (0);
+}
+
+static void
+lpc_fb_blank(struct lpc_fb_softc *sc)
+{
+	memset(sc->lf_buffer, 0xffff, sc->lf_buffer_size);
+}
+
+static device_method_t lpc_fb_methods[] = {
+	/* Device interface */
+	DEVMETHOD(device_probe,		lpc_fb_probe),
+	DEVMETHOD(device_attach,	lpc_fb_attach),
+
+	{ 0, 0 }
+};
+
+static devclass_t lpc_fb_devclass;
+
+static driver_t lpc_fb_driver = {
+	"lpcfb",
+	lpc_fb_methods,
+	sizeof(struct lpc_fb_softc),
+};
+
+DRIVER_MODULE(lpcfb, simplebus, lpc_fb_driver, lpc_fb_devclass, 0, 0);
diff -r 7fffa673adcd -r a301a330526b head/sys/arm/lpc/lpc_gpio.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/head/sys/arm/lpc/lpc_gpio.c	Wed Aug 15 11:16:36 2012 +0300
@@ -0,0 +1,547 @@
+/*-
+ * Copyright (c) 2011 Jakub Wojciech Klama <jceel at FreeBSD.org>
+ * 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.
+ *
+ */
+
+/*
+ * GPIO on LPC32x0 consist of 4 ports:
+ * - Port0 with 8 input/output pins
+ * - Port1 with 24 input/output pins
+ * - Port2 with 13 input/output pins
+ * - Port3 with:
+ *   - 26 input pins (GPI_00..GPI_09 + GPI_15..GPI_23 + GPI_25 + GPI_27..GPI_28)
+ *   - 24 output pins (GPO_00..GPO_23)
+ *   - 6 input/ouput pins (GPIO_00..GPIO_05)
+ *
+ * Pins are mapped to logical pin number as follows:
+ * [0..9] -> GPI_00..GPI_09 		(port 3)
+ * [10..18] -> GPI_15..GPI_23 		(port 3)
+ * [19] -> GPI_25			(port 3)
+ * [20..21] -> GPI_27..GPI_28		(port 3)
+ * [22..45] -> GPO_00..GPO_23		(port 3)
+ * [46..51] -> GPIO_00..GPIO_05		(port 3)
+ * [52..64] -> P2.0..P2.12		(port 2)
+ * [65..88] -> P1.0..P1.23		(port 1)
+ * [89..96] -> P0.0..P0.7		(port 0)
+ *
+ */
+
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: head/sys/arm/lpc/lpc_gpio.c 239278 2012-08-15 05:37:10Z gonzo $");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/bio.h>
+#include <sys/bus.h>
+#include <sys/conf.h>
+#include <sys/endian.h>
+#include <sys/kernel.h>
+#include <sys/kthread.h>
+#include <sys/lock.h>
+#include <sys/malloc.h>
+#include <sys/module.h>
+#include <sys/mutex.h>
+#include <sys/queue.h>
+#include <sys/resource.h>
+#include <sys/rman.h>
+#include <sys/time.h>
+#include <sys/timetc.h>
+#include <sys/watchdog.h>
+#include <sys/gpio.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 <machine/fdt.h>
+
+#include <dev/ofw/ofw_bus.h>
+#include <dev/ofw/ofw_bus_subr.h>
+
+#include <arm/lpc/lpcreg.h>
+#include <arm/lpc/lpcvar.h>
+
+#include "gpio_if.h"
+
+struct lpc_gpio_softc
+{
+	device_t		lg_dev;
+	struct resource *	lg_res;
+	bus_space_tag_t		lg_bst;
+	bus_space_handle_t	lg_bsh;
+};
+
+struct lpc_gpio_pinmap
+{
+	int			lp_start_idx;
+	int			lp_pin_count;
+	int			lp_port;
+	int			lp_start_bit;
+	int			lp_flags;
+};
+
+static const struct lpc_gpio_pinmap lpc_gpio_pins[] = {
+	{ 0,	10,	3,	0,	GPIO_PIN_INPUT },
+	{ 10,	9,	3,	15,	GPIO_PIN_INPUT },
+	{ 19,	1,	3,	25,	GPIO_PIN_INPUT },
+	{ 20,	2,	3,	27,	GPIO_PIN_INPUT },
+	{ 22,	24,	3,	0,	GPIO_PIN_OUTPUT },
+	/*
+	 * -1 below is to mark special case for Port3 GPIO pins, as they
+	 * have other bits in Port 3 registers as inputs and as outputs
+	 */
+	{ 46,	6,	3,	-1,	GPIO_PIN_INPUT | GPIO_PIN_OUTPUT },
+	{ 52,	13,	2,	0,	GPIO_PIN_INPUT | GPIO_PIN_OUTPUT },
+	{ 65,	24,	1,	0,	GPIO_PIN_INPUT | GPIO_PIN_OUTPUT },
+	{ 89,	8,	0,	0,	GPIO_PIN_INPUT | GPIO_PIN_OUTPUT },
+	{ -1,	-1,	-1,	-1,	-1 },
+};
+
+#define	LPC_GPIO_NPINS				\
+    (LPC_GPIO_P0_COUNT + LPC_GPIO_P1_COUNT +	\
+    LPC_GPIO_P2_COUNT + LPC_GPIO_P3_COUNT)
+
+#define	LPC_GPIO_PIN_IDX(_map, _idx)	\
+    (_idx - _map->lp_start_idx)
+
+#define	LPC_GPIO_PIN_BIT(_map, _idx)	\
+    (_map->lp_start_bit + LPC_GPIO_PIN_IDX(_map, _idx))
+
+static int lpc_gpio_probe(device_t);
+static int lpc_gpio_attach(device_t);
+static int lpc_gpio_detach(device_t);
+
+static int lpc_gpio_pin_max(device_t, int *);
+static int lpc_gpio_pin_getcaps(device_t, uint32_t, uint32_t *);
+static int lpc_gpio_pin_getflags(device_t, uint32_t, uint32_t *);
+static int lpc_gpio_pin_setflags(device_t, uint32_t, uint32_t);
+static int lpc_gpio_pin_getname(device_t, uint32_t, char *);
+static int lpc_gpio_pin_get(device_t, uint32_t, uint32_t *);
+static int lpc_gpio_pin_set(device_t, uint32_t, uint32_t);
+static int lpc_gpio_pin_toggle(device_t, uint32_t);
+
+static const struct lpc_gpio_pinmap *lpc_gpio_get_pinmap(int);
+
+static struct lpc_gpio_softc *lpc_gpio_sc = NULL;
+
+#define	lpc_gpio_read_4(_sc, _reg) \
+    bus_space_read_4(_sc->lg_bst, _sc->lg_bsh, _reg)
+#define	lpc_gpio_write_4(_sc, _reg, _val) \
+    bus_space_write_4(_sc->lg_bst, _sc->lg_bsh, _reg, _val)
+#define	lpc_gpio_get_4(_sc, _test, _reg1, _reg2) \
+    lpc_gpio_read_4(_sc, ((_test) ? _reg1 : _reg2))
+#define	lpc_gpio_set_4(_sc, _test, _reg1, _reg2, _val) \
+    lpc_gpio_write_4(_sc, ((_test) ? _reg1 : _reg2), _val)
+
+static int
+lpc_gpio_probe(device_t dev)
+{
+	if (!ofw_bus_is_compatible(dev, "lpc,gpio"))
+		return (ENXIO);
+
+	device_set_desc(dev, "LPC32x0 GPIO");
+	return (BUS_PROBE_DEFAULT);
+}
+
+static int
+lpc_gpio_attach(device_t dev)
+{
+	struct lpc_gpio_softc *sc = device_get_softc(dev);
+	int rid;
+
+	sc->lg_dev = dev;
+
+	rid = 0;
+	sc->lg_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid,
+	    RF_ACTIVE);
+	if (!sc->lg_res) {
+		device_printf(dev, "cannot allocate memory window\n");
+		return (ENXIO);
+	}
+
+	sc->lg_bst = rman_get_bustag(sc->lg_res);
+	sc->lg_bsh = rman_get_bushandle(sc->lg_res);
+
+	lpc_gpio_sc = sc;
+
+	device_add_child(dev, "gpioc", device_get_unit(dev));
+	device_add_child(dev, "gpiobus", device_get_unit(dev));
+
+	return (bus_generic_attach(dev));
+}
+
+static int
+lpc_gpio_detach(device_t dev)
+{
+	return (EBUSY);
+}
+
+static int
+lpc_gpio_pin_max(device_t dev, int *npins)
+{
+	*npins = LPC_GPIO_NPINS - 1;
+	return (0);
+}
+
+static int
+lpc_gpio_pin_getcaps(device_t dev, uint32_t pin, uint32_t *caps)
+{
+	const struct lpc_gpio_pinmap *map;
+
+	if (pin > LPC_GPIO_NPINS)
+		return (ENODEV);
+
+	map = lpc_gpio_get_pinmap(pin);
+
+	*caps = map->lp_flags;
+	return (0);
+}
+
+static int
+lpc_gpio_pin_getflags(device_t dev, uint32_t pin, uint32_t *flags)
+{
+	struct lpc_gpio_softc *sc = device_get_softc(dev);
+	const struct lpc_gpio_pinmap *map;
+	uint32_t state;
+	int dir;
+
+	if (pin > LPC_GPIO_NPINS)
+		return (ENODEV);
+
+	map = lpc_gpio_get_pinmap(pin);
+
+	/* Check whether it's bidirectional pin */
+	if ((map->lp_flags & (GPIO_PIN_INPUT | GPIO_PIN_OUTPUT)) != 
+	    (GPIO_PIN_INPUT | GPIO_PIN_OUTPUT)) {
+		*flags = map->lp_flags;
+		return (0);
+	}
+
+	switch (map->lp_port) {
+	case 0:
+		state = lpc_gpio_read_4(sc, LPC_GPIO_P0_DIR_STATE);
+		dir = (state & (1 << LPC_GPIO_PIN_BIT(map, pin)));
+		break;
+	case 1:
+		state = lpc_gpio_read_4(sc, LPC_GPIO_P1_DIR_STATE);
+		dir = (state & (1 << LPC_GPIO_PIN_BIT(map, pin)));
+		break;
+	case 2:
+		state = lpc_gpio_read_4(sc, LPC_GPIO_P2_DIR_STATE);
+		dir = (state & (1 << LPC_GPIO_PIN_BIT(map, pin)));
+		break;
+	case 3:
+		state = lpc_gpio_read_4(sc, LPC_GPIO_P2_DIR_STATE);
+		dir = (state & (1 << (25 + LPC_GPIO_PIN_IDX(map, pin))));
+		break;
+	default:
+		panic("unknown GPIO port");
+	}
+
+	*flags = dir ? GPIO_PIN_OUTPUT : GPIO_PIN_INPUT;
+
+	return (0);
+}
+
+static int
+lpc_gpio_pin_setflags(device_t dev, uint32_t pin, uint32_t flags)
+{
+	struct lpc_gpio_softc *sc = device_get_softc(dev);
+	const struct lpc_gpio_pinmap *map;
+	uint32_t dir, state;
+
+	if (pin > LPC_GPIO_NPINS)
+		return (ENODEV);
+
+	map = lpc_gpio_get_pinmap(pin);
+
+	/* Check whether it's bidirectional pin */
+	if ((map->lp_flags & (GPIO_PIN_INPUT | GPIO_PIN_OUTPUT)) != 
+	    (GPIO_PIN_INPUT | GPIO_PIN_OUTPUT))
+		return (ENOTSUP);
+	
+	if (flags & GPIO_PIN_INPUT)
+		dir = 0;
+
+	if (flags & GPIO_PIN_OUTPUT)
+		dir = 1;
+
+	switch (map->lp_port) {
+	case 0:
+		state = (1 << LPC_GPIO_PIN_IDX(map, pin));
+		lpc_gpio_set_4(sc, dir, LPC_GPIO_P0_DIR_SET, 
+		    LPC_GPIO_P0_DIR_CLR, state);
+		break;
+	case 1:
+		state = (1 << LPC_GPIO_PIN_IDX(map, pin));
+		lpc_gpio_set_4(sc, dir, LPC_GPIO_P1_DIR_SET, 
+		    LPC_GPIO_P0_DIR_CLR, state);
+		break;
+	case 2:
+		state = (1 << LPC_GPIO_PIN_IDX(map, pin));
+		lpc_gpio_set_4(sc, dir, LPC_GPIO_P2_DIR_SET, 
+		    LPC_GPIO_P0_DIR_CLR, state);
+		break;
+	case 3:
+		state = (1 << (25 + (pin - map->lp_start_idx)));
+		lpc_gpio_set_4(sc, dir, LPC_GPIO_P2_DIR_SET, 
+		    LPC_GPIO_P0_DIR_CLR, state);
+		break;
+	}
+
+	return (0);
+}
+
+static int
+lpc_gpio_pin_getname(device_t dev, uint32_t pin, char *name)
+{
+	const struct lpc_gpio_pinmap *map;
+	int idx;
+
+	map = lpc_gpio_get_pinmap(pin);
+	idx = LPC_GPIO_PIN_IDX(map, pin);
+
+	switch (map->lp_port) {
+	case 0:
+	case 1:
+	case 2:
+		snprintf(name, GPIOMAXNAME - 1, "P%d.%d", map->lp_port, 
+		    map->lp_start_bit + LPC_GPIO_PIN_IDX(map, pin));
+		break;
+	case 3:
+		if (map->lp_start_bit == -1) {
+			snprintf(name, GPIOMAXNAME - 1, "GPIO_%02d", idx);
+			break;
+		}
+
+		snprintf(name, GPIOMAXNAME - 1, "GP%c_%02d",
+		    (map->lp_flags & GPIO_PIN_INPUT) ? 'I' : 'O',
+		    map->lp_start_bit + idx);
+		break;
+	}
+
+	return (0);
+}
+
+static int
+lpc_gpio_pin_get(device_t dev, uint32_t pin, uint32_t *value)
+{
+	struct lpc_gpio_softc *sc = device_get_softc(dev);
+	const struct lpc_gpio_pinmap *map;
+	uint32_t state, flags;
+	int dir;
+
+	map = lpc_gpio_get_pinmap(pin);
+
+	if (lpc_gpio_pin_getflags(dev, pin, &flags))
+		return (ENXIO);
+
+	if (flags & GPIO_PIN_OUTPUT)
+		dir = 1;
+
+	if (flags & GPIO_PIN_INPUT)
+		dir = 0;
+
+	switch (map->lp_port) {
+	case 0:
+		state = lpc_gpio_get_4(sc, dir, LPC_GPIO_P0_OUTP_STATE,
+		    LPC_GPIO_P0_INP_STATE);
+		*value = !!(state & (1 << LPC_GPIO_PIN_BIT(map, pin)));
+	case 1:
+		state = lpc_gpio_get_4(sc, dir, LPC_GPIO_P1_OUTP_STATE,
+		    LPC_GPIO_P1_INP_STATE);
+		*value = !!(state & (1 << LPC_GPIO_PIN_BIT(map, pin)));
+	case 2:
+		state = lpc_gpio_read_4(sc, LPC_GPIO_P2_INP_STATE);
+		*value = !!(state & (1 << LPC_GPIO_PIN_BIT(map, pin)));
+	case 3:
+		state = lpc_gpio_get_4(sc, dir, LPC_GPIO_P3_OUTP_STATE,
+		    LPC_GPIO_P3_INP_STATE);
+		if (map->lp_start_bit == -1) {
+			if (dir)
+				*value = !!(state & (1 << (25 + 
+				    LPC_GPIO_PIN_IDX(map, pin))));
+			else
+				*value = !!(state & (1 << (10 + 
+				    LPC_GPIO_PIN_IDX(map, pin))));
+		}
+
+		*value = !!(state & (1 << LPC_GPIO_PIN_BIT(map, pin)));
+	}
+
+	return (0);
+}
+
+static int
+lpc_gpio_pin_set(device_t dev, uint32_t pin, uint32_t value)
+{
+	struct lpc_gpio_softc *sc = device_get_softc(dev);
+	const struct lpc_gpio_pinmap *map;
+	uint32_t state, flags;
+
+	map = lpc_gpio_get_pinmap(pin);
+
+	if (lpc_gpio_pin_getflags(dev, pin, &flags))
+		return (ENXIO);
+
+	if ((flags & GPIO_PIN_OUTPUT) == 0)
+		return (EINVAL);
+
+	state = (1 << LPC_GPIO_PIN_BIT(map, pin));
+
+	switch (map->lp_port) {
+	case 0:
+		lpc_gpio_set_4(sc, value, LPC_GPIO_P0_OUTP_SET,
+		    LPC_GPIO_P0_OUTP_CLR, state);
+		break;
+	case 1:
+		lpc_gpio_set_4(sc, value, LPC_GPIO_P1_OUTP_SET,
+		    LPC_GPIO_P1_OUTP_CLR, state);
+		break;
+	case 2:
+		lpc_gpio_set_4(sc, value, LPC_GPIO_P2_OUTP_SET,
+		    LPC_GPIO_P2_OUTP_CLR, state);
+		break;
+	case 3:
+		if (map->lp_start_bit == -1)
+			state = (1 << (25 + LPC_GPIO_PIN_IDX(map, pin)));
+		
+		lpc_gpio_set_4(sc, value, LPC_GPIO_P3_OUTP_SET,
+		    LPC_GPIO_P3_OUTP_CLR, state);
+		break;
+	}
+
+	return (0);
+}
+
+static int
+lpc_gpio_pin_toggle(device_t dev, uint32_t pin)
+{
+	const struct lpc_gpio_pinmap *map;
+	uint32_t flags;
+
+	map = lpc_gpio_get_pinmap(pin);
+
+	if (lpc_gpio_pin_getflags(dev, pin, &flags))
+		return (ENXIO);
+
+	if ((flags & GPIO_PIN_OUTPUT) == 0)
+		return (EINVAL);
+	
+	panic("not implemented yet");
+
+	return (0);
+
+}
+
+static const struct lpc_gpio_pinmap *
+lpc_gpio_get_pinmap(int pin)
+{
+	const struct lpc_gpio_pinmap *map;
+
+	for (map = &lpc_gpio_pins[0]; map->lp_start_idx != -1; map++) {
+		if (pin >= map->lp_start_idx &&
+		    pin < map->lp_start_idx + map->lp_pin_count)
+			return map;
+	}
+
+	panic("pin number %d out of range", pin);
+}
+
+int
+lpc_gpio_set_flags(device_t dev, int pin, int flags)
+{
+	if (lpc_gpio_sc == NULL)
+		return (ENXIO);
+
+	return lpc_gpio_pin_setflags(lpc_gpio_sc->lg_dev, pin, flags);
+}
+
+int
+lpc_gpio_set_state(device_t dev, int pin, int state)
+{
+	if (lpc_gpio_sc == NULL)
+		return (ENXIO);
+
+	return lpc_gpio_pin_set(lpc_gpio_sc->lg_dev, pin, state); 
+}
+
+int
+lpc_gpio_get_state(device_t dev, int pin, int *state)
+{
+	if (lpc_gpio_sc == NULL)
+		return (ENXIO);
+
+	return lpc_gpio_pin_get(lpc_gpio_sc->lg_dev, pin, state);
+}
+
+void
+platform_gpio_init()
+{
+	/* Preset SPI devices CS pins to one */
+	bus_space_write_4(fdtbus_bs_tag, 
+	    LPC_GPIO_BASE, LPC_GPIO_P3_OUTP_SET,
+	    1 << (SSD1289_CS_PIN - LPC_GPIO_GPO_00(0)) |
+	    1 << (SSD1289_DC_PIN - LPC_GPIO_GPO_00(0)) |
+	    1 << (ADS7846_CS_PIN - LPC_GPIO_GPO_00(0)));	
+}
+
+static device_method_t lpc_gpio_methods[] = {
+	/* Device interface */
+	DEVMETHOD(device_probe,		lpc_gpio_probe),
+	DEVMETHOD(device_attach,	lpc_gpio_attach),
+	DEVMETHOD(device_detach,	lpc_gpio_detach),
+
+	/* GPIO interface */
+	DEVMETHOD(gpio_pin_max,		lpc_gpio_pin_max),
+	DEVMETHOD(gpio_pin_getcaps,	lpc_gpio_pin_getcaps),
+	DEVMETHOD(gpio_pin_getflags,	lpc_gpio_pin_getflags),
+	DEVMETHOD(gpio_pin_setflags,	lpc_gpio_pin_setflags),
+	DEVMETHOD(gpio_pin_getname,	lpc_gpio_pin_getname),
+	DEVMETHOD(gpio_pin_set,		lpc_gpio_pin_set),
+	DEVMETHOD(gpio_pin_get,		lpc_gpio_pin_get),
+	DEVMETHOD(gpio_pin_toggle,	lpc_gpio_pin_toggle),
+
+	{ 0, 0 }
+};
+
+static devclass_t lpc_gpio_devclass;
+
+static driver_t lpc_gpio_driver = {
+	"lpcgpio",
+	lpc_gpio_methods,
+	sizeof(struct lpc_gpio_softc),
+};
+
+extern devclass_t gpiobus_devclass, gpioc_devclass;
+extern driver_t gpiobus_driver, gpioc_driver;
+
+DRIVER_MODULE(lpcgpio, simplebus, lpc_gpio_driver, lpc_gpio_devclass, 0, 0);
+DRIVER_MODULE(gpiobus, lpcgpio, gpiobus_driver, gpiobus_devclass, 0, 0);
+DRIVER_MODULE(gpioc, lpcgpio, gpioc_driver, gpioc_devclass, 0, 0);
+MODULE_VERSION(lpcgpio, 1);
diff -r 7fffa673adcd -r a301a330526b head/sys/arm/lpc/lpc_intc.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/head/sys/arm/lpc/lpc_intc.c	Wed Aug 15 11:16:36 2012 +0300
@@ -0,0 +1,243 @@
+/*-
+ * Copyright (c) 2010 Jakub Wojciech Klama <jceel at FreeBSD.org>
+ * 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.
+ *
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: head/sys/arm/lpc/lpc_intc.c 239278 2012-08-15 05:37:10Z gonzo $");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/bus.h>
+#include <sys/kernel.h>
+#include <sys/module.h>
+#include <sys/malloc.h>
+#include <sys/rman.h>
+#include <sys/timetc.h>
+#include <machine/bus.h>
+#include <machine/intr.h>
+
+#include <dev/fdt/fdt_common.h>
+#include <dev/ofw/openfirm.h>
+
+#include <dev/ofw/ofw_bus.h>
+#include <dev/ofw/ofw_bus_subr.h>
+
+#include <arm/lpc/lpcreg.h>
+
+struct lpc_intc_softc {
+	struct resource *	li_res;
+	bus_space_tag_t		li_bst;
+	bus_space_handle_t	li_bsh;
+};
+
+static int lpc_intc_probe(device_t);
+static int lpc_intc_attach(device_t);
+static void lpc_intc_eoi(void *);
+
+static struct lpc_intc_softc *intc_softc = NULL;
+
+#define	intc_read_4(reg)		\
+    bus_space_read_4(intc_softc->li_bst, intc_softc->li_bsh, reg)
+#define	intc_write_4(reg, val)		\
+    bus_space_write_4(intc_softc->li_bst, intc_softc->li_bsh, reg, val)
+
+static int
+lpc_intc_probe(device_t dev)
+{
+
+	if (!ofw_bus_is_compatible(dev, "lpc,pic"))
+		return (ENXIO);
+
+	device_set_desc(dev, "LPC32x0 Interrupt Controller");
+	return (BUS_PROBE_DEFAULT);
+}
+
+static int
+lpc_intc_attach(device_t dev)
+{
+	struct lpc_intc_softc *sc = device_get_softc(dev);
+	int rid = 0;
+
+	if (intc_softc)
+		return (ENXIO);
+
+	sc->li_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, 
+	    RF_ACTIVE);
+	if (!sc->li_res) {
+		device_printf(dev, "could not alloc resources\n");
+		return (ENXIO);
+	}
+
+	sc->li_bst = rman_get_bustag(sc->li_res);
+	sc->li_bsh = rman_get_bushandle(sc->li_res);
+	intc_softc = sc;
+	arm_post_filter = lpc_intc_eoi;
+
+	/* Clear interrupt status registers and disable all interrupts */
+	intc_write_4(LPC_INTC_MIC_ER, 0);
+	intc_write_4(LPC_INTC_SIC1_ER, 0);
+	intc_write_4(LPC_INTC_SIC2_ER, 0);
+	intc_write_4(LPC_INTC_MIC_RSR, ~0);
+	intc_write_4(LPC_INTC_SIC1_RSR, ~0);
+	intc_write_4(LPC_INTC_SIC2_RSR, ~0);
+	return (0);
+}
+
+static device_method_t lpc_intc_methods[] = {
+	DEVMETHOD(device_probe,		lpc_intc_probe),
+	DEVMETHOD(device_attach,	lpc_intc_attach),
+	{ 0, 0 }
+};
+
+static driver_t lpc_intc_driver = {
+	"pic",
+	lpc_intc_methods,
+	sizeof(struct lpc_intc_softc),
+};
+
+static devclass_t lpc_intc_devclass;
+
+DRIVER_MODULE(pic, simplebus, lpc_intc_driver, lpc_intc_devclass, 0, 0);
+
+int
+arm_get_next_irq(int last)
+{
+	uint32_t value;
+	int i;
+
+	/* IRQs 0-31 are mapped to LPC_INTC_MIC_SR */
+	value = intc_read_4(LPC_INTC_MIC_SR);
+	for (i = 0; i < 32; i++) {
+		if (value & (1 << i))
+			return (i);
+	}
+
+	/* IRQs 32-63 are mapped to LPC_INTC_SIC1_SR */
+	value = intc_read_4(LPC_INTC_SIC1_SR);
+	for (i = 0; i < 32; i++) {
+		if (value & (1 << i))
+			return (i + 32);
+	}
+
+	/* IRQs 64-95 are mapped to LPC_INTC_SIC2_SR */
+	value = intc_read_4(LPC_INTC_SIC2_SR);
+	for (i = 0; i < 32; i++) {
+		if (value & (1 << i))
+			return (i + 64);
+	}
+
+	return (-1);
+}
+
+void
+arm_mask_irq(uintptr_t nb)
+{
+	int reg;
+	uint32_t value;
+
+	/* Make sure that interrupt isn't active already */
+	lpc_intc_eoi((void *)nb);
+
+	if (nb > 63) {
+		nb -= 64;
+		reg = LPC_INTC_SIC2_ER;
+	} else if (nb > 31) {
+		nb -= 32;
+		reg = LPC_INTC_SIC1_ER;
+	} else
+		reg = LPC_INTC_MIC_ER;
+
+	/* Clear bit in ER register */
+	value = intc_read_4(reg);
+	value &= ~(1 << nb);
+	intc_write_4(reg, value);
+}
+
+void
+arm_unmask_irq(uintptr_t nb)
+{
+	int reg;
+	uint32_t value;
+
+	if (nb > 63) {
+		nb -= 64;
+		reg = LPC_INTC_SIC2_ER;
+	} else if (nb > 31) {
+		nb -= 32;
+		reg = LPC_INTC_SIC1_ER;
+	} else
+		reg = LPC_INTC_MIC_ER;
+
+	/* Set bit in ER register */
+	value = intc_read_4(reg);
+	value |= (1 << nb);
+	intc_write_4(reg, value);
+}
+
+static void
+lpc_intc_eoi(void *data)
+{
+	int reg;
+	int nb = (int)data;
+	uint32_t value;
+
+	if (nb > 63) {
+		nb -= 64;
+		reg = LPC_INTC_SIC2_RSR;
+	} else if (nb > 31) {
+		nb -= 32;
+		reg = LPC_INTC_SIC1_RSR;
+	} else
+		reg = LPC_INTC_MIC_RSR;
+
+	/* Set bit in RSR register */
+	value = intc_read_4(reg);
+	value |= (1 << nb);
+	intc_write_4(reg, value);
+
+}
+
+struct fdt_fixup_entry fdt_fixup_table[] = {
+	{ NULL, NULL }
+};
+
+static int
+fdt_pic_decode_ic(phandle_t node, pcell_t *intr, int *interrupt, int *trig,
+    int *pol)
+{
+	if (!fdt_is_compatible(node, "lpc,pic"))
+		return (ENXIO);
+
+	*interrupt = fdt32_to_cpu(intr[0]);
+	*trig = INTR_TRIGGER_CONFORM;
+	*pol = INTR_POLARITY_CONFORM;
+	return (0);
+}
+
+fdt_pic_decode_t fdt_pic_table[] = {
+	&fdt_pic_decode_ic,
+	NULL
+};
diff -r 7fffa673adcd -r a301a330526b head/sys/arm/lpc/lpc_machdep.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/head/sys/arm/lpc/lpc_machdep.c	Wed Aug 15 11:16:36 2012 +0300
@@ -0,0 +1,641 @@
+/*-
+ * 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.
+ *
+ * from: FreeBSD: //depot/projects/arm/src/sys/arm/at91/kb920x_machdep.c, rev 45
+ */
+
+#include "opt_ddb.h"
+#include "opt_platform.h"
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: head/sys/arm/lpc/lpc_machdep.c 239278 2012-08-15 05:37:10Z gonzo $");
+
+#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 <machine/fdt.h>
+
+#include <dev/fdt/fdt_common.h>
+#include <dev/ofw/openfirm.h>
+
+#include <arm/lpc/lpcreg.h>
+#include <arm/lpc/lpcvar.h>
+
+#include <dev/ic/ns16550.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/bus.h>
+#include <machine/pte.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>
+
+#define DEBUG
+#undef DEBUG
+
+#ifdef  DEBUG
+#define debugf(fmt, args...) printf(fmt, ##args)
+#else
+#define debugf(fmt, args...)
+#endif
+
+/*
+ * This is the number of L2 page tables required for covering max
+ * (hypothetical) memsize of 4GB and all kernel mappings (vectors, msgbuf,
+ * stacks etc.), uprounded to be divisible by 4.
+ */
+#define KERNEL_PT_MAX	78
+
+/* Define various stack sizes in pages */
+#define IRQ_STACK_SIZE	1
+#define ABT_STACK_SIZE	1
+#define UND_STACK_SIZE	1
+
+extern unsigned char kernbase[];
+extern unsigned char _etext[];
+extern unsigned char _edata[];
+extern unsigned char __bss_start[];
+extern unsigned char _end[];
+
+#ifdef DDB
+extern vm_offset_t ksym_start, ksym_end;
+#endif
+
+extern u_int data_abort_handler_address;
+extern u_int prefetch_abort_handler_address;
+extern u_int undefined_handler_address;
+
+extern vm_offset_t pmap_bootstrap_lastaddr;
+extern int *end;
+
+struct pv_addr kernel_pt_table[KERNEL_PT_MAX];
+
+/* 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;
+vm_offset_t pmap_bootstrap_lastaddr;
+
+const struct pmap_devmap *pmap_devmap_bootstrap_table;
+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 struct mem_region availmem_regions[FDT_MEM_REGIONS];
+static int availmem_regions_sz;
+
+static void print_kenv(void);
+static void print_kernel_section_addr(void);
+
+static void physmap_init(void);
+static int platform_devmap_init(void);
+
+static char *
+kenv_next(char *cp)
+{
+
+	if (cp != NULL) {
+		while (*cp != 0)
+			cp++;
+		cp++;
+		if (*cp == 0)
+			cp = NULL;
+	}
+	return (cp);
+}
+
+static void
+print_kenv(void)
+{
+	int len;
+	char *cp;
+
+	debugf("loader passed (static) kenv:\n");
+	if (kern_envp == NULL) {
+		debugf(" no env, null ptr\n");
+		return;
+	}
+	debugf(" kern_envp = 0x%08x\n", (uint32_t)kern_envp);
+
+	len = 0;
+	for (cp = kern_envp; cp != NULL; cp = kenv_next(cp))
+		debugf(" %x %s\n", (uint32_t)cp, cp);
+}
+
+static void
+print_kernel_section_addr(void)
+{
+
+	debugf("kernel image addresses:\n");
+	debugf(" kernbase       = 0x%08x\n", (uint32_t)kernbase);
+	debugf(" _etext (sdata) = 0x%08x\n", (uint32_t)_etext);
+	debugf(" _edata         = 0x%08x\n", (uint32_t)_edata);
+	debugf(" __bss_start    = 0x%08x\n", (uint32_t)__bss_start);
+	debugf(" _end           = 0x%08x\n", (uint32_t)_end);
+}
+
+static void
+physmap_init(void)
+{
+	int i, j, cnt;
+	vm_offset_t phys_kernelend, kernload;
+	uint32_t s, e, sz;
+	struct mem_region *mp, *mp1;
+
+	phys_kernelend = KERNPHYSADDR + (virtual_avail - KERNVIRTADDR);
+	kernload = KERNPHYSADDR;
+
+	/*
+	 * Remove kernel physical address range from avail
+	 * regions list. Page align all regions.
+	 * Non-page aligned memory isn't very interesting to us.
+	 * Also, sort the entries for ascending addresses.
+	 */
+	sz = 0;
+	cnt = availmem_regions_sz;
+	debugf("processing avail regions:\n");
+	for (mp = availmem_regions; mp->mr_size; mp++) {
+		s = mp->mr_start;
+		e = mp->mr_start + mp->mr_size;
+		debugf(" %08x-%08x -> ", s, e);
+		/* Check whether this region holds all of the kernel. */
+		if (s < kernload && e > phys_kernelend) {
+			availmem_regions[cnt].mr_start = phys_kernelend;
+			availmem_regions[cnt++].mr_size = e - phys_kernelend;
+			e = kernload;
+		}
+		/* Look whether this regions starts within the kernel. */
+		if (s >= kernload && s < phys_kernelend) {
+			if (e <= phys_kernelend)
+				goto empty;
+			s = phys_kernelend;
+		}
+		/* Now look whether this region ends within the kernel. */
+		if (e > kernload && e <= phys_kernelend) {
+			if (s >= kernload) {
+				goto empty;
+			}
+			e = kernload;
+		}
+		/* Now page align the start and size of the region. */
+		s = round_page(s);
+		e = trunc_page(e);
+		if (e < s)
+			e = s;
+		sz = e - s;
+		debugf("%08x-%08x = %x\n", s, e, sz);
+
+		/* Check whether some memory is left here. */
+		if (sz == 0) {
+		empty:
+			printf("skipping\n");
+			bcopy(mp + 1, mp,
+			    (cnt - (mp - availmem_regions)) * sizeof(*mp));
+			cnt--;
+			mp--;
+			continue;
+		}
+
+		/* Do an insertion sort. */
+		for (mp1 = availmem_regions; mp1 < mp; mp1++)
+			if (s < mp1->mr_start)
+				break;
+		if (mp1 < mp) {
+			bcopy(mp1, mp1 + 1, (char *)mp - (char *)mp1);
+			mp1->mr_start = s;
+			mp1->mr_size = sz;
+		} else {
+			mp->mr_start = s;
+			mp->mr_size = sz;
+		}
+	}
+	availmem_regions_sz = cnt;
+
+	/* Fill in phys_avail table, based on availmem_regions */
+	debugf("fill in phys_avail:\n");
+	for (i = 0, j = 0; i < availmem_regions_sz; i++, j += 2) {
+
+		debugf(" region: 0x%08x - 0x%08x (0x%08x)\n",
+		    availmem_regions[i].mr_start,
+		    availmem_regions[i].mr_start + availmem_regions[i].mr_size,
+		    availmem_regions[i].mr_size);
+
+		phys_avail[j] = availmem_regions[i].mr_start;
+		phys_avail[j + 1] = availmem_regions[i].mr_start +
+		    availmem_regions[i].mr_size;
+	}
+	phys_avail[j] = 0;
+	phys_avail[j + 1] = 0;
+}
+
+void *
+initarm(void *mdp, void *unused __unused)
+{
+	struct pv_addr kernel_l1pt;
+	struct pv_addr dpcpu;
+	vm_offset_t dtbp, freemempos, l2_start, lastaddr;
+	uint32_t memsize, l2size;
+	void *kmdp;
+	u_int l1pagetable;
+	int i = 0, j = 0;
+
+	kmdp = NULL;
+	lastaddr = 0;
+	memsize = 0;
+	dtbp = (vm_offset_t)NULL;
+
+	set_cpufuncs();
+
+	/*
+	 * Mask metadata pointer: it is supposed to be on page boundary. If
+	 * the first argument (mdp) doesn't point to a valid address the
+	 * bootloader must have passed us something else than the metadata
+	 * ptr... In this case we want to fall back to some built-in settings.
+	 */
+	mdp = (void *)((uint32_t)mdp & ~PAGE_MASK);
+
+	/* Parse metadata and fetch parameters */
+	if (mdp != NULL) {
+		preload_metadata = mdp;
+		kmdp = preload_search_by_type("elf kernel");
+		if (kmdp != NULL) {
+			boothowto = MD_FETCH(kmdp, MODINFOMD_HOWTO, int);
+			kern_envp = MD_FETCH(kmdp, MODINFOMD_ENVP, char *);
+			dtbp = MD_FETCH(kmdp, MODINFOMD_DTBP, vm_offset_t);
+			lastaddr = MD_FETCH(kmdp, MODINFOMD_KERNEND,
+			    vm_offset_t);
+#ifdef DDB
+			ksym_start = MD_FETCH(kmdp, MODINFOMD_SSYM, uintptr_t);
+			ksym_end = MD_FETCH(kmdp, MODINFOMD_ESYM, uintptr_t);
+#endif
+		}
+
+	} else {
+		/* Fall back to hardcoded metadata. */
+		lastaddr = fake_preload_metadata();
+	}
+
+#if defined(FDT_DTB_STATIC)
+	/*
+	 * In case the device tree blob was not retrieved (from metadata) try
+	 * to use the statically embedded one.
+	 */
+	if (dtbp == (vm_offset_t)NULL)
+		dtbp = (vm_offset_t)&fdt_static_dtb;
+
+#endif
+
+	if (OF_install(OFW_FDT, 0) == FALSE)
+		while (1);
+
+	if (OF_init((void *)dtbp) != 0)
+		while (1);
+
+	/* Grab physical memory regions information from device tree. */
+	if (fdt_get_mem_regions(availmem_regions, &availmem_regions_sz,
+	    &memsize) != 0)
+		while(1);
+
+	if (fdt_immr_addr(LPC_DEV_BASE) != 0)
+		while (1);
+
+	/* Platform-specific initialisation */
+	pmap_bootstrap_lastaddr = fdt_immr_va - ARM_NOCACHE_KVA_SIZE;
+
+	pcpu_init(pcpup, 0, sizeof(struct pcpu));
+	PCPU_SET(curthread, &thread0);
+
+	/* Calculate number of L2 tables needed for mapping vm_page_array */
+	l2size = (memsize / PAGE_SIZE) * sizeof(struct vm_page);
+	l2size = (l2size >> L1_S_SHIFT) + 1;
+
+	/*
+	 * Add one table for end of kernel map, one for stacks, msgbuf and
+	 * L1 and L2 tables map and one for vectors map.
+	 */
+	l2size += 3;
+
+	/* Make it divisible by 4 */
+	l2size = (l2size + 3) & ~3;
+
+#define KERNEL_TEXT_BASE (KERNBASE)
+	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 (i = 0; i < l2size; ++i) {
+		if (!(i % (PAGE_SIZE / L2_TABLE_SIZE_REAL))) {
+			valloc_pages(kernel_pt_table[i],
+			    L2_TABLE_SIZE / PAGE_SIZE);
+			j = i;
+		} else {
+			kernel_pt_table[i].pv_va = kernel_pt_table[j].pv_va +
+			    L2_TABLE_SIZE_REAL * (i - j);
+			kernel_pt_table[i].pv_pa =
+			    kernel_pt_table[i].pv_va - KERNVIRTADDR +
+			    KERNPHYSADDR;
+
+		}
+	}
+	/*
+	 * Allocate a page for the system page mapped to 0x00000000
+	 * or 0xffff0000. 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);
+
+	init_param1();
+
+	valloc_pages(msgbufpv, round_page(msgbufsize) / 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;
+
+	/*
+	 * Try to map as much as possible of kernel text and data using
+	 * 1MB section mapping and for the rest of initial kernel address
+	 * space use L2 coarse tables.
+	 *
+	 * Link L2 tables for mapping remainder of kernel (modulo 1MB)
+	 * and kernel structures
+	 */
+	l2_start = lastaddr & ~(L1_S_OFFSET);
+	for (i = 0 ; i < l2size - 1; i++)
+		pmap_link_l2pt(l1pagetable, l2_start + i * L1_S_SIZE,
+		    &kernel_pt_table[i]);
+
+	pmap_curmaxkvaddr = l2_start + (l2size - 1) * L1_S_SIZE;
+	
+	/* Map kernel code and data */
+	pmap_map_chunk(l1pagetable, KERNVIRTADDR, KERNPHYSADDR,
+	   (((uint32_t)(lastaddr) - KERNVIRTADDR) + PAGE_MASK) & ~PAGE_MASK,
+	    VM_PROT_READ|VM_PROT_WRITE, PTE_CACHE);
+
+
+	/* Map L1 directory and allocated L2 page tables */
+	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, kernel_pt_table[0].pv_va,
+	    kernel_pt_table[0].pv_pa,
+	    L2_TABLE_SIZE_REAL * l2size,
+	    VM_PROT_READ|VM_PROT_WRITE, PTE_PAGETABLE);
+
+	/* Map allocated DPCPU, stacks and msgbuf */
+	pmap_map_chunk(l1pagetable, dpcpu.pv_va, dpcpu.pv_pa,
+	    freemempos - dpcpu.pv_va,
+	    VM_PROT_READ|VM_PROT_WRITE, PTE_CACHE);
+
+	/* Link and map the vector page */
+	pmap_link_l2pt(l1pagetable, ARM_VECTORS_HIGH,
+	    &kernel_pt_table[l2size - 1]);
+	pmap_map_entry(l1pagetable, ARM_VECTORS_HIGH, systempage.pv_pa,
+	    VM_PROT_READ|VM_PROT_WRITE, PTE_CACHE);
+
+	/* Map pmap_devmap[] entries */
+	if (platform_devmap_init() != 0)
+		while (1);
+	pmap_devmap_bootstrap(l1pagetable, pmap_devmap_bootstrap_table);
+
+	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));
+
+	/*
+	 * Only after the SOC registers block is mapped we can perform device
+	 * tree fixups, as they may attempt to read parameters from hardware.
+	 */
+	OF_interpret("perform-fixup", 0);
+
+#if 0
+	/*
+	 * Initialize GPIO as early as possible.
+	 */
+	if (platform_gpio_init() != 0)
+		while (1);
+#endif
+
+	cninit();
+	
+	physmem = memsize / PAGE_SIZE;
+
+	debugf("initarm: console initialized\n");
+	debugf(" arg1 mdp = 0x%08x\n", (uint32_t)mdp);
+	debugf(" boothowto = 0x%08x\n", boothowto);
+	printf(" dtbp = 0x%08x\n", (uint32_t)dtbp);
+	print_kernel_section_addr();
+	print_kenv();
+
+	/*
+	 * 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();
+
+	init_proc0(kernelstack.pv_va);
+
+	arm_vector_init(ARM_VECTORS_HIGH, ARM_VEC_ALL);
+
+	dump_avail[0] = 0;
+	dump_avail[1] = memsize;
+	dump_avail[2] = 0;
+	dump_avail[3] = 0;
+
+	pmap_bootstrap(freemempos, pmap_bootstrap_lastaddr, &kernel_l1pt);
+	msgbufp = (void *)msgbufpv.pv_va;
+	msgbufinit(msgbufp, msgbufsize);
+	mutex_init();
+
+	/*
+	 * Prepare map of physical memory regions available to vm subsystem.
+	 */
+	physmap_init();
+
+	/*
+	 * Set initial values of GPIO output ports
+	 */
+	platform_gpio_init();
+
+	/* Do basic tuning, hz etc */
+	init_param2(physmem);
+	kdb_init();
+	return ((void *)(kernelstack.pv_va + USPACE_SVC_STACK_TOP -
+	    sizeof(struct pcb)));
+}
+
+#define FDT_DEVMAP_MAX	(1 + 2 + 1 + 1)
+static struct pmap_devmap fdt_devmap[FDT_DEVMAP_MAX] = {
+	{ 0, 0, 0, 0, 0, }
+};
+
+/*
+ * Construct pmap_devmap[] with DT-derived config data.
+ */
+static int
+platform_devmap_init(void)
+{
+
+	/*
+	 * IMMR range.
+	 */
+	fdt_devmap[0].pd_va = fdt_immr_va;
+	fdt_devmap[0].pd_pa = fdt_immr_pa;
+	fdt_devmap[0].pd_size = fdt_immr_size;
+	fdt_devmap[0].pd_prot = VM_PROT_READ | VM_PROT_WRITE;
+	fdt_devmap[0].pd_cache = PTE_NOCACHE;
+	
+	pmap_devmap_bootstrap_table = &fdt_devmap[0];
+	return (0);
+}
+
+struct arm32_dma_range *
+bus_dma_get_range(void)
+{
+
+	return (NULL);
+}
+
+int
+bus_dma_get_range_nb(void)
+{
+
+	return (0);
+}
+
+void
+cpu_reset(void)
+{
+	/* Enable WDT */
+	bus_space_write_4(fdtbus_bs_tag, 
+	    LPC_CLKPWR_BASE, LPC_CLKPWR_TIMCLK_CTRL,
+	    LPC_CLKPWR_TIMCLK_CTRL_WATCHDOG);
+
+	/* Instant assert of RESETOUT_N with pulse length 1ms */
+	bus_space_write_4(fdtbus_bs_tag, LPC_WDTIM_BASE, LPC_WDTIM_PULSE, 13000);
+	bus_space_write_4(fdtbus_bs_tag, LPC_WDTIM_BASE, LPC_WDTIM_MCTRL, 0x70);
+
+	for (;;);
+}
diff -r 7fffa673adcd -r a301a330526b head/sys/arm/lpc/lpc_mmc.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/head/sys/arm/lpc/lpc_mmc.c	Wed Aug 15 11:16:36 2012 +0300
@@ -0,0 +1,777 @@
+/*-
+ * Copyright (c) 2011 Jakub Wojciech Klama <jceel at FreeBSD.org>
+ * 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.
+ *
+ */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: head/sys/arm/lpc/lpc_mmc.c 239278 2012-08-15 05:37:10Z gonzo $");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/bio.h>
+#include <sys/bus.h>
+#include <sys/conf.h>
+#include <sys/endian.h>
+#include <sys/kernel.h>
+#include <sys/kthread.h>
+#include <sys/lock.h>
+#include <sys/malloc.h>
+#include <sys/module.h>
+#include <sys/mutex.h>
+#include <sys/queue.h>
+#include <sys/resource.h>
+#include <sys/rman.h>
+#include <sys/time.h>
+#include <sys/timetc.h>
+#include <sys/watchdog.h>
+
+#include <sys/kdb.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 <dev/ofw/ofw_bus.h>
+#include <dev/ofw/ofw_bus_subr.h>
+
+#include <dev/mmc/bridge.h>
+#include <dev/mmc/mmcreg.h>
+#include <dev/mmc/mmcbrvar.h>
+
+#include <arm/lpc/lpcreg.h>
+#include <arm/lpc/lpcvar.h>
+
+#define	DEBUG
+#undef	DEBUG
+
+#ifdef DEBUG
+#define debugf(fmt, args...) do { printf("%s(): ", __func__);   \
+    printf(fmt,##args); } while (0)
+#else
+#define debugf(fmt, args...)
+#endif
+
+struct lpc_mmc_dmamap_arg {
+	bus_addr_t		lm_dma_busaddr;
+};
+
+struct lpc_mmc_softc {
+	device_t		lm_dev;
+	struct mtx		lm_mtx;
+	struct resource *	lm_mem_res;
+	struct resource *	lm_irq_res;
+	bus_space_tag_t		lm_bst;
+	bus_space_handle_t	lm_bsh;
+	void *			lm_intrhand;
+	struct mmc_host		lm_host;
+	struct mmc_request *	lm_req;
+	struct mmc_data *	lm_data;
+	uint32_t		lm_flags;
+#define	LPC_SD_FLAGS_IGNORECRC		(1 << 0)
+	int			lm_xfer_direction;
+#define	DIRECTION_READ		0
+#define	DIRECTION_WRITE		1
+	int			lm_xfer_done;
+	int			lm_bus_busy;
+	bus_dma_tag_t		lm_dma_tag;
+	bus_dmamap_t		lm_dma_map;
+	bus_addr_t		lm_buffer_phys;
+	void *			lm_buffer;
+};
+
+#define	LPC_SD_MAX_BLOCKSIZE	1024
+/* XXX */
+#define	LPC_MMC_DMACH_READ	1
+#define	LPC_MMC_DMACH_WRITE	0
+
+
+static int lpc_mmc_probe(device_t);
+static int lpc_mmc_attach(device_t);
+static int lpc_mmc_detach(device_t);
+static void lpc_mmc_intr(void *);
+
+static void lpc_mmc_cmd(struct lpc_mmc_softc *, struct mmc_command *);
+static void lpc_mmc_setup_xfer(struct lpc_mmc_softc *, struct mmc_data *);
+
+static int lpc_mmc_update_ios(device_t, device_t);
+static int lpc_mmc_request(device_t, device_t, struct mmc_request *);
+static int lpc_mmc_get_ro(device_t, device_t);
+static int lpc_mmc_acquire_host(device_t, device_t);
+static int lpc_mmc_release_host(device_t, device_t);
+
+static void lpc_mmc_dma_rxfinish(void *);
+static void lpc_mmc_dma_rxerror(void *);
+static void lpc_mmc_dma_txfinish(void *);
+static void lpc_mmc_dma_txerror(void *);
+
+static void lpc_mmc_dmamap_cb(void *, bus_dma_segment_t *, int, int);
+
+#define	lpc_mmc_lock(_sc)						\
+    mtx_lock(&_sc->lm_mtx);
+#define	lpc_mmc_unlock(_sc)						\
+    mtx_unlock(&_sc->lm_mtx);
+#define	lpc_mmc_read_4(_sc, _reg)					\
+    bus_space_read_4(_sc->lm_bst, _sc->lm_bsh, _reg)
+#define	lpc_mmc_write_4(_sc, _reg, _value)				\
+    bus_space_write_4(_sc->lm_bst, _sc->lm_bsh, _reg, _value)
+
+static struct lpc_dmac_channel_config lpc_mmc_dma_rxconf = {
+	.ldc_fcntl = LPC_DMAC_FLOW_D_P2M,
+	.ldc_src_periph = LPC_DMAC_SD_ID,
+	.ldc_src_width = LPC_DMAC_CH_CONTROL_WIDTH_4,
+	.ldc_src_incr = 0,
+	.ldc_src_burst = LPC_DMAC_CH_CONTROL_BURST_8,
+	.ldc_dst_periph = LPC_DMAC_SD_ID,
+	.ldc_dst_width = LPC_DMAC_CH_CONTROL_WIDTH_4,
+	.ldc_dst_incr = 1,
+	.ldc_dst_burst = LPC_DMAC_CH_CONTROL_BURST_8,
+	.ldc_success_handler = lpc_mmc_dma_rxfinish,
+	.ldc_error_handler = lpc_mmc_dma_rxerror,
+};
+
+static struct lpc_dmac_channel_config lpc_mmc_dma_txconf = {
+	.ldc_fcntl = LPC_DMAC_FLOW_P_M2P,
+	.ldc_src_periph = LPC_DMAC_SD_ID,
+	.ldc_src_width = LPC_DMAC_CH_CONTROL_WIDTH_4,
+	.ldc_src_incr = 1,
+	.ldc_src_burst = LPC_DMAC_CH_CONTROL_BURST_8,
+	.ldc_dst_periph = LPC_DMAC_SD_ID,
+	.ldc_dst_width = LPC_DMAC_CH_CONTROL_WIDTH_4,
+	.ldc_dst_incr = 0,
+	.ldc_dst_burst = LPC_DMAC_CH_CONTROL_BURST_8,
+	.ldc_success_handler = lpc_mmc_dma_txfinish,
+	.ldc_error_handler = lpc_mmc_dma_txerror,
+};
+
+static int
+lpc_mmc_probe(device_t dev)
+{
+	if (!ofw_bus_is_compatible(dev, "lpc,mmc"))
+		return (ENXIO);
+
+	device_set_desc(dev, "LPC32x0 MMC/SD controller");
+	return (BUS_PROBE_DEFAULT);
+}
+
+static int
+lpc_mmc_attach(device_t dev)
+{
+	struct lpc_mmc_softc *sc = device_get_softc(dev);
+	struct lpc_mmc_dmamap_arg ctx;
+	device_t child;
+	int rid, err;
+
+	sc->lm_dev = dev;
+	sc->lm_req = NULL;
+
+	mtx_init(&sc->lm_mtx, "lpcmmc", "mmc", MTX_DEF);
+
+	rid = 0;
+	sc->lm_mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid,
+	    RF_ACTIVE);
+	if (!sc->lm_mem_res) {
+		device_printf(dev, "cannot allocate memory window\n");
+		return (ENXIO);
+	}
+
+	sc->lm_bst = rman_get_bustag(sc->lm_mem_res);
+	sc->lm_bsh = rman_get_bushandle(sc->lm_mem_res);
+
+	debugf("virtual register space: 0x%08lx\n", sc->lm_bsh);
+
+	rid = 0;
+	sc->lm_irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid,
+	    RF_ACTIVE);
+	if (!sc->lm_irq_res) {
+		device_printf(dev, "cannot allocate interrupt\n");
+		bus_release_resource(dev, SYS_RES_MEMORY, 0, sc->lm_mem_res);
+		return (ENXIO);
+	}
+
+	if (bus_setup_intr(dev, sc->lm_irq_res, INTR_TYPE_MISC | INTR_MPSAFE,
+	    NULL, lpc_mmc_intr, sc, &sc->lm_intrhand))
+	{
+		bus_release_resource(dev, SYS_RES_MEMORY, 0, sc->lm_mem_res);
+		bus_release_resource(dev, SYS_RES_IRQ, 0, sc->lm_irq_res);
+		device_printf(dev, "cannot setup interrupt handler\n");
+		return (ENXIO);
+	}
+
+	sc->lm_host.f_min = 312500;
+	sc->lm_host.f_max = 2500000;
+	sc->lm_host.host_ocr = MMC_OCR_300_310 | MMC_OCR_310_320 |
+	    MMC_OCR_320_330 | MMC_OCR_330_340;
+#if 0
+	sc->lm_host.caps = MMC_CAP_4_BIT_DATA;
+#endif
+
+	lpc_pwr_write(dev, LPC_CLKPWR_MS_CTRL,
+	    LPC_CLKPWR_MS_CTRL_CLOCK_EN | LPC_CLKPWR_MS_CTRL_SD_CLOCK | 1);
+	lpc_mmc_write_4(sc, LPC_SD_POWER, LPC_SD_POWER_CTRL_ON);
+
+	device_set_ivars(dev, &sc->lm_host);
+
+	child = device_add_child(dev, "mmc", -1);
+	if (!child) {
+		device_printf(dev, "attaching MMC bus failed!\n");
+		bus_teardown_intr(dev, sc->lm_irq_res, sc->lm_intrhand);
+		bus_release_resource(dev, SYS_RES_MEMORY, 0, sc->lm_mem_res);
+		bus_release_resource(dev, SYS_RES_IRQ, 0, sc->lm_irq_res);
+		return (ENXIO);
+	}
+
+	/* Alloc DMA memory */
+	err = bus_dma_tag_create(
+	    bus_get_dma_tag(sc->lm_dev),
+	    4, 0,			/* alignment, boundary */
+	    BUS_SPACE_MAXADDR_32BIT,	/* lowaddr */
+	    BUS_SPACE_MAXADDR,		/* highaddr */
+	    NULL, NULL,			/* filter, filterarg */
+	    LPC_SD_MAX_BLOCKSIZE, 1,	/* maxsize, nsegments */
+	    LPC_SD_MAX_BLOCKSIZE, 0,	/* maxsegsize, flags */
+	    NULL, NULL,			/* lockfunc, lockarg */
+	    &sc->lm_dma_tag);
+
+	err = bus_dmamem_alloc(sc->lm_dma_tag, (void **)&sc->lm_buffer,
+	    0, &sc->lm_dma_map);
+	if (err) {
+		device_printf(dev, "cannot allocate framebuffer\n");
+		goto fail;
+	}
+
+	err = bus_dmamap_load(sc->lm_dma_tag, sc->lm_dma_map, sc->lm_buffer,
+	    LPC_SD_MAX_BLOCKSIZE, lpc_mmc_dmamap_cb, &ctx, BUS_DMA_NOWAIT);
+	if (err) {
+		device_printf(dev, "cannot load DMA map\n");
+		goto fail;
+	}
+
+	sc->lm_buffer_phys = ctx.lm_dma_busaddr;
+
+	lpc_mmc_dma_rxconf.ldc_handler_arg = (void *)sc;
+	err = lpc_dmac_config_channel(dev, LPC_MMC_DMACH_READ, &lpc_mmc_dma_rxconf);
+	if (err) {
+		device_printf(dev, "cannot allocate RX DMA channel\n");
+		goto fail;
+	}
+
+
+	lpc_mmc_dma_txconf.ldc_handler_arg = (void *)sc;
+	err = lpc_dmac_config_channel(dev, LPC_MMC_DMACH_WRITE, &lpc_mmc_dma_txconf);	
+	if (err) {
+		device_printf(dev, "cannot allocate TX DMA channel\n");
+		goto fail;
+	}
+
+	bus_generic_probe(dev);
+	bus_generic_attach(dev);
+
+	return (0);
+
+fail:
+	if (sc->lm_intrhand)
+		bus_teardown_intr(dev, sc->lm_irq_res, sc->lm_intrhand);
+	if (sc->lm_irq_res)
+		bus_release_resource(dev, SYS_RES_IRQ, 0, sc->lm_irq_res);
+	if (sc->lm_mem_res)
+		bus_release_resource(dev, SYS_RES_MEMORY, 0, sc->lm_mem_res);
+	return (err);
+}
+
+static int
+lpc_mmc_detach(device_t dev)
+{
+	return (EBUSY);
+}
+
+static void
+lpc_mmc_intr(void *arg)
+{
+	struct lpc_mmc_softc *sc = (struct lpc_mmc_softc *)arg;
+	struct mmc_command *cmd;
+	uint32_t status;
+
+	status = lpc_mmc_read_4(sc, LPC_SD_STATUS);
+
+	debugf("interrupt: 0x%08x\n", status);
+
+	if (status & LPC_SD_STATUS_CMDCRCFAIL) {
+		cmd = sc->lm_req->cmd;
+		cmd->error = sc->lm_flags & LPC_SD_FLAGS_IGNORECRC
+		    ? MMC_ERR_NONE : MMC_ERR_BADCRC;
+		cmd->resp[0] = lpc_mmc_read_4(sc, LPC_SD_RESP0);
+		sc->lm_req->done(sc->lm_req);
+		sc->lm_req = NULL;
+		lpc_mmc_write_4(sc, LPC_SD_CLEAR, LPC_SD_STATUS_CMDCRCFAIL);	
+	}
+
+	if (status & LPC_SD_STATUS_CMDACTIVE)
+	{
+		debugf("command active\n");
+		cmd = sc->lm_req->cmd;
+		cmd->resp[0] = lpc_mmc_read_4(sc, LPC_SD_RESP0);
+		sc->lm_req->done(sc->lm_req);
+		sc->lm_req = NULL;
+	}
+	
+	if (status & LPC_SD_STATUS_DATATIMEOUT) {
+		device_printf(sc->lm_dev, "data timeout\n");
+		lpc_mmc_write_4(sc, LPC_SD_CLEAR, LPC_SD_STATUS_DATATIMEOUT);
+	}
+
+	if (status & LPC_SD_STATUS_TXUNDERRUN) {
+		device_printf(sc->lm_dev, "TX underrun\n");
+		lpc_mmc_write_4(sc, LPC_SD_CLEAR, LPC_SD_STATUS_TXUNDERRUN);
+	}
+	
+	if (status & LPC_SD_STATUS_CMDRESPEND) {
+		debugf("command response\n");
+		cmd = sc->lm_req->cmd;
+		
+		if (cmd->flags & MMC_RSP_136) {
+			cmd->resp[3] = lpc_mmc_read_4(sc, LPC_SD_RESP3);
+			cmd->resp[2] = lpc_mmc_read_4(sc, LPC_SD_RESP2);
+			cmd->resp[1] = lpc_mmc_read_4(sc, LPC_SD_RESP1);
+		}
+
+		cmd->resp[0] = lpc_mmc_read_4(sc, LPC_SD_RESP0);
+		cmd->error = MMC_ERR_NONE;
+	
+		if (cmd->data && (cmd->data->flags & MMC_DATA_WRITE))
+			lpc_mmc_setup_xfer(sc, sc->lm_req->cmd->data);
+
+		if (!cmd->data) {	
+			sc->lm_req->done(sc->lm_req);
+			sc->lm_req = NULL;
+		}
+
+		lpc_mmc_write_4(sc, LPC_SD_CLEAR, LPC_SD_STATUS_CMDRESPEND);
+	}
+
+	if (status & LPC_SD_STATUS_CMDSENT) {
+		debugf("command sent\n");
+		cmd = sc->lm_req->cmd;
+		cmd->error = MMC_ERR_NONE;
+		sc->lm_req->done(sc->lm_req);
+		sc->lm_req = NULL;
+		lpc_mmc_write_4(sc, LPC_SD_CLEAR, LPC_SD_STATUS_CMDSENT);
+	}
+	
+	if (status & LPC_SD_STATUS_DATAEND) {
+		if (sc->lm_xfer_direction == DIRECTION_READ)
+			lpc_dmac_start_burst(sc->lm_dev, LPC_DMAC_SD_ID);
+
+		lpc_mmc_write_4(sc, LPC_SD_CLEAR, LPC_SD_STATUS_DATAEND);
+	}
+
+	if (status & LPC_SD_STATUS_CMDTIMEOUT) {
+		device_printf(sc->lm_dev, "command response timeout\n");
+		cmd = sc->lm_req->cmd;
+		cmd->error = MMC_ERR_TIMEOUT;
+		sc->lm_req->done(sc->lm_req);
+		sc->lm_req = NULL;
+		lpc_mmc_write_4(sc, LPC_SD_CLEAR, LPC_SD_STATUS_CMDTIMEOUT);
+		return;
+	}
+
+	if (status & LPC_SD_STATUS_STARTBITERR) {
+		device_printf(sc->lm_dev, "start bit error\n");
+		lpc_mmc_write_4(sc, LPC_SD_CLEAR, LPC_SD_STATUS_STARTBITERR);
+	}
+
+	if (status & LPC_SD_STATUS_DATACRCFAIL) {		
+		device_printf(sc->lm_dev, "data CRC error\n");
+		debugf("data buffer: %p\n", sc->lm_buffer);
+		cmd = sc->lm_req->cmd;
+		cmd->error = MMC_ERR_BADCRC;
+		sc->lm_req->done(sc->lm_req);
+		sc->lm_req = NULL;
+
+		if (sc->lm_xfer_direction == DIRECTION_READ)
+			lpc_dmac_start_burst(sc->lm_dev, LPC_DMAC_SD_ID);
+
+		lpc_mmc_write_4(sc, LPC_SD_CLEAR, LPC_SD_STATUS_DATACRCFAIL);
+	}
+
+	if (status & LPC_SD_STATUS_DATABLOCKEND) {
+		debugf("data block end\n");
+		if (sc->lm_xfer_direction == DIRECTION_READ)
+			memcpy(sc->lm_data->data, sc->lm_buffer, sc->lm_data->len);
+
+		if (sc->lm_xfer_direction == DIRECTION_WRITE) {
+			lpc_dmac_disable_channel(sc->lm_dev, LPC_MMC_DMACH_WRITE);
+			lpc_mmc_write_4(sc, LPC_SD_DATACTRL, 0);
+		}
+	
+		sc->lm_req->done(sc->lm_req);
+		sc->lm_req = NULL;
+		lpc_mmc_write_4(sc, LPC_SD_CLEAR, LPC_SD_STATUS_DATABLOCKEND);
+	}
+
+	debugf("done\n");
+}
+
+static int
+lpc_mmc_request(device_t bus, device_t child, struct mmc_request *req)
+{
+	struct lpc_mmc_softc *sc = device_get_softc(bus);
+
+	debugf("request: %p\n", req);
+
+	lpc_mmc_lock(sc);
+	if (sc->lm_req)
+		return (EBUSY);
+
+	sc->lm_req = req;
+
+	if (req->cmd->data && req->cmd->data->flags & MMC_DATA_WRITE) {
+		memcpy(sc->lm_buffer, req->cmd->data->data, req->cmd->data->len);
+		lpc_mmc_cmd(sc, req->cmd);
+		lpc_mmc_unlock(sc);
+		return (0);
+	}
+
+	if (req->cmd->data)
+		lpc_mmc_setup_xfer(sc, req->cmd->data);
+
+	lpc_mmc_cmd(sc, req->cmd);
+	lpc_mmc_unlock(sc);
+
+	return (0);
+}
+
+static void
+lpc_mmc_cmd(struct lpc_mmc_softc *sc, struct mmc_command *cmd)
+{
+	uint32_t cmdreg = 0;
+
+	debugf("cmd: %d arg: 0x%08x\n", cmd->opcode, cmd->arg);
+
+	if (lpc_mmc_read_4(sc, LPC_SD_COMMAND) & LPC_SD_COMMAND_ENABLE) {
+		lpc_mmc_write_4(sc, LPC_SD_COMMAND, 0);
+		DELAY(1000);
+	}
+
+	sc->lm_flags &= ~LPC_SD_FLAGS_IGNORECRC;
+
+	if (cmd->flags & MMC_RSP_PRESENT)
+		cmdreg |= LPC_SD_COMMAND_RESPONSE;
+
+	if (MMC_RSP(cmd->flags) == MMC_RSP_R2)
+		cmdreg |= LPC_SD_COMMAND_LONGRSP;
+
+	if (MMC_RSP(cmd->flags) == MMC_RSP_R3)
+		sc->lm_flags |= LPC_SD_FLAGS_IGNORECRC;
+
+	cmdreg |= LPC_SD_COMMAND_ENABLE;
+	cmdreg |= (cmd->opcode & LPC_SD_COMMAND_CMDINDEXMASK);
+
+	lpc_mmc_write_4(sc, LPC_SD_MASK0, 0xffffffff);
+	lpc_mmc_write_4(sc, LPC_SD_MASK1, 0xffffffff);
+	lpc_mmc_write_4(sc, LPC_SD_ARGUMENT, cmd->arg);
+	lpc_mmc_write_4(sc, LPC_SD_COMMAND, cmdreg);
+}
+
+static void
+lpc_mmc_setup_xfer(struct lpc_mmc_softc *sc, struct mmc_data *data)
+{
+	uint32_t datactrl = 0;
+	int data_words = data->len / 4;
+
+	sc->lm_data = data;
+	sc->lm_xfer_done = 0;
+
+	debugf("data: %p, len: %d, %s\n", data,
+	    data->len, (data->flags & MMC_DATA_READ) ? "read" : "write");
+
+	if (data->flags & MMC_DATA_READ) {
+		sc->lm_xfer_direction = DIRECTION_READ;
+		lpc_dmac_setup_transfer(sc->lm_dev, LPC_MMC_DMACH_READ,
+		    LPC_SD_BASE + LPC_SD_FIFO, sc->lm_buffer_phys,
+		    data_words, 0);
+	}
+
+	if (data->flags & MMC_DATA_WRITE) {
+		sc->lm_xfer_direction = DIRECTION_WRITE;
+		lpc_dmac_setup_transfer(sc->lm_dev, LPC_MMC_DMACH_WRITE,
+		    sc->lm_buffer_phys, LPC_SD_BASE + LPC_SD_FIFO,
+		    data_words, 0);
+	}
+
+	datactrl |= (sc->lm_xfer_direction 
+	    ? LPC_SD_DATACTRL_WRITE 
+	    : LPC_SD_DATACTRL_READ);
+
+	datactrl |= LPC_SD_DATACTRL_DMAENABLE | LPC_SD_DATACTRL_ENABLE;
+	datactrl |= (ffs(data->len) - 1) << 4;
+
+	debugf("datactrl: 0x%08x\n", datactrl);
+
+	lpc_mmc_write_4(sc, LPC_SD_DATATIMER, 0xFFFF0000);
+	lpc_mmc_write_4(sc, LPC_SD_DATALENGTH, data->len);
+	lpc_mmc_write_4(sc, LPC_SD_DATACTRL, datactrl);
+}
+
+static int
+lpc_mmc_read_ivar(device_t bus, device_t child, int which, 
+    uintptr_t *result)
+{
+	struct lpc_mmc_softc *sc = device_get_softc(bus);
+
+	switch (which) {
+	default:
+		return (EINVAL);
+	case MMCBR_IVAR_BUS_MODE:
+		*(int *)result = sc->lm_host.ios.bus_mode;
+		break;
+	case MMCBR_IVAR_BUS_WIDTH:
+		*(int *)result = sc->lm_host.ios.bus_width;
+		break;
+	case MMCBR_IVAR_CHIP_SELECT:
+		*(int *)result = sc->lm_host.ios.chip_select;
+		break;
+	case MMCBR_IVAR_CLOCK:
+		*(int *)result = sc->lm_host.ios.clock;
+		break;
+	case MMCBR_IVAR_F_MIN:
+		*(int *)result = sc->lm_host.f_min;
+		break;
+	case MMCBR_IVAR_F_MAX:
+		*(int *)result = sc->lm_host.f_max;
+		break;
+	case MMCBR_IVAR_HOST_OCR:
+		*(int *)result = sc->lm_host.host_ocr;
+		break;
+	case MMCBR_IVAR_MODE:
+		*(int *)result = sc->lm_host.mode;
+		break;
+	case MMCBR_IVAR_OCR:
+		*(int *)result = sc->lm_host.ocr;
+		break;
+	case MMCBR_IVAR_POWER_MODE:
+		*(int *)result = sc->lm_host.ios.power_mode;
+		break;
+	case MMCBR_IVAR_VDD:
+		*(int *)result = sc->lm_host.ios.vdd;
+		break;
+	case MMCBR_IVAR_CAPS:
+		*(int *)result = sc->lm_host.caps;
+		break;
+	case MMCBR_IVAR_MAX_DATA:
+		*(int *)result = 1;
+		break;
+	}
+
+	return (0);
+}
+
+static int
+lpc_mmc_write_ivar(device_t bus, device_t child, int which,
+    uintptr_t value)
+{
+	struct lpc_mmc_softc *sc = device_get_softc(bus);
+
+	switch (which) {
+	default:
+		return (EINVAL);
+	case MMCBR_IVAR_BUS_MODE:
+		sc->lm_host.ios.bus_mode = value;
+		break;
+	case MMCBR_IVAR_BUS_WIDTH:
+		sc->lm_host.ios.bus_width = value;
+		break;
+	case MMCBR_IVAR_CHIP_SELECT:
+		sc->lm_host.ios.chip_select = value;
+		break;
+	case MMCBR_IVAR_CLOCK:
+		sc->lm_host.ios.clock = value;
+		break;
+	case MMCBR_IVAR_MODE:
+		sc->lm_host.mode = value;
+		break;
+	case MMCBR_IVAR_OCR:
+		sc->lm_host.ocr = value;
+		break;
+	case MMCBR_IVAR_POWER_MODE:
+		sc->lm_host.ios.power_mode = value;
+		break;
+	case MMCBR_IVAR_VDD:
+		sc->lm_host.ios.vdd = value;
+		break;
+	/* These are read-only */
+	case MMCBR_IVAR_CAPS:
+	case MMCBR_IVAR_HOST_OCR:
+	case MMCBR_IVAR_F_MIN:
+	case MMCBR_IVAR_F_MAX:
+	case MMCBR_IVAR_MAX_DATA:
+		return (EINVAL);
+	}
+	return (0);
+}
+
+static int
+lpc_mmc_update_ios(device_t bus, device_t child)
+{
+	struct lpc_mmc_softc *sc = device_get_softc(bus);
+	struct mmc_ios *ios = &sc->lm_host.ios;
+	uint32_t clkdiv = 0, pwr = 0;
+
+	if (ios->bus_width == bus_width_4)
+		clkdiv |= LPC_SD_CLOCK_WIDEBUS;
+
+	/* Calculate clock divider */
+	clkdiv = (LPC_SD_CLK / (2 * ios->clock)) - 1;
+
+	/* Clock rate should not exceed rate requested in ios */
+	if ((LPC_SD_CLK / (2 * (clkdiv + 1))) > ios->clock)
+		clkdiv++;
+
+	debugf("clock: %dHz, clkdiv: %d\n", ios->clock, clkdiv);
+
+	if (ios->bus_width == bus_width_4) {
+		debugf("using wide bus mode\n");
+		clkdiv |= LPC_SD_CLOCK_WIDEBUS;
+	}
+
+	lpc_mmc_write_4(sc, LPC_SD_CLOCK, clkdiv | LPC_SD_CLOCK_ENABLE);
+
+	switch (ios->power_mode) {
+	case power_off:
+		pwr |= LPC_SD_POWER_CTRL_OFF;
+		break;
+	case power_up:
+		pwr |= LPC_SD_POWER_CTRL_UP;
+		break;
+	case power_on:
+		pwr |= LPC_SD_POWER_CTRL_ON;
+		break;
+	}
+
+	if (ios->bus_mode == opendrain)
+		pwr |= LPC_SD_POWER_OPENDRAIN;
+
+	lpc_mmc_write_4(sc, LPC_SD_POWER, pwr);
+
+	return (0);
+}
+
+static int
+lpc_mmc_get_ro(device_t bus, device_t child)
+{
+
+	return (0);
+}
+
+static int
+lpc_mmc_acquire_host(device_t bus, device_t child)
+{
+	struct lpc_mmc_softc *sc = device_get_softc(bus);
+	int error = 0;
+
+	lpc_mmc_lock(sc);
+	while (sc->lm_bus_busy)
+		error = mtx_sleep(sc, &sc->lm_mtx, PZERO, "mmcah", 0);
+
+	sc->lm_bus_busy++;
+	lpc_mmc_unlock(sc);
+	return (error);
+}
+
+static int
+lpc_mmc_release_host(device_t bus, device_t child)
+{
+	struct lpc_mmc_softc *sc = device_get_softc(bus);
+
+	lpc_mmc_lock(sc);
+	sc->lm_bus_busy--;
+	wakeup(sc);
+	lpc_mmc_unlock(sc);
+	return (0);
+}
+
+static void lpc_mmc_dma_rxfinish(void *arg)
+{
+}
+
+static void lpc_mmc_dma_rxerror(void *arg)
+{
+	struct lpc_mmc_softc *sc = (struct lpc_mmc_softc *)arg;
+	device_printf(sc->lm_dev, "DMA RX error\n");
+}
+
+static void lpc_mmc_dma_txfinish(void *arg)
+{
+}
+
+static void lpc_mmc_dma_txerror(void *arg)
+{
+	struct lpc_mmc_softc *sc = (struct lpc_mmc_softc *)arg;
+	device_printf(sc->lm_dev, "DMA TX error\n");
+}
+
+static void
+lpc_mmc_dmamap_cb(void *arg, bus_dma_segment_t *segs, int nseg, int err)
+{
+	struct lpc_mmc_dmamap_arg *ctx;
+
+	if (err)
+		return;
+
+	ctx = (struct lpc_mmc_dmamap_arg *)arg;
+	ctx->lm_dma_busaddr = segs[0].ds_addr;
+}
+
+static device_method_t lpc_mmc_methods[] = {
+	/* Device interface */
+	DEVMETHOD(device_probe,		lpc_mmc_probe),
+	DEVMETHOD(device_attach,	lpc_mmc_attach),
+	DEVMETHOD(device_detach,	lpc_mmc_detach),
+
+	/* Bus interface */
+	DEVMETHOD(bus_read_ivar,	lpc_mmc_read_ivar),
+	DEVMETHOD(bus_write_ivar,	lpc_mmc_write_ivar),
+	DEVMETHOD(bus_print_child,	bus_generic_print_child),
+
+	/* MMC bridge interface */
+	DEVMETHOD(mmcbr_update_ios,	lpc_mmc_update_ios),
+	DEVMETHOD(mmcbr_request,	lpc_mmc_request),
+	DEVMETHOD(mmcbr_get_ro,		lpc_mmc_get_ro),
+	DEVMETHOD(mmcbr_acquire_host,	lpc_mmc_acquire_host),
+	DEVMETHOD(mmcbr_release_host,	lpc_mmc_release_host),
+
+	{ 0, 0 }
+};
+
+static devclass_t lpc_mmc_devclass;
+
+static driver_t lpc_mmc_driver = {
+	"lpcmmc",
+	lpc_mmc_methods,
+	sizeof(struct lpc_mmc_softc),
+};
+
+DRIVER_MODULE(lpcmmc, simplebus, lpc_mmc_driver, lpc_mmc_devclass, 0, 0);
diff -r 7fffa673adcd -r a301a330526b head/sys/arm/lpc/lpc_ohci.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/head/sys/arm/lpc/lpc_ohci.c	Wed Aug 15 11:16:36 2012 +0300
@@ -0,0 +1,354 @@
+/*-
+ * Copyright (c) 2011 Jakub Wojciech Klama <jceel at FreeBSD.org>
+ * 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.
+ *
+ */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: head/sys/arm/lpc/lpc_ohci.c 239278 2012-08-15 05:37:10Z gonzo $");
+
+#include <sys/stdint.h>
+#include <sys/stddef.h>
+#include <sys/param.h>
+#include <sys/queue.h>
+#include <sys/types.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/bus.h>
+#include <sys/module.h>
+#include <sys/lock.h>
+#include <sys/mutex.h>
+#include <sys/condvar.h>
+#include <sys/sysctl.h>
+#include <sys/rman.h>
+#include <sys/sx.h>
+#include <sys/unistd.h>
+#include <sys/callout.h>
+#include <sys/malloc.h>
+#include <sys/priv.h>
+
+#include <sys/kdb.h>
+
+#include <dev/ofw/ofw_bus.h>
+#include <dev/ofw/ofw_bus_subr.h>
+
+#include <dev/usb/usb.h>
+#include <dev/usb/usbdi.h>
+
+#include <dev/usb/usb_core.h>
+#include <dev/usb/usb_busdma.h>
+#include <dev/usb/usb_process.h>
+#include <dev/usb/usb_util.h>
+
+#include <dev/usb/usb_controller.h>
+#include <dev/usb/usb_bus.h>
+#include <dev/usb/controller/ohci.h>
+#include <dev/usb/controller/ohcireg.h>
+
+#include <arm/lpc/lpcreg.h>
+#include <arm/lpc/lpcvar.h>
+
+#define	I2C_START_BIT		(1 << 8)
+#define	I2C_STOP_BIT		(1 << 9)
+#define	I2C_READ		0x01
+#define	I2C_WRITE		0x00
+#define	DUMMY_BYTE		0x55
+
+#define	lpc_otg_read_4(_sc, _reg)					\
+    bus_space_read_4(_sc->sc_io_tag, _sc->sc_io_hdl, _reg)
+#define	lpc_otg_write_4(_sc, _reg, _value)				\
+    bus_space_write_4(_sc->sc_io_tag, _sc->sc_io_hdl, _reg, _value)
+#define	lpc_otg_wait_write_4(_sc, _wreg, _sreg, _value)			\
+    do {								\
+    	lpc_otg_write_4(_sc, _wreg, _value);				\
+    	while ((lpc_otg_read_4(_sc, _sreg) & _value) != _value);    	\
+    } while (0);
+
+static int lpc_ohci_probe(device_t dev);
+static int lpc_ohci_attach(device_t dev);
+static int lpc_ohci_detach(device_t dev);
+
+static void lpc_otg_i2c_reset(struct ohci_softc *);
+
+static int lpc_isp3101_read(struct ohci_softc *, int);
+static void lpc_isp3101_write(struct ohci_softc *, int, int);
+static void lpc_isp3101_clear(struct ohci_softc *, int, int);
+static void lpc_isp3101_configure(device_t dev, struct ohci_softc *);
+
+static int
+lpc_ohci_probe(device_t dev)
+{
+	if (!ofw_bus_is_compatible(dev, "lpc,usb-ohci"))
+		return (ENXIO);
+
+	device_set_desc(dev, "LPC32x0 USB OHCI controller");
+	return (BUS_PROBE_DEFAULT);
+}
+
+static int
+lpc_ohci_attach(device_t dev)
+{
+	struct ohci_softc *sc = device_get_softc(dev);
+	int err;
+	int rid;
+	int i = 0;
+	uint32_t usbctrl;
+	uint32_t otgstatus;
+
+	sc->sc_bus.parent = dev;
+	sc->sc_bus.devices = sc->sc_devices;
+	sc->sc_bus.devices_max = OHCI_MAX_DEVICES;
+
+	if (usb_bus_mem_alloc_all(&sc->sc_bus, USB_GET_DMA_TAG(dev),
+	    &ohci_iterate_hw_softc))
+		return (ENOMEM);
+
+	rid = 0;
+	sc->sc_io_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, RF_ACTIVE);
+	if (!sc->sc_io_res) {
+		device_printf(dev, "cannot map OHCI register space\n");
+		goto fail;
+	}
+
+	sc->sc_io_tag = rman_get_bustag(sc->sc_io_res);
+	sc->sc_io_hdl = rman_get_bushandle(sc->sc_io_res);
+	sc->sc_io_size = rman_get_size(sc->sc_io_res);
+
+	rid = 0;
+	sc->sc_irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, RF_ACTIVE);
+	if (sc->sc_irq_res == NULL) {
+		device_printf(dev, "cannot allocate interrupt\n");
+		goto fail;
+	}
+
+	sc->sc_bus.bdev = device_add_child(dev, "usbus", -1);
+	if (!(sc->sc_bus.bdev))
+		goto fail;
+
+	device_set_ivars(sc->sc_bus.bdev, &sc->sc_bus);
+	strlcpy(sc->sc_vendor, "NXP", sizeof(sc->sc_vendor));
+
+	err = bus_setup_intr(dev, sc->sc_irq_res, INTR_TYPE_BIO | INTR_MPSAFE,
+	    NULL, (void *)ohci_interrupt, sc, &sc->sc_intr_hdl);
+	if (err) {
+		sc->sc_intr_hdl = NULL;
+		goto fail;
+	}
+
+	usbctrl = lpc_pwr_read(dev, LPC_CLKPWR_USB_CTRL);
+	usbctrl |= LPC_CLKPWR_USB_CTRL_SLAVE_HCLK | LPC_CLKPWR_USB_CTRL_BUSKEEPER;
+	lpc_pwr_write(dev, LPC_CLKPWR_USB_CTRL, usbctrl);
+
+	/* Enable OTG I2C clock */
+	lpc_otg_wait_write_4(sc, LPC_OTG_CLOCK_CTRL,
+	    LPC_OTG_CLOCK_STATUS, LPC_OTG_CLOCK_CTRL_I2C_EN);
+
+	/* Reset OTG I2C bus */
+	lpc_otg_i2c_reset(sc);
+
+	lpc_isp3101_configure(dev, sc);
+
+	/* Configure PLL */
+	usbctrl &= ~(LPC_CLKPWR_USB_CTRL_CLK_EN1 | LPC_CLKPWR_USB_CTRL_CLK_EN2);
+	lpc_pwr_write(dev, LPC_CLKPWR_USB_CTRL, usbctrl);
+
+	usbctrl |= LPC_CLKPWR_USB_CTRL_CLK_EN1;
+	lpc_pwr_write(dev, LPC_CLKPWR_USB_CTRL, usbctrl);
+
+	usbctrl |= LPC_CLKPWR_USB_CTRL_FDBKDIV(192-1);
+	usbctrl |= LPC_CLKPWR_USB_CTRL_POSTDIV(1);
+	usbctrl |= LPC_CLKPWR_USB_CTRL_PLL_PDOWN;
+
+	lpc_pwr_write(dev, LPC_CLKPWR_USB_CTRL, usbctrl);
+	do {
+		usbctrl = lpc_pwr_read(dev, LPC_CLKPWR_USB_CTRL);
+		if (i++ > 100000) {
+			device_printf(dev, "USB OTG PLL doesn't lock!\n");
+			goto fail;
+		}
+	} while ((usbctrl & LPC_CLKPWR_USB_CTRL_PLL_LOCK) == 0);
+
+	usbctrl |= LPC_CLKPWR_USB_CTRL_CLK_EN2;
+	usbctrl |= LPC_CLKPWR_USB_CTRL_HOST_NEED_CLK_EN;
+	lpc_pwr_write(dev, LPC_CLKPWR_USB_CTRL, usbctrl);
+	lpc_otg_wait_write_4(sc, LPC_OTG_CLOCK_CTRL, LPC_OTG_CLOCK_STATUS,
+	    (LPC_OTG_CLOCK_CTRL_AHB_EN | LPC_OTG_CLOCK_CTRL_OTG_EN |
+	    LPC_OTG_CLOCK_CTRL_I2C_EN | LPC_OTG_CLOCK_CTRL_HOST_EN));
+
+	otgstatus = lpc_otg_read_4(sc, LPC_OTG_STATUS);
+	lpc_otg_write_4(sc, LPC_OTG_STATUS, otgstatus |
+	    LPC_OTG_STATUS_HOST_EN);
+
+	lpc_isp3101_write(sc, LPC_ISP3101_OTG_CONTROL_1,
+	    LPC_ISP3101_OTG1_VBUS_DRV);
+
+	err = ohci_init(sc);
+	if (err)
+		goto fail;
+
+	err = device_probe_and_attach(sc->sc_bus.bdev);
+	if (err)
+		goto fail;
+	
+	return (0);
+
+fail:
+	if (sc->sc_intr_hdl)
+		bus_teardown_intr(dev, sc->sc_irq_res, sc->sc_intr_hdl);
+	if (sc->sc_irq_res)
+		bus_release_resource(dev, SYS_RES_IRQ, 0, sc->sc_irq_res);
+	if (sc->sc_io_res)
+		bus_release_resource(dev, SYS_RES_MEMORY, 0, sc->sc_io_res);
+
+	return (ENXIO);
+}
+
+static int
+lpc_isp3101_read(struct ohci_softc *sc, int reg)
+{
+	int status;
+	int i = 0;
+
+	lpc_otg_write_4(sc, LPC_OTG_I2C_TXRX, 
+	    (LPC_ISP3101_I2C_ADDR << 1) | I2C_START_BIT);
+	lpc_otg_write_4(sc, LPC_OTG_I2C_TXRX, reg);
+	lpc_otg_write_4(sc, LPC_OTG_I2C_TXRX, (LPC_ISP3101_I2C_ADDR << 1) | 
+	    I2C_START_BIT | I2C_READ);
+	lpc_otg_write_4(sc, LPC_OTG_I2C_TXRX, I2C_STOP_BIT | DUMMY_BYTE);
+	
+	do {
+		status = lpc_otg_read_4(sc, LPC_OTG_I2C_STATUS);
+		i++;
+	} while ((status & LPC_OTG_I2C_STATUS_TDI) == 0 || i < 100000);
+
+	lpc_otg_write_4(sc, LPC_OTG_I2C_STATUS, LPC_OTG_I2C_STATUS_TDI);
+
+	return (lpc_otg_read_4(sc, LPC_OTG_I2C_TXRX) & 0xff);
+}
+
+static void
+lpc_otg_i2c_reset(struct ohci_softc *sc)
+{
+	int ctrl;
+	int i = 0;
+
+	lpc_otg_write_4(sc, LPC_OTG_I2C_CLKHI, 0x3f);
+	lpc_otg_write_4(sc, LPC_OTG_I2C_CLKLO, 0x3f);
+
+	ctrl = lpc_otg_read_4(sc, LPC_OTG_I2C_CTRL);
+	lpc_otg_write_4(sc, LPC_OTG_I2C_CTRL, ctrl | LPC_OTG_I2C_CTRL_SRST);
+
+	do {
+		ctrl = lpc_otg_read_4(sc, LPC_OTG_I2C_CTRL);
+		i++;
+	} while (ctrl & LPC_OTG_I2C_CTRL_SRST);
+}
+
+static void
+lpc_isp3101_write(struct ohci_softc *sc, int reg, int value)
+{
+	int status;
+	int i = 0;
+
+	bus_space_write_4(sc->sc_io_tag, sc->sc_io_hdl, LPC_OTG_I2C_TXRX,
+	    (LPC_ISP3101_I2C_ADDR << 1) | I2C_START_BIT);
+	bus_space_write_4(sc->sc_io_tag, sc->sc_io_hdl, LPC_OTG_I2C_TXRX,
+	    (reg | I2C_WRITE));
+	bus_space_write_4(sc->sc_io_tag, sc->sc_io_hdl, LPC_OTG_I2C_TXRX,
+	    (value | I2C_STOP_BIT));
+
+	do {
+		status = bus_space_read_4(sc->sc_io_tag, sc->sc_io_hdl,
+		    LPC_OTG_I2C_STATUS);
+		i++;
+	} while ((status & LPC_OTG_I2C_STATUS_TDI) == 0 || i < 100000);
+
+	bus_space_write_4(sc->sc_io_tag, sc->sc_io_hdl, LPC_OTG_I2C_STATUS,
+	    LPC_OTG_I2C_STATUS_TDI);
+}
+
+static __inline void
+lpc_isp3101_clear(struct ohci_softc *sc, int reg, int value)
+{
+	lpc_isp3101_write(sc, (reg | LPC_ISP3101_REG_CLEAR_ADDR), value);
+}
+
+static void
+lpc_isp3101_configure(device_t dev, struct ohci_softc *sc)
+{
+	lpc_isp3101_clear(sc, LPC_ISP3101_MODE_CONTROL_1, LPC_ISP3101_MC1_UART_EN);
+	lpc_isp3101_clear(sc, LPC_ISP3101_MODE_CONTROL_1, ~LPC_ISP3101_MC1_SPEED_REG);
+	lpc_isp3101_write(sc, LPC_ISP3101_MODE_CONTROL_1, LPC_ISP3101_MC1_SPEED_REG);
+	lpc_isp3101_clear(sc, LPC_ISP3101_MODE_CONTROL_2, ~0);
+	lpc_isp3101_write(sc, LPC_ISP3101_MODE_CONTROL_2,
+	    (LPC_ISP3101_MC2_BI_DI | LPC_ISP3101_MC2_PSW_EN
+	    | LPC_ISP3101_MC2_SPD_SUSP_CTRL));
+
+	lpc_isp3101_clear(sc, LPC_ISP3101_OTG_CONTROL_1, ~0);
+	lpc_isp3101_write(sc, LPC_ISP3101_MODE_CONTROL_1, LPC_ISP3101_MC1_DAT_SE0);
+	lpc_isp3101_write(sc, LPC_ISP3101_OTG_CONTROL_1,
+	    (LPC_ISP3101_OTG1_DM_PULLDOWN | LPC_ISP3101_OTG1_DP_PULLDOWN));
+	
+	lpc_isp3101_clear(sc, LPC_ISP3101_OTG_CONTROL_1,
+	    (LPC_ISP3101_OTG1_DM_PULLUP | LPC_ISP3101_OTG1_DP_PULLUP));
+
+	lpc_isp3101_clear(sc, LPC_ISP3101_OTG_INTR_LATCH, ~0);
+	lpc_isp3101_clear(sc, LPC_ISP3101_OTG_INTR_FALLING, ~0);
+	lpc_isp3101_clear(sc, LPC_ISP3101_OTG_INTR_RISING, ~0);
+
+	device_printf(dev,
+	    "ISP3101 PHY <vendor:0x%04x, product:0x%04x, version:0x%04x>\n",
+	    (lpc_isp3101_read(sc, 0x00) | (lpc_isp3101_read(sc, 0x01) << 8)),
+	    (lpc_isp3101_read(sc, 0x03) | (lpc_isp3101_read(sc, 0x04) << 8)),
+	    (lpc_isp3101_read(sc, 0x14) | (lpc_isp3101_read(sc, 0x15) << 8)));
+}
+
+static int
+lpc_ohci_detach(device_t dev)
+{
+	return (0);
+}
+
+
+static device_method_t lpc_ohci_methods[] = {
+	/* Device interface */
+	DEVMETHOD(device_probe,		lpc_ohci_probe),
+	DEVMETHOD(device_attach,	lpc_ohci_attach),
+	DEVMETHOD(device_detach,	lpc_ohci_detach),
+	DEVMETHOD(device_shutdown,	bus_generic_shutdown),
+
+	/* Bus interface */
+	DEVMETHOD(bus_print_child,	bus_generic_print_child),
+	{ 0, 0 }
+};
+
+static driver_t lpc_ohci_driver = {
+	"ohci",
+	lpc_ohci_methods,
+	sizeof(struct ohci_softc),
+};
+
+static devclass_t lpc_ohci_devclass;
+
+DRIVER_MODULE(ohci, simplebus, lpc_ohci_driver, lpc_ohci_devclass, 0, 0);
+MODULE_DEPEND(ohci, usb, 1, 1, 1);
diff -r 7fffa673adcd -r a301a330526b head/sys/arm/lpc/lpc_pll.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/head/sys/arm/lpc/lpc_pll.c	Wed Aug 15 11:16:36 2012 +0300
@@ -0,0 +1,28 @@
+/*-
+ * Copyright (c) 2011 Jakub Wojciech Klama <jceel at FreeBSD.org>
+ * 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.
+ *
+ */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: head/sys/arm/lpc/lpc_pll.c 239278 2012-08-15 05:37:10Z gonzo $");
diff -r 7fffa673adcd -r a301a330526b head/sys/arm/lpc/lpc_pwr.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/head/sys/arm/lpc/lpc_pwr.c	Wed Aug 15 11:16:36 2012 +0300
@@ -0,0 +1,126 @@
+/*-
+ * Copyright (c) 2011 Jakub Wojciech Klama <jceel at FreeBSD.org>
+ * 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.
+ *
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: head/sys/arm/lpc/lpc_pwr.c 239278 2012-08-15 05:37:10Z gonzo $");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/bus.h>
+#include <sys/kernel.h>
+#include <sys/module.h>
+#include <sys/malloc.h>
+#include <sys/rman.h>
+#include <machine/bus.h>
+#include <machine/intr.h>
+
+#include <dev/ofw/ofw_bus.h>
+#include <dev/ofw/ofw_bus_subr.h>
+
+#include <arm/lpc/lpcreg.h>
+#include <arm/lpc/lpcvar.h>
+
+struct lpc_pwr_softc {
+	device_t		dp_dev;
+	struct resource *	dp_mem_res;
+	bus_space_tag_t		dp_bst;
+	bus_space_handle_t	dp_bsh;
+};
+
+static struct lpc_pwr_softc *lpc_pwr_sc = NULL;
+
+static int lpc_pwr_probe(device_t);
+static int lpc_pwr_attach(device_t);
+
+#define	lpc_pwr_read_4(_sc, _reg)			\
+    bus_space_read_4((_sc)->dp_bst, (_sc)->dp_bsh, _reg)
+#define	lpc_pwr_write_4(_sc, _reg, _val)		\
+    bus_space_write_4((_sc)->dp_bst, (_sc)->dp_bsh, _reg, _val)
+
+static int
+lpc_pwr_probe(device_t dev)
+{
+	
+	if (!ofw_bus_is_compatible(dev, "lpc,pwr"))
+		return (ENXIO);
+
+	device_set_desc(dev, "LPC32x0 Power Controller");
+	return (BUS_PROBE_DEFAULT);
+}
+
+static int
+lpc_pwr_attach(device_t dev)
+{
+	struct lpc_pwr_softc *sc = device_get_softc(dev);
+	int rid;
+
+	sc->dp_dev = dev;
+
+	rid = 0;
+	sc->dp_mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, 
+	    RF_ACTIVE);
+	if (!sc->dp_mem_res) {
+		device_printf(dev, "cannot allocate memory window\n");
+		return (ENXIO);
+	}
+
+	sc->dp_bst = rman_get_bustag(sc->dp_mem_res);
+	sc->dp_bsh = rman_get_bushandle(sc->dp_mem_res);
+
+	lpc_pwr_sc = sc;
+
+	return (0);
+}
+
+uint32_t
+lpc_pwr_read(device_t dev, int reg)
+{
+	return (lpc_pwr_read_4(lpc_pwr_sc, reg));
+}
+
+void
+lpc_pwr_write(device_t dev, int reg, uint32_t value)
+{
+	lpc_pwr_write_4(lpc_pwr_sc, reg, value);
+}
+
+static device_method_t lpc_pwr_methods[] = {
+	/* Device interface */
+	DEVMETHOD(device_probe,		lpc_pwr_probe),
+	DEVMETHOD(device_attach,	lpc_pwr_attach),
+	{ 0, 0 }
+};
+
+static devclass_t lpc_pwr_devclass;
+
+static driver_t lpc_pwr_driver = {
+	"pwr",
+	lpc_pwr_methods,
+	sizeof(struct lpc_pwr_softc),
+};
+
+DRIVER_MODULE(pwr, simplebus, lpc_pwr_driver, lpc_pwr_devclass, 0, 0);
diff -r 7fffa673adcd -r a301a330526b head/sys/arm/lpc/lpc_rtc.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/head/sys/arm/lpc/lpc_rtc.c	Wed Aug 15 11:16:36 2012 +0300
@@ -0,0 +1,147 @@
+/*-
+ * Copyright (c) 2011 Jakub Wojciech Klama <jceel at FreeBSD.org>
+ * 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.
+ *
+ */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: head/sys/arm/lpc/lpc_rtc.c 239278 2012-08-15 05:37:10Z gonzo $");
+
+#include <sys/param.h>
+#include <sys/bus.h>
+#include <sys/time.h>
+#include <sys/clock.h>
+#include <sys/resource.h>
+#include <sys/systm.h>
+#include <sys/rman.h>
+#include <sys/kernel.h>
+#include <sys/module.h>
+
+#include <machine/bus.h>
+#include <machine/resource.h>
+
+#include <dev/ofw/ofw_bus.h>
+#include <dev/ofw/ofw_bus_subr.h>
+
+#include <arm/lpc/lpcreg.h>
+
+#include "clock_if.h"
+
+struct lpc_rtc_softc {
+	device_t			lr_dev;
+	struct resource	*		lr_mem_res;
+	bus_space_tag_t			lr_bst;
+	bus_space_handle_t		lr_bsh;
+};
+
+static int lpc_rtc_probe(device_t dev);
+static int lpc_rtc_attach(device_t dev);
+static int lpc_rtc_gettime(device_t dev, struct timespec *ts);
+static int lpc_rtc_settime(device_t, struct timespec *);
+
+static int
+lpc_rtc_probe(device_t dev)
+{
+
+	if (!ofw_bus_is_compatible(dev, "lpc,rtc"))
+		return (ENXIO);
+
+	device_set_desc(dev, "LPC32x0 real time clock");
+	return (BUS_PROBE_DEFAULT);
+}
+
+static int
+lpc_rtc_attach(device_t dev)
+{
+	struct lpc_rtc_softc *sc = device_get_softc(dev);
+	int rid = 0;
+
+	sc->lr_dev = dev;
+
+	clock_register(dev, 1000000);
+
+	sc->lr_mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid,
+	    RF_ACTIVE);
+	if (!sc->lr_mem_res) {
+		device_printf(dev, "cannot allocate memory window\n");
+		return (ENXIO);
+	}
+
+	sc->lr_bst = rman_get_bustag(sc->lr_mem_res);
+	sc->lr_bsh = rman_get_bushandle(sc->lr_mem_res);
+
+	return (0);
+}
+
+static int
+lpc_rtc_gettime(device_t dev, struct timespec *ts)
+{
+	struct lpc_rtc_softc *sc = device_get_softc(dev);
+
+	ts->tv_sec = bus_space_read_4(sc->lr_bst, sc->lr_bsh, LPC_RTC_UCOUNT);
+	ts->tv_nsec = 0;
+
+	return (0);
+}
+
+static int
+lpc_rtc_settime(device_t dev, struct timespec *ts)
+{
+	struct lpc_rtc_softc *sc = device_get_softc(dev);
+	uint32_t ctrl;
+
+	/* Stop RTC */
+	ctrl = bus_space_read_4(sc->lr_bst, sc->lr_bsh, LPC_RTC_CTRL);
+	bus_space_write_4(sc->lr_bst, sc->lr_bsh, LPC_RTC_CTRL, ctrl | LPC_RTC_CTRL_DISABLE);
+
+	/* Write actual value */
+	bus_space_write_4(sc->lr_bst, sc->lr_bsh, LPC_RTC_UCOUNT, ts->tv_sec);
+
+	/* Start RTC */
+	ctrl = bus_space_read_4(sc->lr_bst, sc->lr_bsh, LPC_RTC_CTRL);
+	bus_space_write_4(sc->lr_bst, sc->lr_bsh, LPC_RTC_CTRL, ctrl & ~LPC_RTC_CTRL_DISABLE);
+
+	return (0);	
+}
+
+static device_method_t lpc_rtc_methods[] = {
+	/* Device interface */
+	DEVMETHOD(device_probe,		lpc_rtc_probe),
+	DEVMETHOD(device_attach,	lpc_rtc_attach),
+
+	/* Clock interface */
+	DEVMETHOD(clock_gettime,	lpc_rtc_gettime),
+	DEVMETHOD(clock_settime,	lpc_rtc_settime),
+
+	{ 0, 0 },
+};
+
+static driver_t lpc_rtc_driver = {
+	"rtc",
+	lpc_rtc_methods,
+	sizeof(struct lpc_rtc_softc),
+};
+
+static devclass_t lpc_rtc_devclass;
+
+DRIVER_MODULE(rtc, simplebus, lpc_rtc_driver, lpc_rtc_devclass, 0, 0);
diff -r 7fffa673adcd -r a301a330526b head/sys/arm/lpc/lpc_space.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/head/sys/arm/lpc/lpc_space.c	Wed Aug 15 11:16:36 2012 +0300
@@ -0,0 +1,147 @@
+/*-
+ * Copyright (c) 2011 Jakub Wojciech Klama <jceel at FreeBSD.org>
+ * 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.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: head/sys/arm/lpc/lpc_space.c 239278 2012-08-15 05:37:10Z gonzo $");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/bus.h>
+#include <sys/kernel.h>
+#include <sys/malloc.h>
+#include <machine/bus.h>
+
+bs_protos(generic);
+bs_protos(generic_armv4);
+
+static struct bus_space _base_tag = {
+	/* cookie */
+	NULL,
+
+	/* mapping/unmapping */
+	generic_bs_map,
+	generic_bs_unmap,
+	generic_bs_subregion,
+
+	/* allocation/deallocation */
+	generic_bs_alloc,
+	generic_bs_free,
+
+	/* barrier */
+	generic_bs_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,
+	NULL,
+	NULL,
+	NULL,
+
+	/* set multiple */
+	NULL,
+	NULL,
+	NULL,
+	NULL,
+
+	/* set region */
+	NULL,
+	NULL,
+	NULL,
+	NULL,
+
+	/* copy */
+	NULL,
+	NULL,
+	NULL,
+	NULL,
+
+	/* read stream (single) */
+	NULL,
+	NULL,
+	NULL,
+	NULL,
+
+	/* read multiple stream */
+	NULL,
+	generic_armv4_bs_rm_2,
+	NULL,
+	NULL,
+
+	/* read region stream */
+	NULL,
+	NULL,
+	NULL,
+	NULL,
+
+	/* write stream (single) */
+	NULL,
+	NULL,
+	NULL,
+	NULL,
+
+	/* write multiple stream */
+	NULL,
+	generic_armv4_bs_wm_2,
+	NULL,
+	NULL,
+
+	/* write region stream */
+	NULL,
+	NULL,
+	NULL,
+	NULL,
+};
+
+bus_space_tag_t fdtbus_bs_tag = &_base_tag;
diff -r 7fffa673adcd -r a301a330526b head/sys/arm/lpc/lpc_spi.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/head/sys/arm/lpc/lpc_spi.c	Wed Aug 15 11:16:36 2012 +0300
@@ -0,0 +1,195 @@
+/*-
+ * Copyright (c) 2011 Jakub Wojciech Klama <jceel at FreeBSD.org>
+ * 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.
+ *
+ */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: head/sys/arm/lpc/lpc_spi.c 239278 2012-08-15 05:37:10Z gonzo $");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/bio.h>
+#include <sys/bus.h>
+#include <sys/conf.h>
+#include <sys/endian.h>
+#include <sys/kernel.h>
+#include <sys/kthread.h>
+#include <sys/lock.h>
+#include <sys/malloc.h>
+#include <sys/module.h>
+#include <sys/mutex.h>
+#include <sys/queue.h>
+#include <sys/resource.h>
+#include <sys/rman.h>
+#include <sys/time.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 <dev/spibus/spi.h>
+#include <dev/spibus/spibusvar.h>
+
+#include <dev/ofw/ofw_bus.h>
+#include <dev/ofw/ofw_bus_subr.h>
+
+#include <arm/lpc/lpcreg.h>
+#include <arm/lpc/lpcvar.h>
+
+#include "spibus_if.h"
+
+struct lpc_spi_softc
+{
+	device_t		ls_dev;
+	struct resource *	ls_mem_res;
+	struct resource *	ls_irq_res;
+	bus_space_tag_t		ls_bst;
+	bus_space_handle_t	ls_bsh;
+};
+
+static int lpc_spi_probe(device_t);
+static int lpc_spi_attach(device_t);
+static int lpc_spi_detach(device_t);
+static int lpc_spi_transfer(device_t, device_t, struct spi_command *);
+
+#define	lpc_spi_read_4(_sc, _reg)		\
+    bus_space_read_4(_sc->ls_bst, _sc->ls_bsh, _reg)
+#define	lpc_spi_write_4(_sc, _reg, _val)	\
+    bus_space_write_4(_sc->ls_bst, _sc->ls_bsh, _reg, _val)
+
+static int
+lpc_spi_probe(device_t dev)
+{
+	if (!ofw_bus_is_compatible(dev, "lpc,spi"))
+		return (ENXIO);
+
+	device_set_desc(dev, "LPC32x0 PL022 SPI/SSP controller");
+	return (BUS_PROBE_DEFAULT);
+}
+
+static int
+lpc_spi_attach(device_t dev)
+{
+	struct lpc_spi_softc *sc = device_get_softc(dev);
+	int rid;
+
+	sc->ls_dev = dev;
+
+	rid = 0;
+	sc->ls_mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid,
+	    RF_ACTIVE);
+	if (!sc->ls_mem_res) {
+		device_printf(dev, "cannot allocate memory window\n");
+		return (ENXIO);
+	}
+
+	sc->ls_bst = rman_get_bustag(sc->ls_mem_res);
+	sc->ls_bsh = rman_get_bushandle(sc->ls_mem_res);
+
+	rid = 0;
+	sc->ls_irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid,
+	    RF_ACTIVE);
+	if (!sc->ls_irq_res) {
+		device_printf(dev, "cannot allocate interrupt\n");
+		return (ENXIO);
+	}
+
+	bus_space_write_4(sc->ls_bst, 0xd0028100, 0, (1<<12)|(1<<10)|(1<<9)|(1<<8)|(1<<6)|(1<<5)); 
+	lpc_pwr_write(dev, LPC_CLKPWR_SSP_CTRL, LPC_CLKPWR_SSP_CTRL_SSP0EN);
+	lpc_spi_write_4(sc, LPC_SSP_CR0, LPC_SSP_CR0_DSS(8));
+	lpc_spi_write_4(sc, LPC_SSP_CR1, LPC_SSP_CR1_SSE);
+	lpc_spi_write_4(sc, LPC_SSP_CPSR, 128);
+
+	device_add_child(dev, "spibus", 0);
+	return (bus_generic_attach(dev));
+}
+
+static int
+lpc_spi_detach(device_t dev)
+{
+	return (EBUSY);
+}
+
+static int
+lpc_spi_transfer(device_t dev, device_t child, struct spi_command *cmd)
+{
+	struct lpc_spi_softc *sc = device_get_softc(dev);
+	struct spibus_ivar *devi = SPIBUS_IVAR(child);
+	uint8_t *in_buf, *out_buf;
+	int i;
+
+	/* Set CS active */
+	lpc_gpio_set_state(child, devi->cs, 0);
+
+	/* Wait for FIFO to be ready */
+	while ((lpc_spi_read_4(sc, LPC_SSP_SR) & LPC_SSP_SR_TNF) == 0);
+
+	/* Command */
+	in_buf = cmd->rx_cmd;
+	out_buf = cmd->tx_cmd;
+	for (i = 0; i < cmd->tx_cmd_sz; i++) {
+		lpc_spi_write_4(sc, LPC_SSP_DR, out_buf[i]);
+		in_buf[i] = lpc_spi_read_4(sc, LPC_SSP_DR);
+	}
+
+	/* Data */
+	in_buf = cmd->rx_data;
+	out_buf = cmd->tx_data;
+	for (i = 0; i < cmd->tx_data_sz; i++) {
+		lpc_spi_write_4(sc, LPC_SSP_DR, out_buf[i]);
+		in_buf[i] = lpc_spi_read_4(sc, LPC_SSP_DR);
+	}
+
+	/* Set CS inactive */
+	lpc_gpio_set_state(child, devi->cs, 1);
+
+	return (0);
+}
+
+static device_method_t lpc_spi_methods[] = {
+	/* Device interface */
+	DEVMETHOD(device_probe,		lpc_spi_probe),
+	DEVMETHOD(device_attach,	lpc_spi_attach),
+	DEVMETHOD(device_detach,	lpc_spi_detach),
+
+	/* SPI interface */
+	DEVMETHOD(spibus_transfer,	lpc_spi_transfer),
+
+	{ 0, 0 }
+};
+
+static devclass_t lpc_spi_devclass;
+
+static driver_t lpc_spi_driver = {
+	"spi",
+	lpc_spi_methods,
+	sizeof(struct lpc_spi_softc),
+};
+
+DRIVER_MODULE(lpcspi, simplebus, lpc_spi_driver, lpc_spi_devclass, 0, 0);
diff -r 7fffa673adcd -r a301a330526b head/sys/arm/lpc/lpc_timer.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/head/sys/arm/lpc/lpc_timer.c	Wed Aug 15 11:16:36 2012 +0300
@@ -0,0 +1,320 @@
+/*-
+ * Copyright (c) 2011 Jakub Wojciech Klama <jceel at FreeBSD.org>
+ * 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.
+ *
+ */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: head/sys/arm/lpc/lpc_timer.c 239278 2012-08-15 05:37:10Z gonzo $");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/bus.h>
+#include <sys/kernel.h>
+#include <sys/module.h>
+#include <sys/malloc.h>
+#include <sys/rman.h>
+#include <sys/timetc.h>
+#include <sys/timeet.h>
+#include <machine/bus.h>
+#include <machine/cpu.h>
+#include <machine/frame.h>
+#include <machine/intr.h>
+
+#include <dev/fdt/fdt_common.h>
+#include <dev/ofw/ofw_bus.h>
+#include <dev/ofw/ofw_bus_subr.h>
+
+#include <arm/lpc/lpcreg.h>
+#include <arm/lpc/lpcvar.h>
+
+struct lpc_timer_softc {
+	device_t		lt_dev;
+	struct eventtimer	lt_et;
+	struct resource	*	lt_res[5];
+	bus_space_tag_t		lt_bst0;
+	bus_space_handle_t	lt_bsh0;
+	bus_space_tag_t		lt_bst1;
+	bus_space_handle_t	lt_bsh1;
+	int			lt_oneshot;
+	uint32_t		lt_period;
+};
+
+static struct resource_spec lpc_timer_spec[] = {
+	{ SYS_RES_MEMORY,	0,	RF_ACTIVE },
+	{ SYS_RES_MEMORY,	1,	RF_ACTIVE },
+	{ SYS_RES_IRQ,		0,	RF_ACTIVE },
+	{ SYS_RES_IRQ,		1,	RF_ACTIVE },
+	{ -1, 0 }
+};
+
+static struct lpc_timer_softc *timer_softc = NULL;
+static int lpc_timer_initialized = 0;
+static int lpc_timer_probe(device_t);
+static int lpc_timer_attach(device_t);
+static int lpc_timer_start(struct eventtimer *, struct bintime *first,
+    struct bintime *);
+static int lpc_timer_stop(struct eventtimer *et);
+static unsigned lpc_get_timecount(struct timecounter *);
+static int lpc_hardclock(void *);
+
+#define	timer0_read_4(sc, reg)			\
+    bus_space_read_4(sc->lt_bst0, sc->lt_bsh0, reg)
+#define	timer0_write_4(sc, reg, val)		\
+    bus_space_write_4(sc->lt_bst0, sc->lt_bsh0, reg, val)
+#define	timer0_clear(sc)			\
+    do {					\
+	    timer0_write_4(sc, LPC_TIMER_TC, 0);	\
+	    timer0_write_4(sc, LPC_TIMER_PR, 0);	\
+	    timer0_write_4(sc, LPC_TIMER_PC, 0);	\
+    } while(0)
+
+#define	timer1_read_4(sc, reg)			\
+    bus_space_read_4(sc->lt_bst1, sc->lt_bsh1, reg)
+#define	timer1_write_4(sc, reg, val)		\
+    bus_space_write_4(sc->lt_bst1, sc->lt_bsh1, reg, val)
+#define	timer1_clear(sc)			\
+    do {					\
+	    timer1_write_4(sc, LPC_TIMER_TC, 0);	\
+	    timer1_write_4(sc, LPC_TIMER_PR, 0);	\
+	    timer1_write_4(sc, LPC_TIMER_PC, 0);	\
+    } while(0)
+
+static struct timecounter lpc_timecounter = {
+	.tc_get_timecount = lpc_get_timecount,
+	.tc_name = "LPC32x0 Timer1",
+	.tc_frequency = 0, /* will be filled later */
+	.tc_counter_mask = ~0u,
+	.tc_quality = 1000,
+};
+
+static int
+lpc_timer_probe(device_t dev)
+{
+
+	if (!ofw_bus_is_compatible(dev, "lpc,timer"))
+		return (ENXIO);
+
+	device_set_desc(dev, "LPC32x0 timer");
+	return (BUS_PROBE_DEFAULT);
+}
+
+static int
+lpc_timer_attach(device_t dev)
+{
+	void *intrcookie;
+	struct lpc_timer_softc *sc = device_get_softc(dev);
+	phandle_t node;
+	uint32_t freq;
+
+	if (timer_softc)
+		return (ENXIO);
+
+	timer_softc = sc;
+
+	if (bus_alloc_resources(dev, lpc_timer_spec, sc->lt_res)) {
+		device_printf(dev, "could not allocate resources\n");
+		return (ENXIO);
+	}
+
+	sc->lt_bst0 = rman_get_bustag(sc->lt_res[0]);
+	sc->lt_bsh0 = rman_get_bushandle(sc->lt_res[0]);
+	sc->lt_bst1 = rman_get_bustag(sc->lt_res[1]);
+	sc->lt_bsh1 = rman_get_bushandle(sc->lt_res[1]);
+
+	if (bus_setup_intr(dev, sc->lt_res[2], INTR_TYPE_CLK,
+	    lpc_hardclock, NULL, sc, &intrcookie)) {
+		device_printf(dev, "could not setup interrupt handler\n");
+		bus_release_resources(dev, lpc_timer_spec, sc->lt_res);
+		return (ENXIO);
+	}
+
+	/* Enable timer clock */
+	lpc_pwr_write(dev, LPC_CLKPWR_TIMCLK_CTRL1,
+	    LPC_CLKPWR_TIMCLK_CTRL1_TIMER0 |
+	    LPC_CLKPWR_TIMCLK_CTRL1_TIMER1);
+
+	/* Get PERIPH_CLK encoded in parent bus 'bus-frequency' property */
+	node = ofw_bus_get_node(dev);
+	if (OF_getprop(OF_parent(node), "bus-frequency", &freq,
+	    sizeof(pcell_t)) <= 0) {
+		bus_release_resources(dev, lpc_timer_spec, sc->lt_res);
+		bus_teardown_intr(dev, sc->lt_res[2], intrcookie);
+		device_printf(dev, "could not obtain base clock frequency\n");
+		return (ENXIO);
+	}
+
+	freq = fdt32_to_cpu(freq);
+
+	/* Set desired frequency in event timer and timecounter */
+	sc->lt_et.et_frequency = (uint64_t)freq;
+	lpc_timecounter.tc_frequency = (uint64_t)freq;	
+
+	sc->lt_et.et_name = "LPC32x0 Timer0";
+	sc->lt_et.et_flags = ET_FLAGS_PERIODIC | ET_FLAGS_ONESHOT;
+	sc->lt_et.et_quality = 1000;
+	sc->lt_et.et_min_period.sec = 0;
+	sc->lt_et.et_min_period.frac =
+	    ((0x00000002LLU << 32) / sc->lt_et.et_frequency) << 32;
+	sc->lt_et.et_max_period.sec = 0xfffffff0U / sc->lt_et.et_frequency;
+	sc->lt_et.et_max_period.frac =
+	    ((0xfffffffeLLU << 32) / sc->lt_et.et_frequency) << 32;
+	sc->lt_et.et_start = lpc_timer_start;
+	sc->lt_et.et_stop = lpc_timer_stop;
+	sc->lt_et.et_priv = sc;
+
+	et_register(&sc->lt_et);
+	tc_init(&lpc_timecounter);
+
+	/* Reset and enable timecounter */
+	timer1_write_4(sc, LPC_TIMER_TCR, LPC_TIMER_TCR_RESET);
+	timer1_write_4(sc, LPC_TIMER_TCR, 0);
+	timer1_clear(sc);
+	timer1_write_4(sc, LPC_TIMER_TCR, LPC_TIMER_TCR_ENABLE);
+
+	/* DELAY() now can work properly */
+	lpc_timer_initialized = 1;
+
+	return (0);
+}
+
+static int
+lpc_timer_start(struct eventtimer *et, struct bintime *first,
+    struct bintime *period)
+{
+	struct lpc_timer_softc *sc = (struct lpc_timer_softc *)et->et_priv;
+	uint32_t ticks;
+
+	if (period == NULL)
+		sc->lt_oneshot = 1;
+	else {
+		sc->lt_oneshot = 0;
+		sc->lt_period = (sc->lt_et.et_frequency * (first->frac >> 32)) >> 32;
+			sc->lt_period += sc->lt_et.et_frequency * first->sec;
+	}
+
+	if (first == NULL)
+		ticks = sc->lt_period;
+	else {
+		ticks = (sc->lt_et.et_frequency * (first->frac >> 32)) >> 32;
+		if (first->sec != 0)
+			ticks += sc->lt_et.et_frequency * first->sec;
+	}
+
+	/* Reset timer */
+	timer0_write_4(sc, LPC_TIMER_TCR, LPC_TIMER_TCR_RESET);
+	timer0_write_4(sc, LPC_TIMER_TCR, 0);
+	
+	/* Start timer */
+	timer0_clear(sc);
+	timer0_write_4(sc, LPC_TIMER_MR0, ticks);
+	timer0_write_4(sc, LPC_TIMER_MCR, LPC_TIMER_MCR_MR0I | LPC_TIMER_MCR_MR0S);
+	timer0_write_4(sc, LPC_TIMER_TCR, LPC_TIMER_TCR_ENABLE);
+	return (0);
+}
+
+static int
+lpc_timer_stop(struct eventtimer *et)
+{
+	struct lpc_timer_softc *sc = (struct lpc_timer_softc *)et->et_priv;
+
+	timer0_write_4(sc, LPC_TIMER_TCR, 0);
+	return (0);
+}
+
+static device_method_t lpc_timer_methods[] = {
+	DEVMETHOD(device_probe,		lpc_timer_probe),
+	DEVMETHOD(device_attach,	lpc_timer_attach),
+	{ 0, 0 }
+};
+
+static driver_t lpc_timer_driver = {
+	"timer",
+	lpc_timer_methods,
+	sizeof(struct lpc_timer_softc),
+};
+
+static devclass_t lpc_timer_devclass;
+
+DRIVER_MODULE(timer, simplebus, lpc_timer_driver, lpc_timer_devclass, 0, 0);
+
+static int
+lpc_hardclock(void *arg)
+{
+	struct lpc_timer_softc *sc = (struct lpc_timer_softc *)arg;
+
+	/* Reset pending interrupt */
+	timer0_write_4(sc, LPC_TIMER_IR, 0xffffffff);
+
+	/* Start timer again */
+	if (!sc->lt_oneshot) {
+		timer0_clear(sc);
+		timer0_write_4(sc, LPC_TIMER_MR0, sc->lt_period);
+		timer0_write_4(sc, LPC_TIMER_TCR, LPC_TIMER_TCR_ENABLE);
+	}
+
+	if (sc->lt_et.et_active)
+		sc->lt_et.et_event_cb(&sc->lt_et, sc->lt_et.et_arg);
+
+	return (FILTER_HANDLED);
+}
+
+static unsigned
+lpc_get_timecount(struct timecounter *tc)
+{
+	return timer1_read_4(timer_softc, LPC_TIMER_TC);
+}
+
+void
+cpu_initclocks(void)
+{
+	cpu_initclocks_bsp();
+}
+
+void
+DELAY(int usec)
+{
+	uint32_t counter;
+	uint32_t first, last;
+	int val = (lpc_timecounter.tc_frequency / 1000000 + 1) * usec;
+
+	/* Timer is not initialized yet */
+	if (!lpc_timer_initialized) {
+		for (; usec > 0; usec--)
+			for (counter = 100; counter > 0; counter--)
+				;
+		return;
+	}
+
+	first = lpc_get_timecount(&lpc_timecounter);
+	while (val > 0) {
+		last = lpc_get_timecount(&lpc_timecounter);
+		if (last < first) {
+			/* Timer rolled over */
+			last = first;
+		}
+		
+		val -= (last - first);
+		first = last;
+	}
+}
diff -r 7fffa673adcd -r a301a330526b head/sys/arm/lpc/lpcreg.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/head/sys/arm/lpc/lpcreg.h	Wed Aug 15 11:16:36 2012 +0300
@@ -0,0 +1,661 @@
+/*-
+ * Copyright (c) 2011 Jakub Wojciech Klama <jceel at FreeBSD.org>
+ * 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: head/sys/arm/lpc/lpcreg.h 239278 2012-08-15 05:37:10Z gonzo $
+ */
+
+#ifndef	_ARM_LPC_LPCREG_H
+#define	_ARM_LPC_LPCREG_H
+
+#define	LPC_DEV_PHYS_BASE		0x40000000
+#define	LPC_DEV_P5_PHYS_BASE		0x20000000
+#define	LPC_DEV_P6_PHYS_BASE		0x30000000
+#define	LPC_DEV_BASE			0xd0000000
+#define	LPC_DEV_SIZE			0x10000000
+
+/*
+ * Interrupt controller (from UM10326: LPC32x0 User manual, page 87)
+
+ */
+#define	LPC_INTC_MIC_ER			0x0000
+#define	LPC_INTC_MIC_RSR		0x0004
+#define	LPC_INTC_MIC_SR			0x0008
+#define	LPC_INTC_MIC_APR		0x000c
+#define	LPC_INTC_MIC_ATR		0x0010
+#define	LPC_INTC_MIC_ITR		0x0014
+#define	LPC_INTC_SIC1_ER		0x4000
+#define	LPC_INTC_SIC1_RSR		0x4004
+#define	LPC_INTC_SIC1_SR		0x4008
+#define	LPC_INTC_SIC1_APR		0x400c
+#define	LPC_INTC_SIC1_ATR		0x4010
+#define	LPC_INTC_SIC1_ITR		0x4014
+#define	LPC_INTC_SIC2_ER		0x8000
+#define	LPC_INTC_SIC2_RSR		0x8004
+#define	LPC_INTC_SIC2_SR		0x8008
+#define	LPC_INTC_SIC2_APR		0x800c
+#define	LPC_INTC_SIC2_ATR		0x8010
+#define	LPC_INTC_SIC2_ITR		0x8014
+
+
+/*
+ * Timer 0|1|2|3|4|5. (from UM10326: LPC32x0 User manual, page 540)
+ */
+#define	LPC_TIMER_IR			0x00
+#define	LPC_TIMER_TCR			0x04
+#define	LPC_TIMER_TCR_ENABLE		(1 << 0)
+#define	LPC_TIMER_TCR_RESET		(1 << 1)
+#define	LPC_TIMER_TC			0x08
+#define	LPC_TIMER_PR			0x0c
+#define	LPC_TIMER_PC			0x10
+#define	LPC_TIMER_MCR			0x14
+#define	LPC_TIMER_MCR_MR0I		(1 << 0)
+#define	LPC_TIMER_MCR_MR0R		(1 << 1)
+#define	LPC_TIMER_MCR_MR0S		(1 << 2)
+#define	LPC_TIMER_MCR_MR1I		(1 << 3)
+#define	LPC_TIMER_MCR_MR1R		(1 << 4)
+#define	LPC_TIMER_MCR_MR1S		(1 << 5)
+#define	LPC_TIMER_MCR_MR2I		(1 << 6)
+#define	LPC_TIMER_MCR_MR2R		(1 << 7)
+#define	LPC_TIMER_MCR_MR2S		(1 << 8)
+#define	LPC_TIMER_MCR_MR3I		(1 << 9)
+#define	LPC_TIMER_MCR_MR3R		(1 << 10)
+#define	LPC_TIMER_MCR_MR3S		(1 << 11)
+#define	LPC_TIMER_MR0			0x18
+#define	LPC_TIMER_CTCR			0x70
+
+/*
+ * Watchdog timer. (from UM10326: LPC32x0 User manual, page 572)
+ */
+#define	LPC_WDTIM_BASE			(LPC_DEV_BASE + 0x3c000)
+#define	LPC_WDTIM_INT			0x00
+#define	LPC_WDTIM_CTRL			0x04
+#define	LPC_WDTIM_COUNTER		0x08
+#define	LPC_WDTIM_MCTRL			0x0c
+#define	LPC_WDTIM_MATCH0		0x10
+#define	LPC_WDTIM_EMR			0x14
+#define	LPC_WDTIM_PULSE			0x18
+#define	LPC_WDTIM_RES			0x1c
+
+/*
+ * Clocking and power control. (from UM10326: LPC32x0 User manual, page 58)
+ */
+#define	LPC_CLKPWR_BASE			(LPC_DEV_BASE + 0x4000)
+#define	LPC_CLKPWR_PWR_CTRL		0x44
+#define	LPC_CLKPWR_OSC_CTRL		0x4c
+#define	LPC_CLKPWR_SYSCLK_CTRL		0x50
+#define	LPC_CLKPWR_PLL397_CTRL		0x48
+#define	LPC_CLKPWR_HCLKPLL_CTRL		0x58
+#define	LPC_CLKPWR_HCLKDIV_CTRL		0x40
+#define	LPC_CLKPWR_TEST_CTRL		0xa4
+#define	LPC_CLKPWR_AUTOCLK_CTRL		0xec
+#define	LPC_CLKPWR_START_ER_PIN		0x30
+#define	LPC_CLKPWR_START_ER_INT		0x20
+#define	LPC_CLKPWR_P0_INTR_ER		0x18
+#define	LPC_CLKPWR_START_SR_PIN		0x38
+#define	LPC_CLKPWR_START_SR_INT		0x28
+#define	LPC_CLKPWR_START_RSR_PIN	0x34
+#define	LPC_CLKPWR_START_RSR_INT	0x24
+#define	LPC_CLKPWR_START_APR_PIN	0x3c
+#define	LPC_CLKPWR_START_APR_INT	0x2c
+#define	LPC_CLKPWR_USB_CTRL		0x64
+#define	LPC_CLKPWR_USB_CTRL_SLAVE_HCLK	(1 << 24)
+#define	LPC_CLKPWR_USB_CTRL_I2C_EN	(1 << 23)
+#define	LPC_CLKPWR_USB_CTRL_DEV_NEED_CLK_EN	(1 << 22)
+#define	LPC_CLKPWR_USB_CTRL_HOST_NEED_CLK_EN	(1 << 21)
+#define	LPC_CLKPWR_USB_CTRL_BUSKEEPER	(1 << 19)
+#define	LPC_CLKPWR_USB_CTRL_CLK_EN2	(1 << 18)
+#define	LPC_CLKPWR_USB_CTRL_CLK_EN1	(1 << 17)
+#define	LPC_CLKPWR_USB_CTRL_PLL_PDOWN	(1 << 16)
+#define	LPC_CLKPWR_USB_CTRL_BYPASS	(1 << 15)
+#define	LPC_CLKPWR_USB_CTRL_DIRECT_OUT	(1 << 14)
+#define	LPC_CLKPWR_USB_CTRL_FEEDBACK	(1 << 13)
+#define	LPC_CLKPWR_USB_CTRL_POSTDIV(_x)	((_x & 0x3) << 11)
+#define	LPC_CLKPWR_USB_CTRL_PREDIV(_x)	((_x & 0x3) << 9)
+#define	LPC_CLKPWR_USB_CTRL_FDBKDIV(_x)	(((_x-1) & 0xff) << 1)
+#define	LPC_CLKPWR_USB_CTRL_PLL_LOCK	(1 << 0)
+#define	LPC_CLKPWR_USBDIV_CTRL		0x1c
+#define	LPC_CLKPWR_MS_CTRL		0x80
+#define	LPC_CLKPWR_MS_CTRL_DISABLE_SD	(1 << 10)
+#define	LPC_CLKPWR_MS_CTRL_CLOCK_EN	(1 << 9)
+#define	LPC_CLKPWR_MS_CTRL_MSSDIO23_PAD	(1 << 8)
+#define	LPC_CLKPWR_MS_CTRL_MSSDIO1_PAD	(1 << 7)
+#define	LPC_CLKPWR_MS_CTRL_MSSDIO0_PAD	(1 << 6)
+#define	LPC_CLKPWR_MS_CTRL_SD_CLOCK	(1 << 5)
+#define	LPC_CLKPWR_MS_CTRL_CLKDIV_MASK	0xf
+#define	LPC_CLKPWR_DMACLK_CTRL		0xe8
+#define	LPC_CLKPWR_DMACLK_CTRL_EN	(1 << 0)
+#define	LPC_CLKPWR_FLASHCLK_CTRL	0xc8
+#define	LPC_CLKPWR_MACCLK_CTRL		0x90
+#define	LPC_CLKPWR_MACCLK_CTRL_REG	(1 << 0)
+#define	LPC_CLKPWR_MACCLK_CTRL_SLAVE	(1 << 1)
+#define	LPC_CLKPWR_MACCLK_CTRL_MASTER	(1 << 2)
+#define	LPC_CLKPWR_MACCLK_CTRL_HDWINF(_n) ((_n & 0x3) << 3)
+#define	LPC_CLKPWR_LCDCLK_CTRL		0x54
+#define	LPC_CLKPWR_LCDCLK_CTRL_DISPTYPE	(1 << 8)
+#define	LPC_CLKPWR_LCDCLK_CTRL_MODE(_n)	((_n & 0x3) << 6)
+#define	LPC_CLKPWR_LCDCLK_CTRL_MODE_12	0x0
+#define	LPC_CLKPWR_LCDCLK_CTRL_MODE_15	0x1
+#define	LPC_CLKPWR_LCDCLK_CTRL_MODE_16	0x2
+#define	LPC_CLKPWR_LCDCLK_CTRL_MODE_24	0x3
+#define	LPC_CLKPWR_LCDCLK_CTRL_HCLKEN	(1 << 5)
+#define	LPC_CLKPWR_LCDCLK_CTRL_CLKDIV(_n) ((_n) & 0x1f)
+#define	LPC_CLKPWR_I2S_CTRL		0x7c
+#define	LPC_CLKPWR_SSP_CTRL		0x78
+#define	LPC_CLKPWR_SSP_CTRL_SSP1RXDMA	(1 << 5)
+#define	LPC_CLKPWR_SSP_CTRL_SSP1TXDMA	(1 << 4)
+#define	LPC_CLKPWR_SSP_CTRL_SSP0RXDMA	(1 << 3)
+#define	LPC_CLKPWR_SSP_CTRL_SSP0TXDMA	(1 << 2)
+#define	LPC_CLKPWR_SSP_CTRL_SSP1EN	(1 << 1)
+#define	LPC_CLKPWR_SSP_CTRL_SSP0EN	(1 << 0)
+#define	LPC_CLKPWR_SPI_CTRL		0xc4
+#define	LPC_CLKPWR_I2CCLK_CTRL		0xac
+#define	LPC_CLKPWR_TIMCLK_CTRL1		0xc0
+#define	LPC_CLKPWR_TIMCLK_CTRL1_TIMER4	(1 << 0)
+#define	LPC_CLKPWR_TIMCLK_CTRL1_TIMER5	(1 << 1)
+#define	LPC_CLKPWR_TIMCLK_CTRL1_TIMER0	(1 << 2)
+#define	LPC_CLKPWR_TIMCLK_CTRL1_TIMER1	(1 << 3)
+#define	LPC_CLKPWR_TIMCLK_CTRL1_TIMER2	(1 << 4)
+#define	LPC_CLKPWR_TIMCLK_CTRL1_TIMER3	(1 << 5)
+#define	LPC_CLKPWR_TIMCLK_CTRL1_MOTORCTL	(1 << 6)
+#define	LPC_CLKPWR_TIMCLK_CTRL		0xbc
+#define	LPC_CLKPWR_TIMCLK_CTRL_WATCHDOG	(1 << 0)
+#define	LPC_CLKPWR_TIMCLK_CTRL_HSTIMER	(1 << 1)
+#define	LPC_CLKPWR_ADCLK_CTRL		0xb4
+#define	LPC_CLKPWR_ADCLK_CTRL1		0x60
+#define	LPC_CLKPWR_KEYCLK_CTRL		0xb0
+#define	LPC_CLKPWR_PWMCLK_CTRL		0xb8
+#define	LPC_CLKPWR_UARTCLK_CTRL		0xe4
+#define	LPC_CLKPWR_POS0_IRAM_CTRL	0x110
+#define	LPC_CLKPWR_POS1_IRAM_CTRL	0x114
+
+/* Additional UART registers in CLKPWR address space. */
+#define	LPC_CLKPWR_UART_U3CLK		0xd0
+#define	LPC_CLKPWR_UART_U4CLK		0xd4
+#define	LPC_CLKPWR_UART_U5CLK		0xd8
+#define	LPC_CLKPWR_UART_U6CLK		0xdc
+#define	LPC_CLKPWR_UART_UCLK_HCLK	(1 << 16)
+#define	LPC_CLKPWR_UART_UCLK_X(_n)	(((_n) & 0xff) << 8)
+#define	LPC_CLKPWR_UART_UCLK_Y(_n)	((_n) & 0xff)
+#define	LPC_CLKPWR_UART_IRDACLK		0xe0
+
+/* Additional UART registers */
+#define	LPC_UART_BASE			(LPC_DEV_BASE + 0x80000)
+#define	LPC_UART_CONTROL_BASE		(LPC_DEV_BASE + 0x54000)
+#define	LPC_UART5_BASE			(LPC_DEV_BASE + 0x90000)
+#define	LPC_UART_CTRL			0x00
+#define	LPC_UART_CLKMODE		0x04
+#define	LPC_UART_CLKMODE_UART3(_n)	(((_n) & 0x3) << 4)
+#define	LPC_UART_CLKMODE_UART4(_n)	(((_n) & 0x3) << 6)
+#define	LPC_UART_CLKMODE_UART5(_n)	(((_n) & 0x3) << 8)
+#define	LPC_UART_CLKMODE_UART6(_n)	(((_n) & 0x3) << 10)
+#define	LPC_UART_LOOP			0x08
+#define	LPC_UART_FIFOSIZE		64
+
+/*
+ * Real time clock. (from UM10326: LPC32x0 User manual, page 566)
+ */
+#define	LPC_RTC_UCOUNT			0x00
+#define	LPC_RTC_DCOUNT			0x04
+#define	LPC_RTC_MATCH0			0x08
+#define	LPC_RTC_MATCH1			0x0c
+#define	LPC_RTC_CTRL			0x10
+#define	LPC_RTC_CTRL_ONSW		(1 << 7)
+#define	LPC_RTC_CTRL_DISABLE		(1 << 6)
+#define	LPC_RTC_CTRL_RTCRESET		(1 << 4)
+#define	LPC_RTC_CTRL_MATCH0ONSW		(1 << 3)
+#define	LPC_RTC_CTRL_MATCH1ONSW		(1 << 2)
+#define	LPC_RTC_CTRL_MATCH1INTR		(1 << 1)
+#define	LPC_RTC_CTRL_MATCH0INTR		(1 << 0)
+#define	LPC_RTC_INTSTAT			0x14
+#define	LPC_RTC_KEY			0x18
+#define	LPC_RTC_SRAM_BEGIN		0x80
+#define LPC_RTC_SRAM_END		0xff
+
+/*
+ * MMC/SD controller. (from UM10326: LPC32x0 User manual, page 436)
+ */
+#define	LPC_SD_BASE			(LPC_DEV_P5_PHYS_BASE + 0x98000)
+#define	LPC_SD_CLK			(13 * 1000 * 1000)	// 13Mhz
+#define	LPC_SD_POWER			0x00
+#define	LPC_SD_POWER_OPENDRAIN		(1 << 6)
+#define	LPC_SD_POWER_CTRL_OFF		0x00
+#define	LPC_SD_POWER_CTRL_UP		0x02
+#define	LPC_SD_POWER_CTRL_ON		0x03
+#define	LPC_SD_CLOCK			0x04
+#define	LPC_SD_CLOCK_WIDEBUS		(1 << 11)
+#define	LPC_SD_CLOCK_BYPASS		(1 << 10)
+#define	LPC_SD_CLOCK_PWRSAVE		(1 << 9)
+#define	LPC_SD_CLOCK_ENABLE		(1 << 8)
+#define	LPC_SD_CLOCK_CLKDIVMASK		0xff
+#define	LPC_SD_ARGUMENT			0x08
+#define	LPC_SD_COMMAND			0x0c
+#define	LPC_SD_COMMAND_ENABLE		(1 << 10)
+#define	LPC_SD_COMMAND_PENDING		(1 << 9)
+#define	LPC_SD_COMMAND_INTERRUPT	(1 << 8)
+#define	LPC_SD_COMMAND_LONGRSP		(1 << 7)
+#define	LPC_SD_COMMAND_RESPONSE		(1 << 6)
+#define	LPC_SD_COMMAND_CMDINDEXMASK	0x3f
+#define	LPC_SD_RESPCMD			0x10
+#define	LPC_SD_RESP0			0x14
+#define	LPC_SD_RESP1			0x18
+#define	LPC_SD_RESP2			0x1c
+#define	LPC_SD_RESP3			0x20
+#define	LPC_SD_DATATIMER		0x24
+#define	LPC_SD_DATALENGTH		0x28
+#define	LPC_SD_DATACTRL			0x2c
+#define	LPC_SD_DATACTRL_BLOCKSIZESHIFT	4
+#define	LPC_SD_DATACTRL_BLOCKSIZEMASK	0xf
+#define	LPC_SD_DATACTRL_DMAENABLE	(1 << 3)
+#define	LPC_SD_DATACTRL_MODE		(1 << 2)
+#define	LPC_SD_DATACTRL_WRITE		(0 << 1)
+#define	LPC_SD_DATACTRL_READ		(1 << 1)
+#define	LPC_SD_DATACTRL_ENABLE		(1 << 0)
+#define	LPC_SD_DATACNT			0x30
+#define	LPC_SD_STATUS			0x34
+#define	LPC_SD_STATUS_RXDATAAVLBL	(1 << 21)
+#define	LPC_SD_STATUS_TXDATAAVLBL	(1 << 20)
+#define	LPC_SD_STATUS_RXFIFOEMPTY	(1 << 19)
+#define	LPC_SD_STATUS_TXFIFOEMPTY	(1 << 18)
+#define	LPC_SD_STATUS_RXFIFOFULL	(1 << 17)
+#define	LPC_SD_STATUS_TXFIFOFULL	(1 << 16)
+#define	LPC_SD_STATUS_RXFIFOHALFFULL	(1 << 15)
+#define	LPC_SD_STATUS_TXFIFOHALFEMPTY	(1 << 14)
+#define	LPC_SD_STATUS_RXACTIVE		(1 << 13)
+#define	LPC_SD_STATUS_TXACTIVE		(1 << 12)
+#define	LPC_SD_STATUS_CMDACTIVE		(1 << 11)
+#define	LPC_SD_STATUS_DATABLOCKEND	(1 << 10)
+#define	LPC_SD_STATUS_STARTBITERR	(1 << 9)
+#define	LPC_SD_STATUS_DATAEND		(1 << 8)
+#define	LPC_SD_STATUS_CMDSENT		(1 << 7)
+#define	LPC_SD_STATUS_CMDRESPEND	(1 << 6)
+#define	LPC_SD_STATUS_RXOVERRUN		(1 << 5)
+#define	LPC_SD_STATUS_TXUNDERRUN	(1 << 4)
+#define	LPC_SD_STATUS_DATATIMEOUT	(1 << 3)
+#define	LPC_SD_STATUS_CMDTIMEOUT	(1 << 2)
+#define	LPC_SD_STATUS_DATACRCFAIL	(1 << 1)
+#define	LPC_SD_STATUS_CMDCRCFAIL	(1 << 0)
+#define	LPC_SD_CLEAR			0x38
+#define	LPC_SD_MASK0			0x03c
+#define	LPC_SD_MASK1			0x40
+#define	LPC_SD_FIFOCNT			0x48
+#define	LPC_SD_FIFO			0x80
+
+/*
+ * USB OTG controller (from UM10326: LPC32x0 User manual, page 410)
+ */
+#define	LPC_OTG_INT_STATUS		0x100
+#define	LPC_OTG_INT_ENABLE		0x104
+#define	LPC_OTG_INT_SET			0x108
+#define	LPC_OTG_INT_CLEAR		0x10c
+#define	LPC_OTG_STATUS			0x110
+#define	LPC_OTG_STATUS_ATOB_HNP_TRACK	(1 << 9)
+#define	LPC_OTG_STATUS_BTOA_HNP_TACK	(1 << 8)
+#define	LPC_OTG_STATUS_TRANSP_I2C_EN	(1 << 7)
+#define	LPC_OTG_STATUS_TIMER_RESET	(1 << 6)
+#define	LPC_OTG_STATUS_TIMER_EN		(1 << 5)
+#define	LPC_OTG_STATUS_TIMER_MODE	(1 << 4)
+#define	LPC_OTG_STATUS_TIMER_SCALE	(1 << 2)
+#define	LPC_OTG_STATUS_HOST_EN		(1 << 0)
+#define	LPC_OTG_TIMER			0x114
+#define	LPC_OTG_I2C_TXRX		0x300
+#define	LPC_OTG_I2C_STATUS		0x304
+#define	LPC_OTG_I2C_STATUS_TFE		(1 << 11)
+#define	LPC_OTG_I2C_STATUS_TFF		(1 << 10)
+#define	LPC_OTG_I2C_STATUS_RFE		(1 << 9)
+#define	LPC_OTG_I2C_STATUS_RFF		(1 << 8)
+#define	LPC_OTG_I2C_STATUS_SDA		(1 << 7)
+#define	LPC_OTG_I2C_STATUS_SCL		(1 << 6)
+#define	LPC_OTG_I2C_STATUS_ACTIVE	(1 << 5)
+#define	LPC_OTG_I2C_STATUS_DRSI		(1 << 4)
+#define	LPC_OTG_I2C_STATUS_DRMI		(1 << 3)
+#define	LPC_OTG_I2C_STATUS_NAI		(1 << 2)
+#define	LPC_OTG_I2C_STATUS_AFI		(1 << 1)
+#define	LPC_OTG_I2C_STATUS_TDI		(1 << 0)
+#define	LPC_OTG_I2C_CTRL		0x308
+#define	LPC_OTG_I2C_CTRL_SRST		(1 << 8)
+#define	LPC_OTG_I2C_CTRL_TFFIE		(1 << 7)
+#define	LPC_OTG_I2C_CTRL_RFDAIE		(1 << 6)
+#define	LPC_OTG_I2C_CTRL_RFFIE		(1 << 5)
+#define	LPC_OTG_I2C_CTRL_DRSIE		(1 << 4)
+#define	LPC_OTG_I2C_CTRL_DRMIE		(1 << 3)
+#define	LPC_OTG_I2C_CTRL_NAIE		(1 << 2)
+#define	LPC_OTG_I2C_CTRL_AFIE		(1 << 1)
+#define	LPC_OTG_I2C_CTRL_TDIE		(1 << 0)
+#define	LPC_OTG_I2C_CLKHI		0x30c
+#define	LPC_OTG_I2C_CLKLO		0x310
+#define	LPC_OTG_CLOCK_CTRL		0xff4
+#define	LPC_OTG_CLOCK_CTRL_AHB_EN	(1 << 4)
+#define	LPC_OTG_CLOCK_CTRL_OTG_EN	(1 << 3)
+#define	LPC_OTG_CLOCK_CTRL_I2C_EN	(1 << 2)
+#define	LPC_OTG_CLOCK_CTRL_DEV_EN	(1 << 1)
+#define	LPC_OTG_CLOCK_CTRL_HOST_EN	(1 << 0)
+#define	LPC_OTG_CLOCK_STATUS		0xff8
+
+/*
+ * ISP3101 USB transceiver registers
+ */
+#define	LPC_ISP3101_I2C_ADDR		0x2d
+#define	LPC_ISP3101_MODE_CONTROL_1	0x04
+#define	LPC_ISP3101_MC1_SPEED_REG	(1 << 0)
+#define	LPC_ISP3101_MC1_SUSPEND_REG	(1 << 1)
+#define	LPC_ISP3101_MC1_DAT_SE0		(1 << 2)
+#define	LPC_ISP3101_MC1_TRANSPARENT	(1 << 3)
+#define	LPC_ISP3101_MC1_BDIS_ACON_EN	(1 << 4)
+#define	LPC_ISP3101_MC1_OE_INT_EN	(1 << 5)
+#define	LPC_ISP3101_MC1_UART_EN		(1 << 6)
+#define	LPC_ISP3101_MODE_CONTROL_2	0x12
+#define	LPC_ISP3101_MC2_GLOBAL_PWR_DN	(1 << 0)
+#define	LPC_ISP3101_MC2_SPD_SUSP_CTRL	(1 << 1)
+#define	LPC_ISP3101_MC2_BI_DI		(1 << 2)
+#define	LPC_ISP3101_MC2_TRANSP_BDIR0	(1 << 3)
+#define	LPC_ISP3101_MC2_TRANSP_BDIR1	(1 << 4)
+#define	LPC_ISP3101_MC2_AUDIO_EN	(1 << 5)
+#define	LPC_ISP3101_MC2_PSW_EN		(1 << 6)
+#define	LPC_ISP3101_MC2_EN2V7		(1 << 7)
+#define	LPC_ISP3101_OTG_CONTROL_1	0x06
+#define	LPC_ISP3101_OTG1_DP_PULLUP	(1 << 0)
+#define	LPC_ISP3101_OTG1_DM_PULLUP	(1 << 1)
+#define	LPC_ISP3101_OTG1_DP_PULLDOWN	(1 << 2)
+#define	LPC_ISP3101_OTG1_DM_PULLDOWN	(1 << 3)
+#define	LPC_ISP3101_OTG1_ID_PULLDOWN	(1 << 4)
+#define	LPC_ISP3101_OTG1_VBUS_DRV	(1 << 5)
+#define	LPC_ISP3101_OTG1_VBUS_DISCHRG	(1 << 6)
+#define	LPC_ISP3101_OTG1_VBUS_CHRG	(1 << 7)
+#define	LPC_ISP3101_OTG_CONTROL_2	0x10
+#define	LPC_ISP3101_OTG_INTR_LATCH	0x0a
+#define	LPC_ISP3101_OTG_INTR_FALLING	0x0c
+#define	LPC_ISP3101_OTG_INTR_RISING	0x0e
+#define	LPC_ISP3101_REG_CLEAR_ADDR	0x01
+
+/*
+ * LCD Controller (from UM10326: LPC32x0 User manual, page 229)
+ */
+#define	LPC_LCD_TIMH			0x00
+#define	LPC_LCD_TIMH_HBP(_n)		(((_n) & 0xff) << 24)
+#define	LPC_LCD_TIMH_HFP(_n)		(((_n) & 0xff) << 16)
+#define	LPC_LCD_TIMH_HSW(_n)		(((_n) & 0xff) << 8)
+#define	LPC_LCD_TIMH_PPL(_n)		(((_n) / 16 - 1) << 2)
+#define	LPC_LCD_TIMV			0x04
+#define	LPC_LCD_TIMV_VBP(_n)		(((_n) & 0xff) << 24)
+#define	LPC_LCD_TIMV_VFP(_n)		(((_n) & 0xff) << 16)
+#define	LPC_LCD_TIMV_VSW(_n)		(((_n) & 0x3f) << 10)
+#define	LPC_LCD_TIMV_LPP(_n)		((_n) & 0x1ff)
+#define	LPC_LCD_POL			0x08
+#define	LPC_LCD_POL_PCD_HI		(((_n) & 0x1f) << 27)
+#define	LPC_LCD_POL_BCD			(1 << 26)
+#define	LPC_LCD_POL_CPL(_n)		(((_n) & 0x3ff) << 16)
+#define	LPC_LCD_POL_IOE			(1 << 14)
+#define	LPC_LCD_POL_IPC			(1 << 13)
+#define	LPC_LCD_POL_IHS			(1 << 12)
+#define	LPC_LCD_POL_IVS			(1 << 11)
+#define	LPC_LCD_POL_ACB(_n)		((_n & 0x1f) << 6)
+#define	LPC_LCD_POL_CLKSEL		(1 << 5)
+#define	LPC_LCD_POL_PCD_LO(_n)		((_n) & 0x1f)
+#define	LPC_LCD_LE			0x0c
+#define	LPC_LCD_LE_LEE			(1 << 16)
+#define	LPC_LCD_LE_LED			((_n) & 0x7f)
+#define	LPC_LCD_UPBASE			0x10
+#define	LPC_LCD_LPBASE			0x14
+#define	LPC_LCD_CTRL			0x18
+#define	LPC_LCD_CTRL_WATERMARK		(1 << 16)
+#define	LPC_LCD_CTRL_LCDVCOMP(_n)	(((_n) & 0x3) << 12)
+#define	LPC_LCD_CTRL_LCDPWR		(1 << 11)
+#define	LPC_LCD_CTRL_BEPO		(1 << 10)
+#define	LPC_LCD_CTRL_BEBO		(1 << 9)
+#define	LPC_LCD_CTRL_BGR		(1 << 8)
+#define	LPC_LCD_CTRL_LCDDUAL		(1 << 7)
+#define	LPC_LCD_CTRL_LCDMONO8		(1 << 6)
+#define	LPC_LCD_CTRL_LCDTFT		(1 << 5)
+#define	LPC_LCD_CTRL_LCDBW		(1 << 4)
+#define	LPC_LCD_CTRL_LCDBPP(_n)		(((_n) & 0x7) << 1)
+#define	LPC_LCD_CTRL_BPP1		0
+#define	LPC_LCD_CTRL_BPP2		1
+#define	LPC_LCD_CTRL_BPP4		2
+#define	LPC_LCD_CTRL_BPP8		3
+#define	LPC_LCD_CTRL_BPP16		4
+#define	LPC_LCD_CTRL_BPP24		5
+#define	LPC_LCD_CTRL_BPP16_565		6
+#define	LPC_LCD_CTRL_BPP12_444		7
+#define	LPC_LCD_CTRL_LCDEN		(1 << 0)
+#define	LPC_LCD_INTMSK			0x1c
+#define	LPC_LCD_INTRAW			0x20
+#define	LPC_LCD_INTSTAT			0x24
+#define	LPC_LCD_INTCLR			0x28
+#define	LPC_LCD_UPCURR			0x2c
+#define	LPC_LCD_LPCURR			0x30
+#define	LPC_LCD_PAL			0x200
+#define	LPC_LCD_CRSR_IMG		0x800
+#define	LPC_LCD_CRSR_CTRL		0xc00
+#define	LPC_LCD_CRSR_CFG		0xc04
+#define	LPC_LCD_CRSR_PAL0		0xc08
+#define	LPC_LCD_CRSR_PAL1		0xc0c
+#define	LPC_LCD_CRSR_XY			0xc10
+#define	LPC_LCD_CRSR_CLIP		0xc14
+#define	LPC_LCD_CRSR_INTMSK		0xc20
+#define	LPC_LCD_CRSR_INTCLR		0xc24
+#define	LPC_LCD_CRSR_INTRAW		0xc28
+#define	LPC_LCD_CRSR_INTSTAT		0xc2c
+
+/*
+ * SPI interface (from UM10326: LPC32x0 User manual, page 483)
+ */
+#define	LPC_SPI_GLOBAL			0x00
+#define	LPC_SPI_GLOBAL_RST		(1 << 1)
+#define	LPC_SPI_GLOBAL_ENABLE		(1 << 0)
+#define	LPC_SPI_CON			0x04
+#define	LPC_SPI_CON_UNIDIR		(1 << 23)
+#define	LPC_SPI_CON_BHALT		(1 << 22)
+#define	LPC_SPI_CON_BPOL		(1 << 21)
+#define	LPC_SPI_CON_MSB			(1 << 19)
+#define	LPC_SPI_CON_MODE(_n)		((_n & 0x3) << 16)
+#define	LPC_SPI_CON_RXTX		(1 << 15)
+#define	LPC_SPI_CON_THR			(1 << 14)
+#define	LPC_SPI_CON_SHIFT_OFF		(1 << 13)
+#define	LPC_SPI_CON_BITNUM(_n)		((_n & 0xf) << 9)
+#define	LPC_SPI_CON_MS			(1 << 7)
+#define	LPC_SPI_CON_RATE(_n)		(_n & 0x7f)
+#define	LPC_SPI_FRM			0x08
+#define	LPC_SPI_IER			0x0c
+#define	LPC_SPI_IER_INTEOT		(1 << 1)
+#define	LPC_SPI_IER_INTTHR		(1 << 0)
+#define	LPC_SPI_STAT			0x10
+#define	LPC_SPI_STAT_INTCLR		(1 << 8)
+#define	LPC_SPI_STAT_EOT		(1 << 7)
+#define	LPC_SPI_STAT_BUSYLEV		(1 << 6)
+#define	LPC_SPI_STAT_SHIFTACT		(1 << 3)
+#define	LPC_SPI_STAT_BF			(1 << 2)
+#define	LPC_SPI_STAT_THR		(1 << 1)
+#define	LPC_SPI_STAT_BE			(1 << 0)
+#define	LPC_SPI_DAT			0x14
+#define	LPC_SPI_TIM_CTRL		0x400
+#define	LPC_SPI_TIM_COUNT		0x404
+#define	LPC_SPI_TIM_STAT		0x408
+
+/*
+ * SSP interface (from UM10326: LPC32x0 User manual, page 500)
+ */
+#define	LPC_SSP0_BASE			0x4c00
+#define	LPC_SSP1_BASE			0xc000
+#define	LPC_SSP_CR0			0x00
+#define	LPC_SSP_CR0_DSS(_n)		((_n-1) & 0xf)
+#define	LPC_SSP_CR0_TI			(1 << 4)
+#define	LPC_SSP_CR0_MICROWIRE		(1 << 5)
+#define	LPC_SSP_CR0_CPOL		(1 << 6)
+#define	LPC_SSP_CR0_CPHA		(1 << 7)
+#define	LPC_SSP_CR0_SCR(_n)		((_x & & 0xff) << 8)
+#define	LPC_SSP_CR1			0x04
+#define	LPC_SSP_CR1_LBM			(1 << 0)
+#define	LPC_SSP_CR1_SSE			(1 << 1)
+#define	LPC_SSP_CR1_MS			(1 << 2)
+#define	LPC_SSP_CR1_SOD			(1 << 3)
+#define	LPC_SSP_DR			0x08
+#define	LPC_SSP_SR			0x0c
+#define	LPC_SSP_SR_TFE			(1 << 0)
+#define	LPC_SSP_SR_TNF			(1 << 1)
+#define	LPC_SSP_SR_RNE			(1 << 2)
+#define	LPC_SSP_SR_RFF			(1 << 3)
+#define	LPC_SSP_SR_BSY			(1 << 4)
+#define	LPC_SSP_CPSR			0x10
+#define	LPC_SSP_IMSC			0x14
+#define	LPC_SSP_IMSC_RORIM		(1 << 0)
+#define	LPC_SSP_IMSC_RTIM		(1 << 1)
+#define	LPC_SSP_IMSC_RXIM		(1 << 2)
+#define	LPC_SSP_IMSC_TXIM		(1 << 3)
+#define	LPC_SSP_RIS			0x18
+#define	LPC_SSP_RIS_RORRIS		(1 << 0)
+#define	LPC_SSP_RIS_RTRIS		(1 << 1)
+#define	LPC_SSP_RIS_RXRIS		(1 << 2)
+#define	LPC_SSP_RIS_TXRIS		(1 << 3)
+#define	LPC_SSP_MIS			0x1c
+#define	LPC_SSP_ICR			0x20
+#define	LPC_SSP_DMACR			0x24
+
+/*
+ * GPIO (from UM10326: LPC32x0 User manual, page 606)
+ */
+#define	LPC_GPIO_BASE			(LPC_DEV_BASE + 0x28000)
+#define	LPC_GPIO_P0_COUNT		8
+#define	LPC_GPIO_P1_COUNT		24
+#define	LPC_GPIO_P2_COUNT		13
+#define	LPC_GPIO_P3_COUNT		52
+#define	LPC_GPIO_P0_INP_STATE		0x40
+#define	LPC_GPIO_P0_OUTP_SET		0x44
+#define	LPC_GPIO_P0_OUTP_CLR		0x48
+#define	LPC_GPIO_P0_OUTP_STATE		0x4c
+#define	LPC_GPIO_P0_DIR_SET		0x50
+#define	LPC_GPIO_P0_DIR_CLR		0x54
+#define	LPC_GPIO_P0_DIR_STATE		0x58
+#define	LPC_GPIO_P1_INP_STATE		0x60
+#define	LPC_GPIO_P1_OUTP_SET		0x64
+#define	LPC_GPIO_P1_OUTP_CLR		0x68
+#define	LPC_GPIO_P1_OUTP_STATE		0x6c
+#define	LPC_GPIO_P1_DIR_SET		0x70
+#define	LPC_GPIO_P1_DIR_CLR		0x74
+#define	LPC_GPIO_P1_DIR_STATE		0x78
+#define	LPC_GPIO_P2_INP_STATE		0x1c
+#define	LPC_GPIO_P2_OUTP_SET		0x20
+#define	LPC_GPIO_P2_OUTP_CLR		0x24
+#define	LPC_GPIO_P2_DIR_SET		0x10
+#define	LPC_GPIO_P2_DIR_CLR		0x14
+#define	LPC_GPIO_P2_DIR_STATE		0x14
+#define	LPC_GPIO_P3_INP_STATE		0x00
+#define	LPC_GPIO_P3_OUTP_SET		0x04
+#define	LPC_GPIO_P3_OUTP_CLR		0x08
+#define	LPC_GPIO_P3_OUTP_STATE		0x0c
+/* Aliases for logical pin numbers: */
+#define	LPC_GPIO_GPI_00(_n)		(0 + _n)
+#define	LPC_GPIO_GPI_15(_n)		(10 + _n)
+#define	LPC_GPIO_GPI_25			(19)
+#define	LPC_GPIO_GPI_27(_n)		(20 + _n)
+#define	LPC_GPIO_GPO_00(_n)		(22 + _n)
+#define	LPC_GPIO_GPIO_00(_n)		(46 + _n)
+/* SPI devices chip selects: */
+#define	SSD1289_CS_PIN			LPC_GPIO_GPO_00(4)
+#define	SSD1289_DC_PIN			LPC_GPIO_GPO_00(5)
+#define	ADS7846_CS_PIN			LPC_GPIO_GPO_00(11)
+#define	ADS7846_INTR_PIN		LPC_GPIO_GPIO_00(0)
+
+/*
+ * GPDMA controller (from UM10326: LPC32x0 User manual, page 106)
+ */
+#define	LPC_DMAC_INTSTAT		0x00
+#define	LPC_DMAC_INTTCSTAT		0x04
+#define	LPC_DMAC_INTTCCLEAR		0x08
+#define	LPC_DMAC_INTERRSTAT		0x0c
+#define	LPC_DMAC_INTERRCLEAR		0x10
+#define	LPC_DMAC_RAWINTTCSTAT		0x14
+#define	LPC_DMAC_RAWINTERRSTAT		0x18
+#define	LPC_DMAC_ENABLED_CHANNELS	0x1c
+#define	LPC_DMAC_SOFTBREQ		0x20
+#define	LPC_DMAC_SOFTSREQ		0x24
+#define	LPC_DMAC_SOFTLBREQ		0x28
+#define	LPC_DMAC_SOFTLSREQ		0x2c
+#define	LPC_DMAC_CONFIG			0x30
+#define	LPC_DMAC_CONFIG_M1		(1 << 2)
+#define	LPC_DMAC_CONFIG_M0		(1 << 1)
+#define	LPC_DMAC_CONFIG_ENABLE		(1 << 0)
+#define	LPC_DMAC_CHADDR(_n)		(0x100 + (_n * 0x20))
+#define	LPC_DMAC_CHNUM			8
+#define	LPC_DMAC_CHSIZE			0x20
+#define	LPC_DMAC_CH_SRCADDR		0x00
+#define	LPC_DMAC_CH_DSTADDR		0x04
+#define	LPC_DMAC_CH_LLI			0x08
+#define	LPC_DMAC_CH_LLI_AHB1		(1 << 0)
+#define	LPC_DMAC_CH_CONTROL		0x0c
+#define	LPC_DMAC_CH_CONTROL_I		(1 << 31)
+#define	LPC_DMAC_CH_CONTROL_DI		(1 << 27)
+#define	LPC_DMAC_CH_CONTROL_SI		(1 << 26)
+#define	LPC_DMAC_CH_CONTROL_D		(1 << 25)
+#define	LPC_DMAC_CH_CONTROL_S		(1 << 24)
+#define	LPC_DMAC_CH_CONTROL_WIDTH_4	2
+#define	LPC_DMAC_CH_CONTROL_DWIDTH(_n)	((_n & 0x7) << 21)
+#define	LPC_DMAC_CH_CONTROL_SWIDTH(_n)	((_n & 0x7) << 18)
+#define	LPC_DMAC_CH_CONTROL_BURST_8	2
+#define	LPC_DMAC_CH_CONTROL_DBSIZE(_n)	((_n & 0x7) << 15)
+#define	LPC_DMAC_CH_CONTROL_SBSIZE(_n)	((_n & 0x7) << 12)
+#define	LPC_DMAC_CH_CONTROL_XFERLEN(_n)	(_n & 0xfff) 
+#define	LPC_DMAC_CH_CONFIG		0x10
+#define	LPC_DMAC_CH_CONFIG_H		(1 << 18)
+#define	LPC_DMAC_CH_CONFIG_A		(1 << 17)
+#define	LPC_DMAC_CH_CONFIG_L		(1 << 16)
+#define	LPC_DMAC_CH_CONFIG_ITC		(1 << 15)
+#define	LPC_DMAC_CH_CONFIG_IE		(1 << 14)
+#define	LPC_DMAC_CH_CONFIG_FLOWCNTL(_n)	((_n & 0x7) << 11)
+#define	LPC_DMAC_CH_CONFIG_DESTP(_n)	((_n & 0x1f) << 6)
+#define	LPC_DMAC_CH_CONFIG_SRCP(_n)	((_n & 0x1f) << 1)
+#define	LPC_DMAC_CH_CONFIG_E		(1 << 0)
+
+/* DMA flow control values */
+#define	LPC_DMAC_FLOW_D_M2M		0
+#define	LPC_DMAC_FLOW_D_M2P		1
+#define	LPC_DMAC_FLOW_D_P2M		2
+#define	LPC_DMAC_FLOW_D_P2P		3
+#define	LPC_DMAC_FLOW_DP_P2P		4
+#define	LPC_DMAC_FLOW_P_M2P		5
+#define	LPC_DMAC_FLOW_P_P2M		6
+#define	LPC_DMAC_FLOW_SP_P2P		7
+
+/* DMA peripheral ID's */
+#define	LPC_DMAC_I2S0_DMA0_ID		0
+#define	LPC_DMAC_NAND_ID		1
+#define	LPC_DMAC_IS21_DMA0_ID		2
+#define	LPC_DMAC_SSP1_ID		3
+#define	LPC_DMAC_SPI2_ID		3
+#define	LPC_DMAC_SD_ID			4
+#define	LPC_DMAC_UART1_TX_ID		5
+#define	LPC_DMAC_UART1_RX_ID		6
+#define	LPC_DMAC_UART2_TX_ID		7
+#define	LPC_DMAC_UART2_RX_ID		8
+#define	LPC_DMAC_UART7_TX_ID		9
+#define	LPC_DMAC_UART7_RX_ID		10
+#define	LPC_DMAC_I2S1_DMA1_ID		10
+#define	LPC_DMAC_SPI1_ID		11
+#define	LPC_DMAC_SSP1_TX_ID		11
+#define	LPC_DMAC_NAND2_ID		12
+#define	LPC_DMAC_I2S0_DMA1_ID		13
+#define	LPC_DMAC_SSP0_RX		14
+#define	LPC_DMAC_SSP0_TX		15
+
+#endif	/* _ARM_LPC_LPCREG_H */
diff -r 7fffa673adcd -r a301a330526b head/sys/arm/lpc/lpcvar.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/head/sys/arm/lpc/lpcvar.h	Wed Aug 15 11:16:36 2012 +0300
@@ -0,0 +1,69 @@
+/*-
+ * Copyright (c) 2011 Jakub Wojciech Klama <jceel at FreeBSD.org>
+ * 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: head/sys/arm/lpc/lpcvar.h 239278 2012-08-15 05:37:10Z gonzo $
+ */
+
+#ifndef	_ARM_LPC_LPCVAR_H
+#define	_ARM_LPC_LPCVAR_H
+
+#include <sys/types.h>
+#include <sys/bus.h>
+#include <machine/bus.h>
+
+/* Clocking and power control */
+uint32_t lpc_pwr_read(device_t, int);
+void lpc_pwr_write(device_t, int, uint32_t);
+
+/* GPIO */
+void platform_gpio_init(void);
+int lpc_gpio_set_flags(device_t, int, int);
+int lpc_gpio_set_state(device_t, int, int);
+int lpc_gpio_get_state(device_t, int, int *);
+
+/* DMA */
+struct lpc_dmac_channel_config
+{
+	int		ldc_fcntl;
+	int		ldc_src_periph;
+	int		ldc_src_width;
+	int		ldc_src_incr;
+	int		ldc_src_burst;
+	int		ldc_dst_periph;
+	int		ldc_dst_width;
+	int		ldc_dst_incr;
+	int		ldc_dst_burst;
+	void		(*ldc_success_handler)(void *);
+	void		(*ldc_error_handler)(void *);
+	void *		ldc_handler_arg;
+};
+
+int lpc_dmac_config_channel(device_t, int, struct lpc_dmac_channel_config *);
+int lpc_dmac_setup_transfer(device_t, int, bus_addr_t, bus_addr_t, bus_size_t, int);
+int lpc_dmac_enable_channel(device_t, int);
+int lpc_dmac_disable_channel(device_t, int);
+int lpc_dmac_start_burst(device_t, int);
+
+#endif	/* _ARM_LPC_LPCVAR_H */
diff -r 7fffa673adcd -r a301a330526b head/sys/arm/lpc/ssd1289.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/head/sys/arm/lpc/ssd1289.c	Wed Aug 15 11:16:36 2012 +0300
@@ -0,0 +1,209 @@
+/*-
+ * Copyright (c) 2011 Jakub Wojciech Klama <jceel at FreeBSD.org>
+ * 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.
+ *
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: head/sys/arm/lpc/ssd1289.c 239278 2012-08-15 05:37:10Z gonzo $");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/bio.h>
+#include <sys/bus.h>
+#include <sys/conf.h>
+#include <sys/endian.h>
+#include <sys/kernel.h>
+#include <sys/kthread.h>
+#include <sys/lock.h>
+#include <sys/malloc.h>
+#include <sys/module.h>
+#include <sys/mutex.h>
+#include <sys/queue.h>
+#include <sys/resource.h>
+#include <sys/rman.h>
+#include <sys/time.h>
+#include <sys/timetc.h>
+#include <sys/watchdog.h>
+
+#include <dev/spibus/spi.h>
+
+#include <dev/ofw/ofw_bus.h>
+#include <dev/ofw/ofw_bus_subr.h>
+
+#include <arm/lpc/lpcreg.h>
+#include <arm/lpc/lpcvar.h>
+
+#include "spibus_if.h"
+
+struct ssd1289_softc
+{
+	device_t		ss_dev;
+};
+
+static int ssd1289_probe(device_t);
+static int ssd1289_attach(device_t);
+
+static __inline void ssd1289_set_dc(struct ssd1289_softc *, int);
+static __inline void ssd1289_spi_send(struct ssd1289_softc *, uint8_t *, int);
+static void ssd1289_write_reg(struct ssd1289_softc *, uint16_t, uint16_t);
+
+static struct ssd1289_softc *ssd1289_sc = NULL;
+
+void ssd1289_configure(void);
+
+static int
+ssd1289_probe(device_t dev)
+{
+#if 0
+	if (!ofw_bus_is_compatible(dev, "ssd1289"))
+		return (ENXIO);
+#endif
+
+	device_set_desc(dev, "Solomon Systech SSD1289 LCD controller");
+	return (BUS_PROBE_DEFAULT);
+}
+
+static int
+ssd1289_attach(device_t dev)
+{
+	struct ssd1289_softc *sc = device_get_softc(dev);
+
+	sc->ss_dev = dev;
+	ssd1289_sc = sc;
+
+	return (0);
+}
+
+void
+ssd1289_configure(void)
+{
+	struct ssd1289_softc *sc = ssd1289_sc;
+
+	/* XXX will be replaced with commented code */
+        ssd1289_write_reg(sc,0x00,0x0001);
+        DELAY(20);
+
+        ssd1289_write_reg(sc,0x03,0xA2A4);
+        ssd1289_write_reg(sc,0x0C,0x0004);
+        ssd1289_write_reg(sc,0x0D,0x0308);
+        ssd1289_write_reg(sc,0x0E,0x3000);
+        DELAY(50);
+
+        ssd1289_write_reg(sc,0x1E,0x00AF);
+        ssd1289_write_reg(sc,0x01,0x2B3F);
+        ssd1289_write_reg(sc,0x02,0x0600);
+        ssd1289_write_reg(sc,0x10,0x0000);
+        ssd1289_write_reg(sc,0x07,0x0233);
+        ssd1289_write_reg(sc,0x0B,0x0039);
+        ssd1289_write_reg(sc,0x0F,0x0000);
+        DELAY(50);
+
+        ssd1289_write_reg(sc,0x30,0x0707);
+        ssd1289_write_reg(sc,0x31,0x0204);
+        ssd1289_write_reg(sc,0x32,0x0204);
+        ssd1289_write_reg(sc,0x33,0x0502);
+        ssd1289_write_reg(sc,0x34,0x0507);
+        ssd1289_write_reg(sc,0x35,0x0204);
+        ssd1289_write_reg(sc,0x36,0x0204);
+        ssd1289_write_reg(sc,0x37,0x0502);
+        ssd1289_write_reg(sc,0x3A,0x0302);
+        ssd1289_write_reg(sc,0x3B,0x0302);
+
+        ssd1289_write_reg(sc,0x23,0x0000);
+        ssd1289_write_reg(sc,0x24,0x0000);
+
+        ssd1289_write_reg(sc,0x48,0x0000);
+        ssd1289_write_reg(sc,0x49,0x013F);
+        ssd1289_write_reg(sc,0x4A,0x0000);
+        ssd1289_write_reg(sc,0x4B,0x0000);
+
+        ssd1289_write_reg(sc,0x41,0x0000);
+        ssd1289_write_reg(sc,0x42,0x0000);
+
+        ssd1289_write_reg(sc,0x44,0xEF00);
+        ssd1289_write_reg(sc,0x45,0x0000);
+        ssd1289_write_reg(sc,0x46,0x013F);
+        DELAY(50);
+
+        ssd1289_write_reg(sc,0x44,0xEF00);
+        ssd1289_write_reg(sc,0x45,0x0000);
+        ssd1289_write_reg(sc,0x4E,0x0000);
+        ssd1289_write_reg(sc,0x4F,0x0000);
+        ssd1289_write_reg(sc,0x46,0x013F);
+}
+
+static __inline void
+ssd1289_spi_send(struct ssd1289_softc *sc, uint8_t *data, int len)
+{
+	struct spi_command cmd;
+	uint8_t buffer[8];
+	cmd.tx_cmd = data;
+	cmd.tx_cmd_sz = len;
+	cmd.rx_cmd = buffer;
+	cmd.rx_cmd_sz = len;
+	cmd.tx_data_sz = 0;
+	cmd.rx_data_sz = 0;
+	SPIBUS_TRANSFER(device_get_parent(sc->ss_dev), sc->ss_dev, &cmd);
+}
+
+static __inline void
+ssd1289_set_dc(struct ssd1289_softc *sc, int value)
+{
+	lpc_gpio_set_state(sc->ss_dev, SSD1289_DC_PIN, value);
+}
+
+static void
+ssd1289_write_reg(struct ssd1289_softc *sc, uint16_t addr, uint16_t value)
+{
+	uint8_t buffer[2];
+
+	ssd1289_set_dc(sc, 0);
+	buffer[0] = 0x00;
+	buffer[1] = addr & 0xff;
+	ssd1289_spi_send(sc, buffer, 2);
+
+	ssd1289_set_dc(sc, 1);
+	buffer[0] = (value >> 8) & 0xff;
+	buffer[1] = value & 0xff;
+	ssd1289_spi_send(sc, buffer, 2);
+}
+
+static device_method_t ssd1289_methods[] = {
+	/* Device interface */
+	DEVMETHOD(device_probe,		ssd1289_probe),
+	DEVMETHOD(device_attach,	ssd1289_attach),
+
+	{ 0, 0 }
+};
+
+static devclass_t ssd1289_devclass;
+
+static driver_t ssd1289_driver = {
+	"ssd1289",
+	ssd1289_methods,
+	sizeof(struct ssd1289_softc),
+};
+
+DRIVER_MODULE(ssd1289, spibus, ssd1289_driver, ssd1289_devclass, 0, 0);
diff -r 7fffa673adcd -r a301a330526b head/sys/arm/lpc/std.lpc
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/head/sys/arm/lpc/std.lpc	Wed Aug 15 11:16:36 2012 +0300
@@ -0,0 +1,14 @@
+# $FreeBSD: head/sys/arm/lpc/std.lpc 239278 2012-08-15 05:37:10Z gonzo $
+#
+# DM644x
+#
+
+files		"../lpc/files.lpc"
+cpu		CPU_ARM9
+makeoptions	CONF_CFLAGS="-march=armv5te"
+options		PHYSADDR=0x80000000
+options		STARTUP_PAGETABLE_ADDR=0x80000000
+makeoptions	KERNPHYSADDR=0x80100000
+options		KERNPHYSADDR=0x80100000
+makeoptions	KERNVIRTADDR=0xc0100000
+options		KERNVIRTADDR=0xc0100000
diff -r 7fffa673adcd -r a301a330526b head/sys/arm/mv/armadaxp/armadaxp.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/head/sys/arm/mv/armadaxp/armadaxp.c	Wed Aug 15 11:16:36 2012 +0300
@@ -0,0 +1,73 @@
+/*-
+ * Copyright (c) 2011 Semihalf.
+ * 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.
+ *
+ * From: FreeBSD: src/sys/arm/mv/kirkwood/sheevaplug.c,v 1.2 2010/06/13 13:28:53
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: head/sys/arm/mv/armadaxp/armadaxp.c 239277 2012-08-15 05:15:49Z gonzo $");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/bus.h>
+
+#include <machine/bus.h>
+
+#include <arm/mv/mvreg.h>
+#include <arm/mv/mvvar.h>
+
+#include <dev/fdt/fdt_common.h>
+#include <dev/ofw/openfirm.h>
+
+#include <machine/fdt.h>
+
+struct resource_spec mv_gpio_res[] = {
+	{ SYS_RES_MEMORY,	0,	RF_ACTIVE },
+	{ SYS_RES_IRQ,		0,	RF_ACTIVE },
+	{ -1, 0 }
+};
+
+uint32_t
+get_tclk(void)
+{
+
+	return (TCLK_200MHZ);
+}
+
+uint32_t
+get_l2clk(void)
+{
+
+	return (TCLK_667MHZ);
+}
+
+int
+fdt_pci_devmap(phandle_t node, struct pmap_devmap *devmap, vm_offset_t io_va,
+    vm_offset_t mem_va)
+{
+
+	return (0);
+}
+
diff -r 7fffa673adcd -r a301a330526b head/sys/arm/mv/armadaxp/armadaxp_mp.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/head/sys/arm/mv/armadaxp/armadaxp_mp.c	Wed Aug 15 11:16:36 2012 +0300
@@ -0,0 +1,208 @@
+/*-
+ * Copyright (c) 2011 Semihalf.
+ * 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: head/sys/arm/mv/armadaxp/armadaxp_mp.c 239277 2012-08-15 05:15:49Z gonzo $
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/bus.h>
+#include <sys/lock.h>
+#include <sys/mutex.h>
+#include <sys/smp.h>
+
+#include <machine/smp.h>
+#include <machine/fdt.h>
+
+#include <arm/mv/mvwin.h>
+
+static int platform_get_ncpus(void);
+
+#define MV_AXP_CPU_DIVCLK_BASE		(MV_BASE + 0x18700)
+#define CPU_DIVCLK_CTRL0		0x00
+#define CPU_DIVCLK_CTRL2_RATIO_FULL0	0x08
+#define CPU_DIVCLK_CTRL2_RATIO_FULL1	0x0c
+
+#define MV_COHERENCY_FABRIC_BASE	(MV_MBUS_BRIDGE_BASE + 0x200)
+#define COHER_FABRIC_CTRL		0x00
+#define COHER_FABRIC_CONF		0x04
+
+#define CPU_PMU(x)			(MV_BASE + 0x22100 + (0x100 * (x)))
+#define CPU_PMU_BOOT			0x24
+
+#define MP				(MV_BASE + 0x20800)
+#define MP_SW_RESET(x)			((x) * 8)
+
+#define CPU_RESUME_CONTROL		(0x20988)
+
+/* Coherency Fabric registers */
+static uint32_t
+read_coher_fabric(uint32_t reg)
+{
+
+	return (bus_space_read_4(fdtbus_bs_tag, MV_COHERENCY_FABRIC_BASE, reg));
+}
+
+static void
+write_coher_fabric(uint32_t reg, uint32_t val)
+{
+
+	bus_space_write_4(fdtbus_bs_tag, MV_COHERENCY_FABRIC_BASE, reg, val);
+}
+
+/* Coherency Fabric registers */
+static uint32_t
+read_cpu_clkdiv(uint32_t reg)
+{
+
+	return (bus_space_read_4(fdtbus_bs_tag, MV_AXP_CPU_DIVCLK_BASE, reg));
+}
+
+static void
+write_cpu_clkdiv(uint32_t reg, uint32_t val)
+{
+
+	bus_space_write_4(fdtbus_bs_tag, MV_AXP_CPU_DIVCLK_BASE, reg, val);
+}
+
+void
+platform_mp_setmaxid(void)
+{
+
+	mp_maxid = 3;
+}
+
+int
+platform_mp_probe(void)
+{
+
+	mp_ncpus = platform_get_ncpus();
+
+	return (mp_ncpus > 1);
+}
+
+void
+platform_mp_init_secondary(void)
+{
+}
+
+void mpentry(void);
+void mptramp(void);
+
+static void
+initialize_coherency_fabric(void)
+{
+	uint32_t val, cpus, mask;
+
+	cpus = platform_get_ncpus();
+	mask = (1 << cpus) - 1;
+	val = read_coher_fabric(COHER_FABRIC_CTRL);
+	val |= (mask << 24);
+	write_coher_fabric(COHER_FABRIC_CTRL, val);
+
+	val = read_coher_fabric(COHER_FABRIC_CONF);
+	val |= (mask << 24);
+	write_coher_fabric(COHER_FABRIC_CONF, val);
+}
+
+
+void
+platform_mp_start_ap(void)
+{
+	uint32_t reg, *ptr, cpu_num;
+
+	/* Copy boot code to SRAM */
+	*((unsigned int*)(0xf1020240)) = 0xffff0101;
+	*((unsigned int*)(0xf1008500)) = 0xffff0003;
+
+	pmap_kenter_nocache(0x880f0000, 0xffff0000);
+	reg = 0x880f0000;
+
+	for (ptr = (uint32_t *)mptramp; ptr < (uint32_t *)mpentry;
+	    ptr++, reg += 4)
+		*((uint32_t *)reg) = *ptr;
+
+	if (mp_ncpus > 1) {
+		reg = read_cpu_clkdiv(CPU_DIVCLK_CTRL2_RATIO_FULL0);
+		reg &= 0x00ffffff;
+		reg |= 0x01000000;
+		write_cpu_clkdiv(CPU_DIVCLK_CTRL2_RATIO_FULL0, reg);
+	}
+	if (mp_ncpus > 2) {
+		reg = read_cpu_clkdiv(CPU_DIVCLK_CTRL2_RATIO_FULL1);
+		reg &= 0xff00ffff;
+		reg |= 0x00010000;
+		write_cpu_clkdiv(CPU_DIVCLK_CTRL2_RATIO_FULL1, reg);
+	}
+	if (mp_ncpus > 3) {
+		reg = read_cpu_clkdiv(CPU_DIVCLK_CTRL2_RATIO_FULL1);
+		reg &= 0x00ffffff;
+		reg |= 0x01000000;
+		write_cpu_clkdiv(CPU_DIVCLK_CTRL2_RATIO_FULL1, reg);
+	}
+
+	reg = read_cpu_clkdiv(CPU_DIVCLK_CTRL0);
+	reg |= ((0x1 << (mp_ncpus - 1)) - 1) << 21;
+	write_cpu_clkdiv(CPU_DIVCLK_CTRL0, reg);
+	reg = read_cpu_clkdiv(CPU_DIVCLK_CTRL0);
+	reg |= 0x01000000;
+	write_cpu_clkdiv(CPU_DIVCLK_CTRL0, reg);
+
+	DELAY(100);
+	reg &= ~(0xf << 21);
+	write_cpu_clkdiv(CPU_DIVCLK_CTRL0, reg);
+	DELAY(100);
+
+	bus_space_write_4(fdtbus_bs_tag, MV_BASE, CPU_RESUME_CONTROL, 0);
+
+	for (cpu_num = 1; cpu_num < mp_ncpus; cpu_num++ )
+		bus_space_write_4(fdtbus_bs_tag, CPU_PMU(cpu_num), CPU_PMU_BOOT,
+		    pmap_kextract(mpentry));
+
+	cpu_idcache_wbinv_all();
+
+	for (cpu_num = 1; cpu_num < mp_ncpus; cpu_num++ )
+		bus_space_write_4(fdtbus_bs_tag, MP, MP_SW_RESET(cpu_num), 0);
+
+	/* XXX: Temporary workaround for hangup after releasing AP's */
+	wmb();
+	DELAY(10);
+
+	initialize_coherency_fabric();
+}
+
+static int
+platform_get_ncpus(void)
+{
+
+	return ((read_coher_fabric(COHER_FABRIC_CONF) & 0xf) + 1);
+}
+
+void
+platform_ipi_send(cpuset_t cpus, u_int ipi)
+{
+
+	pic_ipi_send(cpus, ipi);
+}
diff -r 7fffa673adcd -r a301a330526b head/sys/arm/mv/armadaxp/files.armadaxp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/head/sys/arm/mv/armadaxp/files.armadaxp	Wed Aug 15 11:16:36 2012 +0300
@@ -0,0 +1,6 @@
+# $FreeBSD: head/sys/arm/mv/armadaxp/files.armadaxp 239277 2012-08-15 05:15:49Z gonzo $
+
+arm/mv/armadaxp/armadaxp.c	standard
+arm/mv/mpic.c			standard
+arm/mv/rtc.c			standard
+arm/mv/armadaxp/armadaxp_mp.c	optional smp
diff -r 7fffa673adcd -r a301a330526b head/sys/arm/mv/armadaxp/std.armadaxp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/head/sys/arm/mv/armadaxp/std.armadaxp	Wed Aug 15 11:16:36 2012 +0300
@@ -0,0 +1,15 @@
+# $FreeBSD: head/sys/arm/mv/armadaxp/std.armadaxp 239277 2012-08-15 05:15:49Z gonzo $
+
+# kernel gets loaded at 0x00f00000 by the loader, but runs at virtual address
+# 0xc0f00000.  RAM starts at 0.  We put the pagetable at a reasonable place
+# in memory, but may need to bounce it higher if there's a problem with this.
+# We could paper over this by loading the kernel at 0xc0000000 virtual, but
+# that leads to other complications, so we'll just reclaim the lower region of
+# ram after we're loaded.  Put the page tables for startup at 1MB.
+makeoptions	KERNPHYSADDR=0x00f00000
+makeoptions	KERNVIRTADDR=0xc0f00000
+
+options		KERNPHYSADDR=0x00f00000
+options		KERNVIRTADDR=0xc0f00000
+options		PHYSADDR=0x00000000
+options		STARTUP_PAGETABLE_ADDR=0x00100000
diff -r 7fffa673adcd -r a301a330526b head/sys/arm/mv/armadaxp/std.mv78x60
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/head/sys/arm/mv/armadaxp/std.mv78x60	Wed Aug 15 11:16:36 2012 +0300
@@ -0,0 +1,5 @@
+# $FreeBSD: head/sys/arm/mv/armadaxp/std.mv78x60 239277 2012-08-15 05:15:49Z gonzo $
+
+include	"../mv/std-pj4b.mv"
+include "../mv/armadaxp/std.armadaxp"
+files	"../mv/armadaxp/files.armadaxp"
diff -r 7fffa673adcd -r a301a330526b head/sys/arm/mv/common.c
--- a/head/sys/arm/mv/common.c	Wed Aug 15 11:15:12 2012 +0300
+++ b/head/sys/arm/mv/common.c	Wed Aug 15 11:16:36 2012 +0300
@@ -1,5 +1,5 @@
 /*-
- * Copyright (C) 2008 MARVELL INTERNATIONAL LTD.
+ * Copyright (C) 2008-2011 MARVELL INTERNATIONAL LTD.
  * All rights reserved.
  *
  * Developed by Semihalf.
@@ -29,24 +29,36 @@
  * SUCH DAMAGE.
  */
 
+#include "opt_global.h"
+
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD: head/sys/arm/mv/common.c 238873 2012-07-28 21:56:24Z hrs $");
+__FBSDID("$FreeBSD: head/sys/arm/mv/common.c 239277 2012-08-15 05:15:49Z gonzo $");
 
 #include <sys/param.h>
 #include <sys/systm.h>
 #include <sys/bus.h>
 #include <sys/kernel.h>
+#include <sys/malloc.h>
+#include <sys/kdb.h>
+#include <sys/reboot.h>
 
 #include <dev/fdt/fdt_common.h>
 #include <dev/ofw/openfirm.h>
 
 #include <machine/bus.h>
 #include <machine/fdt.h>
+#include <machine/vmparam.h>
 
 #include <arm/mv/mvreg.h>
 #include <arm/mv/mvvar.h>
 #include <arm/mv/mvwin.h>
 
+
+MALLOC_DEFINE(M_IDMA, "idma", "idma dma test memory");
+
+#define IDMA_DEBUG
+#undef IDMA_DEBUG
+
 #define MAX_CPU_WIN	5
 
 #ifdef DEBUG
@@ -64,7 +76,9 @@
 
 static int win_eth_can_remap(int i);
 
+#ifndef SOC_MV_FREY
 static int decode_win_cpu_valid(void);
+#endif
 static int decode_win_usb_valid(void);
 static int decode_win_eth_valid(void);
 static int decode_win_pcie_valid(void);
@@ -73,10 +87,11 @@
 static int decode_win_idma_valid(void);
 static int decode_win_xor_valid(void);
 
+#ifndef SOC_MV_FREY
 static void decode_win_cpu_setup(void);
+#endif
 static void decode_win_usb_setup(u_long);
 static void decode_win_eth_setup(u_long);
-static void decode_win_pcie_setup(u_long);
 static void decode_win_sata_setup(u_long);
 static void decode_win_cesa_setup(u_long);
 static void decode_win_idma_setup(u_long);
@@ -93,7 +108,6 @@
 static int win_cpu_from_dt(void);
 static int fdt_win_setup(void);
 
-static uint32_t used_cpu_wins;
 static uint32_t dev_mask = 0;
 static int cpu_wins_no = 0;
 static int eth_port = 0;
@@ -101,7 +115,7 @@
 
 static struct decode_win cpu_win_tbl[MAX_CPU_WIN];
 
-static const struct decode_win *cpu_wins = cpu_win_tbl;
+const struct decode_win *cpu_wins = cpu_win_tbl;
 
 typedef void (*decode_win_setup_t)(u_long);
 typedef void (*dump_win_t)(u_long);
@@ -251,15 +265,23 @@
 	uint32_t ef = 0;
 
 	soc_id(&dev, &rev);
-	if (dev == MV_DEV_88F6281 ||
-	    dev == MV_DEV_88F6282 ||
-	    dev == MV_DEV_MV78100_Z0 ||
-	    dev == MV_DEV_MV78100)
+
+	switch (dev) {
+	case MV_DEV_88F6281:
+	case MV_DEV_88F6282:
+	case MV_DEV_88RC8180:
+	case MV_DEV_MV78100_Z0:
+	case MV_DEV_MV78100:
 		__asm __volatile("mrc p15, 1, %0, c15, c1, 0" : "=r" (ef));
-	else if (dev == MV_DEV_88F5182 || dev == MV_DEV_88F5281)
+		break;
+	case MV_DEV_88F5182:
+	case MV_DEV_88F5281:
 		__asm __volatile("mrc p15, 0, %0, c14, c0, 0" : "=r" (ef));
-	else if (bootverbose)
-		printf("This ARM Core does not support any extra features\n");
+		break;
+	default:
+		if (bootverbose)
+			printf("This ARM Core does not support any extra features\n");
+	}
 
 	return (ef);
 }
@@ -272,7 +294,7 @@
 soc_power_ctrl_get(uint32_t mask)
 {
 
-#ifndef SOC_MV_ORION
+#if !defined(SOC_MV_ORION) && !defined(SOC_MV_LOKIPLUS) && !defined(SOC_MV_FREY)
 	if (mask != CPU_PM_CTRL_NONE)
 		mask &= read_cpu_ctrl(CPU_PM_CTRL);
 
@@ -290,7 +312,7 @@
 soc_power_ctrl_set(uint32_t mask)
 {
 
-#ifndef SOC_MV_ORION
+#if !defined(SOC_MV_ORION) && !defined(SOC_MV_LOKIPLUS)
 	if (mask != CPU_PM_CTRL_NONE)
 		write_cpu_ctrl(CPU_PM_CTRL, mask);
 #endif
@@ -313,7 +335,7 @@
 static void
 soc_identify(void)
 {
-	uint32_t d, r;
+	uint32_t d, r, size, mode;
 	const char *dev;
 	const char *rev;
 
@@ -353,6 +375,20 @@
 		else if (r == 3)
 			rev = "A1";
 		break;
+	case MV_DEV_88RC8180:
+		dev = "Marvell 88RC8180";
+		break;
+	case MV_DEV_88RC9480:
+		dev = "Marvell 88RC9480";
+		break;
+	case MV_DEV_88RC9580:
+		dev = "Marvell 88RC9580";
+		break;
+	case MV_DEV_88F6781:
+		dev = "Marvell 88F6781";
+		if (r == 2)
+			rev = "Y0";
+		break;
 	case MV_DEV_88F6282:
 		dev = "Marvell 88F6282";
 		if (r == 0)
@@ -366,6 +402,15 @@
 	case MV_DEV_MV78100:
 		dev = "Marvell MV78100";
 		break;
+	case MV_DEV_MV78160:
+		dev = "Marvell MV78160";
+		break;
+	case MV_DEV_MV78260:
+		dev = "Marvell MV78260";
+		break;
+	case MV_DEV_MV78460:
+		dev = "Marvell MV78460";
+		break;
 	default:
 		dev = "UNKNOWN";
 		break;
@@ -376,7 +421,28 @@
 		printf(" rev %s", rev);
 	printf(", TClock %dMHz\n", get_tclk() / 1000 / 1000);
 
-	/* TODO add info on currently set endianess */
+	mode = read_cpu_ctrl(CPU_CONFIG);
+	printf("  Instruction cache prefetch %s, data cache prefetch %s\n",
+	    (mode & CPU_CONFIG_IC_PREF) ? "enabled" : "disabled",
+	    (mode & CPU_CONFIG_DC_PREF) ? "enabled" : "disabled");
+
+	switch (d) {
+	case MV_DEV_88F6281:
+		mode = read_cpu_ctrl(CPU_L2_CONFIG) & CPU_L2_CONFIG_MODE;
+		printf("  256KB 4-way set-associative %s unified L2 cache\n",
+		    mode ? "write-through" : "write-back");
+		break;
+	case MV_DEV_MV78100:
+		mode = read_cpu_ctrl(CPU_CONTROL);
+		size = mode & CPU_CONTROL_L2_SIZE;
+		mode = mode & CPU_CONTROL_L2_MODE;
+		printf("  %s set-associative %s unified L2 cache\n",
+		    size ? "256KB 4-way" : "512KB 8-way",
+		    mode ? "write-through" : "write-back");
+		break;
+	default:
+		break;
+	}
 }
 
 static void
@@ -393,6 +459,17 @@
 SYSINIT(platform_identify, SI_SUB_CPU, SI_ORDER_SECOND, platform_identify,
     NULL);
 
+#ifdef KDB
+static void
+mv_enter_debugger(void *dummy)
+{
+
+	if (boothowto & RB_KDB)
+		kdb_enter(KDB_WHY_BOOTFLAGS, "Boot flags requested debugger");
+}
+SYSINIT(mv_enter_debugger, SI_SUB_CPU, SI_ORDER_ANY, mv_enter_debugger, NULL);
+#endif
+
 int
 soc_decode_win(void)
 {
@@ -412,6 +489,7 @@
 	/* Retrieve our ID: some windows facilities vary between SoC models */
 	soc_id(&dev, &rev);
 
+#ifndef SOC_MV_FREY
 	if (!decode_win_cpu_valid() || !decode_win_usb_valid() ||
 	    !decode_win_eth_valid() || !decode_win_idma_valid() ||
 	    !decode_win_pcie_valid() || !decode_win_sata_valid() ||
@@ -419,6 +497,13 @@
 		return (EINVAL);
 
 	decode_win_cpu_setup();
+#else
+	if (!decode_win_usb_valid() ||
+	    !decode_win_eth_valid() || !decode_win_idma_valid() ||
+	    !decode_win_pcie_valid() || !decode_win_sata_valid() ||
+	    !decode_win_cesa_valid() || !decode_win_xor_valid())
+		return (EINVAL);
+#endif
 	if (MV_DUMP_WIN)
 		soc_dump_decode_win();
 
@@ -433,6 +518,7 @@
 /**************************************************************************
  * Decode windows registers accessors
  **************************************************************************/
+#if !defined(SOC_MV_FREY)
 WIN_REG_IDX_RD(win_cpu, cr, MV_WIN_CPU_CTRL, MV_MBUS_BRIDGE_BASE)
 WIN_REG_IDX_RD(win_cpu, br, MV_WIN_CPU_BASE, MV_MBUS_BRIDGE_BASE)
 WIN_REG_IDX_RD(win_cpu, remap_l, MV_WIN_CPU_REMAP_LO, MV_MBUS_BRIDGE_BASE)
@@ -441,9 +527,7 @@
 WIN_REG_IDX_WR(win_cpu, br, MV_WIN_CPU_BASE, MV_MBUS_BRIDGE_BASE)
 WIN_REG_IDX_WR(win_cpu, remap_l, MV_WIN_CPU_REMAP_LO, MV_MBUS_BRIDGE_BASE)
 WIN_REG_IDX_WR(win_cpu, remap_h, MV_WIN_CPU_REMAP_HI, MV_MBUS_BRIDGE_BASE)
-
-WIN_REG_IDX_RD(ddr, br, MV_WIN_DDR_BASE, MV_DDR_CADR_BASE)
-WIN_REG_IDX_RD(ddr, sz, MV_WIN_DDR_SIZE, MV_DDR_CADR_BASE)
+#endif
 
 WIN_REG_BASE_IDX_RD(win_usb, cr, MV_WIN_USB_CTRL)
 WIN_REG_BASE_IDX_RD(win_usb, br, MV_WIN_USB_BASE)
@@ -482,7 +566,10 @@
 WIN_REG_BASE_IDX_WR(win_pcie, cr, MV_WIN_PCIE_CTRL);
 WIN_REG_BASE_IDX_WR(win_pcie, br, MV_WIN_PCIE_BASE);
 WIN_REG_BASE_IDX_WR(win_pcie, remap, MV_WIN_PCIE_REMAP);
-WIN_REG_BASE_IDX_WR(pcie, bar, MV_PCIE_BAR);
+WIN_REG_BASE_IDX_RD(pcie_bar, br, MV_PCIE_BAR_BASE);
+WIN_REG_BASE_IDX_WR(pcie_bar, br, MV_PCIE_BAR_BASE);
+WIN_REG_BASE_IDX_WR(pcie_bar, brh, MV_PCIE_BAR_BASE_H);
+WIN_REG_BASE_IDX_WR(pcie_bar, cr, MV_PCIE_BAR_CTRL);
 
 WIN_REG_BASE_IDX_RD(win_idma, br, MV_WIN_IDMA_BASE)
 WIN_REG_BASE_IDX_RD(win_idma, sz, MV_WIN_IDMA_SIZE)
@@ -499,7 +586,44 @@
 WIN_REG_BASE_IDX_RD(win_sata, br, MV_WIN_SATA_BASE);
 WIN_REG_BASE_IDX_WR(win_sata, cr, MV_WIN_SATA_CTRL);
 WIN_REG_BASE_IDX_WR(win_sata, br, MV_WIN_SATA_BASE);
+#ifndef SOC_MV_DOVE
+WIN_REG_IDX_RD(ddr, br, MV_WIN_DDR_BASE, MV_DDR_CADR_BASE)
+WIN_REG_IDX_RD(ddr, sz, MV_WIN_DDR_SIZE, MV_DDR_CADR_BASE)
+#else
+/*
+ * On 88F6781 (Dove) SoC DDR Controller is accessed through
+ * single MBUS <-> AXI bridge. In this case we provide emulated
+ * ddr_br_read() and ddr_sz_read() functions to keep compatibility
+ * with common decoding windows setup code.
+ */
 
+static inline uint32_t ddr_br_read(int i)
+{
+	uint32_t mmap;
+
+	/* Read Memory Address Map Register for CS i */
+	mmap = bus_space_read_4(fdtbus_bs_tag, MV_DDR_CADR_BASE + (i * 0x10), 0);
+
+	/* Return CS i base address */
+	return (mmap & 0xFF000000);
+}
+
+static inline uint32_t ddr_sz_read(int i)
+{
+	uint32_t mmap, size;
+
+	/* Read Memory Address Map Register for CS i */
+	mmap = bus_space_read_4(fdtbus_bs_tag, MV_DDR_CADR_BASE + (i * 0x10), 0);
+
+	/* Extract size of CS space in 64kB units */
+	size = (1 << ((mmap >> 16) & 0x0F));
+
+	/* Return CS size and enable/disable status */
+	return (((size - 1) << 16) | (mmap & 0x01));
+}
+#endif
+
+#if !defined(SOC_MV_FREY)
 /**************************************************************************
  * Decode windows helper routines
  **************************************************************************/
@@ -545,9 +669,12 @@
 	if ((dev == MV_DEV_88F5182 && i < 2) ||
 	    (dev == MV_DEV_88F5281 && i < 4) ||
 	    (dev == MV_DEV_88F6281 && i < 4) ||
+	    (dev == MV_DEV_88RC8180 && i < 2) ||
+	    (dev == MV_DEV_88F6781 && i < 4) ||
 	    (dev == MV_DEV_88F6282 && i < 4) ||
 	    (dev == MV_DEV_MV78100 && i < 8) ||
-	    (dev == MV_DEV_MV78100_Z0 && i < 8))
+	    (dev == MV_DEV_MV78100_Z0 && i < 8) ||
+	    ((dev & MV_DEV_FAMILY_MASK) == MV_DEV_DISCOVERY && i < 8))
 		return (1);
 
 	return (0);
@@ -600,7 +727,7 @@
 			rv = 0;
 		}
 
-		if (cpu_wins[i].remap >= 0 && win_cpu_can_remap(i) != 1) {
+		if (cpu_wins[i].remap != ~0 && win_cpu_can_remap(i) != 1) {
 			printf("CPU window#%d: not capable of remapping, but "
 			    "val 0x%08x defined\n", i, cpu_wins[i].remap);
 			rv = 0;
@@ -620,6 +747,13 @@
 			continue;
 		}
 
+		if (b != (b & ~(s - 1))) {
+			printf("CPU window#%d: address 0x%08x is not aligned "
+			    "to 0x%08x\n", i, b, s);
+			rv = 0;
+			continue;
+		}
+
 		j = decode_win_overlap(i, cpu_wins_no, &cpu_wins[0]);
 		if (j >= 0) {
 			printf("CPU window#%d: (0x%08x - 0x%08x) overlaps "
@@ -635,21 +769,39 @@
 
 int
 decode_win_cpu_set(int target, int attr, vm_paddr_t base, uint32_t size,
-    int remap)
+    vm_paddr_t remap)
 {
 	uint32_t br, cr;
-	int win;
+	int win, i;
 
-	if (used_cpu_wins >= MV_WIN_CPU_MAX)
-		return (0);
+	if (remap == ~0) {
+		win = MV_WIN_CPU_MAX - 1;
+		i = -1;
+	} else {
+		win = 0;
+		i = 1;
+	}
 
-	win = used_cpu_wins++;
+	while ((win >= 0) && (win < MV_WIN_CPU_MAX)) {
+		cr = win_cpu_cr_read(win);
+		if ((cr & MV_WIN_CPU_ENABLE_BIT) == 0)
+			break;
+		if ((cr & ((0xff << MV_WIN_CPU_ATTR_SHIFT) |
+		    (0x1f << MV_WIN_CPU_TARGET_SHIFT))) ==
+		    ((attr << MV_WIN_CPU_ATTR_SHIFT) |
+		    (target << MV_WIN_CPU_TARGET_SHIFT)))
+			break;
+		win += i;
+	}
+	if ((win < 0) || (win >= MV_WIN_CPU_MAX) ||
+	    ((remap != ~0) && (win_cpu_can_remap(win) == 0)))
+		return (-1);
 
 	br = base & 0xffff0000;
 	win_cpu_br_write(win, br);
 
 	if (win_cpu_can_remap(win)) {
-		if (remap >= 0) {
+		if (remap != ~0) {
 			win_cpu_remap_l_write(win, remap & 0xffff0000);
 			win_cpu_remap_h_write(win, 0);
 		} else {
@@ -663,7 +815,8 @@
 		}
 	}
 
-	cr = ((size - 1) & 0xffff0000) | (attr << 8) | (target << 4) | 1;
+	cr = ((size - 1) & 0xffff0000) | (attr << MV_WIN_CPU_ATTR_SHIFT) |
+	    (target << MV_WIN_CPU_TARGET_SHIFT) | MV_WIN_CPU_ENABLE_BIT;
 	win_cpu_cr_write(win, cr);
 
 	return (0);
@@ -674,8 +827,6 @@
 {
 	int i;
 
-	used_cpu_wins = 0;
-
 	/* Disable all CPU windows */
 	for (i = 0; i < MV_WIN_CPU_MAX; i++) {
 		win_cpu_cr_write(i, 0);
@@ -693,7 +844,7 @@
 			    cpu_wins[i].size, cpu_wins[i].remap);
 
 }
-
+#endif
 /*
  * Check if we're able to cover all active DDR banks.
  */
@@ -746,6 +897,13 @@
 uint32_t
 ddr_attr(int i)
 {
+	uint32_t dev, rev;
+
+	soc_id(&dev, &rev);
+	if (dev == MV_DEV_88RC8180)
+		return ((ddr_sz_read(i) & 0xf0) >> 4);
+	if (dev == MV_DEV_88F6781)
+		return (0);
 
 	return (i == 0 ? 0xe :
 	    (i == 1 ? 0xd :
@@ -756,8 +914,21 @@
 uint32_t
 ddr_target(int i)
 {
+	uint32_t dev, rev;
 
-	/* Mbus unit ID is 0x0 for DDR SDRAM controller */
+	soc_id(&dev, &rev);
+	if (dev == MV_DEV_88RC8180) {
+		i = (ddr_sz_read(i) & 0xf0) >> 4;
+		return (i == 0xe ? 0xc :
+		    (i == 0xd ? 0xd :
+		    (i == 0xb ? 0xe :
+		    (i == 0x7 ? 0xf : 0xc))));
+	}
+
+	/*
+	 * On SOCs other than 88RC8180 Mbus unit ID for
+	 * DDR SDRAM controller is always 0x0.
+	 */
 	return (0);
 }
 
@@ -840,7 +1011,7 @@
 	/* ETH encode windows 0-3 have remap capability */
 	if (i < 4)
 		return (1);
-	
+
 	return (0);
 }
 
@@ -901,6 +1072,12 @@
 	    win_eth_epap_read(base));
 }
 
+#if defined(SOC_MV_LOKIPLUS)
+#define MV_WIN_ETH_DDR_TRGT(n)	0
+#else
+#define MV_WIN_ETH_DDR_TRGT(n)	ddr_target(n)
+#endif
+
 static void
 decode_win_eth_setup(u_long base)
 {
@@ -927,7 +1104,7 @@
 	for (i = 0; i < MV_WIN_DDR_MAX; i++)
 		if (ddr_is_active(i)) {
 
-			br = ddr_base(i) | (ddr_attr(i) << 8) | ddr_target(i);
+			br = ddr_base(i) | (ddr_attr(i) << 8) | MV_WIN_ETH_DDR_TRGT(i);
 			sz = ((ddr_size(i) - 1) & 0xffff0000);
 
 			/* Set the first free ETH window */
@@ -961,15 +1138,21 @@
  * PCIE windows routines
  **************************************************************************/
 
-static void
+void
 decode_win_pcie_setup(u_long base)
 {
-	uint32_t size = 0;
+	uint32_t size = 0, ddrbase = ~0;
 	uint32_t cr, br;
 	int i, j;
 
-	for (i = 0; i < MV_PCIE_BAR_MAX; i++)
-		pcie_bar_write(base, i, 0);
+	for (i = 0; i < MV_PCIE_BAR_MAX; i++) {
+		pcie_bar_br_write(base, i,
+		    MV_PCIE_BAR_64BIT | MV_PCIE_BAR_PREFETCH_EN);
+		if (i < 3)
+			pcie_bar_brh_write(base, i, 0);
+		if (i > 0)
+			pcie_bar_cr_write(base, i, 0);
+	}
 
 	for (i = 0; i < MV_WIN_PCIE_MAX; i++) {
 		win_pcie_cr_write(base, i, 0);
@@ -977,6 +1160,13 @@
 		win_pcie_remap_write(base, i, 0);
 	}
 
+	/* On End-Point only set BAR size to 1MB regardless of DDR size */
+	if ((bus_space_read_4(fdtbus_bs_tag, base, MV_PCIE_CONTROL)
+	    & MV_PCIE_ROOT_CMPLX) == 0) {
+		pcie_bar_cr_write(base, 1, 0xf0000 | 1);
+		return;
+	}
+
 	for (i = 0; i < MV_WIN_DDR_MAX; i++) {
 		if (ddr_is_active(i)) {
 			/* Map DDR to BAR 1 */
@@ -984,6 +1174,8 @@
 			size += ddr_size(i) & 0xffff0000;
 			cr |= (ddr_attr(i) << 8) | (ddr_target(i) << 4) | 1;
 			br = ddr_base(i);
+			if (br < ddrbase)
+				ddrbase = br;
 
 			/* Use the first available PCIE window */
 			for (j = 0; j < MV_WIN_PCIE_MAX; j++) {
@@ -1003,7 +1195,11 @@
 	 * form value passed to register to get correct value.
 	 */
 	size -= 0x10000;
-	pcie_bar_write(base, 0, size | 1);
+	pcie_bar_cr_write(base, 1, size | 1);
+	pcie_bar_br_write(base, 1, ddrbase |
+	    MV_PCIE_BAR_64BIT | MV_PCIE_BAR_PREFETCH_EN);
+	pcie_bar_br_write(base, 0, fdt_immr_pa |
+	    MV_PCIE_BAR_64BIT | MV_PCIE_BAR_PREFETCH_EN);
 }
 
 static int
@@ -1289,7 +1485,6 @@
 /*
  * Set channel protection 'val' for window 'w' on channel 'c'
  */
-
 static void
 xor_chan_write(u_long base, int c, int e, int w, int val)
 {
@@ -1748,7 +1943,7 @@
 	/* Retrieve 'ranges' property of '/localbus' node. */
 	if ((err = fdt_get_ranges("/localbus", ranges, sizeof(ranges),
 	    &tuples, &tuple_size)) != 0)
-		return (err);
+		return (0);
 
 	/*
 	 * Fill CPU decode windows table.
@@ -1763,9 +1958,9 @@
 		cpu_win_tbl[t].attr = fdt32_to_cpu(ranges[i + 1]);
 		cpu_win_tbl[t].base = fdt32_to_cpu(ranges[i + 2]);
 		cpu_win_tbl[t].size = fdt32_to_cpu(ranges[i + 3]);
-		cpu_win_tbl[t].remap = -1;
+		cpu_win_tbl[t].remap = ~0;
 		debugf("target = 0x%0x attr = 0x%0x base = 0x%0x "
-		    "size = 0x%0x remap = %d\n", cpu_win_tbl[t].target,
+		    "size = 0x%0x remap = 0x%0x\n", cpu_win_tbl[t].target,
 		    cpu_win_tbl[t].attr, cpu_win_tbl[t].base,
 		    cpu_win_tbl[t].size, cpu_win_tbl[t].remap);
 	}
@@ -1792,7 +1987,7 @@
 	cpu_win_tbl[t].attr = MV_WIN_CESA_ATTR;
 	cpu_win_tbl[t].base = sram_base;
 	cpu_win_tbl[t].size = sram_size;
-	cpu_win_tbl[t].remap = -1;
+	cpu_win_tbl[t].remap = ~0;
 	debugf("sram: base = 0x%0lx size = 0x%0lx\n", sram_base, sram_size);
 
 	return (0);
@@ -1810,15 +2005,12 @@
 	if (node == -1)
 		panic("fdt_win_setup: no root node");
 
-	node = fdt_find_compatible(node, "simple-bus", 1);
-	if (node == 0)
-		return (ENXIO);
-
 	/*
-	 * Traverse through all children of simple-bus node, and retrieve
-	 * decode windows data for devices (if applicable).
+	 * Traverse through all children of root and simple-bus nodes.
+	 * For each found device retrieve decode windows data (if applicable).
 	 */
-	for (child = OF_child(node); child != 0; child = OF_peer(child))
+	child = OF_child(node);
+	while (child != 0) {
 		for (i = 0; soc_nodes[i].compat != NULL; i++) {
 
 			soc_node = &soc_nodes[i];
@@ -1830,7 +2022,7 @@
 			if (err != 0)
 				return (err);
 
-			base += fdt_immr_va;
+			base = (base & 0x000fffff) | fdt_immr_va;
 			if (soc_node->decode_handler != NULL)
 				soc_node->decode_handler(base);
 			else
@@ -1840,6 +2032,19 @@
 				soc_node->dump_handler(base);
 		}
 
+		/*
+		 * Once done with root-level children let's move down to
+		 * simple-bus and its children.
+		 */
+		child = OF_peer(child);
+		if ((child == 0) && (node == OF_finddevice("/"))) {
+			node = fdt_find_compatible(node, "simple-bus", 1);
+			if (node == 0)
+				return (ENXIO);
+			child = OF_child(node);
+		}
+	}
+
 	return (0);
 }
 
@@ -1870,7 +2075,8 @@
     int *pol)
 {
 
-	if (!fdt_is_compatible(node, "mrvl,pic"))
+	if (!fdt_is_compatible(node, "mrvl,pic") &&
+	    !fdt_is_compatible(node, "mrvl,mpic"))
 		return (ENXIO);
 
 	*interrupt = fdt32_to_cpu(intr[0]);
diff -r 7fffa673adcd -r a301a330526b head/sys/arm/mv/discovery/files.db78xxx
--- a/head/sys/arm/mv/discovery/files.db78xxx	Wed Aug 15 11:15:12 2012 +0300
+++ b/head/sys/arm/mv/discovery/files.db78xxx	Wed Aug 15 11:16:36 2012 +0300
@@ -1,3 +1,5 @@
-# $FreeBSD$
+# $FreeBSD: head/sys/arm/mv/discovery/files.db78xxx 239277 2012-08-15 05:15:49Z gonzo $
 
 arm/mv/discovery/discovery.c	standard
+arm/mv/ic.c			standard
+
diff -r 7fffa673adcd -r a301a330526b head/sys/arm/mv/files.mv
--- a/head/sys/arm/mv/files.mv	Wed Aug 15 11:15:12 2012 +0300
+++ b/head/sys/arm/mv/files.mv	Wed Aug 15 11:16:36 2012 +0300
@@ -1,4 +1,4 @@
-# $FreeBSD: head/sys/arm/mv/files.mv 235609 2012-05-18 14:41:14Z gber $
+# $FreeBSD: head/sys/arm/mv/files.mv 239277 2012-08-15 05:15:49Z gonzo $
 #
 # The Marvell CPU cores
 # - Compliant with V5TE architecture
@@ -14,14 +14,17 @@
 #
 arm/arm/bus_space_generic.c	standard
 arm/arm/cpufunc_asm_arm10.S	standard
+arm/arm/cpufunc_asm_arm11.S	standard
+arm/arm/cpufunc_asm_armv5.S	standard
 arm/arm/cpufunc_asm_armv5_ec.S	standard
+arm/arm/cpufunc_asm_armv7.S	standard
 arm/arm/cpufunc_asm_sheeva.S	standard
+arm/arm/cpufunc_asm_pj4b.S	standard
 arm/arm/irq_dispatch.S		standard
 
 arm/mv/bus_space.c		standard
 arm/mv/common.c			standard
 arm/mv/gpio.c			standard
-arm/mv/ic.c			standard
 arm/mv/mv_localbus.c		standard
 arm/mv/mv_machdep.c		standard
 arm/mv/mv_pci.c			optional	pci
diff -r 7fffa673adcd -r a301a330526b head/sys/arm/mv/kirkwood/files.kirkwood
--- a/head/sys/arm/mv/kirkwood/files.kirkwood	Wed Aug 15 11:15:12 2012 +0300
+++ b/head/sys/arm/mv/kirkwood/files.kirkwood	Wed Aug 15 11:16:36 2012 +0300
@@ -1,4 +1,5 @@
-# $FreeBSD$
+# $FreeBSD: head/sys/arm/mv/kirkwood/files.kirkwood 239277 2012-08-15 05:15:49Z gonzo $
 
+arm/mv/ic.c			standard
 arm/mv/rtc.c			standard
 arm/mv/kirkwood/kirkwood.c	standard
diff -r 7fffa673adcd -r a301a330526b head/sys/arm/mv/mpic.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/head/sys/arm/mv/mpic.c	Wed Aug 15 11:16:36 2012 +0300
@@ -0,0 +1,304 @@
+/*-
+ * Copyright (c) 2006 Benno Rice.
+ * Copyright (C) 2007-2011 MARVELL INTERNATIONAL LTD.
+ * All rights reserved.
+ *
+ * Developed by Semihalf.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * from: FreeBSD: //depot/projects/arm/src/sys/arm/xscale/pxa2x0/pxa2x0_icu.c, rev 1
+ * from: FreeBSD: src/sys/arm/mv/ic.c,v 1.5 2011/02/08 01:49:30
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: head/sys/arm/mv/mpic.c 239277 2012-08-15 05:15:49Z gonzo $");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/bus.h>
+#include <sys/kernel.h>
+#include <sys/cpuset.h>
+#include <sys/ktr.h>
+#include <sys/module.h>
+#include <sys/rman.h>
+
+#include <machine/bus.h>
+#include <machine/intr.h>
+#include <machine/cpufunc.h>
+#include <machine/smp.h>
+
+#include <dev/ofw/ofw_bus.h>
+#include <dev/ofw/ofw_bus_subr.h>
+
+#define IRQ_ERR			4
+#define MAIN_IRQS		116
+
+#define IRQ_MASK		0x3ff
+
+#define MPIC_CTRL		0x0
+#define MPIC_SOFT_INT		0x4
+#define MPIC_ERR_CAUSE		0x20
+#define MPIC_ISE		0x30
+#define MPIC_ICE		0x34
+
+
+#define MPIC_IN_DOORBELL	0x78
+#define MPIC_IN_DOORBELL_MASK	0x7c
+#define MPIC_CTP		0xb0
+#define MPIC_CTP		0xb0
+#define MPIC_IIACK		0xb4
+#define MPIC_ISM		0xb8
+#define MPIC_ICM		0xbc
+#define MPIC_ERR_MASK		0xec0
+
+struct mv_mpic_softc {
+	struct resource	*	mpic_res[2];
+	bus_space_tag_t		mpic_bst;
+	bus_space_handle_t	mpic_bsh;
+	bus_space_tag_t		cpu_bst;
+	bus_space_handle_t	cpu_bsh;
+	int			mpic_high_regs;
+	int			mpic_error_regs;
+};
+
+static struct resource_spec mv_mpic_spec[] = {
+	{ SYS_RES_MEMORY,	0,	RF_ACTIVE },
+	{ SYS_RES_MEMORY,	1,	RF_ACTIVE },
+	{ -1, 0 }
+};
+
+static struct mv_mpic_softc *mv_mpic_sc = NULL;
+
+void mpic_send_ipi(int cpus, u_int ipi);
+
+static int	mv_mpic_probe(device_t);
+static int	mv_mpic_attach(device_t);
+uint32_t	mv_mpic_get_cause(void);
+uint32_t	mv_mpic_get_cause_err(void);
+static void	arm_mask_irq_err(uintptr_t);
+static void	arm_unmask_irq_err(uintptr_t);
+
+#define MPIC_CPU_WRITE(softc, reg, val) \
+    bus_space_write_4((softc)->cpu_bst, (softc)->cpu_bsh, (reg), (val))
+#define MPIC_CPU_READ(softc, reg) \
+    bus_space_read_4((softc)->cpu_bst, (softc)->cpu_bsh, (reg))
+
+static int
+mv_mpic_probe(device_t dev)
+{
+
+	if (!ofw_bus_is_compatible(dev, "mrvl,mpic"))
+		return (ENXIO);
+
+	device_set_desc(dev, "Marvell Integrated Interrupt Controller");
+	return (0);
+}
+
+static int
+mv_mpic_attach(device_t dev)
+{
+	struct mv_mpic_softc *sc;
+	int error;
+
+	sc = (struct mv_mpic_softc *)device_get_softc(dev);
+
+	if (mv_mpic_sc != NULL)
+		return (ENXIO);
+	mv_mpic_sc = sc;
+
+	error = bus_alloc_resources(dev, mv_mpic_spec, sc->mpic_res);
+	if (error) {
+		device_printf(dev, "could not allocate resources\n");
+		return (ENXIO);
+	}
+
+	sc->mpic_bst = rman_get_bustag(sc->mpic_res[0]);
+	sc->mpic_bsh = rman_get_bushandle(sc->mpic_res[0]);
+
+	sc->cpu_bst = rman_get_bustag(sc->mpic_res[1]);
+	sc->cpu_bsh = rman_get_bushandle(sc->mpic_res[1]);
+
+	bus_space_write_4(mv_mpic_sc->mpic_bst, mv_mpic_sc->mpic_bsh,
+	    MPIC_CTRL, 1);
+	MPIC_CPU_WRITE(mv_mpic_sc, MPIC_CTP, 0);
+
+	return (0);
+}
+
+static device_method_t mv_mpic_methods[] = {
+	DEVMETHOD(device_probe,		mv_mpic_probe),
+	DEVMETHOD(device_attach,	mv_mpic_attach),
+	{ 0, 0 }
+};
+
+static driver_t mv_mpic_driver = {
+	"mpic",
+	mv_mpic_methods,
+	sizeof(struct mv_mpic_softc),
+};
+
+static devclass_t mv_mpic_devclass;
+
+DRIVER_MODULE(mpic, simplebus, mv_mpic_driver, mv_mpic_devclass, 0, 0);
+
+int
+arm_get_next_irq(int last)
+{
+	u_int irq, next = -1;
+
+	irq = mv_mpic_get_cause() & IRQ_MASK;
+	CTR2(KTR_INTR, "%s: irq:%#x", __func__, irq);
+
+	if (irq != IRQ_MASK) {
+		if (irq == IRQ_ERR)
+			irq = mv_mpic_get_cause_err();
+		next = irq;
+	}
+
+	CTR3(KTR_INTR, "%s: last=%d, next=%d", __func__, last, next);
+	return (next);
+}
+
+/*
+ * XXX We can make arm_enable_irq to operate on ICE and then mask/unmask only
+ * by ISM/ICM and remove access to ICE in masking operation
+ */
+void
+arm_mask_irq(uintptr_t nb)
+{
+
+	MPIC_CPU_WRITE(mv_mpic_sc, MPIC_CTP, 1);
+
+	if (nb < MAIN_IRQS) {
+		bus_space_write_4(mv_mpic_sc->mpic_bst, mv_mpic_sc->mpic_bsh,
+		    MPIC_ICE, nb);
+		MPIC_CPU_WRITE(mv_mpic_sc, MPIC_ISM, nb);
+	} else
+		arm_mask_irq_err(nb);
+}
+
+
+static void
+arm_mask_irq_err(uintptr_t nb)
+{
+	uint32_t mask;
+	uint8_t bit_off;
+
+	bit_off = nb - MAIN_IRQS;
+	mask = MPIC_CPU_READ(mv_mpic_sc, MPIC_ERR_MASK);
+	mask &= ~(1 << bit_off);
+	MPIC_CPU_WRITE(mv_mpic_sc, MPIC_ERR_MASK, mask);
+}
+
+void
+arm_unmask_irq(uintptr_t nb)
+{
+
+	MPIC_CPU_WRITE(mv_mpic_sc, MPIC_CTP, 0);
+
+	if (nb < MAIN_IRQS) {
+		bus_space_write_4(mv_mpic_sc->mpic_bst, mv_mpic_sc->mpic_bsh,
+		    MPIC_ISE, nb);
+		MPIC_CPU_WRITE(mv_mpic_sc, MPIC_ICM, nb);
+	} else
+		arm_unmask_irq_err(nb);
+
+	if (nb == 0)
+		MPIC_CPU_WRITE(mv_mpic_sc, MPIC_IN_DOORBELL_MASK, 0xffffffff);
+}
+
+void
+arm_unmask_irq_err(uintptr_t nb)
+{
+	uint32_t mask;
+	uint8_t bit_off;
+
+	bus_space_write_4(mv_mpic_sc->mpic_bst, mv_mpic_sc->mpic_bsh,
+	    MPIC_ISE, IRQ_ERR);
+	MPIC_CPU_WRITE(mv_mpic_sc, MPIC_ICM, IRQ_ERR);
+
+	bit_off = nb - MAIN_IRQS;
+	mask = MPIC_CPU_READ(mv_mpic_sc, MPIC_ERR_MASK);
+	mask |= (1 << bit_off);
+	MPIC_CPU_WRITE(mv_mpic_sc, MPIC_ERR_MASK, mask);
+}
+
+uint32_t
+mv_mpic_get_cause(void)
+{
+
+	return (MPIC_CPU_READ(mv_mpic_sc, MPIC_IIACK));
+}
+
+uint32_t
+mv_mpic_get_cause_err(void)
+{
+	uint32_t err_cause;
+	uint8_t bit_off;
+
+	err_cause = bus_space_read_4(mv_mpic_sc->mpic_bst,
+	    mv_mpic_sc->mpic_bsh, MPIC_ERR_CAUSE);
+
+	if (err_cause)
+		bit_off = ffs(err_cause) - 1;
+	else
+		return (-1);
+	return (MAIN_IRQS + bit_off);
+}
+
+#if defined(SMP)
+void
+pic_ipi_send(cpuset_t cpus, u_int ipi)
+{
+	uint32_t val, i;
+
+	val = 0x00000000;
+	for (i = 0; i < MAXCPU; i++)
+		if (CPU_ISSET(i, &cpus))
+			val |= (1 << (8 + i));
+	val |= ipi;
+	bus_space_write_4(mv_mpic_sc->mpic_bst, mv_mpic_sc->mpic_bsh,
+	    MPIC_SOFT_INT, val);
+}
+
+int
+pic_ipi_get(int i __unused)
+{
+	uint32_t val;
+
+	val = MPIC_CPU_READ(mv_mpic_sc, MPIC_IN_DOORBELL);
+	if (val)
+		return (ffs(val) - 1);
+
+	return (0x3ff);
+}
+
+void
+pic_ipi_clear(int ipi)
+{
+	uint32_t val;
+
+	val = ~(1 << ipi);
+	MPIC_CPU_WRITE(mv_mpic_sc, MPIC_IN_DOORBELL, val);
+}
+
+#endif
diff -r 7fffa673adcd -r a301a330526b head/sys/arm/mv/mv_machdep.c
--- a/head/sys/arm/mv/mv_machdep.c	Wed Aug 15 11:15:12 2012 +0300
+++ b/head/sys/arm/mv/mv_machdep.c	Wed Aug 15 11:16:36 2012 +0300
@@ -39,7 +39,7 @@
 #include "opt_platform.h"
 
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD: head/sys/arm/mv/mv_machdep.c 238329 2012-07-10 01:49:50Z imp $");
+__FBSDID("$FreeBSD: head/sys/arm/mv/mv_machdep.c 239277 2012-08-15 05:15:49Z gonzo $");
 
 #define _ARM32_BUS_DMA_PRIVATE
 #include <sys/param.h>
@@ -122,14 +122,12 @@
 extern vm_offset_t pmap_bootstrap_lastaddr;
 
 struct pv_addr kernel_pt_table[KERNEL_PT_MAX];
-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 pmap_bootstrap_lastaddr;
+vm_paddr_t pmap_pa;
 
 const struct pmap_devmap *pmap_devmap_bootstrap_table;
 struct pv_addr systempage;
@@ -139,6 +137,8 @@
 struct pv_addr abtstack;
 struct pv_addr kernelstack;
 
+void set_stackptrs(int cpu);
+
 static struct mem_region availmem_regions[FDT_MEM_REGIONS];
 static int availmem_regions_sz;
 
@@ -348,8 +348,7 @@
 	/* Platform-specific initialisation */
 	pmap_bootstrap_lastaddr = fdt_immr_va - ARM_NOCACHE_KVA_SIZE;
 
-	pcpu_init(pcpup, 0, sizeof(struct pcpu));
-	PCPU_SET(curthread, &thread0);
+	pcpu0_init();
 
 	/* Calculate number of L2 tables needed for mapping vm_page_array */
 	l2size = (memsize / PAGE_SIZE) * sizeof(struct vm_page);
@@ -407,10 +406,10 @@
 	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(irqstack, (IRQ_STACK_SIZE * MAXCPU));
+	valloc_pages(abtstack, (ABT_STACK_SIZE * MAXCPU));
+	valloc_pages(undstack, (UND_STACK_SIZE * MAXCPU));
+	valloc_pages(kernelstack, (KSTACK_PAGES * MAXCPU));
 
 	init_param1();
 
@@ -462,7 +461,7 @@
 	pmap_link_l2pt(l1pagetable, ARM_VECTORS_HIGH,
 	    &kernel_pt_table[l2size - 1]);
 	pmap_map_entry(l1pagetable, ARM_VECTORS_HIGH, systempage.pv_pa,
-	    VM_PROT_READ|VM_PROT_WRITE, PTE_CACHE);
+	    VM_PROT_READ|VM_PROT_WRITE|VM_PROT_EXECUTE, PTE_CACHE);
 
 	/* Map pmap_devmap[] entries */
 	err_devmap = platform_devmap_init();
@@ -470,6 +469,7 @@
 
 	cpu_domains((DOMAIN_CLIENT << (PMAP_DOMAIN_KERNEL * 2)) |
 	    DOMAIN_CLIENT);
+	pmap_pa = kernel_l1pt.pv_pa;
 	setttb(kernel_l1pt.pv_pa);
 	cpu_tlb_flushID();
 	cpu_domains(DOMAIN_CLIENT << (PMAP_DOMAIN_KERNEL * 2));
@@ -494,7 +494,7 @@
 	debugf("initarm: console initialized\n");
 	debugf(" arg1 kmdp = 0x%08x\n", (uint32_t)kmdp);
 	debugf(" boothowto = 0x%08x\n", boothowto);
-	printf(" dtbp = 0x%08x\n", (uint32_t)dtbp);
+	debugf(" dtbp = 0x%08x\n", (uint32_t)dtbp);
 	print_kernel_section_addr();
 	print_kenv();
 
@@ -505,9 +505,14 @@
 	/*
 	 * Re-initialise decode windows
 	 */
+#if !defined(SOC_MV_FREY)
 	if (soc_decode_win() != 0)
 		printf("WARNING: could not re-initialise decode windows! "
 		    "Running with existing settings...\n");
+#else
+	/* Disable watchdog and timers */
+	write_cpu_ctrl(CPU_TIMERS_BASE + CPU_TIMER_CONTROL, 0);
+#endif
 
 	/*
 	 * Pages were allocated during the secondary bootstrap for the
@@ -518,12 +523,8 @@
 	 * 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);
+
+	set_stackptrs(0);
 
 	/*
 	 * We must now clean the cache again....
@@ -564,7 +565,19 @@
 	    sizeof(struct pcb)));
 }
 
-#define MPP_PIN_MAX		50
+void
+set_stackptrs(int cpu)
+{
+
+	set_stackptr(PSR_IRQ32_MODE,
+	    irqstack.pv_va + ((IRQ_STACK_SIZE * PAGE_SIZE) * (cpu + 1)));
+	set_stackptr(PSR_ABT32_MODE,
+	    abtstack.pv_va + ((ABT_STACK_SIZE * PAGE_SIZE) * (cpu + 1)));
+	set_stackptr(PSR_UND32_MODE,
+	    undstack.pv_va + ((UND_STACK_SIZE * PAGE_SIZE) * (cpu + 1)));
+}
+
+#define MPP_PIN_MAX		68
 #define MPP_PIN_CELLS		2
 #define MPP_PINS_PER_REG	8
 #define MPP_SEL(pin,func)	(((func) & 0xf) <<		\
@@ -601,7 +614,11 @@
 		return (ENXIO);
 
 	if ((node = fdt_find_compatible(node, "mrvl,mpp", 0)) == 0)
-		return (ENXIO);
+		/*
+		 * No MPP node. Fall back to how MPP got set by the
+		 * first-stage loader and try to continue booting.
+		 */
+		return (0);
 moveon:
 	/*
 	 * Process 'reg' prop.
@@ -694,11 +711,49 @@
 	return (0);
 }
 
-#define FDT_DEVMAP_MAX	(MV_WIN_CPU_MAX + 1)
+#define FDT_DEVMAP_MAX	(MV_WIN_CPU_MAX + 2)
 static struct pmap_devmap fdt_devmap[FDT_DEVMAP_MAX] = {
 	{ 0, 0, 0, 0, 0, }
 };
 
+static int
+platform_sram_devmap(struct pmap_devmap *map)
+{
+#if !defined(SOC_MV_ARMADAXP)
+	phandle_t child, root;
+	u_long base, size;
+	/*
+	 * SRAM range.
+	 */
+	if ((child = OF_finddevice("/sram")) != 0)
+		if (fdt_is_compatible(child, "mrvl,cesa-sram") ||
+		    fdt_is_compatible(child, "mrvl,scratchpad"))
+			goto moveon;
+
+	if ((root = OF_finddevice("/")) == 0)
+		return (ENXIO);
+
+	if ((child = fdt_find_compatible(root, "mrvl,cesa-sram", 0)) == 0 &&
+	    (child = fdt_find_compatible(root, "mrvl,scratchpad", 0)) == 0)
+			goto out;
+
+moveon:
+	if (fdt_regsize(child, &base, &size) != 0)
+		return (EINVAL);
+
+	map->pd_va = MV_CESA_SRAM_BASE; /* XXX */
+	map->pd_pa = base;
+	map->pd_size = size;
+	map->pd_prot = VM_PROT_READ | VM_PROT_WRITE;
+	map->pd_cache = PTE_NOCACHE;
+
+	return (0);
+out:
+#endif
+	return (ENOENT);
+
+}
+
 /*
  * XXX: When device entry in devmap has pd_size smaller than section size,
  * system will freeze during initialization
@@ -730,27 +785,33 @@
 	i++;
 
 	/*
+	 * SRAM range.
+	 */
+	if (i < FDT_DEVMAP_MAX)
+		if (platform_sram_devmap(&fdt_devmap[i]) == 0)
+			i++;
+
+	/*
+	 * PCI range(s).
 	 * PCI range(s) and localbus.
 	 */
 	if ((root = OF_finddevice("/")) == -1)
 		return (ENXIO);
-
 	for (child = OF_child(root); child != 0; child = OF_peer(child)) {
-		if (fdt_is_type(child, "pci")) {
+		if (fdt_is_type(child, "pci") || fdt_is_type(child, "pciep")) {
 			/*
 			 * Check space: each PCI node will consume 2 devmap
 			 * entries.
 			 */
-			if (i + 1 >= FDT_DEVMAP_MAX) {
+			if (i + 1 >= FDT_DEVMAP_MAX)
 				return (ENOMEM);
-			}
 
 			/*
 			 * XXX this should account for PCI and multiple ranges
 			 * of a given kind.
 			 */
-			if (fdt_pci_devmap(child, &fdt_devmap[i],
-			    MV_PCIE_IO_BASE, MV_PCIE_MEM_BASE) != 0)
+			if (fdt_pci_devmap(child, &fdt_devmap[i], MV_PCI_VA_IO_BASE,
+				    MV_PCI_VA_MEM_BASE) != 0)
 				return (ENXIO);
 			i += 2;
 		}
@@ -817,3 +878,62 @@
 
 	return (0);
 }
+
+#if defined(CPU_MV_PJ4B)
+#ifdef DDB
+#include <ddb/ddb.h>
+
+DB_SHOW_COMMAND(cp15, db_show_cp15)
+{
+	u_int reg;
+
+	__asm __volatile("mrc p15, 0, %0, c0, c0, 0" : "=r" (reg));
+	db_printf("Cpu ID: 0x%08x\n", reg);
+	__asm __volatile("mrc p15, 0, %0, c0, c0, 1" : "=r" (reg));
+	db_printf("Current Cache Lvl ID: 0x%08x\n",reg);
+
+	__asm __volatile("mrc p15, 0, %0, c1, c0, 0" : "=r" (reg));
+	db_printf("Ctrl: 0x%08x\n",reg);
+	__asm __volatile("mrc p15, 0, %0, c1, c0, 1" : "=r" (reg));
+	db_printf("Aux Ctrl: 0x%08x\n",reg);
+
+	__asm __volatile("mrc p15, 0, %0, c0, c1, 0" : "=r" (reg));
+	db_printf("Processor Feat 0: 0x%08x\n", reg);
+	__asm __volatile("mrc p15, 0, %0, c0, c1, 1" : "=r" (reg));
+	db_printf("Processor Feat 1: 0x%08x\n", reg);
+	__asm __volatile("mrc p15, 0, %0, c0, c1, 2" : "=r" (reg));
+	db_printf("Debug Feat 0: 0x%08x\n", reg);
+	__asm __volatile("mrc p15, 0, %0, c0, c1, 3" : "=r" (reg));
+	db_printf("Auxiliary Feat 0: 0x%08x\n", reg);
+	__asm __volatile("mrc p15, 0, %0, c0, c1, 4" : "=r" (reg));
+	db_printf("Memory Model Feat 0: 0x%08x\n", reg);
+	__asm __volatile("mrc p15, 0, %0, c0, c1, 5" : "=r" (reg));
+	db_printf("Memory Model Feat 1: 0x%08x\n", reg);
+	__asm __volatile("mrc p15, 0, %0, c0, c1, 6" : "=r" (reg));
+	db_printf("Memory Model Feat 2: 0x%08x\n", reg);
+	__asm __volatile("mrc p15, 0, %0, c0, c1, 7" : "=r" (reg));
+	db_printf("Memory Model Feat 3: 0x%08x\n", reg);
+
+	__asm __volatile("mrc p15, 1, %0, c15, c2, 0" : "=r" (reg));
+	db_printf("Aux Func Modes Ctrl 0: 0x%08x\n",reg);
+	__asm __volatile("mrc p15, 1, %0, c15, c2, 1" : "=r" (reg));
+	db_printf("Aux Func Modes Ctrl 1: 0x%08x\n",reg);
+
+	__asm __volatile("mrc p15, 1, %0, c15, c12, 0" : "=r" (reg));
+	db_printf("CPU ID code extension: 0x%08x\n",reg);
+}
+
+DB_SHOW_COMMAND(vtop, db_show_vtop)
+{
+	u_int reg;
+
+	if (have_addr) {
+		__asm __volatile("mcr p15, 0, %0, c7, c8, 0" : : "r" (addr));
+		__asm __volatile("mrc p15, 0, %0, c7, c4, 0" : "=r" (reg));
+		db_printf("Physical address reg: 0x%08x\n",reg);
+	} else
+		db_printf("show vtop <virt_addr>\n");
+}
+#endif /* DDB */
+#endif /* CPU_MV_PJ4B */
+
diff -r 7fffa673adcd -r a301a330526b head/sys/arm/mv/mv_pci.c
--- a/head/sys/arm/mv/mv_pci.c	Wed Aug 15 11:15:12 2012 +0300
+++ b/head/sys/arm/mv/mv_pci.c	Wed Aug 15 11:16:36 2012 +0300
@@ -38,7 +38,7 @@
  */
 
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD: head/sys/arm/mv/mv_pci.c 227843 2011-11-22 21:28:20Z marius $");
+__FBSDID("$FreeBSD: head/sys/arm/mv/mv_pci.c 239277 2012-08-15 05:15:49Z gonzo $");
 
 #include <sys/param.h>
 #include <sys/systm.h>
@@ -240,16 +240,16 @@
 	parnode = OF_parent(node);
 	if (fdt_is_compatible(node, "mrvl,pcie")) {
 		sc->sc_type = MV_TYPE_PCIE;
-		sc->sc_mem_win_target = MV_WIN_PCIE_MEM_TARGET;
-		sc->sc_mem_win_attr = MV_WIN_PCIE_MEM_ATTR;
-		sc->sc_io_win_target = MV_WIN_PCIE_IO_TARGET;
-		sc->sc_io_win_attr = MV_WIN_PCIE_IO_ATTR;
+		sc->sc_mem_win_target = MV_WIN_PCIE_TARGET(0);
+		sc->sc_mem_win_attr = MV_WIN_PCIE_MEM_ATTR(0);
+		sc->sc_io_win_target = MV_WIN_PCIE_TARGET(0);
+		sc->sc_io_win_attr = MV_WIN_PCIE_IO_ATTR(0);
 #ifdef SOC_MV_ORION
 	} else if (fdt_is_compatible(node, "mrvl,pci")) {
 		sc->sc_type = MV_TYPE_PCI;
-		sc->sc_mem_win_target = MV_WIN_PCI_MEM_TARGET;
+		sc->sc_mem_win_target = MV_WIN_PCI_TARGET;
 		sc->sc_mem_win_attr = MV_WIN_PCI_MEM_ATTR;
-		sc->sc_io_win_target = MV_WIN_PCI_IO_TARGET;
+		sc->sc_io_win_target = MV_WIN_PCI_TARGET;
 		sc->sc_io_win_attr = MV_WIN_PCI_IO_ATTR;
 #endif
 	} else
diff -r 7fffa673adcd -r a301a330526b head/sys/arm/mv/mvreg.h
--- a/head/sys/arm/mv/mvreg.h	Wed Aug 15 11:15:12 2012 +0300
+++ b/head/sys/arm/mv/mvreg.h	Wed Aug 15 11:16:36 2012 +0300
@@ -1,5 +1,5 @@
 /*-
- * Copyright (C) 2007-2008 MARVELL INTERNATIONAL LTD.
+ * Copyright (C) 2007-2011 MARVELL INTERNATIONAL LTD.
  * All rights reserved.
  *
  * Developed by Semihalf.
@@ -28,15 +28,12 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $FreeBSD: head/sys/arm/mv/mvreg.h 238873 2012-07-28 21:56:24Z hrs $
+ * $FreeBSD: head/sys/arm/mv/mvreg.h 239277 2012-08-15 05:15:49Z gonzo $
  */
 
 #ifndef _MVREG_H_
 #define _MVREG_H_
 
-#define BRIDGE_IRQ_CAUSE	0x10
-#define BRIGDE_IRQ_MASK		0x14
-
 #if defined(SOC_MV_DISCOVERY)
 #define IRQ_CAUSE_ERROR		0x0
 #define IRQ_CAUSE		0x4
@@ -49,23 +46,55 @@
 #define FIQ_MASK		0x20
 #define FIQ_MASK_HI		0x24
 #define FIQ_CAUSE_SELECT	0x28
-#define ENDPOINT_IRQ_MASK_ERROR	0x2C
-#define ENDPOINT_IRQ_MASK	0x30
-#define ENDPOINT_IRQ_MASK_HI	0x34
+#define ENDPOINT_IRQ_MASK_ERROR(n) 0x2C
+#define ENDPOINT_IRQ_MASK(n)	0x30
+#define ENDPOINT_IRQ_MASK_HI(n)	0x34
 #define ENDPOINT_IRQ_CAUSE_SELECT 0x38
-#else /* !SOC_MV_DISCOVERY */
+#elif defined (SOC_MV_LOKIPLUS) || defined (SOC_MV_FREY)
 #define IRQ_CAUSE		0x0
 #define IRQ_MASK		0x4
 #define FIQ_MASK		0x8
-#define ENDPOINT_IRQ_MASK	0xC
+#define ENDPOINT_IRQ_MASK(n)	(0xC + (n) * 4)
+#define IRQ_CAUSE_HI		(-1)		/* Fake defines for unified */
+#define IRQ_MASK_HI		(-1)		/* interrupt controller code */
+#define FIQ_MASK_HI		(-1)
+#define ENDPOINT_IRQ_MASK_HI(n)	(-1)
+#define ENDPOINT_IRQ_MASK_ERROR(n) (-1)
+#define IRQ_CAUSE_ERROR		(-1)
+#define IRQ_MASK_ERROR		(-1)
+#elif defined (SOC_MV_ARMADAXP)
+#define IRQ_CAUSE		0x18
+#define IRQ_MASK		0x30
+#else /* !SOC_MV_DISCOVERY && !SOC_MV_LOKIPLUS */
+#define IRQ_CAUSE		0x0
+#define IRQ_MASK		0x4
+#define FIQ_MASK		0x8
+#define ENDPOINT_IRQ_MASK(n)	0xC
 #define IRQ_CAUSE_HI		0x10
 #define IRQ_MASK_HI		0x14
 #define FIQ_MASK_HI		0x18
-#define ENDPOINT_IRQ_MASK_HI	0x1C
+#define ENDPOINT_IRQ_MASK_HI(n)	0x1C
+#define ENDPOINT_IRQ_MASK_ERROR(n) (-1)
 #define IRQ_CAUSE_ERROR		(-1)		/* Fake defines for unified */
 #define IRQ_MASK_ERROR		(-1)		/* interrupt controller code */
 #endif
 
+#if defined(SOC_MV_FREY)
+#define BRIDGE_IRQ_CAUSE	0x118
+#define IRQ_TIMER0		0x00000002
+#define IRQ_TIMER1		0x00000004
+#define IRQ_TIMER_WD		0x00000008
+
+#define BRIDGE_IRQ_MASK		0x11c
+#define IRQ_TIMER0_MASK		0x00000002
+#define IRQ_TIMER1_MASK		0x00000004
+#define IRQ_TIMER_WD_MASK	0x00000008
+#elif defined(SOC_MV_ARMADAXP)
+#define BRIDGE_IRQ_CAUSE	0x68
+#define IRQ_TIMER0		0x00000001
+#define IRQ_TIMER1		0x00000002
+#define IRQ_TIMER_WD		0x00000004
+#else
 #define BRIDGE_IRQ_CAUSE	0x10
 #define IRQ_CPU_SELF		0x00000001
 #define IRQ_TIMER0		0x00000002
@@ -77,6 +106,19 @@
 #define IRQ_TIMER0_MASK		0x00000002
 #define IRQ_TIMER1_MASK		0x00000004
 #define IRQ_TIMER_WD_MASK	0x00000008
+#endif
+
+#if defined(SOC_MV_LOKIPLUS) || defined(SOC_MV_FREY)
+#define IRQ_CPU_SELF_CLR	IRQ_CPU_SELF
+#define IRQ_TIMER0_CLR		IRQ_TIMER0
+#define IRQ_TIMER1_CLR		IRQ_TIMER1
+#define IRQ_TIMER_WD_CLR	IRQ_TIMER_WD
+#else
+#define IRQ_CPU_SELF_CLR	(~IRQ_CPU_SELF)
+#define IRQ_TIMER0_CLR		(~IRQ_TIMER0)
+#define IRQ_TIMER1_CLR		(~IRQ_TIMER1)
+#define IRQ_TIMER_WD_CLR	(~IRQ_TIMER_WD)
+#endif
 
 /*
  * System reset
@@ -155,6 +197,7 @@
 /*
  * Timers
  */
+#define CPU_TIMERS_BASE		0x300
 #define CPU_TIMER_CONTROL	0x0
 #define CPU_TIMER0_EN		0x00000001
 #define CPU_TIMER0_AUTO		0x00000002
@@ -182,7 +225,15 @@
 #define SATA_CR_NOPRDPBS		(1 << 10)
 #define SATA_CR_COALDIS(ch)		(1 << (24 + ch))
 
-#define	SATA_ICR			0x014 /* Interrupt Cause Reg. */
+/* Interrupt Coalescing Threshold Reg. */
+#define SATA_ICTR			0x00C
+#define SATA_ICTR_MAX			((1 << 8) - 1)
+
+/* Interrupt Time Threshold Reg. */
+#define SATA_ITTR			0x010
+#define SATA_ITTR_MAX			((1 << 24) - 1)
+
+#define SATA_ICR			0x014 /* Interrupt Cause Reg. */
 #define SATA_ICR_DMADONE(ch)		(1 << (ch))
 #define SATA_ICR_COAL			(1 << 4)
 #define SATA_ICR_DEV(ch)		(1 << (8 + ch))
@@ -271,34 +322,18 @@
 #define GPIO2IRQ(gpio)		((gpio) + NIRQ)
 #define IRQ2GPIO(irq)		((irq) - NIRQ)
 
-/*
- * MPP
- */
-#if defined(SOC_MV_ORION)
-#define MPP_CONTROL0		0x00
-#define MPP_CONTROL1		0x04
-#define MPP_CONTROL2		0x50
-#elif defined(SOC_MV_KIRKWOOD) || defined(SOC_MV_DISCOVERY)
-#define MPP_CONTROL0		0x00
-#define MPP_CONTROL1		0x04
-#define MPP_CONTROL2		0x08
-#define MPP_CONTROL3		0x0C
-#define MPP_CONTROL4		0x10
-#define MPP_CONTROL5		0x14
-#define MPP_CONTROL6		0x18
-#else
-#error SOC_MV_XX not defined
-#endif
-
-#if defined(SOC_MV_ORION)
+#if defined(SOC_MV_ORION) || defined(SOC_MV_LOKIPLUS)
 #define SAMPLE_AT_RESET		0x10
 #elif defined(SOC_MV_KIRKWOOD)
 #define SAMPLE_AT_RESET		0x30
 #elif defined(SOC_MV_DISCOVERY)
 #define SAMPLE_AT_RESET_LO	0x30
 #define SAMPLE_AT_RESET_HI	0x34
-#else
-#error SOC_MV_XX not defined
+#elif defined(SOC_MV_DOVE)
+#define SAMPLE_AT_RESET_LO	0x14
+#define SAMPLE_AT_RESET_HI	0x18
+#elif defined(SOC_MV_FREY)
+#define SAMPLE_AT_RESET		0x100
 #endif
 
 /*
@@ -310,6 +345,9 @@
 #elif defined(SOC_MV_DISCOVERY)
 #define TCLK_MASK		0x00000180
 #define TCLK_SHIFT		0x07
+#elif defined(SOC_MV_LOKIPLUS)
+#define TCLK_MASK		0x0000F000
+#define TCLK_SHIFT		0x0C
 #endif
 
 #define TCLK_100MHZ		100000000
@@ -318,6 +356,33 @@
 #define TCLK_150MHZ		150000000
 #define TCLK_166MHZ		166666667
 #define TCLK_200MHZ		200000000
+#define TCLK_250MHZ		250000000
+#define TCLK_300MHZ		300000000
+#define TCLK_667MHZ		667000000
+
+/*
+ * CPU Cache Configuration
+ */
+
+#define CPU_CONFIG		0x00000000
+#define CPU_CONFIG_IC_PREF	0x00010000
+#define CPU_CONFIG_DC_PREF	0x00020000
+#define CPU_CONTROL		0x00000004
+#define CPU_CONTROL_L2_SIZE	0x00200000	/* Only on Discovery */
+#define CPU_CONTROL_L2_MODE	0x00020000	/* Only on Discovery */
+#define CPU_L2_CONFIG		0x00000028	/* Only on Kirkwood */
+#define CPU_L2_CONFIG_MODE	0x00000010	/* Only on Kirkwood */
+
+/*
+ * PCI Express port control (CPU Control registers)
+ */
+#define CPU_CONTROL_PCIE_DISABLE(n)	(1 << (3 * (n)))
+
+/*
+ * Vendor ID
+ */
+#define PCI_VENDORID_MRVL	0x11AB
+#define PCI_VENDORID_MRVL2	0x1B4B
 
 /*
  * Chip ID
@@ -326,8 +391,35 @@
 #define MV_DEV_88F5182		0x5182
 #define MV_DEV_88F5281		0x5281
 #define MV_DEV_88F6281		0x6281
+#define MV_DEV_88F6781		0x6781
 #define MV_DEV_88F6282		0x6282
 #define MV_DEV_MV78100_Z0	0x6381
 #define MV_DEV_MV78100		0x7810
+#define MV_DEV_MV78130		0x7813
+#define MV_DEV_MV78160		0x7816
+#define MV_DEV_MV78230		0x7823
+#define MV_DEV_MV78260		0x7826
+#define MV_DEV_MV78460		0x7846
+#define MV_DEV_88RC8180		0x8180
+#define MV_DEV_88RC9480		0x9480
+#define MV_DEV_88RC9580		0x9580
 
+#define MV_DEV_FAMILY_MASK	0xff00
+#define MV_DEV_DISCOVERY	0x7800
+
+/*
+ * Doorbell register control
+ */
+#define MV_DRBL_PCIE_TO_CPU	0
+#define MV_DRBL_CPU_TO_PCIE	1
+
+#if defined(SOC_MV_FREY)
+#define MV_DRBL_CAUSE(d,u)	(0x60 + 0x20 * (d) + 0x8 * (u))
+#define MV_DRBL_MASK(d,u)	(0x60 + 0x20 * (d) + 0x8 * (u) + 0x4)
+#define MV_DRBL_MSG(m,d,u)	(0x8 * (u) + 0x20 * (d) + 0x4 * (m))
+#else
+#define MV_DRBL_CAUSE(d,u)	(0x10 * (u) + 0x8 * (d))
+#define MV_DRBL_MASK(d,u)	(0x10 * (u) + 0x8 * (d) + 0x4)
+#define MV_DRBL_MSG(m,d,u)	(0x10 * (u) + 0x8 * (d) + 0x4 * (m) + 0x30)
+#endif
 #endif /* _MVREG_H_ */
diff -r 7fffa673adcd -r a301a330526b head/sys/arm/mv/mvvar.h
--- a/head/sys/arm/mv/mvvar.h	Wed Aug 15 11:15:12 2012 +0300
+++ b/head/sys/arm/mv/mvvar.h	Wed Aug 15 11:16:36 2012 +0300
@@ -34,13 +34,14 @@
  *
  * from: FreeBSD: //depot/projects/arm/src/sys/arm/xscale/pxa2x0/pxa2x0var.h, rev 1
  *
- * $FreeBSD$
+ * $FreeBSD: head/sys/arm/mv/mvvar.h 239277 2012-08-15 05:15:49Z gonzo $
  */
 
 #ifndef _MVVAR_H_
 #define _MVVAR_H_
 
 #include <sys/rman.h>
+#include <machine/bus.h>
 #include <vm/vm.h>
 #include <vm/pmap.h>
 #include <machine/pmap.h>
@@ -49,6 +50,9 @@
 #define	MV_TYPE_PCI		0
 #define	MV_TYPE_PCIE		1
 
+#define MV_MODE_ENDPOINT	0
+#define MV_MODE_ROOT		1
+
 struct gpio_config {
 	int		gc_gpio;	/* GPIO number */
 	uint32_t	gc_flags;	/* GPIO flags */
@@ -60,11 +64,12 @@
 	int		attr;		/* Attributes of the target interface */
 	vm_paddr_t	base;		/* Physical base addr */
 	uint32_t	size;
-	int		remap;
+	vm_paddr_t	remap;
 };
 
 extern const struct pmap_devmap pmap_devmap[];
 extern const struct gpio_config mv_gpio_config[];
+extern const struct decode_win *cpu_wins;
 extern const struct decode_win *idma_wins;
 extern const struct decode_win *xor_wins;
 extern int idma_wins_no;
@@ -86,9 +91,10 @@
 void soc_power_ctrl_set(uint32_t mask);
 
 int decode_win_cpu_set(int target, int attr, vm_paddr_t base, uint32_t size,
-    int remap);
+    vm_paddr_t remap);
 int decode_win_overlap(int, int, const struct decode_win *);
 int win_cpu_can_remap(int);
+void decode_win_pcie_setup(u_long);
 
 int ddr_is_active(int i);
 uint32_t ddr_base(int i);
@@ -98,7 +104,26 @@
 
 uint32_t cpu_extra_feat(void);
 uint32_t get_tclk(void);
+uint32_t get_l2clk(void);
 uint32_t read_cpu_ctrl(uint32_t);
 void write_cpu_ctrl(uint32_t, uint32_t);
 
+int mv_pcib_bar_win_set(device_t dev, uint32_t base, uint32_t size,
+    uint32_t remap, int winno, int busno);
+int mv_pcib_cpu_win_remap(device_t dev, uint32_t remap, uint32_t size);
+
+void mv_mask_endpoint_irq(uintptr_t nb, int unit);
+void mv_unmask_endpoint_irq(uintptr_t nb, int unit);
+
+int	mv_drbl_get_next_irq(int dir, int unit);
+void	mv_drbl_mask_all(int unit);
+void	mv_drbl_mask_irq(uint32_t irq, int dir, int unit);
+void	mv_drbl_unmask_irq(uint32_t irq, int dir, int unit);
+void	mv_drbl_set_mask(uint32_t val, int dir, int unit);
+uint32_t mv_drbl_get_mask(int dir, int unit);
+void	mv_drbl_set_cause(uint32_t val, int dir, int unit);
+uint32_t mv_drbl_get_cause(int dir, int unit);
+void	mv_drbl_set_msg(uint32_t val, int mnr, int dir, int unit);
+uint32_t mv_drbl_get_msg(int mnr, int dir, int unit);
+
 #endif /* _MVVAR_H_ */
diff -r 7fffa673adcd -r a301a330526b head/sys/arm/mv/mvwin.h
--- a/head/sys/arm/mv/mvwin.h	Wed Aug 15 11:15:12 2012 +0300
+++ b/head/sys/arm/mv/mvwin.h	Wed Aug 15 11:16:36 2012 +0300
@@ -1,5 +1,5 @@
 /*-
- * Copyright (C) 2007-2008 MARVELL INTERNATIONAL LTD.
+ * Copyright (C) 2007-2011 MARVELL INTERNATIONAL LTD.
  * All rights reserved.
  *
  * Developed by Semihalf.
@@ -28,71 +28,125 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $FreeBSD: head/sys/arm/mv/mvwin.h 236990 2012-06-13 04:59:00Z imp $
+ * $FreeBSD: head/sys/arm/mv/mvwin.h 239277 2012-08-15 05:15:49Z gonzo $
  */
 
 #ifndef _MVWIN_H_
 #define _MVWIN_H_
 
 /*
- * Physical addresses of integrated SoC peripherals
+ * Decode windows addresses.
+ *
+ * All decoding windows must be aligned to their size, which has to be
+ * a power of 2.
  */
-#define MV_PHYS_BASE		0xF1000000
-#define MV_SIZE			0x100000
 
 /*
- * Decode windows addresses (physical)
+ * SoC Integrated devices: 0xF1000000, 16 MB (VA == PA)
  */
-#define MV_PCIE_IO_PHYS_BASE	(MV_PHYS_BASE + MV_SIZE)
-#define MV_PCIE_IO_BASE		MV_PCIE_IO_PHYS_BASE
-#define MV_PCIE_IO_SIZE		(1024 * 1024)
-#define MV_PCI_IO_PHYS_BASE	(MV_PCIE_IO_PHYS_BASE + MV_PCIE_IO_SIZE)
+
+/* SoC Regs */
+#define MV_PHYS_BASE		0xF1000000
+#define MV_SIZE			(1024 * 1024)	/* 1 MB */
+
+/* SRAM */
+#define MV_CESA_SRAM_BASE	0xF1100000
+
+/* AXI Regs */
+#ifdef SOC_MV_DOVE
+#define MV_AXI_PHYS_BASE	0xF1800000
+#define MV_AXI_BASE		MV_AXI_PHYS_BASE
+#define MV_AXI_SIZE		(16 * 1024 * 1024)	/* 16 MB */
+#endif
+
+/*
+ * External devices: 0x80000000, 1 GB (VA == PA)
+ * Includes Device Bus, PCI and PCIE.
+ */
+#if defined(SOC_MV_ORION)
+#define MV_PCI_PORTS	2	/* 1x PCI + 1x PCIE */
+#elif defined(SOC_MV_KIRKWOOD) || defined(SOC_MV_FREY)
+#define MV_PCI_PORTS	1	/* 1x PCIE */
+#elif defined(SOC_MV_DISCOVERY)
+#define MV_PCI_PORTS	8	/* 8x PCIE */
+#elif defined(SOC_MV_DOVE) || defined(SOC_MV_LOKIPLUS)
+#define MV_PCI_PORTS	2	/* 2x PCIE */
+#elif defined(SOC_MV_ARMADAXP)
+#define MV_PCI_PORTS	3	/* 3x PCIE */
+#else
+#error "MV_PCI_PORTS not configured !"
+#endif
+
+/* PCI/PCIE Memory */
+#define MV_PCI_MEM_PHYS_BASE	0x80000000
+#define MV_PCI_MEM_SIZE		(512 * 1024 * 1024)	/* 512 MB */
+#define MV_PCI_MEM_BASE		MV_PCI_MEM_PHYS_BASE
+#define MV_PCI_MEM_SLICE_SIZE	(MV_PCI_MEM_SIZE / MV_PCI_PORTS)
+#define MV_PCI_MEM_SLICE(n)	(MV_PCI_MEM_BASE + ((n) * \
+				    MV_PCI_MEM_SLICE_SIZE))
+/* PCI/PCIE I/O */
+#define MV_PCI_IO_PHYS_BASE	0xBF000000
+#define MV_PCI_IO_SIZE		(16 * 1024 * 1024)	/* 16 MB */
 #define MV_PCI_IO_BASE		MV_PCI_IO_PHYS_BASE
-#define MV_PCI_IO_SIZE		(1024 * 1024)
+#define MV_PCI_IO_SLICE_SIZE	(MV_PCI_IO_SIZE / MV_PCI_PORTS)
+#define MV_PCI_IO_SLICE(n)	(MV_PCI_IO_BASE + ((n) * MV_PCI_IO_SLICE_SIZE))
 
-#define MV_PCIE_MEM_PHYS_BASE	(MV_PCI_IO_PHYS_BASE + MV_PCI_IO_SIZE)
-#define MV_PCIE_MEM_BASE	MV_PCIE_MEM_PHYS_BASE
-#define MV_PCIE_MEM_SIZE	(64 * 1024 * 1024)
-#define MV_PCI_MEM_PHYS_BASE	(MV_PCIE_MEM_PHYS_BASE + MV_PCIE_MEM_SIZE)
-#define MV_PCI_MEM_BASE		MV_PCI_MEM_PHYS_BASE
-#define MV_PCI_MEM_SIZE		(64 * 1024 * 1024)
+#if defined(SOC_MV_FREY)
+#define MV_PCI_VA_MEM_BASE	MV_PCI_MEM_BASE
+#else
+#define MV_PCI_VA_MEM_BASE	0
+#endif
+#define MV_PCI_VA_IO_BASE	0
 
-#define MV_DEV_BOOT_BASE	0xF9300000
-#define MV_DEV_BOOT_SIZE	(1024 * 1024)		/* 1 MB */
+/*
+ * Device Bus (VA == PA)
+ */
+#define MV_DEV_BOOT_BASE    0xF9300000
+#define MV_DEV_BOOT_SIZE    (1024 * 1024)   /* 1 MB */
 
-#define MV_DEV_CS0_BASE		0xF9400000
-#define MV_DEV_CS0_SIZE		(1024 * 1024)		/* 1 MB */
+#define MV_DEV_CS0_BASE     0xF9400000
+#define MV_DEV_CS0_SIZE     (1024 * 1024)   /* 1 MB */
 
-#define MV_DEV_CS1_BASE		0xF9500000
-#define MV_DEV_CS1_SIZE		(32 * 1024 * 1024)	/* 32 MB */
+#define MV_DEV_CS1_BASE     0xF9500000
+#define MV_DEV_CS1_SIZE     (32 * 1024 * 1024)  /* 32 MB */
 
-#define MV_DEV_CS2_BASE		0xFB500000
-#define MV_DEV_CS2_SIZE		(1024 * 1024)		/* 1 MB */
+#define MV_DEV_CS2_BASE     0xFB500000
+#define MV_DEV_CS2_SIZE     (1024 * 1024)   /* 1 MB */
 
-#define MV_CESA_SRAM_PHYS_BASE	0xFD000000
-#define MV_CESA_SRAM_BASE	MV_CESA_SRAM_PHYS_BASE /* VA == PA mapping */
-#define MV_CESA_SRAM_SIZE	(1024 * 1024)
-
-/* XXX this is probably not robust against wraparounds... */
-#if ((MV_CESA_SRAM_PHYS_BASE + MV_CESA_SRAM_SIZE) > 0xFFFEFFFF)
-#error Devices memory layout overlaps reset vectors range!
-#endif
 
 /*
  * Integrated SoC peripherals addresses
  */
 #define MV_BASE			MV_PHYS_BASE	/* VA == PA mapping */
+#if defined(SOC_MV_DOVE)
+#define MV_DDR_CADR_BASE	(MV_AXI_BASE + 0x100)
+#elif defined(SOC_MV_LOKIPLUS)
+#define MV_DDR_CADR_BASE	(MV_BASE + 0xF1500)
+#else
 #define MV_DDR_CADR_BASE	(MV_BASE + 0x1500)
+#endif
 #define MV_MPP_BASE		(MV_BASE + 0x10000)
 
+#if defined(SOC_MV_ARMADAXP)
+#define MV_MBUS_BRIDGE_BASE	(MV_BASE + 0x20000)
+#define MV_INTREGS_BASE		(MV_MBUS_BRIDGE_BASE + 0x80)
+#define MV_CPU_CONTROL_BASE	(MV_MBUS_BRIDGE_BASE + 0x1800)
+#elif !defined(SOC_MV_FREY)
 #define MV_MBUS_BRIDGE_BASE	(MV_BASE + 0x20000)
 #define MV_INTREGS_BASE		(MV_MBUS_BRIDGE_BASE + 0x80)
 #define MV_CPU_CONTROL_BASE	(MV_MBUS_BRIDGE_BASE + 0x100)
+#else
+#define MV_CPU_CONTROL_BASE	(MV_BASE + 0x10000)
+#endif
 
 #define MV_PCI_BASE		(MV_BASE + 0x30000)
 #define MV_PCI_SIZE		0x2000
 
+#if defined(SOC_MV_FREY)
+#define MV_PCIE_BASE		(MV_BASE + 0x8000)
+#else
 #define MV_PCIE_BASE		(MV_BASE + 0x40000)
+#endif
 #define MV_PCIE_SIZE		0x2000
 
 #define MV_PCIE00_BASE		(MV_PCIE_BASE + 0x00000)
@@ -104,22 +158,53 @@
 #define MV_PCIE12_BASE		(MV_PCIE_BASE + 0x48000)
 #define MV_PCIE13_BASE		(MV_PCIE_BASE + 0x4C000)
 
+#define MV_SDIO_BASE		(MV_BASE + 0x90000)
+#define MV_SDIO_SIZE		0x10000
+
 /*
  * Decode windows definitions and macros
  */
+#if defined(SOC_MV_ARMADAXP)
+#define MV_WIN_CPU_CTRL(n)		(((n) < 8) ? 0x10 * (n) :  0x90 + (0x8 * ((n) - 8)))
+#define MV_WIN_CPU_BASE(n)		((((n) < 8) ? 0x10 * (n) :  0x90 + (0x8 * ((n) - 8))) + 0x4)
+#define MV_WIN_CPU_REMAP_LO(n)		(0x10 * (n) +  0x008)
+#define MV_WIN_CPU_REMAP_HI(n)		(0x10 * (n) +  0x00C)
+#else
 #define MV_WIN_CPU_CTRL(n)		(0x10 * (n) + (((n) < 8) ? 0x000 : 0x880))
 #define MV_WIN_CPU_BASE(n)		(0x10 * (n) + (((n) < 8) ? 0x004 : 0x884))
 #define MV_WIN_CPU_REMAP_LO(n)		(0x10 * (n) + (((n) < 8) ? 0x008 : 0x888))
 #define MV_WIN_CPU_REMAP_HI(n)		(0x10 * (n) + (((n) < 8) ? 0x00C : 0x88C))
+#endif
+
 #if defined(SOC_MV_DISCOVERY)
 #define MV_WIN_CPU_MAX			14
+#elif defined(SOC_MV_ARMADAXP)
+#define MV_WIN_CPU_MAX			20
 #else
 #define MV_WIN_CPU_MAX			8
 #endif
 
+#define MV_WIN_CPU_ATTR_SHIFT		8
+#if defined(SOC_MV_LOKIPLUS)
+#define MV_WIN_CPU_TARGET_SHIFT		0
+#define MV_WIN_CPU_ENABLE_BIT		(1 << 5)
+#else
+#define MV_WIN_CPU_TARGET_SHIFT		4
+#define MV_WIN_CPU_ENABLE_BIT		1
+#endif
+
+#if defined(SOC_MV_DOVE)
+#define MV_WIN_DDR_MAX			2
+#else /* SOC_MV_DOVE */
+#if defined(SOC_MV_LOKIPLUS)
+#define MV_WIN_DDR_BASE(n)		(0xc * (n) + 0x4)
+#define MV_WIN_DDR_SIZE(n)		(0xc * (n) + 0x0)
+#else /* SOC_MV_LOKIPLUS */
 #define MV_WIN_DDR_BASE(n)		(0x8 * (n) + 0x0)
 #define MV_WIN_DDR_SIZE(n)		(0x8 * (n) + 0x4)
+#endif /* SOC_MV_LOKIPLUS */
 #define MV_WIN_DDR_MAX			4
+#endif /* SOC_MV_DOVE */
 
 #define MV_WIN_CESA_CTRL(n)		(0x8 * (n) + 0xa04)
 #define MV_WIN_CESA_BASE(n)		(0x8 * (n) + 0xa00)
@@ -133,8 +218,8 @@
 #define MV_WIN_CESA_ATTR		0
 #endif
 
-#define MV_WIN_USB_CTRL(n)		(0x10 * (n) + 0x0)
-#define MV_WIN_USB_BASE(n)		(0x10 * (n) + 0x4)
+#define MV_WIN_USB_CTRL(n)		(0x10 * (n) + 0x320)
+#define MV_WIN_USB_BASE(n)		(0x10 * (n) + 0x324)
 #define MV_WIN_USB_MAX			4
 
 #define MV_WIN_ETH_BASE(n)		(0x8 * (n) + 0x200)
@@ -158,25 +243,25 @@
 #define MV_XOR_CHAN_MAX			2
 #define MV_XOR_NON_REMAP		4
 
-#if defined(SOC_MV_DISCOVERY)
-#define MV_WIN_PCIE_MEM_TARGET		4
-#define MV_WIN_PCIE_MEM_ATTR		0xE8
-#define MV_WIN_PCIE_IO_TARGET		4
-#define MV_WIN_PCIE_IO_ATTR		0xE0
-#elif defined(SOC_MV_KIRKWOOD)
-#define MV_WIN_PCIE_MEM_TARGET		4
-#define MV_WIN_PCIE_MEM_ATTR		0xE8
-#define MV_WIN_PCIE_IO_TARGET		4
-#define MV_WIN_PCIE_IO_ATTR		0xE0
+#if defined(SOC_MV_DISCOVERY) || defined(SOC_MV_KIRKWOOD) || defined(SOC_MV_DOVE)
+#define MV_WIN_PCIE_TARGET(n)		4
+#define MV_WIN_PCIE_MEM_ATTR(n)		0xE8
+#define MV_WIN_PCIE_IO_ATTR(n)		0xE0
+#elif defined(SOC_MV_ARMADAXP)
+#define MV_WIN_PCIE_TARGET(n)		(4 + (4 * ((n) % 2)))
+#define MV_WIN_PCIE_MEM_ATTR(n)		(0xE8 + (0x10 * ((n) / 2)))
+#define MV_WIN_PCIE_IO_ATTR(n)		(0xE0 + (0x10 * ((n) / 2)))
 #elif defined(SOC_MV_ORION)
-#define MV_WIN_PCIE_MEM_TARGET		4
-#define MV_WIN_PCIE_MEM_ATTR		0x59
-#define MV_WIN_PCIE_IO_TARGET		4
-#define MV_WIN_PCIE_IO_ATTR		0x51
-#define MV_WIN_PCI_MEM_TARGET		3
+#define MV_WIN_PCIE_TARGET(n)		4
+#define MV_WIN_PCIE_MEM_ATTR(n)		0x59
+#define MV_WIN_PCIE_IO_ATTR(n)		0x51
+#define MV_WIN_PCI_TARGET		3
 #define MV_WIN_PCI_MEM_ATTR		0x59
-#define MV_WIN_PCI_IO_TARGET		3
 #define MV_WIN_PCI_IO_ATTR		0x51
+#elif defined(SOC_MV_LOKIPLUS)
+#define MV_WIN_PCIE_TARGET(n)		(3 + (n))
+#define MV_WIN_PCIE_MEM_ATTR(n)		0x59
+#define MV_WIN_PCIE_IO_ATTR(n)		0x51
 #endif
 
 #define MV_WIN_PCIE_CTRL(n)		(0x10 * (((n) < 5) ? (n) : \
@@ -187,8 +272,15 @@
 					    (n) + 1) + 0x182C)
 #define MV_WIN_PCIE_MAX			6
 
-#define MV_PCIE_BAR(n)			(0x04 * (n) + 0x1804)
-#define MV_PCIE_BAR_MAX			3
+#define MV_PCIE_BAR_CTRL(n)		(0x04 * (n) + 0x1800)
+#define MV_PCIE_BAR_BASE(n)		(0x08 * ((n) < 3 ? (n) : 4) + 0x0010)
+#define MV_PCIE_BAR_BASE_H(n)		(0x08 * (n) + 0x0014)
+#define MV_PCIE_BAR_MAX			4
+#define MV_PCIE_BAR_64BIT		(0x4)
+#define MV_PCIE_BAR_PREFETCH_EN		(0x8)
+
+#define MV_PCIE_CONTROL			(0x1a00)
+#define MV_PCIE_ROOT_CMPLX		(1 << 1)
 
 #define	MV_WIN_SATA_CTRL(n)		(0x10 * (n) + 0x30)
 #define	MV_WIN_SATA_BASE(n)		(0x10 * (n) + 0x34)
diff -r 7fffa673adcd -r a301a330526b head/sys/arm/mv/orion/files.db88f5xxx
--- a/head/sys/arm/mv/orion/files.db88f5xxx	Wed Aug 15 11:15:12 2012 +0300
+++ b/head/sys/arm/mv/orion/files.db88f5xxx	Wed Aug 15 11:16:36 2012 +0300
@@ -1,4 +1,5 @@
-# $FreeBSD$
+# $FreeBSD: head/sys/arm/mv/orion/files.db88f5xxx 239277 2012-08-15 05:15:49Z gonzo $
 
+arm/mv/ic.c			standard
 arm/mv/orion/orion.c		standard
 arm/mv/orion/db88f5xxx.c	standard
diff -r 7fffa673adcd -r a301a330526b head/sys/arm/mv/orion/files.ts7800
--- a/head/sys/arm/mv/orion/files.ts7800	Wed Aug 15 11:15:12 2012 +0300
+++ b/head/sys/arm/mv/orion/files.ts7800	Wed Aug 15 11:16:36 2012 +0300
@@ -1,4 +1,5 @@
-# $FreeBSD: head/sys/arm/mv/orion/files.ts7800 220653 2011-04-15 13:37:43Z philip $
+# $FreeBSD: head/sys/arm/mv/orion/files.ts7800 239277 2012-08-15 05:15:49Z gonzo $
 
+arm/mv/ic.c			standard
 arm/mv/orion/orion.c	standard
 
diff -r 7fffa673adcd -r a301a330526b head/sys/arm/mv/std-pj4b.mv
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/head/sys/arm/mv/std-pj4b.mv	Wed Aug 15 11:16:36 2012 +0300
@@ -0,0 +1,6 @@
+# $FreeBSD: head/sys/arm/mv/std-pj4b.mv 239277 2012-08-15 05:15:49Z gonzo $
+
+files		"../mv/files.mv"
+cpu		CPU_MV_PJ4B
+
+options		VM_MAXUSER_ADDRESS="(KERNBASE-(1024*1024*1024))"
diff -r 7fffa673adcd -r a301a330526b head/sys/arm/mv/timer.c
--- a/head/sys/arm/mv/timer.c	Wed Aug 15 11:15:12 2012 +0300
+++ b/head/sys/arm/mv/timer.c	Wed Aug 15 11:16:36 2012 +0300
@@ -29,7 +29,7 @@
  */
 
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD$");
+__FBSDID("$FreeBSD: head/sys/arm/mv/timer.c 239277 2012-08-15 05:15:49Z gonzo $");
 
 #include <sys/param.h>
 #include <sys/systm.h>
@@ -55,6 +55,12 @@
 #define INITIAL_TIMECOUNTER	(0xffffffff)
 #define MAX_WATCHDOG_TICKS	(0xffffffff)
 
+#if defined(SOC_MV_ARMADAXP)
+#define MV_CLOCK_SRC		get_l2clk()
+#else
+#define MV_CLOCK_SRC		get_tclk()
+#endif
+
 struct mv_timer_softc {
 	struct resource	*	timer_res[2];
 	bus_space_tag_t		timer_bst;
@@ -116,7 +122,9 @@
 	int	error;
 	void	*ihl;
 	struct	mv_timer_softc *sc;
+#if !defined(SOC_MV_ARMADAXP)
 	uint32_t irq_cause, irq_mask;
+#endif
 
 	if (timer_softc != NULL)
 		return (ENXIO);
@@ -145,18 +153,21 @@
 	}
 
 	mv_setup_timers();
+#if !defined(SOC_MV_ARMADAXP)
 	irq_cause = read_cpu_ctrl(BRIDGE_IRQ_CAUSE);
-	irq_cause &= ~(IRQ_TIMER0);
+        irq_cause &= IRQ_TIMER0_CLR;
+
 	write_cpu_ctrl(BRIDGE_IRQ_CAUSE, irq_cause);
 	irq_mask = read_cpu_ctrl(BRIDGE_IRQ_MASK);
 	irq_mask |= IRQ_TIMER0_MASK;
 	irq_mask &= ~IRQ_TIMER1_MASK;
 	write_cpu_ctrl(BRIDGE_IRQ_MASK, irq_mask);
-
+#endif
 	sc->et.et_name = "CPUTimer0";
 	sc->et.et_flags = ET_FLAGS_PERIODIC | ET_FLAGS_ONESHOT;
 	sc->et.et_quality = 1000;
-	sc->et.et_frequency = get_tclk();
+
+	sc->et.et_frequency = MV_CLOCK_SRC;
 	sc->et.et_min_period.sec = 0;
 	sc->et.et_min_period.frac =
 	    ((0x00000002LLU << 32) / sc->et.et_frequency) << 32;
@@ -167,7 +178,7 @@
 	sc->et.et_stop = mv_timer_stop;
 	sc->et.et_priv = sc;
 	et_register(&sc->et);
-	mv_timer_timecounter.tc_frequency = get_tclk();
+	mv_timer_timecounter.tc_frequency = MV_CLOCK_SRC;
 	tc_init(&mv_timer_timecounter);
 
 	return (0);
@@ -180,7 +191,7 @@
 	uint32_t irq_cause;
 
 	irq_cause = read_cpu_ctrl(BRIDGE_IRQ_CAUSE);
-	irq_cause &= ~(IRQ_TIMER0);
+	irq_cause &= IRQ_TIMER0_CLR;
 	write_cpu_ctrl(BRIDGE_IRQ_CAUSE, irq_cause);
 
 	sc = (struct mv_timer_softc *)arg;
@@ -235,7 +246,7 @@
 	}
 
 	val = mv_get_timer(1);
-	nticks = ((get_tclk() / 1000000 + 1) * usec);
+	nticks = ((MV_CLOCK_SRC / 1000000 + 1) * usec);
 
 	while (nticks > 0) {
 		val_temp = mv_get_timer(1);
@@ -291,16 +302,20 @@
 static void
 mv_watchdog_enable(void)
 {
-	uint32_t val;
-	uint32_t irq_cause, irq_mask;
+	uint32_t val, irq_cause;
+#if !defined(SOC_MV_ARMADAXP)
+	uint32_t irq_mask;
+#endif
 
 	irq_cause = read_cpu_ctrl(BRIDGE_IRQ_CAUSE);
-	irq_cause &= ~(IRQ_TIMER_WD);
+	irq_cause &= IRQ_TIMER_WD_CLR;
 	write_cpu_ctrl(BRIDGE_IRQ_CAUSE, irq_cause);
 
+#if !defined(SOC_MV_ARMADAXP)
 	irq_mask = read_cpu_ctrl(BRIDGE_IRQ_MASK);
 	irq_mask |= IRQ_TIMER_WD_MASK;
 	write_cpu_ctrl(BRIDGE_IRQ_MASK, irq_mask);
+#endif
 
 	val = read_cpu_ctrl(RSTOUTn_MASK);
 	val |= WD_RST_OUT_EN;
@@ -314,8 +329,10 @@
 static void
 mv_watchdog_disable(void)
 {
-	uint32_t val;
-	uint32_t irq_cause, irq_mask;
+	uint32_t val, irq_cause;
+#if !defined(SOC_MV_ARMADAXP)
+	uint32_t irq_mask;
+#endif
 
 	val = mv_get_timer_control();
 	val &= ~(CPU_TIMER_WD_EN | CPU_TIMER_WD_AUTO);
@@ -325,12 +342,14 @@
 	val &= ~WD_RST_OUT_EN;
 	write_cpu_ctrl(RSTOUTn_MASK, val);
 
+#if !defined(SOC_MV_ARMADAXP)
 	irq_mask = read_cpu_ctrl(BRIDGE_IRQ_MASK);
 	irq_mask &= ~(IRQ_TIMER_WD_MASK);
 	write_cpu_ctrl(BRIDGE_IRQ_MASK, irq_mask);
+#endif
 
 	irq_cause = read_cpu_ctrl(BRIDGE_IRQ_CAUSE);
-	irq_cause &= ~(IRQ_TIMER_WD);
+	irq_cause &= IRQ_TIMER_WD_CLR;
 	write_cpu_ctrl(BRIDGE_IRQ_CAUSE, irq_cause);
 }
 
@@ -353,7 +372,7 @@
 		 * watchdog(9)
 		 */
 		ns = (uint64_t)1 << (cmd & WD_INTERVAL);
-		ticks = (uint64_t)(ns * get_tclk()) / 1000000000;
+		ticks = (uint64_t)(ns * MV_CLOCK_SRC) / 1000000000;
 		if (ticks > MAX_WATCHDOG_TICKS)
 			mv_watchdog_disable();
 		else {
diff -r 7fffa673adcd -r a301a330526b head/sys/arm/s3c2xx0/s3c24x0_machdep.c
--- a/head/sys/arm/s3c2xx0/s3c24x0_machdep.c	Wed Aug 15 11:15:12 2012 +0300
+++ b/head/sys/arm/s3c2xx0/s3c24x0_machdep.c	Wed Aug 15 11:16:36 2012 +0300
@@ -46,7 +46,7 @@
 #include "opt_ddb.h"
 
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD: head/sys/arm/s3c2xx0/s3c24x0_machdep.c 238329 2012-07-10 01:49:50Z imp $");
+__FBSDID("$FreeBSD: head/sys/arm/s3c2xx0/s3c24x0_machdep.c 239268 2012-08-15 03:03:03Z gonzo $");
 
 #define _ARM32_BUS_DMA_PRIVATE
 #include <sys/param.h>
@@ -118,9 +118,6 @@
 
 struct pv_addr kernel_pt_table[NUM_KERNEL_PTS];
 
-struct pcpu __pcpu;
-struct pcpu *pcpup = &__pcpu;
-
 /* Physical and virtual addresses for some global pages */
 
 vm_paddr_t phys_avail[10];
@@ -241,8 +238,7 @@
 	set_cpufuncs();
 	cpufuncs.cf_sleep = s3c24x0_sleep;
 
-	pcpu_init(pcpup, 0, sizeof(struct pcpu));
-	PCPU_SET(curthread, &thread0);
+	pcpu0_init();
 
 	/* Do basic tuning, hz etc */
 	init_param1();
diff -r 7fffa673adcd -r a301a330526b head/sys/arm/s3c2xx0/std.ln2410sbc
--- a/head/sys/arm/s3c2xx0/std.ln2410sbc	Wed Aug 15 11:15:12 2012 +0300
+++ b/head/sys/arm/s3c2xx0/std.ln2410sbc	Wed Aug 15 11:16:36 2012 +0300
@@ -1,4 +1,4 @@
-#$FreeBSD$
+#$FreeBSD: head/sys/arm/s3c2xx0/std.ln2410sbc 239268 2012-08-15 03:03:03Z gonzo $
 include "../s3c2xx0/std.s3c2410"
 
 makeoptions	KERNPHYSADDR=0x30000000
@@ -7,4 +7,5 @@
 options		KERNVIRTADDR=0xc0000000
 options		PHYSADDR=0x30000000
 options		STARTUP_PAGETABLE_ADDR=0x30800000
+options		NO_EVENTTIMERS
 
diff -r 7fffa673adcd -r a301a330526b head/sys/arm/s3c2xx0/std.s3c2410
--- a/head/sys/arm/s3c2xx0/std.s3c2410	Wed Aug 15 11:15:12 2012 +0300
+++ b/head/sys/arm/s3c2xx0/std.s3c2410	Wed Aug 15 11:16:36 2012 +0300
@@ -1,6 +1,7 @@
-# $FreeBSD$
+# $FreeBSD: head/sys/arm/s3c2xx0/std.s3c2410 239268 2012-08-15 03:03:03Z gonzo $
 
 files	"../s3c2xx0/files.s3c2xx0"
 cpu	CPU_ARM9
 
 makeoptions	CONF_CFLAGS=-mcpu=arm920t
+options		NO_EVENTTIMERS
diff -r 7fffa673adcd -r a301a330526b head/sys/arm/sa11x0/assabet_machdep.c
--- a/head/sys/arm/sa11x0/assabet_machdep.c	Wed Aug 15 11:15:12 2012 +0300
+++ b/head/sys/arm/sa11x0/assabet_machdep.c	Wed Aug 15 11:16:36 2012 +0300
@@ -47,7 +47,7 @@
 
 
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD: head/sys/arm/sa11x0/assabet_machdep.c 238329 2012-07-10 01:49:50Z imp $");
+__FBSDID("$FreeBSD: head/sys/arm/sa11x0/assabet_machdep.c 239268 2012-08-15 03:03:03Z gonzo $");
 
 #include "opt_md.h"
 
@@ -123,9 +123,6 @@
 
 extern vm_offset_t sa1_cache_clean_addr;
 
-struct pcpu __pcpu;
-struct pcpu *pcpup = &__pcpu;
-
 #ifndef MD_ROOT_SIZE
 #define MD_ROOT_SIZE 65535
 #endif
@@ -197,7 +194,6 @@
 void *
 initarm(struct arm_boot_params *abp)
 {
-	struct pcpu *pc;
 	struct pv_addr  kernel_l1pt;
 	struct pv_addr	md_addr;
 	struct pv_addr	md_bla;
@@ -215,9 +211,7 @@
 	cninit();
 	set_cpufuncs();
 	physmem = memsize / PAGE_SIZE;
-	pc = &__pcpu;
-	pcpu_init(pc, 0, sizeof(struct pcpu));
-	PCPU_SET(curthread, &thread0);
+	pcpu0_init();
 
 	/* Do basic tuning, hz etc */
 	init_param1();
diff -r 7fffa673adcd -r a301a330526b head/sys/arm/sa11x0/std.sa11x0
--- a/head/sys/arm/sa11x0/std.sa11x0	Wed Aug 15 11:15:12 2012 +0300
+++ b/head/sys/arm/sa11x0/std.sa11x0	Wed Aug 15 11:16:36 2012 +0300
@@ -1,7 +1,8 @@
 #StrongARM SA11x0 common options
-#$FreeBSD$
+#$FreeBSD: head/sys/arm/sa11x0/std.sa11x0 239268 2012-08-15 03:03:03Z gonzo $
 files		"../sa11x0/files.sa11x0"
 cpu		CPU_SA1100
 cpu		CPU_SA1110
 makeoptions	KERNPHYSADDR=0xc0000000
 makeoptions	KERNVIRTADDR=0xc0000000
+options		NO_EVENTTIMERS
diff -r 7fffa673adcd -r a301a330526b head/sys/arm/tegra/bus_space.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/head/sys/arm/tegra/bus_space.c	Wed Aug 15 11:16:36 2012 +0300
@@ -0,0 +1,153 @@
+/*-
+ * Copyright (c) 2012 Damjan Marion <damjan.marion at 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 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.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: head/sys/arm/tegra/bus_space.c 239280 2012-08-15 06:06:43Z gonzo $");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/bus.h>
+#include <sys/kernel.h>
+#include <sys/malloc.h>
+
+#include <machine/bus.h>
+
+/* Prototypes for all the bus_space structure functions */
+bs_protos(generic);
+bs_protos(generic_armv4);
+
+/*
+ * The bus space tag.  This is constant for all instances, so
+ * we never have to explicitly "create" it.
+ */
+static struct bus_space _base_tag = {
+	/* cookie */
+	(void *) 0,
+
+	/* mapping/unmapping */
+	generic_bs_map,
+	generic_bs_unmap,
+	generic_bs_subregion,
+
+	/* allocation/deallocation */
+	generic_bs_alloc,
+	generic_bs_free,
+
+	/* barrier */
+	generic_bs_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,
+	NULL,
+	NULL,
+	NULL,
+
+	/* set multiple */
+	NULL,
+	NULL,
+	NULL,
+	NULL,
+
+	/* set region */
+	NULL,
+	NULL,
+	NULL,
+	NULL,
+
+	/* copy */
+	NULL,
+	NULL,
+	NULL,
+	NULL,
+
+	/* read stream (single) */
+	NULL,
+	NULL,
+	NULL,
+	NULL,
+
+	/* read multiple stream */
+	NULL,
+	generic_armv4_bs_rm_2,		/* bus_space_read_multi_stream_2 */
+	NULL,
+	NULL,
+
+	/* read region stream */
+	NULL,
+	NULL,
+	NULL,
+	NULL,
+
+	/* write stream (single) */
+	NULL,
+	NULL,
+	NULL,
+	NULL,
+
+	/* write multiple stream */
+	NULL,
+	generic_armv4_bs_wm_2,		/* bus_space_write_multi_stream_2 */
+	NULL,
+	NULL,
+
+	/* write region stream */
+	NULL,
+	NULL,
+	NULL,
+	NULL
+};
+
+bus_space_tag_t fdtbus_bs_tag = &_base_tag;
diff -r 7fffa673adcd -r a301a330526b head/sys/arm/tegra/common.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/head/sys/arm/tegra/common.c	Wed Aug 15 11:16:36 2012 +0300
@@ -0,0 +1,78 @@
+/*-
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ *
+ * Developed by Damjan Marion <damjan.marion at gmail.com>
+ *
+ * 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.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: head/sys/arm/tegra/common.c 239280 2012-08-15 06:06:43Z gonzo $");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/bus.h>
+#include <sys/kernel.h>
+
+#include <dev/fdt/fdt_common.h>
+#include <dev/ofw/openfirm.h>
+
+#include <machine/bus.h>
+#include <machine/fdt.h>
+
+/* FIXME move to header file */
+#define TEGRA2_CLK_RST_PA_BASE		0x60006000
+
+void
+cpu_reset(void)
+{
+	bus_space_handle_t bsh;
+	printf("Restetting...\n");
+	bus_space_map(fdtbus_bs_tag,TEGRA2_CLK_RST_PA_BASE, 0x1000, 0, &bsh);
+	bus_space_write_4(fdtbus_bs_tag, bsh, 4, 4);
+}
+
+struct fdt_fixup_entry fdt_fixup_table[] = {
+	{ NULL, NULL }
+};
+
+static int
+fdt_pic_decode_ic(phandle_t node, pcell_t *intr, int *interrupt, int *trig,
+    int *pol)
+{
+	if (!fdt_is_compatible(node, "arm,gic"))
+		return (ENXIO);
+
+	*interrupt = fdt32_to_cpu(intr[0]);
+	*trig = INTR_TRIGGER_CONFORM;
+	*pol = INTR_POLARITY_CONFORM;
+	return (0);
+}
+
+fdt_pic_decode_t fdt_pic_table[] = {
+	&fdt_pic_decode_ic,
+	NULL
+};
+
+
+
diff -r 7fffa673adcd -r a301a330526b head/sys/arm/tegra/files.tegra2
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/head/sys/arm/tegra/files.tegra2	Wed Aug 15 11:16:36 2012 +0300
@@ -0,0 +1,19 @@
+# $FreeBSD: head/sys/arm/tegra/files.tegra2 239280 2012-08-15 06:06:43Z gonzo $
+
+arm/arm/bus_space_asm_generic.S		standard
+arm/arm/bus_space_generic.c		standard
+arm/arm/cpufunc_asm_armv5.S		standard
+arm/arm/cpufunc_asm_arm11.S		standard
+arm/arm/cpufunc_asm_armv7.S		standard
+arm/arm/irq_dispatch.S			standard
+
+arm/arm/gic.c				standard
+arm/arm/mpcore_timer.c			standard
+
+arm/tegra/bus_space.c			standard
+arm/tegra/common.c			standard
+arm/tegra/tegra2_machdep.c		standard
+
+kern/kern_clocksource.c			standard
+
+dev/uart/uart_dev_ns8250.c		optional	uart
diff -r 7fffa673adcd -r a301a330526b head/sys/arm/tegra/std.tegra2
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/head/sys/arm/tegra/std.tegra2	Wed Aug 15 11:16:36 2012 +0300
@@ -0,0 +1,16 @@
+# nVidia Tegra 2 common options
+#$FreeBSD: head/sys/arm/tegra/std.tegra2 239280 2012-08-15 06:06:43Z gonzo $
+
+cpu		CPU_CORTEXA
+makeoption      ARM_LITTLE_ENDIAN
+
+options		PHYSADDR=0x00000000
+
+makeoptions	KERNPHYSADDR=0x00200000
+options		KERNPHYSADDR=0x00200000
+makeoptions	KERNVIRTADDR=0xc0200000
+options		KERNVIRTADDR=0xc0200000
+
+options		STARTUP_PAGETABLE_ADDR=0x00100000
+
+files	"../tegra/files.tegra2"
diff -r 7fffa673adcd -r a301a330526b head/sys/arm/tegra/tegra2_machdep.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/head/sys/arm/tegra/tegra2_machdep.c	Wed Aug 15 11:16:36 2012 +0300
@@ -0,0 +1,705 @@
+/*-
+ * Copyright (c) 2011 Damjan Marion.
+ * 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.
+ *
+ * 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.
+ *
+ * from: FreeBSD: //depot/projects/arm/src/sys/arm/mv/mv_machdep.c
+ */
+
+#include "opt_ddb.h"
+#include "opt_platform.h"
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: head/sys/arm/tegra/tegra2_machdep.c 239280 2012-08-15 06:06:43Z gonzo $");
+
+#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 <dev/fdt/fdt_common.h>
+#include <dev/ofw/openfirm.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 <vm/vnode_pager.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>
+
+/* FIXME move to tegrareg.h */
+#define TEGRA2_BASE			0xE0000000	/* KVM base for peripherials */
+#define TEGRA2_UARTA_VA_BASE		0xE1006000
+#define TEGRA2_UARTA_PA_BASE		0x70006000
+
+
+
+
+
+#define KERNEL_PT_MAX	78
+#define IRQ_STACK_SIZE	1
+#define ABT_STACK_SIZE	1
+#define UND_STACK_SIZE	1
+#define FIQ_STACK_SIZE	1
+
+#define PTE_DEVICE  3
+
+#define debugf(fmt, args...) printf(fmt, ##args)
+
+#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)
+
+#ifdef DDB
+extern vm_offset_t ksym_start, ksym_end;
+#endif
+
+
+extern unsigned char kernbase[];
+extern unsigned char _etext[];
+extern unsigned char _edata[];
+extern unsigned char __bss_start[];
+extern unsigned char _end[];
+
+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[KERNEL_PT_MAX];
+
+
+
+static struct pv_addr	kernel_l1pt;				/* Level-1 page table entry */
+
+/* Physical and virtual addresses for some global pages */
+
+vm_paddr_t phys_avail[10];
+vm_paddr_t dump_avail[4];
+
+static struct mem_region availmem_regions[FDT_MEM_REGIONS];
+static int availmem_regions_sz;
+
+extern vm_offset_t pmap_bootstrap_lastaddr;
+
+vm_offset_t pmap_bootstrap_lastaddr;
+
+const struct pmap_devmap *pmap_devmap_bootstrap_table;
+struct pv_addr systempage;
+struct pv_addr msgbufpv;
+static struct pv_addr	fiqstack;
+static struct pv_addr	irqstack;
+static struct pv_addr	undstack;
+static struct pv_addr	abtstack;
+static struct pv_addr	kernelstack;
+
+#define PHYS2VIRT(x)	((x - KERNPHYSADDR) + KERNVIRTADDR)
+#define VIRT2PHYS(x)	((x - KERNVIRTADDR) + KERNPHYSADDR)
+
+static int platform_devmap_init(void);
+
+static char *
+kenv_next(char *cp)
+{
+
+	if (cp != NULL) {
+		while (*cp != 0)
+			cp++;
+		cp++;
+		if (*cp == 0)
+			cp = NULL;
+	}
+	return (cp);
+}
+
+
+/*
+ *  Early Print 
+ */
+
+#define DEBUGBUF_SIZE 256
+#define LSR_THRE    0x20	/* Xmit holding register empty */
+#define EARLY_UART_VA_BASE	TEGRA2_UARTA_VA_BASE
+#define EARLY_UART_PA_BASE	TEGRA2_UARTA_PA_BASE
+char debugbuf[DEBUGBUF_SIZE];
+
+void early_putstr(unsigned char *str)
+{
+	volatile uint8_t *p_lsr = (volatile uint8_t*) (EARLY_UART_VA_BASE + 0x14);
+	volatile uint8_t *p_thr = (volatile uint8_t*) (EARLY_UART_VA_BASE + 0x00);
+	
+	do {
+		while ((*p_lsr & LSR_THRE) == 0);
+		*p_thr = *str;
+
+		if (*str == '\n')
+		{
+			while ((*p_lsr & LSR_THRE) == 0);
+			*p_thr = '\r';
+		}
+	} while (*++str != '\0');
+}
+
+#if (STARTUP_PAGETABLE_ADDR < PHYSADDR) || \
+    (STARTUP_PAGETABLE_ADDR > (PHYSADDR + (64 * 1024 * 1024)))
+#error STARTUP_PAGETABLE_ADDR is not within init. MMU table, early print support not possible
+#endif
+
+void
+early_print_init(void)
+{
+	volatile uint32_t *mmu_tbl = (volatile uint32_t*)STARTUP_PAGETABLE_ADDR;
+	mmu_tbl[(EARLY_UART_VA_BASE >> L1_S_SHIFT)] = L1_TYPE_S | L1_S_AP(AP_KRW) | (EARLY_UART_PA_BASE & L1_S_FRAME);
+	__asm __volatile ("mcr	p15, 0, r0, c8, c7, 0");	/* invalidate I+D TLBs */
+	__asm __volatile ("mcr	p15, 0, r0, c7, c10, 4");	/* drain the write buffer */
+	early_putstr("Early printf initialise\n");
+}
+
+#define EPRINTF(args...) \
+	snprintf(debugbuf,DEBUGBUF_SIZE, ##args ); \
+	early_putstr(debugbuf);
+
+static void
+print_kenv(void)
+{
+	int len;
+	char *cp;
+
+	debugf("loader passed (static) kenv:\n");
+	if (kern_envp == NULL) {
+		debugf(" no env, null ptr\n");
+		return;
+	}
+	debugf(" kern_envp = 0x%08x\n", (uint32_t)kern_envp);
+
+	len = 0;
+	for (cp = kern_envp; cp != NULL; cp = kenv_next(cp))
+		debugf(" %x %s\n", (uint32_t)cp, cp);
+}
+
+static void
+print_kernel_section_addr(void)
+{
+
+	debugf("kernel image addresses:\n");
+	debugf(" kernbase       = 0x%08x\n", (uint32_t)kernbase);
+	debugf(" _etext (sdata) = 0x%08x\n", (uint32_t)_etext);
+	debugf(" _edata         = 0x%08x\n", (uint32_t)_edata);
+	debugf(" __bss_start    = 0x%08x\n", (uint32_t)__bss_start);
+	debugf(" _end           = 0x%08x\n", (uint32_t)_end);
+}
+
+static void
+physmap_init(void)
+{
+	int i, j, cnt;
+	vm_offset_t phys_kernelend, kernload;
+	uint32_t s, e, sz;
+	struct mem_region *mp, *mp1;
+
+	phys_kernelend = KERNPHYSADDR + (virtual_avail - KERNVIRTADDR);
+	kernload = KERNPHYSADDR;
+
+	/*
+	 * Remove kernel physical address range from avail
+	 * regions list. Page align all regions.
+	 * Non-page aligned memory isn't very interesting to us.
+	 * Also, sort the entries for ascending addresses.
+	 */
+	sz = 0;
+	cnt = availmem_regions_sz;
+	debugf("processing avail regions:\n");
+	for (mp = availmem_regions; mp->mr_size; mp++) {
+		s = mp->mr_start;
+		e = mp->mr_start + mp->mr_size;
+		debugf(" %08x-%08x -> ", s, e);
+		/* Check whether this region holds all of the kernel. */
+		if (s < kernload && e > phys_kernelend) {
+			availmem_regions[cnt].mr_start = phys_kernelend;
+			availmem_regions[cnt++].mr_size = e - phys_kernelend;
+			e = kernload;
+		}
+		/* Look whether this regions starts within the kernel. */
+		if (s >= kernload && s < phys_kernelend) {
+			if (e <= phys_kernelend)
+				goto empty;
+			s = phys_kernelend;
+		}
+		/* Now look whether this region ends within the kernel. */
+		if (e > kernload && e <= phys_kernelend) {
+			if (s >= kernload) {
+				goto empty;
+			}
+			e = kernload;
+		}
+		/* Now page align the start and size of the region. */
+		s = round_page(s);
+		e = trunc_page(e);
+		if (e < s)
+			e = s;
+		sz = e - s;
+		debugf("%08x-%08x = %x\n", s, e, sz);
+
+		/* Check whether some memory is left here. */
+		if (sz == 0) {
+		empty:
+			printf("skipping\n");
+			bcopy(mp + 1, mp,
+			    (cnt - (mp - availmem_regions)) * sizeof(*mp));
+			cnt--;
+			mp--;
+			continue;
+		}
+
+		/* Do an insertion sort. */
+		for (mp1 = availmem_regions; mp1 < mp; mp1++)
+			if (s < mp1->mr_start)
+				break;
+		if (mp1 < mp) {
+			bcopy(mp1, mp1 + 1, (char *)mp - (char *)mp1);
+			mp1->mr_start = s;
+			mp1->mr_size = sz;
+		} else {
+			mp->mr_start = s;
+			mp->mr_size = sz;
+		}
+	}
+	availmem_regions_sz = cnt;
+
+	/* Fill in phys_avail table, based on availmem_regions */
+	debugf("fill in phys_avail:\n");
+	for (i = 0, j = 0; i < availmem_regions_sz; i++, j += 2) {
+
+		debugf(" region: 0x%08x - 0x%08x (0x%08x)\n",
+		    availmem_regions[i].mr_start,
+		    availmem_regions[i].mr_start + availmem_regions[i].mr_size,
+		    availmem_regions[i].mr_size);
+
+		phys_avail[j] = availmem_regions[i].mr_start;
+		phys_avail[j + 1] = availmem_regions[i].mr_start +
+		    availmem_regions[i].mr_size;
+	}
+	phys_avail[j] = 0;
+	phys_avail[j + 1] = 0;
+}
+
+#define TEGRA2_CLK_RST_PA_BASE		0x60006000
+
+#define TEGRA2_CLK_RST_OSC_FREQ_DET_REG		0x58
+#define TEGRA2_CLK_RST_OSC_FREQ_DET_STAT_REG	0x5C
+#define OSC_FREQ_DET_TRIG			(1<<31)
+#define OSC_FREQ_DET_BUSY               	(1<<31)
+
+static int
+tegra2_osc_freq_detect(void)
+{
+	bus_space_handle_t	bsh;
+	uint32_t		c;
+	uint32_t		r=0;
+	int			i=0;
+
+	struct {
+		uint32_t val;
+		uint32_t freq;
+	} freq_det_cnts[] = {
+		{ 732,  12000000 },
+		{ 794,  13000000 },
+		{1172,  19200000 },
+		{1587,  26000000 },
+		{  -1,         0 },
+	};
+
+	printf("Measuring...\n");
+	bus_space_map(fdtbus_bs_tag,TEGRA2_CLK_RST_PA_BASE, 0x1000, 0, &bsh);
+
+	bus_space_write_4(fdtbus_bs_tag, bsh, TEGRA2_CLK_RST_OSC_FREQ_DET_REG,
+			OSC_FREQ_DET_TRIG | 1 );
+	do {} while (bus_space_read_4(fdtbus_bs_tag, bsh,
+			TEGRA2_CLK_RST_OSC_FREQ_DET_STAT_REG) & OSC_FREQ_DET_BUSY);
+
+	c = bus_space_read_4(fdtbus_bs_tag, bsh, TEGRA2_CLK_RST_OSC_FREQ_DET_STAT_REG);
+
+	while (freq_det_cnts[i].val > 0) {
+		if (((freq_det_cnts[i].val - 3) < c) && (c < (freq_det_cnts[i].val + 3)))
+			r = freq_det_cnts[i].freq;
+		i++;
+	}
+	printf("c=%u r=%u\n",c,r );
+	bus_space_free(fdtbus_bs_tag, bsh, 0x1000);
+	return r;
+}
+
+void *
+initarm(void *mdp, void *unused __unused)
+{
+	vm_offset_t	freemempos;
+	vm_offset_t	dtbp;
+	vm_offset_t	lastaddr;
+	vm_offset_t	l2_start;
+	struct pv_addr	dpcpu;
+	uint32_t	memsize = 0;
+	u_int		l1pagetable;
+	uint32_t	l2size;
+	int		i = 0;
+	int		j = 0;
+	void *kmdp;
+
+	lastaddr = 0;
+	dtbp = (vm_offset_t)NULL;
+
+	/* FIXME */
+	early_print_init();
+
+#define PHYS2VIRT(x)	((x - KERNPHYSADDR) + KERNVIRTADDR)
+#define VIRT2PHYS(x)	((x - KERNVIRTADDR) + KERNPHYSADDR)
+
+#define VALLOC_PAGES(var, np)                   \
+        ALLOC_PAGES((var).pv_pa, (np));         \
+        (var).pv_va = PHYS2VIRT((var).pv_pa);
+
+#define ALLOC_PAGES(var, np)                    \
+        (var) = freemempos;			\
+        freemempos += (np * PAGE_SIZE);         \
+        memset((char *)(var), 0, ((np) * PAGE_SIZE));
+
+#define ROUND_L_PAGE(x) (((x) + L2_L_OFFSET) & L2_L_FRAME)
+
+	set_cpufuncs();
+
+	/*
+	 * Mask metadata pointer: it is supposed to be on page boundary. If
+	 * the first argument (mdp) doesn't point to a valid address the
+	 * bootloader must have passed us something else than the metadata
+	 * ptr... In this case we want to fall back to some built-in settings.
+	 */
+	mdp = (void *)((uint32_t)mdp & ~PAGE_MASK);
+
+	/* Parse metadata and fetch parameters */
+	if (mdp != NULL) {
+		preload_metadata = mdp;
+		kmdp = preload_search_by_type("elf kernel");
+		if (kmdp != NULL) {
+			boothowto = MD_FETCH(kmdp, MODINFOMD_HOWTO, int);
+			kern_envp = MD_FETCH(kmdp, MODINFOMD_ENVP, char *);
+			dtbp = MD_FETCH(kmdp, MODINFOMD_DTBP, vm_offset_t);
+			lastaddr = MD_FETCH(kmdp, MODINFOMD_KERNEND,
+			    vm_offset_t);
+#ifdef DDB
+			ksym_start = MD_FETCH(kmdp, MODINFOMD_SSYM, uintptr_t);
+			ksym_end = MD_FETCH(kmdp, MODINFOMD_ESYM, uintptr_t);
+#endif
+		}
+
+		preload_addr_relocate = KERNVIRTADDR - KERNPHYSADDR;
+	} else {
+		/* Fall back to hardcoded metadata. */
+		lastaddr = fake_preload_metadata();
+	}
+
+#if defined(FDT_DTB_STATIC)
+	/*
+	 * In case the device tree blob was not retrieved (from metadata) try
+	 * to use the statically embedded one.
+	 */
+	if (dtbp == (vm_offset_t)NULL)
+		dtbp = (vm_offset_t)&fdt_static_dtb;
+#endif
+
+	if (OF_install(OFW_FDT, 0) == FALSE)
+		while (1);
+
+	if (OF_init((void *)dtbp) != 0)
+		while (1);
+
+	/* Grab physical memory regions information from device tree. */
+	if (fdt_get_mem_regions(availmem_regions, &availmem_regions_sz,
+	    &memsize) != 0)
+		while(1);
+
+	if (fdt_immr_addr(TEGRA2_BASE) != 0)				/* FIXME ???? */
+		while (1);
+
+	pmap_bootstrap_lastaddr = fdt_immr_va - ARM_NOCACHE_KVA_SIZE;
+
+	pcpu0_init();
+
+	/* Calculate number of L2 tables needed for mapping vm_page_array */
+	l2size = (memsize / PAGE_SIZE) * sizeof(struct vm_page);
+	l2size = (l2size >> L1_S_SHIFT) + 1;
+
+	/*
+	 * Add one table for end of kernel map, one for stacks, msgbuf and
+	 * L1 and L2 tables map and one for vectors map and make it div by 4.
+	 */
+	l2size += 3;
+	l2size = (l2size + 3) & ~3;
+
+	freemempos = VIRT2PHYS(ROUND_L_PAGE(lastaddr));
+
+	VALLOC_PAGES(kernel_l1pt, L1_TABLE_SIZE / PAGE_SIZE);
+
+	for (i = 0; i < l2size; ++i) {
+		if (!(i % (PAGE_SIZE / L2_TABLE_SIZE_REAL))) {
+			VALLOC_PAGES(kernel_pt_table[i],
+			    L2_TABLE_SIZE / PAGE_SIZE);
+			j = i;
+		} else {
+			kernel_pt_table[i].pv_va = kernel_pt_table[j].pv_va +
+			    L2_TABLE_SIZE_REAL * (i - j);
+			kernel_pt_table[i].pv_pa =
+			    kernel_pt_table[i].pv_va - KERNVIRTADDR +
+			    KERNPHYSADDR;
+
+		}
+	}
+	/*
+	 * Allocate a page for the system page mapped to 0x00000000
+	 * or 0xffff0000. This page will just contain the system vectors
+	 * and can be shared by all processes.
+	 */
+
+	VALLOC_PAGES(systempage, 1);
+ 	EPRINTF("systempage PA:0x%08x VA:0x%08x\n", systempage.pv_pa, systempage.pv_va);
+
+	/* 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(fiqstack, FIQ_STACK_SIZE);
+	VALLOC_PAGES(irqstack, IRQ_STACK_SIZE);
+	VALLOC_PAGES(abtstack, ABT_STACK_SIZE);
+	VALLOC_PAGES(undstack, UND_STACK_SIZE);
+	VALLOC_PAGES(kernelstack, KSTACK_PAGES);
+
+	init_param1();
+
+	VALLOC_PAGES(msgbufpv, round_page(msgbufsize) / 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;
+
+	/*
+	 * Try to map as much as possible of kernel text and data using
+	 * 1MB section mapping and for the rest of initial kernel address
+	 * space use L2 coarse tables.
+	 *
+	 * Link L2 tables for mapping remainder of kernel (modulo 1MB)
+	 * and kernel structures
+	 */
+	l2_start = lastaddr & ~(L1_S_OFFSET);
+	for (i = 0 ; i < l2size - 1; i++)
+		pmap_link_l2pt(l1pagetable, l2_start + i * L1_S_SIZE,
+		    &kernel_pt_table[i]);
+
+	pmap_curmaxkvaddr = l2_start + (l2size - 1) * L1_S_SIZE;
+
+	/* Map kernel code and data */
+	pmap_map_chunk(l1pagetable, KERNVIRTADDR, KERNPHYSADDR,
+	   (((uint32_t)(lastaddr) - KERNVIRTADDR) + PAGE_MASK) & ~PAGE_MASK,
+	    VM_PROT_READ|VM_PROT_WRITE, PTE_CACHE);
+
+	/* Map L1 directory and allocated L2 page tables */
+	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, kernel_pt_table[0].pv_va,
+	    kernel_pt_table[0].pv_pa,
+	    L2_TABLE_SIZE_REAL * l2size,
+	    VM_PROT_READ|VM_PROT_WRITE, PTE_PAGETABLE);
+
+	/* Map allocated DPCPU, stacks and msgbuf */
+	pmap_map_chunk(l1pagetable, dpcpu.pv_va, dpcpu.pv_pa,
+	     PHYS2VIRT(freemempos) - dpcpu.pv_va,
+	    VM_PROT_READ|VM_PROT_WRITE, PTE_CACHE);
+
+	/* Link and map the vector page */
+	pmap_link_l2pt(l1pagetable, ARM_VECTORS_HIGH,
+	    &kernel_pt_table[l2size - 1]);
+	pmap_map_entry(l1pagetable, ARM_VECTORS_HIGH, systempage.pv_pa,
+	    VM_PROT_READ|VM_PROT_WRITE|VM_PROT_EXECUTE, PTE_CACHE);
+
+	/* Map pmap_devmap[] entries */
+	if (platform_devmap_init() != 0)
+		while (1);
+	pmap_devmap_bootstrap(l1pagetable, pmap_devmap_bootstrap_table);
+
+	/* Switch L1 table */
+	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)));
+
+	OF_interpret("perform-fixup", 0);
+
+	cninit();
+	physmem = memsize / PAGE_SIZE;
+
+	debugf("initarm: console initialized\n");
+	debugf(" arg1 mdp = 0x%08x\n", (uint32_t)mdp);
+	debugf(" boothowto = 0x%08x\n", boothowto);
+	printf(" dtbp = 0x%08x\n", (uint32_t)dtbp);
+	print_kernel_section_addr();
+	print_kenv();
+
+	/*
+	 * 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_FIQ32_MODE,
+	    fiqstack.pv_va + FIQ_STACK_SIZE * PAGE_SIZE);
+	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();
+
+	init_proc0(kernelstack.pv_va);
+	arm_vector_init(ARM_VECTORS_HIGH, ARM_VEC_ALL);
+
+	dump_avail[0] = 0;
+	dump_avail[1] = memsize;
+	dump_avail[2] = 0;
+	dump_avail[3] = 0;
+
+	pmap_bootstrap(PHYS2VIRT(freemempos), pmap_bootstrap_lastaddr, &kernel_l1pt);
+	msgbufp = (void *)msgbufpv.pv_va;
+	msgbufinit(msgbufp, msgbufsize);
+	mutex_init();
+
+	/*
+	 * Prepare map of physical memory regions available to vm subsystem.
+	 */
+
+	physmap_init();
+
+	/* Do basic tuning, hz etc */
+	init_param2(physmem);
+	kdb_init();
+	return ((void *)(kernelstack.pv_va + USPACE_SVC_STACK_TOP -
+	    sizeof(struct pcb)));
+}
+
+#define FDT_DEVMAP_MAX	(1 + 2 + 1 + 1)	/* FIXME */
+static struct pmap_devmap fdt_devmap[FDT_DEVMAP_MAX] = {
+	{ 0, 0, 0, 0, 0, }
+};
+
+/*
+ * Construct pmap_devmap[] with DT-derived config data.
+ */
+static int
+platform_devmap_init(void)
+{
+	int i = 0;
+	fdt_devmap[i].pd_va = 0xe0000000;
+	fdt_devmap[i].pd_pa = 0x70000000;
+	fdt_devmap[i].pd_size = 0x100000;
+	fdt_devmap[i].pd_prot = VM_PROT_READ | VM_PROT_WRITE;
+	fdt_devmap[i].pd_cache = PTE_NOCACHE;
+	i++;
+
+	pmap_devmap_bootstrap_table = &fdt_devmap[0];
+	return (0);
+}
+
+
+struct arm32_dma_range *
+bus_dma_get_range(void)
+{
+
+	return (NULL);
+}
+
+int
+bus_dma_get_range_nb(void)
+{
+
+	return (0);
+}
diff -r 7fffa673adcd -r a301a330526b head/sys/arm/ti/aintc.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/head/sys/arm/ti/aintc.c	Wed Aug 15 11:16:36 2012 +0300
@@ -0,0 +1,179 @@
+/*-
+ * Copyright (c) 2012 Damjan Marion <dmarion at Freebsd.org>
+ * All rights reserved.
+ *
+ * Based on OMAP3 INTC code by Ben Gray
+ *
+ * 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.
+ */
+
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: head/sys/arm/ti/aintc.c 239281 2012-08-15 06:31:32Z gonzo $");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/bus.h>
+#include <sys/kernel.h>
+#include <sys/ktr.h>
+#include <sys/module.h>
+#include <sys/rman.h>
+#include <machine/bus.h>
+#include <machine/intr.h>
+
+#include <dev/fdt/fdt_common.h>
+#include <dev/ofw/openfirm.h>
+#include <dev/ofw/ofw_bus.h>
+#include <dev/ofw/ofw_bus_subr.h>
+
+#define INTC_REVISION		0x00
+#define INTC_SYSCONFIG		0x10
+#define INTC_SYSSTATUS		0x14
+#define INTC_SIR_IRQ		0x40
+#define INTC_CONTROL		0x48
+#define INTC_THRESHOLD		0x68
+#define INTC_MIR_CLEAR(x)	(0x88 + ((x) * 0x20))
+#define INTC_MIR_SET(x)		(0x8C + ((x) * 0x20))
+#define INTC_ISR_SET(x)		(0x90 + ((x) * 0x20))
+#define INTC_ISR_CLEAR(x)	(0x94 + ((x) * 0x20))
+
+struct ti_aintc_softc {
+	device_t		sc_dev;
+	struct resource *	aintc_res[3];
+	bus_space_tag_t		aintc_bst;
+	bus_space_handle_t	aintc_bsh;
+	uint8_t			ver;
+};
+
+static struct resource_spec ti_aintc_spec[] = {
+	{ SYS_RES_MEMORY,	0,	RF_ACTIVE },
+	{ -1, 0 }
+};
+
+
+static struct ti_aintc_softc *ti_aintc_sc = NULL;
+
+#define	aintc_read_4(reg)		\
+    bus_space_read_4(ti_aintc_sc->aintc_bst, ti_aintc_sc->aintc_bsh, reg)
+#define	aintc_write_4(reg, val)		\
+    bus_space_write_4(ti_aintc_sc->aintc_bst, ti_aintc_sc->aintc_bsh, reg, val)
+
+
+static int
+ti_aintc_probe(device_t dev)
+{
+	if (!ofw_bus_is_compatible(dev, "ti,aintc"))
+		return (ENXIO);
+	device_set_desc(dev, "TI AINTC Interrupt Controller");
+	return (BUS_PROBE_DEFAULT);
+}
+
+static int
+ti_aintc_attach(device_t dev)
+{
+	struct		ti_aintc_softc *sc = device_get_softc(dev);
+	uint32_t x;
+
+	sc->sc_dev = dev;
+
+	if (ti_aintc_sc)
+		return (ENXIO);
+
+	if (bus_alloc_resources(dev, ti_aintc_spec, sc->aintc_res)) {
+		device_printf(dev, "could not allocate resources\n");
+		return (ENXIO);
+	}
+
+	sc->aintc_bst = rman_get_bustag(sc->aintc_res[0]);
+	sc->aintc_bsh = rman_get_bushandle(sc->aintc_res[0]);
+
+	ti_aintc_sc = sc;
+
+	x = aintc_read_4(INTC_REVISION);
+	device_printf(dev, "Revision %u.%u\n",(x >> 4) & 0xF, x & 0xF);
+
+	/* SoftReset */
+	aintc_write_4(INTC_SYSCONFIG, 2);
+
+	/* Wait for reset to complete */
+	while(!(aintc_read_4(INTC_SYSSTATUS) & 1));
+
+	/*Set Priority Threshold */
+	aintc_write_4(INTC_THRESHOLD, 0xFF);
+
+	return (0);
+}
+
+static device_method_t ti_aintc_methods[] = {
+	DEVMETHOD(device_probe,		ti_aintc_probe),
+	DEVMETHOD(device_attach,	ti_aintc_attach),
+	{ 0, 0 }
+};
+
+static driver_t ti_aintc_driver = {
+	"aintc",
+	ti_aintc_methods,
+	sizeof(struct ti_aintc_softc),
+};
+
+static devclass_t ti_aintc_devclass;
+
+DRIVER_MODULE(aintc, simplebus, ti_aintc_driver, ti_aintc_devclass, 0, 0);
+
+int
+arm_get_next_irq(int last_irq)
+{
+	uint32_t active_irq;
+
+	if (last_irq != -1) {
+		aintc_write_4(INTC_ISR_CLEAR(last_irq >> 5),
+			1UL << (last_irq & 0x1F));
+		aintc_write_4(INTC_CONTROL,1);
+	}
+
+	/* Get the next active interrupt */
+	active_irq = aintc_read_4(INTC_SIR_IRQ);
+
+	/* Check for spurious interrupt */
+	if ((active_irq & 0xffffff80)) {
+		device_printf(ti_aintc_sc->sc_dev,
+			"Spurious interrupt detected (0x%08x)\n", active_irq);
+		return -1;
+	}
+
+	if (active_irq != last_irq)
+		return active_irq;
+	else
+		return -1;
+}
+
+void
+arm_mask_irq(uintptr_t nb)
+{
+	aintc_write_4(INTC_MIR_SET(nb >> 5), (1UL << (nb & 0x1F)));
+}
+
+void
+arm_unmask_irq(uintptr_t nb)
+{
+	aintc_write_4(INTC_MIR_CLEAR(nb >> 5), (1UL << (nb & 0x1F)));
+}
diff -r 7fffa673adcd -r a301a330526b head/sys/arm/ti/am335x/am335x_dmtimer.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/head/sys/arm/ti/am335x/am335x_dmtimer.c	Wed Aug 15 11:16:36 2012 +0300
@@ -0,0 +1,385 @@
+/*-
+ * Copyright (c) 2012 Damjan Marion <dmarion at Freebsd.org>
+ * 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.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: head/sys/arm/ti/am335x/am335x_dmtimer.c 239281 2012-08-15 06:31:32Z gonzo $");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/bus.h>
+#include <sys/kernel.h>
+#include <sys/module.h>
+#include <sys/malloc.h>
+#include <sys/rman.h>
+#include <sys/timeet.h>
+#include <sys/timetc.h>
+#include <sys/watchdog.h>
+#include <machine/bus.h>
+#include <machine/cpu.h>
+#include <machine/frame.h>
+#include <machine/intr.h>
+
+#include <dev/fdt/fdt_common.h>
+#include <dev/ofw/openfirm.h>
+#include <dev/ofw/ofw_bus.h>
+#include <dev/ofw/ofw_bus_subr.h>
+
+#include <machine/bus.h>
+#include <machine/fdt.h>
+
+#include <arm/ti/ti_prcm.h>
+
+#define AM335X_NUM_TIMERS	8
+
+#define DMTIMER_TIDR		0x00 /* Identification Register */
+#define DMTIMER_TIOCP_CFG	0x10 /* Timer OCP Configuration Reg */
+#define DMTIMER_IQR_EOI		0x20 /* Timer IRQ End-Of-Interrupt Reg */
+#define DMTIMER_IRQSTATUS_RAW	0x24 /* Timer IRQSTATUS Raw Reg */
+#define DMTIMER_IRQSTATUS	0x28 /* Timer IRQSTATUS Reg */
+#define DMTIMER_IRQENABLE_SET	0x2c /* Timer IRQSTATUS Set Reg */
+#define DMTIMER_IRQENABLE_CLR	0x30 /* Timer IRQSTATUS Clear Reg */
+#define DMTIMER_IRQWAKEEN	0x34 /* Timer IRQ Wakeup Enable Reg */
+#define DMTIMER_TCLR		0x38 /* Timer Control Register */
+#define DMTIMER_TCRR		0x3C /* Timer Counter Register */
+#define DMTIMER_TLDR		0x40 /* Timer Load Reg */
+#define DMTIMER_TTGR		0x44 /* Timer Trigger Reg */
+#define DMTIMER_TWPS		0x48 /* Timer Write Posted Status Reg */
+#define DMTIMER_TMAR		0x4C /* Timer Match Reg */
+#define DMTIMER_TCAR1		0x50 /* Timer Capture Reg */
+#define DMTIMER_TSICR		0x54 /* Timer Synchr. Interface Control Reg */
+#define DMTIMER_TCAR2		0x48 /* Timer Capture Reg */
+ 
+
+struct am335x_dmtimer_softc {
+	struct resource *	tmr_mem_res[AM335X_NUM_TIMERS];
+	struct resource *	tmr_irq_res[AM335X_NUM_TIMERS];
+	uint32_t		sysclk_freq;
+	struct am335x_dmtimer {
+		bus_space_tag_t		bst;
+		bus_space_handle_t	bsh;
+		struct eventtimer	et;
+	} t[AM335X_NUM_TIMERS];
+};
+
+static struct resource_spec am335x_dmtimer_mem_spec[] = {
+	{ SYS_RES_MEMORY,   0,  RF_ACTIVE },
+	{ SYS_RES_MEMORY,   1,  RF_ACTIVE },
+	{ SYS_RES_MEMORY,   2,  RF_ACTIVE },
+	{ SYS_RES_MEMORY,   3,  RF_ACTIVE },
+	{ SYS_RES_MEMORY,   4,  RF_ACTIVE },
+	{ SYS_RES_MEMORY,   5,  RF_ACTIVE },
+	{ SYS_RES_MEMORY,   6,  RF_ACTIVE },
+	{ SYS_RES_MEMORY,   7,  RF_ACTIVE },
+	{ -1,               0,  0 }
+};
+static struct resource_spec am335x_dmtimer_irq_spec[] = {
+	{ SYS_RES_IRQ,      0,  RF_ACTIVE },
+	{ SYS_RES_IRQ,      1,  RF_ACTIVE },
+	{ SYS_RES_IRQ,      2,  RF_ACTIVE },
+	{ SYS_RES_IRQ,      3,  RF_ACTIVE },
+	{ SYS_RES_IRQ,      4,  RF_ACTIVE },
+	{ SYS_RES_IRQ,      5,  RF_ACTIVE },
+	{ SYS_RES_IRQ,      6,  RF_ACTIVE },
+	{ SYS_RES_IRQ,      7,  RF_ACTIVE },
+	{ -1,               0,  0 }
+};
+
+static struct am335x_dmtimer *am335x_dmtimer_tc_tmr = NULL;
+
+/* Read/Write macros for Timer used as timecounter */
+#define am335x_dmtimer_tc_read_4(reg)		\
+	bus_space_read_4(am335x_dmtimer_tc_tmr->bst, \
+		am335x_dmtimer_tc_tmr->bsh, reg)
+
+#define am335x_dmtimer_tc_write_4(reg, val)	\
+	bus_space_write_4(am335x_dmtimer_tc_tmr->bst, \
+		am335x_dmtimer_tc_tmr->bsh, reg, val)
+
+/* Read/Write macros for Timer used as eventtimer */
+#define am335x_dmtimer_et_read_4(reg)		\
+	bus_space_read_4(tmr->bst, tmr->bsh, reg)
+
+#define am335x_dmtimer_et_write_4(reg, val)	\
+	bus_space_write_4(tmr->bst, tmr->bsh, reg, val)
+
+static unsigned am335x_dmtimer_tc_get_timecount(struct timecounter *);
+
+static struct timecounter am335x_dmtimer_tc = {
+	.tc_name           = "AM335x Timecouter",
+	.tc_get_timecount  = am335x_dmtimer_tc_get_timecount,
+	.tc_poll_pps       = NULL,
+	.tc_counter_mask   = ~0u,
+	.tc_frequency      = 0,
+	.tc_quality        = 1000,
+};
+
+static unsigned
+am335x_dmtimer_tc_get_timecount(struct timecounter *tc)
+{
+	return am335x_dmtimer_tc_read_4(DMTIMER_TCRR);
+}
+
+static int
+am335x_dmtimer_start(struct eventtimer *et, struct bintime *first,
+              struct bintime *period)
+{
+	struct am335x_dmtimer *tmr = (struct am335x_dmtimer *)et->et_priv;
+	uint32_t load, count;
+	uint32_t tclr = 0;
+
+	if (period != NULL) {
+		load = (et->et_frequency * (period->frac >> 32)) >> 32;
+		if (period->sec > 0)
+			load += et->et_frequency * period->sec;
+		tclr |= 2; /* autoreload bit */
+		panic("periodic timer not implemented\n");
+	} else {
+		load = 0;
+	}
+
+	if (first != NULL) {
+		count = (tmr->et.et_frequency * (first->frac >> 32)) >> 32;
+		if (first->sec != 0)
+			count += tmr->et.et_frequency * first->sec;
+	} else {
+		count = load;
+	}
+
+	/* Reset Timer */
+	am335x_dmtimer_et_write_4(DMTIMER_TSICR, 2);
+
+	/* Wait for reset to complete */
+	while (am335x_dmtimer_et_read_4(DMTIMER_TIOCP_CFG) & 1);
+
+	/* set load value */
+	am335x_dmtimer_et_write_4(DMTIMER_TLDR, 0xFFFFFFFE - load);
+
+	/* set counter value */
+	am335x_dmtimer_et_write_4(DMTIMER_TCRR, 0xFFFFFFFE - count);
+
+	/* enable overflow interrupt */
+	am335x_dmtimer_et_write_4(DMTIMER_IRQENABLE_SET, 2);
+
+	/* start timer(ST) */
+	tclr |= 1;
+	am335x_dmtimer_et_write_4(DMTIMER_TCLR, tclr);
+
+	return (0);
+}
+
+static int
+am335x_dmtimer_stop(struct eventtimer *et)
+{
+	struct am335x_dmtimer *tmr = (struct am335x_dmtimer *)et->et_priv;
+
+	/* Disable all interrupts */
+	am335x_dmtimer_et_write_4(DMTIMER_IRQENABLE_CLR, 7);
+
+	/* Stop Timer */
+	am335x_dmtimer_et_write_4(DMTIMER_TCLR, 0);
+
+	return (0);
+}
+
+static int
+am335x_dmtimer_intr(void *arg)
+{
+	struct am335x_dmtimer *tmr = (struct am335x_dmtimer *)arg;
+
+	/* Ack interrupt */
+	am335x_dmtimer_et_write_4(DMTIMER_IRQSTATUS, 7);
+	if (tmr->et.et_active)
+		tmr->et.et_event_cb(&tmr->et, tmr->et.et_arg);
+
+	return (FILTER_HANDLED);
+}
+
+static int
+am335x_dmtimer_probe(device_t dev)
+{
+	struct	am335x_dmtimer_softc *sc;
+	sc = (struct am335x_dmtimer_softc *)device_get_softc(dev);
+
+	if (ofw_bus_is_compatible(dev, "ti,am335x-dmtimer")) {
+		device_set_desc(dev, "AM335x DMTimer");
+		return(BUS_PROBE_DEFAULT);
+	}
+
+	return (ENXIO);
+}
+
+static int
+am335x_dmtimer_attach(device_t dev)
+{
+	struct am335x_dmtimer_softc *sc = device_get_softc(dev);
+	void *ihl;
+	int err;
+	int i;
+
+	if (am335x_dmtimer_tc_tmr != NULL)
+		return (EINVAL);
+
+	/* Get the base clock frequency */
+	err = ti_prcm_clk_get_source_freq(SYS_CLK, &sc->sysclk_freq);
+	if (err) {
+		device_printf(dev, "Error: could not get sysclk frequency\n");
+		return (ENXIO);
+	}
+
+	/* Request the memory resources */
+	err = bus_alloc_resources(dev, am335x_dmtimer_mem_spec,
+		sc->tmr_mem_res);
+	if (err) {
+		device_printf(dev, "Error: could not allocate mem resources\n");
+		return (ENXIO);
+	}
+
+	/* Request the IRQ resources */
+	err = bus_alloc_resources(dev, am335x_dmtimer_irq_spec,
+		sc->tmr_irq_res);
+	if (err) {
+		device_printf(dev, "Error: could not allocate irq resources\n");
+		return (ENXIO);
+	}
+
+	for(i=0;i<AM335X_NUM_TIMERS;i++) {
+		sc->t[i].bst = rman_get_bustag(sc->tmr_mem_res[i]);
+		sc->t[i].bsh = rman_get_bushandle(sc->tmr_mem_res[i]);
+	}
+
+	/* Configure DMTimer2 and DMTimer3 source and enable them */
+	err  = ti_prcm_clk_set_source(DMTIMER2_CLK, SYSCLK_CLK);
+	err |= ti_prcm_clk_enable(DMTIMER2_CLK);
+	err |= ti_prcm_clk_set_source(DMTIMER3_CLK, SYSCLK_CLK);
+	err |= ti_prcm_clk_enable(DMTIMER3_CLK);
+	if (err) {
+		device_printf(dev, "Error: could not setup timer clock\n");
+		return (ENXIO);
+	}
+
+	/* Take DMTimer2 for TC */
+	am335x_dmtimer_tc_tmr = &sc->t[2];
+
+	/* Reset Timer */
+	am335x_dmtimer_tc_write_4(DMTIMER_TSICR, 2);
+
+	/* Wait for reset to complete */
+	while (am335x_dmtimer_tc_read_4(DMTIMER_TIOCP_CFG) & 1);
+
+	/* set load value */
+	am335x_dmtimer_tc_write_4(DMTIMER_TLDR, 0);
+
+	/* set counter value */
+	am335x_dmtimer_tc_write_4(DMTIMER_TCRR, 0);
+
+	/* Set Timer autoreload(AR) and start timer(ST) */
+	am335x_dmtimer_tc_write_4(DMTIMER_TCLR, 3);
+
+	am335x_dmtimer_tc.tc_frequency = sc->sysclk_freq;
+	tc_init(&am335x_dmtimer_tc);
+
+	/* Register DMTimer3 as ET */
+
+	/* Setup and enable the timer */
+	if (bus_setup_intr(dev, sc->tmr_irq_res[3], INTR_TYPE_CLK,
+			am335x_dmtimer_intr, NULL, &sc->t[3], &ihl) != 0) {
+		bus_release_resources(dev, am335x_dmtimer_irq_spec,
+			sc->tmr_irq_res);
+		device_printf(dev, "Unable to setup the clock irq handler.\n");
+		return (ENXIO);
+	}
+
+	sc->t[3].et.et_name = "AM335x Eventtimer0";
+	sc->t[3].et.et_flags = ET_FLAGS_PERIODIC | ET_FLAGS_ONESHOT;
+	sc->t[3].et.et_quality = 1000;
+	sc->t[3].et.et_frequency = sc->sysclk_freq;
+	sc->t[3].et.et_min_period.sec = 0;
+	sc->t[3].et.et_min_period.frac =
+	    ((0x00000002LLU << 32) / sc->t[3].et.et_frequency) << 32;
+	sc->t[3].et.et_max_period.sec = 0xfffffff0U / sc->t[3].et.et_frequency;
+	sc->t[3].et.et_max_period.frac =
+	    ((0xfffffffeLLU << 32) / sc->t[3].et.et_frequency) << 32;
+	sc->t[3].et.et_start = am335x_dmtimer_start;
+	sc->t[3].et.et_stop = am335x_dmtimer_stop;
+	sc->t[3].et.et_priv = &sc->t[3];
+	et_register(&sc->t[3].et);
+
+	return (0);
+}
+
+static device_method_t am335x_dmtimer_methods[] = {
+	DEVMETHOD(device_probe,		am335x_dmtimer_probe),
+	DEVMETHOD(device_attach,	am335x_dmtimer_attach),
+	{ 0, 0 }
+};
+
+static driver_t am335x_dmtimer_driver = {
+	"am335x_dmtimer",
+	am335x_dmtimer_methods,
+	sizeof(struct am335x_dmtimer_softc),
+};
+
+static devclass_t am335x_dmtimer_devclass;
+
+DRIVER_MODULE(am335x_dmtimer, simplebus, am335x_dmtimer_driver, am335x_dmtimer_devclass, 0, 0);
+MODULE_DEPEND(am335x_dmtimer, am335x_prcm, 1, 1, 1);
+
+void
+cpu_initclocks(void)
+{
+	cpu_initclocks_bsp();
+}
+
+void
+DELAY(int usec)
+{
+		int32_t counts;
+	uint32_t first, last;
+
+	if (am335x_dmtimer_tc_tmr == NULL) {
+		for (; usec > 0; usec--)
+			for (counts = 200; counts > 0; counts--)
+				/* Prevent gcc from optimizing  out the loop */
+				cpufunc_nullop();
+		return;
+	}
+
+	/* Get the number of times to count */
+	counts = usec * ((am335x_dmtimer_tc.tc_frequency / 1000000) + 1);;
+
+	first = am335x_dmtimer_tc_read_4(DMTIMER_TCRR);
+
+	while (counts > 0) {
+		last = am335x_dmtimer_tc_read_4(DMTIMER_TCRR);
+		if (last>first) {
+			counts -= (int32_t)(last - first);
+		} else {
+			counts -= (int32_t)((0xFFFFFFFF - first) + last);
+		}
+		first = last;
+	}
+}
+
diff -r 7fffa673adcd -r a301a330526b head/sys/arm/ti/am335x/am335x_pmic.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/head/sys/arm/ti/am335x/am335x_pmic.c	Wed Aug 15 11:16:36 2012 +0300
@@ -0,0 +1,176 @@
+/*-
+ * Copyright (c) 2012 Damjan Marion <dmarion at Freebsd.org>
+ * 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.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: head/sys/arm/ti/am335x/am335x_pmic.c 239281 2012-08-15 06:31:32Z gonzo $");
+/*
+* TPS65217 PMIC companion chip for AM335x SoC sitting on I2C bus
+*/
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/module.h>
+#include <sys/clock.h>
+#include <sys/time.h>
+#include <sys/bus.h>
+#include <sys/resource.h>
+#include <sys/rman.h>
+
+#include <dev/iicbus/iicbus.h>
+#include <dev/iicbus/iiconf.h>
+
+#include <dev/ofw/openfirm.h>
+#include <dev/ofw/ofw_bus.h>
+#include <dev/ofw/ofw_bus_subr.h>
+
+#include "iicbus_if.h"
+
+#define TPS65217A		0x7
+#define TPS65217B		0xF
+
+/* TPS65217 Reisters */
+#define TPS65217_CHIPID_REG	0x00
+#define TPS65217_STATUS_REG	0x0A
+
+#define MAX_IIC_DATA_SIZE	2
+
+
+struct am335x_pmic_softc {
+	device_t		sc_dev;
+	uint32_t		sc_addr;
+	struct intr_config_hook enum_hook;
+};
+
+static int
+am335x_pmic_read(device_t dev, uint8_t addr, uint8_t *data, uint8_t size)
+{
+	struct am335x_pmic_softc *sc = device_get_softc(dev);
+	struct iic_msg msg[] = {
+		{ sc->sc_addr, IIC_M_WR, 1, &addr },
+		{ sc->sc_addr, IIC_M_RD, size, data },
+	};
+	return (iicbus_transfer(dev, msg, 2));
+}
+
+#ifdef notyet
+static int
+am335x_pmic_write(device_t dev, uint8_t address, uint8_t *data, uint8_t size)
+{
+	uint8_t buffer[MAX_IIC_DATA_SIZE + 1];
+	struct am335x_pmic_softc *sc = device_get_softc(dev);
+	struct iic_msg msg[] = {
+		{ sc->sc_addr, IIC_M_WR, size + 1, buffer },
+	};
+
+	if (size > MAX_IIC_DATA_SIZE)
+		return (ENOMEM);
+
+	buffer[0] = address;
+	memcpy(buffer + 1, data, size);
+
+	return (iicbus_transfer(dev, msg, 1));
+}
+#endif
+
+static int
+am335x_pmic_probe(device_t dev)
+{
+	struct am335x_pmic_softc *sc;
+
+	if (!ofw_bus_is_compatible(dev, "ti,am335x-pmic"))
+		return (ENXIO);
+
+	sc = device_get_softc(dev);
+	sc->sc_dev = dev;
+	sc->sc_addr = iicbus_get_addr(dev);
+
+	device_set_desc(dev, "TI TPS65217 Power Management IC");
+
+	return (0);
+}
+
+static void
+am335x_pmic_start(void *xdev)
+{
+	struct am335x_pmic_softc *sc;
+	device_t dev = (device_t)xdev;
+	uint8_t reg;
+	char name[20];
+	char pwr[4][11] = {"Unknown", "USB", "AC", "USB and AC"};
+
+	sc = device_get_softc(dev);
+
+	am335x_pmic_read(dev, TPS65217_CHIPID_REG, &reg, 1);
+	switch (reg>>4) {
+		case TPS65217A:
+			sprintf(name, "TPS65217A ver 1.%u", reg & 0xF);
+			break;
+		case TPS65217B:
+			sprintf(name, "TPS65217B ver 1.%u", reg & 0xF);
+			break;
+		default:
+			sprintf(name, "Unknown PMIC");
+	}
+
+	am335x_pmic_read(dev, TPS65217_STATUS_REG, &reg, 1);
+	device_printf(dev, "%s powered by %s\n", name, pwr[(reg>>2)&0x03]);
+
+	config_intrhook_disestablish(&sc->enum_hook);
+}
+
+static int
+am335x_pmic_attach(device_t dev)
+{
+	struct am335x_pmic_softc *sc;
+
+	sc = device_get_softc(dev);
+
+	sc->enum_hook.ich_func = am335x_pmic_start;
+	sc->enum_hook.ich_arg = dev;
+
+	if (config_intrhook_establish(&sc->enum_hook) != 0)
+		return (ENOMEM);
+
+	return (0);
+}
+
+static device_method_t am335x_pmic_methods[] = {
+	DEVMETHOD(device_probe,		am335x_pmic_probe),
+	DEVMETHOD(device_attach,	am335x_pmic_attach),
+	{0, 0},
+};
+
+static driver_t am335x_pmic_driver = {
+	"am335x_pmic",
+	am335x_pmic_methods,
+	sizeof(struct am335x_pmic_softc),
+};
+
+static devclass_t am335x_pmic_devclass;
+
+DRIVER_MODULE(am335x_pmic, iicbus, am335x_pmic_driver, am335x_pmic_devclass, 0, 0);
+MODULE_VERSION(am335x_pmic, 1);
+MODULE_DEPEND(am335x_pmic, iicbus, 1, 1, 1);
diff -r 7fffa673adcd -r a301a330526b head/sys/arm/ti/am335x/am335x_prcm.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/head/sys/arm/ti/am335x/am335x_prcm.c	Wed Aug 15 11:16:36 2012 +0300
@@ -0,0 +1,568 @@
+/*-
+ * Copyright (c) 2012 Damjan Marion <dmarion at Freebsd.org>
+ * 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.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: head/sys/arm/ti/am335x/am335x_prcm.c 239281 2012-08-15 06:31:32Z gonzo $");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/bus.h>
+#include <sys/kernel.h>
+#include <sys/module.h>
+#include <sys/malloc.h>
+#include <sys/rman.h>
+#include <sys/timeet.h>
+#include <sys/timetc.h>
+#include <sys/watchdog.h>
+#include <machine/bus.h>
+#include <machine/cpu.h>
+#include <machine/frame.h>
+#include <machine/intr.h>
+
+#include <arm/ti/tivar.h>
+#include <arm/ti/ti_scm.h>
+#include <arm/ti/ti_prcm.h>
+
+#include <dev/fdt/fdt_common.h>
+#include <dev/ofw/openfirm.h>
+#include <dev/ofw/ofw_bus.h>
+#include <dev/ofw/ofw_bus_subr.h>
+
+#include <machine/bus.h>
+#include <machine/fdt.h>
+
+#define CM_PER				0
+#define CM_PER_L4LS_CLKSTCTRL		(CM_PER + 0x000)
+#define CM_PER_L3S_CLKSTCTRL		(CM_PER + 0x004)
+#define CM_PER_L3_CLKSTCTRL		(CM_PER + 0x00C)
+#define CM_PER_CPGMAC0_CLKCTRL		(CM_PER + 0x014)
+#define CM_PER_USB0_CLKCTRL		(CM_PER + 0x01C)
+#define CM_PER_TPTC0_CLKCTRL		(CM_PER + 0x024)
+#define CM_PER_MMC0_CLKCTRL		(CM_PER + 0x03C)
+#define CM_PER_I2C2_CLKCTRL		(CM_PER + 0x044)
+#define CM_PER_I2C1_CLKCTRL		(CM_PER + 0x048)
+#define CM_PER_TIMER7_CLKCTRL		(CM_PER + 0x07C)
+#define CM_PER_TIMER2_CLKCTRL		(CM_PER + 0x080)
+#define CM_PER_TIMER3_CLKCTRL		(CM_PER + 0x084)
+#define CM_PER_TIMER4_CLKCTRL		(CM_PER + 0x088)
+#define CM_PER_GPIO1_CLKCTRL		(CM_PER + 0x0AC)
+#define CM_PER_GPIO2_CLKCTRL		(CM_PER + 0x0B0)
+#define CM_PER_GPIO3_CLKCTRL		(CM_PER + 0x0B4)
+#define CM_PER_TPCC_CLKCTRL		(CM_PER + 0x0BC)
+#define CM_PER_L3_INSTR_CLKCTRL		(CM_PER + 0x0DC)
+#define CM_PER_L3_CLKCTRL		(CM_PER + 0x0E0)
+#define CM_PER_TIMER5_CLKCTRL		(CM_PER + 0x0EC)
+#define CM_PER_TIMER6_CLKCTRL		(CM_PER + 0x0F0)
+#define CM_PER_MMC1_CLKCTRL		(CM_PER + 0x0F4)
+#define CM_PER_MMC2_CLKCTRL		(CM_PER + 0x0F8)
+#define CM_PER_TPTC1_CLKCTRL		(CM_PER + 0x0FC)
+#define CM_PER_TPTC2_CLKCTRL		(CM_PER + 0x100)
+#define CM_PER_OCPWP_L3_CLKSTCTRL	(CM_PER + 0x12C)
+#define CM_PER_OCPWP_CLKCTRL		(CM_PER + 0x130)
+#define CM_PER_CPSW_CLKSTCTRL		(CM_PER + 0x144)
+
+#define CM_WKUP				0x400
+#define CM_WKUP_CLKSTCTRL		(CM_WKUP + 0x000)
+#define CM_WKUP_CONTROL_CLKCTRL		(CM_WKUP + 0x004)
+#define CM_WKUP_GPIO0_CLKCTRL		(CM_WKUP + 0x008)
+#define CM_WKUP_CM_L3_AON_CLKSTCTRL	(CM_WKUP + 0x01C)
+#define CM_WKUP_CM_CLKSEL_DPLL_MPU	(CM_WKUP + 0x02C)
+#define CM_WKUP_CM_CLKDCOLDO_DPLL_PER	(CM_WKUP + 0x07C)
+#define CM_WKUP_I2C0_CLKCTRL		(CM_WKUP + 0x0B8)
+
+#define CM_DPLL				0x500
+#define CLKSEL_TIMER7_CLK		(CM_DPLL + 0x004)
+#define CLKSEL_TIMER2_CLK		(CM_DPLL + 0x008)
+#define CLKSEL_TIMER3_CLK		(CM_DPLL + 0x00C)
+#define CLKSEL_TIMER4_CLK		(CM_DPLL + 0x010)
+#define CLKSEL_TIMER5_CLK		(CM_DPLL + 0x018)
+#define CLKSEL_TIMER6_CLK		(CM_DPLL + 0x01C)
+
+#define PRM_DEVICE_OFFSET		0xF00
+#define PRM_RSTCTRL			(PRM_DEVICE_OFFSET + 0x00)
+
+struct am335x_prcm_softc {
+	struct resource *	res[2];
+	bus_space_tag_t		bst;
+	bus_space_handle_t	bsh;
+};
+
+static struct resource_spec am335x_prcm_spec[] = {
+	{ SYS_RES_MEMORY,	0,	RF_ACTIVE },
+	{ -1, 0 }
+};
+
+static struct am335x_prcm_softc *am335x_prcm_sc = NULL;
+
+static int am335x_clk_generic_activate(struct ti_clock_dev *clkdev);
+static int am335x_clk_gpio_activate(struct ti_clock_dev *clkdev);
+static int am335x_clk_generic_deactivate(struct ti_clock_dev *clkdev);
+static int am335x_clk_generic_set_source(struct ti_clock_dev *clkdev, clk_src_t clksrc);
+static int am335x_clk_hsmmc_get_source_freq(struct ti_clock_dev *clkdev,  unsigned int *freq);
+static int am335x_clk_get_sysclk_freq(struct ti_clock_dev *clkdev, unsigned int *freq);
+static int am335x_clk_get_arm_fclk_freq(struct ti_clock_dev *clkdev, unsigned int *freq);
+static void am335x_prcm_reset(void);
+static int am335x_clk_cpsw_activate(struct ti_clock_dev *clkdev);
+static int am335x_clk_musb0_activate(struct ti_clock_dev *clkdev);
+
+#define AM335X_GENERIC_CLOCK_DEV(i) \
+	{	.id = (i), \
+		.clk_activate = am335x_clk_generic_activate, \
+		.clk_deactivate = am335x_clk_generic_deactivate, \
+		.clk_set_source = am335x_clk_generic_set_source, \
+		.clk_accessible = NULL, \
+		.clk_get_source_freq = NULL \
+	}
+
+#define AM335X_GPIO_CLOCK_DEV(i) \
+	{	.id = (i), \
+		.clk_activate = am335x_clk_gpio_activate, \
+		.clk_deactivate = am335x_clk_generic_deactivate, \
+		.clk_set_source = am335x_clk_generic_set_source, \
+		.clk_accessible = NULL, \
+		.clk_get_source_freq = NULL \
+	}
+
+#define AM335X_MMCHS_CLOCK_DEV(i) \
+	{	.id = (i), \
+		.clk_activate = am335x_clk_generic_activate, \
+		.clk_deactivate = am335x_clk_generic_deactivate, \
+		.clk_set_source = am335x_clk_generic_set_source, \
+		.clk_accessible = NULL, \
+		.clk_get_source_freq = am335x_clk_hsmmc_get_source_freq \
+	}
+
+struct ti_clock_dev ti_clk_devmap[] = {
+	/* System clocks */
+	{	.id                  = SYS_CLK,
+		.clk_activate        = NULL,
+		.clk_deactivate      = NULL,
+		.clk_set_source      = NULL,
+		.clk_accessible      = NULL,
+		.clk_get_source_freq = am335x_clk_get_sysclk_freq,
+	},
+	/* MPU (ARM) core clocks */
+	{	.id                  = MPU_CLK,
+		.clk_activate        = NULL,
+		.clk_deactivate      = NULL,
+		.clk_set_source      = NULL,
+		.clk_accessible      = NULL,
+		.clk_get_source_freq = am335x_clk_get_arm_fclk_freq,
+	},
+	/* CPSW Ethernet Switch core clocks */
+	{	.id                  = CPSW_CLK,
+		.clk_activate        = am335x_clk_cpsw_activate,
+		.clk_deactivate      = NULL,
+		.clk_set_source      = NULL,
+		.clk_accessible      = NULL,
+		.clk_get_source_freq = NULL,
+	},
+
+	/* Mentor USB HS controller core clocks */
+	{	.id                  = MUSB0_CLK,
+		.clk_activate        = am335x_clk_musb0_activate,
+		.clk_deactivate      = NULL,
+		.clk_set_source      = NULL,
+		.clk_accessible      = NULL,
+		.clk_get_source_freq = NULL,
+	},
+
+	/* DMTimer */
+	AM335X_GENERIC_CLOCK_DEV(DMTIMER2_CLK),
+	AM335X_GENERIC_CLOCK_DEV(DMTIMER3_CLK),
+	AM335X_GENERIC_CLOCK_DEV(DMTIMER4_CLK),
+	AM335X_GENERIC_CLOCK_DEV(DMTIMER5_CLK),
+	AM335X_GENERIC_CLOCK_DEV(DMTIMER6_CLK),
+	AM335X_GENERIC_CLOCK_DEV(DMTIMER7_CLK),
+
+	/* GPIO */
+	AM335X_GPIO_CLOCK_DEV(GPIO0_CLK),
+	AM335X_GPIO_CLOCK_DEV(GPIO1_CLK),
+	AM335X_GPIO_CLOCK_DEV(GPIO2_CLK),
+	AM335X_GPIO_CLOCK_DEV(GPIO3_CLK),
+
+	/* I2C */
+	AM335X_GENERIC_CLOCK_DEV(I2C0_CLK),
+	AM335X_GENERIC_CLOCK_DEV(I2C1_CLK),
+	AM335X_GENERIC_CLOCK_DEV(I2C2_CLK),
+
+	/* EDMA */
+	AM335X_GENERIC_CLOCK_DEV(EDMA_TPCC_CLK),
+	AM335X_GENERIC_CLOCK_DEV(EDMA_TPTC0_CLK),
+	AM335X_GENERIC_CLOCK_DEV(EDMA_TPTC1_CLK),
+	AM335X_GENERIC_CLOCK_DEV(EDMA_TPTC2_CLK),
+
+	/* MMCHS */
+	AM335X_MMCHS_CLOCK_DEV(MMC0_CLK),
+	AM335X_MMCHS_CLOCK_DEV(MMC1_CLK),
+	AM335X_MMCHS_CLOCK_DEV(MMC2_CLK),
+
+	{  INVALID_CLK_IDENT, NULL, NULL, NULL, NULL }
+};
+
+struct am335x_clk_details {
+	clk_ident_t	id;
+	uint32_t	clkctrl_reg;
+	uint32_t	clksel_reg;
+};
+
+#define _CLK_DETAIL(i, c, s) \
+	{	.id = (i), \
+		.clkctrl_reg = (c), \
+		.clksel_reg = (s), \
+	}
+
+static struct am335x_clk_details g_am335x_clk_details[] = {
+
+	/* DMTimer modules */
+	_CLK_DETAIL(DMTIMER2_CLK, CM_PER_TIMER2_CLKCTRL, CLKSEL_TIMER2_CLK),
+	_CLK_DETAIL(DMTIMER3_CLK, CM_PER_TIMER3_CLKCTRL, CLKSEL_TIMER3_CLK),
+	_CLK_DETAIL(DMTIMER4_CLK, CM_PER_TIMER4_CLKCTRL, CLKSEL_TIMER4_CLK),
+	_CLK_DETAIL(DMTIMER5_CLK, CM_PER_TIMER5_CLKCTRL, CLKSEL_TIMER5_CLK),
+	_CLK_DETAIL(DMTIMER6_CLK, CM_PER_TIMER6_CLKCTRL, CLKSEL_TIMER6_CLK),
+	_CLK_DETAIL(DMTIMER7_CLK, CM_PER_TIMER7_CLKCTRL, CLKSEL_TIMER7_CLK),
+
+	/* GPIO modules */
+	_CLK_DETAIL(GPIO0_CLK, CM_WKUP_GPIO0_CLKCTRL, 0),
+	_CLK_DETAIL(GPIO1_CLK, CM_PER_GPIO1_CLKCTRL, 0),
+	_CLK_DETAIL(GPIO2_CLK, CM_PER_GPIO2_CLKCTRL, 0),
+	_CLK_DETAIL(GPIO3_CLK, CM_PER_GPIO3_CLKCTRL, 0),
+
+	/* I2C modules */
+	_CLK_DETAIL(I2C0_CLK, CM_WKUP_I2C0_CLKCTRL, 0),
+	_CLK_DETAIL(I2C1_CLK, CM_PER_I2C1_CLKCTRL, 0),
+	_CLK_DETAIL(I2C2_CLK, CM_PER_I2C2_CLKCTRL, 0),
+
+	/* EDMA modules */
+	_CLK_DETAIL(EDMA_TPCC_CLK, CM_PER_TPCC_CLKCTRL, 0),
+	_CLK_DETAIL(EDMA_TPTC0_CLK, CM_PER_TPTC0_CLKCTRL, 0),
+	_CLK_DETAIL(EDMA_TPTC1_CLK, CM_PER_TPTC1_CLKCTRL, 0),
+	_CLK_DETAIL(EDMA_TPTC2_CLK, CM_PER_TPTC2_CLKCTRL, 0),
+
+	/* MMCHS modules*/
+	_CLK_DETAIL(MMC0_CLK, CM_PER_MMC0_CLKCTRL, 0),
+	_CLK_DETAIL(MMC1_CLK, CM_PER_MMC1_CLKCTRL, 0),
+	_CLK_DETAIL(MMC2_CLK, CM_PER_MMC1_CLKCTRL, 0),
+
+	{ INVALID_CLK_IDENT, 0},
+};
+
+/* Read/Write macros */
+#define prcm_read_4(reg)		\
+	bus_space_read_4(am335x_prcm_sc->bst, am335x_prcm_sc->bsh, reg)
+#define prcm_write_4(reg, val)		\
+	bus_space_write_4(am335x_prcm_sc->bst, am335x_prcm_sc->bsh, reg, val)
+
+void am335x_prcm_setup_dmtimer(int);
+
+static int
+am335x_prcm_probe(device_t dev)
+{
+	if (ofw_bus_is_compatible(dev, "am335x,prcm")) {
+		device_set_desc(dev, "AM335x Power and Clock Management");
+		return(BUS_PROBE_DEFAULT);
+	}
+
+	return (ENXIO);
+}
+
+static int
+am335x_prcm_attach(device_t dev)
+{
+	struct am335x_prcm_softc *sc = device_get_softc(dev);
+	unsigned int sysclk, fclk;
+
+	if (am335x_prcm_sc)
+		return (ENXIO);
+
+	if (bus_alloc_resources(dev, am335x_prcm_spec, sc->res)) {
+		device_printf(dev, "could not allocate resources\n");
+		return (ENXIO);
+	}
+
+	sc->bst = rman_get_bustag(sc->res[0]);
+	sc->bsh = rman_get_bushandle(sc->res[0]);
+
+	am335x_prcm_sc = sc;
+	ti_cpu_reset = am335x_prcm_reset;
+
+	am335x_clk_get_sysclk_freq(NULL, &sysclk);
+	am335x_clk_get_arm_fclk_freq(NULL, &fclk);
+	device_printf(dev, "Clocks: System %u.%01u MHz, CPU %u MHz\n",
+		sysclk/1000000, (sysclk % 1000000)/100000, fclk/1000000);
+
+	return (0);
+}
+
+static device_method_t am335x_prcm_methods[] = {
+	DEVMETHOD(device_probe,		am335x_prcm_probe),
+	DEVMETHOD(device_attach,	am335x_prcm_attach),
+	{ 0, 0 }
+};
+
+static driver_t am335x_prcm_driver = {
+	"am335x_prcm",
+	am335x_prcm_methods,
+	sizeof(struct am335x_prcm_softc),
+};
+
+static devclass_t am335x_prcm_devclass;
+
+DRIVER_MODULE(am335x_prcm, simplebus, am335x_prcm_driver,
+	am335x_prcm_devclass, 0, 0);
+MODULE_DEPEND(am335x_prcm, ti_scm, 1, 1, 1);
+
+static struct am335x_clk_details*
+am335x_clk_details(clk_ident_t id)
+{
+	struct am335x_clk_details *walker;
+
+	for (walker = g_am335x_clk_details; walker->id != INVALID_CLK_IDENT; walker++) {
+		if (id == walker->id)
+			return (walker);
+	}
+
+	return NULL;
+}
+
+static int
+am335x_clk_generic_activate(struct ti_clock_dev *clkdev)
+{
+	struct am335x_prcm_softc *sc = am335x_prcm_sc;
+	struct am335x_clk_details* clk_details;
+
+	if (sc == NULL)
+		return ENXIO;
+
+	clk_details = am335x_clk_details(clkdev->id);
+
+	if (clk_details == NULL)
+		return (ENXIO);
+
+	/* set *_CLKCTRL register MODULEMODE[1:0] to enable(2) */
+	prcm_write_4(clk_details->clkctrl_reg, 2);
+	while ((prcm_read_4(clk_details->clkctrl_reg) & 0x3) != 2)
+		DELAY(10);
+
+	return (0);
+}
+
+static int
+am335x_clk_gpio_activate(struct ti_clock_dev *clkdev)
+{
+	struct am335x_prcm_softc *sc = am335x_prcm_sc;
+	struct am335x_clk_details* clk_details;
+
+	if (sc == NULL)
+		return ENXIO;
+
+	clk_details = am335x_clk_details(clkdev->id);
+
+	if (clk_details == NULL)
+		return (ENXIO);
+
+	/* set *_CLKCTRL register MODULEMODE[1:0] to enable(2) */
+	/* set *_CLKCTRL register OPTFCLKEN_GPIO_1_G DBCLK[18] to FCLK_EN(1) */
+	prcm_write_4(clk_details->clkctrl_reg, 2 | (1 << 18));
+	while ((prcm_read_4(clk_details->clkctrl_reg) & 
+	    (3 | (1 << 18) )) != (2 | (1 << 18)))
+		DELAY(10);
+
+	return (0);
+}
+
+static int
+am335x_clk_generic_deactivate(struct ti_clock_dev *clkdev)
+{
+	struct am335x_prcm_softc *sc = am335x_prcm_sc;
+	struct am335x_clk_details* clk_details;
+
+	if (sc == NULL)
+		return ENXIO;
+
+	clk_details = am335x_clk_details(clkdev->id);
+
+	if (clk_details == NULL)
+		return (ENXIO);
+
+	/* set *_CLKCTRL register MODULEMODE[1:0] to disable(0) */
+	prcm_write_4(clk_details->clkctrl_reg, 0);
+	while ((prcm_read_4(clk_details->clkctrl_reg) & 0x3) != 0)
+		DELAY(10);
+
+	return (0);
+}
+
+static int
+am335x_clk_generic_set_source(struct ti_clock_dev *clkdev, clk_src_t clksrc)
+{
+	struct am335x_prcm_softc *sc = am335x_prcm_sc;
+	struct am335x_clk_details* clk_details;
+	uint32_t reg;
+
+	if (sc == NULL)
+		return ENXIO;
+
+	clk_details = am335x_clk_details(clkdev->id);
+
+	if (clk_details == NULL)
+		return (ENXIO);
+
+	switch (clksrc) {
+		case EXT_CLK:
+			reg = 0; /* SEL2: TCLKIN clock */
+			break;
+		case SYSCLK_CLK:
+			reg = 1; /* SEL1: CLK_M_OSC clock */
+			break;
+		case F32KHZ_CLK:
+			reg = 2; /* SEL3: CLK_32KHZ clock */
+			break;
+		default:
+			return (ENXIO);
+	}
+
+	prcm_write_4(clk_details->clksel_reg, reg);
+	while ((prcm_read_4(clk_details->clksel_reg) & 0x3) != reg)
+		DELAY(10);
+
+	return (0);
+}
+
+static int
+am335x_clk_hsmmc_get_source_freq(struct ti_clock_dev *clkdev,  unsigned int *freq)
+{
+	*freq = 96000000;
+	return (0);
+}
+
+static int
+am335x_clk_get_sysclk_freq(struct ti_clock_dev *clkdev, unsigned int *freq)
+{
+	uint32_t ctrl_status;
+
+	/* Read the input clock freq from the control module */
+	/* control_status reg (0x40) */
+	if (ti_scm_reg_read_4(0x40, &ctrl_status))
+		return ENXIO;
+
+	switch ((ctrl_status>>22) & 0x3) {
+	case 0x0:
+		/* 19.2Mhz */
+		*freq = 19200000;
+		break;
+	case 0x1:
+		/* 24Mhz */
+		*freq = 24000000;
+		break;
+	case 0x2:
+		/* 25Mhz */
+		*freq = 25000000;
+		break;
+	case 0x3:
+		/* 26Mhz */
+		*freq = 26000000;
+		break;
+	}
+
+	return (0);
+}
+
+static int
+am335x_clk_get_arm_fclk_freq(struct ti_clock_dev *clkdev, unsigned int *freq)
+{
+	uint32_t reg;
+	uint32_t sysclk;
+#define DPLL_BYP_CLKSEL(reg)	((reg>>23) & 1)
+#define DPLL_DIV(reg)		((reg & 0x7f)+1)
+#define DPLL_MULT(reg)		((reg>>8) & 0x7FF)
+
+	reg = prcm_read_4(CM_WKUP_CM_CLKSEL_DPLL_MPU);
+
+	/*Check if we are running in bypass */
+	if (DPLL_BYP_CLKSEL(reg))
+		return ENXIO;
+
+	am335x_clk_get_sysclk_freq(NULL, &sysclk);
+	*freq = DPLL_MULT(reg) * (sysclk / DPLL_DIV(reg));
+	return(0);
+}
+
+static void
+am335x_prcm_reset(void)
+{
+	prcm_write_4(PRM_RSTCTRL, (1<<1));
+}
+
+static int
+am335x_clk_cpsw_activate(struct ti_clock_dev *clkdev)
+{
+	struct am335x_prcm_softc *sc = am335x_prcm_sc;
+
+	if (sc == NULL)
+		return ENXIO;
+
+	/* set MODULENAME to ENABLE */
+	prcm_write_4(CM_PER_CPGMAC0_CLKCTRL, 2);
+
+	/* wait for IDLEST to become Func(0) */
+	while(prcm_read_4(CM_PER_CPGMAC0_CLKCTRL) & (3<<16));
+
+	/*set CLKTRCTRL to SW_WKUP(2) */
+	prcm_write_4(CM_PER_CPSW_CLKSTCTRL, 2);
+
+	/* wait for 125 MHz OCP clock to become active */
+	while((prcm_read_4(CM_PER_CPSW_CLKSTCTRL) & (1<<4)) == 0);
+	return(0);
+}
+
+static int
+am335x_clk_musb0_activate(struct ti_clock_dev *clkdev)
+{
+	struct am335x_prcm_softc *sc = am335x_prcm_sc;
+
+	if (sc == NULL)
+		return ENXIO;
+
+	/* set ST_DPLL_CLKDCOLDO(9) to CLK_GATED(1) */
+	/* set DPLL_CLKDCOLDO_GATE_CTRL(8) to CLK_ENABLE(1)*/
+        prcm_write_4(CM_WKUP_CM_CLKDCOLDO_DPLL_PER, 0x300);
+
+	/*set MODULEMODE to ENABLE(2) */
+	prcm_write_4(CM_PER_USB0_CLKCTRL, 2);
+
+	/* wait for MODULEMODE to become ENABLE(2) */
+	while ((prcm_read_4(CM_PER_USB0_CLKCTRL) & 0x3) != 2)
+		DELAY(10);
+
+	/* wait for IDLEST to become Func(0) */
+	while(prcm_read_4(CM_PER_USB0_CLKCTRL) & (3<<16))
+		DELAY(10);
+
+	return(0);
+}
+
+
diff -r 7fffa673adcd -r a301a330526b head/sys/arm/ti/am335x/am335x_reg.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/head/sys/arm/ti/am335x/am335x_reg.h	Wed Aug 15 11:16:36 2012 +0300
@@ -0,0 +1,41 @@
+/*-
+ * Copyright (c) 2012 Damjan Marion <dmarion at Freebsd.org>
+ * 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: head/sys/arm/ti/am335x/am335x_reg.h 239281 2012-08-15 06:31:32Z gonzo $
+ */
+
+#ifndef _AM335X_REG_H_
+#define _AM335X_REG_H_
+
+#define AM335X_L4_WKUP_BASE			0x44C00000
+#define AM335X_L4_WKUP_SIZE			0x400000
+
+#define AM335X_CONTROL_BASE			AM335X_L4_WKUP_BASE + 0x210000
+#define AM335X_CONTROL_SIZE			0x2000
+#define AM335X_CONTROL_DEVICE_ID		0x0600
+#define AM335X_CONTROL_DEV_FEATURE		0x0604
+
+#endif
+
diff -r 7fffa673adcd -r a301a330526b head/sys/arm/ti/am335x/am335x_scm_padconf.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/head/sys/arm/ti/am335x/am335x_scm_padconf.c	Wed Aug 15 11:16:36 2012 +0300
@@ -0,0 +1,373 @@
+/*-
+ * Copyright (c) 2012 Damjan Marion <dmarion at FreeBSD.org>
+ * 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.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: head/sys/arm/ti/am335x/am335x_scm_padconf.c 239281 2012-08-15 06:31:32Z gonzo $");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/module.h>
+#include <sys/bus.h>
+#include <sys/resource.h>
+#include <sys/rman.h>
+#include <sys/lock.h>
+#include <sys/malloc.h>
+
+#include <machine/bus.h>
+#include <machine/cpu.h>
+#include <machine/cpufunc.h>
+#include <machine/frame.h>
+#include <machine/resource.h>
+#include <machine/intr.h>
+#include <sys/gpio.h>
+
+#include <arm/ti/tivar.h>
+#include <arm/ti/ti_scm.h>
+
+#define _PIN(r, b, gp, gm, m0, m1, m2, m3, m4, m5, m6, m7) \
+	{	.reg_off = r, \
+		.gpio_pin = gp, \
+		.gpio_mode = gm, \
+		.ballname = b, \
+		.muxmodes[0] = m0, \
+		.muxmodes[1] = m1, \
+		.muxmodes[2] = m2, \
+		.muxmodes[3] = m3, \
+		.muxmodes[4] = m4, \
+		.muxmodes[5] = m5, \
+		.muxmodes[6] = m6, \
+		.muxmodes[7] = m7, \
+	}
+
+#define SLEWCTRL	(0x01 << 6) /* faster(0) or slower(1) slew rate. */
+#define RXACTIVE	(0x01 << 5) /* Input enable value for the Pad */
+#define PULLTYPESEL	(0x01 << 4) /* Pad pullup/pulldown type selection */
+#define PULLUDEN	(0x01 << 3) /* Pullup/pulldown disabled */
+
+#define PADCONF_OUTPUT			(0)
+#define PADCONF_OUTPUT_PULLUP		(PULLTYPESEL)
+#define PADCONF_INPUT			(RXACTIVE | PULLUDEN)
+#define PADCONF_INPUT_PULLUP		(RXACTIVE | PULLTYPESEL)
+#define PADCONF_INPUT_PULLDOWN		(RXACTIVE)
+#define PADCONF_INPUT_PULLUP_SLOW	(PADCONF_INPUT_PULLUP | SLEWCTRL)
+
+const struct ti_scm_padstate ti_padstate_devmap[] = {
+	{"output",		PADCONF_OUTPUT },
+	{"output_pullup",	PADCONF_OUTPUT_PULLUP },
+	{"input",		PADCONF_INPUT },
+	{"input_pulldown",	PADCONF_INPUT_PULLDOWN },
+	{"input_pullup",	PADCONF_INPUT_PULLUP },
+	{"i2c",			PADCONF_INPUT_PULLUP_SLOW },
+	{ .state = NULL }
+};
+
+const struct ti_scm_padconf ti_padconf_devmap[] = {
+	_PIN(0x800, "GPMC_AD0",		 32, 7,"gpmc_ad0", "mmc1_dat0", NULL, NULL, NULL, NULL, NULL, "gpio1_0"),
+	_PIN(0x804, "GPMC_AD1",		 33, 7,"gpmc_ad1", "mmc1_dat1", NULL, NULL, NULL, NULL, NULL, "gpio1_1"),
+	_PIN(0x808, "GPMC_AD2",		 34, 7,"gpmc_ad2", "mmc1_dat2", NULL, NULL, NULL, NULL, NULL, "gpio1_2"),
+	_PIN(0x80C, "GPMC_AD3",		 35, 7,"gpmc_ad3", "mmc1_dat3", NULL, NULL, NULL, NULL, NULL, "gpio1_3"),
+	_PIN(0x810, "GPMC_AD4",		 36, 7,"gpmc_ad4", "mmc1_dat4", NULL, NULL, NULL, NULL, NULL, "gpio1_4"),
+	_PIN(0x814, "GPMC_AD5",		 37, 7,"gpmc_ad5", "mmc1_dat5", NULL, NULL, NULL, NULL, NULL, "gpio1_5"),
+	_PIN(0x818, "GPMC_AD6",		 38, 7,"gpmc_ad6", "mmc1_dat6", NULL, NULL, NULL, NULL, NULL, "gpio1_6"),
+	_PIN(0x81C, "GPMC_AD7",		 39, 7,"gpmc_ad7", "mmc1_dat7", NULL, NULL, NULL, NULL, NULL, "gpio1_7"),
+#if 0 /* Incomplete Entries - fill with data from table 2-7 in datasheet */
+	_PIN(0x820, "gpmc_ad8",		0, 0, "gpmc_ad8", NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+	_PIN(0x824, "gpmc_ad9",		0, 0, "gpmc_ad9", NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+	_PIN(0x828, "gpmc_ad10",	0, 0, "gpmc_ad10", NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+	_PIN(0x82C, "gpmc_ad11",	0, 0, "gpmc_ad11", NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+	_PIN(0x830, "gpmc_ad12",	0, 0, "gpmc_ad12", NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+	_PIN(0x834, "gpmc_ad13",	0, 0, "gpmc_ad13", NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+	_PIN(0x838, "gpmc_ad14",	0, 0, "gpmc_ad14", NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+	_PIN(0x83C, "gpmc_ad15",	0, 0, "gpmc_ad15", NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+	_PIN(0x840, "gpmc_a0",		0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+	_PIN(0x844, "gpmc_a1",		0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+	_PIN(0x848, "gpmc_a2",		0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+	_PIN(0x84C, "gpmc_a3",		0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+	_PIN(0x850, "gpmc_a4",		0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+#endif
+	_PIN(0x854, "GPMC_A5",		 53, 7, "gpmc_a5", "gmii2_txd0", "rgmii2_td0", "rmii2_txd0", "gpmc_a21", "pr1_mii1_rxd3", "eQEP1B_in", "gpio1_21"),
+	_PIN(0x858, "GPMC_A6",		 54, 7, "gpmc_a6", "gmii2_txclk", "rgmii2_tclk", "mmc2_dat4", "gpmc_a22", "pr1_mii1_rxd2", "eQEP1_index", "gpio1_22"),
+	_PIN(0x85C, "GPMC_A7",		 55, 7, "gpmc_a7", "gmii2_rxclk", "rgmii2_rclk", "mmc2_dat5", "gpmc_a23", "pr1_mii1_rxd1", "eQEP1_strobe", "gpio1_23"),
+	_PIN(0x860, "GPMC_A8",		 56, 7, "gpmc_a8", "gmii2_rxd3", "rgmii2_rd3", "mmc2_dat6", "gpmc_a24", "pr1_mii1_rxd0", "mcasp0_aclkx", "gpio1_24"),
+#if 0
+	_PIN(0x864, "gpmc_a9",		0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+	_PIN(0x868, "gpmc_a10",		0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+	_PIN(0x86C, "gpmc_a11",		0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+	_PIN(0x870, "gpmc_wait0",	0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+	_PIN(0x874, "gpmc_wpn",		0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+	_PIN(0x878, "gpmc_be1n",	0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+	_PIN(0x87c, "gpmc_csn0",	0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+	_PIN(0x880, "gpmc_csn1",	0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+	_PIN(0x884, "gpmc_csn2",	0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+	_PIN(0x888, "gpmc_csn3",	0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+	_PIN(0x88c, "gpmc_clk",		0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+	_PIN(0x890, "gpmc_advn_ale",	0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+	_PIN(0x894, "gpmc_oen_ren",	0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+	_PIN(0x898, "gpmc_wen",		0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+	_PIN(0x89c, "gpmc_be0n_cle",	0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+	_PIN(0x8a0, "lcd_data0",	0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+	_PIN(0x8a4, "lcd_data1",	0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+	_PIN(0x8a8, "lcd_data2",	0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+	_PIN(0x8ac, "lcd_data3",	0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+	_PIN(0x8b0, "lcd_data4",	0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+	_PIN(0x8b4, "lcd_data5",	0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+	_PIN(0x8b8, "lcd_data6",	0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+	_PIN(0x8bc, "lcd_data7",	0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+	_PIN(0x8c0, "lcd_data8",	0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+	_PIN(0x8c4, "lcd_data9",	0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+	_PIN(0x8c8, "lcd_data10",	0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+	_PIN(0x8cc, "lcd_data11",	0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+	_PIN(0x8d0, "lcd_data12",	0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+	_PIN(0x8d4, "lcd_data13",	0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+	_PIN(0x8d8, "lcd_data14",	0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+	_PIN(0x8dc, "lcd_data15",	0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+	_PIN(0x8e0, "lcd_vsync",	0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+	_PIN(0x8e4, "lcd_hsync",	0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+	_PIN(0x8e8, "lcd_pclk",		0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+	_PIN(0x8ec, "lcd_ac_bias_en",	0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+#endif
+	_PIN(0x8f0, "MMC0_DAT3",	 90, 7, "mmc0_dat3", "gpmc_a20", "uart4_ctsn", "timer5", "uart1_dcdn", "pr1_pru0_pru_r30_8", "pr1_pru0_pru_r31_8", "gpio2_26"),
+	_PIN(0x8f4, "MMC0_DAT2",	 91, 7, "mmc0_dat2", "gpmc_a21", "uart4_rtsn", "timer6", "uart1_dsrn", "pr1_pru0_pru_r30_9", "pr1_pru0_pru_r31_9", "gpio2_27"),
+	_PIN(0x8f8, "MMC0_DAT1",	 92, 7, "mmc0_dat1", "gpmc_a22", "uart5_ctsn", "uart3_rxd", "uart1_dtrn", "pr1_pru0_pru_r30_10", "pr1_pru0_pru_r31_10", "gpio2_28"),
+	_PIN(0x8fc, "MMC0_DAT0",	 93, 7, "mmc0_dat0", "gpmc_a23", "uart5_rtsn", "uart3_txd", "uart1_rin", "pr1_pru0_pru_r30_11", "pr1_pru0_pru_r31_11", "gpio2_29"),
+	_PIN(0x900, "MMC0_CLK",		 94, 7, "mmc0_clk", "gpmc_a24", "uart3_ctsn", "uart2_rxd", "dcan1_tx", "pr1_pru0_pru_r30_12", "pr1_pru0_pru_r31_12", "gpio2_30"),
+	_PIN(0x904, "MMC0_CMD",		 95, 7, "mmc0_cmd", "gpmc_a25", "uart3_rtsn", "uart2_txd", "dcan1_rx", "pr1_pru0_pru_r30_13", "pr1_pru0_pru_r31_13", "gpio2_31"),
+	_PIN(0x908, "MII1_COL",		 96, 7, "gmii1_col", "rmii2_refclk", "spi1_sclk", "uart5_rxd", "mcasp1_axr2", "mmc2_dat3", "mcasp0_axr2", "gpio3_0"),
+	_PIN(0x90c, "MII1_CRS",		 97, 7, "gmii1_crs", "rmii1_crs_dv", "spi1_d0", "I2C1_SDA", "mcasp1_aclkx", "uart5_ctsn", "uart2_rxd", "gpio3_1"),
+	_PIN(0x910, "MII1_RX_ER",	 98, 7, "gmii1_rxerr", "rmii1_rxerr", "spi1_d1", "I2C1_SCL", "mcasp1_fsx", "uart5_rtsn", "uart2_txd", "gpio3_2"),
+	_PIN(0x914, "MII1_TX_EN",	 99, 7, "gmii1_txen", "rmii1_txen", "rgmii1_tctl", "timer4", "mcasp1_axr0", "eQEP0_index", "mmc2_cmd", "gpio3_3"),
+	_PIN(0x918, "MII1_RX_DV",	100, 7, "gmii1_rxdv", "cd_memory_clk", "rgmii1_rctl", "uart5_txd", "mcasp1_aclkx", "mmc2_dat0", "mcasp0_aclkr", "gpio3_4"),
+	_PIN(0x91c, "MII1_TXD3",	 16, 7, "gmii1_txd3", "dcan0_tx", "rgmii1_td3", "uart4_rxd", "mcasp1_fsx", "mmc2_dat1", "mcasp0_fsr", "gpio0_16"),
+	_PIN(0x920, "MII1_TXD2",	 17, 7, "gmii1_txd2", "dcan0_rx", "rgmii1_td2", "uart4_txd", "mcasp1_axr0", "mmc2_dat2", "mcasp0_ahclkx", "gpio0_17"),
+	_PIN(0x924, "MII1_TXD1",	 21, 7, "gmii1_txd1", "rmii1_txd1", "rgmii1_td1", "mcasp1_fsr", "mcasp1_axr1", "eQEP0A_in", "mmc1_cmd", "gpio0_21"),
+	_PIN(0x928, "MII1_TXD0",	 28, 7, "gmii1_txd0", "rmii1_txd0", "rgmii1_td0", "mcasp1_axr2", "mcasp1_aclkr", "eQEP0B_in", "mmc1_clk", "gpio0_28"),
+	_PIN(0x92c, "MII1_TX_CLK",	105, 7, "gmii1_txclk", "uart2_rxd", "rgmii1_tclk", "mmc0_dat7", "mmc1_dat0", "uart1_dcdn", "mcasp0_aclkx", "gpio3_9"),
+	_PIN(0x930, "MII1_RX_CLK",	106, 7, "gmii1_rxclk", "uart2_txd", "rgmii1_rclk", "mmc0_dat6", "mmc1_dat1", "uart1_dsrn", "mcasp0_fsx", "gpio3_10"),
+	_PIN(0x934, "MII1_RXD3",	 82, 7, "gmii1_rxd3", "uart3_rxd", "rgmii1_rd3", "mmc0_dat5", "mmc1_dat2", "uart1_dtrn", "mcasp0_axr0", "gpio2_18"),
+	_PIN(0x938, "MII1_RXD2",	 83, 7, "gmii1_rxd2", "uart3_txd", "rgmii1_rd2", "mmc0_dat4", "mmc1_dat3", "uart1_rin", "mcasp0_axr1", "gpio2_19"),
+	_PIN(0x93c, "MII1_RXD1",	 84, 7, "gmii1_rxd1", "rmii1_rxd1", "rgmii1_rd1", "mcasp1_axr3", "mcasp1_fsr", "eQEP0_strobe", "mmc2_clk", "gpio2_20"),
+	_PIN(0x940, "MII1_RXD0",	 85, 7, "gmii1_rxd0", "rmii1_rxd0", "rgmii1_rd0", "mcasp1_ahclkx", "mcasp1_ahclkr", "mcasp1_aclkr", "mcasp0_axr3", "gpio2_21"),
+	_PIN(0x944, "RMII1_REF_CLK",	 29, 7, "rmii1_refclk", "xdma_event_intr2", "spi1_cs0", "uart5_txd", "mcasp1_axr3", "mmc0_pow", "mcasp1_ahclkx", "gpio0_29"),
+	_PIN(0x948, "MDIO",		  0, 7, "mdio_data", "timer6", "uart5_rxd", "uart3_ctsn", "mmc0_sdcd","mmc1_cmd", "mmc2_cmd","gpio0_0"),
+	_PIN(0x94c, "MDC",		  1, 7, "mdio_clk", "timer5", "uart5_txd", "uart3_rtsn", "mmc0_sdwp", "mmc1_clk", "mmc2_clk", "gpio0_1"),
+#if 0 /* Incomplete Entries - fill with data from table 2-7 in datasheet */
+	_PIN(0x950, "spi0_sclk",	0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+	_PIN(0x954, "spi0_d0",		0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+#endif
+	_PIN(0x958, "spi0_d1",		  4, 7, "spi0_d1", "mmc1_sdwp", "I2C1_SDA", "ehrpwm0_tripzone_input", "pr1_uart0_rxd", "pr1_edio_data_in0", "pr1_edio_data_out0", "gpio0_4"),
+	_PIN(0x95c, "spi0_cs0",		  5, 7, "spi0_cs0", "mmc2_sdwp", "I2C1_SCL", "ehrpwm0_synci", "pr1_uart0_txd", "pr1_edio_data_in1", "pr1_edio_data_out1", "gpio0_5"),
+#if 0
+	_PIN(0x960, "spi0_cs1",		0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+	_PIN(0x964, "ecap0_in_pwm0_out",0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+	_PIN(0x968, "uart0_ctsn",	0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+	_PIN(0x96c, "uart0_rtsn",	0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+	_PIN(0x970, "uart0_rxd",	0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+	_PIN(0x974, "uart0_txd",	0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+#endif
+	_PIN(0x978, "uart1_ctsn",	 12, 7, "uart1_ctsn", "timer6_mux1", "dcan0_tx", "I2C2_SDA", "spi1_cs0", "pr1_uart0_cts_n", "pr1_edc_latch0_in", "gpio0_12"),
+	_PIN(0x97c, "uart1_rtsn",	 13, 7, "uart1_rtsn", "timer5_mux1", "dcan0_rx", "I2C2_SCL", "spi1_cs1", "pr1_uart0_rts_n	", "pr1_edc_latch1_in", "gpio0_13"),
+#if 0
+	_PIN(0x980, "uart1_rxd",	0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+	_PIN(0x984, "uart1_txd",	0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+#endif
+	_PIN(0x988, "I2C0_SDA",		101, 7, "I2C0_SDA", "timer4", "uart2_ctsn", "eCAP2_in_PWM2_out", NULL, NULL, NULL, "gpio3_5"),
+	_PIN(0x98c, "I2C0_SCL",		102, 7, "I2C0_SCL", "timer7", "uart2_rtsn", "eCAP1_in_PWM1_out", NULL, NULL, NULL, "gpio3_6"),
+#if 0
+	_PIN(0x990, "mcasp0_aclkx",	0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+	_PIN(0x994, "mcasp0_fsx",	0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+	_PIN(0x998, "mcasp0_axr0",	0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+	_PIN(0x99c, "mcasp0_ahclkr",	0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+	_PIN(0x9a0, "mcasp0_aclkr",	0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+	_PIN(0x9a4, "mcasp0_fsr",	0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+	_PIN(0x9a8, "mcasp0_axr1",	0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+	_PIN(0x9ac, "mcasp0_ahclkx",	0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+	_PIN(0x9b0, "xdma_event_intr0",	0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+	_PIN(0x9b4, "xdma_event_intr1",	0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+	_PIN(0x9b8, "nresetin_out",	0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+	_PIN(0x9bc, "porz",		0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+	_PIN(0x9c0, "nnmi",		0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+	_PIN(0x9c4, "osc0_in",		0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+	_PIN(0x9c8, "osc0_out",		0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+	_PIN(0x9cc, "osc0_vss",		0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+	_PIN(0x9d0, "tms",		0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+	_PIN(0x9d4, "tdi",		0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+	_PIN(0x9d8, "tdo",		0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+	_PIN(0x9dc, "tck",		0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+	_PIN(0x9e0, "ntrst",		0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+	_PIN(0x9e4, "emu0",		0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+	_PIN(0x9e8, "emu1",		0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+	_PIN(0x9ec, "osc1_in",		0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+	_PIN(0x9f0, "osc1_out",		0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+	_PIN(0x9f4, "osc1_vss",		0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+	_PIN(0x9f8, "rtc_porz",		0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+	_PIN(0x9fc, "pmic_power_en",	0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+	_PIN(0xa00, "ext_wakeup",	0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+	_PIN(0xa04, "enz_kaldo_1p8v",	0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+#endif
+	_PIN(0xa08, "USB0_DM",		  0, 0, "USB0_DM", NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+	_PIN(0xa0c, "USB0_DP",		  0, 0, "USB0_DP", NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+	_PIN(0xa10, "USB0_CE",		  0, 0, "USB0_CE", NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+	_PIN(0xa14, "USB0_ID",		  0, 0, "USB0_ID", NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+	_PIN(0xa18, "USB0_VBUS",	  0, 0, "USB0_VBUS", NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+	_PIN(0xa1c, "USB0_DRVVBUS",	 18, 7, "USB0_DRVVBUS", NULL, NULL, NULL, NULL, NULL, NULL, "gpio0_18"),
+	_PIN(0xa20, "USB1_DM",		  0, 0, "USB1_DM", NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+	_PIN(0xa24, "USB1_DP",		  0, 0, "USB1_DP", NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+	_PIN(0xa28, "USB1_CE",		  0, 0, "USB1_CE", NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+	_PIN(0xa2c, "USB1_ID",		  0, 0, "USB1_ID", NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+	_PIN(0xa30, "USB1_VBUS",	  0, 0, "USB1_VBUS", NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+	_PIN(0xa34, "USB1_DRVVBUS",	109, 7, "USB1_DRVVBUS", NULL, NULL, NULL, NULL, NULL, NULL, "gpio3_13"),
+#if 0
+	_PIN(0xa38, "ddr_resetn",	0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+	_PIN(0xa3c, "ddr_csn0",		0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+	_PIN(0xa40, "ddr_cke",		0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+	_PIN(0xa44, "ddr_ck",		0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+	_PIN(0xa48, "ddr_nck",		0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+	_PIN(0xa4c, "ddr_casn",		0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+	_PIN(0xa50, "ddr_rasn",		0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+	_PIN(0xa54, "ddr_wen",		0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+	_PIN(0xa58, "ddr_ba0",		0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+	_PIN(0xa5c, "ddr_ba1",		0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+	_PIN(0xa60, "ddr_ba2",		0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+	_PIN(0xa64, "ddr_a0",		0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+	_PIN(0xa68, "ddr_a1",		0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+	_PIN(0xa6c, "ddr_a2",		0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+	_PIN(0xa70, "ddr_a3",		0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+	_PIN(0xa74, "ddr_a4",		0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+	_PIN(0xa78, "ddr_a5",		0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+	_PIN(0xa7c, "ddr_a6",		0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+	_PIN(0xa80, "ddr_a7",		0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+	_PIN(0xa84, "ddr_a8",		0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+	_PIN(0xa88, "ddr_a9",		0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+	_PIN(0xa8c, "ddr_a10",		0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+	_PIN(0xa90, "ddr_a11",		0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+	_PIN(0xa94, "ddr_a12",		0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+	_PIN(0xa98, "ddr_a13",		0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+	_PIN(0xa9c, "ddr_a14",		0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+	_PIN(0xaa0, "ddr_a15",		0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+	_PIN(0xaa4, "ddr_odt",		0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+	_PIN(0xaa8, "ddr_d0",		0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+	_PIN(0xaac, "ddr_d1",		0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+	_PIN(0xab0, "ddr_d2",		0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+	_PIN(0xab4, "ddr_d3",		0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+	_PIN(0xab8, "ddr_d4",		0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+	_PIN(0xabc, "ddr_d5",		0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+	_PIN(0xac0, "ddr_d6",		0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+	_PIN(0xac4, "ddr_d7",		0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+	_PIN(0xac8, "ddr_d8",		0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+	_PIN(0xacc, "ddr_d9",		0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+	_PIN(0xad0, "ddr_d10",		0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+	_PIN(0xad4, "ddr_d11",		0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+	_PIN(0xad8, "ddr_d12",		0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+	_PIN(0xadc, "ddr_d13",		0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+	_PIN(0xae0, "ddr_d14",		0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+	_PIN(0xae4, "ddr_d15",		0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+	_PIN(0xae8, "ddr_dqm0",		0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+	_PIN(0xaec, "ddr_dqm1",		0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+	_PIN(0xaf0, "ddr_dqs0",		0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+	_PIN(0xaf4, "ddr_dqsn0",	0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+	_PIN(0xaf8, "ddr_dqs1",		0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+	_PIN(0xafc, "ddr_dqsn1",	0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+	_PIN(0xb00, "ddr_vref",		0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+	_PIN(0xb04, "ddr_vtp",		0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+	_PIN(0xb08, "ddr_strben0",	0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+	_PIN(0xb0c, "ddr_strben1",	0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+	_PIN(0xb2c, "ain0",		0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+	_PIN(0xb28, "ain1",		0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+	_PIN(0xb24, "ain2",		0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+	_PIN(0xb20, "ain3",		0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+	_PIN(0xb1c, "ain4",		0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+	_PIN(0xb18, "ain5",		0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+	_PIN(0xb14, "ain6",		0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+	_PIN(0xb10, "ain7",		0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+	_PIN(0xb30, "vrefp",		0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+	_PIN(0xb34, "vrefn",		0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+	_PIN(0xb38, "avdd",		0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+	_PIN(0xb3c, "avss",		0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+	_PIN(0xb40, "iforce",		0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+	_PIN(0xb44, "vsense",		0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+	_PIN(0xb48, "testout",		0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+#endif
+	{  .ballname = NULL  },
+};
+
+const struct ti_scm_device ti_scm_dev = {
+	.padconf_muxmode_mask	= 0x7,
+	.padconf_sate_mask	= 0x78,
+	.padstate		= (struct ti_scm_padstate *) &ti_padstate_devmap,
+	.padconf		= (struct ti_scm_padconf *) &ti_padconf_devmap,
+};
+
+int
+ti_scm_padconf_set_gpioflags(uint32_t gpio, uint32_t flags)
+{
+	unsigned int state = 0;
+	if (flags & GPIO_PIN_OUTPUT) {
+		if (flags & GPIO_PIN_PULLUP)
+			state = PADCONF_OUTPUT_PULLUP;
+		else
+			state = PADCONF_OUTPUT;
+	} else if (flags & GPIO_PIN_INPUT) {
+		if (flags & GPIO_PIN_PULLUP)
+			state = PADCONF_INPUT_PULLUP;
+		else if (flags & GPIO_PIN_PULLDOWN)
+			state = PADCONF_INPUT_PULLDOWN;
+		else
+			state = PADCONF_INPUT;
+	}
+	return ti_scm_padconf_set_gpiomode(gpio, state);
+}
+
+void
+ti_scm_padconf_get_gpioflags(uint32_t gpio, uint32_t *flags)
+{
+	unsigned int state;
+	if (ti_scm_padconf_get_gpiomode(gpio, &state) != 0)
+		*flags = 0;
+	else {
+		switch (state) {
+			case PADCONF_OUTPUT:
+				*flags = GPIO_PIN_OUTPUT;
+				break;
+			case PADCONF_OUTPUT_PULLUP:
+				*flags = GPIO_PIN_OUTPUT | GPIO_PIN_PULLUP;
+				break;
+			case PADCONF_INPUT:
+				*flags = GPIO_PIN_INPUT;
+				break;
+			case PADCONF_INPUT_PULLUP:
+				*flags = GPIO_PIN_INPUT | GPIO_PIN_PULLUP;
+				break;
+			case PADCONF_INPUT_PULLDOWN:
+				*flags = GPIO_PIN_INPUT | GPIO_PIN_PULLDOWN;
+				break;
+			default:
+				*flags = 0;
+				break;
+		}
+	}
+}
+
diff -r 7fffa673adcd -r a301a330526b head/sys/arm/ti/am335x/files.am335x
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/head/sys/arm/ti/am335x/files.am335x	Wed Aug 15 11:16:36 2012 +0300
@@ -0,0 +1,9 @@
+#$FreeBSD: head/sys/arm/ti/am335x/files.am335x 239281 2012-08-15 06:31:32Z gonzo $
+
+arm/ti/aintc.c				standard
+arm/ti/am335x/am335x_prcm.c		standard
+arm/ti/am335x/am335x_dmtimer.c		standard
+arm/ti/am335x/am335x_scm_padconf.c	standard
+arm/ti/ti_edma3.c			standard
+arm/ti/ti_mmchs.c			optional	mmc
+arm/ti/cpsw/if_cpsw.c			optional	cpsw
diff -r 7fffa673adcd -r a301a330526b head/sys/arm/ti/am335x/files.beaglebone
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/head/sys/arm/ti/am335x/files.beaglebone	Wed Aug 15 11:16:36 2012 +0300
@@ -0,0 +1,3 @@
+#$FreeBSD: head/sys/arm/ti/am335x/files.beaglebone 239281 2012-08-15 06:31:32Z gonzo $
+
+arm/ti/am335x/am335x_pmic.c			optional	am335x_pmic
diff -r 7fffa673adcd -r a301a330526b head/sys/arm/ti/am335x/std.am335x
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/head/sys/arm/ti/am335x/std.am335x	Wed Aug 15 11:16:36 2012 +0300
@@ -0,0 +1,21 @@
+# AM335x generic configuration
+#$FreeBSD: head/sys/arm/ti/am335x/std.am335x 239281 2012-08-15 06:31:32Z gonzo $
+files		"../ti/am335x/files.am335x"
+include		"../ti/std.ti"
+makeoption	ARM_LITTLE_ENDIAN
+
+# Physical memory starts at 0x80000000.  We assume images are loaded at
+# 0x80200000, e.g. from u-boot with 'fatload mmc 0 0x80200000 kernel.bin'
+#
+#
+options		PHYSADDR=0x80000000
+options		KERNPHYSADDR=0x80200000
+makeoptions	KERNPHYSADDR=0x80200000
+options		KERNVIRTADDR=0xc0200000		# Used in ldscript.arm
+makeoptions	KERNVIRTADDR=0xc0200000
+
+options		STARTUP_PAGETABLE_ADDR=0x80000000
+
+options		SOC_TI_AM335X
+
+options		ARM_L2_PIPT
diff -r 7fffa673adcd -r a301a330526b head/sys/arm/ti/am335x/std.beaglebone
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/head/sys/arm/ti/am335x/std.beaglebone	Wed Aug 15 11:16:36 2012 +0300
@@ -0,0 +1,4 @@
+# $FreeBSD: head/sys/arm/ti/am335x/std.beaglebone 239281 2012-08-15 06:31:32Z gonzo $
+
+files		"../ti/am335x/files.beaglebone"
+include		"../ti/am335x/std.am335x"
diff -r 7fffa673adcd -r a301a330526b head/sys/arm/ti/bus_space.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/head/sys/arm/ti/bus_space.c	Wed Aug 15 11:16:36 2012 +0300
@@ -0,0 +1,113 @@
+/*-
+ * Copyright (C) 2012 FreeBSD Foundation
+ * 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.
+ * 3. Neither the name of MARVELL nor the names of contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * 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: head/sys/arm/ti/bus_space.c 239281 2012-08-15 06:31:32Z gonzo $");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/bus.h>
+#include <sys/kernel.h>
+#include <sys/malloc.h>
+
+#include <machine/bus.h>
+
+/* Prototypes for all the bus_space structure functions */
+bs_protos(generic);
+bs_protos(generic_armv4);
+
+struct bus_space _base_tag = {
+	/* cookie */
+	.bs_cookie	= (void *) 0,
+	
+	/* mapping/unmapping */
+	.bs_map		= generic_bs_map,
+	.bs_unmap	= generic_bs_unmap,
+	.bs_subregion	= generic_bs_subregion,
+	
+	/* allocation/deallocation */
+	.bs_alloc	= generic_bs_alloc,
+	.bs_free	= generic_bs_free,
+	
+	/* barrier */
+	.bs_barrier	= generic_bs_barrier,
+	
+	/* read (single) */
+	.bs_r_1		= generic_bs_r_1,
+	.bs_r_2		= generic_armv4_bs_r_2,
+	.bs_r_4		= generic_bs_r_4,
+	.bs_r_8		= NULL,
+	
+	/* read multiple */
+	.bs_rm_1	= generic_bs_rm_1,
+	.bs_rm_2	= generic_armv4_bs_rm_2,
+	.bs_rm_4	= generic_bs_rm_4,
+	.bs_rm_8	= NULL,
+	
+	/* read region */
+	.bs_rr_1	= generic_bs_rr_1,
+	.bs_rr_2	= generic_armv4_bs_rr_2,
+	.bs_rr_4	= generic_bs_rr_4,
+	.bs_rr_8	= NULL,
+	
+	/* write (single) */
+	.bs_w_1		= generic_bs_w_1,
+	.bs_w_2		= generic_armv4_bs_w_2,
+	.bs_w_4		= generic_bs_w_4,
+	.bs_w_8		= NULL,
+	
+	/* write multiple */
+	.bs_wm_1	= generic_bs_wm_1,
+	.bs_wm_2	= generic_armv4_bs_wm_2,
+	.bs_wm_4	= generic_bs_wm_4,
+	.bs_wm_8	= NULL,
+	
+	/* write region */
+	.bs_wr_1	= generic_bs_wr_1,
+	.bs_wr_2	= generic_armv4_bs_wr_2,
+	.bs_wr_4	= generic_bs_wr_4,
+	.bs_wr_8	= NULL,
+	
+	/* set multiple */
+	/* XXX not implemented */
+	
+	/* set region */
+	.bs_sr_1	= NULL,
+	.bs_sr_2	= generic_armv4_bs_sr_2,
+	.bs_sr_4	= generic_bs_sr_4,
+	.bs_sr_8	= NULL,
+	
+	/* copy */
+	.bs_c_1		= NULL,
+	.bs_c_2		= generic_armv4_bs_c_2,
+	.bs_c_4		= NULL,
+	.bs_c_8		= NULL,
+};
+
+bus_space_tag_t fdtbus_bs_tag = &_base_tag;
diff -r 7fffa673adcd -r a301a330526b head/sys/arm/ti/common.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/head/sys/arm/ti/common.c	Wed Aug 15 11:16:36 2012 +0300
@@ -0,0 +1,98 @@
+/*-
+ * Copyright (C) 2008-2011 MARVELL INTERNATIONAL LTD.
+ * All rights reserved.
+ *
+ * Developed by Semihalf.
+ *
+ * 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. Neither the name of MARVELL nor the names of contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include "opt_global.h"
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: head/sys/arm/ti/common.c 239281 2012-08-15 06:31:32Z gonzo $");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/bus.h>
+#include <sys/kernel.h>
+#include <sys/malloc.h>
+#include <sys/kdb.h>
+#include <sys/reboot.h>
+
+#include <dev/fdt/fdt_common.h>
+#include <dev/ofw/openfirm.h>
+
+#include <machine/bus.h>
+#include <machine/fdt.h>
+#include <machine/vmparam.h>
+
+struct fdt_fixup_entry fdt_fixup_table[] = {
+	{ NULL, NULL }
+};
+
+#ifdef SOC_OMAP4
+static int
+fdt_gic_decode_ic(phandle_t node, pcell_t *intr, int *interrupt, int *trig,
+    int *pol)
+{
+
+	if (!fdt_is_compatible(node, "arm,gic"))
+		return (ENXIO);
+
+	*interrupt = fdt32_to_cpu(intr[0]);
+	*trig = INTR_TRIGGER_CONFORM;
+	*pol = INTR_POLARITY_CONFORM;
+
+	return (0);
+}
+#endif
+
+#ifdef SOC_TI_AM335X
+static int
+fdt_aintc_decode_ic(phandle_t node, pcell_t *intr, int *interrupt, int *trig,
+    int *pol)
+{
+
+	if (!fdt_is_compatible(node, "ti,aintc"))
+		return (ENXIO);
+
+	*interrupt = fdt32_to_cpu(intr[0]);
+	*trig = INTR_TRIGGER_CONFORM;
+	*pol = INTR_POLARITY_CONFORM;
+
+	return (0);
+}
+#endif
+
+fdt_pic_decode_t fdt_pic_table[] = {
+#ifdef SOC_OMAP4
+	&fdt_gic_decode_ic,
+#endif
+#ifdef SOC_TI_AM335X
+	&fdt_aintc_decode_ic,
+#endif
+	NULL
+};
diff -r 7fffa673adcd -r a301a330526b head/sys/arm/ti/cpsw/if_cpsw.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/head/sys/arm/ti/cpsw/if_cpsw.c	Wed Aug 15 11:16:36 2012 +0300
@@ -0,0 +1,1251 @@
+/*-
+ * Copyright (c) 2012 Damjan Marion <dmarion at Freebsd.org>
+ * 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.
+ */
+
+/*
+ * TI 3 Port Switch Ethernet (CPSW) Driver
+ * Found in TI8148, AM335x SoCs
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: head/sys/arm/ti/cpsw/if_cpsw.c 239281 2012-08-15 06:31:32Z gonzo $");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/endian.h>
+#include <sys/mbuf.h>
+#include <sys/lock.h>
+#include <sys/mutex.h>
+#include <sys/kernel.h>
+#include <sys/module.h>
+#include <sys/socket.h>
+#include <sys/sysctl.h>
+
+#include <net/ethernet.h>
+#include <net/bpf.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>
+
+#include <netinet/in_systm.h>
+#include <netinet/in.h>
+#include <netinet/ip.h>
+
+#include <sys/sockio.h>
+#include <sys/bus.h>
+#include <machine/bus.h>
+#include <sys/rman.h>
+#include <machine/resource.h>
+
+#include <dev/mii/mii.h>
+#include <dev/mii/miivar.h>
+
+#include <dev/fdt/fdt_common.h>
+#include <dev/ofw/ofw_bus.h>
+#include <dev/ofw/ofw_bus_subr.h>
+
+#include <arm/ti/cpsw/if_cpswreg.h>
+#include <arm/ti/cpsw/if_cpswvar.h>
+ 
+#include <arm/ti/ti_scm.h>
+
+#include "miibus_if.h"
+
+static int cpsw_probe(device_t dev);
+static int cpsw_attach(device_t dev);
+static int cpsw_detach(device_t dev);
+static int cpsw_shutdown(device_t dev);
+static int cpsw_suspend(device_t dev);
+static int cpsw_resume(device_t dev);
+
+static int cpsw_miibus_readreg(device_t dev, int phy, int reg);
+static int cpsw_miibus_writereg(device_t dev, int phy, int reg, int value);
+
+static int cpsw_ifmedia_upd(struct ifnet *ifp);
+static void cpsw_ifmedia_sts(struct ifnet *ifp, struct ifmediareq *ifmr);
+
+static void cpsw_init(void *arg);
+static void cpsw_init_locked(void *arg);
+static void cpsw_start(struct ifnet *ifp);
+static void cpsw_start_locked(struct ifnet *ifp);
+static void cpsw_stop(struct cpsw_softc *sc);
+static int cpsw_ioctl(struct ifnet *ifp, u_long command, caddr_t data);
+static int cpsw_allocate_dma(struct cpsw_softc *sc);
+static int cpsw_free_dma(struct cpsw_softc *sc);
+static int cpsw_new_rxbuf(struct cpsw_softc *sc, uint32_t i, uint32_t next);
+static void cpsw_watchdog(struct cpsw_softc *sc);
+
+static void cpsw_intr_rx_thresh(void *arg);
+static void cpsw_intr_rx(void *arg);
+static void cpsw_intr_rx_locked(void *arg);
+static void cpsw_intr_tx(void *arg);
+static void cpsw_intr_tx_locked(void *arg);
+static void cpsw_intr_misc(void *arg);
+
+static void cpsw_ale_read_entry(struct cpsw_softc *sc, uint16_t idx, uint32_t *ale_entry);
+static void cpsw_ale_write_entry(struct cpsw_softc *sc, uint16_t idx, uint32_t *ale_entry);
+static int cpsw_ale_uc_entry_set(struct cpsw_softc *sc, uint8_t port, uint8_t *mac);
+static int cpsw_ale_mc_entry_set(struct cpsw_softc *sc, uint8_t portmap, uint8_t *mac);
+#ifdef CPSW_DEBUG
+static void cpsw_ale_dump_table(struct cpsw_softc *sc);
+#endif
+
+static device_method_t cpsw_methods[] = {
+	/* Device interface */
+	DEVMETHOD(device_probe,		cpsw_probe),
+	DEVMETHOD(device_attach,	cpsw_attach),
+	DEVMETHOD(device_detach,	cpsw_detach),
+	DEVMETHOD(device_shutdown,	cpsw_shutdown),
+	DEVMETHOD(device_suspend,	cpsw_suspend),
+	DEVMETHOD(device_resume,	cpsw_resume),
+	/* MII interface */
+	DEVMETHOD(miibus_readreg,	cpsw_miibus_readreg),
+	DEVMETHOD(miibus_writereg,	cpsw_miibus_writereg),
+	{ 0, 0 }
+};
+
+static driver_t cpsw_driver = {
+	"cpsw",
+	cpsw_methods,
+	sizeof(struct cpsw_softc),
+};
+
+static devclass_t cpsw_devclass;
+
+
+DRIVER_MODULE(cpsw, simplebus, cpsw_driver, cpsw_devclass, 0, 0);
+DRIVER_MODULE(miibus, cpsw, miibus_driver, miibus_devclass, 0, 0);
+MODULE_DEPEND(cpsw, ether, 1, 1, 1);
+MODULE_DEPEND(cpsw, miibus, 1, 1, 1);
+
+static struct resource_spec res_spec[] = {
+	{ SYS_RES_MEMORY, 0, RF_ACTIVE },
+	{ SYS_RES_IRQ, 0, RF_ACTIVE | RF_SHAREABLE },
+	{ SYS_RES_IRQ, 1, RF_ACTIVE | RF_SHAREABLE },
+	{ SYS_RES_IRQ, 2, RF_ACTIVE | RF_SHAREABLE },
+	{ SYS_RES_IRQ, 3, RF_ACTIVE | RF_SHAREABLE },
+	{ -1, 0 }
+};
+
+static struct {
+	driver_intr_t *handler;
+	char * description;
+} cpsw_intrs[CPSW_INTR_COUNT + 1] = {
+	{ cpsw_intr_rx_thresh,"CPSW RX threshold interrupt" },
+	{ cpsw_intr_rx,	"CPSW RX interrupt" },
+	{ cpsw_intr_tx,	"CPSW TX interrupt" },
+	{ cpsw_intr_misc,"CPSW misc interrupt" },
+};
+
+/* Locking macros */
+#define CPSW_TX_LOCK(sc) do {					\
+		mtx_assert(&(sc)->rx_lock, MA_NOTOWNED);		\
+		mtx_lock(&(sc)->tx_lock);				\
+} while (0)
+
+#define CPSW_TX_UNLOCK(sc)	mtx_unlock(&(sc)->tx_lock)
+#define CPSW_TX_LOCK_ASSERT(sc)	mtx_assert(&(sc)->tx_lock, MA_OWNED)
+
+#define CPSW_RX_LOCK(sc) do {					\
+		mtx_assert(&(sc)->tx_lock, MA_NOTOWNED);		\
+		mtx_lock(&(sc)->rx_lock);				\
+} while (0)
+
+#define CPSW_RX_UNLOCK(sc)		mtx_unlock(&(sc)->rx_lock)
+#define CPSW_RX_LOCK_ASSERT(sc)	mtx_assert(&(sc)->rx_lock, MA_OWNED)
+
+#define CPSW_GLOBAL_LOCK(sc) do {					\
+		if ((mtx_owned(&(sc)->tx_lock) ? 1 : 0) !=	\
+		    (mtx_owned(&(sc)->rx_lock) ? 1 : 0)) {		\
+			panic("cpsw deadlock possibility detection!");	\
+		}							\
+		mtx_lock(&(sc)->tx_lock);				\
+		mtx_lock(&(sc)->rx_lock);				\
+} while (0)
+
+#define CPSW_GLOBAL_UNLOCK(sc) do {					\
+		CPSW_RX_UNLOCK(sc);				\
+		CPSW_TX_UNLOCK(sc);				\
+} while (0)
+
+#define CPSW_GLOBAL_LOCK_ASSERT(sc) do {				\
+		CPSW_TX_LOCK_ASSERT(sc);				\
+		CPSW_RX_LOCK_ASSERT(sc);				\
+} while (0)
+
+
+static int
+cpsw_probe(device_t dev)
+{
+
+	if (!ofw_bus_is_compatible(dev, "ti,cpsw"))
+		return (ENXIO);
+
+	device_set_desc(dev, "3-port Switch Ethernet Subsystem");
+	return (BUS_PROBE_DEFAULT);
+}
+
+static int
+cpsw_attach(device_t dev)
+{
+	struct cpsw_softc *sc;
+	struct mii_softc *miisc;
+	struct ifnet *ifp;
+	uint8_t mac_addr[ETHER_ADDR_LEN];
+	int i, error, phy;
+	uint32_t reg;
+
+	sc = device_get_softc(dev);
+	sc->dev = dev;
+	memcpy(sc->mac_addr, mac_addr, ETHER_ADDR_LEN);
+	sc->node = ofw_bus_get_node(dev);
+
+	/* Get phy address from fdt */
+	if (fdt_get_phyaddr(sc->node, sc->dev, &phy, (void **)&sc->phy_sc) != 0) {
+		device_printf(dev, "failed to get PHY address from FDT\n");
+		return (ENXIO);
+	}
+	/* Initialize mutexes */
+	mtx_init(&sc->tx_lock, device_get_nameunit(dev),
+		"cpsw TX lock", MTX_DEF);
+	mtx_init(&sc->rx_lock, device_get_nameunit(dev),
+		"cpsw RX lock", MTX_DEF);
+
+	/* Allocate IO and IRQ resources */
+	error = bus_alloc_resources(dev, res_spec, sc->res);
+	if (error) {
+		device_printf(dev, "could not allocate resources\n");
+		cpsw_detach(dev);
+		return (ENXIO);
+	}
+
+	reg = cpsw_read_4(CPSW_SS_IDVER);
+	device_printf(dev, "Version %d.%d (%d)\n", (reg >> 8 & 0x7),
+		reg & 0xFF, (reg >> 11) & 0x1F);
+
+	/* Allocate DMA, buffers, buffer descriptors */
+	error = cpsw_allocate_dma(sc);
+	if (error) {
+		cpsw_detach(dev);
+		return (ENXIO);
+	}
+
+	//cpsw_add_sysctls(sc); TODO
+
+	/* Allocate network interface */
+	ifp = sc->ifp = if_alloc(IFT_ETHER);
+	if (ifp == NULL) {
+		device_printf(dev, "if_alloc() failed\n");
+		cpsw_detach(dev);
+		return (ENOMEM);
+	}
+
+	if_initname(ifp, device_get_name(dev), device_get_unit(dev));
+	ifp->if_softc = sc;
+	ifp->if_flags = IFF_SIMPLEX | IFF_MULTICAST | IFF_BROADCAST;
+	ifp->if_capabilities = IFCAP_VLAN_MTU | IFCAP_HWCSUM; //FIXME VLAN?
+	ifp->if_capenable = ifp->if_capabilities;
+
+	ifp->if_init = cpsw_init;
+	ifp->if_start = cpsw_start;
+	ifp->if_ioctl = cpsw_ioctl;
+
+	ifp->if_snd.ifq_drv_maxlen = CPSW_MAX_TX_BUFFERS - 1;
+	IFQ_SET_MAXLEN(&ifp->if_snd, ifp->if_snd.ifq_drv_maxlen);
+	IFQ_SET_READY(&ifp->if_snd);
+
+	/* Get low part of MAC address from control module (mac_id0_lo) */
+	ti_scm_reg_read_4(0x630, &reg);
+	mac_addr[0] = (reg >>  8) & 0xFF;
+	mac_addr[1] = reg & 0xFF;
+
+	/* Get high part of MAC address from control module (mac_id0_hi) */
+	ti_scm_reg_read_4(0x634, &reg);
+	mac_addr[2] = (reg >> 24) & 0xFF;
+	mac_addr[3] = (reg >> 16) & 0xFF;
+	mac_addr[4] = (reg >>  8) & 0xFF;
+	mac_addr[5] = reg & 0xFF;
+
+	ether_ifattach(ifp, sc->mac_addr);
+	callout_init(&sc->wd_callout, 0);
+
+	/* Initialze MDIO - ENABLE, PREAMBLE=0, FAULTENB, CLKDIV=0xFF */
+	/* TODO Calculate MDCLK=CLK/(CLKDIV+1) */
+	cpsw_write_4(MDIOCONTROL, (1<<30) | (1<<18) | 0xFF);
+
+	/* Attach PHY(s) */
+	error = mii_attach(dev, &sc->miibus, ifp, cpsw_ifmedia_upd,
+	    cpsw_ifmedia_sts, BMSR_DEFCAPMASK, phy, MII_OFFSET_ANY, 0);
+	if (error) {
+		device_printf(dev, "attaching PHYs failed\n");
+		cpsw_detach(dev);
+		return (error);
+	}
+	sc->mii = device_get_softc(sc->miibus);
+
+	/* Tell the MAC where to find the PHY so autoneg works */
+	miisc = LIST_FIRST(&sc->mii->mii_phys);
+
+	/* Select PHY and enable interrupts */
+	cpsw_write_4(MDIOUSERPHYSEL0, (1 << 6) | (miisc->mii_phy & 0x1F));
+
+	/* Attach interrupt handlers */
+	for (i = 1; i <= CPSW_INTR_COUNT; ++i) {
+		error = bus_setup_intr(dev, sc->res[i],
+		    INTR_TYPE_NET | INTR_MPSAFE,
+		    NULL, *cpsw_intrs[i - 1].handler,
+		    sc, &sc->ih_cookie[i - 1]);
+		if (error) {
+			device_printf(dev, "could not setup %s\n",
+			    cpsw_intrs[i].description);
+			cpsw_detach(dev);
+			return (error);
+		}
+	}
+
+	return (0);
+}
+
+static int
+cpsw_detach(device_t dev)
+{
+	struct cpsw_softc *sc;
+	int error,i;
+
+	sc = device_get_softc(dev);
+
+	/* Stop controller and free TX queue */
+	if (sc->ifp)
+		cpsw_shutdown(dev);
+
+	/* Wait for stopping ticks */
+        callout_drain(&sc->wd_callout);
+
+	/* Stop and release all interrupts */
+	for (i = 0; i < CPSW_INTR_COUNT; ++i) {
+		if (!sc->ih_cookie[i])
+			continue;
+
+		error = bus_teardown_intr(dev, sc->res[1 + i], sc->ih_cookie[i]);
+		if (error)
+			device_printf(dev, "could not release %s\n",
+			    cpsw_intrs[i + 1].description);
+	}
+
+	/* Detach network interface */
+	if (sc->ifp) {
+		ether_ifdetach(sc->ifp);
+		if_free(sc->ifp);
+	}
+
+	/* Free DMA resources */
+	cpsw_free_dma(sc);
+
+	/* Free IO memory handler */
+	bus_release_resources(dev, res_spec, sc->res);
+
+	/* Destroy mutexes */
+	mtx_destroy(&sc->rx_lock);
+	mtx_destroy(&sc->tx_lock);
+
+	return (0);
+}
+
+static int
+cpsw_suspend(device_t dev)
+{
+
+	device_printf(dev, "%s\n", __FUNCTION__);
+	return (0);
+}
+
+static int
+cpsw_resume(device_t dev)
+{
+
+	device_printf(dev, "%s\n", __FUNCTION__);
+	return (0);
+}
+
+static int
+cpsw_shutdown(device_t dev)
+{
+	struct cpsw_softc *sc = device_get_softc(dev);
+
+	CPSW_GLOBAL_LOCK(sc);
+
+	cpsw_stop(sc);
+
+	CPSW_GLOBAL_UNLOCK(sc);
+
+	return (0);
+}
+
+static int
+cpsw_miibus_readreg(device_t dev, int phy, int reg)
+{
+	struct cpsw_softc *sc;
+	uint32_t r;
+	uint32_t retries = CPSW_MIIBUS_RETRIES;
+
+	sc = device_get_softc(dev);
+
+	/* Wait until interface is ready by watching GO bit */
+	while(--retries && (cpsw_read_4(MDIOUSERACCESS0) & (1 << 31)) )
+		DELAY(CPSW_MIIBUS_DELAY);
+	if (!retries)
+		device_printf(dev, "Timeout while waiting for MDIO.\n");
+
+	/* Set GO, phy and reg */
+	cpsw_write_4(MDIOUSERACCESS0, (1 << 31) |
+		((reg & 0x1F) << 21) | ((phy & 0x1F) << 16));
+
+	while(--retries && (cpsw_read_4(MDIOUSERACCESS0) & (1 << 31)) )
+		DELAY(CPSW_MIIBUS_DELAY);
+	if (!retries)
+		device_printf(dev, "Timeout while waiting for MDIO.\n");
+
+	r = cpsw_read_4(MDIOUSERACCESS0);
+	/* Check for ACK */
+	if(r & (1<<29)) {
+		return (r & 0xFFFF);
+	}
+	device_printf(dev, "Failed to read from PHY.\n");
+	return 0;
+}
+
+static int
+cpsw_miibus_writereg(device_t dev, int phy, int reg, int value)
+{
+	struct cpsw_softc *sc;
+	uint32_t retries = CPSW_MIIBUS_RETRIES;
+
+	sc = device_get_softc(dev);
+
+	/* Wait until interface is ready by watching GO bit */
+	while(--retries && (cpsw_read_4(MDIOUSERACCESS0) & (1 << 31)) )
+		DELAY(CPSW_MIIBUS_DELAY);
+	if (!retries)
+		device_printf(dev, "Timeout while waiting for MDIO.\n");
+
+	/* Set GO, WRITE, phy, reg and value */
+	cpsw_write_4(MDIOUSERACCESS0, (value & 0xFFFF) | (3 << 30) |
+		((reg & 0x1F) << 21) | ((phy & 0x1F) << 16));
+
+	while(--retries && (cpsw_read_4(MDIOUSERACCESS0) & (1 << 31)) )
+		DELAY(CPSW_MIIBUS_DELAY);
+	if (!retries)
+		device_printf(dev, "Timeout while waiting for MDIO.\n");
+
+	/* Check for ACK */
+	if(cpsw_read_4(MDIOUSERACCESS0) & (1<<29)) {
+		return 0;
+	}
+	device_printf(dev, "Failed to write to PHY.\n");
+
+	return 0;
+}
+
+static int
+cpsw_allocate_dma(struct cpsw_softc *sc)
+{
+	int err;
+	int i;
+
+	/* Allocate a busdma tag and DMA safe memory for tx mbufs. */
+	err = 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,			/* filtfunc, filtfuncarg */
+		MCLBYTES, 1,			/* maxsize, nsegments */
+		MCLBYTES, 0,			/* maxsegsz, flags */
+		NULL, NULL,			/* lockfunc, lockfuncarg */
+		&sc->mbuf_dtag);		/* dmatag */
+
+	if (err)
+		return (ENOMEM);
+	for (i = 0; i < CPSW_MAX_TX_BUFFERS; i++) {
+		if ( bus_dmamap_create(sc->mbuf_dtag, 0, &sc->tx_dmamap[i])) {
+			if_printf(sc->ifp, "failed to create dmamap for rx mbuf\n");
+			return (ENOMEM);
+		}
+	}
+
+	for (i = 0; i < CPSW_MAX_RX_BUFFERS; i++) {
+		if ( bus_dmamap_create(sc->mbuf_dtag, 0, &sc->rx_dmamap[i])) {
+			if_printf(sc->ifp, "failed to create dmamap for rx mbuf\n");
+			return (ENOMEM);
+		}
+	}
+
+	return (0);
+}
+
+static int
+cpsw_free_dma(struct cpsw_softc *sc)
+{
+	(void)sc; /* UNUSED */
+	// TODO
+	return 0;
+}
+
+static int
+cpsw_new_rxbuf(struct cpsw_softc *sc, uint32_t i, uint32_t next)
+{
+	bus_dma_segment_t seg[1];
+	struct cpsw_cpdma_bd bd;
+	int error;
+	int nsegs;
+
+	if (sc->rx_mbuf[i]) {
+		bus_dmamap_sync(sc->mbuf_dtag, sc->rx_dmamap[i], BUS_DMASYNC_POSTREAD);
+		bus_dmamap_unload(sc->mbuf_dtag, sc->rx_dmamap[i]);
+	}
+
+	sc->rx_mbuf[i] = m_getcl(M_DONTWAIT, MT_DATA, M_PKTHDR);
+	if (sc->rx_mbuf[i] == NULL)
+		return (ENOBUFS);
+
+	sc->rx_mbuf[i]->m_len = sc->rx_mbuf[i]->m_pkthdr.len = sc->rx_mbuf[i]->m_ext.ext_size;
+
+	error = bus_dmamap_load_mbuf_sg(sc->mbuf_dtag, sc->rx_dmamap[i], 
+		sc->rx_mbuf[i], seg, &nsegs, BUS_DMA_NOWAIT);
+
+	KASSERT(nsegs == 1, ("Too many segments returned!"));
+	if (nsegs != 1 || error)
+		panic("%s: nsegs(%d), error(%d)",__func__, nsegs, error);
+
+	bus_dmamap_sync(sc->mbuf_dtag, sc->rx_dmamap[i], BUS_DMASYNC_PREREAD);
+
+	/* Create and submit new rx descriptor*/
+	bd.next = next;
+	bd.bufptr = seg->ds_addr;
+	bd.buflen = MCLBYTES-1;
+	bd.bufoff = 2; /* make IP hdr aligned with 4 */
+	bd.pktlen = 0;
+	bd.flags = CPDMA_BD_OWNER;
+	cpsw_cpdma_write_rxbd(i, &bd);
+
+	return (0);
+}
+
+
+static int
+cpsw_encap(struct cpsw_softc *sc, struct mbuf *m0)
+{
+	bus_dma_segment_t seg[1];
+	struct cpsw_cpdma_bd bd;
+	int error;
+	int nsegs;
+	int idx;
+
+	if (sc->txbd_queue_size == CPSW_MAX_TX_BUFFERS)
+		return (ENOBUFS);
+
+	idx = sc->txbd_head + sc->txbd_queue_size;
+
+	if (idx >= (CPSW_MAX_TX_BUFFERS) )
+		idx -= CPSW_MAX_TX_BUFFERS;
+
+	/* Create mapping in DMA memory */
+	error = bus_dmamap_load_mbuf_sg(sc->mbuf_dtag, sc->tx_dmamap[idx], m0, seg, &nsegs,
+	    BUS_DMA_NOWAIT);
+	sc->tc[idx]++;
+	if (error != 0 || nsegs != 1 ) {
+		bus_dmamap_unload(sc->mbuf_dtag, sc->tx_dmamap[idx]);
+		return ((error != 0) ? error : -1);
+	}
+	bus_dmamap_sync(sc->mbuf_dtag, sc->tx_dmamap[idx], BUS_DMASYNC_PREWRITE);
+
+	/* Fill descriptor data */
+	bd.next = 0;
+	bd.bufptr = seg->ds_addr;
+	bd.bufoff = 0;
+	bd.buflen = (seg->ds_len < 64 ? 64 : seg->ds_len);
+	bd.pktlen = (seg->ds_len < 64 ? 64 : seg->ds_len);
+	/* Set OWNERSHIP, SOP, EOP */
+	bd.flags = (7<<13);
+
+	/* Write descriptor */
+	cpsw_cpdma_write_txbd(idx, &bd);
+
+	/* Previous descriptor should point to us */
+	cpsw_cpdma_write_txbd_next(((idx-1<0)?(CPSW_MAX_TX_BUFFERS-1):(idx-1)),
+		cpsw_cpdma_txbd_paddr(idx));
+
+	sc->txbd_queue_size++;
+
+	return (0);
+}
+
+static void
+cpsw_start(struct ifnet *ifp)
+{
+	struct cpsw_softc *sc = ifp->if_softc;
+
+	CPSW_TX_LOCK(sc);
+	cpsw_start_locked(ifp);
+	CPSW_TX_UNLOCK(sc);
+}
+
+static void
+cpsw_start_locked(struct ifnet *ifp)
+{
+	struct cpsw_softc *sc = ifp->if_softc;
+	struct mbuf *m0, *mtmp;
+	uint32_t queued = 0;
+
+	CPSW_TX_LOCK_ASSERT(sc);
+
+	if ((ifp->if_drv_flags & (IFF_DRV_RUNNING | IFF_DRV_OACTIVE)) !=
+	    IFF_DRV_RUNNING)
+		return;
+
+	for (;;) {
+		/* Get packet from the queue */
+		IF_DEQUEUE(&ifp->if_snd, m0);
+		if (m0 == NULL)
+			break;
+
+		mtmp = m_defrag(m0, M_DONTWAIT);
+		if (mtmp)
+			m0 = mtmp;
+
+		if (cpsw_encap(sc, m0)) {
+			IF_PREPEND(&ifp->if_snd, m0);
+			ifp->if_drv_flags |= IFF_DRV_OACTIVE;
+			break;
+		}
+		queued++;
+		BPF_MTAP(ifp, m0);
+	}
+
+	if (!queued)
+		return;
+
+	if (sc->eoq) {
+		cpsw_write_4(CPSW_CPDMA_TX_HDP(0), cpsw_cpdma_txbd_paddr(sc->txbd_head));
+		sc->eoq = 0;
+	}
+	sc->wd_timer = 5;
+}
+
+static void
+cpsw_stop(struct cpsw_softc *sc)
+{
+	struct ifnet *ifp;
+
+	ifp = sc->ifp;
+
+	if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0)
+		return;
+
+	/* Stop tick engine */
+	callout_stop(&sc->wd_callout);
+
+	/* Disable interface */
+	ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE);
+	sc->wd_timer = 0;
+
+	/* Disable interrupts  TODO */
+
+}
+
+static int
+cpsw_ioctl(struct ifnet *ifp, u_long command, caddr_t data)
+{
+	struct cpsw_softc *sc = ifp->if_softc;
+	struct ifreq *ifr = (struct ifreq *)data;
+	int error;
+	uint32_t flags;
+
+	error = 0;
+
+	// FIXME
+	switch (command) {
+	case SIOCSIFFLAGS:
+		CPSW_GLOBAL_LOCK(sc);
+		if (ifp->if_flags & IFF_UP) {
+			if (ifp->if_drv_flags & IFF_DRV_RUNNING) {
+				flags = ifp->if_flags ^ sc->cpsw_if_flags;
+				if (flags & IFF_PROMISC)
+					printf("%s: SIOCSIFFLAGS "
+						"IFF_PROMISC unimplemented\n",
+						__func__);
+
+				if (flags & IFF_ALLMULTI)
+					printf("%s: SIOCSIFFLAGS "
+						"IFF_ALLMULTI unimplemented\n",
+						__func__);
+			} else {
+				printf("%s: SIOCSIFFLAGS cpsw_init_locked\n", __func__);
+				//cpsw_init_locked(sc);
+			}
+		}
+		else if (ifp->if_drv_flags & IFF_DRV_RUNNING)
+			cpsw_stop(sc);
+
+		sc->cpsw_if_flags = ifp->if_flags;
+		CPSW_GLOBAL_UNLOCK(sc);
+		break;
+		printf("%s: SIOCSIFFLAGS\n",__func__);
+		break;
+	case SIOCADDMULTI:
+		printf("%s: SIOCADDMULTI\n",__func__);
+		break;
+	case SIOCDELMULTI:
+		printf("%s: SIOCDELMULTI\n",__func__);
+		break;
+	case SIOCSIFCAP:
+		printf("%s: SIOCSIFCAP\n",__func__);
+		break;
+	case SIOCGIFMEDIA: /* fall through */
+		printf("%s: SIOCGIFMEDIA\n",__func__);
+		error = ifmedia_ioctl(ifp, ifr, &sc->mii->mii_media, command);
+		break;
+	case SIOCSIFMEDIA:
+		printf("%s: SIOCSIFMEDIA\n",__func__);
+		error = ifmedia_ioctl(ifp, ifr, &sc->mii->mii_media, command);
+		break;
+	default:
+		error = ether_ioctl(ifp, command, data);
+	}
+	return (error);
+}
+
+static void
+cpsw_ifmedia_sts(struct ifnet *ifp, struct ifmediareq *ifmr)
+{
+	struct cpsw_softc *sc = ifp->if_softc;
+	struct mii_data *mii;
+
+	CPSW_TX_LOCK(sc);
+
+	mii = sc->mii;
+	mii_pollstat(mii);
+
+	ifmr->ifm_active = mii->mii_media_active;
+	ifmr->ifm_status = mii->mii_media_status;
+
+	CPSW_TX_UNLOCK(sc);
+}
+
+
+static int
+cpsw_ifmedia_upd(struct ifnet *ifp)
+{
+	struct cpsw_softc *sc = ifp->if_softc;
+
+	if (ifp->if_flags & IFF_UP) {
+		CPSW_GLOBAL_LOCK(sc);
+
+		sc->cpsw_media_status = sc->mii->mii_media.ifm_media;
+		mii_mediachg(sc->mii);
+		cpsw_init_locked(sc);
+
+		CPSW_GLOBAL_UNLOCK(sc);
+	}
+
+	return (0);
+}
+
+static void
+cpsw_intr_rx_thresh(void *arg)
+{
+	(void)arg; /* UNUSED */
+}
+
+static void
+cpsw_intr_rx(void *arg)
+{
+	struct cpsw_softc *sc = arg;
+	CPSW_RX_LOCK(sc);
+	cpsw_intr_rx_locked(arg);
+	CPSW_RX_UNLOCK(sc);
+}
+
+static void
+cpsw_intr_rx_locked(void *arg)
+{
+	struct cpsw_softc *sc = arg;
+	struct cpsw_cpdma_bd bd;
+	struct ifnet *ifp;
+	int i;
+
+	ifp = sc->ifp;
+
+	i = sc->rxbd_head;
+	cpsw_cpdma_read_rxbd(i, &bd);
+
+	while (bd.flags & CPDMA_BD_SOP) {
+		cpsw_write_4(CPSW_CPDMA_RX_CP(0), cpsw_cpdma_rxbd_paddr(i));
+
+		bus_dmamap_sync(sc->mbuf_dtag, sc->rx_dmamap[i], BUS_DMASYNC_POSTREAD);
+
+		/* Fill mbuf */
+		sc->rx_mbuf[i]->m_hdr.mh_data +=2;
+		sc->rx_mbuf[i]->m_len = bd.pktlen-2;
+		sc->rx_mbuf[i]->m_pkthdr.len = bd.pktlen-2;
+		sc->rx_mbuf[i]->m_flags |= M_PKTHDR;
+		sc->rx_mbuf[i]->m_pkthdr.rcvif = ifp;
+
+		if ((ifp->if_capenable & IFCAP_RXCSUM) != 0) {
+			/* check for valid CRC by looking into pkt_err[5:4] */
+			if ( (bd.flags & CPDMA_BD_PKT_ERR_MASK) == 0  ) {
+				sc->rx_mbuf[i]->m_pkthdr.csum_flags |= CSUM_IP_CHECKED;
+				sc->rx_mbuf[i]->m_pkthdr.csum_flags |= CSUM_IP_VALID;
+				sc->rx_mbuf[i]->m_pkthdr.csum_data = 0xffff;
+			}
+		}
+
+		/* Handover packet */
+		CPSW_RX_UNLOCK(sc);
+		(*ifp->if_input)(ifp, sc->rx_mbuf[i]);
+		CPSW_RX_LOCK(sc);
+
+		/* Allocate new buffer for current descriptor */
+		cpsw_new_rxbuf(sc, i, 0);
+
+		/* we are not at tail so old tail BD should point to new one */
+		cpsw_cpdma_write_rxbd_next(sc->rxbd_tail,
+			cpsw_cpdma_rxbd_paddr(i));
+
+		/* Check if EOQ is reached */
+		if (cpsw_cpdma_read_rxbd_flags(sc->rxbd_tail) & CPDMA_BD_EOQ) {
+			cpsw_write_4(CPSW_CPDMA_RX_HDP(0), cpsw_cpdma_rxbd_paddr(i));
+		}
+		sc->rxbd_tail = i;
+
+		/* read next descriptor */
+		if (++i == CPSW_MAX_RX_BUFFERS)
+			i = 0;
+		cpsw_cpdma_read_rxbd(i, &bd);
+		sc->rxbd_head = i;
+	}
+
+	cpsw_write_4(CPSW_CPDMA_CPDMA_EOI_VECTOR, 1);
+}
+
+static void
+cpsw_intr_tx(void *arg)
+{
+	struct cpsw_softc *sc = arg;
+	CPSW_TX_LOCK(sc);
+	cpsw_intr_tx_locked(arg);
+	CPSW_TX_UNLOCK(sc);
+}
+
+static void
+cpsw_intr_tx_locked(void *arg)
+{
+	struct cpsw_softc *sc = arg;
+	uint32_t flags;
+
+	if(sc->txbd_head == -1)
+		return;
+
+	if(sc->txbd_queue_size<1) {
+		/* in some casses interrupt happens even when there is no
+		   data in transmit queue */
+		return;
+	}
+
+	/* Disable watchdog */
+	sc->wd_timer = 0;
+
+	flags = cpsw_cpdma_read_txbd_flags(sc->txbd_head);
+
+	/* After BD is transmitted CPDMA will set OWNER to 0 */
+	if (flags & CPDMA_BD_OWNER)
+		return;
+
+	if(flags & CPDMA_BD_EOQ)
+		sc->eoq=1;
+
+	/* release dmamap and mbuf */
+	bus_dmamap_sync(sc->mbuf_dtag, sc->tx_dmamap[sc->txbd_head],
+	    BUS_DMASYNC_POSTWRITE);
+	bus_dmamap_unload(sc->mbuf_dtag, sc->tx_dmamap[sc->txbd_head]);
+	m_freem(sc->tx_mbuf[sc->txbd_head]);
+
+	cpsw_write_4(CPSW_CPDMA_TX_CP(0), cpsw_cpdma_txbd_paddr(sc->txbd_head));
+
+	if (++sc->txbd_head == CPSW_MAX_TX_BUFFERS)
+		sc->txbd_head = 0;
+
+	--sc->txbd_queue_size;
+
+	cpsw_write_4(CPSW_CPDMA_CPDMA_EOI_VECTOR, 2);
+	cpsw_write_4(CPSW_CPDMA_CPDMA_EOI_VECTOR, 1);
+}
+
+static void
+cpsw_intr_misc(void *arg)
+{
+	struct cpsw_softc *sc = arg;
+	uint32_t stat = cpsw_read_4(CPSW_WR_C_MISC_STAT(0));
+	printf("%s: stat=%x\n",__func__,stat);
+	/* EOI_RX_PULSE */
+	cpsw_write_4(CPSW_CPDMA_CPDMA_EOI_VECTOR, 3);
+}
+
+static void
+cpsw_tick(void *msc)
+{
+	struct cpsw_softc *sc = msc;
+
+	/* Check for TX timeout */
+	cpsw_watchdog(sc);
+
+	mii_tick(sc->mii);
+
+	/* Check for media type change */
+	if(sc->cpsw_media_status != sc->mii->mii_media.ifm_media) {
+		printf("%s: media type changed (ifm_media=%x)\n",__func__, 
+			sc->mii->mii_media.ifm_media);
+		cpsw_ifmedia_upd(sc->ifp);
+	}
+
+	/* Schedule another timeout one second from now */
+	callout_reset(&sc->wd_callout, hz, cpsw_tick, sc);
+}
+
+static void
+cpsw_watchdog(struct cpsw_softc *sc)
+{
+	struct ifnet *ifp;
+
+	ifp = sc->ifp;
+
+	CPSW_GLOBAL_LOCK(sc);
+
+	if (sc->wd_timer == 0 || --sc->wd_timer) {
+		CPSW_GLOBAL_UNLOCK(sc);
+		return;
+	}
+
+	ifp->if_oerrors++;
+	if_printf(ifp, "watchdog timeout\n");
+
+	cpsw_stop(sc);
+	cpsw_init_locked(sc);
+
+	CPSW_GLOBAL_UNLOCK(sc);
+}
+
+static void
+cpsw_init(void *arg)
+{
+	struct cpsw_softc *sc = arg;
+	CPSW_GLOBAL_LOCK(sc);
+	cpsw_init_locked(arg);
+	CPSW_GLOBAL_UNLOCK(sc);
+}
+
+int once = 1;
+
+static void
+cpsw_init_locked(void *arg)
+{
+	struct ifnet *ifp;
+	struct cpsw_softc *sc = arg;
+	uint8_t  broadcast_address[6] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
+	uint32_t next_bdp;
+	uint32_t i;
+
+	ifp = sc->ifp;
+	if ((ifp->if_drv_flags & IFF_DRV_RUNNING) != 0)
+		return;
+
+	printf("%s: start\n",__func__);
+
+	/* Reset writer */
+	cpsw_write_4(CPSW_WR_SOFT_RESET, 1);
+	while(cpsw_read_4(CPSW_WR_SOFT_RESET) & 1);
+
+	/* Reset SS */
+	cpsw_write_4(CPSW_SS_SOFT_RESET, 1);
+	while(cpsw_read_4(CPSW_SS_SOFT_RESET) & 1);
+
+	/* Clear table (30) and enable ALE(31) */
+	if (once)
+		cpsw_write_4(CPSW_ALE_CONTROL, (3 << 30));
+	else
+		cpsw_write_4(CPSW_ALE_CONTROL, (1 << 31));
+	once = 0; // FIXME
+
+	/* Reset and init Sliver port 1 and 2 */
+	for(i=0;i<2;i++) {
+		/* Reset */
+		cpsw_write_4(CPSW_SL_SOFT_RESET(i), 1);
+		while(cpsw_read_4(CPSW_SL_SOFT_RESET(i)) & 1);
+		/* Set Slave Mapping */
+		cpsw_write_4(CPSW_SL_RX_PRI_MAP(i),0x76543210);
+		cpsw_write_4(CPSW_PORT_P_TX_PRI_MAP(i+1),0x33221100);
+		cpsw_write_4(CPSW_SL_RX_MAXLEN(i),0x5f2);
+		/* Set MAC Address */
+		cpsw_write_4(CPSW_PORT_P_SA_HI(i+1), sc->mac_addr[0] |
+			(sc->mac_addr[1] <<  8) |
+			(sc->mac_addr[2] << 16) |
+			(sc->mac_addr[3] << 24));
+		cpsw_write_4(CPSW_PORT_P_SA_LO(i+1), sc->mac_addr[4] |
+			(sc->mac_addr[5] <<  8));
+
+		/* Set MACCONTROL for ports 0,1: FULLDUPLEX(1), GMII_EN(5),
+		   IFCTL_A(15), IFCTL_B(16) FIXME */
+		cpsw_write_4(CPSW_SL_MACCONTROL(i), 1 | (1<<5) | (1<<15));
+
+		/* Set ALE port to forwarding(3) */
+		cpsw_write_4(CPSW_ALE_PORTCTL(i+1), 3);
+	}
+
+	/* Set Host Port Mapping */
+	cpsw_write_4(CPSW_PORT_P0_CPDMA_TX_PRI_MAP, 0x76543210);
+	cpsw_write_4(CPSW_PORT_P0_CPDMA_RX_CH_MAP, 0);
+
+	/* Set ALE port to forwarding(3)*/
+	cpsw_write_4(CPSW_ALE_PORTCTL(0), 3);
+
+	/* Add own MAC address and broadcast to ALE */
+	cpsw_ale_uc_entry_set(sc, 0, sc->mac_addr);
+	cpsw_ale_mc_entry_set(sc, 7, broadcast_address);
+
+	cpsw_write_4(CPSW_SS_PTYPE, 0);
+	/* Enable statistics for ports 0, 1 and 2 */
+	cpsw_write_4(CPSW_SS_STAT_PORT_EN, 7);
+
+	/* Reset CPDMA */
+	cpsw_write_4(CPSW_CPDMA_SOFT_RESET, 1);
+	while(cpsw_read_4(CPSW_CPDMA_SOFT_RESET) & 1);
+
+        for(i = 0; i < 8; i++) {
+		cpsw_write_4(CPSW_CPDMA_TX_HDP(i), 0);
+		cpsw_write_4(CPSW_CPDMA_RX_HDP(i), 0);
+		cpsw_write_4(CPSW_CPDMA_TX_CP(i), 0);
+		cpsw_write_4(CPSW_CPDMA_RX_CP(i), 0);
+        }
+
+	cpsw_write_4(CPSW_CPDMA_RX_FREEBUFFER(0), 0);
+
+	/* Initialize RX Buffer Descriptors */
+	i = CPSW_MAX_RX_BUFFERS;
+	next_bdp = 0;
+	while (i--) {
+		cpsw_new_rxbuf(sc, i, next_bdp);
+		/* Increment number of free RX buffers */
+		//cpsw_write_4(CPSW_CPDMA_RX_FREEBUFFER(0), 1);
+		next_bdp = cpsw_cpdma_rxbd_paddr(i);
+	}
+
+	sc->rxbd_head = 0;
+	sc->rxbd_tail = CPSW_MAX_RX_BUFFERS-1;
+	sc->txbd_head = 0;
+	sc->eoq = 1;
+	sc->txbd_queue_size = 0;
+
+	/* Make IP hdr aligned with 4 */
+	cpsw_write_4(CPSW_CPDMA_RX_BUFFER_OFFSET, 2);
+	/* Write channel 0 RX HDP */
+	cpsw_write_4(CPSW_CPDMA_RX_HDP(0), cpsw_cpdma_rxbd_paddr(0));
+
+	/* Clear all interrupt Masks */
+	cpsw_write_4(CPSW_CPDMA_RX_INTMASK_CLEAR, 0xFFFFFFFF);
+	cpsw_write_4(CPSW_CPDMA_TX_INTMASK_CLEAR, 0xFFFFFFFF);
+
+	/* Enable TX & RX DMA */
+	cpsw_write_4(CPSW_CPDMA_TX_CONTROL, 1);
+	cpsw_write_4(CPSW_CPDMA_RX_CONTROL, 1);
+
+	/* Enable TX and RX interrupt receive for core 0 */
+	cpsw_write_4(CPSW_WR_C_TX_EN(0), 0xFF);
+	cpsw_write_4(CPSW_WR_C_RX_EN(0), 0xFF);
+	//cpsw_write_4(CPSW_WR_C_MISC_EN(0), 0x3F);
+
+	/* Enable host Error Interrupt */
+	cpsw_write_4(CPSW_CPDMA_DMA_INTMASK_SET, 1);
+
+	/* Enable interrupts for TX and RX Channel 0 */
+	cpsw_write_4(CPSW_CPDMA_TX_INTMASK_SET, 1);
+	cpsw_write_4(CPSW_CPDMA_RX_INTMASK_SET, 1);
+
+	/* Ack stalled irqs */
+	cpsw_write_4(CPSW_CPDMA_CPDMA_EOI_VECTOR, 0);
+	cpsw_write_4(CPSW_CPDMA_CPDMA_EOI_VECTOR, 1);
+	cpsw_write_4(CPSW_CPDMA_CPDMA_EOI_VECTOR, 2);
+	cpsw_write_4(CPSW_CPDMA_CPDMA_EOI_VECTOR, 3);
+
+	/* Initialze MDIO - ENABLE, PREAMBLE=0, FAULTENB, CLKDIV=0xFF */
+	/* TODO Calculate MDCLK=CLK/(CLKDIV+1) */
+	cpsw_write_4(MDIOCONTROL, (1<<30) | (1<<18) | 0xFF);
+
+	/* Select MII in GMII_SEL, Internal Delay mode */
+	//ti_scm_reg_write_4(0x650, 0);
+
+	/* Activate network interface */
+	sc->ifp->if_drv_flags |= IFF_DRV_RUNNING;
+	sc->ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
+	sc->wd_timer = 0;
+	callout_reset(&sc->wd_callout, hz, cpsw_tick, sc);
+}
+
+static void
+cpsw_ale_read_entry(struct cpsw_softc *sc, uint16_t idx, uint32_t *ale_entry)
+{
+	cpsw_write_4(CPSW_ALE_TBLCTL, idx & 1023);
+	ale_entry[0] = cpsw_read_4(CPSW_ALE_TBLW0);
+	ale_entry[1] = cpsw_read_4(CPSW_ALE_TBLW1);
+	ale_entry[2] = cpsw_read_4(CPSW_ALE_TBLW2);
+}
+
+static void
+cpsw_ale_write_entry(struct cpsw_softc *sc, uint16_t idx, uint32_t *ale_entry)
+{
+	cpsw_write_4(CPSW_ALE_TBLW0, ale_entry[0]);
+	cpsw_write_4(CPSW_ALE_TBLW1, ale_entry[1]);
+	cpsw_write_4(CPSW_ALE_TBLW2, ale_entry[2]);
+	cpsw_write_4(CPSW_ALE_TBLCTL, (idx & 1023) | (1 << 31));
+}
+
+static int
+cpsw_ale_find_entry_by_mac(struct cpsw_softc *sc, uint8_t *mac)
+{
+	int i;
+	uint32_t ale_entry[3];
+	for(i=0; i< CPSW_MAX_ALE_ENTRIES; i++) {
+		cpsw_ale_read_entry(sc, i, ale_entry);
+		if ((((ale_entry[1] >> 8) & 0xFF) == mac[0]) &&
+		    (((ale_entry[1] >> 0) & 0xFF) == mac[1]) &&
+		    (((ale_entry[0] >>24) & 0xFF) == mac[2]) &&
+		    (((ale_entry[0] >>16) & 0xFF) == mac[3]) &&
+		    (((ale_entry[0] >> 8) & 0xFF) == mac[4]) &&
+		    (((ale_entry[0] >> 0) & 0xFF) == mac[5])) {
+			return (i);
+		}
+	}
+	return CPSW_MAX_ALE_ENTRIES;
+}
+
+static int
+cpsw_ale_find_free_entry(struct cpsw_softc *sc)
+{
+	int i;
+	uint32_t ale_entry[3];
+	for(i=0; i< CPSW_MAX_ALE_ENTRIES; i++) {
+		cpsw_ale_read_entry(sc, i, ale_entry);
+		/* Entry Type[61:60] is 0 for free entry */ 
+		if (((ale_entry[1] >> 28) & 3) == 0) {
+			return i;
+		}
+	}
+	return CPSW_MAX_ALE_ENTRIES;
+}
+
+
+static int
+cpsw_ale_uc_entry_set(struct cpsw_softc *sc, uint8_t port, uint8_t *mac)
+{
+	int i;
+	uint32_t ale_entry[3];
+
+	if ((i = cpsw_ale_find_entry_by_mac(sc, mac)) == CPSW_MAX_ALE_ENTRIES) {
+		i = cpsw_ale_find_free_entry(sc);
+	}
+
+	if (i == CPSW_MAX_ALE_ENTRIES)
+		return (ENOMEM);
+
+	/* Set MAC address */
+	ale_entry[0] = mac[2]<<24 | mac[3]<<16 | mac[4]<<8 | mac[5];
+	ale_entry[1] = mac[0]<<8 | mac[1];
+
+	/* Entry type[61:60] is addr entry(1) */
+	ale_entry[1] |= 0x10<<24;
+
+	/* Set portmask [67:66] */
+	ale_entry[2] = (port & 3) << 2;
+
+	cpsw_ale_write_entry(sc, i, ale_entry);
+
+	return 0;
+}
+
+static int
+cpsw_ale_mc_entry_set(struct cpsw_softc *sc, uint8_t portmap, uint8_t *mac)
+{
+	int i;
+	uint32_t ale_entry[3];
+
+	if ((i = cpsw_ale_find_entry_by_mac(sc, mac)) == CPSW_MAX_ALE_ENTRIES) {
+		i = cpsw_ale_find_free_entry(sc);
+	}
+
+	if (i == CPSW_MAX_ALE_ENTRIES)
+		return (ENOMEM);
+
+	/* Set MAC address */
+	ale_entry[0] = mac[2]<<24 | mac[3]<<16 | mac[4]<<8 | mac[5];
+	ale_entry[1] = mac[0]<<8 | mac[1];
+
+	/* Entry type[61:60] is addr entry(1), Mcast fwd state[63:62] is fw(3)*/
+	ale_entry[1] |= 0xd0<<24;
+
+	/* Set portmask [68:66] */
+	ale_entry[2] = (portmap & 7) << 2;
+
+	cpsw_ale_write_entry(sc, i, ale_entry);
+
+	return 0;
+}
+
+#ifdef CPSW_DEBUG
+static void
+cpsw_ale_dump_table(struct cpsw_softc *sc) {
+	int i;
+	uint32_t ale_entry[3];
+	for(i=0; i< CPSW_MAX_ALE_ENTRIES; i++) {
+		cpsw_ale_read_entry(sc, i, ale_entry);
+		if (ale_entry[0] || ale_entry[1] || ale_entry[2]) {
+			printf("ALE[%4u] %08x %08x %08x ", i, ale_entry[0],
+				ale_entry[1],ale_entry[2]);
+			printf("mac: %02x:%02x:%02x:%02x:%02x:%02x ",
+				(ale_entry[1] >> 8) & 0xFF,
+				(ale_entry[1] >> 0) & 0xFF,
+				(ale_entry[0] >>24) & 0xFF,
+				(ale_entry[0] >>16) & 0xFF,
+				(ale_entry[0] >> 8) & 0xFF,
+				(ale_entry[0] >> 0) & 0xFF);
+			printf( ((ale_entry[1]>>8)&1) ? "mcast " : "ucast ");
+			printf("type: %u ", (ale_entry[1]>>28)&3);
+			printf("port: %u ", (ale_entry[2]>>2)&7);
+			printf("\n");
+		}
+	}
+}
+#endif
diff -r 7fffa673adcd -r a301a330526b head/sys/arm/ti/cpsw/if_cpswreg.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/head/sys/arm/ti/cpsw/if_cpswreg.h	Wed Aug 15 11:16:36 2012 +0300
@@ -0,0 +1,107 @@
+/*-
+ * Copyright (c) 2012 Damjan Marion <dmarion at Freebsd.org>
+ * 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: head/sys/arm/ti/cpsw/if_cpswreg.h 239281 2012-08-15 06:31:32Z gonzo $
+ */
+
+#ifndef	_IF_CPSWREG_H
+#define	_IF_CPSWREG_H
+
+#define CPSW_SS_OFFSET			0x0000
+#define CPSW_SS_IDVER			(CPSW_SS_OFFSET + 0x00)
+#define CPSW_SS_SOFT_RESET		(CPSW_SS_OFFSET + 0x08)
+#define CPSW_SS_STAT_PORT_EN		(CPSW_SS_OFFSET + 0x0C)
+#define CPSW_SS_PTYPE			(CPSW_SS_OFFSET + 0x10)
+
+#define CPSW_PORT_OFFSET		0x0100
+#define CPSW_PORT_P_TX_PRI_MAP(p)	(CPSW_PORT_OFFSET + 0x118 + ((p-1) * 0x100))
+#define CPSW_PORT_P0_CPDMA_TX_PRI_MAP	(CPSW_PORT_OFFSET + 0x01C)
+#define CPSW_PORT_P0_CPDMA_RX_CH_MAP	(CPSW_PORT_OFFSET + 0x020)
+#define CPSW_PORT_P_SA_LO(p)		(CPSW_PORT_OFFSET + 0x120 + ((p-1) * 0x100))
+#define CPSW_PORT_P_SA_HI(p)		(CPSW_PORT_OFFSET + 0x124 + ((p-1) * 0x100))
+
+#define CPSW_CPDMA_OFFSET		0x0800
+#define CPSW_CPDMA_TX_CONTROL		(CPSW_CPDMA_OFFSET + 0x04)
+#define CPSW_CPDMA_RX_CONTROL		(CPSW_CPDMA_OFFSET + 0x14)
+#define CPSW_CPDMA_SOFT_RESET		(CPSW_CPDMA_OFFSET + 0x1c)
+#define CPSW_CPDMA_DMACONTROL		(CPSW_CPDMA_OFFSET + 0x20)
+#define CPSW_CPDMA_DMASTATUS		(CPSW_CPDMA_OFFSET + 0x24)
+#define CPSW_CPDMA_RX_BUFFER_OFFSET	(CPSW_CPDMA_OFFSET + 0x28)
+#define CPSW_CPDMA_TX_INTSTAT_RAW	(CPSW_CPDMA_OFFSET + 0x80)
+#define CPSW_CPDMA_TX_INTSTAT_MASKED	(CPSW_CPDMA_OFFSET + 0x84)
+#define CPSW_CPDMA_TX_INTMASK_SET	(CPSW_CPDMA_OFFSET + 0x88)
+#define CPSW_CPDMA_TX_INTMASK_CLEAR	(CPSW_CPDMA_OFFSET + 0x8C)
+#define CPSW_CPDMA_CPDMA_EOI_VECTOR	(CPSW_CPDMA_OFFSET + 0x94)
+#define CPSW_CPDMA_RX_INTSTAT_RAW	(CPSW_CPDMA_OFFSET + 0xA0)
+#define CPSW_CPDMA_RX_INTSTAT_MASKED	(CPSW_CPDMA_OFFSET + 0xA4)
+#define CPSW_CPDMA_RX_INTMASK_SET	(CPSW_CPDMA_OFFSET + 0xA8)
+#define CPSW_CPDMA_RX_INTMASK_CLEAR	(CPSW_CPDMA_OFFSET + 0xAc)
+#define CPSW_CPDMA_DMA_INTSTAT_RAW	(CPSW_CPDMA_OFFSET + 0xB0)
+#define CPSW_CPDMA_DMA_INTSTAT_MASKED	(CPSW_CPDMA_OFFSET + 0xB4)
+#define CPSW_CPDMA_DMA_INTMASK_SET	(CPSW_CPDMA_OFFSET + 0xB8)
+#define CPSW_CPDMA_DMA_INTMASK_CLEAR	(CPSW_CPDMA_OFFSET + 0xBC)
+#define CPSW_CPDMA_RX_FREEBUFFER(p)	(CPSW_CPDMA_OFFSET + 0x0e0 + ((p) * 0x04))
+#define CPSW_CPDMA_TX_HDP(p)		(CPSW_CPDMA_OFFSET + 0x200 + ((p) * 0x04))
+#define CPSW_CPDMA_RX_HDP(p)		(CPSW_CPDMA_OFFSET + 0x220 + ((p) * 0x04))
+#define CPSW_CPDMA_TX_CP(p)		(CPSW_CPDMA_OFFSET + 0x240 + ((p) * 0x04))
+#define CPSW_CPDMA_RX_CP(p)		(CPSW_CPDMA_OFFSET + 0x260 + ((p) * 0x04))
+
+#define CPSW_CPTS_OFFSET		0x0C00
+
+#define CPSW_ALE_OFFSET			0x0D00
+#define CPSW_ALE_CONTROL		(CPSW_ALE_OFFSET + 0x08)
+#define CPSW_ALE_TBLCTL			(CPSW_ALE_OFFSET + 0x20)
+#define CPSW_ALE_TBLW2			(CPSW_ALE_OFFSET + 0x34)
+#define CPSW_ALE_TBLW1			(CPSW_ALE_OFFSET + 0x38)
+#define CPSW_ALE_TBLW0			(CPSW_ALE_OFFSET + 0x3C)
+#define CPSW_ALE_PORTCTL(p)		(CPSW_ALE_OFFSET + 0x40 + ((p) * 0x04))
+
+#define CPSW_SL_OFFSET			0x0D80
+#define CPSW_SL_MACCONTROL(p)		(CPSW_SL_OFFSET + (0x40 * (p)) + 0x04)
+#define CPSW_SL_SOFT_RESET(p)		(CPSW_SL_OFFSET + (0x40 * (p)) + 0x0C)
+#define CPSW_SL_RX_MAXLEN(p)		(CPSW_SL_OFFSET + (0x40 * (p)) + 0x10)
+#define CPSW_SL_RX_PRI_MAP(p)		(CPSW_SL_OFFSET + (0x40 * (p)) + 0x24)
+
+#define MDIO_OFFSET			0x1000
+#define MDIOCONTROL			(MDIO_OFFSET + 0x04)
+#define MDIOUSERACCESS0			(MDIO_OFFSET + 0x80)
+#define MDIOUSERPHYSEL0			(MDIO_OFFSET + 0x84)
+
+#define CPSW_WR_OFFSET			0x1200
+#define CPSW_WR_SOFT_RESET		(CPSW_WR_OFFSET + 0x04)
+#define CPSW_WR_CONTROL			(CPSW_WR_OFFSET + 0x08)
+#define CPSW_WR_INT_CONTROL		(CPSW_WR_OFFSET + 0x0c)
+#define CPSW_WR_C_RX_THRESH_EN(p)	(CPSW_WR_OFFSET + (0x10 * (p)) + 0x10)
+#define CPSW_WR_C_RX_EN(p)		(CPSW_WR_OFFSET + (0x10 * (p)) + 0x14)
+#define CPSW_WR_C_TX_EN(p)		(CPSW_WR_OFFSET + (0x10 * (p)) + 0x18)
+#define CPSW_WR_C_MISC_EN(p)		(CPSW_WR_OFFSET + (0x10 * (p)) + 0x1C)
+#define CPSW_WR_C_RX_THRESH_STAT(p)	(CPSW_WR_OFFSET + (0x10 * (p)) + 0x40)
+#define CPSW_WR_C_RX_STAT(p)		(CPSW_WR_OFFSET + (0x10 * (p)) + 0x44)
+#define CPSW_WR_C_TX_STAT(p)		(CPSW_WR_OFFSET + (0x10 * (p)) + 0x48)
+#define CPSW_WR_C_MISC_STAT(p)		(CPSW_WR_OFFSET + (0x10 * (p)) + 0x4C)
+
+#define CPSW_CPPI_RAM_OFFSET		0x2000
+
+#endif /*_IF_CPSWREG_H */
diff -r 7fffa673adcd -r a301a330526b head/sys/arm/ti/cpsw/if_cpswvar.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/head/sys/arm/ti/cpsw/if_cpswvar.h	Wed Aug 15 11:16:36 2012 +0300
@@ -0,0 +1,124 @@
+/*-
+ * Copyright (c) 2012 Damjan Marion <dmarion at Freebsd.org>
+ * 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: head/sys/arm/ti/cpsw/if_cpswvar.h 239281 2012-08-15 06:31:32Z gonzo $
+ */
+
+#ifndef	_IF_CPSWVAR_H
+#define	_IF_CPSWVAR_H
+
+#define CPSW_INTR_COUNT		4
+
+/* MII BUS  */
+#define CPSW_MIIBUS_RETRIES	5
+#define CPSW_MIIBUS_DELAY	1000
+
+#define CPSW_MAX_TX_BUFFERS	128
+#define CPSW_MAX_RX_BUFFERS	128
+#define CPSW_MAX_ALE_ENTRIES	1024
+
+struct cpsw_softc {
+	struct ifnet	*ifp;
+	phandle_t	node;
+	device_t	dev;
+	uint8_t		mac_addr[ETHER_ADDR_LEN];
+	device_t	miibus;
+	struct mii_data	*mii;
+	struct mtx	tx_lock;			/* transmitter lock */
+	struct mtx	rx_lock;			/* receiver lock */
+	struct resource	*res[1 + CPSW_INTR_COUNT];	/* resources */
+	void		*ih_cookie[CPSW_INTR_COUNT];	/* interrupt handlers cookies */
+
+	uint32_t	cpsw_if_flags;
+	int		cpsw_media_status;
+
+	struct callout	wd_callout;
+	int		wd_timer;
+
+	/* buffers */
+	bus_dma_tag_t	mbuf_dtag;
+	bus_dmamap_t	tx_dmamap[CPSW_MAX_TX_BUFFERS];
+	bus_dmamap_t	rx_dmamap[CPSW_MAX_RX_BUFFERS];
+	struct mbuf	*tx_mbuf[CPSW_MAX_TX_BUFFERS];
+	struct mbuf	*rx_mbuf[CPSW_MAX_RX_BUFFERS];
+	int		txbd_head;
+	int		txbd_queue_size;
+	int		rxbd_head;
+	int		rxbd_tail;
+
+	int		tmp;
+	int		eoq;
+	int		tc[CPSW_MAX_TX_BUFFERS];
+	int		tc_unload[CPSW_MAX_TX_BUFFERS];
+	
+	struct cpsw_softc *phy_sc;
+};
+
+#define CPDMA_BD_SOP		(1<<15)
+#define CPDMA_BD_EOP		(1<<14)
+#define CPDMA_BD_OWNER		(1<<13)
+#define CPDMA_BD_EOQ		(1<<12)
+#define CPDMA_BD_PKT_ERR_MASK	(3<< 4)
+
+struct cpsw_cpdma_bd {
+	volatile uint32_t next;
+	volatile uint32_t bufptr;
+	volatile uint16_t buflen;
+	volatile uint16_t bufoff;
+	volatile uint16_t pktlen;
+	volatile uint16_t flags;
+};
+
+/* Read/Write macros */
+#define cpsw_read_4(reg)		bus_read_4(sc->res[0], reg)
+#define cpsw_write_4(reg, val)		bus_write_4(sc->res[0], reg, val)
+
+#define cpsw_cpdma_txbd_offset(i)	\
+	(CPSW_CPPI_RAM_OFFSET + ((i)*16))
+#define cpsw_cpdma_txbd_paddr(i)	(cpsw_cpdma_txbd_offset(i) + \
+	vtophys(rman_get_start(sc->res[0])))
+#define cpsw_cpdma_read_txbd(i, val)	\
+	bus_read_region_4(sc->res[0], cpsw_cpdma_txbd_offset(i), (uint32_t *) val, 4)
+#define cpsw_cpdma_write_txbd(i, val)	\
+	bus_write_region_4(sc->res[0], cpsw_cpdma_txbd_offset(i), (uint32_t *) val, 4)
+#define cpsw_cpdma_write_txbd_next(i, val) \
+	bus_write_4(sc->res[0], cpsw_cpdma_txbd_offset(i), val)
+#define cpsw_cpdma_read_txbd_flags(i) \
+	bus_read_2(sc->res[0], cpsw_cpdma_txbd_offset(i)+14)
+
+#define cpsw_cpdma_rxbd_offset(i)	\
+	(CPSW_CPPI_RAM_OFFSET + ((CPSW_MAX_TX_BUFFERS + (i))*16))
+#define cpsw_cpdma_rxbd_paddr(i)	(cpsw_cpdma_rxbd_offset(i) + \
+	vtophys(rman_get_start(sc->res[0])))
+#define cpsw_cpdma_read_rxbd(i, val)	\
+	bus_read_region_4(sc->res[0], cpsw_cpdma_rxbd_offset(i), (uint32_t *) val, 4)
+#define cpsw_cpdma_write_rxbd(i, val)	\
+	bus_write_region_4(sc->res[0], cpsw_cpdma_rxbd_offset(i), (uint32_t *) val, 4)
+#define cpsw_cpdma_write_rxbd_next(i, val) \
+	bus_write_4(sc->res[0], cpsw_cpdma_rxbd_offset(i), val)
+#define cpsw_cpdma_read_rxbd_flags(i) \
+	bus_read_2(sc->res[0], cpsw_cpdma_rxbd_offset(i)+14)
+
+#endif /*_IF_CPSWVAR_H */
diff -r 7fffa673adcd -r a301a330526b head/sys/arm/ti/files.ti
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/head/sys/arm/ti/files.ti	Wed Aug 15 11:16:36 2012 +0300
@@ -0,0 +1,25 @@
+#$FreeBSD: head/sys/arm/ti/files.ti 239281 2012-08-15 06:31:32Z gonzo $
+
+kern/kern_clocksource.c				standard
+
+arm/arm/bus_space_generic.c			standard
+arm/arm/bus_space_asm_generic.S			standard
+arm/arm/cpufunc_asm_armv5.S			standard
+arm/arm/cpufunc_asm_arm10.S			standard
+arm/arm/cpufunc_asm_arm11.S			standard
+arm/arm/cpufunc_asm_armv7.S			standard
+arm/arm/irq_dispatch.S				standard
+
+arm/ti/bus_space.c				standard
+arm/ti/common.c					standard
+arm/ti/ti_cpuid.c				standard
+arm/ti/ti_machdep.c				standard
+arm/ti/ti_prcm.c				standard
+arm/ti/ti_scm.c					standard
+
+arm/ti/ti_gpio.c				optional	gpio
+arm/ti/ti_i2c.c					optional	ti_i2c
+dev/ofw/ofw_iicbus.c				optional	iicbus
+
+dev/uart/uart_dev_ns8250.c			optional	uart
+
diff -r 7fffa673adcd -r a301a330526b head/sys/arm/ti/omap3/omap3_reg.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/head/sys/arm/ti/omap3/omap3_reg.h	Wed Aug 15 11:16:36 2012 +0300
@@ -0,0 +1,780 @@
+/*-
+ * Copyright (c) 2011
+ *	Ben Gray <ben.r.gray at 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.
+ *
+ * $FreeBSD: head/sys/arm/ti/omap3/omap3_reg.h 239281 2012-08-15 06:31:32Z gonzo $
+ */
+
+/*
+ * Texas Instruments - OMAP3xxx series processors
+ *
+ * Reference:
+ *  OMAP35x Applications Processor
+ *   Technical Reference Manual
+ *  (omap35xx_techref.pdf)
+ *
+ *
+ * Note:
+ *  The devices are mapped into address above 0xD000_0000 as the kernel space
+ *  memory is at 0xC000_0000 and above.  The first 256MB after this is reserved
+ *  for the size of the kernel, everything above that is reserved for SoC
+ *  devices.
+ *
+ */
+#ifndef _OMAP35XX_REG_H_
+#define _OMAP35XX_REG_H_
+
+#ifndef _LOCORE
+#include <sys/types.h>		/* for uint32_t */
+#endif
+
+
+
+
+#define OMAP35XX_SDRAM0_START		0x80000000UL
+#define OMAP35XX_SDRAM1_START		0xA0000000UL
+#define	OMAP35XX_SDRAM_BANKS		2
+#define	OMAP35XX_SDRAM_BANK_SIZE	0x20000000UL
+
+
+/* Physical/Virtual address for SDRAM controller */
+
+#define OMAP35XX_SMS_VBASE			0x6C000000UL
+#define OMAP35XX_SMS_HWBASE			0x6C000000UL
+#define	OMAP35XX_SMS_SIZE			0x01000000UL
+
+#define OMAP35XX_SDRC_VBASE			0x6D000000UL
+#define OMAP35XX_SDRC_HWBASE		0x6D000000UL
+#define	OMAP35XX_SDRC_SIZE			0x01000000UL
+
+
+
+/* Physical/Virtual address for I/O space */
+
+#define	OMAP35XX_L3_VBASE			0xD0000000UL
+#define	OMAP35XX_L3_HWBASE			0x68000000UL
+#define	OMAP35XX_L3_SIZE			0x01000000UL
+
+#define	OMAP35XX_L4_CORE_VBASE		0xE8000000UL
+#define	OMAP35XX_L4_CORE_HWBASE		0x48000000UL
+#define	OMAP35XX_L4_CORE_SIZE		0x01000000UL
+
+#define	OMAP35XX_L4_WAKEUP_VBASE	0xE8300000UL
+#define	OMAP35XX_L4_WAKEUP_HWBASE	0x48300000UL
+#define	OMAP35XX_L4_WAKEUP_SIZE		0x00040000UL
+
+#define	OMAP35XX_L4_PERIPH_VBASE	0xE9000000UL
+#define	OMAP35XX_L4_PERIPH_HWBASE	0x49000000UL
+#define	OMAP35XX_L4_PERIPH_SIZE		0x00100000UL
+
+
+/*
+ * L4-CORE Physical/Virtual addresss offsets
+ */
+#define	OMAP35XX_SCM_OFFSET			0x00002000UL
+#define	OMAP35XX_CM_OFFSET			0x00004000UL
+#define OMAP35XX_SDMA_OFFSET		0x00056000UL
+#define	OMAP35XX_I2C3_OFFSET		0x00060000UL
+#define	OMAP35XX_USB_TLL_OFFSET     0x00062000UL
+#define	OMAP35XX_USB_UHH_OFFSET     0x00064000UL
+#define	OMAP35XX_USB_EHCI_OFFSET    0x00064800UL
+
+
+#define	OMAP35XX_UART1_OFFSET		0x0006A000UL
+#define	OMAP35XX_UART2_OFFSET		0x0006C000UL
+#define	OMAP35XX_I2C1_OFFSET		0x00070000UL
+#define	OMAP35XX_I2C2_OFFSET		0x00072000UL
+#define	OMAP35XX_MCBSP1_OFFSET		0x00074000UL
+#define	OMAP35XX_GPTIMER10_OFFSET	0x00086000UL
+#define	OMAP35XX_GPTIMER11_OFFSET	0x00088000UL
+#define	OMAP35XX_MCBSP5_OFFSET		0x00096000UL
+#define	OMAP35XX_MMU1_OFFSET		0x000BD400UL
+#define	OMAP35XX_INTCPS_OFFSET		0x00200000UL
+
+
+/*
+ * L4-WAKEUP Physical/Virtual addresss offsets
+ */
+#define OMAP35XX_PRM_OFFSET			0x00006000UL
+#define	OMAP35XX_GPIO1_OFFSET		0x00010000UL
+#define	OMAP35XX_GPTIMER1_OFFSET	0x00018000UL
+
+
+
+/*
+ * L4-PERIPH Physical/Virtual addresss offsets
+ */
+#define	OMAP35XX_UART3_OFFSET		0x00020000UL
+#define	OMAP35XX_MCBSP2_OFFSET		0x00022000UL
+#define	OMAP35XX_MCBSP3_OFFSET		0x00024000UL
+#define	OMAP35XX_MCBSP4_OFFSET		0x00026000UL
+#define	OMAP35XX_SIDETONE_MCBSP2_OFFSET		0x00028000UL
+#define	OMAP35XX_SIDETONE_MCBSP3_OFFSET		0x0002A000UL
+#define	OMAP35XX_GPTIMER2_OFFSET	0x00032000UL
+#define	OMAP35XX_GPTIMER3_OFFSET	0x00034000UL
+#define	OMAP35XX_GPTIMER4_OFFSET	0x00036000UL
+#define	OMAP35XX_GPTIMER5_OFFSET	0x00038000UL
+#define	OMAP35XX_GPTIMER6_OFFSET	0x0003A000UL
+#define	OMAP35XX_GPTIMER7_OFFSET	0x0003C000UL
+#define	OMAP35XX_GPTIMER8_OFFSET	0x0003E000UL
+#define	OMAP35XX_GPTIMER9_OFFSET	0x00040000UL
+#define	OMAP35XX_GPIO2_OFFSET		0x00050000UL
+#define	OMAP35XX_GPIO3_OFFSET		0x00052000UL
+#define	OMAP35XX_GPIO4_OFFSET		0x00054000UL
+#define	OMAP35XX_GPIO5_OFFSET		0x00056000UL
+#define	OMAP35XX_GPIO6_OFFSET		0x00058000UL
+
+
+
+
+
+
+/*
+ * System Control Module
+ */
+#define	OMAP35XX_SCM_HWBASE				(OMAP35XX_L4_CORE_HWBASE + OMAP35XX_SCM_OFFSET)
+#define OMAP35XX_SCM_VBASE				(OMAP35XX_L4_CORE_VBASE + OMAP35XX_SCM_OFFSET)
+#define OMAP35XX_SCM_SIZE				0x00001000UL
+
+#define OMAP35XX_SCM_REVISION			0x00000000UL
+#define OMAP35XX_SCM_SYSCONFIG			0x00000010UL
+#define OMAP35XX_SCM_PADCONFS_BASE		0x00000030UL
+#define OMAP35XX_SCM_DEVCONF0			0x00000274UL
+#define OMAP35XX_SCM_MEM_DFTRW0			0x00000278UL
+
+
+
+
+/*
+ *
+ */
+#define	OMAP35XX_CM_HWBASE				(OMAP35XX_L4_CORE_HWBASE + OMAP35XX_CM_OFFSET)
+#define OMAP35XX_CM_VBASE				(OMAP35XX_L4_CORE_VBASE + OMAP35XX_CM_OFFSET)
+#define OMAP35XX_CM_SIZE				0x00001500UL
+
+#define OMAP35XX_CM_CORE_OFFSET			0x00000A00UL
+#define OMAP35XX_CM_CORE_SIZE			0x00000100UL
+#define OMAP35XX_CM_FCLKEN1_CORE		(OMAP35XX_CM_CORE_OFFSET + 0x0000UL)
+#define OMAP35XX_CM_FCLKEN3_CORE		(OMAP35XX_CM_CORE_OFFSET + 0x0008UL)
+#define OMAP35XX_CM_ICLKEN1_CORE		(OMAP35XX_CM_CORE_OFFSET + 0x0010UL)
+#define OMAP35XX_CM_ICLKEN2_CORE		(OMAP35XX_CM_CORE_OFFSET + 0x0014UL)
+#define OMAP35XX_CM_ICLKEN3_CORE		(OMAP35XX_CM_CORE_OFFSET + 0x0018UL)
+#define OMAP35XX_CM_IDLEST1_CORE		(OMAP35XX_CM_CORE_OFFSET + 0x0020UL)
+#define OMAP35XX_CM_IDLEST2_CORE		(OMAP35XX_CM_CORE_OFFSET + 0x0024UL)
+#define OMAP35XX_CM_IDLEST3_CORE		(OMAP35XX_CM_CORE_OFFSET + 0x0028UL)
+#define OMAP35XX_CM_AUTOIDLE1_CORE		(OMAP35XX_CM_CORE_OFFSET + 0x0030UL)
+#define OMAP35XX_CM_AUTOIDLE2_CORE		(OMAP35XX_CM_CORE_OFFSET + 0x0034UL)
+#define OMAP35XX_CM_AUTOIDLE3_CORE		(OMAP35XX_CM_CORE_OFFSET + 0x0038UL)
+#define OMAP35XX_CM_CLKSEL_CORE			(OMAP35XX_CM_CORE_OFFSET + 0x0040UL)
+#define OMAP35XX_CM_CLKSTCTRL_CORE		(OMAP35XX_CM_CORE_OFFSET + 0x0048UL)
+#define OMAP35XX_CM_CLKSTST_CORE		(OMAP35XX_CM_CORE_OFFSET + 0x004CUL)
+
+#define OMAP35XX_CM_WKUP_OFFSET			0x00000C00UL
+#define OMAP35XX_CM_WKUP_SIZE			0x00000100UL
+#define OMAP35XX_CM_FCLKEN_WKUP			(OMAP35XX_CM_WKUP_OFFSET + 0x0000UL)
+#define OMAP35XX_CM_ICLKEN_WKUP			(OMAP35XX_CM_WKUP_OFFSET + 0x0010UL)
+#define OMAP35XX_CM_IDLEST_WKUP			(OMAP35XX_CM_WKUP_OFFSET + 0x0020UL)
+#define OMAP35XX_CM_AUTOIDLE_WKUP		(OMAP35XX_CM_WKUP_OFFSET + 0x0030UL)
+#define OMAP35XX_CM_CLKSEL_WKUP			(OMAP35XX_CM_WKUP_OFFSET + 0x0040UL)
+
+#define OMAP35XX_CM_PLL_OFFSET			0x00000D00UL
+#define OMAP35XX_CM_PLL_SIZE			0x00000100UL
+#define OMAP35XX_CM_CLKEN_PLL			(OMAP35XX_CM_PLL_OFFSET + 0x0000UL)
+#define OMAP35XX_CM_CLKEN2_PLL			(OMAP35XX_CM_PLL_OFFSET + 0x0004UL)
+#define OMAP35XX_CM_IDLEST_CKGEN		(OMAP35XX_CM_PLL_OFFSET + 0x0020UL)
+#define OMAP35XX_CM_IDLEST2_CKGEN		(OMAP35XX_CM_PLL_OFFSET + 0x0024UL)
+#define OMAP35XX_CM_AUTOIDLE_PLL		(OMAP35XX_CM_PLL_OFFSET + 0x0030UL)
+#define OMAP35XX_CM_AUTOIDLE2_PLL		(OMAP35XX_CM_PLL_OFFSET + 0x0034UL)
+#define OMAP35XX_CM_CLKSEL1_PLL			(OMAP35XX_CM_PLL_OFFSET + 0x0040UL)
+#define OMAP35XX_CM_CLKSEL2_PLL			(OMAP35XX_CM_PLL_OFFSET + 0x0044UL)
+#define OMAP35XX_CM_CLKSEL3_PLL			(OMAP35XX_CM_PLL_OFFSET + 0x0048UL)
+#define OMAP35XX_CM_CLKSEL4_PLL			(OMAP35XX_CM_PLL_OFFSET + 0x004CUL)
+#define OMAP35XX_CM_CLKSEL5_PLL			(OMAP35XX_CM_PLL_OFFSET + 0x0050UL)
+#define OMAP35XX_CM_CLKOUT_CTRL			(OMAP35XX_CM_PLL_OFFSET + 0x0070UL)
+
+#define OMAP35XX_CM_PER_OFFSET			0x00001000UL
+#define OMAP35XX_CM_PER_SIZE			0x00000100UL
+#define OMAP35XX_CM_FCLKEN_PER			(OMAP35XX_CM_PER_OFFSET + 0x0000UL)
+#define OMAP35XX_CM_ICLKEN_PER			(OMAP35XX_CM_PER_OFFSET + 0x0010UL)
+#define OMAP35XX_CM_IDLEST_PER			(OMAP35XX_CM_PER_OFFSET + 0x0020UL)
+#define OMAP35XX_CM_AUTOIDLE_PER 		(OMAP35XX_CM_PER_OFFSET + 0x0030UL)
+#define OMAP35XX_CM_CLKSEL_PER			(OMAP35XX_CM_PER_OFFSET + 0x0040UL)
+#define OMAP35XX_CM_SLEEPDEP_PER		(OMAP35XX_CM_PER_OFFSET + 0x0044UL)
+#define OMAP35XX_CM_CLKSTCTRL_PER		(OMAP35XX_CM_PER_OFFSET + 0x0048UL)
+#define OMAP35XX_CM_CLKSTST_PER			(OMAP35XX_CM_PER_OFFSET + 0x004CUL)
+
+#define OMAP35XX_CM_USBHOST_OFFSET		0x00001400UL
+#define OMAP35XX_CM_USBHOST_SIZE		0x00000100UL
+#define OMAP35XX_CM_FCLKEN_USBHOST		(OMAP35XX_CM_USBHOST_OFFSET + 0x0000UL)
+#define OMAP35XX_CM_ICLKEN_USBHOST		(OMAP35XX_CM_USBHOST_OFFSET + 0x0010UL)
+#define OMAP35XX_CM_IDLEST_USBHOST		(OMAP35XX_CM_USBHOST_OFFSET + 0x0020UL)
+#define OMAP35XX_CM_AUTOIDLE_USBHOST	(OMAP35XX_CM_USBHOST_OFFSET + 0x0030UL)
+#define OMAP35XX_CM_SLEEPDEP_USBHOST	(OMAP35XX_CM_USBHOST_OFFSET + 0x0044UL)
+#define OMAP35XX_CM_CLKSTCTRL_USBHOST	(OMAP35XX_CM_USBHOST_OFFSET + 0x0048UL)
+#define OMAP35XX_CM_CLKSTST_USBHOST		(OMAP35XX_CM_USBHOST_OFFSET + 0x004CUL)
+
+
+
+
+/*
+ *
+ */
+#define	OMAP35XX_PRM_HWBASE				(OMAP35XX_L4_WAKEUP_HWBASE + OMAP35XX_PRM_OFFSET)
+#define OMAP35XX_PRM_VBASE				(OMAP35XX_L4_WAKEUP_VBASE + OMAP35XX_PRM_OFFSET)
+#define OMAP35XX_PRM_SIZE				0x00001600UL
+
+#define OMAP35XX_PRM_CLKCTRL_OFFSET		0x00000D00UL
+#define OMAP35XX_PRM_CLKCTRL_SIZE		0x00000100UL
+#define OMAP35XX_PRM_CLKSEL				(OMAP35XX_PRM_CLKCTRL_OFFSET + 0x0040UL)
+#define OMAP35XX_PRM_CLKOUT_CTRL		(OMAP35XX_PRM_CLKCTRL_OFFSET + 0x0070UL)
+
+#define OMAP35XX_PRM_GLOBAL_OFFSET		0x00001200UL
+#define OMAP35XX_PRM_GLOBAL_SIZE		0x00000100UL
+#define OMAP35XX_PRM_CLKSRC_CTRL		(OMAP35XX_PRM_GLOBAL_OFFSET + 0x0070UL)
+
+
+
+
+
+/*
+ * Uarts
+ */
+#define	OMAP35XX_UART1_HWBASE			(OMAP35XX_L4_CORE_HWBASE + OMAP35XX_UART1_OFFSET)
+#define	OMAP35XX_UART1_VBASE			(OMAP35XX_L4_CORE_VBASE  + OMAP35XX_UART1_OFFSET)
+#define	OMAP35XX_UART1_SIZE				0x00001000UL
+
+#define	OMAP35XX_UART2_HWBASE			(OMAP35XX_L4_CORE_HWBASE + OMAP35XX_UART2_OFFSET)
+#define	OMAP35XX_UART2_VBASE			(OMAP35XX_L4_CORE_VBASE  + OMAP35XX_UART2_OFFSET)
+#define	OMAP35XX_UART2_SIZE				0x00001000UL
+
+#define OMAP35XX_UART3_HWBASE			(OMAP35XX_L4_PERIPH_HWBASE + OMAP35XX_UART3_OFFSET)
+#define OMAP35XX_UART3_VBASE			(OMAP35XX_L4_PERIPH_VBASE  + OMAP35XX_UART3_OFFSET)
+#define	OMAP35XX_UART3_SIZE				0x00001000UL
+
+
+
+
+/*
+ * I2C Modules
+ */
+#define	OMAP35XX_I2C1_HWBASE			(OMAP35XX_L4_CORE_HWBASE + OMAP35XX_I2C1_OFFSET)
+#define	OMAP35XX_I2C1_VBASE				(OMAP35XX_L4_CORE_VBASE  + OMAP35XX_I2C1_OFFSET)
+#define	OMAP35XX_I2C1_SIZE				0x00000080UL
+
+#define	OMAP35XX_I2C2_HWBASE			(OMAP35XX_L4_CORE_HWBASE + OMAP35XX_I2C2_OFFSET)
+#define	OMAP35XX_I2C2_VBASE				(OMAP35XX_L4_CORE_VBASE  + OMAP35XX_I2C2_OFFSET)
+#define	OMAP35XX_I2C2_SIZE				0x00000080UL
+
+#define	OMAP35XX_I2C3_HWBASE			(OMAP35XX_L4_CORE_HWBASE + OMAP35XX_I2C3_OFFSET)
+#define	OMAP35XX_I2C3_VBASE				(OMAP35XX_L4_CORE_VBASE  + OMAP35XX_I2C3_OFFSET)
+#define	OMAP35XX_I2C3_SIZE				0x00000080UL
+
+#define	OMAP35XX_I2C_IE					0x04
+#define	OMAP35XX_I2C_STAT				0x08
+#define	OMAP35XX_I2C_WE					0x0C
+#define	OMAP35XX_I2C_SYSS				0x10
+#define	OMAP35XX_I2C_BUF				0x14
+#define	OMAP35XX_I2C_CNT				0x18
+#define	OMAP35XX_I2C_DATA				0x1C
+#define	OMAP35XX_I2C_SYSC				0x20
+#define	OMAP35XX_I2C_CON				0x24
+#define	OMAP35XX_I2C_OA0				0x28
+#define	OMAP35XX_I2C_SA					0x2C
+#define	OMAP35XX_I2C_PSC				0x30
+#define	OMAP35XX_I2C_SCLL				0x34
+#define	OMAP35XX_I2C_SCLH				0x38
+#define	OMAP35XX_I2C_SYSTEST			0x3C
+#define	OMAP35XX_I2C_BUFSTAT			0x40
+#define	OMAP35XX_I2C_OA1				0x44
+#define	OMAP35XX_I2C_OA2				0x48
+#define	OMAP35XX_I2C_OA3				0x4C
+#define	OMAP35XX_I2C_ACTOA				0x50
+#define	OMAP35XX_I2C_SBLOCK				0x54
+
+
+
+/*
+ * McBSP Modules
+ */
+#define	OMAP35XX_MCBSP1_HWBASE			(OMAP35XX_L4_CORE_HWBASE + OMAP35XX_MCBSP1_OFFSET)
+#define	OMAP35XX_MCBSP1_VBASE			(OMAP35XX_L4_CORE_VBASE  + OMAP35XX_MCBSP1_OFFSET)
+#define	OMAP35XX_MCBSP1_SIZE			0x00001000UL
+
+#define	OMAP35XX_MCBSP2_HWBASE			(OMAP35XX_L4_PERIPH_HWBASE + OMAP35XX_MCBSP2_OFFSET)
+#define	OMAP35XX_MCBSP2_VBASE			(OMAP35XX_L4_PERIPH_VBASE  + OMAP35XX_MCBSP2_OFFSET)
+#define	OMAP35XX_MCBSP2_SIZE			0x00001000UL
+
+#define	OMAP35XX_MCBSP3_HWBASE			(OMAP35XX_L4_PERIPH_HWBASE + OMAP35XX_MCBSP3_OFFSET)
+#define	OMAP35XX_MCBSP3_VBASE			(OMAP35XX_L4_PERIPH_VBASE  + OMAP35XX_MCBSP3_OFFSET)
+#define	OMAP35XX_MCBSP3_SIZE			0x00001000UL
+
+#define	OMAP35XX_MCBSP4_HWBASE			(OMAP35XX_L4_PERIPH_HWBASE + OMAP35XX_MCBSP4_OFFSET)
+#define	OMAP35XX_MCBSP4_VBASE			(OMAP35XX_L4_PERIPH_VBASE  + OMAP35XX_MCBSP4_OFFSET)
+#define	OMAP35XX_MCBSP4_SIZE			0x00001000UL
+
+#define	OMAP35XX_MCBSP5_HWBASE			(OMAP35XX_L4_CORE_HWBASE + OMAP35XX_MCBSP5_OFFSET)
+#define	OMAP35XX_MCBSP5_VBASE			(OMAP35XX_L4_CORE_VBASE  + OMAP35XX_MCBSP5_OFFSET)
+#define	OMAP35XX_MCBSP5_SIZE			0x00001000UL
+
+#define	OMAP35XX_MCBSP_DRR				0x0000
+#define	OMAP35XX_MCBSP_DXR				0x0008
+#define	OMAP35XX_MCBSP_SPCR2			0x0010
+#define	OMAP35XX_MCBSP_SPCR1			0x0014
+#define	OMAP35XX_MCBSP_RCR2				0x0018
+#define	OMAP35XX_MCBSP_RCR1				0x001C
+#define	OMAP35XX_MCBSP_XCR2				0x0020
+#define	OMAP35XX_MCBSP_XCR1				0x0024
+#define	OMAP35XX_MCBSP_SRGR2			0x0028
+#define	OMAP35XX_MCBSP_SRGR1			0x002C
+#define	OMAP35XX_MCBSP_MCR2				0x0030
+#define	OMAP35XX_MCBSP_MCR1				0x0034
+#define	OMAP35XX_MCBSP_RCERA			0x0038
+#define	OMAP35XX_MCBSP_RCERB			0x003C
+#define	OMAP35XX_MCBSP_XCERA			0x0040
+#define	OMAP35XX_MCBSP_XCERB			0x0044
+#define	OMAP35XX_MCBSP_PCR				0x0048
+#define	OMAP35XX_MCBSP_RCERC			0x004C
+#define	OMAP35XX_MCBSP_RCERD			0x0050
+#define	OMAP35XX_MCBSP_XCERC			0x0054
+#define	OMAP35XX_MCBSP_XCERD			0x0058
+#define	OMAP35XX_MCBSP_RCERE			0x005C
+#define	OMAP35XX_MCBSP_RCERF			0x0060
+#define	OMAP35XX_MCBSP_XCERE			0x0064
+#define	OMAP35XX_MCBSP_XCERF			0x0068
+#define	OMAP35XX_MCBSP_RCERG			0x006C
+#define	OMAP35XX_MCBSP_RCERH			0x0070
+#define	OMAP35XX_MCBSP_XCERG			0x0074
+#define	OMAP35XX_MCBSP_XCERH			0x0078
+#define	OMAP35XX_MCBSP_RINTCLR			0x0080
+#define	OMAP35XX_MCBSP_XINTCLR			0x0084
+#define	OMAP35XX_MCBSP_ROVFLCLR			0x0088
+#define	OMAP35XX_MCBSP_SYSCONFIG		0x008C
+#define	OMAP35XX_MCBSP_THRSH2			0x0090
+#define	OMAP35XX_MCBSP_THRSH1			0x0094
+#define	OMAP35XX_MCBSP_IRQSTATUS		0x00A0
+#define	OMAP35XX_MCBSP_IRQENABLE		0x00A4
+#define	OMAP35XX_MCBSP_WAKEUPEN			0x00A8
+#define	OMAP35XX_MCBSP_XCCR				0x00AC
+#define	OMAP35XX_MCBSP_RCCR				0x00B0
+#define	OMAP35XX_MCBSP_XBUFFSTAT		0x00B4
+#define	OMAP35XX_MCBSP_RBUFFSTAT		0x00B8
+#define	OMAP35XX_MCBSP_SSELCR			0x00BC
+#define	OMAP35XX_MCBSP_STATUS			0x00C0
+
+
+
+/*
+ * USB TTL Module
+ */
+#define	OMAP35XX_USBTLL_HWBASE			(OMAP35XX_L4_CORE_HWBASE + OMAP35XX_USBTLL_OFFSET)
+#define	OMAP35XX_USBTLL_VBASE			(OMAP35XX_L4_CORE_VBASE  + OMAP35XX_USBTLL_OFFSET)
+#define	OMAP35XX_USBTLL_SIZE			0x00001000UL
+
+#define	OMAP35XX_USBTLL_REVISION						0x0000
+#define	OMAP35XX_USBTLL_SYSCONFIG						0x0010
+#define	OMAP35XX_USBTLL_SYSSTATUS						0x0014
+#define	OMAP35XX_USBTLL_IRQSTATUS						0x0018
+#define	OMAP35XX_USBTLL_IRQENABLE						0x001C
+#define	OMAP35XX_USBTLL_TLL_SHARED_CONF					0x0030
+#define	OMAP35XX_USBTLL_TLL_CHANNEL_CONF(i)				(0x0040 + (0x04 * (i)))
+#define	OMAP35XX_USBTLL_ULPI_VENDOR_ID_LO(i)			(0x0800 + (0x100 * (i)))
+#define	OMAP35XX_USBTLL_ULPI_VENDOR_ID_HI(i)			(0x0801 + (0x100 * (i)))
+#define	OMAP35XX_USBTLL_ULPI_PRODUCT_ID_LO(i)			(0x0802 + (0x100 * (i)))
+#define	OMAP35XX_USBTLL_ULPI_PRODUCT_ID_HI(i)			(0x0803 + (0x100 * (i)))
+#define	OMAP35XX_USBTLL_ULPI_FUNCTION_CTRL(i)			(0x0804 + (0x100 * (i)))
+#define	OMAP35XX_USBTLL_ULPI_FUNCTION_CTRL_SET(i)		(0x0805 + (0x100 * (i)))
+#define	OMAP35XX_USBTLL_ULPI_FUNCTION_CTRL_CLR(i)		(0x0806 + (0x100 * (i)))
+#define	OMAP35XX_USBTLL_ULPI_INTERFACE_CTRL(i)			(0x0807 + (0x100 * (i)))
+#define	OMAP35XX_USBTLL_ULPI_INTERFACE_CTRL_SET(i)		(0x0808 + (0x100 * (i)))
+#define	OMAP35XX_USBTLL_ULPI_INTERFACE_CTRL_CLR(i)		(0x0809 + (0x100 * (i)))
+#define	OMAP35XX_USBTLL_ULPI_OTG_CTRL(i)				(0x080A + (0x100 * (i)))
+#define	OMAP35XX_USBTLL_ULPI_OTG_CTRL_SET(i)			(0x080B + (0x100 * (i)))
+#define	OMAP35XX_USBTLL_ULPI_OTG_CTRL_CLR(i)			(0x080C + (0x100 * (i)))
+#define	OMAP35XX_USBTLL_ULPI_USB_INT_EN_RISE(i)			(0x080D + (0x100 * (i)))
+#define	OMAP35XX_USBTLL_ULPI_USB_INT_EN_RISE_SET(i)		(0x080E + (0x100 * (i)))
+#define	OMAP35XX_USBTLL_ULPI_USB_INT_EN_RISE_CLR(i)		(0x080F + (0x100 * (i)))
+#define	OMAP35XX_USBTLL_ULPI_USB_INT_EN_FALL(i)			(0x0810 + (0x100 * (i)))
+#define	OMAP35XX_USBTLL_ULPI_USB_INT_EN_FALL_SET(i)		(0x0811 + (0x100 * (i)))
+#define	OMAP35XX_USBTLL_ULPI_USB_INT_EN_FALL_CLR(i)		(0x0812 + (0x100 * (i)))
+#define	OMAP35XX_USBTLL_ULPI_USB_INT_STATUS(i)			(0x0813 + (0x100 * (i)))
+#define	OMAP35XX_USBTLL_ULPI_USB_INT_LATCH(i)			(0x0814 + (0x100 * (i)))
+#define	OMAP35XX_USBTLL_ULPI_DEBUG(i)					(0x0815 + (0x100 * (i)))
+#define	OMAP35XX_USBTLL_ULPI_SCRATCH_REGISTER(i)		(0x0816 + (0x100 * (i)))
+#define	OMAP35XX_USBTLL_ULPI_SCRATCH_REGISTER_SET(i)	(0x0817 + (0x100 * (i)))
+#define	OMAP35XX_USBTLL_ULPI_SCRATCH_REGISTER_CLR(i)	(0x0818 + (0x100 * (i)))
+#define	OMAP35XX_USBTLL_ULPI_EXTENDED_SET_ACCESS(i)		(0x082F + (0x100 * (i)))
+#define	OMAP35XX_USBTLL_ULPI_UTMI_VCONTROL_EN(i)		(0x0830 + (0x100 * (i)))
+#define	OMAP35XX_USBTLL_ULPI_UTMI_VCONTROL_EN_SET(i)	(0x0831 + (0x100 * (i)))
+#define	OMAP35XX_USBTLL_ULPI_UTMI_VCONTROL_EN_CLR(i)	(0x0832 + (0x100 * (i)))
+#define	OMAP35XX_USBTLL_ULPI_UTMI_VCONTROL_STATUS(i)	(0x0833 + (0x100 * (i)))
+#define	OMAP35XX_USBTLL_ULPI_UTMI_VCONTROL_LATCH(i)		(0x0834 + (0x100 * (i)))
+#define	OMAP35XX_USBTLL_ULPI_UTMI_VSTATUS(i)			(0x0835 + (0x100 * (i)))
+#define	OMAP35XX_USBTLL_ULPI_UTMI_VSTATUS_SET(i)		(0x0836 + (0x100 * (i)))
+#define	OMAP35XX_USBTLL_ULPI_UTMI_VSTATUS_CLR(i)		(0x0837 + (0x100 * (i)))
+#define	OMAP35XX_USBTLL_ULPI_USB_INT_LATCH_NOCLR(i)		(0x0838 + (0x100 * (i)))
+#define	OMAP35XX_USBTLL_ULPI_VENDOR_INT_EN(i)			(0x083B + (0x100 * (i)))
+#define	OMAP35XX_USBTLL_ULPI_VENDOR_INT_EN_SET(i)		(0x083C + (0x100 * (i)))
+#define	OMAP35XX_USBTLL_ULPI_VENDOR_INT_EN_CLR(i)		(0x083D + (0x100 * (i)))
+#define	OMAP35XX_USBTLL_ULPI_VENDOR_INT_STATUS(i)		(0x083E + (0x100 * (i)))
+#define	OMAP35XX_USBTLL_ULPI_VENDOR_INT_LATCH(i)		(0x083F + (0x100 * (i)))
+
+
+/*
+ * USB Host Module
+ */
+#define	OMAP35XX_USB_TLL_HWBASE         (OMAP35XX_L4_CORE_HWBASE + OMAP35XX_USB_TLL_OFFSET)
+#define	OMAP35XX_USB_TLL_VBASE          (OMAP35XX_L4_CORE_VBASE + OMAP35XX_USB_TLL_OFFSET)
+#define OMAP35XX_USB_TLL_SIZE           0x00001000UL
+
+#define	OMAP35XX_USB_EHCI_HWBASE        (OMAP35XX_L4_CORE_HWBASE + OMAP35XX_USB_EHCI_OFFSET)
+#define	OMAP35XX_USB_EHCI_VBASE         (OMAP35XX_L4_CORE_VBASE + OMAP35XX_USB_EHCI_OFFSET)
+#define OMAP35XX_USB_EHCI_SIZE          0x00000400UL
+
+#define	OMAP35XX_USB_UHH_HWBASE         (OMAP35XX_L4_CORE_HWBASE + OMAP35XX_USB_UHH_OFFSET)
+#define	OMAP35XX_USB_UHH_VBASE          (OMAP35XX_L4_CORE_VBASE + OMAP35XX_USB_UHH_OFFSET)
+#define OMAP35XX_USB_UHH_SIZE           0x00000400UL
+
+
+
+
+
+/*
+ * SDRAM Controler (SDRC)
+ *  PA 0x6D00_0000
+ */
+
+#define OMAP35XX_SDRC_SYSCONFIG			(OMAP35XX_SDRC_VBASE + 0x10)
+#define OMAP35XX_SDRC_SYSSTATUS			(OMAP35XX_SDRC_VBASE + 0x14)
+#define OMAP35XX_SDRC_CS_CFG			(OMAP35XX_SDRC_VBASE + 0x40)
+#define OMAP35XX_SDRC_SHARING			(OMAP35XX_SDRC_VBASE + 0x44)
+#define OMAP35XX_SDRC_ERR_ADDR			(OMAP35XX_SDRC_VBASE + 0x48)
+#define OMAP35XX_SDRC_ERR_TYPE			(OMAP35XX_SDRC_VBASE + 0x4C)
+#define OMAP35XX_SDRC_DLLA_CTRL			(OMAP35XX_SDRC_VBASE + 0x60)
+#define OMAP35XX_SDRC_DLLA_STATUS		(OMAP35XX_SDRC_VBASE + 0x64)
+#define OMAP35XX_SDRC_POWER_REG			(OMAP35XX_SDRC_VBASE + 0x70)
+#define OMAP35XX_SDRC_MCFG(p)			(OMAP35XX_SDRC_VBASE + 0x80 + (0x30 * (p)))
+#define OMAP35XX_SDRC_MR(p)				(OMAP35XX_SDRC_VBASE + 0x84 + (0x30 * (p)))
+#define OMAP35XX_SDRC_EMR2(p)			(OMAP35XX_SDRC_VBASE + 0x8C + (0x30 * (p)))
+#define OMAP35XX_SDRC_ACTIM_CTRLA(p)	(OMAP35XX_SDRC_VBASE + 0x9C + (0x28 * (p)))
+#define OMAP35XX_SDRC_ACTIM_CTRLB(p)	(OMAP35XX_SDRC_VBASE + 0xA0 + (0x28 * (p)))
+#define OMAP35XX_SDRC_RFR_CTRL(p)		(OMAP35XX_SDRC_VBASE + 0xA4 + (0x30 * (p)))
+#define OMAP35XX_SDRC_MANUAL(p)			(OMAP35XX_SDRC_VBASE + 0xA8 + (0x30 * (p)))
+
+
+/*
+ * SDMA Offset
+ *  PA 0x4805 6000
+ */
+
+#define	OMAP35XX_SDMA_HWBASE			(OMAP35XX_L4_CORE_HWBASE + OMAP35XX_SDMA_OFFSET)
+#define	OMAP35XX_SDMA_VBASE				(OMAP35XX_L4_CORE_VBASE  + OMAP35XX_SDMA_OFFSET)
+#define	OMAP35XX_SDMA_SIZE				0x00001000UL
+
+
+
+/*
+ * Interrupt Controller Unit.
+ *  PA 0x4820_0000
+ */
+
+#define	OMAP35XX_INTCPS_HWBASE			(OMAP35XX_L4_CORE_HWBASE + OMAP35XX_INTCPS_OFFSET)
+#define	OMAP35XX_INTCPS_VBASE			(OMAP35XX_L4_CORE_VBASE  + OMAP35XX_INTCPS_OFFSET)
+#define	OMAP35XX_INTCPS_SIZE			0x00001000UL
+
+#define	OMAP35XX_INTCPS_SYSCONFIG		(OMAP35XX_INTCPS_VBASE + 0x10)
+#define	OMAP35XX_INTCPS_SYSSTATUS		(OMAP35XX_INTCPS_VBASE + 0x14)
+#define	OMAP35XX_INTCPS_SIR_IRQ			(OMAP35XX_INTCPS_VBASE + 0x40)
+#define	OMAP35XX_INTCPS_SIR_FIQ			(OMAP35XX_INTCPS_VBASE + 0x44)
+#define	OMAP35XX_INTCPS_CONTROL			(OMAP35XX_INTCPS_VBASE + 0x48)
+#define	OMAP35XX_INTCPS_PROTECTION		(OMAP35XX_INTCPS_VBASE + 0x4C)
+#define	OMAP35XX_INTCPS_IDLE			(OMAP35XX_INTCPS_VBASE + 0x50)
+#define	OMAP35XX_INTCPS_IRQ_PRIORITY	(OMAP35XX_INTCPS_VBASE + 0x60)
+#define	OMAP35XX_INTCPS_FIQ_PRIORITY	(OMAP35XX_INTCPS_VBASE + 0x64)
+#define	OMAP35XX_INTCPS_THRESHOLD		(OMAP35XX_INTCPS_VBASE + 0x68)
+#define OMAP35XX_INTCPS_ITR(n)			(OMAP35XX_INTCPS_VBASE + 0x80 + (0x20 * (n)))
+#define OMAP35XX_INTCPS_MIR(n)			(OMAP35XX_INTCPS_VBASE + 0x84 + (0x20 * (n)))
+#define OMAP35XX_INTCPS_MIR_CLEAR(n)	(OMAP35XX_INTCPS_VBASE + 0x88 + (0x20 * (n)))
+#define OMAP35XX_INTCPS_MIR_SET(n)		(OMAP35XX_INTCPS_VBASE + 0x8C + (0x20 * (n)))
+#define OMAP35XX_INTCPS_ISR_SET(n)		(OMAP35XX_INTCPS_VBASE + 0x90 + (0x20 * (n)))
+#define OMAP35XX_INTCPS_ISR_CLEAR(n)	(OMAP35XX_INTCPS_VBASE + 0x94 + (0x20 * (n)))
+#define OMAP35XX_INTCPS_PENDING_IRQ(n)	(OMAP35XX_INTCPS_VBASE + 0x98 + (0x20 * (n)))
+#define OMAP35XX_INTCPS_PENDING_FIQ(n)	(OMAP35XX_INTCPS_VBASE + 0x9C + (0x20 * (n)))
+#define OMAP35XX_INTCPS_ILR(m)			(OMAP35XX_INTCPS_VBASE + 0x100 + (0x4 * (m)))
+
+
+#define	OMAP35XX_IRQ_EMUINT			0	/* MPU emulation(2) */
+#define	OMAP35XX_IRQ_COMMTX			1	/* MPU emulation(2) */
+#define	OMAP35XX_IRQ_COMMRX			2	/* MPU emulation(2) */
+#define	OMAP35XX_IRQ_BENCH			3	/* MPU emulation(2) */
+#define	OMAP35XX_IRQ_MCBSP2_ST		4	/* Sidetone MCBSP2 overflow */
+#define	OMAP35XX_IRQ_MCBSP3_ST		5	/* Sidetone MCBSP3 overflow */
+#define	OMAP35XX_IRQ_SSM_ABORT		6	/* MPU subsystem secure state-machine abort (2) */
+#define	OMAP35XX_IRQ_SYS_NIRQ		7	/* External source (active low) */
+#define	OMAP35XX_IRQ_RESERVED8		8	/* RESERVED */
+#define	OMAP35XX_IRQ_SMX_DBG		9	/* SMX error for debug */
+#define	OMAP35XX_IRQ_SMX_APP		10	/* SMX error for application */
+#define	OMAP35XX_IRQ_PRCM_MPU		11	/* PRCM module IRQ */
+#define	OMAP35XX_IRQ_SDMA0			12	/* System DMA request 0(3) */
+#define	OMAP35XX_IRQ_SDMA1			13	/* System DMA request 1(3) */
+#define	OMAP35XX_IRQ_SDMA2			14	/* System DMA request 2 */
+#define	OMAP35XX_IRQ_SDMA3			15	/* System DMA request 3 */
+#define	OMAP35XX_IRQ_MCBSP1			16	/* McBSP module 1 IRQ (3) */
+#define	OMAP35XX_IRQ_MCBSP2			17	/* McBSP module 2 IRQ (3) */
+#define	OMAP35XX_IRQ_SR1			18	/* SmartReflexâ„¢ 1 */
+#define	OMAP35XX_IRQ_SR2			19	/* SmartReflexâ„¢ 2 */
+#define	OMAP35XX_IRQ_GPMC			20	/* General-purpose memory controller module */
+#define	OMAP35XX_IRQ_SGX			21	/* 2D/3D graphics module */
+#define	OMAP35XX_IRQ_MCBSP3			22	/* McBSP module 3(3) */
+#define	OMAP35XX_IRQ_MCBSP4			23	/* McBSP module 4(3) */
+#define	OMAP35XX_IRQ_CAM0			24	/* Camera interface request 0 */
+#define	OMAP35XX_IRQ_DSS			25	/* Display subsystem module(3) */
+#define	OMAP35XX_IRQ_MAIL_U0		26	/* Mailbox user 0 request */
+#define	OMAP35XX_IRQ_MCBSP5_IRQ1	27	/*  McBSP module 5 (3) */
+#define	OMAP35XX_IRQ_IVA2_MMU		28	/* IVA2 MMU */
+#define	OMAP35XX_IRQ_GPIO1_MPU		29	/* GPIO module 1(3) */
+#define	OMAP35XX_IRQ_GPIO2_MPU		30	/* GPIO module 2(3) */
+#define	OMAP35XX_IRQ_GPIO3_MPU		31	/* GPIO module 3(3) */
+#define	OMAP35XX_IRQ_GPIO4_MPU		32	/* GPIO module 4(3) */
+#define	OMAP35XX_IRQ_GPIO5_MPU		33	/* GPIO module 5(3) */
+#define	OMAP35XX_IRQ_GPIO6_MPU		34	/* GPIO module 6(3) */
+#define	OMAP35XX_IRQ_USIM			35	/* USIM interrupt (HS devices only) (4) */
+#define	OMAP35XX_IRQ_WDT3			36	/* Watchdog timer module 3 overflow */
+#define	OMAP35XX_IRQ_GPT1			37	/* General-purpose timer module 1 */
+#define	OMAP35XX_IRQ_GPT2			38	/* General-purpose timer module 2 */
+#define	OMAP35XX_IRQ_GPT3			39	/* General-purpose timer module 3 */
+#define	OMAP35XX_IRQ_GPT4			40	/* General-purpose timer module 4 */
+#define	OMAP35XX_IRQ_GPT5			41	/* General-purpose timer module 5(3) */
+#define	OMAP35XX_IRQ_GPT6			42	/* General-purpose timer module 6(3) */
+#define	OMAP35XX_IRQ_GPT7			43	/* General-purpose timer module 7(3) */
+#define	OMAP35XX_IRQ_GPT8			44	/* General-purpose timer module 8(3) */
+#define	OMAP35XX_IRQ_GPT9			45	/* General-purpose timer module 9 */
+#define	OMAP35XX_IRQ_GPT10			46	/* General-purpose timer module 10 */
+#define	OMAP35XX_IRQ_GPT11			47	/* General-purpose timer module 11 */
+#define	OMAP35XX_IRQ_SPI4			48	/* McSPI module 4 */
+#define	OMAP35XX_IRQ_SHA1MD5_2		49	/* SHA-1/MD5 crypto-accelerator 2 (HS devices only)(4) */
+#define	OMAP35XX_IRQ_FPKA_IRQREADY_N	50	/* PKA crypto-accelerator (HS devices only) (4) */
+#define	OMAP35XX_IRQ_SHA2MD5		51	/* SHA-2/MD5 crypto-accelerator 1 (HS devices only) (4) */
+#define	OMAP35XX_IRQ_RNG			52	/* RNG module (HS devices only) (4) */
+#define	OMAP35XX_IRQ_MG				53	/* MG function (3) */
+#define	OMAP35XX_IRQ_MCBSP4_TX		54	/* McBSP module 4 transmit(3) */
+#define	OMAP35XX_IRQ_MCBSP4_RX		55	/* McBSP module 4 receive(3) */
+#define	OMAP35XX_IRQ_I2C1			56	/* I2C module 1 */
+#define	OMAP35XX_IRQ_I2C2			57	/* I2C module 2 */
+#define	OMAP35XX_IRQ_HDQ			58	/* HDQ / One-wire */
+#define	OMAP35XX_IRQ_MCBSP1_TX		59	/* McBSP module 1 transmit(3) */
+#define	OMAP35XX_IRQ_MCBSP1_RX		60	/* McBSP module 1 receive(3) */
+#define	OMAP35XX_IRQ_I2C3			61	/* I2C module 3 */
+#define	OMAP35XX_IRQ_McBSP2_TX		62	/* McBSP module 2 transmit(3) */
+#define	OMAP35XX_IRQ_McBSP2_RX		63	/* McBSP module 2 receive(3) */
+#define	OMAP35XX_IRQ_FPKA_IRQRERROR_N	64	/* PKA crypto-accelerator (HS devices only) (4) */
+#define	OMAP35XX_IRQ_SPI1			65	/* McSPI module 1 */
+#define	OMAP35XX_IRQ_SPI2			66	/* McSPI module 2 */
+#define	OMAP35XX_IRQ_RESERVED67		67	/* RESERVED */
+#define	OMAP35XX_IRQ_RESERVED68		68	/* RESERVED */
+#define	OMAP35XX_IRQ_RESERVED69		69	/* RESERVED */
+#define	OMAP35XX_IRQ_RESERVED70		70	/* RESERVED */
+#define	OMAP35XX_IRQ_RESERVED71		71	/* RESERVED */
+#define	OMAP35XX_IRQ_UART1			72	/* UART module 1 */
+#define	OMAP35XX_IRQ_UART2			73	/* UART module 2 */
+#define	OMAP35XX_IRQ_UART3			74	/* UART module 3 (also infrared)(3) */
+#define	OMAP35XX_IRQ_PBIAS			75	/* Merged interrupt for PBIASlite1 and 2 */
+#define	OMAP35XX_IRQ_OHCI			76	/* OHCI controller HSUSB MP Host Interrupt */
+#define	OMAP35XX_IRQ_EHCI			77	/* EHCI controller HSUSB MP Host Interrupt */
+#define	OMAP35XX_IRQ_TLL			78	/* HSUSB MP TLL Interrupt */
+#define	OMAP35XX_IRQ_PARTHASH		79	/* SHA2/MD5 crypto-accelerator 1 (HS devices only) (4) */
+#define	OMAP35XX_IRQ_RESERVED80		80	/* Reserved */
+#define	OMAP35XX_IRQ_MCBSP5_TX		81	/* McBSP module 5 transmit(3) */
+#define	OMAP35XX_IRQ_MCBSP5_RX		82	/* McBSP module 5 receive(3) */
+#define	OMAP35XX_IRQ_MMC1			83	/* MMC/SD module 1 */
+#define	OMAP35XX_IRQ_MS				84	/* MS-PROâ„¢ module */
+#define	OMAP35XX_IRQ_RESERVED85		85	/* Reserved */
+#define	OMAP35XX_IRQ_MMC2			86	/* MMC/SD module 2 */
+#define	OMAP35XX_IRQ_MPU_ICR		87	/* MPU ICR */
+#define	OMAP35XX_IRQ_RESERVED		88	/* RESERVED */
+#define	OMAP35XX_IRQ_MCBSP3_TX		89	/* McBSP module 3 transmit(3) */
+#define	OMAP35XX_IRQ_MCBSP3_RX		90	/* McBSP module 3 receive(3) */
+#define	OMAP35XX_IRQ_SPI3			91	/* McSPI module 3 */
+#define	OMAP35XX_IRQ_HSUSB_MC_NINT	92	/* High-Speed USB OTG controller */
+#define	OMAP35XX_IRQ_HSUSB_DMA_NINT	93	/* High-Speed USB OTG DMA controller */
+#define	OMAP35XX_IRQ_MMC3			94	/* MMC/SD module 3 */
+#define	OMAP35XX_IRQ_GPT12			95	/* General-purpose timer module 12 */
+
+
+
+
+/*
+ * General Purpose Timers
+ */
+#define OMAP35XX_GPTIMER1_VBASE     (OMAP35XX_L4_WAKEUP_VBASE + OMAP35XX_GPTIMER1_OFFSET)
+#define OMAP35XX_GPTIMER1_HWBASE    (OMAP35XX_L4_WAKEUP_HWBASE + OMAP35XX_GPTIMER1_OFFSET)
+#define OMAP35XX_GPTIMER2_VBASE     (OMAP35XX_L4_PERIPH_VBASE + OMAP35XX_GPTIMER2_OFFSET)
+#define OMAP35XX_GPTIMER2_HWBASE    (OMAP35XX_L4_PERIPH_HWBASE + OMAP35XX_GPTIMER2_OFFSET)
+#define OMAP35XX_GPTIMER3_VBASE     (OMAP35XX_L4_PERIPH_VBASE + OMAP35XX_GPTIMER3_OFFSET)
+#define OMAP35XX_GPTIMER3_HWBASE    (OMAP35XX_L4_PERIPH_HWBASE + OMAP35XX_GPTIMER3_OFFSET)
+#define OMAP35XX_GPTIMER4_VBASE     (OMAP35XX_L4_PERIPH_VBASE + OMAP35XX_GPTIMER4_OFFSET)
+#define OMAP35XX_GPTIMER4_HWBASE    (OMAP35XX_L4_PERIPH_HWBASE + OMAP35XX_GPTIMER4_OFFSET)
+#define OMAP35XX_GPTIMER5_VBASE     (OMAP35XX_L4_PERIPH_VBASE + OMAP35XX_GPTIMER5_OFFSET)
+#define OMAP35XX_GPTIMER5_HWBASE    (OMAP35XX_L4_PERIPH_HWBASE + OMAP35XX_GPTIMER5_OFFSET)
+#define OMAP35XX_GPTIMER6_VBASE     (OMAP35XX_L4_PERIPH_VBASE + OMAP35XX_GPTIMER6_OFFSET)
+#define OMAP35XX_GPTIMER6_HWBASE    (OMAP35XX_L4_PERIPH_HWBASE + OMAP35XX_GPTIMER6_OFFSET)
+#define OMAP35XX_GPTIMER7_VBASE     (OMAP35XX_L4_PERIPH_VBASE + OMAP35XX_GPTIMER7_OFFSET)
+#define OMAP35XX_GPTIMER7_HWBASE    (OMAP35XX_L4_PERIPH_HWBASE + OMAP35XX_GPTIMER7_OFFSET)
+#define OMAP35XX_GPTIMER8_VBASE     (OMAP35XX_L4_PERIPH_VBASE + OMAP35XX_GPTIMER8_OFFSET)
+#define OMAP35XX_GPTIMER8_HWBASE    (OMAP35XX_L4_PERIPH_HWBASE + OMAP35XX_GPTIMER8_OFFSET)
+#define OMAP35XX_GPTIMER9_VBASE     (OMAP35XX_L4_PERIPH_VBASE + OMAP35XX_GPTIMER9_OFFSET)
+#define OMAP35XX_GPTIMER9_HWBASE    (OMAP35XX_L4_PERIPH_HWBASE + OMAP35XX_GPTIMER9_OFFSET)
+#define OMAP35XX_GPTIMER10_VBASE    (OMAP35XX_L4_CORE_VBASE + OMAP35XX_GPTIMER10_OFFSET)
+#define OMAP35XX_GPTIMER10_HWBASE   (OMAP35XX_L4_CORE_HWBASE + OMAP35XX_GPTIMER10_OFFSET)
+#define OMAP35XX_GPTIMER11_VBASE    (OMAP35XX_L4_CORE_VBASE + OMAP35XX_GPTIMER11_OFFSET)
+#define OMAP35XX_GPTIMER11_HWBASE   (OMAP35XX_L4_CORE_HWBASE + OMAP35XX_GPTIMER11_OFFSET)
+#define OMAP35XX_GPTIMER12_VBASE    0x48304000UL   /* GPTIMER12 */
+#define OMAP35XX_GPTIMER_SIZE       0x00001000UL
+
+
+
+/* Timer register offsets */
+#define OMAP35XX_GPTIMER_TIOCP_CFG	0x010
+#define OMAP35XX_GPTIMER_TISTAT		0x014
+#define OMAP35XX_GPTIMER_TISR		0x018
+#define OMAP35XX_GPTIMER_TIER		0x01C
+#define OMAP35XX_GPTIMER_TWER		0x020
+#define OMAP35XX_GPTIMER_TCLR		0x024
+#define OMAP35XX_GPTIMER_TCRR		0x028
+#define OMAP35XX_GPTIMER_TLDR		0x02C
+#define OMAP35XX_GPTIMER_TTGR		0x030
+#define OMAP35XX_GPTIMER_TWPS		0x034
+#define OMAP35XX_GPTIMER_TMAR		0x038
+#define OMAP35XX_GPTIMER_TCAR1		0x03C
+#define OMAP35XX_GPTIMER_TSICR		0x040
+#define OMAP35XX_GPTIMER_TCAR2		0x044
+#define OMAP35XX_GPTIMER_TPIR		0x048
+#define OMAP35XX_GPTIMER_TNIR		0x04C
+#define OMAP35XX_GPTIMER_TCVR		0x050
+#define OMAP35XX_GPTIMER_TOCR		0x054
+#define OMAP35XX_GPTIMER_TOWR		0x058
+
+/* Bit values */
+#define MAT_IT_FLAG		0x01
+#define OVF_IT_FLAG		0x02
+#define TCAR_IT_FLAG	0x04
+
+
+
+/*
+ * GPIO - General Purpose IO
+ */
+
+/* Base addresses for the GPIO modules */
+#define	OMAP35XX_GPIO1_HWBASE		(OMAP35XX_L4_WAKEUP_HWBASE + OMAP35XX_GPIO1_OFFSET)
+#define	OMAP35XX_GPIO1_VBASE		(OMAP35XX_L4_WAKEUP_VBASE  + OMAP35XX_GPIO1_OFFSET)
+#define	OMAP35XX_GPIO1_SIZE			0x00001000UL
+#define	OMAP35XX_GPIO2_HWBASE		(OMAP35XX_L4_PERIPH_HWBASE + OMAP35XX_GPIO2_OFFSET)
+#define	OMAP35XX_GPIO2_VBASE		(OMAP35XX_L4_PERIPH_VBASE  + OMAP35XX_GPIO2_OFFSET)
+#define	OMAP35XX_GPIO2_SIZE			0x00001000UL
+#define	OMAP35XX_GPIO3_HWBASE		(OMAP35XX_L4_PERIPH_HWBASE + OMAP35XX_GPIO3_OFFSET)
+#define	OMAP35XX_GPIO3_VBASE		(OMAP35XX_L4_PERIPH_VBASE  + OMAP35XX_GPIO3_OFFSET)
+#define	OMAP35XX_GPIO3_SIZE			0x00001000UL
+#define	OMAP35XX_GPIO4_HWBASE		(OMAP35XX_L4_PERIPH_HWBASE + OMAP35XX_GPIO4_OFFSET)
+#define	OMAP35XX_GPIO4_VBASE		(OMAP35XX_L4_PERIPH_VBASE  + OMAP35XX_GPIO4_OFFSET)
+#define	OMAP35XX_GPIO4_SIZE			0x00001000UL
+#define	OMAP35XX_GPIO5_HWBASE		(OMAP35XX_L4_PERIPH_HWBASE + OMAP35XX_GPIO5_OFFSET)
+#define	OMAP35XX_GPIO5_VBASE		(OMAP35XX_L4_PERIPH_VBASE  + OMAP35XX_GPIO5_OFFSET)
+#define	OMAP35XX_GPIO5_SIZE			0x00001000UL
+#define	OMAP35XX_GPIO6_HWBASE		(OMAP35XX_L4_PERIPH_HWBASE + OMAP35XX_GPIO6_OFFSET)
+#define	OMAP35XX_GPIO6_VBASE		(OMAP35XX_L4_PERIPH_VBASE  + OMAP35XX_GPIO6_OFFSET)
+#define	OMAP35XX_GPIO6_SIZE			0x00001000UL
+
+
+
+/* Register offsets within the banks above */
+#define OMAP35XX_GPIO_SYSCONFIG			0x010
+#define OMAP35XX_GPIO_SYSSTATUS			0x014
+#define OMAP35XX_GPIO_IRQSTATUS1		0x018
+#define OMAP35XX_GPIO_IRQENABLE1		0x01C
+#define OMAP35XX_GPIO_WAKEUPENABLE		0x020
+#define OMAP35XX_GPIO_IRQSTATUS2		0x028
+#define OMAP35XX_GPIO_IRQENABLE2		0x02C
+#define OMAP35XX_GPIO_CTRL				0x030
+#define OMAP35XX_GPIO_OE				0x034
+#define OMAP35XX_GPIO_DATAIN			0x038
+#define OMAP35XX_GPIO_DATAOUT			0x03C
+#define OMAP35XX_GPIO_LEVELDETECT0		0x040
+#define OMAP35XX_GPIO_LEVELDETECT1		0x044
+#define OMAP35XX_GPIO_RISINGDETECT		0x048
+#define OMAP35XX_GPIO_FALLINGDETECT		0x04C
+#define OMAP35XX_GPIO_DEBOUNCENABLE		0x050
+#define OMAP35XX_GPIO_DEBOUNCINGTIME	0x054
+#define OMAP35XX_GPIO_CLEARIRQENABLE1	0x060
+#define OMAP35XX_GPIO_SETIRQENABLE1		0x064
+#define OMAP35XX_GPIO_CLEARIRQENABLE2	0x070
+#define OMAP35XX_GPIO_SETIRQENABLE2		0x074
+#define OMAP35XX_GPIO_CLEARWKUENA		0x080
+#define OMAP35XX_GPIO_SETWKUENA			0x084
+#define OMAP35XX_GPIO_CLEARDATAOUT		0x090
+#define OMAP35XX_GPIO_SETDATAOUT		0x094
+
+
+/*
+ * MMC/SD/SDIO
+ */
+
+/* Base addresses for the MMC/SD/SDIO modules */
+#define	OMAP35XX_MMCHS1_HWBASE		(OMAP35XX_L4_CORE_HWBASE + 0x0009C000)
+#define	OMAP35XX_MMCHS1_VBASE		(OMAP35XX_L4_CORE_VBASE + 0x0009C000)
+#define	OMAP35XX_MMCHS2_HWBASE		(OMAP35XX_L4_CORE_HWBASE + 0x000B4000)
+#define	OMAP35XX_MMCHS2_VBASE		(OMAP35XX_L4_CORE_VBASE + 0x000B4000)
+#define	OMAP35XX_MMCHS3_HWBASE		(OMAP35XX_L4_CORE_HWBASE + 0x000AD000)
+#define	OMAP35XX_MMCHS3_VBASE		(OMAP35XX_L4_CORE_VBASE + 0x000AD000)
+#define	OMAP35XX_MMCHS_SIZE			0x00000200UL
+
+/* Register offsets within each of the MMC/SD/SDIO controllers */
+#define OMAP35XX_MMCHS_SYSCONFIG	0x010
+#define OMAP35XX_MMCHS_SYSSTATUS	0x014
+#define OMAP35XX_MMCHS_CSRE			0x024
+#define OMAP35XX_MMCHS_SYSTEST		0x028
+#define OMAP35XX_MMCHS_CON			0x02C
+#define OMAP35XX_MMCHS_PWCNT		0x030
+#define OMAP35XX_MMCHS_BLK			0x104
+#define OMAP35XX_MMCHS_ARG			0x108
+#define OMAP35XX_MMCHS_CMD			0x10C
+#define OMAP35XX_MMCHS_RSP10		0x110
+#define OMAP35XX_MMCHS_RSP32		0x114
+#define OMAP35XX_MMCHS_RSP54		0x118
+#define OMAP35XX_MMCHS_RSP76		0x11C
+#define OMAP35XX_MMCHS_DATA			0x120
+#define OMAP35XX_MMCHS_PSTATE		0x124
+#define OMAP35XX_MMCHS_HCTL			0x128
+#define OMAP35XX_MMCHS_SYSCTL		0x12C
+#define OMAP35XX_MMCHS_STAT			0x130
+#define OMAP35XX_MMCHS_IE			0x134
+#define OMAP35XX_MMCHS_ISE			0x138
+#define OMAP35XX_MMCHS_AC12			0x13C
+#define OMAP35XX_MMCHS_CAPA			0x140
+#define OMAP35XX_MMCHS_CUR_CAPA		0x148
+#define OMAP35XX_MMCHS_REV			0x1FC
+
+
+
+#endif /* _OMAP35XX_REG_H_ */
diff -r 7fffa673adcd -r a301a330526b head/sys/arm/ti/omap4/files.omap4
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/head/sys/arm/ti/omap4/files.omap4	Wed Aug 15 11:16:36 2012 +0300
@@ -0,0 +1,19 @@
+#$FreeBSD: head/sys/arm/ti/omap4/files.omap4 239281 2012-08-15 06:31:32Z gonzo $
+
+arm/arm/gic.c					standard
+arm/arm/mpcore_timer.c				standard
+arm/ti/ti_smc.S					standard
+
+arm/ti/usb/omap_ehci.c				optional	usb ehci
+arm/ti/ti_sdma.c				optional	ti_sdma
+arm/ti/ti_mmchs.c				optional	mmc
+
+arm/ti/omap4/omap4_l2cache.c			optional	pl310
+arm/ti/omap4/omap4_prcm_clks.c			standard
+arm/ti/omap4/omap4_scm_padconf.c		standard
+arm/ti/omap4/omap4_mp.c				optional	smp
+
+arm/ti/twl/twl.c				optional	twl
+arm/ti/twl/twl_vreg.c				optional	twl twl_vreg
+arm/ti/twl/twl_clks.c				optional	twl twl_clks
+
diff -r 7fffa673adcd -r a301a330526b head/sys/arm/ti/omap4/omap4_l2cache.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/head/sys/arm/ti/omap4/omap4_l2cache.c	Wed Aug 15 11:16:36 2012 +0300
@@ -0,0 +1,39 @@
+/*-
+ * Copyright (c) 2012 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 THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: head/sys/arm/ti/omap4/omap4_l2cache.c 239281 2012-08-15 06:31:32Z gonzo $");
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <arm/ti/ti_smc.h>
+#include <arm/ti/omap4/omap4_smc.h>
+#include <machine/pl310.h>
+
+void
+platform_init_pl310(struct pl310_softc *softc)
+{
+	ti_smc0(1, 0, L2CACHE_ENABLE_L2);
+}
+
diff -r 7fffa673adcd -r a301a330526b head/sys/arm/ti/omap4/omap4_mp.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/head/sys/arm/ti/omap4/omap4_mp.c	Wed Aug 15 11:16:36 2012 +0300
@@ -0,0 +1,87 @@
+/*-
+ * Copyright (c) 2012 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 THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: head/sys/arm/ti/omap4/omap4_mp.c 239281 2012-08-15 06:31:32Z gonzo $");
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/bus.h>
+#include <sys/lock.h>
+#include <sys/mutex.h>
+#include <sys/smp.h>
+
+#include <machine/smp.h>
+#include <machine/fdt.h>
+#include <machine/intr.h>
+
+#include <arm/ti/ti_smc.h>
+#include <arm/ti/omap4/omap4_smc.h>
+
+void mpentry(void);
+void mptramp(void);
+
+void
+platform_mp_init_secondary(void)
+{
+	gic_init_secondary();
+}
+
+void
+platform_mp_setmaxid(void)
+{
+
+        mp_maxid = 1;
+}
+
+int
+platform_mp_probe(void)
+{
+
+	mp_ncpus = 2;
+	return (1);
+}
+
+void    
+platform_mp_start_ap(void)
+{
+	bus_addr_t scu_addr;
+
+	if (bus_space_map(fdtbus_bs_tag, 0x48240000, 0x1000, 0, &scu_addr) != 0)
+		panic("Couldn't map the SCU\n");
+	/* Enable the SCU */
+	*(volatile unsigned int *)scu_addr |= 1;
+	//*(volatile unsigned int *)(scu_addr + 0x30) |= 1;
+	cpu_idcache_wbinv_all();
+	cpu_l2cache_wbinv_all();
+	ti_smc0(0x200, 0xfffffdff, MODIFY_AUX_CORE_0);
+	ti_smc0(pmap_kextract(mpentry), 0, WRITE_AUX_CORE_1);
+	armv7_sev();
+	bus_space_unmap(fdtbus_bs_tag, scu_addr, 0x1000);
+}
+
+void
+platform_ipi_send(cpuset_t cpus, u_int ipi)
+{
+	pic_ipi_send(cpus, ipi);
+}
diff -r 7fffa673adcd -r a301a330526b head/sys/arm/ti/omap4/omap4_prcm_clks.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/head/sys/arm/ti/omap4/omap4_prcm_clks.c	Wed Aug 15 11:16:36 2012 +0300
@@ -0,0 +1,1418 @@
+/*-
+ * Copyright (c) 2011
+ *	Ben Gray <ben.r.gray at 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.
+ * 3. 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 BEN GRAY ``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 BEN GRAY 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: head/sys/arm/ti/omap4/omap4_prcm_clks.c 239281 2012-08-15 06:31:32Z gonzo $");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/module.h>
+#include <sys/bus.h>
+#include <sys/resource.h>
+#include <sys/rman.h>
+#include <sys/lock.h>
+#include <sys/malloc.h>
+
+#include <machine/bus.h>
+#include <machine/cpu.h>
+#include <machine/cpufunc.h>
+#include <machine/frame.h>
+#include <machine/resource.h>
+#include <machine/intr.h>
+
+#include <arm/ti/tivar.h>
+#include <arm/ti/ti_prcm.h>
+#include <arm/ti/omap4/omap4_reg.h>
+
+#include <dev/fdt/fdt_common.h>
+#include <dev/ofw/openfirm.h>
+#include <dev/ofw/ofw_bus.h>
+#include <dev/ofw/ofw_bus_subr.h>
+
+/*
+ *	This file defines the clock configuration for the OMAP4xxx series of
+ *	devices.
+ *
+ *	How This is Suppose to Work
+ *	===========================
+ *	- There is a top level omap_prcm module that defines all OMAP SoC drivers
+ *	should use to enable/disable the system clocks regardless of the version
+ *	of OMAP device they are running on.  This top level PRCM module is just
+ *	a thin shim to chip specific functions that perform the donkey work of
+ *	configuring the clock - this file is the 'donkey' for OMAP44xx devices.
+ *
+ *	- The key bit in this file is the omap_clk_devmap array, it's
+ *	used by the omap_prcm driver to determine what clocks are valid and which
+ *	functions to call to manipulate them.
+ *
+ *	- In essence you just need to define some callbacks for each of the
+ *	clocks and then you're done.
+ *
+ *	- The other thing that is worth noting is that when the omap_prcm device
+ *	is registered you typically pass in some memory ranges which are the
+ *	SYS_MEMORY resources.  These resources are in turn allocated using 
+ *	bus_allocate_resources(...) and the resource handles are passed to all
+ *	individual clock callback handlers. 
+ *
+ *
+ *
+ *	OMAP4 devices are different from the previous OMAP3 devices in that there
+ *	is no longer a separate functional and interface clock for each module,
+ *	instead there is typically an interface clock that spans many modules.
+ *
+ */
+
+#define FREQ_96MHZ    96000000
+#define FREQ_64MHZ    64000000
+#define FREQ_48MHZ    48000000
+#define FREQ_32KHZ    32000
+
+/**
+ *	We need three memory regions to cover all the clock configuration registers.
+ *	
+ *	   PRM Instance -  0x4A30 6000 : 0x4A30 8000
+ *	   CM1 Instance -  0x4A00 4000 : 0x4A00 5000
+ *	   CM2 Instance -  0x4A00 8000 : 0x4A00 A000
+ *
+ */
+#define PRM_INSTANCE_MEM_REGION    0
+#define CM1_INSTANCE_MEM_REGION    1
+#define CM2_INSTANCE_MEM_REGION    2
+
+/**
+ *	Address offsets from the PRM memory region to the top level clock control
+ *	registers.
+ */
+#define CKGEN_PRM_OFFSET               0x00000100UL
+#define MPU_PRM_OFFSET                 0x00000300UL
+#define DSP_PRM_OFFSET                 0x00000400UL
+#define ABE_PRM_OFFSET                 0x00000500UL
+#define ALWAYS_ON_PRM_OFFSET           0x00000600UL
+#define CORE_PRM_OFFSET                0x00000700UL
+#define IVAHD_PRM_OFFSET               0x00000F00UL
+#define CAM_PRM_OFFSET                 0x00001000UL
+#define DSS_PRM_OFFSET                 0x00001100UL
+#define SGX_PRM_OFFSET                 0x00001200UL
+#define L3INIT_PRM_OFFSET              0x00001300UL
+#define L4PER_PRM_OFFSET               0x00001400UL
+#define WKUP_PRM_OFFSET                0x00001700UL
+#define WKUP_CM_OFFSET                 0x00001800UL
+#define EMU_PRM_OFFSET                 0x00001900UL
+#define EMU_CM_OFFSET                  0x00001A00UL
+#define DEVICE_PRM_OFFSET              0x00001B00UL
+#define INSTR_PRM_OFFSET               0x00001F00UL
+
+#define CM_ABE_DSS_SYS_CLKSEL_OFFSET   (CKGEN_PRM_OFFSET + 0x0000UL)
+#define CM_L4_WKUP_CLKSELL_OFFSET      (CKGEN_PRM_OFFSET + 0x0008UL)
+#define CM_ABE_PLL_REF_CLKSEL_OFFSET   (CKGEN_PRM_OFFSET + 0x000CUL)
+#define CM_SYS_CLKSEL_OFFSET           (CKGEN_PRM_OFFSET + 0x0010UL)
+
+/**
+ *	Address offsets from the CM1 memory region to the top level clock control
+ *	registers.
+ */
+#define CKGEN_CM1_OFFSET               0x00000100UL
+#define MPU_CM1_OFFSET                 0x00000300UL
+#define DSP_CM1_OFFSET                 0x00000400UL
+#define ABE_CM1_OFFSET                 0x00000500UL
+#define RESTORE_CM1_OFFSET             0x00000E00UL
+#define INSTR_CM1_OFFSET               0x00000F00UL
+
+#define CM_CLKSEL_DPLL_MPU             (CKGEN_CM1_OFFSET + 0x006CUL)
+
+/**
+ *	Address offsets from the CM2 memory region to the top level clock control
+ *	registers.
+ */
+#define INTRCONN_SOCKET_CM2_OFFSET     0x00000000UL
+#define CKGEN_CM2_OFFSET               0x00000100UL
+#define ALWAYS_ON_CM2_OFFSET           0x00000600UL
+#define CORE_CM2_OFFSET                0x00000700UL
+#define IVAHD_CM2_OFFSET               0x00000F00UL
+#define CAM_CM2_OFFSET                 0x00001000UL
+#define DSS_CM2_OFFSET                 0x00001100UL
+#define SGX_CM2_OFFSET                 0x00001200UL
+#define L3INIT_CM2_OFFSET              0x00001300UL
+#define L4PER_CM2_OFFSET               0x00001400UL
+#define RESTORE_CM2_OFFSET             0x00001E00UL
+#define INSTR_CM2_OFFSET               0x00001F00UL
+
+#define CLKCTRL_MODULEMODE_MASK       0x00000003UL
+#define CLKCTRL_MODULEMODE_DISABLE    0x00000000UL
+#define CLKCTRL_MODULEMODE_AUTO       0x00000001UL
+#define CLKCTRL_MODULEMODE_ENABLE     0x00000001UL
+
+#define CLKCTRL_IDLEST_MASK           0x00030000UL
+#define CLKCTRL_IDLEST_ENABLED        0x00000000UL
+#define CLKCTRL_IDLEST_WAKING         0x00010000UL
+#define CLKCTRL_IDLEST_IDLE           0x00020000UL
+#define CLKCTRL_IDLEST_DISABLED       0x00030000UL
+
+static struct resource_spec omap4_scm_res_spec[] = {
+	{ SYS_RES_MEMORY,	0,	RF_ACTIVE },	/* Control memory window */
+	{ SYS_RES_MEMORY,	1,	RF_ACTIVE },	/* Control memory window */
+	{ SYS_RES_MEMORY,	2,	RF_ACTIVE },	/* Control memory window */
+	{ -1, 0 }
+};
+
+struct omap4_prcm_softc {
+	struct resource	*sc_res[3];
+};
+
+static struct omap4_prcm_softc *omap4_prcm_sc;
+
+static int omap4_clk_generic_activate(struct ti_clock_dev *clkdev);
+static int omap4_clk_generic_deactivate(struct ti_clock_dev *clkdev);
+static int omap4_clk_generic_accessible(struct ti_clock_dev *clkdev);
+static int omap4_clk_generic_set_source(struct ti_clock_dev *clkdev, clk_src_t clksrc);
+static int omap4_clk_generic_get_source_freq(struct ti_clock_dev *clkdev, unsigned int *freq);
+
+static int omap4_clk_gptimer_set_source(struct ti_clock_dev *clkdev, clk_src_t clksrc);
+static int omap4_clk_gptimer_get_source_freq(struct ti_clock_dev *clkdev, unsigned int *freq);
+
+static int omap4_clk_hsmmc_set_source(struct ti_clock_dev *clkdev, clk_src_t clksrc);
+static int omap4_clk_hsmmc_get_source_freq(struct ti_clock_dev *clkdev, unsigned int *freq);
+
+static int omap4_clk_hsusbhost_set_source(struct ti_clock_dev *clkdev, clk_src_t clksrc);
+static int omap4_clk_hsusbhost_activate(struct ti_clock_dev *clkdev);
+static int omap4_clk_hsusbhost_deactivate(struct ti_clock_dev *clkdev);
+static int omap4_clk_hsusbhost_accessible(struct ti_clock_dev *clkdev);
+
+static int omap4_clk_get_sysclk_freq(struct ti_clock_dev *clkdev, unsigned int *freq);
+static int omap4_clk_get_arm_fclk_freq(struct ti_clock_dev *clkdev, unsigned int *freq);
+
+/**
+ *	omap_clk_devmap - Array of clock devices available on OMAP4xxx devices
+ *
+ *	This map only defines which clocks are valid and the callback functions
+ *	for clock activate, deactivate, etc.  It is used by the top level omap_prcm
+ *	driver.
+ *
+ *	The actual details of the clocks (config registers, bit fields, sources,
+ *	etc) are in the private g_omap3_clk_details array below.
+ *
+ */
+
+#define OMAP4_GENERIC_CLOCK_DEV(i) \
+	{	.id = (i), \
+		.clk_activate = omap4_clk_generic_activate, \
+		.clk_deactivate = omap4_clk_generic_deactivate, \
+		.clk_set_source = omap4_clk_generic_set_source, \
+		.clk_accessible = omap4_clk_generic_accessible, \
+		.clk_get_source_freq = omap4_clk_generic_get_source_freq \
+	}
+
+#define OMAP4_GPTIMER_CLOCK_DEV(i) \
+	{	.id = (i), \
+		.clk_activate = omap4_clk_generic_activate, \
+		.clk_deactivate = omap4_clk_generic_deactivate, \
+		.clk_set_source = omap4_clk_gptimer_set_source, \
+		.clk_accessible = omap4_clk_generic_accessible, \
+		.clk_get_source_freq = omap4_clk_gptimer_get_source_freq \
+	}
+
+#define OMAP4_HSMMC_CLOCK_DEV(i) \
+	{	.id = (i), \
+		.clk_activate = omap4_clk_generic_activate, \
+		.clk_deactivate = omap4_clk_generic_deactivate, \
+		.clk_set_source = omap4_clk_hsmmc_set_source, \
+		.clk_accessible = omap4_clk_generic_accessible, \
+		.clk_get_source_freq = omap4_clk_hsmmc_get_source_freq \
+	}
+
+#define OMAP4_HSUSBHOST_CLOCK_DEV(i) \
+	{	.id = (i), \
+		.clk_activate = omap4_clk_hsusbhost_activate, \
+		.clk_deactivate = omap4_clk_hsusbhost_deactivate, \
+		.clk_set_source = omap4_clk_hsusbhost_set_source, \
+		.clk_accessible = omap4_clk_hsusbhost_accessible, \
+		.clk_get_source_freq = NULL \
+	}
+
+
+struct ti_clock_dev ti_clk_devmap[] = {
+
+	/* System clocks */
+	{	.id                  = SYS_CLK,
+		.clk_activate        = NULL,
+		.clk_deactivate      = NULL,
+		.clk_set_source      = NULL,
+		.clk_accessible      = NULL,
+		.clk_get_source_freq = omap4_clk_get_sysclk_freq,
+	},
+	/* MPU (ARM) core clocks */
+	{	.id                  = MPU_CLK,
+		.clk_activate        = NULL,
+		.clk_deactivate      = NULL,
+		.clk_set_source      = NULL,
+		.clk_accessible      = NULL,
+		.clk_get_source_freq = omap4_clk_get_arm_fclk_freq,
+	},
+
+
+	/* UART device clocks */
+	OMAP4_GENERIC_CLOCK_DEV(UART1_CLK),
+	OMAP4_GENERIC_CLOCK_DEV(UART2_CLK),
+	OMAP4_GENERIC_CLOCK_DEV(UART3_CLK),
+	OMAP4_GENERIC_CLOCK_DEV(UART4_CLK),
+	
+	/* Timer device source clocks */
+	OMAP4_GPTIMER_CLOCK_DEV(GPTIMER1_CLK),
+	OMAP4_GPTIMER_CLOCK_DEV(GPTIMER2_CLK),
+	OMAP4_GPTIMER_CLOCK_DEV(GPTIMER3_CLK),
+	OMAP4_GPTIMER_CLOCK_DEV(GPTIMER4_CLK),
+	OMAP4_GPTIMER_CLOCK_DEV(GPTIMER5_CLK),
+	OMAP4_GPTIMER_CLOCK_DEV(GPTIMER6_CLK),
+	OMAP4_GPTIMER_CLOCK_DEV(GPTIMER7_CLK),
+	OMAP4_GPTIMER_CLOCK_DEV(GPTIMER8_CLK),
+	OMAP4_GPTIMER_CLOCK_DEV(GPTIMER9_CLK),
+	OMAP4_GPTIMER_CLOCK_DEV(GPTIMER10_CLK),
+	OMAP4_GPTIMER_CLOCK_DEV(GPTIMER11_CLK),
+	
+	/* MMC device clocks (MMC1 and MMC2 can have different input clocks) */
+	OMAP4_HSMMC_CLOCK_DEV(MMC1_CLK),
+	OMAP4_HSMMC_CLOCK_DEV(MMC2_CLK),
+	OMAP4_GENERIC_CLOCK_DEV(MMC3_CLK),
+	OMAP4_GENERIC_CLOCK_DEV(MMC4_CLK),
+	OMAP4_GENERIC_CLOCK_DEV(MMC5_CLK),
+
+	/* USB HS (high speed TLL, EHCI and OHCI) */
+	OMAP4_HSUSBHOST_CLOCK_DEV(USBTLL_CLK),
+	OMAP4_HSUSBHOST_CLOCK_DEV(USBHSHOST_CLK),
+	OMAP4_HSUSBHOST_CLOCK_DEV(USBFSHOST_CLK),
+	OMAP4_HSUSBHOST_CLOCK_DEV(USBP1_PHY_CLK),
+	OMAP4_HSUSBHOST_CLOCK_DEV(USBP2_PHY_CLK),
+	OMAP4_HSUSBHOST_CLOCK_DEV(USBP1_UTMI_CLK),
+	OMAP4_HSUSBHOST_CLOCK_DEV(USBP2_UTMI_CLK),
+	OMAP4_HSUSBHOST_CLOCK_DEV(USBP1_HSIC_CLK),
+	OMAP4_HSUSBHOST_CLOCK_DEV(USBP2_HSIC_CLK),
+	
+	/* GPIO */
+	OMAP4_GENERIC_CLOCK_DEV(GPIO1_CLK),
+	OMAP4_GENERIC_CLOCK_DEV(GPIO2_CLK),
+	OMAP4_GENERIC_CLOCK_DEV(GPIO3_CLK),
+	OMAP4_GENERIC_CLOCK_DEV(GPIO4_CLK),
+	OMAP4_GENERIC_CLOCK_DEV(GPIO5_CLK),
+	OMAP4_GENERIC_CLOCK_DEV(GPIO6_CLK),
+	
+	/* sDMA */
+	OMAP4_GENERIC_CLOCK_DEV(SDMA_CLK),	
+
+	/* I2C */
+	OMAP4_GENERIC_CLOCK_DEV(I2C1_CLK),
+	OMAP4_GENERIC_CLOCK_DEV(I2C2_CLK),
+	OMAP4_GENERIC_CLOCK_DEV(I2C3_CLK),
+	OMAP4_GENERIC_CLOCK_DEV(I2C4_CLK),
+
+	{  INVALID_CLK_IDENT, NULL, NULL, NULL, NULL }
+};
+
+/**
+ *	omap4_clk_details - Stores details for all the different clocks supported
+ *
+ *	Whenever an operation on a clock is being performed (activated, deactivated,
+ *	etc) this array is looked up to find the correct register and bit(s) we
+ *	should be modifying.
+ *
+ */
+struct omap4_clk_details {
+	clk_ident_t id;
+	
+	uint32_t    mem_region;
+	uint32_t    clksel_reg;
+	
+	int32_t     src_freq;
+	
+	uint32_t    enable_mode;
+};
+
+#define OMAP4_GENERIC_CLOCK_DETAILS(i, f, m, r, e) \
+	{	.id = (i), \
+		.mem_region = (m), \
+		.clksel_reg = (r), \
+		.src_freq = (f), \
+		.enable_mode = (e), \
+	}
+
+static struct omap4_clk_details g_omap4_clk_details[] = {
+
+	/* UART */
+	OMAP4_GENERIC_CLOCK_DETAILS(UART1_CLK, FREQ_48MHZ, CM2_INSTANCE_MEM_REGION,
+		(L4PER_CM2_OFFSET + 0x0140), CLKCTRL_MODULEMODE_ENABLE),
+	OMAP4_GENERIC_CLOCK_DETAILS(UART2_CLK, FREQ_48MHZ, CM2_INSTANCE_MEM_REGION,
+		(L4PER_CM2_OFFSET + 0x0148), CLKCTRL_MODULEMODE_ENABLE),
+	OMAP4_GENERIC_CLOCK_DETAILS(UART3_CLK, FREQ_48MHZ, CM2_INSTANCE_MEM_REGION,
+		(L4PER_CM2_OFFSET + 0x0140), CLKCTRL_MODULEMODE_ENABLE),
+	OMAP4_GENERIC_CLOCK_DETAILS(UART4_CLK, FREQ_48MHZ, CM2_INSTANCE_MEM_REGION,
+		(L4PER_CM2_OFFSET + 0x0148), CLKCTRL_MODULEMODE_ENABLE),
+
+	/* General purpose timers */
+	OMAP4_GENERIC_CLOCK_DETAILS(GPTIMER1_CLK,  -1, PRM_INSTANCE_MEM_REGION,
+		(WKUP_CM_OFFSET + 0x040), CLKCTRL_MODULEMODE_ENABLE),
+	OMAP4_GENERIC_CLOCK_DETAILS(GPTIMER2_CLK,  -1, CM2_INSTANCE_MEM_REGION,
+		(L4PER_CM2_OFFSET + 0x038), CLKCTRL_MODULEMODE_ENABLE),
+	OMAP4_GENERIC_CLOCK_DETAILS(GPTIMER3_CLK,  -1, CM2_INSTANCE_MEM_REGION,
+		(L4PER_CM2_OFFSET + 0x040), CLKCTRL_MODULEMODE_ENABLE),
+	OMAP4_GENERIC_CLOCK_DETAILS(GPTIMER4_CLK,  -1, CM2_INSTANCE_MEM_REGION,
+		(L4PER_CM2_OFFSET + 0x048), CLKCTRL_MODULEMODE_ENABLE),
+	OMAP4_GENERIC_CLOCK_DETAILS(GPTIMER5_CLK,  -1, CM1_INSTANCE_MEM_REGION,
+		(ABE_CM1_OFFSET + 0x068), CLKCTRL_MODULEMODE_ENABLE),
+	OMAP4_GENERIC_CLOCK_DETAILS(GPTIMER6_CLK,  -1, CM1_INSTANCE_MEM_REGION,
+		(ABE_CM1_OFFSET + 0x070), CLKCTRL_MODULEMODE_ENABLE),
+	OMAP4_GENERIC_CLOCK_DETAILS(GPTIMER7_CLK,  -1, CM1_INSTANCE_MEM_REGION,
+		(ABE_CM1_OFFSET + 0x078), CLKCTRL_MODULEMODE_ENABLE),
+	OMAP4_GENERIC_CLOCK_DETAILS(GPTIMER8_CLK,  -1, CM1_INSTANCE_MEM_REGION,
+		(ABE_CM1_OFFSET + 0x080), CLKCTRL_MODULEMODE_ENABLE),
+	OMAP4_GENERIC_CLOCK_DETAILS(GPTIMER9_CLK,  -1, CM2_INSTANCE_MEM_REGION,
+		(L4PER_CM2_OFFSET + 0x050), CLKCTRL_MODULEMODE_ENABLE),
+	OMAP4_GENERIC_CLOCK_DETAILS(GPTIMER10_CLK, -1, CM2_INSTANCE_MEM_REGION,
+		(L4PER_CM2_OFFSET + 0x028), CLKCTRL_MODULEMODE_ENABLE),
+	OMAP4_GENERIC_CLOCK_DETAILS(GPTIMER11_CLK, -1, CM2_INSTANCE_MEM_REGION,
+		(L4PER_CM2_OFFSET + 0x030), CLKCTRL_MODULEMODE_ENABLE),
+
+	/* HSMMC (MMC1 and MMC2 can have different input clocks) */
+	OMAP4_GENERIC_CLOCK_DETAILS(MMC1_CLK, -1, CM2_INSTANCE_MEM_REGION,
+		(L3INIT_CM2_OFFSET + 0x028), /*CLKCTRL_MODULEMODE_ENABLE*/2),
+	OMAP4_GENERIC_CLOCK_DETAILS(MMC2_CLK, -1, CM2_INSTANCE_MEM_REGION,
+		(L3INIT_CM2_OFFSET + 0x030), /*CLKCTRL_MODULEMODE_ENABLE*/2),
+	OMAP4_GENERIC_CLOCK_DETAILS(MMC3_CLK, FREQ_48MHZ, CM2_INSTANCE_MEM_REGION,
+		(L4PER_CM2_OFFSET + 0x120), /*CLKCTRL_MODULEMODE_ENABLE*/2),
+	OMAP4_GENERIC_CLOCK_DETAILS(MMC4_CLK, FREQ_48MHZ, CM2_INSTANCE_MEM_REGION,
+		(L4PER_CM2_OFFSET + 0x128), /*CLKCTRL_MODULEMODE_ENABLE*/2),
+	OMAP4_GENERIC_CLOCK_DETAILS(MMC5_CLK, FREQ_48MHZ, CM2_INSTANCE_MEM_REGION,
+	       (L4PER_CM2_OFFSET + 0x160), /*CLKCTRL_MODULEMODE_ENABLE*/1),
+	
+	/* GPIO modules */
+	OMAP4_GENERIC_CLOCK_DETAILS(GPIO1_CLK, -1, PRM_INSTANCE_MEM_REGION,
+		(WKUP_CM_OFFSET + 0x038), CLKCTRL_MODULEMODE_AUTO),
+	OMAP4_GENERIC_CLOCK_DETAILS(GPIO2_CLK, -1, CM2_INSTANCE_MEM_REGION,
+		(L4PER_CM2_OFFSET + 0x060), CLKCTRL_MODULEMODE_AUTO),
+	OMAP4_GENERIC_CLOCK_DETAILS(GPIO3_CLK, -1, CM2_INSTANCE_MEM_REGION,
+		(L4PER_CM2_OFFSET + 0x068), CLKCTRL_MODULEMODE_AUTO),
+	OMAP4_GENERIC_CLOCK_DETAILS(GPIO4_CLK, -1, CM2_INSTANCE_MEM_REGION,
+		(L4PER_CM2_OFFSET + 0x070), CLKCTRL_MODULEMODE_AUTO),
+	OMAP4_GENERIC_CLOCK_DETAILS(GPIO5_CLK, -1, CM2_INSTANCE_MEM_REGION,
+		(L4PER_CM2_OFFSET + 0x078), CLKCTRL_MODULEMODE_AUTO),
+	OMAP4_GENERIC_CLOCK_DETAILS(GPIO6_CLK, -1, CM2_INSTANCE_MEM_REGION,
+		(L4PER_CM2_OFFSET + 0x080), CLKCTRL_MODULEMODE_AUTO),
+		
+	/* sDMA block */
+	OMAP4_GENERIC_CLOCK_DETAILS(SDMA_CLK, -1, CM2_INSTANCE_MEM_REGION,
+		(CORE_CM2_OFFSET + 0x300), CLKCTRL_MODULEMODE_AUTO),
+
+	/* I2C modules */
+	OMAP4_GENERIC_CLOCK_DETAILS(I2C1_CLK, -1, CM2_INSTANCE_MEM_REGION,
+		(L4PER_CM2_OFFSET + 0x0A0), CLKCTRL_MODULEMODE_ENABLE),
+	OMAP4_GENERIC_CLOCK_DETAILS(I2C2_CLK, -1, CM2_INSTANCE_MEM_REGION,
+		(L4PER_CM2_OFFSET + 0x0A8), CLKCTRL_MODULEMODE_ENABLE),
+	OMAP4_GENERIC_CLOCK_DETAILS(I2C3_CLK, -1, CM2_INSTANCE_MEM_REGION,
+		(L4PER_CM2_OFFSET + 0x0B0), CLKCTRL_MODULEMODE_ENABLE),
+	OMAP4_GENERIC_CLOCK_DETAILS(I2C4_CLK, -1, CM2_INSTANCE_MEM_REGION,
+		(L4PER_CM2_OFFSET + 0x0B8), CLKCTRL_MODULEMODE_ENABLE),
+
+	{ INVALID_CLK_IDENT, 0, 0, 0, 0 },
+};
+
+/**
+ *	MAX_MODULE_ENABLE_WAIT - the number of loops to wait for the module to come
+ *	alive.
+ *
+ */
+#define MAX_MODULE_ENABLE_WAIT    100
+	
+/**
+ *	ARRAY_SIZE - Macro to return the number of elements in a static const array.
+ *
+ */
+#define ARRAY_SIZE(x) (sizeof(x)/sizeof(x[0]))
+
+/**
+ *	omap4_clk_details - writes a 32-bit value to one of the timer registers
+ *	@timer: Timer device context
+ *	@off: The offset of a register from the timer register address range
+ *	@val: The value to write into the register
+ *
+ *
+ *	RETURNS:
+ *	nothing
+ */
+static struct omap4_clk_details*
+omap4_clk_details(clk_ident_t id)
+{
+	struct omap4_clk_details *walker;
+
+	for (walker = g_omap4_clk_details; walker->id != INVALID_CLK_IDENT; walker++) {
+		if (id == walker->id)
+			return (walker);
+	}
+
+	return NULL;
+}
+	
+/**
+ *	omap4_clk_generic_activate - checks if a module is accessible
+ *	@module: identifier for the module to check, see omap3_prcm.h for a list
+ *	         of possible modules.
+ *	         Example: OMAP3_MODULE_MMC1
+ *	
+ *	
+ *
+ *	LOCKING:
+ *	Inherits the locks from the omap_prcm driver, no internal locking.
+ *
+ *	RETURNS:
+ *	Returns 0 on success or a positive error code on failure.
+ */
+static int
+omap4_clk_generic_activate(struct ti_clock_dev *clkdev)
+{
+	struct omap4_prcm_softc *sc = omap4_prcm_sc;
+	struct omap4_clk_details* clk_details;
+	struct resource* clk_mem_res;
+	uint32_t clksel;
+	unsigned int i;
+
+	if (sc == NULL)
+		return ENXIO;
+
+	clk_details = omap4_clk_details(clkdev->id);
+
+	if (clk_details == NULL)
+		return (ENXIO);
+
+	clk_mem_res = sc->sc_res[clk_details->mem_region];
+
+	if (clk_mem_res == NULL)
+		return (EINVAL);
+	
+	/* All the 'generic' clocks have a CLKCTRL register which is more or less
+	 * generic - the have at least two fielda called MODULEMODE and IDLEST.
+	 */
+	clksel = bus_read_4(clk_mem_res, clk_details->clksel_reg);
+	clksel &= ~CLKCTRL_MODULEMODE_MASK;
+	clksel |=  clk_details->enable_mode;
+	bus_write_4(clk_mem_res, clk_details->clksel_reg, clksel);
+
+	/* Now poll on the IDLEST register to tell us if the module has come up.
+	 * TODO: We need to take into account the parent clocks.
+	 */
+	
+	/* Try MAX_MODULE_ENABLE_WAIT number of times to check if enabled */
+	for (i = 0; i < MAX_MODULE_ENABLE_WAIT; i++) {
+		clksel = bus_read_4(clk_mem_res, clk_details->clksel_reg);
+		if ((clksel & CLKCTRL_IDLEST_MASK) == CLKCTRL_IDLEST_ENABLED)
+			break;
+		DELAY(10);
+	}
+		
+	/* Check the enabled state */
+	if ((clksel & CLKCTRL_IDLEST_MASK) != CLKCTRL_IDLEST_ENABLED) {
+		printf("Error: failed to enable module with clock %d\n", clkdev->id);
+		printf("Error: 0x%08x => 0x%08x\n", clk_details->clksel_reg, clksel);
+		return (ETIMEDOUT);
+	}
+	
+	return (0);
+}
+
+/**
+ *	omap4_clk_generic_deactivate - checks if a module is accessible
+ *	@module: identifier for the module to check, see omap3_prcm.h for a list
+ *	         of possible modules.
+ *	         Example: OMAP3_MODULE_MMC1
+ *	
+ *	
+ *
+ *	LOCKING:
+ *	Inherits the locks from the omap_prcm driver, no internal locking.
+ *
+ *	RETURNS:
+ *	Returns 0 on success or a positive error code on failure.
+ */
+static int
+omap4_clk_generic_deactivate(struct ti_clock_dev *clkdev)
+{
+	struct omap4_prcm_softc *sc = omap4_prcm_sc;
+	struct omap4_clk_details* clk_details;
+	struct resource* clk_mem_res;
+	uint32_t clksel;
+
+	if (sc == NULL)
+		return ENXIO;
+
+	clk_details = omap4_clk_details(clkdev->id);
+
+	if (clk_details == NULL)
+		return (ENXIO);
+
+	clk_mem_res = sc->sc_res[clk_details->mem_region];
+
+	if (clk_mem_res == NULL)
+		return (EINVAL);
+	
+	/* All the 'generic' clocks have a CLKCTRL register which is more or less
+	 * generic - the have at least two fielda called MODULEMODE and IDLEST.
+	 */
+	clksel = bus_read_4(clk_mem_res, clk_details->clksel_reg);
+	clksel &= ~CLKCTRL_MODULEMODE_MASK;
+	clksel |=  CLKCTRL_MODULEMODE_DISABLE;
+	bus_write_4(clk_mem_res, clk_details->clksel_reg, clksel);
+
+	return (0);
+}
+
+/**
+ *	omap4_clk_generic_set_source - checks if a module is accessible
+ *	@module: identifier for the module to check, see omap3_prcm.h for a list
+ *	         of possible modules.
+ *	         Example: OMAP3_MODULE_MMC1
+ *	
+ *	
+ *
+ *	LOCKING:
+ *	Inherits the locks from the omap_prcm driver, no internal locking.
+ *
+ *	RETURNS:
+ *	Returns 0 on success or a positive error code on failure.
+ */
+static int
+omap4_clk_generic_set_source(struct ti_clock_dev *clkdev,
+                             clk_src_t clksrc)
+{
+
+	return (0);
+}
+
+/**
+ *	omap4_clk_generic_accessible - checks if a module is accessible
+ *	@module: identifier for the module to check, see omap3_prcm.h for a list
+ *	         of possible modules.
+ *	         Example: OMAP3_MODULE_MMC1
+ *	
+ *	
+ *
+ *	LOCKING:
+ *	Inherits the locks from the omap_prcm driver, no internal locking.
+ *
+ *	RETURNS:
+ *	Returns 0 on success or a negative error code on failure.
+ */
+static int
+omap4_clk_generic_accessible(struct ti_clock_dev *clkdev)
+{
+	struct omap4_prcm_softc *sc = omap4_prcm_sc;
+	struct omap4_clk_details* clk_details;
+	struct resource* clk_mem_res;
+	uint32_t clksel;
+
+	if (sc == NULL)
+		return ENXIO;
+
+	clk_details = omap4_clk_details(clkdev->id);
+
+	if (clk_details == NULL)
+		return (ENXIO);
+
+	clk_mem_res = sc->sc_res[clk_details->mem_region];
+
+	if (clk_mem_res == NULL)
+		return (EINVAL);
+	
+	clksel = bus_read_4(clk_mem_res, clk_details->clksel_reg);
+		
+	/* Check the enabled state */
+	if ((clksel & CLKCTRL_IDLEST_MASK) != CLKCTRL_IDLEST_ENABLED)
+		return (0);
+	
+	return (1);
+}
+
+/**
+ *	omap4_clk_generic_get_source_freq - checks if a module is accessible
+ *	@module: identifier for the module to check, see omap3_prcm.h for a list
+ *	         of possible modules.
+ *	         Example: OMAP3_MODULE_MMC1
+ *	
+ *	
+ *
+ *	LOCKING:
+ *	Inherits the locks from the omap_prcm driver, no internal locking.
+ *
+ *	RETURNS:
+ *	Returns 0 on success or a negative error code on failure.
+ */
+static int
+omap4_clk_generic_get_source_freq(struct ti_clock_dev *clkdev,
+                                  unsigned int *freq
+                                  )
+{
+	struct omap4_clk_details* clk_details = omap4_clk_details(clkdev->id);
+
+	if (clk_details == NULL)
+		return (ENXIO);
+	
+	/* Simply return the stored frequency */
+	if (freq)
+		*freq = (unsigned int)clk_details->src_freq;
+	
+	return (0);
+}
+
+
+/**
+ *	omap4_clk_gptimer_set_source - checks if a module is accessible
+ *	@module: identifier for the module to check, see omap3_prcm.h for a list
+ *	         of possible modules.
+ *	         Example: OMAP3_MODULE_MMC1
+ *	
+ *	
+ *
+ *	LOCKING:
+ *	Inherits the locks from the omap_prcm driver, no internal locking.
+ *
+ *	RETURNS:
+ *	Returns 0 on success or a negative error code on failure.
+ */
+static int
+omap4_clk_gptimer_set_source(struct ti_clock_dev *clkdev,
+                             clk_src_t clksrc)
+{
+	struct omap4_prcm_softc *sc = omap4_prcm_sc;
+	struct omap4_clk_details* clk_details;
+	struct resource* clk_mem_res;
+
+	if (sc == NULL)
+		return ENXIO;
+
+	clk_details = omap4_clk_details(clkdev->id);
+
+	if (clk_details == NULL)
+		return (ENXIO);
+
+	clk_mem_res = sc->sc_res[clk_details->mem_region];
+
+	if (clk_mem_res == NULL)
+		return (EINVAL);
+	
+	/* TODO: Implement */
+	
+	return (0);
+}
+
+/**
+ *	omap4_clk_gptimer_get_source_freq - checks if a module is accessible
+ *	@module: identifier for the module to check, see omap3_prcm.h for a list
+ *	         of possible modules.
+ *	         Example: OMAP3_MODULE_MMC1
+ *	
+ *	
+ *
+ *	LOCKING:
+ *	Inherits the locks from the omap_prcm driver, no internal locking.
+ *
+ *	RETURNS:
+ *	Returns 0 on success or a negative error code on failure.
+ */
+static int
+omap4_clk_gptimer_get_source_freq(struct ti_clock_dev *clkdev,
+                                  unsigned int *freq
+                                  )
+{
+	struct omap4_prcm_softc *sc = omap4_prcm_sc;
+	struct omap4_clk_details* clk_details;
+	struct resource* clk_mem_res;
+	uint32_t clksel;
+	unsigned int src_freq;
+
+	if (sc == NULL)
+		return ENXIO;
+
+	clk_details = omap4_clk_details(clkdev->id);
+
+	if (clk_details == NULL)
+		return (ENXIO);
+
+	clk_mem_res = sc->sc_res[clk_details->mem_region];
+
+	if (clk_mem_res == NULL)
+		return (EINVAL);
+	
+	/* Need to read the CLKSEL field to determine the clock source */
+	clksel = bus_read_4(clk_mem_res, clk_details->clksel_reg);
+	if (clksel & (0x1UL << 24))
+		src_freq = FREQ_32KHZ;
+	else
+		omap4_clk_get_sysclk_freq(NULL, &src_freq);
+	
+	/* Return the frequency */
+	if (freq)
+		*freq = src_freq;
+	
+	return (0);
+}
+
+/**
+ *	omap4_clk_hsmmc_set_source - sets the source clock (freq)
+ *	@clkdev: pointer to the clockdev structure (id field will contain clock id)
+ *	
+ *	The MMC 1 and 2 clocks can be source from either a 64MHz or 96MHz clock.
+ *
+ *	LOCKING:
+ *	Inherits the locks from the omap_prcm driver, no internal locking.
+ *
+ *	RETURNS:
+ *	Returns 0 on success or a negative error code on failure.
+ */
+static int
+omap4_clk_hsmmc_set_source(struct ti_clock_dev *clkdev,
+                           clk_src_t clksrc)
+{
+	struct omap4_prcm_softc *sc = omap4_prcm_sc;
+	struct omap4_clk_details* clk_details;
+	struct resource* clk_mem_res;
+	uint32_t clksel;
+
+	if (sc == NULL)
+		return ENXIO;
+
+	clk_details = omap4_clk_details(clkdev->id);
+
+	if (clk_details == NULL)
+		return (ENXIO);
+
+	clk_mem_res = sc->sc_res[clk_details->mem_region];
+
+	if (clk_mem_res == NULL)
+		return (EINVAL);
+		
+	/* For MMC modules 3, 4 & 5 you can't change the freq, it's always 48MHz */
+	if ((clkdev->id == MMC3_CLK) || (clkdev->id == MMC4_CLK) ||
+	    (clkdev->id == MMC5_CLK)) {
+		if (clksrc != F48MHZ_CLK)
+			return (EINVAL);
+		return 0;
+	}
+
+	
+	clksel = bus_read_4(clk_mem_res, clk_details->clksel_reg);
+
+	/* Bit 24 is set if 96MHz clock or cleared for 64MHz clock */
+	if (clksrc == F64MHZ_CLK)
+		clksel &= ~(0x1UL << 24);
+	else if (clksrc == F96MHZ_CLK)
+		clksel |= (0x1UL << 24);
+	else
+		return (EINVAL);
+		
+	bus_write_4(clk_mem_res, clk_details->clksel_reg, clksel);
+	
+	return (0);
+}
+
+/**
+ *	omap4_clk_hsmmc_get_source_freq - checks if a module is accessible
+ *	@clkdev: pointer to the clockdev structure (id field will contain clock id)
+ *	
+ *	
+ *
+ *	LOCKING:
+ *	Inherits the locks from the omap_prcm driver, no internal locking.
+ *
+ *	RETURNS:
+ *	Returns 0 on success or a negative error code on failure.
+ */
+static int
+omap4_clk_hsmmc_get_source_freq(struct ti_clock_dev *clkdev,
+                                unsigned int *freq
+                                )
+{
+	struct omap4_prcm_softc *sc = omap4_prcm_sc;
+	struct omap4_clk_details* clk_details;
+	struct resource* clk_mem_res;
+	uint32_t clksel;
+	unsigned int src_freq;
+
+	if (sc == NULL)
+		return ENXIO;
+
+	clk_details = omap4_clk_details(clkdev->id);
+
+	if (clk_details == NULL)
+		return (ENXIO);
+
+	clk_mem_res = sc->sc_res[clk_details->mem_region];
+
+	if (clk_mem_res == NULL)
+		return (EINVAL);
+	
+	switch (clkdev->id) {
+	case MMC1_CLK:
+	case MMC2_CLK:
+		/* Need to read the CLKSEL field to determine the clock source */
+		clksel = bus_read_4(clk_mem_res, clk_details->clksel_reg);
+		if (clksel & (0x1UL << 24))
+			src_freq = FREQ_96MHZ;
+		else
+			src_freq = FREQ_64MHZ;
+		break;
+	case MMC3_CLK:
+	case MMC4_CLK:
+	case MMC5_CLK:
+		src_freq = FREQ_48MHZ;
+		break;
+	default:
+		return (EINVAL);
+	}
+		
+	/* Return the frequency */
+	if (freq)
+		*freq = src_freq;
+	
+	return (0);
+}
+
+/**
+ *	omap4_clk_get_sysclk_freq - gets the sysclk frequency
+ *	@sc: pointer to the clk module/device context
+ *
+ *	Read the clocking information from the power-control/boot-strap registers,
+ *  and stored in two global variables.
+ *
+ *	RETURNS:
+ *	nothing, values are saved in global variables
+ */
+static int
+omap4_clk_get_sysclk_freq(struct ti_clock_dev *clkdev,
+                          unsigned int *freq)
+{
+	uint32_t clksel;
+	uint32_t sysclk;
+	struct omap4_prcm_softc *sc = omap4_prcm_sc;
+	
+	if (sc == NULL)
+		return ENXIO;
+
+	/* Read the input clock freq from the configuration register (CM_SYS_CLKSEL) */
+	clksel = bus_read_4(sc->sc_res[PRM_INSTANCE_MEM_REGION], CM_SYS_CLKSEL_OFFSET);
+	switch (clksel & 0x7) {
+	case 0x1:
+		/* 12Mhz */
+		sysclk = 12000000;
+		break;
+	case 0x3:
+		/* 16.8Mhz */
+		sysclk = 16800000;
+		break;
+	case 0x4:
+		/* 19.2Mhz */
+		sysclk = 19200000;
+		break;
+	case 0x5:
+		/* 26Mhz */
+		sysclk = 26000000;
+		break;
+	case 0x7:
+		/* 38.4Mhz */
+		sysclk = 38400000;
+		break;
+	default:
+		panic("%s: Invalid clock freq", __func__);
+	}
+
+	/* Return the value */
+	if (freq)
+		*freq = sysclk;
+		
+	return (0);
+}
+
+/**
+ *	omap4_clk_get_arm_fclk_freq - gets the MPU clock frequency
+ *	@clkdev: ignored
+ *	@freq: pointer which upon return will contain the freq in hz
+ *	@mem_res: array of allocated memory resources
+ *
+ *	Reads the frequency setting information registers and returns the value
+ *	in the freq variable.
+ *
+ *	RETURNS:
+ *	returns 0 on success, a positive error code on failure.
+ */
+static int
+omap4_clk_get_arm_fclk_freq(struct ti_clock_dev *clkdev,
+                            unsigned int *freq)
+{
+	uint32_t clksel;
+	uint32_t pll_mult, pll_div;
+	uint32_t mpuclk, sysclk;
+	struct omap4_prcm_softc *sc = omap4_prcm_sc;
+
+	if (sc == NULL)
+		return ENXIO;
+
+	/* Read the clksel register which contains the DPLL multiple and divide
+	 * values.  These are applied to the sysclk.
+	 */
+	clksel = bus_read_4(sc->sc_res[CM1_INSTANCE_MEM_REGION], CM_CLKSEL_DPLL_MPU);
+
+	pll_mult = ((clksel >> 8) & 0x7ff);
+	pll_div = (clksel & 0x7f) + 1;
+	
+	
+	/* Get the system clock freq */
+	omap4_clk_get_sysclk_freq(NULL, &sysclk);
+
+
+	/* Calculate the MPU freq */
+	mpuclk = (sysclk * pll_mult) / pll_div;
+
+	/* Return the value */
+	if (freq)
+		*freq = mpuclk;
+		
+	return (0);
+}
+
+/**
+ *	omap4_clk_hsusbhost_activate - activates the USB clocks for the given module
+ *	@clkdev: pointer to the clock device structure.
+ *	@mem_res: array of memory resouces allocated by the top level PRCM driver.
+ *	
+ *	The USB clocking setup seems to be a bit more tricky than the other modules,
+ *	to start with the clocking diagram for the HS host module shows 13 different
+ *	clocks.  So to try and make it easier to follow the clocking activation
+ *	and deactivation is handled in it's own set of callbacks.
+ *
+ *	LOCKING:
+ *	Inherits the locks from the omap_prcm driver, no internal locking.
+ *
+ *	RETURNS:
+ *	Returns 0 on success or a positive error code on failure.
+ */
+
+struct dpll_param {
+	unsigned int m;
+	unsigned int n;
+	unsigned int m2;
+	unsigned int m3;
+	unsigned int m4;
+	unsigned int m5;
+	unsigned int m6;
+	unsigned int m7;
+};
+/* USB parameters */
+struct dpll_param usb_dpll_param[7] = {
+	/* 12M values */
+	{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0},
+	/* 13M values */
+	{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0},
+	/* 16.8M values */
+	{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0},
+	/* 19.2M values */
+	{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0},
+	/* 26M values */
+	{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0},
+	/* 27M values */
+	{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0},
+	/* 38.4M values */
+#ifdef CONFIG_OMAP4_SDC
+	{0x32, 0x1, 0x2, 0x0, 0x0, 0x0, 0x0, 0x0},
+#else
+	{0x32, 0x1, 0x2, 0x0, 0x0, 0x0, 0x0, 0x0},
+#endif
+};
+static int
+omap4_clk_hsusbhost_activate(struct ti_clock_dev *clkdev)
+{
+	struct omap4_prcm_softc *sc = omap4_prcm_sc;
+	struct resource* clk_mem_res;
+	uint32_t clksel_reg_off;
+	uint32_t clksel;
+	unsigned int i;
+
+	if (sc == NULL)
+		return ENXIO;
+
+	switch (clkdev->id) {
+	case USBTLL_CLK:
+		/* For the USBTLL module we need to enable the following clocks:
+		 *  - INIT_L4_ICLK  (will be enabled by bootloader)
+		 *  - TLL_CH0_FCLK
+		 *  - TLL_CH1_FCLK
+		 */
+
+		/* We need the CM_L3INIT_HSUSBTLL_CLKCTRL register in CM2 register set */
+		clk_mem_res = sc->sc_res[CM2_INSTANCE_MEM_REGION];
+		clksel_reg_off = L3INIT_CM2_OFFSET + 0x68;
+	
+		/* Enable the module and also enable the optional func clocks for
+		 * channels 0 & 1 (is this needed ?)
+		 */
+		clksel = bus_read_4(clk_mem_res, clksel_reg_off);
+		clksel &= ~CLKCTRL_MODULEMODE_MASK;
+		clksel |=  CLKCTRL_MODULEMODE_ENABLE;
+		
+		clksel |= (0x1 << 8); /* USB-HOST optional clock: USB_CH0_CLK */
+		clksel |= (0x1 << 9); /* USB-HOST optional clock: USB_CH1_CLK */
+		break;
+
+	case USBHSHOST_CLK:
+	case USBP1_PHY_CLK:
+	case USBP2_PHY_CLK:
+	case USBP1_UTMI_CLK:
+	case USBP2_UTMI_CLK:
+	case USBP1_HSIC_CLK:
+	case USBP2_HSIC_CLK:
+		/* For the USB HS HOST module we need to enable the following clocks:
+		 *  - INIT_L4_ICLK     (will be enabled by bootloader)
+		 *  - INIT_L3_ICLK     (will be enabled by bootloader)
+		 *  - INIT_48MC_FCLK
+		 *  - UTMI_ROOT_GFCLK  (UTMI only, create a new clock for that ?)
+		 *  - UTMI_P1_FCLK     (UTMI only, create a new clock for that ?)
+		 *  - UTMI_P2_FCLK     (UTMI only, create a new clock for that ?)
+		 *  - HSIC_P1_60       (HSIC only, create a new clock for that ?)
+		 *  - HSIC_P1_480      (HSIC only, create a new clock for that ?)
+		 *  - HSIC_P2_60       (HSIC only, create a new clock for that ?)
+		 *  - HSIC_P2_480      (HSIC only, create a new clock for that ?)
+		 */
+
+		/* We need the CM_L3INIT_HSUSBHOST_CLKCTRL register in CM2 register set */
+		clk_mem_res = sc->sc_res[CM2_INSTANCE_MEM_REGION];
+		clksel_reg_off = L3INIT_CM2_OFFSET + 0x58;
+		clksel = bus_read_4(clk_mem_res, clksel_reg_off);	
+		/* Enable the module and also enable the optional func clocks */
+		if (clkdev->id == USBHSHOST_CLK) {
+			clksel &= ~CLKCTRL_MODULEMODE_MASK;
+			clksel |=  /*CLKCTRL_MODULEMODE_ENABLE*/2;
+
+			clksel |= (0x1 << 15); /* USB-HOST clock control: FUNC48MCLK */
+		}
+		
+		else if (clkdev->id == USBP1_UTMI_CLK)
+			clksel |= (0x1 << 8);  /* UTMI_P1_CLK */
+		else if (clkdev->id == USBP2_UTMI_CLK)
+			clksel |= (0x1 << 9);  /* UTMI_P2_CLK */
+
+		else if (clkdev->id == USBP1_HSIC_CLK)
+			clksel |= (0x5 << 11);  /* HSIC60M_P1_CLK + HSIC480M_P1_CLK */
+		else if (clkdev->id == USBP2_HSIC_CLK)
+			clksel |= (0x5 << 12);  /* HSIC60M_P2_CLK + HSIC480M_P2_CLK */
+		
+		break;
+	
+	default:
+		return (EINVAL);
+	}
+	
+	bus_write_4(clk_mem_res, clksel_reg_off, clksel);
+	
+	/* Try MAX_MODULE_ENABLE_WAIT number of times to check if enabled */
+	for (i = 0; i < MAX_MODULE_ENABLE_WAIT; i++) {
+		clksel = bus_read_4(clk_mem_res, clksel_reg_off);
+		if ((clksel & CLKCTRL_IDLEST_MASK) == CLKCTRL_IDLEST_ENABLED)
+			break;
+	}
+		
+	/* Check the enabled state */
+	if ((clksel & CLKCTRL_IDLEST_MASK) != CLKCTRL_IDLEST_ENABLED) {
+		printf("Error: HERE failed to enable module with clock %d\n", clkdev->id);
+		printf("Error: 0x%08x => 0x%08x\n", clksel_reg_off, clksel);
+		return (ETIMEDOUT);
+	}
+	
+	return (0);
+}
+
+/**
+ *	omap4_clk_generic_deactivate - checks if a module is accessible
+ *	@clkdev: pointer to the clock device structure.
+ *	@mem_res: array of memory resouces allocated by the top level PRCM driver.
+ *	
+ *	
+ *
+ *	LOCKING:
+ *	Inherits the locks from the omap_prcm driver, no internal locking.
+ *
+ *	RETURNS:
+ *	Returns 0 on success or a positive error code on failure.
+ */
+static int
+omap4_clk_hsusbhost_deactivate(struct ti_clock_dev *clkdev)
+{
+	struct omap4_prcm_softc *sc = omap4_prcm_sc;
+	struct resource* clk_mem_res;
+	uint32_t clksel_reg_off;
+	uint32_t clksel;
+
+	if (sc == NULL)
+		return ENXIO;
+
+	switch (clkdev->id) {
+	case USBTLL_CLK:
+		/* We need the CM_L3INIT_HSUSBTLL_CLKCTRL register in CM2 register set */
+		clk_mem_res = sc->sc_res[CM2_INSTANCE_MEM_REGION];
+		clksel_reg_off = L3INIT_CM2_OFFSET + 0x68;
+	
+		clksel = bus_read_4(clk_mem_res, clksel_reg_off);
+		clksel &= ~CLKCTRL_MODULEMODE_MASK;
+		clksel |=  CLKCTRL_MODULEMODE_DISABLE;
+		break;
+
+	case USBHSHOST_CLK:
+	case USBP1_PHY_CLK:
+	case USBP2_PHY_CLK:
+	case USBP1_UTMI_CLK:
+	case USBP2_UTMI_CLK:
+	case USBP1_HSIC_CLK:
+	case USBP2_HSIC_CLK:
+		/* For the USB HS HOST module we need to enable the following clocks:
+		 *  - INIT_L4_ICLK     (will be enabled by bootloader)
+		 *  - INIT_L3_ICLK     (will be enabled by bootloader)
+		 *  - INIT_48MC_FCLK
+		 *  - UTMI_ROOT_GFCLK  (UTMI only, create a new clock for that ?)
+		 *  - UTMI_P1_FCLK     (UTMI only, create a new clock for that ?)
+		 *  - UTMI_P2_FCLK     (UTMI only, create a new clock for that ?)
+		 *  - HSIC_P1_60       (HSIC only, create a new clock for that ?)
+		 *  - HSIC_P1_480      (HSIC only, create a new clock for that ?)
+		 *  - HSIC_P2_60       (HSIC only, create a new clock for that ?)
+		 *  - HSIC_P2_480      (HSIC only, create a new clock for that ?)
+		 */
+
+		/* We need the CM_L3INIT_HSUSBHOST_CLKCTRL register in CM2 register set */
+		clk_mem_res = sc->sc_res[CM2_INSTANCE_MEM_REGION];
+		clksel_reg_off = L3INIT_CM2_OFFSET + 0x58;
+		clksel = bus_read_4(clk_mem_res, clksel_reg_off);
+
+		/* Enable the module and also enable the optional func clocks */
+		if (clkdev->id == USBHSHOST_CLK) {
+			clksel &= ~CLKCTRL_MODULEMODE_MASK;
+			clksel |=  CLKCTRL_MODULEMODE_DISABLE;
+
+			clksel &= ~(0x1 << 15); /* USB-HOST clock control: FUNC48MCLK */
+		}
+		
+		else if (clkdev->id == USBP1_UTMI_CLK)
+			clksel &= ~(0x1 << 8);  /* UTMI_P1_CLK */
+		else if (clkdev->id == USBP2_UTMI_CLK)
+			clksel &= ~(0x1 << 9);  /* UTMI_P2_CLK */
+
+		else if (clkdev->id == USBP1_HSIC_CLK)
+			clksel &= ~(0x5 << 11);  /* HSIC60M_P1_CLK + HSIC480M_P1_CLK */
+		else if (clkdev->id == USBP2_HSIC_CLK)
+			clksel &= ~(0x5 << 12);  /* HSIC60M_P2_CLK + HSIC480M_P2_CLK */
+		
+		break;
+	
+	default:
+		return (EINVAL);
+	}
+	
+	bus_write_4(clk_mem_res, clksel_reg_off, clksel);
+
+	return (0);
+}
+
+/**
+ *	omap4_clk_hsusbhost_accessible - checks if a module is accessible
+ *	@clkdev: pointer to the clock device structure.
+ *	@mem_res: array of memory resouces allocated by the top level PRCM driver.
+ *	
+ *	
+ *
+ *	LOCKING:
+ *	Inherits the locks from the omap_prcm driver, no internal locking.
+ *
+ *	RETURNS:
+ *	Returns 0 if module is not enable, 1 if module is enabled or a negative
+ *	error code on failure.
+ */
+static int
+omap4_clk_hsusbhost_accessible(struct ti_clock_dev *clkdev)
+{
+	struct omap4_prcm_softc *sc = omap4_prcm_sc;
+	struct resource* clk_mem_res;
+	uint32_t clksel_reg_off;
+	uint32_t clksel;
+
+	if (sc == NULL)
+		return ENXIO;
+
+	if (clkdev->id == USBTLL_CLK) {
+		/* We need the CM_L3INIT_HSUSBTLL_CLKCTRL register in CM2 register set */
+		clk_mem_res = sc->sc_res[CM2_INSTANCE_MEM_REGION];
+		clksel_reg_off = L3INIT_CM2_OFFSET + 0x68;
+	}
+	else if (clkdev->id == USBHSHOST_CLK) {
+		/* We need the CM_L3INIT_HSUSBHOST_CLKCTRL register in CM2 register set */
+		clk_mem_res = sc->sc_res[CM2_INSTANCE_MEM_REGION];
+		clksel_reg_off = L3INIT_CM2_OFFSET + 0x58;
+	}
+	else {
+		return (EINVAL);
+	}
+
+	clksel = bus_read_4(clk_mem_res, clksel_reg_off);
+		
+	/* Check the enabled state */
+	if ((clksel & CLKCTRL_IDLEST_MASK) != CLKCTRL_IDLEST_ENABLED)
+		return (0);
+	
+	return (1);
+}
+
+/**
+ *	omap4_clk_hsusbhost_set_source - sets the source clocks
+ *	@clkdev: pointer to the clock device structure.
+ *	@clksrc: the clock source ID for the given clock.
+ *	@mem_res: array of memory resouces allocated by the top level PRCM driver.
+ *	
+ *	
+ *
+ *	LOCKING:
+ *	Inherits the locks from the omap_prcm driver, no internal locking.
+ *
+ *	RETURNS:
+ *	Returns 0 if sucessful otherwise a negative error code on failure.
+ */
+static int
+omap4_clk_hsusbhost_set_source(struct ti_clock_dev *clkdev,
+                               clk_src_t clksrc)
+{
+	struct omap4_prcm_softc *sc = omap4_prcm_sc;
+	struct resource* clk_mem_res;
+	uint32_t clksel_reg_off;
+	uint32_t clksel;
+	unsigned int bit;
+
+	if (sc == NULL)
+		return ENXIO;
+
+	if (clkdev->id == USBP1_PHY_CLK)
+		bit = 24;
+	else if (clkdev->id != USBP2_PHY_CLK)
+		bit = 25;
+	else
+		return (EINVAL);
+	
+	/* We need the CM_L3INIT_HSUSBHOST_CLKCTRL register in CM2 register set */
+	clk_mem_res = sc->sc_res[CM2_INSTANCE_MEM_REGION];
+	clksel_reg_off = L3INIT_CM2_OFFSET + 0x58;
+	clksel = bus_read_4(clk_mem_res, clksel_reg_off);
+	
+	/* Set the clock source to either external or internal */
+	if (clksrc == EXT_CLK)
+		clksel |= (0x1 << bit);
+	else
+		clksel &= ~(0x1 << bit);
+	
+	bus_write_4(clk_mem_res, clksel_reg_off, clksel);
+
+	return (0);
+}
+
+#define PRM_RSTCTRL		0x1b00
+#define PRM_RSTCTRL_RESET	0x2
+
+static void
+omap4_prcm_reset(void)
+{
+	struct omap4_prcm_softc *sc = omap4_prcm_sc;
+	bus_write_4(sc->sc_res[0], PRM_RSTCTRL,
+	    bus_read_4(sc->sc_res[0], PRM_RSTCTRL) | PRM_RSTCTRL_RESET);
+	bus_read_4(sc->sc_res[0], PRM_RSTCTRL);
+}
+
+/**
+ *	omap4_prcm_probe - probe function for the driver
+ *	@dev: prcm device handle
+ *
+ *	Simply sets the name of the driver module.
+ *
+ *	LOCKING:
+ *	None
+ *
+ *	RETURNS:
+ *	Always returns 0
+ */
+static int
+omap4_prcm_probe(device_t dev)
+{
+	if (!ofw_bus_is_compatible(dev, "ti,omap4_prcm"))
+		return (ENXIO);
+
+	device_set_desc(dev, "TI OMAP Power, Reset and Clock Management");
+	return (0);
+}
+
+/**
+ *	omap_prcm_attach - attach function for the driver
+ *	@dev: prcm device handle
+ *
+ *	Allocates and sets up the driver context, this simply entails creating a
+ *	bus mappings for the PRCM register set.
+ *
+ *	LOCKING:
+ *	None
+ *
+ *	RETURNS:
+ *	Always returns 0
+ */
+static int
+omap4_prcm_attach(device_t dev)
+{
+	struct omap4_prcm_softc *sc = device_get_softc(dev);
+
+	if (bus_alloc_resources(dev, omap4_scm_res_spec, sc->sc_res)) {
+		device_printf(dev, "could not allocate resources\n");
+		return (ENXIO);
+	}
+
+	omap4_prcm_sc = sc;
+	ti_cpu_reset = omap4_prcm_reset;
+
+	return (0);
+}
+
+static device_method_t omap4_prcm_methods[] = {
+	DEVMETHOD(device_probe, omap4_prcm_probe),
+	DEVMETHOD(device_attach, omap4_prcm_attach),
+	{0, 0},
+};
+
+static driver_t omap4_prcm_driver = {
+	"omap4_prcm",
+	omap4_prcm_methods,
+	sizeof(struct omap4_prcm_softc),
+};
+
+static devclass_t omap4_prcm_devclass;
+
+DRIVER_MODULE(omap4_prcm, simplebus, omap4_prcm_driver, omap4_prcm_devclass, 0, 0);
+MODULE_VERSION(omap4_prcm, 1);
diff -r 7fffa673adcd -r a301a330526b head/sys/arm/ti/omap4/omap4_reg.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/head/sys/arm/ti/omap4/omap4_reg.h	Wed Aug 15 11:16:36 2012 +0300
@@ -0,0 +1,586 @@
+/*-
+ * Copyright (c) 2011
+ *	Ben Gray <ben.r.gray at 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.
+ *
+ * $FreeBSD: head/sys/arm/ti/omap4/omap4_reg.h 239281 2012-08-15 06:31:32Z gonzo $
+ */
+
+/*
+ * Texas Instruments - OMAP44xx series processors
+ *
+ * Reference:
+ *  OMAP44xx Applications Processor
+ *   Technical Reference Manual
+ *  (omap44xx_techref.pdf)
+ *
+ *
+ * Note:
+ *  The devices are mapped into address above 0xD000_0000 as the kernel space
+ *  memory is at 0xC000_0000 and above.  The first 256MB after this is reserved
+ *  for the size of the kernel, everything above that is reserved for SoC
+ *  devices.
+ *
+ */
+#ifndef _OMAP44XX_REG_H_
+#define _OMAP44XX_REG_H_
+
+#ifndef _LOCORE
+#include <sys/types.h>		/* for uint32_t */
+#endif
+
+
+
+
+
+/* Physical/Virtual address for SDRAM controller */
+
+#define OMAP44XX_SMS_VBASE			0x6C000000UL
+#define OMAP44XX_SMS_HWBASE			0x6C000000UL
+#define OMAP44XX_SMS_SIZE			0x01000000UL
+
+#define OMAP44XX_SDRC_VBASE			0x6D000000UL
+#define OMAP44XX_SDRC_HWBASE		0x6D000000UL
+#define OMAP44XX_SDRC_SIZE			0x01000000UL
+
+
+
+/* Physical/Virtual address for I/O space */
+
+#define OMAP44XX_L3_EMU_VBASE		0xD4000000UL
+#define OMAP44XX_L3_EMU_HWBASE		0x54000000UL
+#define OMAP44XX_L3_EMU_SIZE		0x00200000UL
+
+#define OMAP44XX_L3_EMIF1_VBASE     0xEC000000UL
+#define OMAP44XX_L3_EMIF1_HWBASE    0x4C000000UL
+#define OMAP44XX_L3_EMIF1_SIZE      0x01000000UL
+
+#define OMAP44XX_L3_EMIF2_VBASE     0xED000000UL
+#define OMAP44XX_L3_EMIF2_HWBASE    0x4D000000UL
+#define OMAP44XX_L3_EMIF2_SIZE      0x01000000UL
+
+
+#define OMAP44XX_L4_CORE_VBASE		0xEA000000UL
+#define OMAP44XX_L4_CORE_HWBASE		0x4A000000UL
+#define OMAP44XX_L4_CORE_SIZE		0x01000000UL
+
+#define OMAP44XX_L4_WAKEUP_VBASE	0xEA300000UL
+#define OMAP44XX_L4_WAKEUP_HWBASE	0x4A300000UL
+#define OMAP44XX_L4_WAKEUP_SIZE		0x00040000UL
+
+#define OMAP44XX_L4_PERIPH_VBASE	0xE8000000UL
+#define OMAP44XX_L4_PERIPH_HWBASE	0x48000000UL
+#define OMAP44XX_L4_PERIPH_SIZE		0x01000000UL
+
+#define OMAP44XX_L4_ABE_VBASE		0xE9000000UL
+#define OMAP44XX_L4_ABE_HWBASE		0x49000000UL
+#define OMAP44XX_L4_ABE_SIZE		0x00100000UL
+
+
+/* Physical/Virtual address for MPU Subsystem space */
+
+#define OMAP44XX_MPU_SUBSYS_VBASE   (OMAP44XX_L4_PERIPH_VBASE + 0x00240000UL)
+#define OMAP44XX_MPU_SUBSYS_HWBASE  (OMAP44XX_L4_PERIPH_HWBASE + 0x00240000UL)
+#define OMAP44XX_MPU_SUBSYS_SIZE    0x00004000UL
+
+/*
+ * MPU Subsystem addresss offsets
+ */
+#define OMAP44XX_SCU_OFFSET                     0x00000000UL
+#define OMAP44XX_GIC_CPU_OFFSET                 0x00000100UL
+#define OMAP44XX_GBL_TIMER_OFFSET               0x00000200UL
+#define OMAP44XX_PRV_TIMER_OFFSET               0x00000600UL
+#define OMAP44XX_GIC_DIST_OFFSET                0x00001000UL
+#define OMAP44XX_PL310_OFFSET                   0x00002000UL
+#define OMAP44XX_CORTEXA9_SOCKET_PRCM_OFFSET    0x00003000UL
+#define OMAP44XX_CORTEXA9_PRM_OFFSET            0x00003200UL
+#define OMAP44XX_CORTEXA9_CPU0_OFFSET           0x00003400UL
+#define OMAP44XX_CORTEXA9_CPU1_OFFSET           0x00003800UL
+
+#define OMAP44XX_SCU_HWBASE         (OMAP44XX_MPU_SUBSYS_HWBASE + OMAP44XX_SCU_OFFSET)
+#define OMAP44XX_SCU_VBASE          (OMAP44XX_MPU_SUBSYS_VBASE  + OMAP44XX_SCU_OFFSET)
+#define OMAP44XX_SCU_SIZE           0x00000080UL
+#define OMAP44XX_GIC_CPU_HWBASE     (OMAP44XX_MPU_SUBSYS_HWBASE + OMAP44XX_GIC_CPU_OFFSET)
+#define OMAP44XX_GIC_CPU_VBASE      (OMAP44XX_MPU_SUBSYS_VBASE  + OMAP44XX_GIC_CPU_OFFSET)
+#define OMAP44XX_GIC_CPU_SIZE       0x00000100UL
+#define OMAP44XX_GBL_TIMER_HWBASE   (OMAP44XX_MPU_SUBSYS_HWBASE + OMAP44XX_GBL_TIMER_OFFSET)
+#define OMAP44XX_GBL_TIMER_VBASE    (OMAP44XX_MPU_SUBSYS_VBASE  + OMAP44XX_GBL_TIMER_OFFSET)
+#define OMAP44XX_GBL_TIMER_SIZE     0x00000100UL
+#define OMAP44XX_PRV_TIMER_HWBASE   (OMAP44XX_MPU_SUBSYS_HWBASE + OMAP44XX_PRV_TIMER_OFFSET)
+#define OMAP44XX_PRV_TIMER_VBASE    (OMAP44XX_MPU_SUBSYS_VBASE  + OMAP44XX_PRV_TIMER_OFFSET)
+#define OMAP44XX_PRV_TIMER_SIZE     0x00000100UL
+#define OMAP44XX_GIC_DIST_HWBASE    (OMAP44XX_MPU_SUBSYS_HWBASE + OMAP44XX_GIC_DIST_OFFSET)
+#define OMAP44XX_GIC_DIST_VBASE     (OMAP44XX_MPU_SUBSYS_VBASE  + OMAP44XX_GIC_DIST_OFFSET)
+#define OMAP44XX_GIC_DIST_SIZE      0x00000100UL
+#define OMAP44XX_PL310_HWBASE       (OMAP44XX_MPU_SUBSYS_HWBASE + OMAP44XX_PL310_OFFSET)
+#define OMAP44XX_PL310_VBASE        (OMAP44XX_MPU_SUBSYS_VBASE  + OMAP44XX_PL310_OFFSET)
+#define OMAP44XX_PL310_SIZE         0x00001000UL
+
+
+
+
+/*
+ * L4-CORE Physical/Virtual addresss offsets
+ */
+#define OMAP44XX_SCM_OFFSET         0x00002000UL
+#define OMAP44XX_CM_OFFSET          0x00004000UL
+#define OMAP44XX_SDMA_OFFSET        0x00056000UL
+#define OMAP44XX_USB_TLL_OFFSET     0x00062000UL
+#define OMAP44XX_USB_UHH_OFFSET     0x00064000UL
+#define OMAP44XX_USB_OHCI_OFFSET    0x00064800UL
+#define OMAP44XX_USB_EHCI_OFFSET    0x00064C00UL
+#define OMAP44XX_MCBSP1_OFFSET      0x00074000UL
+#define OMAP44XX_MCBSP5_OFFSET      0x00096000UL
+#define OMAP44XX_SCM_PADCONF_OFFSET 0x00100000UL
+
+/*
+ * L4-WAKEUP Physical/Virtual addresss offsets
+ */
+#define OMAP44XX_PRM_OFFSET         0x00006000UL
+#define OMAP44XX_SCRM_OFFSET        0x0000A000UL
+#define OMAP44XX_GPIO1_OFFSET       0x00010000UL
+#define OMAP44XX_GPTIMER1_OFFSET    0x00018000UL
+
+
+
+/*
+ * L4-PERIPH Physical/Virtual addresss offsets
+ */
+#define OMAP44XX_UART3_OFFSET		0x00020000UL
+#define OMAP44XX_GPTIMER2_OFFSET	0x00032000UL
+#define OMAP44XX_GPTIMER3_OFFSET	0x00034000UL
+#define OMAP44XX_GPTIMER4_OFFSET	0x00036000UL
+#define OMAP44XX_GPTIMER9_OFFSET	0x0003E000UL
+#define OMAP44XX_GPIO2_OFFSET		0x00055000UL
+#define OMAP44XX_GPIO3_OFFSET		0x00057000UL
+#define OMAP44XX_GPIO4_OFFSET		0x00059000UL
+#define OMAP44XX_GPIO5_OFFSET		0x0005B000UL
+#define OMAP44XX_GPIO6_OFFSET		0x0005D000UL
+#define OMAP44XX_I2C3_OFFSET		0x00060000UL
+#define OMAP44XX_UART1_OFFSET		0x0006A000UL
+#define OMAP44XX_UART2_OFFSET		0x0006C000UL
+#define OMAP44XX_UART4_OFFSET		0x0006E000UL
+#define OMAP44XX_I2C1_OFFSET		0x00070000UL
+#define OMAP44XX_I2C2_OFFSET		0x00072000UL
+#define OMAP44XX_SLIMBUS2_OFFSET	0x00076000UL
+#define OMAP44XX_ELM_OFFSET			0x00078000UL
+#define OMAP44XX_GPTIMER10_OFFSET	0x00086000UL
+#define OMAP44XX_GPTIMER11_OFFSET	0x00088000UL
+#define OMAP44XX_MCBSP4_OFFSET		0x00096000UL
+#define OMAP44XX_MCSPI1_OFFSET		0x00098000UL
+#define OMAP44XX_MCSPI2_OFFSET		0x0009A000UL
+#define OMAP44XX_MMCHS1_OFFSET		0x0009C000UL
+#define OMAP44XX_MMCSD3_OFFSET		0x000AD000UL
+#define OMAP44XX_MMCHS2_OFFSET		0x000B4000UL
+#define OMAP44XX_MMCSD4_OFFSET		0x000D1000UL
+#define OMAP44XX_MMCSD5_OFFSET		0x000D5000UL
+#define OMAP44XX_I2C4_OFFSET		0x00350000UL
+
+/* The following are registers defined as part of the ARM MPCORE system,
+ * they are not SoC components rather registers that control the MPCORE core.
+ */
+// #define OMAP44XX_SCU_OFFSET			0x48240000	/* Snoop control unit */
+// #define OMAP44XX_GIC_PROC_OFFSET	0x48240100	/* Interrupt controller unit */
+// #define OMAP44XX_MPU_TIMER_OFFSET	0x48240600
+// #define OMAP44XX_GIC_INTR_OFFSET	0x48241000
+// #define OMAP44XX_PL310_OFFSET		0x48242000	/* L2 Cache controller */
+
+
+/*
+ * L4-ABE Physical/Virtual addresss offsets
+ */
+#define OMAP44XX_GPTIMER5_OFFSET	0x00038000UL
+#define OMAP44XX_GPTIMER6_OFFSET	0x0003A000UL
+#define OMAP44XX_GPTIMER7_OFFSET	0x0003C000UL
+#define OMAP44XX_GPTIMER8_OFFSET	0x0003E000UL
+
+
+
+
+
+/*
+ * System Control Module
+ */
+#define OMAP44XX_SCM_HWBASE				(OMAP44XX_L4_CORE_HWBASE + OMAP44XX_SCM_OFFSET)
+#define OMAP44XX_SCM_VBASE				(OMAP44XX_L4_CORE_VBASE + OMAP44XX_SCM_OFFSET)
+#define OMAP44XX_SCM_SIZE				0x00001000UL
+
+
+
+/*
+ *
+ */
+#define OMAP44XX_CM_HWBASE				(OMAP44XX_L4_CORE_HWBASE + OMAP44XX_CM_OFFSET)
+#define OMAP44XX_CM_VBASE				(OMAP44XX_L4_CORE_VBASE + OMAP44XX_CM_OFFSET)
+#define OMAP44XX_CM_SIZE				0x00001500UL
+
+
+/*
+ *
+ */
+#define OMAP44XX_PRM_HWBASE				(OMAP44XX_L4_WAKEUP_HWBASE + OMAP44XX_PRM_OFFSET)
+#define OMAP44XX_PRM_VBASE				(OMAP44XX_L4_WAKEUP_VBASE + OMAP44XX_PRM_OFFSET)
+#define OMAP44XX_PRM_SIZE				0x00001600UL
+
+/*
+ *
+ */
+#define OMAP44XX_SCRM_HWBASE            (OMAP44XX_L4_WAKEUP_HWBASE + OMAP44XX_SCRM_OFFSET)
+#define OMAP44XX_SCRM_VBASE             (OMAP44XX_L4_WAKEUP_VBASE + OMAP44XX_SCRM_OFFSET)
+#define OMAP44XX_SCRM_SIZE              0x00000800UL
+
+
+
+/*
+ * Uarts
+ */
+#define OMAP44XX_UART1_HWBASE			(OMAP44XX_L4_CORE_HWBASE + OMAP44XX_UART1_OFFSET)
+#define OMAP44XX_UART1_VBASE			(OMAP44XX_L4_CORE_VBASE  + OMAP44XX_UART1_OFFSET)
+#define OMAP44XX_UART1_SIZE				0x00001000UL
+#define OMAP44XX_UART2_HWBASE			(OMAP44XX_L4_CORE_HWBASE + OMAP44XX_UART2_OFFSET)
+#define OMAP44XX_UART2_VBASE			(OMAP44XX_L4_CORE_VBASE  + OMAP44XX_UART2_OFFSET)
+#define OMAP44XX_UART2_SIZE				0x00001000UL
+#define OMAP44XX_UART3_HWBASE			(OMAP44XX_L4_PERIPH_HWBASE + OMAP44XX_UART3_OFFSET)
+#define OMAP44XX_UART3_VBASE			(OMAP44XX_L4_PERIPH_VBASE  + OMAP44XX_UART3_OFFSET)
+#define OMAP44XX_UART3_SIZE				0x00001000UL
+#define OMAP44XX_UART4_HWBASE			(OMAP44XX_L4_PERIPH_HWBASE + OMAP44XX_UART4_OFFSET)
+#define OMAP44XX_UART4_VBASE			(OMAP44XX_L4_PERIPH_VBASE  + OMAP44XX_UART4_OFFSET)
+#define OMAP44XX_UART4_SIZE				0x00001000UL
+
+
+
+
+/*
+ * I2C Modules
+ */
+#define OMAP44XX_I2C1_HWBASE			(OMAP44XX_L4_CORE_HWBASE + OMAP44XX_I2C1_OFFSET)
+#define OMAP44XX_I2C1_VBASE				(OMAP44XX_L4_CORE_VBASE  + OMAP44XX_I2C1_OFFSET)
+#define OMAP44XX_I2C1_SIZE				0x00000080UL
+#define OMAP44XX_I2C2_HWBASE			(OMAP44XX_L4_CORE_HWBASE + OMAP44XX_I2C2_OFFSET)
+#define OMAP44XX_I2C2_VBASE				(OMAP44XX_L4_CORE_VBASE  + OMAP44XX_I2C2_OFFSET)
+#define OMAP44XX_I2C2_SIZE				0x00000080UL
+#define OMAP44XX_I2C3_HWBASE			(OMAP44XX_L4_CORE_HWBASE + OMAP44XX_I2C3_OFFSET)
+#define OMAP44XX_I2C3_VBASE				(OMAP44XX_L4_CORE_VBASE  + OMAP44XX_I2C3_OFFSET)
+#define OMAP44XX_I2C3_SIZE				0x00000080UL
+
+
+
+/*
+ * McBSP Modules
+ */
+#define OMAP44XX_MCBSP1_HWBASE			(OMAP44XX_L4_CORE_HWBASE + OMAP44XX_MCBSP1_OFFSET)
+#define OMAP44XX_MCBSP1_VBASE			(OMAP44XX_L4_CORE_VBASE  + OMAP44XX_MCBSP1_OFFSET)
+#define OMAP44XX_MCBSP1_SIZE			0x00001000UL
+#define OMAP44XX_MCBSP2_HWBASE			(OMAP44XX_L4_PERIPH_HWBASE + OMAP44XX_MCBSP2_OFFSET)
+#define OMAP44XX_MCBSP2_VBASE			(OMAP44XX_L4_PERIPH_VBASE  + OMAP44XX_MCBSP2_OFFSET)
+#define OMAP44XX_MCBSP2_SIZE			0x00001000UL
+#define OMAP44XX_MCBSP3_HWBASE			(OMAP44XX_L4_PERIPH_HWBASE + OMAP44XX_MCBSP3_OFFSET)
+#define OMAP44XX_MCBSP3_VBASE			(OMAP44XX_L4_PERIPH_VBASE  + OMAP44XX_MCBSP3_OFFSET)
+#define OMAP44XX_MCBSP3_SIZE			0x00001000UL
+#define OMAP44XX_MCBSP4_HWBASE			(OMAP44XX_L4_PERIPH_HWBASE + OMAP44XX_MCBSP4_OFFSET)
+#define OMAP44XX_MCBSP4_VBASE			(OMAP44XX_L4_PERIPH_VBASE  + OMAP44XX_MCBSP4_OFFSET)
+#define OMAP44XX_MCBSP4_SIZE			0x00001000UL
+#define OMAP44XX_MCBSP5_HWBASE			(OMAP44XX_L4_CORE_HWBASE + OMAP44XX_MCBSP5_OFFSET)
+#define OMAP44XX_MCBSP5_VBASE			(OMAP44XX_L4_CORE_VBASE  + OMAP44XX_MCBSP5_OFFSET)
+#define OMAP44XX_MCBSP5_SIZE			0x00001000UL
+
+
+
+/*
+ * USB TTL Module
+ */
+#define OMAP44XX_USB_TLL_HWBASE         (OMAP44XX_L4_CORE_HWBASE + OMAP44XX_USB_TLL_OFFSET)
+#define OMAP44XX_USB_TLL_VBASE          (OMAP44XX_L4_CORE_VBASE  + OMAP44XX_USB_TLL_OFFSET)
+#define OMAP44XX_USB_TLL_SIZE           0x00001000UL
+
+/*
+ * USB Host Module
+ */
+#define OMAP44XX_USB_UHH_HWBASE         (OMAP44XX_L4_CORE_HWBASE + OMAP44XX_USB_UHH_OFFSET)
+#define OMAP44XX_USB_UHH_VBASE          (OMAP44XX_L4_CORE_VBASE  + OMAP44XX_USB_UHH_OFFSET)
+#define OMAP44XX_USB_UHH_SIZE           0x00000700UL
+
+/*
+ * USB OHCI Module
+ */
+#define OMAP44XX_USB_OHCI_HWBASE        (OMAP44XX_L4_CORE_HWBASE + OMAP44XX_USB_OHCI_OFFSET)
+#define OMAP44XX_USB_OHCI_VBASE         (OMAP44XX_L4_CORE_VBASE  + OMAP44XX_USB_OHCI_OFFSET)
+#define OMAP44XX_USB_OHCI_SIZE          0x00000400UL
+
+/*
+ * USB EHCI Module
+ */
+#define OMAP44XX_USB_EHCI_HWBASE        (OMAP44XX_L4_CORE_HWBASE + OMAP44XX_USB_EHCI_OFFSET)
+#define OMAP44XX_USB_EHCI_VBASE         (OMAP44XX_L4_CORE_VBASE  + OMAP44XX_USB_EHCI_OFFSET)
+#define OMAP44XX_USB_EHCI_SIZE          0x0000400UL
+
+
+
+
+
+/*
+ * SDMA Offset
+ *  PA 0x4805 6000
+ */
+
+#define OMAP44XX_SDMA_HWBASE			(OMAP44XX_L4_CORE_HWBASE + OMAP44XX_SDMA_OFFSET)
+#define OMAP44XX_SDMA_VBASE				(OMAP44XX_L4_CORE_VBASE  + OMAP44XX_SDMA_OFFSET)
+#define OMAP44XX_SDMA_SIZE				0x00001000UL
+
+
+
+/*
+ * Interrupt Controller Unit.
+ *
+ *    Refer to the omap4_intr.c file for interrupt controller (GIC)
+ *    implementation.
+ *
+ *    Note:
+ *    - 16 Interprocessor interrupts (IPI): ID[15:0]
+ *    - 2 private Timer/Watchdog interrupts: ID[30:29]
+ *    - 2 legacy nFIQ & nIRQ: one per CPU, bypasses the interrupt distributor
+ *      logic and directly drives interrupt requests into CPU if used in
+ *      legacy mode (else treated like other interrupts lines with ID28
+ *      and ID31 respectively)
+ *    - 128 hardware interrupts: ID[159:32] (rising-edge or high-level sensitive).
+ */
+#define OMAP44XX_HARDIRQ(x)         (32 + (x))
+
+#define OMAP44XX_IRQ_L2CACHE        OMAP44XX_HARDIRQ(0)     /* L2 cache controller interrupt */
+#define OMAP44XX_IRQ_CTI_0          OMAP44XX_HARDIRQ(1)     /* Cross-trigger module 0 (CTI0) interrupt */
+#define OMAP44XX_IRQ_CTI_1          OMAP44XX_HARDIRQ(2)     /* Cross-trigger module 1 (CTI1) interrupt */
+#define OMAP44XX_IRQ_RESERVED3      OMAP44XX_HARDIRQ(3)     /* RESERVED */
+#define OMAP44XX_IRQ_ELM            OMAP44XX_HARDIRQ(4)     /* Error location process completion */
+#define OMAP44XX_IRQ_RESERVED5      OMAP44XX_HARDIRQ(5)     /* RESERVED */
+#define OMAP44XX_IRQ_RESERVED6      OMAP44XX_HARDIRQ(6)     /* RESERVED */
+#define OMAP44XX_IRQ_SYS_NIRQ       OMAP44XX_HARDIRQ(7)     /* External source (active low) */
+#define OMAP44XX_IRQ_RESERVED8      OMAP44XX_HARDIRQ(8)     /* RESERVED */
+#define OMAP44XX_IRQ_L3_DBG         OMAP44XX_HARDIRQ(9)     /* L3 interconnect debug error */
+#define OMAP44XX_IRQ_L3_APP         OMAP44XX_HARDIRQ(10)    /* L3 interconnect application error */
+#define OMAP44XX_IRQ_PRCM_MPU       OMAP44XX_HARDIRQ(11)    /* PRCM module IRQ */
+#define OMAP44XX_IRQ_SDMA0          OMAP44XX_HARDIRQ(12)    /* System DMA request 0(3) */
+#define OMAP44XX_IRQ_SDMA1          OMAP44XX_HARDIRQ(13)    /* System DMA request 1(3) */
+#define OMAP44XX_IRQ_SDMA2          OMAP44XX_HARDIRQ(14)    /* System DMA request 2 */
+#define OMAP44XX_IRQ_SDMA3          OMAP44XX_HARDIRQ(15)    /* System DMA request 3 */
+#define OMAP44XX_IRQ_MCBSP4         OMAP44XX_HARDIRQ(16)    /* McBSP module 4 IRQ */
+#define OMAP44XX_IRQ_MCBSP1         OMAP44XX_HARDIRQ(17)    /* McBSP module 1 IRQ */
+#define OMAP44XX_IRQ_SR1            OMAP44XX_HARDIRQ(18)    /* SmartReflexâ„¢ 1 */
+#define OMAP44XX_IRQ_SR2            OMAP44XX_HARDIRQ(19)    /* SmartReflexâ„¢ 2 */
+#define OMAP44XX_IRQ_GPMC           OMAP44XX_HARDIRQ(20)    /* General-purpose memory controller module */
+#define OMAP44XX_IRQ_SGX            OMAP44XX_HARDIRQ(21)    /* 2D/3D graphics module */
+#define OMAP44XX_IRQ_MCBSP2         OMAP44XX_HARDIRQ(22)    /* McBSP module 2 */
+#define OMAP44XX_IRQ_MCBSP3         OMAP44XX_HARDIRQ(23)    /* McBSP module 3 */
+#define OMAP44XX_IRQ_ISS5           OMAP44XX_HARDIRQ(24)    /* Imaging subsystem interrupt 5 */
+#define OMAP44XX_IRQ_DSS            OMAP44XX_HARDIRQ(25)    /* Display subsystem module(3) */
+#define OMAP44XX_IRQ_MAIL_U0        OMAP44XX_HARDIRQ(26)    /* Mailbox user 0 request */
+#define OMAP44XX_IRQ_C2C_SSCM       OMAP44XX_HARDIRQ(27)    /* C2C status interrupt */
+#define OMAP44XX_IRQ_DSP_MMU        OMAP44XX_HARDIRQ(28)    /* DSP MMU */
+#define OMAP44XX_IRQ_GPIO1_MPU      OMAP44XX_HARDIRQ(29)    /* GPIO module 1(3) */
+#define OMAP44XX_IRQ_GPIO2_MPU      OMAP44XX_HARDIRQ(30)    /* GPIO module 2(3) */
+#define OMAP44XX_IRQ_GPIO3_MPU      OMAP44XX_HARDIRQ(31)    /* GPIO module 3(3) */
+#define OMAP44XX_IRQ_GPIO4_MPU      OMAP44XX_HARDIRQ(32)    /* GPIO module 4(3) */
+#define OMAP44XX_IRQ_GPIO5_MPU      OMAP44XX_HARDIRQ(33)    /* GPIO module 5(3) */
+#define OMAP44XX_IRQ_GPIO6_MPU      OMAP44XX_HARDIRQ(34)    /* GPIO module 6(3) */
+#define OMAP44XX_IRQ_RESERVED35     OMAP44XX_HARDIRQ(35)    /* RESERVED */
+#define OMAP44XX_IRQ_WDT3           OMAP44XX_HARDIRQ(36)    /* Watchdog timer module 3 overflow */
+#define OMAP44XX_IRQ_GPT1           OMAP44XX_HARDIRQ(37)    /* General-purpose timer module 1 */
+#define OMAP44XX_IRQ_GPT2           OMAP44XX_HARDIRQ(38)    /* General-purpose timer module 2 */
+#define OMAP44XX_IRQ_GPT3           OMAP44XX_HARDIRQ(39)    /* General-purpose timer module 3 */
+#define OMAP44XX_IRQ_GPT4           OMAP44XX_HARDIRQ(40)    /* General-purpose timer module 4 */
+#define OMAP44XX_IRQ_GPT5           OMAP44XX_HARDIRQ(41)    /* General-purpose timer module 5 */
+#define OMAP44XX_IRQ_GPT6           OMAP44XX_HARDIRQ(42)    /* General-purpose timer module 6 */
+#define OMAP44XX_IRQ_GPT7           OMAP44XX_HARDIRQ(43)    /* General-purpose timer module 7 */
+#define OMAP44XX_IRQ_GPT8           OMAP44XX_HARDIRQ(44)    /* General-purpose timer module 8 */
+#define OMAP44XX_IRQ_GPT9           OMAP44XX_HARDIRQ(45)    /* General-purpose timer module 9 */
+#define OMAP44XX_IRQ_GPT10          OMAP44XX_HARDIRQ(46)    /* General-purpose timer module 10 */
+#define OMAP44XX_IRQ_GPT11          OMAP44XX_HARDIRQ(47)    /* General-purpose timer module 11 */
+#define OMAP44XX_IRQ_MCSPI4         OMAP44XX_HARDIRQ(48)    /* McSPI module 4 */
+#define OMAP44XX_IRQ_RESERVED49     OMAP44XX_HARDIRQ(49)    /* RESERVED */
+#define OMAP44XX_IRQ_RESERVED50     OMAP44XX_HARDIRQ(50)    /* RESERVED */
+#define OMAP44XX_IRQ_RESERVED51     OMAP44XX_HARDIRQ(51)    /* RESERVED */
+#define OMAP44XX_IRQ_RESERVED52     OMAP44XX_HARDIRQ(52)    /* RESERVED */
+#define OMAP44XX_IRQ_DSS_DSI1       OMAP44XX_HARDIRQ(53)    /* Display Subsystem DSI1 interrupt */
+#define OMAP44XX_IRQ_RESERVED54     OMAP44XX_HARDIRQ(54)    /* RESERVED */
+#define OMAP44XX_IRQ_RESERVED55     OMAP44XX_HARDIRQ(55)    /* RESERVED */
+#define OMAP44XX_IRQ_I2C1           OMAP44XX_HARDIRQ(56)    /* I2C module 1 */
+#define OMAP44XX_IRQ_I2C2           OMAP44XX_HARDIRQ(57)    /* I2C module 2 */
+#define OMAP44XX_IRQ_HDQ            OMAP44XX_HARDIRQ(58)    /* HDQ / One-wire */
+#define OMAP44XX_IRQ_MMC5           OMAP44XX_HARDIRQ(59)    /* MMC5 interrupt */
+#define OMAP44XX_IRQ_RESERVED60     OMAP44XX_HARDIRQ(60)    /* RESERVED */
+#define OMAP44XX_IRQ_I2C3           OMAP44XX_HARDIRQ(61)    /* I2C module 3 */
+#define OMAP44XX_IRQ_I2C4           OMAP44XX_HARDIRQ(62)    /* I2C module 4 */
+#define OMAP44XX_IRQ_RESERVED63     OMAP44XX_HARDIRQ(63)    /* RESERVED */
+#define OMAP44XX_IRQ_RESERVED64     OMAP44XX_HARDIRQ(64)    /* RESERVED */
+#define OMAP44XX_IRQ_MCSPI1         OMAP44XX_HARDIRQ(65)    /* McSPI module 1 */
+#define OMAP44XX_IRQ_MCSPI2         OMAP44XX_HARDIRQ(66)    /* McSPI module 2 */
+#define OMAP44XX_IRQ_HSI_P1         OMAP44XX_HARDIRQ(67)    /* HSI Port 1 interrupt */
+#define OMAP44XX_IRQ_HSI_P2         OMAP44XX_HARDIRQ(68)    /* HSI Port 2 interrupt */
+#define OMAP44XX_IRQ_FDIF_3         OMAP44XX_HARDIRQ(69)    /* Face detect interrupt 3 */
+#define OMAP44XX_IRQ_UART4          OMAP44XX_HARDIRQ(70)    /* UART module 4 interrupt */
+#define OMAP44XX_IRQ_HSI_DMA        OMAP44XX_HARDIRQ(71)    /* HSI DMA engine MPU request */
+#define OMAP44XX_IRQ_UART1          OMAP44XX_HARDIRQ(72)    /* UART module 1 */
+#define OMAP44XX_IRQ_UART2          OMAP44XX_HARDIRQ(73)    /* UART module 2 */
+#define OMAP44XX_IRQ_UART3          OMAP44XX_HARDIRQ(74)    /* UART module 3 (also infrared)(3) */
+#define OMAP44XX_IRQ_PBIAS          OMAP44XX_HARDIRQ(75)    /* Merged interrupt for PBIASlite1 and 2 */
+#define OMAP44XX_IRQ_OHCI           OMAP44XX_HARDIRQ(76)    /* OHCI controller HSUSB MP Host Interrupt */
+#define OMAP44XX_IRQ_EHCI           OMAP44XX_HARDIRQ(77)    /* EHCI controller HSUSB MP Host Interrupt */
+#define OMAP44XX_IRQ_TLL            OMAP44XX_HARDIRQ(78)    /* HSUSB MP TLL Interrupt */
+#define OMAP44XX_IRQ_RESERVED79     OMAP44XX_HARDIRQ(79)    /* RESERVED */
+#define OMAP44XX_IRQ_WDT2           OMAP44XX_HARDIRQ(80)    /* WDTIMER2 interrupt */
+#define OMAP44XX_IRQ_RESERVED81     OMAP44XX_HARDIRQ(81)    /* RESERVED */
+#define OMAP44XX_IRQ_RESERVED82     OMAP44XX_HARDIRQ(82)    /* RESERVED */
+#define OMAP44XX_IRQ_MMC1           OMAP44XX_HARDIRQ(83)    /* MMC/SD module 1 */
+#define OMAP44XX_IRQ_DSS_DSI2       OMAP44XX_HARDIRQ(84)    /* Display subsystem DSI2 interrupt */
+#define OMAP44XX_IRQ_RESERVED85     OMAP44XX_HARDIRQ(85)    /* Reserved */
+#define OMAP44XX_IRQ_MMC2           OMAP44XX_HARDIRQ(86)    /* MMC/SD module 2 */
+#define OMAP44XX_IRQ_MPU_ICR        OMAP44XX_HARDIRQ(87)    /* MPU ICR */
+#define OMAP44XX_IRQ_C2C_GPI        OMAP44XX_HARDIRQ(88)    /* C2C GPI interrupt */
+#define OMAP44XX_IRQ_FSUSB          OMAP44XX_HARDIRQ(89)    /* FS-USB - host controller Interrupt */
+#define OMAP44XX_IRQ_FSUSB_SMI      OMAP44XX_HARDIRQ(90)    /* FS-USB - host controller SMI Interrupt */
+#define OMAP44XX_IRQ_MCSPI3         OMAP44XX_HARDIRQ(91)    /* McSPI module 3 */
+#define OMAP44XX_IRQ_HSUSB_OTG      OMAP44XX_HARDIRQ(92)    /* High-Speed USB OTG controller */
+#define OMAP44XX_IRQ_HSUSB_OTG_DMA  OMAP44XX_HARDIRQ(93)    /* High-Speed USB OTG DMA controller */
+#define OMAP44XX_IRQ_MMC3           OMAP44XX_HARDIRQ(94)    /* MMC/SD module 3 */
+#define OMAP44XX_IRQ_RESERVED95     OMAP44XX_HARDIRQ(95)    /* RESERVED */
+#define OMAP44XX_IRQ_MMC4           OMAP44XX_HARDIRQ(96)    /* MMC4 interrupt */
+#define OMAP44XX_IRQ_SLIMBUS1       OMAP44XX_HARDIRQ(97)    /* SLIMBUS1 interrupt */
+#define OMAP44XX_IRQ_SLIMBUS2       OMAP44XX_HARDIRQ(98)    /* SLIMBUS2 interrupt */
+#define OMAP44XX_IRQ_ABE            OMAP44XX_HARDIRQ(99)    /* Audio back-end interrupt */
+#define OMAP44XX_IRQ_CORTEXM3_MMU   OMAP44XX_HARDIRQ(100)   /* Cortex-M3 MMU interrupt */
+#define OMAP44XX_IRQ_DSS_HDMI       OMAP44XX_HARDIRQ(101)   /* Display subsystem HDMI interrupt */
+#define OMAP44XX_IRQ_SR_IVA         OMAP44XX_HARDIRQ(102)   /* SmartReflex IVA interrupt */
+#define OMAP44XX_IRQ_IVAHD1         OMAP44XX_HARDIRQ(103)   /* Sync interrupt from iCONT2 (vDMA) */
+#define OMAP44XX_IRQ_IVAHD2         OMAP44XX_HARDIRQ(104)   /* Sync interrupt from iCONT1 */
+#define OMAP44XX_IRQ_RESERVED105    OMAP44XX_HARDIRQ(105)   /* RESERVED */
+#define OMAP44XX_IRQ_RESERVED106    OMAP44XX_HARDIRQ(106)   /* RESERVED */
+#define OMAP44XX_IRQ_IVAHD_MAILBOX0 OMAP44XX_HARDIRQ(107)   /* IVAHD mailbox interrupt */
+#define OMAP44XX_IRQ_RESERVED108    OMAP44XX_HARDIRQ(108)   /* RESERVED */
+#define OMAP44XX_IRQ_MCASP1         OMAP44XX_HARDIRQ(109)   /* McASP1 transmit interrupt */
+#define OMAP44XX_IRQ_EMIF1          OMAP44XX_HARDIRQ(110)   /* EMIF1 interrupt */
+#define OMAP44XX_IRQ_EMIF2          OMAP44XX_HARDIRQ(111)   /* EMIF2 interrupt */
+#define OMAP44XX_IRQ_MCPDM          OMAP44XX_HARDIRQ(112)   /* MCPDM interrupt */
+#define OMAP44XX_IRQ_DMM            OMAP44XX_HARDIRQ(113)   /* DMM interrupt */
+#define OMAP44XX_IRQ_DMIC           OMAP44XX_HARDIRQ(114)   /* DMIC interrupt */
+#define OMAP44XX_IRQ_RESERVED115    OMAP44XX_HARDIRQ(115)   /* RESERVED */
+#define OMAP44XX_IRQ_RESERVED116    OMAP44XX_HARDIRQ(116)   /* RESERVED */
+#define OMAP44XX_IRQ_RESERVED117    OMAP44XX_HARDIRQ(117)   /* RESERVED */
+#define OMAP44XX_IRQ_RESERVED118    OMAP44XX_HARDIRQ(118)   /* RESERVED */
+#define OMAP44XX_IRQ_SYS_NIRQ2      OMAP44XX_HARDIRQ(119)   /* External source 2 (active low) */
+#define OMAP44XX_IRQ_KBD            OMAP44XX_HARDIRQ(120)   /* Keyboard controller interrupt */
+#define OMAP44XX_IRQ_RESERVED121    OMAP44XX_HARDIRQ(121)   /* RESERVED */
+#define OMAP44XX_IRQ_RESERVED122    OMAP44XX_HARDIRQ(122)   /* RESERVED */
+#define OMAP44XX_IRQ_RESERVED123    OMAP44XX_HARDIRQ(123)   /* RESERVED */
+#define OMAP44XX_IRQ_RESERVED124    OMAP44XX_HARDIRQ(124)   /* RESERVED */
+#define OMAP44XX_IRQ_RESERVED125    OMAP44XX_HARDIRQ(125)   /* RESERVED */
+#define OMAP44XX_IRQ_RESERVED126    OMAP44XX_HARDIRQ(126)   /* RESERVED */
+#define OMAP44XX_IRQ_RESERVED127    OMAP44XX_HARDIRQ(127)   /* RESERVED */
+
+
+
+/*
+ * General Purpose Timers
+ */
+#define OMAP44XX_GPTIMER1_VBASE		(OMAP44XX_L4_WAKEUP_VBASE + OMAP44XX_GPTIMER1_OFFSET)
+#define OMAP44XX_GPTIMER1_HWBASE	(OMAP44XX_L4_WAKEUP_HWBASE + OMAP44XX_GPTIMER1_OFFSET)
+#define OMAP44XX_GPTIMER2_VBASE		(OMAP44XX_L4_PERIPH_VBASE + OMAP44XX_GPTIMER2_OFFSET)
+#define OMAP44XX_GPTIMER2_HWBASE	(OMAP44XX_L4_PERIPH_HWBASE + OMAP44XX_GPTIMER2_OFFSET)
+#define OMAP44XX_GPTIMER3_VBASE		(OMAP44XX_L4_PERIPH_VBASE + OMAP44XX_GPTIMER3_OFFSET)
+#define OMAP44XX_GPTIMER3_HWBASE	(OMAP44XX_L4_PERIPH_HWBASE + OMAP44XX_GPTIMER3_OFFSET)
+#define OMAP44XX_GPTIMER4_VBASE		(OMAP44XX_L4_PERIPH_VBASE + OMAP44XX_GPTIMER4_OFFSET)
+#define OMAP44XX_GPTIMER4_HWBASE	(OMAP44XX_L4_PERIPH_HWBASE + OMAP44XX_GPTIMER4_OFFSET)
+#define OMAP44XX_GPTIMER5_VBASE		(OMAP44XX_L4_ABE_VBASE + OMAP44XX_GPTIMER5_OFFSET)
+#define OMAP44XX_GPTIMER5_HWBASE	(OMAP44XX_L4_ABE_HWBASE + OMAP44XX_GPTIMER5_OFFSET)
+#define OMAP44XX_GPTIMER6_VBASE		(OMAP44XX_L4_ABE_VBASE + OMAP44XX_GPTIMER6_OFFSET)
+#define OMAP44XX_GPTIMER6_HWBASE	(OMAP44XX_L4_ABE_HWBASE + OMAP44XX_GPTIMER6_OFFSET)
+#define OMAP44XX_GPTIMER7_VBASE		(OMAP44XX_L4_ABE_VBASE + OMAP44XX_GPTIMER7_OFFSET)
+#define OMAP44XX_GPTIMER7_HWBASE	(OMAP44XX_L4_ABE_HWBASE + OMAP44XX_GPTIMER7_OFFSET)
+#define OMAP44XX_GPTIMER8_VBASE		(OMAP44XX_L4_ABE_VBASE + OMAP44XX_GPTIMER8_OFFSET)
+#define OMAP44XX_GPTIMER8_HWBASE	(OMAP44XX_L4_ABE_HWBASE + OMAP44XX_GPTIMER8_OFFSET)
+#define OMAP44XX_GPTIMER9_VBASE		(OMAP44XX_L4_PERIPH_VBASE + OMAP44XX_GPTIMER9_OFFSET)
+#define OMAP44XX_GPTIMER9_HWBASE    (OMAP44XX_L4_PERIPH_HWBASE + OMAP44XX_GPTIMER9_OFFSET)
+#define OMAP44XX_GPTIMER10_VBASE	(OMAP44XX_L4_PERIPH_VBASE + OMAP44XX_GPTIMER10_OFFSET)
+#define OMAP44XX_GPTIMER10_HWBASE	(OMAP44XX_L4_PERIPH_HWBASE + OMAP44XX_GPTIMER10_OFFSET)
+#define OMAP44XX_GPTIMER11_VBASE	(OMAP44XX_L4_PERIPH_VBASE + OMAP44XX_GPTIMER11_OFFSET)
+#define OMAP44XX_GPTIMER11_HWBASE	(OMAP44XX_L4_PERIPH_HWBASE + OMAP44XX_GPTIMER11_OFFSET)
+#define OMAP44XX_GPTIMER_SIZE		0x00001000UL
+
+
+
+/*
+ * GPIO - General Purpose IO
+ */
+
+/* Base addresses for the GPIO modules */
+#define OMAP44XX_GPIO1_HWBASE		(OMAP44XX_L4_WAKEUP_HWBASE + OMAP44XX_GPIO1_OFFSET)
+#define OMAP44XX_GPIO1_VBASE		(OMAP44XX_L4_WAKEUP_VBASE  + OMAP44XX_GPIO1_OFFSET)
+#define OMAP44XX_GPIO1_SIZE			0x00001000UL
+#define OMAP44XX_GPIO2_HWBASE		(OMAP44XX_L4_PERIPH_HWBASE + OMAP44XX_GPIO2_OFFSET)
+#define OMAP44XX_GPIO2_VBASE		(OMAP44XX_L4_PERIPH_VBASE  + OMAP44XX_GPIO2_OFFSET)
+#define OMAP44XX_GPIO2_SIZE			0x00001000UL
+#define OMAP44XX_GPIO3_HWBASE		(OMAP44XX_L4_PERIPH_HWBASE + OMAP44XX_GPIO3_OFFSET)
+#define OMAP44XX_GPIO3_VBASE		(OMAP44XX_L4_PERIPH_VBASE  + OMAP44XX_GPIO3_OFFSET)
+#define OMAP44XX_GPIO3_SIZE			0x00001000UL
+#define OMAP44XX_GPIO4_HWBASE		(OMAP44XX_L4_PERIPH_HWBASE + OMAP44XX_GPIO4_OFFSET)
+#define OMAP44XX_GPIO4_VBASE		(OMAP44XX_L4_PERIPH_VBASE  + OMAP44XX_GPIO4_OFFSET)
+#define OMAP44XX_GPIO4_SIZE			0x00001000UL
+#define OMAP44XX_GPIO5_HWBASE		(OMAP44XX_L4_PERIPH_HWBASE + OMAP44XX_GPIO5_OFFSET)
+#define OMAP44XX_GPIO5_VBASE		(OMAP44XX_L4_PERIPH_VBASE  + OMAP44XX_GPIO5_OFFSET)
+#define OMAP44XX_GPIO5_SIZE			0x00001000UL
+#define OMAP44XX_GPIO6_HWBASE		(OMAP44XX_L4_PERIPH_HWBASE + OMAP44XX_GPIO6_OFFSET)
+#define OMAP44XX_GPIO6_VBASE		(OMAP44XX_L4_PERIPH_VBASE  + OMAP44XX_GPIO6_OFFSET)
+#define OMAP44XX_GPIO6_SIZE			0x00001000UL
+
+
+/*
+ * MMC/SD/SDIO
+ */
+
+/* Base addresses for the MMC/SD/SDIO modules */
+#define OMAP44XX_MMCHS1_HWBASE   (OMAP44XX_L4_PERIPH_HWBASE + OMAP44XX_MMCHS1_OFFSET)
+#define OMAP44XX_MMCHS1_VBASE    (OMAP44XX_L4_PERIPH_VBASE + OMAP44XX_MMCHS1_OFFSET)
+#define OMAP44XX_MMCHS2_HWBASE   (OMAP44XX_L4_PERIPH_HWBASE + OMAP44XX_MMCHS2_OFFSET)
+#define OMAP44XX_MMCHS2_VBASE    (OMAP44XX_L4_PERIPH_VBASE + OMAP44XX_MMCHS2_OFFSET)
+#define OMAP44XX_MMCHS3_HWBASE   (OMAP44XX_L4_PERIPH_HWBASE + OMAP44XX_MMCSD3_OFFSET)
+#define OMAP44XX_MMCHS3_VBASE    (OMAP44XX_L4_PERIPH_VBASE + OMAP44XX_MMCSD3_OFFSET)
+#define OMAP44XX_MMCHS4_HWBASE   (OMAP44XX_L4_PERIPH_HWBASE + OMAP44XX_MMCSD4_OFFSET)
+#define OMAP44XX_MMCHS4_VBASE    (OMAP44XX_L4_PERIPH_VBASE + OMAP44XX_MMCSD4_OFFSET)
+#define OMAP44XX_MMCHS5_HWBASE   (OMAP44XX_L4_PERIPH_HWBASE + OMAP44XX_MMCSD5_OFFSET)
+#define OMAP44XX_MMCHS5_VBASE    (OMAP44XX_L4_PERIPH_VBASE + OMAP44XX_MMCSD5_OFFSET)
+#define OMAP44XX_MMCHS_SIZE      0x00001000UL
+
+
+
+/*
+ * SCM - System Control Module
+ */
+
+/* Base addresses for the SC modules */
+#define OMAP44XX_SCM_PADCONF_HWBASE (OMAP44XX_L4_CORE_HWBASE + OMAP44XX_SCM_PADCONF_OFFSET)
+#define OMAP44XX_SCM_PADCONF_VBASE  (OMAP44XX_L4_CORE_VBASE + OMAP44XX_SCM_PADCONF_OFFSET)
+#define OMAP44XX_SCM_PADCONF_SIZE   0x00001000UL
+
+
+
+
+#endif /* _OMAP44XX_REG_H_ */
diff -r 7fffa673adcd -r a301a330526b head/sys/arm/ti/omap4/omap4_scm_padconf.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/head/sys/arm/ti/omap4/omap4_scm_padconf.c	Wed Aug 15 11:16:36 2012 +0300
@@ -0,0 +1,405 @@
+/*-
+ * Copyright (c) 2011
+ *	Ben Gray <ben.r.gray at 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.
+ * 3. 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 BEN GRAY ``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 BEN GRAY 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: head/sys/arm/ti/omap4/omap4_scm_padconf.c 239281 2012-08-15 06:31:32Z gonzo $");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/module.h>
+#include <sys/bus.h>
+#include <sys/resource.h>
+#include <sys/rman.h>
+#include <sys/lock.h>
+#include <sys/malloc.h>
+
+#include <machine/bus.h>
+#include <machine/cpu.h>
+#include <machine/cpufunc.h>
+#include <machine/frame.h>
+#include <machine/resource.h>
+#include <machine/intr.h>
+#include <sys/gpio.h>
+
+#include <arm/ti/tivar.h>
+#include <arm/ti/ti_scm.h>
+#include <arm/ti/omap4/omap4var.h>
+#include <arm/ti/omap4/omap4_reg.h>
+
+
+/*
+ *	This file defines the pin mux configuration for the OMAP4xxx series of
+ *	devices.
+ *
+ *	How This is Suppose to Work
+ *	===========================
+ *	- There is a top level ti_scm module (System Control Module) that is
+ *	the interface for all omap drivers, which can use it to change the mux
+ *	settings for individual pins.  (That said, typically the pin mux settings
+ *	are set to defaults by the 'hints' and then not altered by the driver).
+ *
+ *	- For this to work the top level driver needs all the pin info, and hence
+ *	this is where this file comes in.  Here we define all the pin information
+ *	that is supplied to the top level driver.
+ *
+ */
+
+#define CONTROL_PADCONF_WAKEUP_EVENT     (1UL << 15)
+#define CONTROL_PADCONF_WAKEUP_ENABLE    (1UL << 14)
+#define CONTROL_PADCONF_OFF_PULL_UP      (1UL << 13)
+#define CONTROL_PADCONF_OFF_PULL_ENABLE  (1UL << 12)
+#define CONTROL_PADCONF_OFF_OUT_HIGH     (1UL << 11)
+#define CONTROL_PADCONF_OFF_OUT_ENABLE   (1UL << 10)
+#define CONTROL_PADCONF_OFF_ENABLE       (1UL << 9)
+#define CONTROL_PADCONF_INPUT_ENABLE     (1UL << 8)
+#define CONTROL_PADCONF_PULL_UP          (1UL << 4)
+#define CONTROL_PADCONF_PULL_ENABLE      (1UL << 3)
+#define CONTROL_PADCONF_MUXMODE_MASK     (0x7)
+
+#define CONTROL_PADCONF_SATE_MASK        ( CONTROL_PADCONF_WAKEUP_EVENT \
+                                         | CONTROL_PADCONF_WAKEUP_ENABLE \
+                                         | CONTROL_PADCONF_OFF_PULL_UP \
+                                         | CONTROL_PADCONF_OFF_PULL_ENABLE \
+                                         | CONTROL_PADCONF_OFF_OUT_HIGH \
+                                         | CONTROL_PADCONF_OFF_OUT_ENABLE \
+                                         | CONTROL_PADCONF_OFF_ENABLE \
+                                         | CONTROL_PADCONF_INPUT_ENABLE \
+                                         | CONTROL_PADCONF_PULL_UP \
+                                         | CONTROL_PADCONF_PULL_ENABLE )
+
+/* Active pin states */
+#define PADCONF_PIN_OUTPUT              0
+#define PADCONF_PIN_INPUT               CONTROL_PADCONF_INPUT_ENABLE
+#define PADCONF_PIN_INPUT_PULLUP        ( CONTROL_PADCONF_INPUT_ENABLE \
+                                        | CONTROL_PADCONF_PULL_ENABLE \
+                                        | CONTROL_PADCONF_PULL_UP)
+#define PADCONF_PIN_INPUT_PULLDOWN      ( CONTROL_PADCONF_INPUT_ENABLE \
+                                        | CONTROL_PADCONF_PULL_ENABLE )
+
+/* Off mode states */
+#define PADCONF_PIN_OFF_NONE            0
+#define PADCONF_PIN_OFF_OUTPUT_HIGH	    ( CONTROL_PADCONF_OFF_ENABLE \
+                                        | CONTROL_PADCONF_OFF_OUT_ENABLE \
+                                        | CONTROL_PADCONF_OFF_OUT_HIGH)
+#define PADCONF_PIN_OFF_OUTPUT_LOW      ( CONTROL_PADCONF_OFF_ENABLE \
+                                        | CONTROL_PADCONF_OFF_OUT_ENABLE)
+#define PADCONF_PIN_OFF_INPUT_PULLUP    ( CONTROL_PADCONF_OFF_ENABLE \
+                                        | CONTROL_PADCONF_OFF_PULL_ENABLE \
+                                        | CONTROL_PADCONF_OFF_PULL_UP)
+#define PADCONF_PIN_OFF_INPUT_PULLDOWN  ( CONTROL_PADCONF_OFF_ENABLE \
+                                        | CONTROL_PADCONF_OFF_PULL_ENABLE)
+#define PADCONF_PIN_OFF_WAKEUPENABLE	CONTROL_PADCONF_WAKEUP_ENABLE
+
+
+#define _PINDEF(r, b, gp, gm, m0, m1, m2, m3, m4, m5, m6, m7) \
+	{	.reg_off = r, \
+		.gpio_pin = gp, \
+		.gpio_mode = gm, \
+		.ballname = b, \
+		.muxmodes[0] = m0, \
+		.muxmodes[1] = m1, \
+		.muxmodes[2] = m2, \
+		.muxmodes[3] = m3, \
+		.muxmodes[4] = m4, \
+		.muxmodes[5] = m5, \
+		.muxmodes[6] = m6, \
+		.muxmodes[7] = m7, \
+	}
+
+const struct ti_scm_padstate ti_padstate_devmap[] = {
+	{"output",		PADCONF_PIN_OUTPUT},
+	{"input",		PADCONF_PIN_INPUT},
+	{"input_pullup",	PADCONF_PIN_INPUT_PULLUP},
+	{"input_pulldown",	PADCONF_PIN_INPUT_PULLDOWN},
+	{ .state = NULL }
+};
+
+/*
+ * Table 18-10, p. 3470
+ */
+const struct ti_scm_padconf ti_padconf_devmap[] = {
+	_PINDEF(0x0040,  "c12",   0, 0, "gpmc_ad0", "sdmmc2_dat0", NULL, NULL, NULL, NULL, NULL, NULL),
+	_PINDEF(0x0042,  "d12",   0, 0, "gpmc_ad1", "sdmmc2_dat1", NULL, NULL, NULL, NULL, NULL, NULL),
+	_PINDEF(0x0044,  "c13",   0, 0, "gpmc_ad2", "sdmmc2_dat2", NULL, NULL, NULL, NULL, NULL, NULL),
+	_PINDEF(0x0046,  "d13",   0, 0, "gpmc_ad3", "sdmmc2_dat3", NULL, NULL, NULL, NULL, NULL, NULL),
+	_PINDEF(0x0048,  "c15",   0, 0, "gpmc_ad4", "sdmmc2_dat4", "sdmmc2_dir_dat0", NULL, NULL, NULL, NULL, NULL),
+	_PINDEF(0x004a,  "d15",   0, 0, "gpmc_ad5", "sdmmc2_dat5", "sdmmc2_dir_dat1", NULL, NULL, NULL, NULL, NULL),
+	_PINDEF(0x004c,  "a16",   0, 0, "gpmc_ad6", "sdmmc2_dat6", "sdmmc2_dir_cmd", NULL, NULL, NULL, NULL, NULL),
+	_PINDEF(0x004e,  "b16",   0, 0, "gpmc_ad7", "sdmmc2_dat7", "sdmmc2_clk_fdbk", NULL, NULL, NULL, NULL, NULL),
+	_PINDEF(0x0050,  "c16",  32, 3, "gpmc_ad8", "kpd_row0", "c2c_data15", "gpio_32", NULL, "sdmmc1_dat0", NULL, NULL),
+	_PINDEF(0x0052,  "d16",  33, 3, "gpmc_ad9", "kpd_row1", "c2c_data14", "gpio_33", NULL, "sdmmc1_dat1", NULL, NULL),
+	_PINDEF(0x0054,  "c17",  34, 3, "gpmc_ad10", "kpd_row2", "c2c_data13", "gpio_34", NULL, "sdmmc1_dat2", NULL, NULL),
+	_PINDEF(0x0056,  "d17",  35, 3, "gpmc_ad11", "kpd_row3", "c2c_data12", "gpio_35", NULL, "sdmmc1_dat3", NULL, NULL),
+	_PINDEF(0x0058,  "c18",  36, 3, "gpmc_ad12", "kpd_col0", "c2c_data11", "gpio_36", NULL, "sdmmc1_dat4", NULL, NULL),
+	_PINDEF(0x005a,  "d18",  37, 3, "gpmc_ad13", "kpd_col1", "c2c_data10", "gpio_37", NULL, "sdmmc1_dat5", NULL, NULL),
+	_PINDEF(0x005c,  "c19",  38, 3, "gpmc_ad14", "kpd_col2", "c2c_data9", "gpio_38", NULL, "sdmmc1_dat6", NULL, NULL),
+	_PINDEF(0x005e,  "d19",  39, 3, "gpmc_ad15", "kpd_col3", "c2c_data8", "gpio_39", NULL, "sdmmc1_dat7", NULL, NULL),
+	_PINDEF(0x0060,  "b17",  40, 3, "gpmc_a16", "kpd_row4", "c2c_datain0", "gpio_40", "venc_656_data0", NULL, NULL, "safe_mode"),
+	_PINDEF(0x0062,  "a18",  41, 3, "gpmc_a17", "kpd_row5", "c2c_datain1", "gpio_41", "venc_656_data1", NULL, NULL, "safe_mode"),
+	_PINDEF(0x0064,  "b18",  42, 3, "gpmc_a18", "kpd_row6", "c2c_datain2", "gpio_42", "venc_656_data2", NULL, NULL, "safe_mode"),
+	_PINDEF(0x0066,  "a19",  43, 3, "gpmc_a19", "kpd_row7", "c2c_datain3", "gpio_43", "venc_656_data3", NULL, NULL, "safe_mode"),
+	_PINDEF(0x0068,  "b19",  44, 3, "gpmc_a20", "kpd_col4", "c2c_datain4", "gpio_44", "venc_656_data4", NULL, NULL, "safe_mode"),
+	_PINDEF(0x006a,  "b20",  45, 3, "gpmc_a21", "kpd_col5", "c2c_datain5", "gpio_45", "venc_656_data5", NULL, NULL, "safe_mode"),
+	_PINDEF(0x006c,  "a21",  46, 3, "gpmc_a22", "kpd_col6", "c2c_datain6", "gpio_46", "venc_656_data6", NULL, NULL, "safe_mode"),
+	_PINDEF(0x006e,  "b21",  47, 3, "gpmc_a23", "kpd_col7", "c2c_datain7", "gpio_47", "venc_656_data7", NULL, NULL, "safe_mode"),
+	_PINDEF(0x0070,  "c20",  48, 3, "gpmc_a24", "kpd_col8", "c2c_clkout0", "gpio_48", NULL, NULL, NULL, "safe_mode"),
+	_PINDEF(0x0072,  "d20",  49, 3, "gpmc_a25", NULL, "c2c_clkout1", "gpio_49", NULL, NULL, NULL, "safe_mode"),
+	_PINDEF(0x0074,  "b25",  50, 3, "gpmc_ncs0", NULL, NULL, "gpio_50", "sys_ndmareq0", NULL, NULL, NULL),
+	_PINDEF(0x0076,  "c21",  51, 3, "gpmc_ncs1", NULL, "c2c_dataout6", "gpio_51", NULL, NULL, NULL, "safe_mode"),
+	_PINDEF(0x0078,  "d21",  52, 3, "gpmc_ncs2", "kpd_row8", "c2c_dataout7", "gpio_52", NULL, NULL, NULL, "safe_mode"),
+	_PINDEF(0x007a,  "c22",  53, 3, "gpmc_ncs3", "gpmc_dir", "c2c_dataout4", "gpio_53", NULL, NULL, NULL, "safe_mode"),
+	_PINDEF(0x007c,  "c25",  54, 3, "gpmc_nwp", "dsi1_te0", NULL, "gpio_54", "sys_ndmareq1", NULL, NULL, NULL),
+	_PINDEF(0x007e,  "b22",  55, 3, "gpmc_clk", NULL, NULL, "gpio_55", "sys_ndmareq2", "sdmmc1_cmd", NULL, NULL),
+	_PINDEF(0x0080,  "d25",  56, 3, "gpmc_nadv_ale", "dsi1_te1", NULL, "gpio_56", "sys_ndmareq3", "sdmmc1_clk", NULL, NULL),
+	_PINDEF(0x0082,  "b11",   0, 0, "gpmc_noe", "sdmmc2_clk", NULL, NULL, NULL, NULL, NULL, NULL),
+	_PINDEF(0x0084,  "b12",   0, 0, "gpmc_nwe", "sdmmc2_cmd", NULL, NULL, NULL, NULL, NULL, NULL),
+	_PINDEF(0x0086,  "c23",  59, 3, "gpmc_nbe0_cle", "dsi2_te0", NULL, "gpio_59", NULL, NULL, NULL, NULL),
+	_PINDEF(0x0088,  "d22",  60, 3, "gpmc_nbe1", NULL, "c2c_dataout5", "gpio_60", NULL, NULL, NULL, "safe_mode"),
+	_PINDEF(0x008a,  "b26",  61, 3, "gpmc_wait0", "dsi2_te1", NULL, "gpio_61", NULL, NULL, NULL, NULL),
+	_PINDEF(0x008c,  "b23",  62, 3, "gpmc_wait1", NULL, "c2c_dataout2", "gpio_62", NULL, NULL, NULL, "safe_mode"),
+	_PINDEF(0x008e,  "d23", 100, 3, "gpmc_wait2", "usbc1_icusb_txen", "c2c_dataout3", "gpio_100", "sys_ndmareq0", NULL, NULL, "safe_mode"),
+	_PINDEF(0x0090,  "a24", 101, 3, "gpmc_ncs4", "dsi1_te0", "c2c_clkin0", "gpio_101", "sys_ndmareq1", NULL, NULL, "safe_mode"),
+	_PINDEF(0x0092,  "b24", 102, 3, "gpmc_ncs5", "dsi1_te1", "c2c_clkin1", "gpio_102", "sys_ndmareq2", NULL, NULL, "safe_mode"),
+	_PINDEF(0x0094,  "c24", 103, 3, "gpmc_ncs6", "dsi2_te0", "c2c_dataout0", "gpio_103", "sys_ndmareq3", NULL, NULL, "safe_mode"),
+	_PINDEF(0x0096,  "d24", 104, 3, "gpmc_ncs7", "dsi2_te1", "c2c_dataout1", "gpio_104", NULL, NULL, NULL, "safe_mode"),
+	_PINDEF(0x0098,   "b9",  63, 3, "hdmi_hpd", NULL, NULL, "gpio_63", NULL, NULL, NULL, "safe_mode"),
+	_PINDEF(0x009a,  "b10",  64, 3, "hdmi_cec", NULL, NULL, "gpio_64", NULL, NULL, NULL, "safe_mode"),
+	_PINDEF(0x009c,   "a8",  65, 3, "hdmi_ddc_scl", NULL, NULL, "gpio_65", NULL, NULL, NULL, "safe_mode"),
+	_PINDEF(0x009e,   "b8",  66, 3, "hdmi_ddc_sda", NULL, NULL, "gpio_66", NULL, NULL, NULL, "safe_mode"),
+	_PINDEF(0x00a0,  "r26",   0, 0, "csi21_dx0", NULL, NULL, "gpi_67", NULL, NULL, NULL, "safe_mode"),
+	_PINDEF(0x00a2,  "r25",   0, 0, "csi21_dy0", NULL, NULL, "gpi_68", NULL, NULL, NULL, "safe_mode"),
+	_PINDEF(0x00a4,  "t26",   0, 0, "csi21_dx1", NULL, NULL, "gpi_69", NULL, NULL, NULL, "safe_mode"),
+	_PINDEF(0x00a6,  "t25",   0, 0, "csi21_dy1", NULL, NULL, "gpi_70", NULL, NULL, NULL, "safe_mode"),
+	_PINDEF(0x00a8,  "u26",   0, 0, "csi21_dx2", NULL, NULL, "gpi_71", NULL, NULL, NULL, "safe_mode"),
+	_PINDEF(0x00aa,  "u25",   0, 0, "csi21_dy2", NULL, NULL, "gpi_72", NULL, NULL, NULL, "safe_mode"),
+	_PINDEF(0x00ac,  "v26",   0, 0, "csi21_dx3", NULL, NULL, "gpi_73", NULL, NULL, NULL, "safe_mode"),
+	_PINDEF(0x00ae,  "v25",   0, 0, "csi21_dy3", NULL, NULL, "gpi_74", NULL, NULL, NULL, "safe_mode"),
+	_PINDEF(0x00b0,  "w26",   0, 0, "csi21_dx4", NULL, NULL, "gpi_75", NULL, NULL, NULL, "safe_mode"),
+	_PINDEF(0x00b2,  "w25",   0, 0, "csi21_dy4", NULL, NULL, "gpi_76", NULL, NULL, NULL, "safe_mode"),
+	_PINDEF(0x00b4,  "m26",   0, 0, "csi22_dx0", NULL, NULL, "gpi_77", NULL, NULL, NULL, "safe_mode"),
+	_PINDEF(0x00b6,  "m25",   0, 0, "csi22_dy0", NULL, NULL, "gpi_78", NULL, NULL, NULL, "safe_mode"),
+	_PINDEF(0x00b8,  "n26",   0, 0, "csi22_dx1", NULL, NULL, "gpi_79", NULL, NULL, NULL, "safe_mode"),
+	_PINDEF(0x00ba,  "n25",   0, 0, "csi22_dy1", NULL, NULL, "gpi_80", NULL, NULL, NULL, "safe_mode"),
+	_PINDEF(0x00bc,  "t27",  81, 3, "cam_shutter", NULL, NULL, "gpio_81", NULL, NULL, NULL, "safe_mode"),
+	_PINDEF(0x00be,  "u27",  82, 3, "cam_strobe", NULL, NULL, "gpio_82", NULL, NULL, NULL, "safe_mode"),
+	_PINDEF(0x00c0,  "v27",  83, 3, "cam_globalreset", NULL, NULL, "gpio_83", NULL, NULL, NULL, "safe_mode"),
+	_PINDEF(0x00c2, "ae18",  84, 3, "usbb1_ulpitll_clk", "hsi1_cawake", NULL, "gpio_84", "usbb1_ulpiphy_clk", NULL, "hw_dbg20", "safe_mode"),
+	_PINDEF(0x00c4, "ag19",  85, 3, "usbb1_ulpitll_stp", "hsi1_cadata", "mcbsp4_clkr", "gpio_85", "usbb1_ulpiphy_stp", "usbb1_mm_rxdp", "hw_dbg21", "safe_mode"),
+	_PINDEF(0x00c6, "af19",  86, 3, "usbb1_ulpitll_dir", "hsi1_caflag", "mcbsp4_fsr", "gpio_86", "usbb1_ulpiphy_dir", NULL, "hw_dbg22", "safe_mode"),
+	_PINDEF(0x00c8, "ae19",  87, 3, "usbb1_ulpitll_nxt", "hsi1_acready", "mcbsp4_fsx", "gpio_87", "usbb1_ulpiphy_nxt", "usbb1_mm_rxdm", "hw_dbg23", "safe_mode"),
+	_PINDEF(0x00ca, "af18",  88, 3, "usbb1_ulpitll_dat0", "hsi1_acwake", "mcbsp4_clkx", "gpio_88", "usbb1_ulpiphy_dat0", "usbb1_mm_txen", "hw_dbg24", "safe_mode"),
+	_PINDEF(0x00cc, "ag18",  89, 3, "usbb1_ulpitll_dat1", "hsi1_acdata", "mcbsp4_dx", "gpio_89", "usbb1_ulpiphy_dat1", "usbb1_mm_txdat", "hw_dbg25", "safe_mode"),
+	_PINDEF(0x00ce, "ae17",  90, 3, "usbb1_ulpitll_dat2", "hsi1_acflag", "mcbsp4_dr", "gpio_90", "usbb1_ulpiphy_dat2", "usbb1_mm_txse0", "hw_dbg26", "safe_mode"),
+	_PINDEF(0x00d0, "af17",  91, 3, "usbb1_ulpitll_dat3", "hsi1_caready", NULL, "gpio_91", "usbb1_ulpiphy_dat3", "usbb1_mm_rxrcv", "hw_dbg27", "safe_mode"),
+	_PINDEF(0x00d2, "ah17",  92, 3, "usbb1_ulpitll_dat4", "dmtimer8_pwm_evt", "abe_mcbsp3_dr", "gpio_92", "usbb1_ulpiphy_dat4", NULL, "hw_dbg28", "safe_mode"),
+	_PINDEF(0x00d4, "ae16",  93, 3, "usbb1_ulpitll_dat5", "dmtimer9_pwm_evt", "abe_mcbsp3_dx", "gpio_93", "usbb1_ulpiphy_dat5", NULL, "hw_dbg29", "safe_mode"),
+	_PINDEF(0x00d6, "af16",  94, 3, "usbb1_ulpitll_dat6", "dmtimer10_pwm_evt", "abe_mcbsp3_clkx", "gpio_94", "usbb1_ulpiphy_dat6", "abe_dmic_din3", "hw_dbg30", "safe_mode"),
+	_PINDEF(0x00d8, "ag16",  95, 3, "usbb1_ulpitll_dat7", "dmtimer11_pwm_evt", "abe_mcbsp3_fsx", "gpio_95", "usbb1_ulpiphy_dat7", "abe_dmic_clk3", "hw_dbg31", "safe_mode"),
+	_PINDEF(0x00da, "af14",  96, 3, "usbb1_hsic_data", NULL, NULL, "gpio_96", NULL, NULL, NULL, "safe_mode"),
+	_PINDEF(0x00dc, "ae14",  97, 3, "usbb1_hsic_strobe", NULL, NULL, "gpio_97", NULL, NULL, NULL, "safe_mode"),
+	_PINDEF(0x00de,   "h2",  98, 3, "usbc1_icusb_dp", NULL, NULL, "gpio_98", NULL, NULL, NULL, "safe_mode"),
+	_PINDEF(0x00e0,   "h3",  99, 3, "usbc1_icusb_dm", NULL, NULL, "gpio_99", NULL, NULL, NULL, "safe_mode"),
+	_PINDEF(0x00e2,   "d2", 100, 3, "sdmmc1_clk", NULL, "dpm_emu19", "gpio_100", NULL, NULL, NULL, "safe_mode"),
+	_PINDEF(0x00e4,   "e3", 101, 3, "sdmmc1_cmd", NULL, "uart1_rx", "gpio_101", NULL, NULL, NULL, "safe_mode"),
+	_PINDEF(0x00e6,   "e4", 102, 3, "sdmmc1_dat0", NULL, "dpm_emu18", "gpio_102", NULL, NULL, NULL, "safe_mode"),
+	_PINDEF(0x00e8,   "e2", 103, 3, "sdmmc1_dat1", NULL, "dpm_emu17", "gpio_103", NULL, NULL, NULL, "safe_mode"),
+	_PINDEF(0x00ea,   "e1", 104, 3, "sdmmc1_dat2", NULL, "dpm_emu16", "gpio_104", "jtag_tms_tmsc", NULL, NULL, "safe_mode"),
+	_PINDEF(0x00ec,   "f4", 105, 3, "sdmmc1_dat3", NULL, "dpm_emu15", "gpio_105", "jtag_tck", NULL, NULL, "safe_mode"),
+	_PINDEF(0x00ee,   "f3", 106, 3, "sdmmc1_dat4", NULL, NULL, "gpio_106", NULL, NULL, NULL, "safe_mode"),
+	_PINDEF(0x00f0,   "f1", 107, 3, "sdmmc1_dat5", NULL, NULL, "gpio_107", NULL, NULL, NULL, "safe_mode"),
+	_PINDEF(0x00f2,   "g4", 108, 3, "sdmmc1_dat6", NULL, NULL, "gpio_108", NULL, NULL, NULL, "safe_mode"),
+	_PINDEF(0x00f4,   "g3", 109, 3, "sdmmc1_dat7", NULL, NULL, "gpio_109", NULL, NULL, NULL, "safe_mode"),
+	_PINDEF(0x00f6, "ad27", 110, 3, "abe_mcbsp2_clkx", "mcspi2_clk", "abe_mcasp_ahclkx", "gpio_110", "usbb2_mm_rxdm", NULL, NULL, "safe_mode"),
+	_PINDEF(0x00f8, "ad26", 111, 3, "abe_mcbsp2_dr", "mcspi2_somi", "abe_mcasp_axr", "gpio_111", "usbb2_mm_rxdp", NULL, NULL, "safe_mode"),
+	_PINDEF(0x00fa, "ad25", 112, 3, "abe_mcbsp2_dx", "mcspi2_simo", "abe_mcasp_amute", "gpio_112", "usbb2_mm_rxrcv", NULL, NULL, "safe_mode"),
+	_PINDEF(0x00fc, "ac28", 113, 3, "abe_mcbsp2_fsx", "mcspi2_cs0", "abe_mcasp_afsx", "gpio_113", "usbb2_mm_txen", NULL, NULL, "safe_mode"),
+	_PINDEF(0x00fe, "ac26", 114, 3, "abe_mcbsp1_clkx", "abe_slimbus1_clock", NULL, "gpio_114", NULL, NULL, NULL, "safe_mode"),
+	_PINDEF(0x0100, "ac25", 115, 3, "abe_mcbsp1_dr", "abe_slimbus1_data", NULL, "gpio_115", NULL, NULL, NULL, "safe_mode"),
+	_PINDEF(0x0102, "ab25", 116, 3, "abe_mcbsp1_dx", "sdmmc3_dat2", "abe_mcasp_aclkx", "gpio_116", NULL, NULL, NULL, "safe_mode"),
+	_PINDEF(0x0104, "ac27", 117, 3, "abe_mcbsp1_fsx", "sdmmc3_dat3", "abe_mcasp_amutein", "gpio_117", NULL, NULL, NULL, "safe_mode"),
+	_PINDEF(0x0106, "ag25",   0, 0, "abe_pdm_ul_data", "abe_mcbsp3_dr", NULL, NULL, NULL, NULL, NULL, "safe_mode"),
+	_PINDEF(0x0108, "af25",   0, 0, "abe_pdm_dl_data", "abe_mcbsp3_dx", NULL, NULL, NULL, NULL, NULL, "safe_mode"),
+	_PINDEF(0x010a, "ae25",   0, 0, "abe_pdm_frame", "abe_mcbsp3_clkx", NULL, NULL, NULL, NULL, NULL, "safe_mode"),
+	_PINDEF(0x010c, "af26",   0, 0, "abe_pdm_lb_clk", "abe_mcbsp3_fsx", NULL, NULL, NULL, NULL, NULL, "safe_mode"),
+	_PINDEF(0x010e, "ah26", 118, 3, "abe_clks", NULL, NULL, "gpio_118", NULL, NULL, NULL, "safe_mode"),
+	_PINDEF(0x0110, "ae24", 119, 3, "abe_dmic_clk1", NULL, NULL, "gpio_119", "usbb2_mm_txse0", "uart4_cts", NULL, "safe_mode"),
+	_PINDEF(0x0112, "af24", 120, 3, "abe_dmic_din1", NULL, NULL, "gpio_120", "usbb2_mm_txdat", "uart4_rts", NULL, "safe_mode"),
+	_PINDEF(0x0114, "ag24", 121, 3, "abe_dmic_din2", "slimbus2_clock", "abe_mcasp_axr", "gpio_121", NULL, "dmtimer11_pwm_evt", NULL, "safe_mode"),
+	_PINDEF(0x0116, "ah24", 122, 3, "abe_dmic_din3", "slimbus2_data", "abe_dmic_clk2", "gpio_122", NULL, "dmtimer9_pwm_evt", NULL, "safe_mode"),
+	_PINDEF(0x0118, "ab26", 123, 3, "uart2_cts", "sdmmc3_clk", NULL, "gpio_123", NULL, NULL, NULL, "safe_mode"),
+	_PINDEF(0x011a, "ab27", 124, 3, "uart2_rts", "sdmmc3_cmd", NULL, "gpio_124", NULL, NULL, NULL, "safe_mode"),
+	_PINDEF(0x011c, "aa25", 125, 3, "uart2_rx", "sdmmc3_dat0", NULL, "gpio_125", NULL, NULL, NULL, "safe_mode"),
+	_PINDEF(0x011e, "aa26", 126, 3, "uart2_tx", "sdmmc3_dat1", NULL, "gpio_126", NULL, NULL, NULL, "safe_mode"),
+	_PINDEF(0x0120, "aa27", 127, 3, "hdq_sio", "i2c3_sccb", "i2c2_sccb", "gpio_127", NULL, NULL, NULL, "safe_mode"),
+	_PINDEF(0x0122, "ae28",   0, 0, "i2c1_scl", NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+	_PINDEF(0x0124, "ae26",   0, 0, "i2c1_sda", NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+	_PINDEF(0x0126,  "c26", 128, 3, "i2c2_scl", "uart1_rx", NULL, "gpio_128", NULL, NULL, NULL, "safe_mode"),
+	_PINDEF(0x0128,  "d26", 129, 3, "i2c2_sda", "uart1_tx", NULL, "gpio_129", NULL, NULL, NULL, "safe_mode"),
+	_PINDEF(0x012a,  "w27", 130, 3, "i2c3_scl", NULL, NULL, "gpio_130", NULL, NULL, NULL, "safe_mode"),
+	_PINDEF(0x012c,  "y27", 131, 3, "i2c3_sda", NULL, NULL, "gpio_131", NULL, NULL, NULL, "safe_mode"),
+	_PINDEF(0x012e, "ag21", 132, 3, "i2c4_scl", NULL, NULL, "gpio_132", NULL, NULL, NULL, "safe_mode"),
+	_PINDEF(0x0130, "ah22", 133, 3, "i2c4_sda", NULL, NULL, "gpio_133", NULL, NULL, NULL, "safe_mode"),
+	_PINDEF(0x0132, "af22", 134, 3, "mcspi1_clk", NULL, NULL, "gpio_134", NULL, NULL, NULL, "safe_mode"),
+	_PINDEF(0x0134, "ae22", 135, 3, "mcspi1_somi", NULL, NULL, "gpio_135", NULL, NULL, NULL, "safe_mode"),
+	_PINDEF(0x0136, "ag22", 136, 3, "mcspi1_simo", NULL, NULL, "gpio_136", NULL, NULL, NULL, "safe_mode"),
+	_PINDEF(0x0138, "ae23", 137, 3, "mcspi1_cs0", NULL, NULL, "gpio_137", NULL, NULL, NULL, "safe_mode"),
+	_PINDEF(0x013a, "af23", 138, 3, "mcspi1_cs1", "uart1_rx", NULL, "gpio_138", NULL, NULL, NULL, "safe_mode"),
+	_PINDEF(0x013c, "ag23", 139, 3, "mcspi1_cs2", "uart1_cts", "slimbus2_clock", "gpio_139", NULL, NULL, NULL, "safe_mode"),
+	_PINDEF(0x013e, "ah23", 140, 3, "mcspi1_cs3", "uart1_rts", "slimbus2_data", "gpio_140", NULL, NULL, NULL, "safe_mode"),
+	_PINDEF(0x0140,  "f27", 141, 3, "uart3_cts_rctx", "uart1_tx", NULL, "gpio_141", NULL, NULL, NULL, "safe_mode"),
+	_PINDEF(0x0142,  "f28", 142, 3, "uart3_rts_sd", NULL, NULL, "gpio_142", NULL, NULL, NULL, "safe_mode"),
+	_PINDEF(0x0144,  "g27", 143, 3, "uart3_rx_irrx", "dmtimer8_pwm_evt", NULL, "gpio_143", NULL, NULL, NULL, "safe_mode"),
+	_PINDEF(0x0146,  "g28", 144, 3, "uart3_tx_irtx", "dmtimer9_pwm_evt", NULL, "gpio_144", NULL, NULL, NULL, "safe_mode"),
+	_PINDEF(0x0148,  "ae5", 145, 3, "sdmmc5_clk", "mcspi2_clk", "usbc1_icusb_dp", "gpio_145", NULL, "sdmmc2_clk", NULL, "safe_mode"),
+	_PINDEF(0x014a,  "af5", 146, 3, "sdmmc5_cmd", "mcspi2_simo", "usbc1_icusb_dm", "gpio_146", NULL, "sdmmc2_cmd", NULL, "safe_mode"),
+	_PINDEF(0x014c,  "ae4", 147, 3, "sdmmc5_dat0", "mcspi2_somi", "usbc1_icusb_rcv", "gpio_147", NULL, "sdmmc2_dat0", NULL, "safe_mode"),
+	_PINDEF(0x014e,  "af4", 148, 3, "sdmmc5_dat1", NULL, "usbc1_icusb_txen", "gpio_148", NULL, "sdmmc2_dat1", NULL, "safe_mode"),
+	_PINDEF(0x0150,  "ag3", 149, 3, "sdmmc5_dat2", "mcspi2_cs1", NULL, "gpio_149", NULL, "sdmmc2_dat2", NULL, "safe_mode"),
+	_PINDEF(0x0152,  "af3", 150, 3, "sdmmc5_dat3", "mcspi2_cs0", NULL, "gpio_150", NULL, "sdmmc2_dat3", NULL, "safe_mode"),
+	_PINDEF(0x0154, "ae21", 151, 3, "mcspi4_clk", "sdmmc4_clk", "kpd_col6", "gpio_151", NULL, NULL, NULL, "safe_mode"),
+	_PINDEF(0x0156, "af20", 152, 3, "mcspi4_simo", "sdmmc4_cmd", "kpd_col7", "gpio_152", NULL, NULL, NULL, "safe_mode"),
+	_PINDEF(0x0158, "af21", 153, 3, "mcspi4_somi", "sdmmc4_dat0", "kpd_row6", "gpio_153", NULL, NULL, NULL, "safe_mode"),
+	_PINDEF(0x015a, "ae20", 154, 3, "mcspi4_cs0", "sdmmc4_dat3", "kpd_row7", "gpio_154", NULL, NULL, NULL, "safe_mode"),
+	_PINDEF(0x015c, "ag20", 155, 3, "uart4_rx", "sdmmc4_dat2", "kpd_row8", "gpio_155", NULL, NULL, NULL, "safe_mode"),
+	_PINDEF(0x015e, "ah19", 156, 3, "uart4_tx", "sdmmc4_dat1", "kpd_col8", "gpio_156", NULL, NULL, NULL, "safe_mode"),
+	_PINDEF(0x0160, "ag12", 157, 3, "usbb2_ulpitll_clk", "usbb2_ulpiphy_clk", "sdmmc4_cmd", "gpio_157", "hsi2_cawake", NULL, NULL, "safe_mode"),
+	_PINDEF(0x0162, "af12", 158, 3, "usbb2_ulpitll_stp", "usbb2_ulpiphy_stp", "sdmmc4_clk", "gpio_158", "hsi2_cadata", "dispc2_data23", NULL, "safe_mode"),
+	_PINDEF(0x0164, "ae12", 159, 3, "usbb2_ulpitll_dir", "usbb2_ulpiphy_dir", "sdmmc4_dat0", "gpio_159", "hsi2_caflag", "dispc2_data22", NULL, "safe_mode"),
+	_PINDEF(0x0166, "ag13", 160, 3, "usbb2_ulpitll_nxt", "usbb2_ulpiphy_nxt", "sdmmc4_dat1", "gpio_160", "hsi2_acready", "dispc2_data21", NULL, "safe_mode"),
+	_PINDEF(0x0168, "ae11", 161, 3, "usbb2_ulpitll_dat0", "usbb2_ulpiphy_dat0", "sdmmc4_dat2", "gpio_161", "hsi2_acwake", "dispc2_data20", "usbb2_mm_txen", "safe_mode"),
+	_PINDEF(0x016a, "af11", 162, 3, "usbb2_ulpitll_dat1", "usbb2_ulpiphy_dat1", "sdmmc4_dat3", "gpio_162", "hsi2_acdata", "dispc2_data19", "usbb2_mm_txdat", "safe_mode"),
+	_PINDEF(0x016c, "ag11", 163, 3, "usbb2_ulpitll_dat2", "usbb2_ulpiphy_dat2", "sdmmc3_dat2", "gpio_163", "hsi2_acflag", "dispc2_data18", "usbb2_mm_txse0", "safe_mode"),
+	_PINDEF(0x016e, "ah11", 164, 3, "usbb2_ulpitll_dat3", "usbb2_ulpiphy_dat3", "sdmmc3_dat1", "gpio_164", "hsi2_caready", "dispc2_data15", "rfbi_data15", "safe_mode"),
+	_PINDEF(0x0170, "ae10", 165, 3, "usbb2_ulpitll_dat4", "usbb2_ulpiphy_dat4", "sdmmc3_dat0", "gpio_165", "mcspi3_somi", "dispc2_data14", "rfbi_data14", "safe_mode"),
+	_PINDEF(0x0172, "af10", 166, 3, "usbb2_ulpitll_dat5", "usbb2_ulpiphy_dat5", "sdmmc3_dat3", "gpio_166", "mcspi3_cs0", "dispc2_data13", "rfbi_data13", "safe_mode"),
+	_PINDEF(0x0174, "ag10", 167, 3, "usbb2_ulpitll_dat6", "usbb2_ulpiphy_dat6", "sdmmc3_cmd", "gpio_167", "mcspi3_simo", "dispc2_data12", "rfbi_data12", "safe_mode"),
+	_PINDEF(0x0176,  "ae9", 168, 3, "usbb2_ulpitll_dat7", "usbb2_ulpiphy_dat7", "sdmmc3_clk", "gpio_168", "mcspi3_clk", "dispc2_data11", "rfbi_data11", "safe_mode"),
+	_PINDEF(0x0178, "af13", 169, 3, "usbb2_hsic_data", NULL, NULL, "gpio_169", NULL, NULL, NULL, "safe_mode"),
+	_PINDEF(0x017a, "ae13", 170, 3, "usbb2_hsic_strobe", NULL, NULL, "gpio_170", NULL, NULL, NULL, "safe_mode"),
+	_PINDEF(0x017c,  "g26", 171, 3, "kpd_col3", "kpd_col0", NULL, "gpio_171", NULL, NULL, NULL, "safe_mode"),
+	_PINDEF(0x017e,  "g25", 172, 3, "kpd_col4", "kpd_col1", NULL, "gpio_172", NULL, NULL, NULL, "safe_mode"),
+	_PINDEF(0x0180,  "h26", 173, 3, "kpd_col5", "kpd_col2", NULL, "gpio_173", NULL, NULL, NULL, "safe_mode"),
+	_PINDEF(0x0182,  "h25", 174, 3, "kpd_col0", "kpd_col3", NULL, "gpio_174", NULL, NULL, NULL, "safe_mode"),
+	_PINDEF(0x0184,  "j27",   0, 0, "kpd_col1", "kpd_col4", NULL, "gpio_0", NULL, NULL, NULL, "safe_mode"),
+	_PINDEF(0x0186,  "h27",   1, 3, "kpd_col2", "kpd_col5", NULL, "gpio_1", NULL, NULL, NULL, "safe_mode"),
+	_PINDEF(0x0188,  "j26", 175, 3, "kpd_row3", "kpd_row0", NULL, "gpio_175", NULL, NULL, NULL, "safe_mode"),
+	_PINDEF(0x018a,  "j25", 176, 3, "kpd_row4", "kpd_row1", NULL, "gpio_176", NULL, NULL, NULL, "safe_mode"),
+	_PINDEF(0x018c,  "k26", 177, 3, "kpd_row5", "kpd_row2", NULL, "gpio_177", NULL, NULL, NULL, "safe_mode"),
+	_PINDEF(0x018e,  "k25", 178, 3, "kpd_row0", "kpd_row3", NULL, "gpio_178", NULL, NULL, NULL, "safe_mode"),
+	_PINDEF(0x0190,  "l27",   2, 3, "kpd_row1", "kpd_row4", NULL, "gpio_2", NULL, NULL, NULL, "safe_mode"),
+	_PINDEF(0x0192,  "k27",   3, 3, "kpd_row2", "kpd_row5", NULL, "gpio_3", NULL, NULL, NULL, "safe_mode"),
+	_PINDEF(0x0194,   "c3",   0, 0, "usba0_otg_ce", NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+	_PINDEF(0x0196,   "b5",   0, 0, "usba0_otg_dp", "uart3_rx_irrx", "uart2_rx", NULL, NULL, NULL, NULL, "safe_mode"),
+	_PINDEF(0x0198,   "b4",   0, 0, "usba0_otg_dm", "uart3_tx_irtx", "uart2_tx", NULL, NULL, NULL, NULL, "safe_mode"),
+	_PINDEF(0x019a, "aa28", 181, 3, "fref_clk1_out", NULL, NULL, "gpio_181", NULL, NULL, NULL, "safe_mode"),
+	_PINDEF(0x019c,  "y28", 182, 3, "fref_clk2_out", NULL, NULL, "gpio_182", NULL, NULL, NULL, "safe_mode"),
+	_PINDEF(0x019e,  "ae6",   0, 0, "sys_nirq1", NULL, NULL, NULL, NULL, NULL, NULL, "safe_mode"),
+	_PINDEF(0x01a0,  "af6", 183, 3, "sys_nirq2", NULL, NULL, "gpio_183", NULL, NULL, NULL, "safe_mode"),
+	_PINDEF(0x01a2,  "f26", 184, 3, "sys_boot0", NULL, NULL, "gpio_184", NULL, NULL, NULL, "safe_mode"),
+	_PINDEF(0x01a4,  "e27", 185, 3, "sys_boot1", NULL, NULL, "gpio_185", NULL, NULL, NULL, "safe_mode"),
+	_PINDEF(0x01a6,  "e26", 186, 3, "sys_boot2", NULL, NULL, "gpio_186", NULL, NULL, NULL, "safe_mode"),
+	_PINDEF(0x01a8,  "e25", 187, 3, "sys_boot3", NULL, NULL, "gpio_187", NULL, NULL, NULL, "safe_mode"),
+	_PINDEF(0x01aa,  "d28", 188, 3, "sys_boot4", NULL, NULL, "gpio_188", NULL, NULL, NULL, "safe_mode"),
+	_PINDEF(0x01ac,  "d27", 189, 3, "sys_boot5", NULL, NULL, "gpio_189", NULL, NULL, NULL, "safe_mode"),
+	_PINDEF(0x01ae,   "m2",  11, 3, "dpm_emu0", NULL, NULL, "gpio_11", NULL, NULL, "hw_dbg0", "safe_mode"),
+	_PINDEF(0x01b0,   "n2",  12, 3, "dpm_emu1", NULL, NULL, "gpio_12", NULL, NULL, "hw_dbg1", "safe_mode"),
+	_PINDEF(0x01b2,   "p2",  13, 3, "dpm_emu2", "usba0_ulpiphy_clk", NULL, "gpio_13", NULL, "dispc2_fid", "hw_dbg2", "safe_mode"),
+	_PINDEF(0x01b4,   "v1",  14, 3, "dpm_emu3", "usba0_ulpiphy_stp", NULL, "gpio_14", "rfbi_data10", "dispc2_data10", "hw_dbg3", "safe_mode"),
+	_PINDEF(0x01b6,   "v2",  15, 3, "dpm_emu4", "usba0_ulpiphy_dir", NULL, "gpio_15", "rfbi_data9", "dispc2_data9", "hw_dbg4", "safe_mode"),
+	_PINDEF(0x01b8,   "w1",  16, 3, "dpm_emu5", "usba0_ulpiphy_nxt", NULL, "gpio_16", "rfbi_te_vsync0", "dispc2_data16", "hw_dbg5", "safe_mode"),
+	_PINDEF(0x01ba,   "w2",  17, 3, "dpm_emu6", "usba0_ulpiphy_dat0", "uart3_tx_irtx", "gpio_17", "rfbi_hsync0", "dispc2_data17", "hw_dbg6", "safe_mode"),
+	_PINDEF(0x01bc,   "w3",  18, 3, "dpm_emu7", "usba0_ulpiphy_dat1", "uart3_rx_irrx", "gpio_18", "rfbi_cs0", "dispc2_hsync", "hw_dbg7", "safe_mode"),
+	_PINDEF(0x01be,   "w4",  19, 3, "dpm_emu8", "usba0_ulpiphy_dat2", "uart3_rts_sd", "gpio_19", "rfbi_re", "dispc2_pclk", "hw_dbg8", "safe_mode"),
+	_PINDEF(0x01c0,   "y2",  20, 3, "dpm_emu9", "usba0_ulpiphy_dat3", "uart3_cts_rctx", "gpio_20", "rfbi_we", "dispc2_vsync", "hw_dbg9", "safe_mode"),
+	_PINDEF(0x01c2,   "y3",  21, 3, "dpm_emu10", "usba0_ulpiphy_dat4", NULL, "gpio_21", "rfbi_a0", "dispc2_de", "hw_dbg10", "safe_mode"),
+	_PINDEF(0x01c4,   "y4",  22, 3, "dpm_emu11", "usba0_ulpiphy_dat5", NULL, "gpio_22", "rfbi_data8", "dispc2_data8", "hw_dbg11", "safe_mode"),
+	_PINDEF(0x01c6,  "aa1",  23, 3, "dpm_emu12", "usba0_ulpiphy_dat6", NULL, "gpio_23", "rfbi_data7", "dispc2_data7", "hw_dbg12", "safe_mode"),
+	_PINDEF(0x01c8,  "aa2",  24, 3, "dpm_emu13", "usba0_ulpiphy_dat7", NULL, "gpio_24", "rfbi_data6", "dispc2_data6", "hw_dbg13", "safe_mode"),
+	_PINDEF(0x01ca,  "aa3",  25, 3, "dpm_emu14", "sys_drm_msecure", "uart1_rx", "gpio_25", "rfbi_data5", "dispc2_data5", "hw_dbg14", "safe_mode"),
+	_PINDEF(0x01cc,  "aa4",  26, 3, "dpm_emu15", "sys_secure_indicator", NULL, "gpio_26", "rfbi_data4", "dispc2_data4", "hw_dbg15", "safe_mode"),
+	_PINDEF(0x01ce,  "ab2",  27, 3, "dpm_emu16", "dmtimer8_pwm_evt", "dsi1_te0", "gpio_27", "rfbi_data3", "dispc2_data3", "hw_dbg16", "safe_mode"),
+	_PINDEF(0x01d0,  "ab3",  28, 3, "dpm_emu17", "dmtimer9_pwm_evt", "dsi1_te1", "gpio_28", "rfbi_data2", "dispc2_data2", "hw_dbg17", "safe_mode"),
+	_PINDEF(0x01d2,  "ab4", 190, 3, "dpm_emu18", "dmtimer10_pwm_evt", "dsi2_te0", "gpio_190", "rfbi_data1", "dispc2_data1", "hw_dbg18", "safe_mode"),
+	_PINDEF(0x01d4,  "ac4", 191, 3, "dpm_emu19", "dmtimer11_pwm_evt", "dsi2_te1", "gpio_191", "rfbi_data0", "dispc2_data0", "hw_dbg19", "safe_mode"),
+	{  .ballname = NULL  },
+};
+
+const struct ti_scm_device ti_scm_dev = {
+	.padconf_muxmode_mask	= CONTROL_PADCONF_MUXMODE_MASK,
+	.padconf_sate_mask	= CONTROL_PADCONF_SATE_MASK,
+	.padstate		= (struct ti_scm_padstate *) &ti_padstate_devmap,
+	.padconf		= (struct ti_scm_padconf *) &ti_padconf_devmap,
+};
+
+int
+ti_scm_padconf_set_gpioflags(uint32_t gpio, uint32_t flags)
+{
+	unsigned int state = 0;
+	/* First the SCM driver needs to be told to put the pad into GPIO mode */
+	if (flags & GPIO_PIN_OUTPUT)
+		state = PADCONF_PIN_OUTPUT;
+	else if (flags & GPIO_PIN_INPUT) {
+		if (flags & GPIO_PIN_PULLUP)
+			state = PADCONF_PIN_INPUT_PULLUP;
+		else if (flags & GPIO_PIN_PULLDOWN)
+			state = PADCONF_PIN_INPUT_PULLDOWN;
+		else
+			state = PADCONF_PIN_INPUT;
+	}
+	return ti_scm_padconf_set_gpiomode(gpio, state);
+}
+
+void
+ti_scm_padconf_get_gpioflags(uint32_t gpio, uint32_t *flags)
+{
+	unsigned int state;
+	/* Get the current pin state */
+	if (ti_scm_padconf_get_gpiomode(gpio, &state) != 0)
+		*flags = 0;
+	else {
+		switch (state) {
+			case PADCONF_PIN_OUTPUT:
+				*flags = GPIO_PIN_OUTPUT;
+				break;
+			case PADCONF_PIN_INPUT:
+				*flags = GPIO_PIN_INPUT;
+				break;
+			case PADCONF_PIN_INPUT_PULLUP:
+				*flags = GPIO_PIN_INPUT | GPIO_PIN_PULLUP;
+				break;
+			case PADCONF_PIN_INPUT_PULLDOWN:
+				*flags = GPIO_PIN_INPUT | GPIO_PIN_PULLDOWN;
+				break;
+			default:
+				*flags = 0;
+				break;
+		}
+	}
+}
+
diff -r 7fffa673adcd -r a301a330526b head/sys/arm/ti/omap4/omap4_smc.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/head/sys/arm/ti/omap4/omap4_smc.h	Wed Aug 15 11:16:36 2012 +0300
@@ -0,0 +1,52 @@
+/*-
+ * Copyright (c) 2012 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 THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * $FreeBSD: head/sys/arm/ti/omap4/omap4_smc.h 239281 2012-08-15 06:31:32Z gonzo $
+ */
+
+#ifndef OMAP4_SMC_H_
+#define OMAP4_SMC_H_
+/* Define the various function IDs used by the OMAP4 */
+#define L2CACHE_WRITE_DEBUG_REG		0x100
+#define L2CACHE_CLEAN_INV_RANG		0x101
+#define L2CACHE_ENABLE_L2		0x102
+#define READ_AUX_CORE_REGS		0x103
+#define MODIFY_AUX_CORE_0		0x104
+#define WRITE_AUX_CORE_1		0x105
+#define READ_WKG_CTRL_REG		0x106
+#define CLEAR_WKG_CTRL_REG		0x107
+#define SET_POWER_STATUS_REG		0x108
+#define WRITE_AUXCTRL_REG		0x109
+#define LOCKDOWN_TLB			0x10a
+#define SELECT_TLB_ENTRY_FOR_WRITE	0x10b
+#define READ_TLB_VA_ENTRY		0x10c
+#define WRITE_TLB_VA_ENTRY		0x10d
+#define READ_TLB_PA_ENTRY		0x10e
+#define WRITE_TLB_PA_ENTRY		0x10f
+#define READ_TLB_ATTR_ENTRY		0x110
+#define WRITE_TLB_ATTR_ENTRY		0x111
+#define WRITE_LATENCY_CTRL_REG		0x112
+#define WRITE_PREFETCH_CTRL_REG		0x113
+#endif /* OMAP4_SMC_H_ */
diff -r 7fffa673adcd -r a301a330526b head/sys/arm/ti/omap4/omap4var.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/head/sys/arm/ti/omap4/omap4var.h	Wed Aug 15 11:16:36 2012 +0300
@@ -0,0 +1,91 @@
+/*-
+ * Copyright (c) 2010
+ *	Ben Gray <ben.r.gray at 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.
+ * 3. 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 BEN GRAY ``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 BEN GRAY 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: head/sys/arm/ti/omap4/omap4var.h 239281 2012-08-15 06:31:32Z gonzo $
+ */
+
+#ifndef _OMAP4VAR_H_
+#define	_OMAP4VAR_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/rman.h>
+#include <sys/sysctl.h>
+#include <sys/endian.h>
+
+#include <machine/bus.h>
+#include <machine/cpu.h>
+#include <machine/cpufunc.h>
+#include <machine/resource.h>
+#include <machine/intr.h>
+
+
+void omap4_mask_all_intr(void);
+void omap4_post_filter_intr(void *arg);
+
+struct omap4_softc {
+	device_t sc_dev;
+	bus_space_tag_t sc_iotag;
+    
+	/* Handles for the two generic interrupt controller (GIC) register mappings */
+	bus_space_handle_t sc_gic_cpu_ioh;
+	bus_space_handle_t sc_gic_dist_ioh;
+	
+	/* Handle for the PL310 L2 cache controller */
+	bus_space_handle_t sc_pl310_ioh;
+	
+	/* Handle for the global and provate timer register set in the Cortex core */
+	bus_space_handle_t sc_prv_timer_ioh;
+	bus_space_handle_t sc_gbl_timer_ioh;
+	
+	/* SCM access */
+	struct resource *sc_scm_mem;
+	int sc_scm_rid;
+};
+
+struct omap4_intr_conf {
+	int            num;
+	unsigned int   priority;
+	unsigned int   target_cpu;
+};
+
+int omap4_setup_intr_controller(device_t dev,
+    const struct omap4_intr_conf *irqs);
+int omap4_setup_gic_cpu(unsigned int prio_mask);
+
+void omap4_init_timer(device_t dev);
+
+int omap4_setup_l2cache_controller(struct omap4_softc *sc);
+void omap4_smc_call(uint32_t fn, uint32_t arg);
+
+#endif /* _OMAP4VAR_H_ */
diff -r 7fffa673adcd -r a301a330526b head/sys/arm/ti/omap4/pandaboard/files.pandaboard
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/head/sys/arm/ti/omap4/pandaboard/files.pandaboard	Wed Aug 15 11:16:36 2012 +0300
@@ -0,0 +1,3 @@
+# $FreeBSD: head/sys/arm/ti/omap4/pandaboard/files.pandaboard 239281 2012-08-15 06:31:32Z gonzo $
+
+arm/ti/omap4/pandaboard/pandaboard.c		standard
diff -r 7fffa673adcd -r a301a330526b head/sys/arm/ti/omap4/pandaboard/pandaboard.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/head/sys/arm/ti/omap4/pandaboard/pandaboard.c	Wed Aug 15 11:16:36 2012 +0300
@@ -0,0 +1,210 @@
+/*-
+ * Copyright (c) 2011
+ *	Ben Gray <ben.r.gray at 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.
+ * 3. 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 BEN GRAY ``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 BEN GRAY 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: head/sys/arm/ti/omap4/pandaboard/pandaboard.c 239281 2012-08-15 06:31:32Z gonzo $");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/bus.h>
+#include <sys/kernel.h>
+
+#include <vm/vm.h>
+#include <vm/pmap.h>
+
+#include <machine/bus.h>
+#include <machine/pte.h>
+#include <machine/pmap.h>
+#include <machine/vmparam.h>
+#include <machine/fdt.h>
+
+#include <arm/ti/omap4/omap4var.h>
+#include <arm/ti/omap4/omap4_reg.h>
+
+/* Registers in the SCRM that control the AUX clocks */
+#define SCRM_ALTCLKSRC			     (0x110)
+#define SCRM_AUXCLK0                         (0x0310)
+#define SCRM_AUXCLK1                         (0x0314)
+#define SCRM_AUXCLK2                         (0x0318)
+#define SCRM_AUXCLK3                         (0x031C)
+
+/* Some of the GPIO register set */
+#define GPIO1_OE                             (0x0134)
+#define GPIO1_CLEARDATAOUT                   (0x0190)
+#define GPIO1_SETDATAOUT                     (0x0194)
+#define GPIO2_OE                             (0x0134)
+#define GPIO2_CLEARDATAOUT                   (0x0190)
+#define GPIO2_SETDATAOUT                     (0x0194)
+
+/* Some of the PADCONF register set */
+#define CONTROL_WKUP_PAD0_FREF_CLK3_OUT  (0x058)
+#define CONTROL_CORE_PAD1_KPD_COL2       (0x186)
+#define CONTROL_CORE_PAD0_GPMC_WAIT1     (0x08C)
+
+#define REG_WRITE32(r, x)    *((volatile uint32_t*)(r)) = (uint32_t)(x)
+#define REG_READ32(r)        *((volatile uint32_t*)(r))
+
+#define REG_WRITE16(r, x)    *((volatile uint16_t*)(r)) = (uint16_t)(x)
+#define REG_READ16(r)        *((volatile uint16_t*)(r))
+
+/**
+ *	usb_hub_init - initialises and resets the external USB hub
+ *	
+ *	The USB hub needs to be held in reset while the power is being applied
+ *	and the reference clock is enabled at 19.2MHz.  The following is the
+ *	layout of the USB hub taken from the Pandaboard reference manual.
+ *
+ *
+ *	   .-------------.         .--------------.         .----------------.
+ *	   |  OMAP4430   |         |   USB3320C   |         |    LAN9514     |
+ *	   |             |         |              |         | USB Hub / Eth  |
+ *	   |         CLK | <------ | CLKOUT       |         |                |
+ *	   |         STP | ------> | STP          |         |                |
+ *	   |         DIR | <------ | DIR          |         |                |
+ *	   |         NXT | <------ | NXT          |         |                |
+ *	   |        DAT0 | <-----> | DAT0         |         |                |
+ *	   |        DAT1 | <-----> | DAT1      DP | <-----> | DP             |
+ *	   |        DAT2 | <-----> | DAT2      DM | <-----> | DM             |
+ *	   |        DAT3 | <-----> | DAT3         |         |                |
+ *	   |        DAT4 | <-----> | DAT4         |         |                |
+ *	   |        DAT5 | <-----> | DAT5         |  +----> | N_RESET        |
+ *	   |        DAT6 | <-----> | DAT6         |  |      |                |
+ *	   |        DAT7 | <-----> | DAT7         |  |      |                |
+ *	   |             |         |              |  |  +-> | VDD33IO        |
+ *	   |    AUX_CLK3 | ------> | REFCLK       |  |  +-> | VDD33A         |
+ *	   |             |         |              |  |  |   |                |
+ *	   |     GPIO_62 | --+---> | RESET        |  |  |   |                |
+ *	   |             |   |     |              |  |  |   |                |
+ *	   |             |   |     '--------------'  |  |   '----------------'
+ *	   |             |   |     .--------------.  |  |
+ *	   |             |   '---->| VOLT CONVERT |--'  |
+ *	   |             |         '--------------'     |
+ *	   |             |                              |
+ *	   |             |         .--------------.     |
+ *	   |      GPIO_1 | ------> |   TPS73633   |-----'
+ *	   |             |         '--------------'
+ *	   '-------------'
+ *	
+ *
+ *	RETURNS:
+ *	nothing.
+ */
+static void
+usb_hub_init(void)
+{
+	bus_space_handle_t scrm_addr, gpio1_addr, gpio2_addr, scm_addr;
+
+	if (bus_space_map(fdtbus_bs_tag, OMAP44XX_SCRM_HWBASE,
+	    OMAP44XX_SCRM_SIZE, 0, &scrm_addr) != 0)
+		panic("Couldn't map SCRM registers");
+	if (bus_space_map(fdtbus_bs_tag, OMAP44XX_GPIO1_HWBASE, 
+	    OMAP44XX_GPIO1_SIZE, 0, &gpio1_addr) != 0)
+		panic("Couldn't map GPIO1 registers");
+	if (bus_space_map(fdtbus_bs_tag, OMAP44XX_GPIO2_HWBASE,
+	    OMAP44XX_GPIO2_SIZE, 0, &gpio2_addr) != 0)
+		panic("Couldn't map GPIO2 registers");
+	if (bus_space_map(fdtbus_bs_tag, OMAP44XX_SCM_PADCONF_HWBASE,
+	    OMAP44XX_SCM_PADCONF_SIZE, 0, &scm_addr) != 0)
+		panic("Couldn't map SCM Padconf registers");
+
+	
+
+	/* Need to set FREF_CLK3_OUT to 19.2 MHz and pump it out on pin GPIO_WK31.
+	 * We know the SYS_CLK is 38.4Mhz and therefore to get the needed 19.2Mhz,
+	 * just use a 2x divider and ensure the SYS_CLK is used as the source.
+	 */
+	REG_WRITE32(scrm_addr + SCRM_AUXCLK3, (1 << 16) |    /* Divider of 2 */
+	                          (0 << 1) |     /* Use the SYS_CLK as the source */
+	                          (1 << 8));     /* Enable the clock */
+
+	/* Enable the clock out to the pin (GPIO_WK31). 
+	 *   muxmode=fref_clk3_out, pullup/down=disabled, input buffer=disabled,
+	 *   wakeup=disabled.
+	 */
+	REG_WRITE16(scm_addr + CONTROL_WKUP_PAD0_FREF_CLK3_OUT, 0x0000);
+
+
+	/* Disable the power to the USB hub, drive GPIO1 low */
+	REG_WRITE32(gpio1_addr + GPIO1_OE, REG_READ32(gpio1_addr + 
+	    GPIO1_OE) & ~(1UL << 1));
+	REG_WRITE32(gpio1_addr + GPIO1_CLEARDATAOUT, (1UL << 1));
+	REG_WRITE16(scm_addr + CONTROL_CORE_PAD1_KPD_COL2, 0x0003);
+	
+	
+	/* Reset the USB PHY and Hub using GPIO_62 */
+	REG_WRITE32(gpio2_addr + GPIO2_OE, 
+	    REG_READ32(gpio2_addr + GPIO2_OE) & ~(1UL << 30));
+	REG_WRITE32(gpio2_addr + GPIO2_CLEARDATAOUT, (1UL << 30));
+	REG_WRITE16(scm_addr + CONTROL_CORE_PAD0_GPMC_WAIT1, 0x0003);
+	DELAY(10);
+	REG_WRITE32(gpio2_addr + GPIO2_SETDATAOUT, (1UL << 30));
+
+	
+	/* Enable power to the hub (GPIO_1) */
+	REG_WRITE32(gpio1_addr + GPIO1_SETDATAOUT, (1UL << 1));
+	bus_space_unmap(fdtbus_bs_tag, scrm_addr, OMAP44XX_SCRM_SIZE);
+	bus_space_unmap(fdtbus_bs_tag, gpio1_addr, OMAP44XX_GPIO1_SIZE);
+	bus_space_unmap(fdtbus_bs_tag, gpio2_addr, OMAP44XX_GPIO2_SIZE);
+	bus_space_unmap(fdtbus_bs_tag, scm_addr, OMAP44XX_SCM_PADCONF_SIZE);
+}
+
+/**
+ *	board_init - initialises the pandaboard
+ *	@dummy: ignored
+ * 
+ *	This function is called before any of the driver are initialised, which is
+ *	annoying because it means we can't use the SCM, PRCM and GPIO modules which
+ *	would really be useful.
+ *
+ *	So we don't have:
+ *	   - any drivers
+ *	   - no interrupts
+ *
+ *	What we do have:
+ *	   - virt/phys mappings from the devmap (see omap4.c)
+ *	   - 
+ *
+ *
+ *	So we are hamstrung without the useful drivers and we have to go back to
+ *	direct register manupulation. Luckly we don't have to do to much, basically
+ *	just setup the usb hub/ethernet.
+ *
+ */
+static void
+board_init(void *dummy)
+{
+	/* Initialise the USB phy and hub */
+	usb_hub_init();
+	
+	/*
+	 * XXX Board identification e.g. read out from FPGA or similar should
+	 * go here
+	 */
+}
+
+SYSINIT(board_init, SI_SUB_CPU, SI_ORDER_THIRD, board_init, NULL);
diff -r 7fffa673adcd -r a301a330526b head/sys/arm/ti/omap4/pandaboard/std.pandaboard
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/head/sys/arm/ti/omap4/pandaboard/std.pandaboard	Wed Aug 15 11:16:36 2012 +0300
@@ -0,0 +1,4 @@
+# $FreeBSD: head/sys/arm/ti/omap4/pandaboard/std.pandaboard 239281 2012-08-15 06:31:32Z gonzo $
+
+include	"../ti/omap4/std.omap4"
+files	"../ti/omap4/pandaboard/files.pandaboard"
diff -r 7fffa673adcd -r a301a330526b head/sys/arm/ti/omap4/std.omap4
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/head/sys/arm/ti/omap4/std.omap4	Wed Aug 15 11:16:36 2012 +0300
@@ -0,0 +1,21 @@
+# Omap4430 generic configuration
+#$FreeBSD: head/sys/arm/ti/omap4/std.omap4 239281 2012-08-15 06:31:32Z gonzo $
+files		"../ti/omap4/files.omap4"
+include		"../ti/std.ti"
+makeoption	ARM_LITTLE_ENDIAN
+
+# Physical memory starts at 0x80000000.  We assume images are loaded at
+# 0x80200000, e.g. from u-boot with 'fatload mmc 0 0x80200000 kernel.bin'
+#
+#
+options		PHYSADDR=0x80000000
+options		KERNPHYSADDR=0x80200000
+makeoptions	KERNPHYSADDR=0x80200000
+options		KERNVIRTADDR=0xc0200000		# Used in ldscript.arm
+makeoptions	KERNVIRTADDR=0xc0200000
+
+options		STARTUP_PAGETABLE_ADDR=0x80000000
+
+options		SOC_OMAP4
+
+options		ARM_L2_PIPT
diff -r 7fffa673adcd -r a301a330526b head/sys/arm/ti/std.ti
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/head/sys/arm/ti/std.ti	Wed Aug 15 11:16:36 2012 +0300
@@ -0,0 +1,5 @@
+# $FreeBSD: head/sys/arm/ti/std.ti 239281 2012-08-15 06:31:32Z gonzo $
+
+cpu 		CPU_CORTEXA
+
+files		"../ti/files.ti"
diff -r 7fffa673adcd -r a301a330526b head/sys/arm/ti/ti_cpuid.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/head/sys/arm/ti/ti_cpuid.c	Wed Aug 15 11:16:36 2012 +0300
@@ -0,0 +1,285 @@
+/*-
+ * Copyright (c) 2011
+ *	Ben Gray <ben.r.gray at 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: head/sys/arm/ti/ti_cpuid.c 239281 2012-08-15 06:31:32Z gonzo $");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/module.h>
+#include <sys/bus.h>
+#include <sys/resource.h>
+#include <sys/rman.h>
+#include <sys/lock.h>
+#include <sys/mutex.h>
+
+#include <machine/bus.h>
+#include <machine/fdt.h>
+#include <machine/cpu.h>
+#include <machine/cpufunc.h>
+#include <machine/frame.h>
+#include <machine/resource.h>
+#include <machine/intr.h>
+
+#include <arm/ti/tivar.h>
+#include <arm/ti/ti_cpuid.h>
+
+#include <arm/ti/omap4/omap4_reg.h>
+#include <arm/ti/omap3/omap3_reg.h>
+#include <arm/ti/am335x/am335x_reg.h>
+
+#define OMAP4_STD_FUSE_DIE_ID_0    0x2200
+#define OMAP4_ID_CODE              0x2204
+#define OMAP4_STD_FUSE_DIE_ID_1    0x2208
+#define OMAP4_STD_FUSE_DIE_ID_2    0x220C
+#define OMAP4_STD_FUSE_DIE_ID_3    0x2210
+#define OMAP4_STD_FUSE_PROD_ID_0   0x2214
+#define OMAP4_STD_FUSE_PROD_ID_1   0x2218
+
+#define OMAP3_ID_CODE              0xA204
+
+static uint32_t chip_revision = 0xffffffff;
+
+/**
+ *	ti_revision - Returns the revision number of the device
+ *
+ *	Simply returns an identifier for the revision of the chip we are running
+ *	on.
+ *
+ *	RETURNS
+ *	A 32-bit identifier for the current chip
+ */
+uint32_t
+ti_revision(void)
+{
+	return chip_revision;
+}
+
+/**
+ *	omap4_get_revision - determines omap4 revision
+ *
+ *	Reads the registers to determine the revision of the chip we are currently
+ *	running on.  Stores the information in global variables.
+ *
+ *
+ */
+static void
+omap4_get_revision(void)
+{
+	uint32_t id_code;
+	uint32_t revision;
+	uint32_t hawkeye;
+	bus_space_handle_t bsh;
+
+	/* The chip revsion is read from the device identification registers and
+	 * the JTAG (?) tap registers, which are located in address 0x4A00_2200 to
+	 * 0x4A00_2218.  This is part of the L4_CORE memory range and should have
+	 * been mapped in by the machdep.c code.
+	 *
+	 *   STD_FUSE_DIE_ID_0    0x4A00 2200
+	 *   ID_CODE              0x4A00 2204   (this is the only one we need)
+	 *   STD_FUSE_DIE_ID_1    0x4A00 2208
+	 *   STD_FUSE_DIE_ID_2    0x4A00 220C
+	 *   STD_FUSE_DIE_ID_3    0x4A00 2210
+	 *   STD_FUSE_PROD_ID_0   0x4A00 2214
+	 *   STD_FUSE_PROD_ID_1   0x4A00 2218
+	 */
+	// id_code = REG_READ32(OMAP44XX_L4_CORE_VBASE + OMAP4_ID_CODE); 
+	//FIXME Should we map somewhere else?
+	bus_space_map(fdtbus_bs_tag,OMAP44XX_L4_CORE_HWBASE, 0x4000, 0, &bsh);
+	id_code = bus_space_read_4(fdtbus_bs_tag, bsh, OMAP4_ID_CODE);
+	bus_space_unmap(fdtbus_bs_tag, bsh, 0x4000);
+
+	hawkeye = ((id_code >> 12) & 0xffff);
+	revision = ((id_code >> 28) & 0xf);
+
+	/* Apparently according to the linux code there were some ES2.0 samples that
+	 * have the wrong id code and report themselves as ES1.0 silicon.  So used
+	 * the ARM cpuid to get the correct revision.
+	 */
+	if (revision == 0) {
+		id_code = cpufunc_id();
+		revision = (id_code & 0xf) - 1;
+	}
+
+	switch (hawkeye) {
+	case 0xB852:
+		if (revision == 0)
+			chip_revision = OMAP4430_REV_ES1_0;
+		else
+			chip_revision = OMAP4430_REV_ES2_0;
+		break;
+	case 0xB95C:
+		if (revision == 3)
+			chip_revision = OMAP4430_REV_ES2_1;
+		else if (revision == 4)
+			chip_revision = OMAP4430_REV_ES2_2;
+		else
+			chip_revision = OMAP4430_REV_ES2_3;
+		break;
+	default:
+		/* Default to the latest revision if we can't determine type */
+		chip_revision = OMAP4430_REV_ES2_3;
+		break;
+	}
+	printf("Texas Instruments OMAP%04x Processor, Revision ES%u.%u\n",
+		OMAP_REV_DEVICE(chip_revision), OMAP_REV_MAJOR(chip_revision), 
+		OMAP_REV_MINOR(chip_revision));
+}
+
+/**
+ *	omap3_get_revision - determines omap3 revision
+ *
+ *	Reads the registers to determine the revision of the chip we are currently
+ *	running on.  Stores the information in global variables.
+ *
+ *	WARNING: This function currently only really works for OMAP3530 devices.
+ *
+ *
+ *
+ */
+static void
+omap3_get_revision(void)
+{
+	uint32_t id_code;
+	uint32_t revision;
+	uint32_t hawkeye;
+	bus_space_handle_t bsh;
+
+	/* The chip revsion is read from the device identification registers and
+	 * the JTAG (?) tap registers, which are located in address 0x4A00_2200 to
+	 * 0x4A00_2218.  This is part of the L4_CORE memory range and should have
+	 * been mapped in by the machdep.c code.
+	 *
+	 *   CONTROL_IDCODE       0x4830 A204   (this is the only one we need)
+	 *
+	 *
+	 */
+	//id_code = REG_READ32(OMAP35XX_L4_WAKEUP_VBASE + OMAP3_ID_CODE);
+	bus_space_map(fdtbus_bs_tag,OMAP35XX_L4_WAKEUP_HWBASE, 0x10000, 0, &bsh);
+	id_code = bus_space_read_4(fdtbus_bs_tag, bsh, OMAP3_ID_CODE);
+	bus_space_unmap(fdtbus_bs_tag, bsh, 0x4000);
+
+	hawkeye = ((id_code >> 12) & 0xffff);
+	revision = ((id_code >> 28) & 0xf);
+
+	switch (hawkeye) {
+	case 0xB6D6:
+		chip_revision = OMAP3350_REV_ES1_0;
+		break;
+	case 0xB7AE:
+		if (revision == 1)
+			chip_revision = OMAP3530_REV_ES2_0;
+		else if (revision == 2)
+			chip_revision = OMAP3530_REV_ES2_1;
+		else if (revision == 3)
+			chip_revision = OMAP3530_REV_ES3_0;
+		else if (revision == 4)
+			chip_revision = OMAP3530_REV_ES3_1;
+		else if (revision == 7)
+			chip_revision = OMAP3530_REV_ES3_1_2;
+		break;
+	default:
+		/* Default to the latest revision if we can't determine type */
+		chip_revision = OMAP3530_REV_ES3_1_2;
+		break;
+	}
+	printf("Texas Instruments OMAP%04x Processor, Revision ES%u.%u\n",
+		OMAP_REV_DEVICE(chip_revision), OMAP_REV_MAJOR(chip_revision), 
+		OMAP_REV_MINOR(chip_revision));
+}
+
+static void
+am335x_get_revision(void)
+{
+	uint32_t dev_feature;
+	uint8_t cpu_last_char;
+	bus_space_handle_t bsh;
+
+	bus_space_map(fdtbus_bs_tag, AM335X_CONTROL_BASE, AM335X_CONTROL_SIZE, 0, &bsh);
+	chip_revision = bus_space_read_4(fdtbus_bs_tag, bsh, AM335X_CONTROL_DEVICE_ID);
+	dev_feature = bus_space_read_4(fdtbus_bs_tag, bsh, AM335X_CONTROL_DEV_FEATURE);
+	bus_space_unmap(fdtbus_bs_tag, bsh, AM335X_CONTROL_SIZE);
+
+	switch (dev_feature) {
+		case 0x00FF0382:
+			cpu_last_char='2';
+			break;
+		case 0x20FF0382:
+			cpu_last_char='4';
+			break;
+		case 0x00FF0383:
+			cpu_last_char='6';
+			break;
+		case 0x00FE0383:
+			cpu_last_char='7';
+			break;
+		case 0x20FF0383:
+			cpu_last_char='8';
+			break;
+		case 0x20FE0383:
+			cpu_last_char='9';
+			break;
+		default:
+			cpu_last_char='x';
+	}
+
+	printf("Texas Instruments AM335%c Processor, Revision ES1.%u\n",
+		cpu_last_char, AM335X_DEVREV(chip_revision));
+}
+
+/**
+ *	ti_cpu_ident - attempts to identify the chip we are running on
+ *	@dummy: ignored
+ *
+ *	This function is called before any of the driver are initialised, however
+ *	the basic virt to phys maps have been setup in machdep.c so we can still
+ *	access the required registers, we just have to use direct register reads
+ *	and writes rather than going through the bus stuff.
+ *
+ *
+ */
+static void
+ti_cpu_ident(void *dummy)
+{
+	switch(ti_chip()) {
+	case CHIP_OMAP_3:
+		omap3_get_revision();
+		break;
+	case CHIP_OMAP_4:
+		omap4_get_revision();
+		break;
+	case CHIP_AM335X:
+		am335x_get_revision();
+		break;
+	default:
+		panic("Unknown chip type, fixme!\n");
+	}
+}
+
+SYSINIT(ti_cpu_ident, SI_SUB_CPU, SI_ORDER_SECOND, ti_cpu_ident, NULL);
diff -r 7fffa673adcd -r a301a330526b head/sys/arm/ti/ti_cpuid.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/head/sys/arm/ti/ti_cpuid.h	Wed Aug 15 11:16:36 2012 +0300
@@ -0,0 +1,77 @@
+/*-
+ * Copyright (c) 2011
+ *	Ben Gray <ben.r.gray at 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.
+ *
+ * $FreeBSD: head/sys/arm/ti/ti_cpuid.h 239281 2012-08-15 06:31:32Z gonzo $
+ */
+
+#ifndef _TI_CPUID_H_
+#define	_TI_CPUID_H_
+
+#define OMAP_MAKEREV(d, a, b, c) \
+	(uint32_t)(((d) << 16) | (((a) & 0xf) << 8) | (((b) & 0xf) << 4) | ((c) & 0xf))
+
+#define OMAP_REV_DEVICE(x)      (((x) >> 16) & 0xffff)
+#define OMAP_REV_MAJOR(x)       (((x) >> 8) & 0xf)
+#define OMAP_REV_MINOR(x)       (((x) >> 4) & 0xf)
+#define OMAP_REV_MINOR_MINOR(x) (((x) >> 0) & 0xf)
+
+#define	OMAP3350_DEV		0x3530
+#define OMAP3350_REV_ES1_0      OMAP_MAKEREV(OMAP3350_DEV, 1, 0, 0)
+#define OMAP3530_REV_ES2_0      OMAP_MAKEREV(OMAP3350_DEV, 2, 0, 0)
+#define OMAP3530_REV_ES2_1      OMAP_MAKEREV(OMAP3350_DEV, 2, 1, 0)
+#define OMAP3530_REV_ES3_0      OMAP_MAKEREV(OMAP3350_DEV, 3, 0, 0)
+#define OMAP3530_REV_ES3_1      OMAP_MAKEREV(OMAP3350_DEV, 3, 1, 0)
+#define OMAP3530_REV_ES3_1_2    OMAP_MAKEREV(OMAP3350_DEV, 3, 1, 2)
+
+#define	OMAP4430_DEV		0x4430
+#define OMAP4430_REV_ES1_0      OMAP_MAKEREV(OMAP4430_DEV, 1, 0, 0)
+#define OMAP4430_REV_ES2_0      OMAP_MAKEREV(OMAP4430_DEV, 2, 0, 0)
+#define OMAP4430_REV_ES2_1      OMAP_MAKEREV(OMAP4430_DEV, 2, 1, 0)
+#define OMAP4430_REV_ES2_2      OMAP_MAKEREV(OMAP4430_DEV, 2, 2, 0)
+#define OMAP4430_REV_ES2_3      OMAP_MAKEREV(OMAP4430_DEV, 2, 3, 0)
+
+#define AM335X_DEVREV(x)	((x) >> 28)
+
+#define CHIP_OMAP_3	0
+#define CHIP_OMAP_4	1
+#define CHIP_AM335X	2
+
+static __inline int ti_chip(void)
+{
+#if defined(SOC_OMAP4)
+	return CHIP_OMAP_4;
+#elif defined(SOC_OMAP3)
+	return CHIP_OMAP_3;
+#elif defined(SOC_TI_AM335X)
+	return CHIP_AM335X;
+#else
+#  error Chip type not defined, ensure SOC_xxxx is defined
+#endif
+}
+
+uint32_t ti_revision(void);
+
+#endif  /* _TI_CPUID_H_ */
diff -r 7fffa673adcd -r a301a330526b head/sys/arm/ti/ti_edma3.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/head/sys/arm/ti/ti_edma3.c	Wed Aug 15 11:16:36 2012 +0300
@@ -0,0 +1,424 @@
+/*-
+ * Copyright (C) 2010 Texas Instruments Incorporated - http://www.ti.com/
+ * Copyright (c) 2012 Damjan Marion <dmarion at Freebsd.org>
+ * 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.
+ * 3. Neither the name of authors nor the names of its contributors may be
+ *    used to endorse or promote products derived from this software without
+ *    specific prior written permission.
+ *
+ * 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.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: head/sys/arm/ti/ti_edma3.c 239281 2012-08-15 06:31:32Z gonzo $");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/endian.h>
+#include <sys/mbuf.h>
+#include <sys/lock.h>
+#include <sys/mutex.h>
+#include <sys/kernel.h>
+#include <sys/module.h>
+#include <sys/socket.h>
+#include <sys/sysctl.h>
+
+#include <sys/sockio.h>
+#include <sys/bus.h>
+#include <machine/bus.h>
+#include <sys/rman.h>
+#include <machine/resource.h>
+
+#include <dev/fdt/fdt_common.h>
+#include <dev/ofw/ofw_bus.h>
+#include <dev/ofw/ofw_bus_subr.h>
+
+#include <arm/ti/ti_scm.h>
+#include <arm/ti/ti_prcm.h>
+
+#include <arm/ti/ti_edma3.h>
+
+#define TI_EDMA3_NUM_TCS		3
+#define TI_EDMA3_NUM_IRQS		3
+#define TI_EDMA3_NUM_DMA_CHS		64
+#define TI_EDMA3_NUM_QDMA_CHS		8
+
+#define TI_EDMA3CC_PID			0x000
+#define TI_EDMA3CC_DCHMAP(p)		(0x100 + ((p)*4))
+#define TI_EDMA3CC_DMAQNUM(n)		(0x240 + ((n)*4))
+#define TI_EDMA3CC_QDMAQNUM		0x260
+#define TI_EDMA3CC_EMCR			0x308
+#define TI_EDMA3CC_EMCRH		0x30C
+#define TI_EDMA3CC_QEMCR		0x314
+#define TI_EDMA3CC_CCERR		0x318
+#define TI_EDMA3CC_CCERRCLR		0x31C
+#define TI_EDMA3CC_DRAE(p)		(0x340 + ((p)*8))
+#define TI_EDMA3CC_DRAEH(p)		(0x344 + ((p)*8))
+#define TI_EDMA3CC_QRAE(p)		(0x380 + ((p)*4))
+#define TI_EDMA3CC_S_ESR(p)		(0x2010 + ((p)*0x200))
+#define TI_EDMA3CC_S_ESRH(p)		(0x2014 + ((p)*0x200))
+#define TI_EDMA3CC_S_SECR(p)		(0x2040 + ((p)*0x200))
+#define TI_EDMA3CC_S_SECRH(p)		(0x2044 + ((p)*0x200))
+#define TI_EDMA3CC_S_EESR(p)		(0x2030 + ((p)*0x200))
+#define TI_EDMA3CC_S_EESRH(p)		(0x2034 + ((p)*0x200))
+#define TI_EDMA3CC_S_IESR(p)		(0x2060 + ((p)*0x200))
+#define TI_EDMA3CC_S_IESRH(p)		(0x2064 + ((p)*0x200))
+#define TI_EDMA3CC_S_IPR(p)		(0x2068 + ((p)*0x200))
+#define TI_EDMA3CC_S_IPRH(p)		(0x206C + ((p)*0x200))
+#define TI_EDMA3CC_S_QEESR(p)		(0x208C + ((p)*0x200))
+
+#define TI_EDMA3CC_PARAM_OFFSET		0x4000
+#define TI_EDMA3CC_OPT(p)		(TI_EDMA3CC_PARAM_OFFSET + 0x0 + ((p)*0x20))
+
+#define TI_EDMA3CC_DMAQNUM_SET(c,q)	((0x7 & (q)) << (((c) % 8) * 4))
+#define TI_EDMA3CC_DMAQNUM_CLR(c)	(~(0x7 << (((c) % 8) * 4)))
+#define TI_EDMA3CC_QDMAQNUM_SET(c,q)	((0x7 & (q)) << ((c) * 4))
+#define TI_EDMA3CC_QDMAQNUM_CLR(c)	(~(0x7 << ((c) * 4)))
+
+#define TI_EDMA3CC_OPT_TCC_CLR		(~(0x3F000))
+#define TI_EDMA3CC_OPT_TCC_SET(p)	(((0x3F000 >> 12) & (p)) << 12)
+
+struct ti_edma3_softc {
+	device_t		sc_dev;
+	struct resource *	mem_res[TI_EDMA3_NUM_TCS+1];
+	struct resource *	irq_res[TI_EDMA3_NUM_IRQS];
+	void			*ih_cookie[TI_EDMA3_NUM_IRQS];
+};
+
+static struct ti_edma3_softc *ti_edma3_sc = NULL;
+
+static struct resource_spec ti_edma3_mem_spec[] = {
+	{ SYS_RES_MEMORY,   0,  RF_ACTIVE },
+	{ SYS_RES_MEMORY,   1,  RF_ACTIVE },
+	{ SYS_RES_MEMORY,   2,  RF_ACTIVE },
+	{ SYS_RES_MEMORY,   3,  RF_ACTIVE },
+	{ -1,               0,  0 }
+};
+static struct resource_spec ti_edma3_irq_spec[] = {
+	{ SYS_RES_IRQ,      0,  RF_ACTIVE },
+	{ SYS_RES_IRQ,      1,  RF_ACTIVE },
+	{ SYS_RES_IRQ,      2,  RF_ACTIVE },
+	{ -1,               0,  0 }
+};
+
+/* Read/Write macros */
+#define ti_edma3_cc_rd_4(reg)		bus_read_4(ti_edma3_sc->mem_res[0], reg)
+#define ti_edma3_cc_wr_4(reg, val)	bus_write_4(ti_edma3_sc->mem_res[0], reg, val)
+#define ti_edma3_tc_rd_4(c, reg)	bus_read_4(ti_edma3_sc->mem_res[c+1], reg)
+#define ti_edma3_tc_wr_4(c, reg, val)	bus_write_4(ti_edma3_sc->mem_res[c+1], reg, val)
+
+static void ti_edma3_intr_comp(void *arg);
+static void ti_edma3_intr_mperr(void *arg);
+static void ti_edma3_intr_err(void *arg);
+
+static struct {
+	driver_intr_t *handler;
+	char * description;
+} ti_edma3_intrs[TI_EDMA3_NUM_IRQS] = {
+	{ ti_edma3_intr_comp,	"EDMA Completion Interrupt" },
+	{ ti_edma3_intr_mperr,	"EDMA Memory Protection Error Interrupt" },
+	{ ti_edma3_intr_err,	"EDMA Error Interrupt" },
+};
+
+static int
+ti_edma3_probe(device_t dev)
+{
+	if (!ofw_bus_is_compatible(dev, "ti,edma"))
+		return (ENXIO);
+
+	device_set_desc(dev, "TI EDMA Controller");
+	return (0);
+}
+
+static int
+ti_edma3_attach(device_t dev)
+{
+	struct ti_edma3_softc *sc = device_get_softc(dev);
+	uint32_t reg;
+	int err;
+	int i;
+
+	if (ti_edma3_sc)
+		return (ENXIO);
+
+	ti_edma3_sc = sc;
+	sc->sc_dev = dev;
+
+	/* Request the memory resources */
+	err = bus_alloc_resources(dev, ti_edma3_mem_spec, sc->mem_res);
+	if (err) {
+		device_printf(dev, "Error: could not allocate mem resources\n");
+		return (ENXIO);
+	}
+
+	/* Request the IRQ resources */
+	err = bus_alloc_resources(dev, ti_edma3_irq_spec, sc->irq_res);
+	if (err) {
+		device_printf(dev, "Error: could not allocate irq resources\n");
+		return (ENXIO);
+	}
+
+	/* Enable Channel Controller */
+	ti_prcm_clk_enable(EDMA_TPCC_CLK);
+
+	reg = ti_edma3_cc_rd_4(TI_EDMA3CC_PID);
+
+	device_printf(dev, "EDMA revision %08x\n", reg);
+
+
+	/* Attach interrupt handlers */
+	for (i = 0; i < TI_EDMA3_NUM_IRQS; ++i) {
+		err = bus_setup_intr(dev, sc->irq_res[i], INTR_TYPE_MISC |
+		    INTR_MPSAFE, NULL, *ti_edma3_intrs[i].handler,
+		    sc, &sc->ih_cookie[i]);
+		if (err) {
+			device_printf(dev, "could not setup %s\n",
+			    ti_edma3_intrs[i].description);
+			return (err);
+		}
+	}
+
+	return (0);
+}
+
+static device_method_t ti_edma3_methods[] = {
+	DEVMETHOD(device_probe, ti_edma3_probe),
+	DEVMETHOD(device_attach, ti_edma3_attach),
+	{0, 0},
+};
+
+static driver_t ti_edma3_driver = {
+	"ti_edma3",
+	ti_edma3_methods,
+	sizeof(struct ti_edma3_softc),
+};
+static devclass_t ti_edma3_devclass;
+
+DRIVER_MODULE(ti_edma3, simplebus, ti_edma3_driver, ti_edma3_devclass, 0, 0);
+MODULE_DEPEND(ti_edma3, ti_prcm, 1, 1, 1);
+
+static void
+ti_edma3_intr_comp(void *arg)
+{
+	printf("%s: unimplemented\n", __func__);
+}
+
+static void
+ti_edma3_intr_mperr(void *arg)
+{
+	printf("%s: unimplemented\n", __func__);
+}
+
+static void
+ti_edma3_intr_err(void *arg)
+{
+	printf("%s: unimplemented\n", __func__);
+}
+
+void
+ti_edma3_init(unsigned int eqn)
+{
+	uint32_t reg;
+	int i;
+
+	/* on AM335x Event queue 0 is always mapped to Transfer Controller 0,
+	 * event queue 1 to TC2, etc. So we are asking PRCM to power on specific
+	 * TC based on what event queue we need to initialize */
+	ti_prcm_clk_enable(EDMA_TPTC0_CLK + eqn);
+
+	/* Clear Event Missed Regs */
+	ti_edma3_cc_wr_4(TI_EDMA3CC_EMCR, 0xFFFFFFFF);
+	ti_edma3_cc_wr_4(TI_EDMA3CC_EMCRH, 0xFFFFFFFF);
+	ti_edma3_cc_wr_4(TI_EDMA3CC_QEMCR, 0xFFFFFFFF);
+
+	/* Clear Error Reg */
+	ti_edma3_cc_wr_4(TI_EDMA3CC_CCERRCLR, 0xFFFFFFFF);
+
+	/* Enable DMA channels 0-63 */
+	ti_edma3_cc_wr_4(TI_EDMA3CC_DRAE(0), 0xFFFFFFFF);
+	ti_edma3_cc_wr_4(TI_EDMA3CC_DRAEH(0), 0xFFFFFFFF);
+
+	for (i = 0; i < 64; i++) {
+		ti_edma3_cc_wr_4(TI_EDMA3CC_DCHMAP(i), i<<5);
+	}
+
+	/* Initialize the DMA Queue Number Registers */
+	for (i = 0; i < TI_EDMA3_NUM_DMA_CHS; i++) {
+		reg = ti_edma3_cc_rd_4(TI_EDMA3CC_DMAQNUM(i>>3));
+		reg &= TI_EDMA3CC_DMAQNUM_CLR(i);
+		reg |= TI_EDMA3CC_DMAQNUM_SET(i, eqn);
+		ti_edma3_cc_wr_4(TI_EDMA3CC_DMAQNUM(i>>3), reg);
+	}
+
+	/* Enable the QDMA Region access for all channels */
+	ti_edma3_cc_wr_4(TI_EDMA3CC_QRAE(0), (1 << TI_EDMA3_NUM_QDMA_CHS) - 1);
+
+	/*Initialize QDMA Queue Number Registers */
+	for (i = 0; i < TI_EDMA3_NUM_QDMA_CHS; i++) {
+		reg = ti_edma3_cc_rd_4(TI_EDMA3CC_QDMAQNUM);
+		reg &= TI_EDMA3CC_QDMAQNUM_CLR(i);
+		reg |= TI_EDMA3CC_QDMAQNUM_SET(i, eqn);
+		ti_edma3_cc_wr_4(TI_EDMA3CC_QDMAQNUM, reg);
+	}
+}
+
+#ifdef notyet
+int
+ti_edma3_enable_event_intr(unsigned int ch)
+{
+	uint32_t reg;
+
+	if (ch >= TI_EDMA3_NUM_DMA_CHS)
+		return (EINVAL);
+
+	if (ch < 32) {
+		ti_edma3_cc_wr_4(TI_EDMA3CC_S_IESR(0), 1 << ch);
+	} else {
+		ti_edma3_cc_wr_4(TI_EDMA3CC_S_IESRH(0), 1 << (ch - 32));
+	}
+	return 0;
+}
+#endif
+
+int
+ti_edma3_request_dma_ch(unsigned int ch, unsigned int tccn, unsigned int eqn)
+{
+	uint32_t reg;
+
+	if (ch >= TI_EDMA3_NUM_DMA_CHS)
+		return (EINVAL);
+
+	/* Enable the DMA channel in the DRAE/DRAEH registers */
+	if (ch < 32) {
+		reg = ti_edma3_cc_rd_4(TI_EDMA3CC_DRAE(0));
+		reg |= (0x01 << ch);
+		ti_edma3_cc_wr_4(TI_EDMA3CC_DRAE(0), reg);
+	} else {
+		reg = ti_edma3_cc_rd_4(TI_EDMA3CC_DRAEH(0));
+		reg |= (0x01 << (ch - 32));
+		ti_edma3_cc_wr_4(TI_EDMA3CC_DRAEH(0), reg);
+	}
+
+	/* Associate DMA Channel to Event Queue */
+	reg = ti_edma3_cc_rd_4(TI_EDMA3CC_DMAQNUM(ch >> 3));
+	reg &= TI_EDMA3CC_DMAQNUM_CLR(ch);
+	reg |= TI_EDMA3CC_DMAQNUM_SET((ch), eqn);
+	ti_edma3_cc_wr_4(TI_EDMA3CC_DMAQNUM(ch >> 3), reg);
+
+	/* Set TCC in corresponding PaRAM Entry */
+	reg = ti_edma3_cc_rd_4(TI_EDMA3CC_OPT(ch));
+	reg &= TI_EDMA3CC_OPT_TCC_CLR;
+	reg |= TI_EDMA3CC_OPT_TCC_SET(ch);
+	ti_edma3_cc_wr_4(TI_EDMA3CC_OPT(ch), reg);
+
+	return 0;
+}
+
+int
+ti_edma3_request_qdma_ch(unsigned int ch, unsigned int tccn, unsigned int eqn)
+{
+	uint32_t reg;
+
+	if (ch >= TI_EDMA3_NUM_DMA_CHS)
+		return (EINVAL);
+
+	/* Enable the QDMA channel in the QRAE registers */
+	reg = ti_edma3_cc_rd_4(TI_EDMA3CC_QRAE(0));
+	reg |= (0x01 << ch);
+	ti_edma3_cc_wr_4(TI_EDMA3CC_QRAE(0), reg);
+
+	/* Associate QDMA Channel to Event Queue */
+	reg = ti_edma3_cc_rd_4(TI_EDMA3CC_QDMAQNUM);
+	reg |= TI_EDMA3CC_QDMAQNUM_SET(ch, eqn);
+	ti_edma3_cc_wr_4(TI_EDMA3CC_QDMAQNUM, reg);
+
+	/* Set TCC in corresponding PaRAM Entry */
+	reg = ti_edma3_cc_rd_4(TI_EDMA3CC_OPT(ch));
+	reg &= TI_EDMA3CC_OPT_TCC_CLR;
+	reg |= TI_EDMA3CC_OPT_TCC_SET(ch);
+	ti_edma3_cc_wr_4(TI_EDMA3CC_OPT(ch), reg);
+
+	return 0;
+}
+
+int
+ti_edma3_enable_transfer_manual(unsigned int ch)
+{
+	if (ch >= TI_EDMA3_NUM_DMA_CHS)
+		return (EINVAL);
+
+	/* set corresponding bit in ESR/ESRH to set a event */
+	if (ch < 32) {
+		ti_edma3_cc_wr_4(TI_EDMA3CC_S_ESR(0), 1 <<  ch);
+	} else {
+		ti_edma3_cc_wr_4(TI_EDMA3CC_S_ESRH(0), 1 <<  (ch - 32));
+	}
+
+	return 0;
+}
+
+int
+ti_edma3_enable_transfer_qdma(unsigned int ch)
+{
+	if (ch >= TI_EDMA3_NUM_QDMA_CHS)
+		return (EINVAL);
+
+	/* set corresponding bit in QEESR to enable QDMA event */
+	ti_edma3_cc_wr_4(TI_EDMA3CC_S_QEESR(0), (1 << ch));
+
+	return 0;
+}
+
+int
+ti_edma3_enable_transfer_event(unsigned int ch)
+{
+	if (ch >= TI_EDMA3_NUM_DMA_CHS)
+		return (EINVAL);
+
+	/* Clear SECR(H) & EMCR(H) to clean any previous NULL request
+	 * and set corresponding bit in EESR to enable DMA event */
+	if(ch < 32) {
+		ti_edma3_cc_wr_4(TI_EDMA3CC_S_SECR(0), (1 << ch));
+		ti_edma3_cc_wr_4(TI_EDMA3CC_EMCR, (1 << ch));
+		ti_edma3_cc_wr_4(TI_EDMA3CC_S_EESR(0), (1 << ch));
+	} else {
+		ti_edma3_cc_wr_4(TI_EDMA3CC_S_SECRH(0), 1 << (ch - 32));
+		ti_edma3_cc_wr_4(TI_EDMA3CC_EMCRH, 1 << (ch - 32));
+		ti_edma3_cc_wr_4(TI_EDMA3CC_S_EESRH(0), 1 << (ch - 32));
+	}
+
+	return 0;
+}
+
+void
+ti_edma3_param_write(unsigned int ch, struct ti_edma3cc_param_set *prs)
+{
+	bus_write_region_4(ti_edma3_sc->mem_res[0], TI_EDMA3CC_OPT(ch),
+	    (uint32_t *) prs, 8);
+}
+
+void
+ti_edma3_param_read(unsigned int ch, struct ti_edma3cc_param_set *prs)
+{
+	bus_read_region_4(ti_edma3_sc->mem_res[0], TI_EDMA3CC_OPT(ch),
+	    (uint32_t *) prs, 8);
+}
diff -r 7fffa673adcd -r a301a330526b head/sys/arm/ti/ti_edma3.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/head/sys/arm/ti/ti_edma3.h	Wed Aug 15 11:16:36 2012 +0300
@@ -0,0 +1,81 @@
+/*-
+ * Copyright (c) 2012 Damjan Marion <dmarion at Freebsd.org>
+ * 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: head/sys/arm/ti/ti_edma3.h 239281 2012-08-15 06:31:32Z gonzo $
+ */
+
+#ifndef _TI_EDMA3_H_
+#define _TI_EDMA3_H_
+
+/* Direct Mapped EDMA3 Events */
+#define TI_EDMA3_EVENT_SDTXEVT1			2
+#define TI_EDMA3_EVENT_SDRXEVT1			3
+#define TI_EDMA3_EVENT_SDTXEVT0			24
+#define TI_EDMA3_EVENT_SDRXEVT0			25
+
+struct ti_edma3cc_param_set {
+	struct {
+		uint32_t sam:1;		/* Source address mode */
+		uint32_t dam:1;		/* Destination address mode */
+		uint32_t syncdim:1;	/* Transfer synchronization dimension */
+		uint32_t static_set:1;	/* Static Set */
+		uint32_t :4;
+		uint32_t fwid:3;	/* FIFO Width */
+		uint32_t tccmode:1;	/* Transfer complete code mode */
+		uint32_t tcc:6;		/* Transfer complete code */
+		uint32_t :2;
+		uint32_t tcinten:1;	/* Transfer complete interrupt enable */
+		uint32_t itcinten:1;	/* Intermediate xfer completion intr. ena */
+		uint32_t tcchen:1;	/* Transfer complete chaining enable */
+		uint32_t itcchen:1;	/* Intermediate xfer completion chaining ena */
+		uint32_t privid:4;	/* Privilege identification */
+		uint32_t :3;
+		uint32_t priv:1;	/* Privilege level */
+	} opt;
+	uint32_t src;			/* Channel Source Address */
+	uint16_t acnt;			/* Count for 1st Dimension */
+	uint16_t bcnt;			/* Count for 2nd Dimension */
+	uint32_t dst;			/* Channel Destination Address */
+	int16_t srcbidx;		/* Source B Index */
+	int16_t dstbidx;		/* Destination B Index */
+	uint16_t link;			/* Link Address */
+	uint16_t bcntrld;		/* BCNT Reload */
+	int16_t srccidx;		/* Source C Index */
+	int16_t dstcidx;		/* Destination C Index */
+	uint16_t ccnt;			/* Count for 3rd Dimension */
+	uint16_t reserved;		/* Reserved */
+};
+
+void ti_edma3_init(unsigned int eqn);
+int ti_edma3_request_dma_ch(unsigned int ch, unsigned int tccn, unsigned int eqn);
+int ti_edma3_request_qdma_ch(unsigned int ch, unsigned int tccn, unsigned int eqn);
+int ti_edma3_enable_transfer_manual(unsigned int ch);
+int ti_edma3_enable_transfer_qdma(unsigned int ch);
+int ti_edma3_enable_transfer_event(unsigned int ch);
+
+void ti_edma3_param_write(unsigned int ch, struct ti_edma3cc_param_set *prs);
+void ti_edma3_param_read(unsigned int ch, struct ti_edma3cc_param_set *prs);
+
+#endif /* _TI_EDMA3_H_ */
diff -r 7fffa673adcd -r a301a330526b head/sys/arm/ti/ti_gpio.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/head/sys/arm/ti/ti_gpio.c	Wed Aug 15 11:16:36 2012 +0300
@@ -0,0 +1,802 @@
+/*-
+ * Copyright (c) 2011
+ *	Ben Gray <ben.r.gray at 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.
+ */
+
+/**
+ *	Very simple GPIO (general purpose IO) driver module for TI OMAP SoC's.
+ *
+ *	Currently this driver only does the basics, get a value on a pin & set a
+ *	value on a pin. Hopefully over time I'll expand this to be a bit more generic
+ *	and support interrupts and other various bits on the SoC can do ... in the
+ *	meantime this is all you get.
+ *
+ *	Beware the OMA datasheet(s) lists GPIO banks 1-6, whereas I've used 0-5 here
+ *	in the code.
+ *
+ *
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: head/sys/arm/ti/ti_gpio.c 239281 2012-08-15 06:31:32Z gonzo $");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/bus.h>
+
+#include <sys/kernel.h>
+#include <sys/module.h>
+#include <sys/rman.h>
+#include <sys/lock.h>
+#include <sys/mutex.h>
+#include <sys/gpio.h>
+
+#include <machine/bus.h>
+#include <machine/resource.h>
+
+#include <arm/ti/ti_scm.h>
+#include <arm/ti/ti_prcm.h>
+
+#include <dev/fdt/fdt_common.h>
+#include <dev/ofw/openfirm.h>
+#include <dev/ofw/ofw_bus.h>
+#include <dev/ofw/ofw_bus_subr.h>
+
+#include "gpio_if.h"
+
+ /* Register definitions */
+#define TI_GPIO_REVISION		0x0000
+#define TI_GPIO_SYSCONFIG		0x0010
+#if defined(SOC_OMAP3)
+#define TI_GPIO_REVISION		0x0000
+#define TI_GPIO_SYSCONFIG		0x0010
+#define TI_GPIO_SYSSTATUS		0x0014
+#define TI_GPIO_IRQSTATUS1		0x0018
+#define TI_GPIO_IRQENABLE1		0x001C
+#define TI_GPIO_WAKEUPENABLE		0x0020
+#define TI_GPIO_IRQSTATUS2		0x0028
+#define TI_GPIO_IRQENABLE2		0x002C
+#define TI_GPIO_CTRL			0x0030
+#define TI_GPIO_OE			0x0034
+#define TI_GPIO_DATAIN			0x0038
+#define TI_GPIO_DATAOUT			0x003C
+#define TI_GPIO_LEVELDETECT0		0x0040
+#define TI_GPIO_LEVELDETECT1		0x0044
+#define TI_GPIO_RISINGDETECT		0x0048
+#define TI_GPIO_FALLINGDETECT		0x004C
+#define TI_GPIO_DEBOUNCENABLE		0x0050
+#define TI_GPIO_DEBOUNCINGTIME		0x0054
+#define TI_GPIO_CLEARIRQENABLE1		0x0060
+#define TI_GPIO_SETIRQENABLE1		0x0064
+#define TI_GPIO_CLEARIRQENABLE2		0x0070
+#define TI_GPIO_SETIRQENABLE2		0x0074
+#define TI_GPIO_CLEARWKUENA		0x0080
+#define TI_GPIO_SETWKUENA		0x0084
+#define TI_GPIO_CLEARDATAOUT		0x0090
+#define TI_GPIO_SETDATAOUT		0x0094
+#elif defined(SOC_OMAP4) || defined(SOC_TI_AM335X)
+#define TI_GPIO_IRQSTATUS_RAW_0		0x0024
+#define TI_GPIO_IRQSTATUS_RAW_1		0x0028
+#define TI_GPIO_IRQSTATUS_0		0x002C
+#define TI_GPIO_IRQSTATUS_1		0x0030
+#define TI_GPIO_IRQSTATUS_SET_0		0x0034
+#define TI_GPIO_IRQSTATUS_SET_1		0x0038
+#define TI_GPIO_IRQSTATUS_CLR_0		0x003C
+#define TI_GPIO_IRQSTATUS_CLR_1		0x0040
+#define TI_GPIO_IRQWAKEN_0		0x0044
+#define TI_GPIO_IRQWAKEN_1		0x0048
+#define TI_GPIO_SYSSTATUS		0x0114
+#define TI_GPIO_IRQSTATUS1		0x0118
+#define TI_GPIO_IRQENABLE1		0x011C
+#define TI_GPIO_WAKEUPENABLE		0x0120
+#define TI_GPIO_IRQSTATUS2		0x0128
+#define TI_GPIO_IRQENABLE2		0x012C
+#define TI_GPIO_CTRL			0x0130
+#define TI_GPIO_OE			0x0134
+#define TI_GPIO_DATAIN			0x0138
+#define TI_GPIO_DATAOUT			0x013C
+#define TI_GPIO_LEVELDETECT0		0x0140
+#define TI_GPIO_LEVELDETECT1		0x0144
+#define TI_GPIO_RISINGDETECT		0x0148
+#define TI_GPIO_FALLINGDETECT		0x014C
+#define TI_GPIO_DEBOUNCENABLE		0x0150
+#define TI_GPIO_DEBOUNCINGTIME		0x0154
+#define TI_GPIO_CLEARIRQENABLE1		0x0160
+#define TI_GPIO_SETIRQENABLE1		0x0164
+#define TI_GPIO_CLEARIRQENABLE2		0x0170
+#define TI_GPIO_SETIRQENABLE2		0x0174
+#define TI_GPIO_CLEARWKUPENA		0x0180
+#define TI_GPIO_SETWKUENA		0x0184
+#define TI_GPIO_CLEARDATAOUT		0x0190
+#define TI_GPIO_SETDATAOUT		0x0194
+#else
+#error "Unknown SoC"
+#endif
+
+ /*Other SoC Specific definitions*/
+#if defined(SOC_OMAP3)
+#define MAX_GPIO_BANKS			6
+#define FIRST_GPIO_BANK			1
+#define PINS_PER_BANK			32
+#define TI_GPIO_REV			0x00000025
+#elif defined(SOC_OMAP4)
+#define MAX_GPIO_BANKS			6
+#define FIRST_GPIO_BANK			1
+#define PINS_PER_BANK			32
+#define TI_GPIO_REV			0x50600801
+#elif defined(SOC_TI_AM335X)
+#define MAX_GPIO_BANKS			4
+#define FIRST_GPIO_BANK			0
+#define PINS_PER_BANK			32
+#define TI_GPIO_REV			0x50600801
+#endif
+
+/**
+ *	ti_gpio_mem_spec - Resource specification used when allocating resources
+ *	ti_gpio_irq_spec - Resource specification used when allocating resources
+ *
+ *	This driver module can have up to six independent memory regions, each
+ *	region typically controls 32 GPIO pins.
+ */
+static struct resource_spec ti_gpio_mem_spec[] = {
+	{ SYS_RES_MEMORY,   0,  RF_ACTIVE },
+	{ SYS_RES_MEMORY,   1,  RF_ACTIVE | RF_OPTIONAL },
+	{ SYS_RES_MEMORY,   2,  RF_ACTIVE | RF_OPTIONAL },
+	{ SYS_RES_MEMORY,   3,  RF_ACTIVE | RF_OPTIONAL },
+#if !defined(SOC_TI_AM335X)
+	{ SYS_RES_MEMORY,   4,  RF_ACTIVE | RF_OPTIONAL },
+	{ SYS_RES_MEMORY,   5,  RF_ACTIVE | RF_OPTIONAL },
+#endif
+	{ -1,               0,  0 }
+};
+static struct resource_spec ti_gpio_irq_spec[] = {
+	{ SYS_RES_IRQ,      0,  RF_ACTIVE },
+	{ SYS_RES_IRQ,      1,  RF_ACTIVE | RF_OPTIONAL },
+	{ SYS_RES_IRQ,      2,  RF_ACTIVE | RF_OPTIONAL },
+	{ SYS_RES_IRQ,      3,  RF_ACTIVE | RF_OPTIONAL },
+#if !defined(SOC_TI_AM335X)
+	{ SYS_RES_IRQ,      4,  RF_ACTIVE | RF_OPTIONAL },
+	{ SYS_RES_IRQ,      5,  RF_ACTIVE | RF_OPTIONAL },
+#endif
+	{ -1,               0,  0 }
+};
+
+/**
+ *	Structure that stores the driver context.
+ *
+ *	This structure is allocated during driver attach.
+ */
+struct ti_gpio_softc {
+	device_t			sc_dev;
+
+	/* The memory resource(s) for the PRCM register set, when the device is
+	 * created the caller can assign up to 4 memory regions.
+	 */
+	struct resource*    sc_mem_res[MAX_GPIO_BANKS];
+	struct resource*    sc_irq_res[MAX_GPIO_BANKS];
+
+	/* The handle for the register IRQ handlers */
+	void*               sc_irq_hdl[MAX_GPIO_BANKS];
+
+	/* The following describes the H/W revision of each of the GPIO banks */
+	uint32_t            sc_revision[MAX_GPIO_BANKS];
+
+	struct mtx			sc_mtx;
+};
+
+/**
+ *	Macros for driver mutex locking
+ */
+#define TI_GPIO_LOCK(_sc)             mtx_lock(&(_sc)->sc_mtx)
+#define	TI_GPIO_UNLOCK(_sc)           mtx_unlock(&(_sc)->sc_mtx)
+#define TI_GPIO_LOCK_INIT(_sc) \
+	mtx_init(&_sc->sc_mtx, device_get_nameunit(_sc->sc_dev), \
+	         "ti_gpio", MTX_DEF)
+#define TI_GPIO_LOCK_DESTROY(_sc)     mtx_destroy(&_sc->sc_mtx);
+#define TI_GPIO_ASSERT_LOCKED(_sc)    mtx_assert(&_sc->sc_mtx, MA_OWNED);
+#define TI_GPIO_ASSERT_UNLOCKED(_sc)  mtx_assert(&_sc->sc_mtx, MA_NOTOWNED);
+
+/**
+ *	ti_gpio_read_4 - reads a 16-bit value from one of the PADCONFS registers
+ *	@sc: GPIO device context
+ *	@bank: The bank to read from
+ *	@off: The offset of a register from the GPIO register address range
+ *
+ *
+ *	RETURNS:
+ *	32-bit value read from the register.
+ */
+static inline uint32_t
+ti_gpio_read_4(struct ti_gpio_softc *sc, unsigned int bank, bus_size_t off)
+{
+	return (bus_read_4(sc->sc_mem_res[bank], off));
+}
+
+/**
+ *	ti_gpio_write_4 - writes a 32-bit value to one of the PADCONFS registers
+ *	@sc: GPIO device context
+ *	@bank: The bank to write to
+ *	@off: The offset of a register from the GPIO register address range
+ *	@val: The value to write into the register
+ *
+ *	RETURNS:
+ *	nothing
+ */
+static inline void
+ti_gpio_write_4(struct ti_gpio_softc *sc, unsigned int bank, bus_size_t off,
+                 uint32_t val)
+{
+	bus_write_4(sc->sc_mem_res[bank], off, val);
+}
+
+/**
+ *	ti_gpio_pin_max - Returns the maximum number of GPIO pins
+ *	@dev: gpio device handle
+ *	@maxpin: pointer to a value that upon return will contain the maximum number
+ *	         of pins in the device.
+ *
+ *
+ *	LOCKING:
+ *	Internally locks the context
+ *
+ *	RETURNS:
+ *	Returns 0 on success otherwise an error code
+ */
+static int
+ti_gpio_pin_max(device_t dev, int *maxpin)
+{
+	struct ti_gpio_softc *sc = device_get_softc(dev);
+	unsigned int i;
+	unsigned int banks = 0;
+
+	TI_GPIO_LOCK(sc);
+
+	/* Calculate how many valid banks we have and then multiply that by 32 to
+	 * give use the total number of pins.
+	 */
+	for (i = 0; i < MAX_GPIO_BANKS; i++) {
+		if (sc->sc_mem_res[i] != NULL)
+			banks++;
+	}
+
+	*maxpin = (banks * PINS_PER_BANK);
+
+	TI_GPIO_UNLOCK(sc);
+
+	return (0);
+}
+
+/**
+ *	ti_gpio_pin_getcaps - Gets the capabilties of a given pin
+ *	@dev: gpio device handle
+ *	@pin: the number of the pin
+ *	@caps: pointer to a value that upon return will contain the capabilities
+ *
+ *	Currently all pins have the same capability, notably:
+ *	  - GPIO_PIN_INPUT
+ *	  - GPIO_PIN_OUTPUT
+ *	  - GPIO_PIN_PULLUP
+ *	  - GPIO_PIN_PULLDOWN
+ *
+ *	LOCKING:
+ *	Internally locks the context
+ *
+ *	RETURNS:
+ *	Returns 0 on success otherwise an error code
+ */
+static int
+ti_gpio_pin_getcaps(device_t dev, uint32_t pin, uint32_t *caps)
+{
+	struct ti_gpio_softc *sc = device_get_softc(dev);
+	uint32_t bank = (pin / PINS_PER_BANK);
+
+	TI_GPIO_LOCK(sc);
+
+	/* Sanity check the pin number is valid */
+	if ((bank > MAX_GPIO_BANKS) || (sc->sc_mem_res[bank] == NULL)) {
+		TI_GPIO_UNLOCK(sc);
+		return (EINVAL);
+	}
+
+	*caps = (GPIO_PIN_INPUT | GPIO_PIN_OUTPUT |GPIO_PIN_PULLUP |
+	    GPIO_PIN_PULLDOWN);
+
+	TI_GPIO_UNLOCK(sc);
+
+	return (0);
+}
+
+/**
+ *	ti_gpio_pin_getflags - Gets the current flags of a given pin
+ *	@dev: gpio device handle
+ *	@pin: the number of the pin
+ *	@flags: upon return will contain the current flags of the pin
+ *
+ *	Reads the current flags of a given pin, here we actually read the H/W
+ *	registers to determine the flags, rather than storing the value in the
+ *	setflags call.
+ *
+ *	LOCKING:
+ *	Internally locks the context
+ *
+ *	RETURNS:
+ *	Returns 0 on success otherwise an error code
+ */
+static int
+ti_gpio_pin_getflags(device_t dev, uint32_t pin, uint32_t *flags)
+{
+	struct ti_gpio_softc *sc = device_get_softc(dev);
+	uint32_t bank = (pin / PINS_PER_BANK);
+
+	TI_GPIO_LOCK(sc);
+
+	/* Sanity check the pin number is valid */
+	if ((bank > MAX_GPIO_BANKS) || (sc->sc_mem_res[bank] == NULL)) {
+		TI_GPIO_UNLOCK(sc);
+		return (EINVAL);
+	}
+
+	/* Get the current pin state */
+	ti_scm_padconf_get_gpioflags(pin, flags);
+
+	TI_GPIO_UNLOCK(sc);
+
+	return (0);
+}
+
+/**
+ *	ti_gpio_pin_getname - Gets the name of a given pin
+ *	@dev: gpio device handle
+ *	@pin: the number of the pin
+ *	@name: buffer to put the name in
+ *
+ *	The driver simply calls the pins gpio_n, where 'n' is obviously the number
+ *	of the pin.
+ *
+ *	LOCKING:
+ *	Internally locks the context
+ *
+ *	RETURNS:
+ *	Returns 0 on success otherwise an error code
+ */
+static int
+ti_gpio_pin_getname(device_t dev, uint32_t pin, char *name)
+{
+	struct ti_gpio_softc *sc = device_get_softc(dev);
+	uint32_t bank = (pin / PINS_PER_BANK);
+
+	TI_GPIO_LOCK(sc);
+
+	/* Sanity check the pin number is valid */
+	if ((bank > MAX_GPIO_BANKS) || (sc->sc_mem_res[bank] == NULL)) {
+		TI_GPIO_UNLOCK(sc);
+		return (EINVAL);
+	}
+
+	/* Set a very simple name */
+	snprintf(name, GPIOMAXNAME, "gpio_%u", pin);
+	name[GPIOMAXNAME - 1] = '\0';
+
+	TI_GPIO_UNLOCK(sc);
+
+	return (0);
+}
+
+/**
+ *	ti_gpio_pin_setflags - Sets the flags for a given pin
+ *	@dev: gpio device handle
+ *	@pin: the number of the pin
+ *	@flags: the flags to set
+ *
+ *	The flags of the pin correspond to things like input/output mode, pull-ups,
+ *	pull-downs, etc.  This driver doesn't support all flags, only the following:
+ *	  - GPIO_PIN_INPUT
+ *	  - GPIO_PIN_OUTPUT
+ *	  - GPIO_PIN_PULLUP
+ *	  - GPIO_PIN_PULLDOWN
+ *
+ *	LOCKING:
+ *	Internally locks the context
+ *
+ *	RETURNS:
+ *	Returns 0 on success otherwise an error code
+ */
+static int
+ti_gpio_pin_setflags(device_t dev, uint32_t pin, uint32_t flags)
+{
+	struct ti_gpio_softc *sc = device_get_softc(dev);
+	uint32_t bank = (pin / PINS_PER_BANK);
+	uint32_t mask = (1UL << (pin % PINS_PER_BANK));
+	uint32_t reg_val;
+
+	/* Sanity check the flags supplied are valid, i.e. not input and output */
+	if ((flags & (GPIO_PIN_INPUT|GPIO_PIN_OUTPUT)) == 0x0000)
+		return (EINVAL);
+	if ((flags & (GPIO_PIN_INPUT|GPIO_PIN_OUTPUT)) == 
+	    (GPIO_PIN_INPUT|GPIO_PIN_OUTPUT))
+		return (EINVAL);
+	if ((flags & (GPIO_PIN_PULLUP|GPIO_PIN_PULLDOWN)) == 
+	    (GPIO_PIN_PULLUP|GPIO_PIN_PULLDOWN))
+		return (EINVAL);
+
+
+	TI_GPIO_LOCK(sc);
+
+	/* Sanity check the pin number is valid */
+	if ((bank > MAX_GPIO_BANKS) || (sc->sc_mem_res[bank] == NULL)) {
+		TI_GPIO_UNLOCK(sc);
+		return (EINVAL);
+	}
+
+	/* Set the GPIO mode and state */
+	if (ti_scm_padconf_set_gpioflags(pin, flags) != 0) {
+		TI_GPIO_UNLOCK(sc);
+		return (EINVAL);
+	}
+
+	/* If configuring as an output set the "output enable" bit */
+	reg_val = ti_gpio_read_4(sc, bank, TI_GPIO_OE);
+	if (flags & GPIO_PIN_INPUT)
+		reg_val |= mask;
+	else
+		reg_val &= ~mask;
+	ti_gpio_write_4(sc, bank, TI_GPIO_OE, reg_val);
+
+
+	TI_GPIO_UNLOCK(sc);
+	
+	return (0);
+}
+
+/**
+ *	ti_gpio_pin_set - Sets the current level on a GPIO pin
+ *	@dev: gpio device handle
+ *	@pin: the number of the pin
+ *	@value: non-zero value will drive the pin high, otherwise the pin is
+ *	        driven low.
+ *
+ *
+ *	LOCKING:
+ *	Internally locks the context
+ *
+ *	RETURNS:
+ *	Returns 0 on success otherwise a error code
+ */
+static int
+ti_gpio_pin_set(device_t dev, uint32_t pin, unsigned int value)
+{
+	struct ti_gpio_softc *sc = device_get_softc(dev);
+	uint32_t bank = (pin / PINS_PER_BANK);
+	uint32_t mask = (1UL << (pin % PINS_PER_BANK));
+
+	TI_GPIO_LOCK(sc);
+
+	/* Sanity check the pin number is valid */
+	if ((bank > MAX_GPIO_BANKS) || (sc->sc_mem_res[bank] == NULL)) {
+		TI_GPIO_UNLOCK(sc);
+		return (EINVAL);
+	}
+
+	ti_gpio_write_4(sc, bank, (value == GPIO_PIN_LOW) ? TI_GPIO_CLEARDATAOUT
+	    : TI_GPIO_SETDATAOUT, mask);
+
+	TI_GPIO_UNLOCK(sc);
+
+	return (0);
+}
+
+/**
+ *	ti_gpio_pin_get - Gets the current level on a GPIO pin
+ *	@dev: gpio device handle
+ *	@pin: the number of the pin
+ *	@value: pointer to a value that upond return will contain the pin value
+ *
+ *	The pin must be configured as an input pin beforehand, otherwise this
+ *	function will fail.
+ *
+ *	LOCKING:
+ *	Internally locks the context
+ *
+ *	RETURNS:
+ *	Returns 0 on success otherwise a error code
+ */
+static int
+ti_gpio_pin_get(device_t dev, uint32_t pin, unsigned int *value)
+{
+	struct ti_gpio_softc *sc = device_get_softc(dev);
+	uint32_t bank = (pin / PINS_PER_BANK);
+	uint32_t mask = (1UL << (pin % PINS_PER_BANK));
+	uint32_t val = 0;
+
+	TI_GPIO_LOCK(sc);
+
+	/* Sanity check the pin number is valid */
+	if ((bank > MAX_GPIO_BANKS) || (sc->sc_mem_res[bank] == NULL)) {
+		TI_GPIO_UNLOCK(sc);
+		return (EINVAL);
+	}
+
+	/* Sanity check the pin is not configured as an output */
+	val = ti_gpio_read_4(sc, bank, TI_GPIO_OE);
+
+	if ((val & mask) == mask) {
+		TI_GPIO_UNLOCK(sc);
+		return (EINVAL);
+	}
+
+	/* Read the value on the pin */
+	*value = (ti_gpio_read_4(sc, bank, TI_GPIO_DATAIN) & mask) ? 1 : 0;
+
+	TI_GPIO_UNLOCK(sc);
+
+	return (0);
+}
+
+/**
+ *	ti_gpio_pin_toggle - Toggles a given GPIO pin
+ *	@dev: gpio device handle
+ *	@pin: the number of the pin
+ *
+ *
+ *	LOCKING:
+ *	Internally locks the context
+ *
+ *	RETURNS:
+ *	Returns 0 on success otherwise a error code
+ */
+static int
+ti_gpio_pin_toggle(device_t dev, uint32_t pin)
+{
+	struct ti_gpio_softc *sc = device_get_softc(dev);
+	uint32_t bank = (pin / PINS_PER_BANK);
+	uint32_t mask = (1UL << (pin % PINS_PER_BANK));
+	uint32_t val;
+
+	TI_GPIO_LOCK(sc);
+
+	/* Sanity check the pin number is valid */
+	if ((bank > MAX_GPIO_BANKS) || (sc->sc_mem_res[bank] == NULL)) {
+		TI_GPIO_UNLOCK(sc);
+		return (EINVAL);
+	}
+
+	/* Toggle the pin */
+	val = ti_gpio_read_4(sc, bank, TI_GPIO_DATAOUT);
+	if (val & mask)
+		ti_gpio_write_4(sc, bank, TI_GPIO_CLEARDATAOUT, mask);
+	else
+		ti_gpio_write_4(sc, bank, TI_GPIO_SETDATAOUT, mask);
+
+	TI_GPIO_UNLOCK(sc);
+
+	return (0);
+}
+
+/**
+ *	ti_gpio_intr - ISR for all GPIO modules
+ *	@arg: the soft context pointer
+ *
+ *	Unsused
+ *
+ *	LOCKING:
+ *	Internally locks the context
+ *
+ */
+static void
+ti_gpio_intr(void *arg)
+{
+	struct ti_gpio_softc *sc = arg;
+
+	TI_GPIO_LOCK(sc);
+	/* TODO: something useful */
+	TI_GPIO_UNLOCK(sc);
+}
+
+/**
+ *	ti_gpio_probe - probe function for the driver
+ *	@dev: gpio device handle
+ *
+ *	Simply sets the name of the driver
+ *
+ *	LOCKING:
+ *	None
+ *
+ *	RETURNS:
+ *	Always returns 0
+ */
+static int
+ti_gpio_probe(device_t dev)
+{
+	if (!ofw_bus_is_compatible(dev, "ti,gpio"))
+		return (ENXIO);
+
+	device_set_desc(dev, "TI General Purpose I/O (GPIO)");
+	return (0);
+}
+
+/**
+ *	ti_gpio_attach - attach function for the driver
+ *	@dev: gpio device handle
+ *
+ *	Allocates and sets up the driver context for all GPIO banks.  This function
+ *	expects the memory ranges and IRQs to already be allocated to the driver.
+ *
+ *	LOCKING:
+ *	None
+ *
+ *	RETURNS:
+ *	Always returns 0
+ */
+static int
+ti_gpio_attach(device_t dev)
+{
+	struct ti_gpio_softc *sc = device_get_softc(dev);
+	unsigned int i;
+	int err = 0;
+
+	sc->sc_dev = dev;
+
+	TI_GPIO_LOCK_INIT(sc);
+
+
+	/* There are up to 6 different GPIO register sets located in different
+	 * memory areas on the chip.  The memory range should have been set for
+	 * the driver when it was added as a child.
+	 */
+	err = bus_alloc_resources(dev, ti_gpio_mem_spec, sc->sc_mem_res);
+	if (err) {
+		device_printf(dev, "Error: could not allocate mem resources\n");
+		return (ENXIO);
+	}
+
+	/* Request the IRQ resources */
+	err = bus_alloc_resources(dev, ti_gpio_irq_spec, sc->sc_irq_res);
+	if (err) {
+		device_printf(dev, "Error: could not allocate irq resources\n");
+		return (ENXIO);
+	}
+
+	/* Setup the IRQ resources */
+	for (i = 0;  i < MAX_GPIO_BANKS; i++) {
+		if (sc->sc_irq_res[i] == NULL)
+			break;
+
+		/* Register an interrupt handler for each of the IRQ resources */
+		if ((bus_setup_intr(dev, sc->sc_irq_res[i], INTR_TYPE_MISC | INTR_MPSAFE, 
+		                    NULL, ti_gpio_intr, sc, &(sc->sc_irq_hdl[i])))) {
+			device_printf(dev, "WARNING: unable to register interrupt handler\n");
+			return (ENXIO);
+		}
+	}
+
+	/* Store the device handle back in the sc */
+	sc->sc_dev = dev;
+
+	/* We need to go through each block and ensure the clocks are running and
+	 * the module is enabled.  It might be better to do this only when the
+	 * pins are configured which would result in less power used if the GPIO
+	 * pins weren't used ... 
+	 */
+	for (i = 0;  i < MAX_GPIO_BANKS; i++) {
+		if (sc->sc_mem_res[i] != NULL) {
+
+			/* Enable the interface and functional clocks for the module */
+			ti_prcm_clk_enable(GPIO0_CLK + FIRST_GPIO_BANK + i);
+
+			/* Read the revision number of the module. TI don't publish the
+			 * actual revision numbers, so instead the values have been
+			 * determined by experimentation.
+			 */
+			sc->sc_revision[i] = ti_gpio_read_4(sc, i, TI_GPIO_REVISION);
+
+			/* Check the revision */
+			if (sc->sc_revision[i] != TI_GPIO_REV) {
+				device_printf(dev, "Warning: could not determine the revision"
+				              "of %u GPIO module (revision:0x%08x)\n",
+				              i, sc->sc_revision[i]);
+				continue;
+			}
+
+			/* Disable interrupts for all pins */
+			ti_gpio_write_4(sc, i, TI_GPIO_CLEARIRQENABLE1, 0xffffffff);
+			ti_gpio_write_4(sc, i, TI_GPIO_CLEARIRQENABLE2, 0xffffffff);
+		}
+	}
+
+	/* Finish of the probe call */
+	device_add_child(dev, "gpioc", device_get_unit(dev));
+	device_add_child(dev, "gpiobus", device_get_unit(dev));
+	return (bus_generic_attach(dev));
+}
+
+/**
+ *	ti_gpio_detach - detach function for the driver
+ *	@dev: scm device handle
+ *
+ *	Allocates and sets up the driver context, this simply entails creating a
+ *	bus mappings for the SCM register set.
+ *
+ *	LOCKING:
+ *	None
+ *
+ *	RETURNS:
+ *	Always returns 0
+ */
+static int
+ti_gpio_detach(device_t dev)
+{
+	struct ti_gpio_softc *sc = device_get_softc(dev);
+	unsigned int i;
+
+	KASSERT(mtx_initialized(&sc->sc_mtx), ("gpio mutex not initialized"));
+
+	/* Disable all interrupts */
+	for (i = 0;  i < MAX_GPIO_BANKS; i++) {
+		if (sc->sc_mem_res[i] != NULL) {
+			ti_gpio_write_4(sc, i, TI_GPIO_CLEARIRQENABLE1, 0xffffffff);
+			ti_gpio_write_4(sc, i, TI_GPIO_CLEARIRQENABLE2, 0xffffffff);
+		}
+	}
+
+	bus_generic_detach(dev);
+
+	/* Release the memory and IRQ resources */
+	for (i = 0;  i < MAX_GPIO_BANKS; i++) {
+		if (sc->sc_mem_res[i] != NULL)
+			bus_release_resource(dev, SYS_RES_MEMORY, i, sc->sc_mem_res[i]);
+		if (sc->sc_irq_res[i] != NULL)
+			bus_release_resource(dev, SYS_RES_IRQ, i, sc->sc_irq_res[i]);
+	}
+
+	TI_GPIO_LOCK_DESTROY(sc);
+
+	return(0);
+}
+
+static device_method_t ti_gpio_methods[] = {
+	DEVMETHOD(device_probe, ti_gpio_probe),
+	DEVMETHOD(device_attach, ti_gpio_attach),
+	DEVMETHOD(device_detach, ti_gpio_detach),
+
+	/* GPIO protocol */
+	DEVMETHOD(gpio_pin_max, ti_gpio_pin_max),
+	DEVMETHOD(gpio_pin_getname, ti_gpio_pin_getname),
+	DEVMETHOD(gpio_pin_getflags, ti_gpio_pin_getflags),
+	DEVMETHOD(gpio_pin_getcaps, ti_gpio_pin_getcaps),
+	DEVMETHOD(gpio_pin_setflags, ti_gpio_pin_setflags),
+	DEVMETHOD(gpio_pin_get, ti_gpio_pin_get),
+	DEVMETHOD(gpio_pin_set, ti_gpio_pin_set),
+	DEVMETHOD(gpio_pin_toggle, ti_gpio_pin_toggle),
+	{0, 0},
+};
+
+static driver_t ti_gpio_driver = {
+	"gpio",
+	ti_gpio_methods,
+	sizeof(struct ti_gpio_softc),
+};
+static devclass_t ti_gpio_devclass;
+
+DRIVER_MODULE(ti_gpio, simplebus, ti_gpio_driver, ti_gpio_devclass, 0, 0);
diff -r 7fffa673adcd -r a301a330526b head/sys/arm/ti/ti_i2c.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/head/sys/arm/ti/ti_i2c.c	Wed Aug 15 11:16:36 2012 +0300
@@ -0,0 +1,1179 @@
+/*-
+ * Copyright (c) 2011
+ *	Ben Gray <ben.r.gray at 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.
+ */
+
+/**
+ * Driver for the I2C module on the TI SoC.
+ *
+ * This driver is heavily based on the TWI driver for the AT91 (at91_twi.c).
+ *
+ * CAUTION: The I2Ci registers are limited to 16 bit and 8 bit data accesses,
+ * 32 bit data access is not allowed and can corrupt register content.
+ *
+ * This driver currently doesn't use DMA for the transfer, although I hope to
+ * incorporate that sometime in the future.  The idea being that for transaction
+ * larger than a certain size the DMA engine is used, for anything less the
+ * normal interrupt/fifo driven option is used.
+ *
+ *
+ * WARNING: This driver uses mtx_sleep and interrupts to perform transactions,
+ * which means you can't do a transaction during startup before the interrupts
+ * have been enabled.  Hint - the freebsd function config_intrhook_establish().
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: head/sys/arm/ti/ti_i2c.c 239281 2012-08-15 06:31:32Z gonzo $");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/bus.h>
+#include <sys/conf.h>
+#include <sys/kernel.h>
+#include <sys/lock.h>
+#include <sys/mbuf.h>
+#include <sys/malloc.h>
+#include <sys/module.h>
+#include <sys/mutex.h>
+#include <sys/rman.h>
+#include <machine/bus.h>
+
+#include <dev/fdt/fdt_common.h>
+#include <dev/ofw/openfirm.h>
+#include <dev/ofw/ofw_bus.h>
+#include <dev/ofw/ofw_bus_subr.h>
+
+#include <arm/ti/ti_prcm.h>
+#include <arm/ti/ti_i2c.h>
+
+#include <dev/iicbus/iiconf.h>
+#include <dev/iicbus/iicbus.h>
+
+#include "iicbus_if.h"
+
+/**
+ *	I2C device driver context, a pointer to this is stored in the device
+ *	driver structure.
+ */
+struct ti_i2c_softc
+{
+	device_t		sc_dev;
+	uint32_t		device_id;
+	struct resource*	sc_irq_res;
+	struct resource*	sc_mem_res;
+	device_t		sc_iicbus;
+
+	void*			sc_irq_h;
+
+	struct mtx		sc_mtx;
+
+	volatile uint16_t	sc_stat_flags;	/* contains the status flags last IRQ */
+
+	uint16_t		sc_i2c_addr;
+	uint16_t		sc_rev;
+};
+
+struct ti_i2c_clock_config
+{
+	int speed;
+	int bitrate;
+	uint8_t psc;		/* Fast/Standard mode prescale divider */
+	uint8_t scll;		/* Fast/Standard mode SCL low time */
+	uint8_t sclh;		/* Fast/Standard mode SCL high time */
+	uint8_t hsscll;		/* High Speed mode SCL low time */
+	uint8_t hssclh;		/* High Speed mode SCL high time */
+};
+
+static struct ti_i2c_clock_config ti_i2c_clock_configs[] = {
+
+#if defined(SOC_OMAP4)
+	{ IIC_SLOW,      100000, 23,  13,  15, 0,  0},
+	{ IIC_FAST,      400000,  9,   5,   7, 0,  0},
+	{ IIC_FASTEST,	3310000,  1, 113, 115, 7, 10},
+#elif defined(SOC_TI_AM335X)
+	{ IIC_SLOW,      100000,  3,  53,  55, 0,  0},
+	{ IIC_FAST,      400000,  3,   8,  10, 0,  0},
+	{ IIC_FASTEST,   400000,  3,   8,  10, 0,  0}, /* This might be higher */
+#else
+#error "TI I2C driver is not supported on this SoC"
+#endif
+	{ -1, 0 }
+};
+
+
+#define TI_I2C_REV1  0x003C      /* OMAP3 */
+#define TI_I2C_REV2  0x000A      /* OMAP4 */
+
+/**
+ *	Locking macros used throughout the driver
+ */
+#define TI_I2C_LOCK(_sc)             mtx_lock(&(_sc)->sc_mtx)
+#define	TI_I2C_UNLOCK(_sc)           mtx_unlock(&(_sc)->sc_mtx)
+#define TI_I2C_LOCK_INIT(_sc) \
+	mtx_init(&_sc->sc_mtx, device_get_nameunit(_sc->sc_dev), \
+	         "ti_i2c", MTX_DEF)
+#define TI_I2C_LOCK_DESTROY(_sc)      mtx_destroy(&_sc->sc_mtx);
+#define TI_I2C_ASSERT_LOCKED(_sc)     mtx_assert(&_sc->sc_mtx, MA_OWNED);
+#define TI_I2C_ASSERT_UNLOCKED(_sc)   mtx_assert(&_sc->sc_mtx, MA_NOTOWNED);
+
+#ifdef DEBUG
+#define ti_i2c_dbg(_sc, fmt, args...) \
+    device_printf((_sc)->sc_dev, fmt, ##args)
+#else
+#define ti_i2c_dbg(_sc, fmt, args...)
+#endif
+
+static devclass_t ti_i2c_devclass;
+
+/* bus entry points */
+
+static int ti_i2c_probe(device_t dev);
+static int ti_i2c_attach(device_t dev);
+static int ti_i2c_detach(device_t dev);
+static void ti_i2c_intr(void *);
+
+/* OFW routine */
+static phandle_t ti_i2c_get_node(device_t bus, device_t dev);
+
+/* helper routines */
+static int ti_i2c_activate(device_t dev);
+static void ti_i2c_deactivate(device_t dev);
+
+/**
+ *	ti_i2c_read_2 - reads a 16-bit value from one of the I2C registers
+ *	@sc: I2C device context
+ *	@off: the byte offset within the register bank to read from.
+ *
+ *
+ *	LOCKING:
+ *	No locking required
+ *
+ *	RETURNS:
+ *	16-bit value read from the register.
+ */
+static inline uint16_t
+ti_i2c_read_2(struct ti_i2c_softc *sc, bus_size_t off)
+{
+	return bus_read_2(sc->sc_mem_res, off);
+}
+
+/**
+ *	ti_i2c_write_2 - writes a 16-bit value to one of the I2C registers
+ *	@sc: I2C device context
+ *	@off: the byte offset within the register bank to read from.
+ *	@val: the value to write into the register
+ *
+ *	LOCKING:
+ *	No locking required
+ *
+ *	RETURNS:
+ *	16-bit value read from the register.
+ */
+static inline void
+ti_i2c_write_2(struct ti_i2c_softc *sc, bus_size_t off, uint16_t val)
+{
+	bus_write_2(sc->sc_mem_res, off, val);
+}
+
+/**
+ *	ti_i2c_read_reg - reads a 16-bit value from one of the I2C registers
+ *	    take into account revision-dependent register offset
+ *	@sc: I2C device context
+ *	@off: the byte offset within the register bank to read from.
+ *
+ *
+ *	LOCKING:
+ *	No locking required
+ *
+ *	RETURNS:
+ *	16-bit value read from the register.
+ */
+static inline uint16_t
+ti_i2c_read_reg(struct ti_i2c_softc *sc, bus_size_t off)
+{
+	/* XXXOMAP3: FIXME add registers mapping here */
+	return bus_read_2(sc->sc_mem_res, off);
+}
+
+/**
+ *	ti_i2c_write_reg - writes a 16-bit value to one of the I2C registers
+ *	    take into account revision-dependent register offset
+ *	@sc: I2C device context
+ *	@off: the byte offset within the register bank to read from.
+ *	@val: the value to write into the register
+ *
+ *	LOCKING:
+ *	No locking required
+ *
+ *	RETURNS:
+ *	16-bit value read from the register.
+ */
+static inline void
+ti_i2c_write_reg(struct ti_i2c_softc *sc, bus_size_t off, uint16_t val)
+{
+	/* XXXOMAP3: FIXME add registers mapping here */
+	bus_write_2(sc->sc_mem_res, off, val);
+}
+
+/**
+ *	ti_i2c_set_intr_enable - writes the interrupt enable register
+ *	@sc: I2C device context
+ *	@ie: bitmask of the interrupts to enable
+ *
+ *	This function is needed as writing the I2C_IE register on the OMAP4 devices
+ *	doesn't seem to actually enable the interrupt, rather you have to write
+ *	through the I2C_IRQENABLE_CLR and I2C_IRQENABLE_SET registers.
+ *
+ *	LOCKING:
+ *	No locking required
+ *
+ *	RETURNS:
+ *	Nothing.
+ */
+static inline void
+ti_i2c_set_intr_enable(struct ti_i2c_softc *sc, uint16_t ie)
+{
+	/* XXXOMAP3: FIXME */
+	ti_i2c_write_2(sc, I2C_REG_IRQENABLE_CLR, 0xffff);
+	if (ie)
+		ti_i2c_write_2(sc, I2C_REG_IRQENABLE_SET, ie);
+}
+
+/**
+ *	ti_i2c_reset - attach function for the driver
+ *	@dev: i2c device handle
+ *
+ *
+ *
+ *	LOCKING:
+ *	Called from timer context
+ *
+ *	RETURNS:
+ *	EH_HANDLED or EH_NOT_HANDLED
+ */
+static int
+ti_i2c_reset(device_t dev, u_char speed, u_char addr, u_char *oldaddr)
+{
+	struct ti_i2c_softc *sc = device_get_softc(dev);
+	struct ti_i2c_clock_config *clkcfg;
+	uint16_t con_reg;
+
+	clkcfg = ti_i2c_clock_configs;
+	while (clkcfg->speed != -1) {
+		if (clkcfg->speed == speed)
+			break;
+		/* take slow if speed is unknown */
+		if ((speed == IIC_UNKNOWN) && (clkcfg->speed == IIC_SLOW))
+			break;
+		clkcfg++;
+	}
+	if (clkcfg->speed == -1)
+		return (EINVAL);
+
+	TI_I2C_LOCK(sc);
+
+	if (oldaddr)
+		*oldaddr = sc->sc_i2c_addr;
+	sc->sc_i2c_addr = addr;
+
+	/* First disable the controller while changing the clocks */
+	con_reg = ti_i2c_read_reg(sc, I2C_REG_CON);
+	ti_i2c_write_reg(sc, I2C_REG_CON, 0x0000);
+
+	/* Program the prescaler */
+	ti_i2c_write_reg(sc, I2C_REG_PSC, clkcfg->psc);
+
+	/* Set the bitrate */
+	ti_i2c_write_reg(sc, I2C_REG_SCLL, clkcfg->scll | (clkcfg->hsscll<<8));
+	ti_i2c_write_reg(sc, I2C_REG_SCLH, clkcfg->sclh | (clkcfg->hssclh<<8));
+
+	/* Set the remote slave address */
+	ti_i2c_write_reg(sc, I2C_REG_SA, addr);
+
+	/* Check if we are dealing with high speed mode */
+	if ((clkcfg->hsscll + clkcfg->hssclh) > 0)
+		con_reg  = I2C_CON_OPMODE_HS;
+	else
+		con_reg  = I2C_CON_OPMODE_STD;
+
+	/* Enable the I2C module again */
+	ti_i2c_write_reg(sc, I2C_REG_CON, I2C_CON_I2C_EN | con_reg);
+
+	TI_I2C_UNLOCK(sc);
+
+	return 0;
+}
+
+/**
+ *	ti_i2c_intr - interrupt handler for the I2C module
+ *	@dev: i2c device handle
+ *
+ *
+ *
+ *	LOCKING:
+ *	Called from timer context
+ *
+ *	RETURNS:
+ *	EH_HANDLED or EH_NOT_HANDLED
+ */
+static void
+ti_i2c_intr(void *arg)
+{
+	struct ti_i2c_softc *sc = (struct ti_i2c_softc*) arg;
+	uint16_t status;
+
+	status = ti_i2c_read_reg(sc, I2C_REG_STAT);
+	if (status == 0)
+		return;
+
+	TI_I2C_LOCK(sc);
+
+	/* save the flags */
+	sc->sc_stat_flags |= status;
+
+	/* clear the status flags */
+	ti_i2c_write_reg(sc, I2C_REG_STAT, status);
+
+	/* wakeup the process the started the transaction */
+	wakeup(sc);
+
+	TI_I2C_UNLOCK(sc);
+
+	return;
+}
+
+/**
+ *	ti_i2c_wait - waits for the specific event to occur
+ *	@sc: i2c driver context
+ *	@flags: the event(s) to wait on, this is a bitmask of the I2C_STAT_??? flags
+ *	@statp: if not null will contain the status flags upon return
+ *	@timo: the number of ticks to wait
+ *
+ *
+ *
+ *	LOCKING:
+ *	The driver context must be locked before calling this function. Internally
+ *	the function sleeps, releasing the lock as it does so, however the lock is
+ *	always retaken before this function returns.
+ *
+ *	RETURNS:
+ *	0 if the event(s) were tripped within timeout period
+ *	EBUSY if timedout waiting for the events
+ *	ENXIO if a NACK event was received
+ */
+static int
+ti_i2c_wait(struct ti_i2c_softc *sc, uint16_t flags, uint16_t *statp, int timo)
+{
+	int waittime = timo;
+	int start_ticks = ticks;
+	int rc;
+
+	TI_I2C_ASSERT_LOCKED(sc);
+
+	/* check if the condition has already occured, the interrupt routine will
+	 * clear the status flags.
+	 */
+	if ((sc->sc_stat_flags & flags) == 0) {
+
+		/* condition(s) haven't occured so sleep on the IRQ */
+		while (waittime > 0) {
+
+			rc = mtx_sleep(sc, &sc->sc_mtx, 0, "I2Cwait", waittime);
+			if (rc == EWOULDBLOCK) {
+				/* timed-out, simply break out of the loop */
+				break;
+			} else {
+				/* IRQ has been tripped, but need to sanity check we have the
+				 * right events in the status flag.
+				 */
+				if ((sc->sc_stat_flags & flags) != 0)
+					break;
+
+				/* event hasn't been tripped so wait some more */
+				waittime -= (ticks - start_ticks);
+				start_ticks = ticks;
+			}
+		}
+	}
+
+	/* copy the actual status bits */
+	if (statp != NULL)
+		*statp = sc->sc_stat_flags;
+
+	/* return the status found */
+	if ((sc->sc_stat_flags & flags) != 0)
+		rc = 0;
+	else
+		rc = EBUSY;
+
+	/* clear the flags set by the interrupt handler */
+	sc->sc_stat_flags = 0;
+
+	return (rc);
+}
+
+/**
+ *	ti_i2c_wait_for_free_bus - waits for the bus to become free
+ *	@sc: i2c driver context
+ *	@timo: the time to wait for the bus to become free
+ *
+ *
+ *
+ *	LOCKING:
+ *	The driver context must be locked before calling this function. Internally
+ *	the function sleeps, releasing the lock as it does so, however the lock is
+ *	always taken before this function returns.
+ *
+ *	RETURNS:
+ *	0 if the event(s) were tripped within timeout period
+ *	EBUSY if timedout waiting for the events
+ *	ENXIO if a NACK event was received
+ */
+static int
+ti_i2c_wait_for_free_bus(struct ti_i2c_softc *sc, int timo)
+{
+	/* check if the bus is free, BB bit = 0 */
+	if ((ti_i2c_read_reg(sc, I2C_REG_STAT) & I2C_STAT_BB) == 0)
+		return 0;
+
+	/* enable bus free interrupts */
+	ti_i2c_set_intr_enable(sc, I2C_IE_BF);
+
+	/* wait for the bus free interrupt to be tripped */
+	return ti_i2c_wait(sc, I2C_STAT_BF, NULL, timo);
+}
+
+/**
+ *	ti_i2c_read_bytes - attempts to perform a read operation
+ *	@sc: i2c driver context
+ *	@buf: buffer to hold the received bytes
+ *	@len: the number of bytes to read
+ *
+ *	This function assumes the slave address is already set
+ *
+ *	LOCKING:
+ *	The context lock should be held before calling this function
+ *
+ *	RETURNS:
+ *	0 on function succeeded
+ *	EINVAL if invalid message is passed as an arg
+ */
+static int
+ti_i2c_read_bytes(struct ti_i2c_softc *sc, uint8_t *buf, uint16_t len)
+{
+	int      timo = (hz / 4);
+	int      err = 0;
+	uint16_t con_reg;
+	uint16_t events;
+	uint16_t status;
+	uint32_t amount = 0;
+	uint32_t sofar = 0;
+	uint32_t i;
+
+	/* wait for the bus to become free */
+	err = ti_i2c_wait_for_free_bus(sc, timo);
+	if (err != 0) {
+		device_printf(sc->sc_dev, "bus never freed\n");
+		return (err);
+	}
+
+	/* set the events to wait for */
+	events = I2C_IE_RDR |   /* Receive draining interrupt */
+	         I2C_IE_RRDY |  /* Receive Data Ready interrupt */
+	         I2C_IE_ARDY |  /* Register Access Ready interrupt */
+	         I2C_IE_NACK |  /* No Acknowledgment interrupt */
+	         I2C_IE_AL;
+
+	/* enable interrupts for the events we want */
+	ti_i2c_set_intr_enable(sc, events);
+
+	/* write the number of bytes to read */
+	ti_i2c_write_reg(sc, I2C_REG_CNT, len);
+
+	/* clear the write bit and initiate the read transaction. Setting the STT
+	 * (start) bit initiates the transfer.
+	 */
+	con_reg = ti_i2c_read_reg(sc, I2C_REG_CON);
+	con_reg &= ~I2C_CON_TRX;
+	con_reg |=  I2C_CON_MST | I2C_CON_STT | I2C_CON_STP;
+	ti_i2c_write_reg(sc, I2C_REG_CON, con_reg);
+
+	/* reading loop */
+	while (1) {
+
+		/* wait for an event */
+		err = ti_i2c_wait(sc, events, &status, timo);
+		if (err != 0) {
+			break;
+		}
+
+		/* check for the error conditions */
+		if (status & I2C_STAT_NACK) {
+			/* no ACK from slave */
+			ti_i2c_dbg(sc, "NACK\n");
+			err = ENXIO;
+			break;
+		}
+		if (status & I2C_STAT_AL) {
+			/* arbitration lost */
+			ti_i2c_dbg(sc, "Arbitration lost\n");
+			err = ENXIO;
+			break;
+		}
+
+		/* check if we have finished */
+		if (status & I2C_STAT_ARDY) {
+			/* register access ready - transaction complete basically */
+			ti_i2c_dbg(sc, "ARDY transaction complete\n");
+			err = 0;
+			break;
+		}
+
+		/* read some data */
+		if (status & I2C_STAT_RDR) {
+			/* Receive draining interrupt - last data received */
+			ti_i2c_dbg(sc, "Receive draining interrupt\n");
+
+			/* get the number of bytes in the FIFO */
+			amount = ti_i2c_read_reg(sc, I2C_REG_BUFSTAT);
+			amount >>= 8;
+			amount &= 0x3f;
+		}
+		else if (status & I2C_STAT_RRDY) {
+			/* Receive data ready interrupt - enough data received */
+			ti_i2c_dbg(sc, "Receive data ready interrupt\n");
+
+			/* get the number of bytes in the FIFO */
+			amount = ti_i2c_read_reg(sc, I2C_REG_BUF);
+			amount >>= 8;
+			amount &= 0x3f;
+			amount += 1;
+		}
+
+		/* sanity check we haven't overwritten the array */
+		if ((sofar + amount) > len) {
+			ti_i2c_dbg(sc, "to many bytes to read\n");
+			amount = (len - sofar);
+		}
+
+		/* read the bytes from the fifo */
+		for (i = 0; i < amount; i++) {
+			buf[sofar++] = (uint8_t)(ti_i2c_read_reg(sc, I2C_REG_DATA) & 0xff);
+		}
+
+		/* attempt to clear the receive ready bits */
+		ti_i2c_write_reg(sc, I2C_REG_STAT, I2C_STAT_RDR | I2C_STAT_RRDY);
+	}
+
+	/* reset the registers regardless if there was an error or not */
+	ti_i2c_set_intr_enable(sc, 0x0000);
+	ti_i2c_write_reg(sc, I2C_REG_CON, I2C_CON_I2C_EN | I2C_CON_MST | I2C_CON_STP);
+
+	return (err);
+}
+
+/**
+ *	ti_i2c_write_bytes - attempts to perform a read operation
+ *	@sc: i2c driver context
+ *	@buf: buffer containing the bytes to write
+ *	@len: the number of bytes to write
+ *
+ *	This function assumes the slave address is already set
+ *
+ *	LOCKING:
+ *	The context lock should be held before calling this function
+ *
+ *	RETURNS:
+ *	0 on function succeeded
+ *	EINVAL if invalid message is passed as an arg
+ */
+static int
+ti_i2c_write_bytes(struct ti_i2c_softc *sc, const uint8_t *buf, uint16_t len)
+{
+	int      timo = (hz / 4);
+	int      err = 0;
+	uint16_t con_reg;
+	uint16_t events;
+	uint16_t status;
+	uint32_t amount = 0;
+	uint32_t sofar = 0;
+	uint32_t i;
+
+	/* wait for the bus to become free */
+	err = ti_i2c_wait_for_free_bus(sc, timo);
+	if (err != 0)
+		return (err);
+
+	/* set the events to wait for */
+	events = I2C_IE_XDR |   /* Transmit draining interrupt */
+	         I2C_IE_XRDY |  /* Transmit Data Ready interrupt */
+	         I2C_IE_ARDY |  /* Register Access Ready interrupt */
+	         I2C_IE_NACK |  /* No Acknowledgment interrupt */
+	         I2C_IE_AL;
+
+	/* enable interrupts for the events we want*/
+	ti_i2c_set_intr_enable(sc, events);
+
+	/* write the number of bytes to write */
+	ti_i2c_write_reg(sc, I2C_REG_CNT, len);
+
+	/* set the write bit and initiate the write transaction. Setting the STT
+	 * (start) bit initiates the transfer.
+	 */
+	con_reg = ti_i2c_read_reg(sc, I2C_REG_CON);
+	con_reg |= I2C_CON_TRX | I2C_CON_MST | I2C_CON_STT | I2C_CON_STP;
+	ti_i2c_write_reg(sc, I2C_REG_CON, con_reg);
+
+	/* writing loop */
+	while (1) {
+
+		/* wait for an event */
+		err = ti_i2c_wait(sc, events, &status, timo);
+		if (err != 0) {
+			break;
+		}
+
+		/* check for the error conditions */
+		if (status & I2C_STAT_NACK) {
+			/* no ACK from slave */
+			ti_i2c_dbg(sc, "NACK\n");
+			err = ENXIO;
+			break;
+		}
+		if (status & I2C_STAT_AL) {
+			/* arbitration lost */
+			ti_i2c_dbg(sc, "Arbitration lost\n");
+			err = ENXIO;
+			break;
+		}
+
+		/* check if we have finished */
+		if (status & I2C_STAT_ARDY) {
+			/* register access ready - transaction complete basically */
+			ti_i2c_dbg(sc, "ARDY transaction complete\n");
+			err = 0;
+			break;
+		}
+
+		/* read some data */
+		if (status & I2C_STAT_XDR) {
+			/* Receive draining interrupt - last data received */
+			ti_i2c_dbg(sc, "Transmit draining interrupt\n");
+
+			/* get the number of bytes in the FIFO */
+			amount = ti_i2c_read_reg(sc, I2C_REG_BUFSTAT);
+			amount &= 0x3f;
+		}
+		else if (status & I2C_STAT_XRDY) {
+			/* Receive data ready interrupt - enough data received */
+			ti_i2c_dbg(sc, "Transmit data ready interrupt\n");
+
+			/* get the number of bytes in the FIFO */
+			amount = ti_i2c_read_reg(sc, I2C_REG_BUF);
+			amount &= 0x3f;
+			amount += 1;
+		}
+
+		/* sanity check we haven't overwritten the array */
+		if ((sofar + amount) > len) {
+			ti_i2c_dbg(sc, "to many bytes to write\n");
+			amount = (len - sofar);
+		}
+
+		/* write the bytes from the fifo */
+		for (i = 0; i < amount; i++) {
+			ti_i2c_write_reg(sc, I2C_REG_DATA, buf[sofar++]);
+		}
+
+		/* attempt to clear the transmit ready bits */
+		ti_i2c_write_reg(sc, I2C_REG_STAT, I2C_STAT_XDR | I2C_STAT_XRDY);
+	}
+
+	/* reset the registers regardless if there was an error or not */
+	ti_i2c_set_intr_enable(sc, 0x0000);
+	ti_i2c_write_reg(sc, I2C_REG_CON, I2C_CON_I2C_EN | I2C_CON_MST | I2C_CON_STP);
+
+	return (err);
+}
+
+/**
+ *	ti_i2c_transfer - called to perform the transfer
+ *	@dev: i2c device handle
+ *	@msgs: the messages to send/receive
+ *	@nmsgs: the number of messages in the msgs array
+ *
+ *
+ *	LOCKING:
+ *	Internally locked
+ *
+ *	RETURNS:
+ *	0 on function succeeded
+ *	EINVAL if invalid message is passed as an arg
+ */
+static int
+ti_i2c_transfer(device_t dev, struct iic_msg *msgs, uint32_t nmsgs)
+{
+	struct ti_i2c_softc *sc = device_get_softc(dev);
+	int err = 0;
+	uint32_t i;
+	uint16_t len;
+	uint8_t *buf;
+
+	TI_I2C_LOCK(sc);
+
+	for (i = 0; i < nmsgs; i++) {
+
+		len = msgs[i].len;
+		buf = msgs[i].buf;
+
+		/* zero byte transfers aren't allowed */
+		if (len == 0 || buf == NULL) {
+			err = EINVAL;
+			goto out;
+		}
+
+		/* set the slave address */
+		ti_i2c_write_reg(sc, I2C_REG_SA, msgs[i].slave);
+
+		/* perform the read or write */
+		if (msgs[i].flags & IIC_M_RD) {
+			err = ti_i2c_read_bytes(sc, buf, len);
+		} else {
+			err = ti_i2c_write_bytes(sc, buf, len);
+		}
+
+	}
+
+out:
+	TI_I2C_UNLOCK(sc);
+
+	return (err);
+}
+
+/**
+ *	ti_i2c_callback - not sure about this one
+ *	@dev: i2c device handle
+ *
+ *
+ *
+ *	LOCKING:
+ *	Called from timer context
+ *
+ *	RETURNS:
+ *	EH_HANDLED or EH_NOT_HANDLED
+ */
+static int
+ti_i2c_callback(device_t dev, int index, caddr_t data)
+{
+	int error = 0;
+
+	switch (index) {
+		case IIC_REQUEST_BUS:
+			break;
+
+		case IIC_RELEASE_BUS:
+			break;
+
+		default:
+			error = EINVAL;
+	}
+
+	return (error);
+}
+
+/**
+ *	ti_i2c_activate - initialises and activates an I2C bus
+ *	@dev: i2c device handle
+ *	@num: the number of the I2C controller to activate; 1, 2 or 3
+ *
+ *
+ *	LOCKING:
+ *	Assumed called in an atomic context.
+ *
+ *	RETURNS:
+ *	nothing
+ */
+static int
+ti_i2c_activate(device_t dev)
+{
+	struct ti_i2c_softc *sc = (struct ti_i2c_softc*) device_get_softc(dev);
+	unsigned int timeout = 0;
+	uint16_t con_reg;
+	int err;
+	clk_ident_t clk;
+
+	/*
+	 * The following sequence is taken from the OMAP3530 technical reference
+	 *
+	 * 1. Enable the functional and interface clocks (see Section 18.3.1.1.1).
+	 */
+	clk = I2C0_CLK + sc->device_id;
+	err = ti_prcm_clk_enable(clk);
+	if (err)
+		return (err);
+
+	/* There seems to be a bug in the I2C reset mechanism, for some reason you
+	 * need to disable the I2C module before issuing the reset and then enable
+	 * it again after to detect the reset done.
+	 *
+	 * I found this out by looking at the Linux driver implementation, thanks
+	 * linux guys!
+	 */
+
+	/* Disable the I2C controller */
+	ti_i2c_write_reg(sc, I2C_REG_CON, 0x0000);
+
+	/* Issue a softreset to the controller */
+	/* XXXOMAP3: FIXME */
+	bus_write_2(sc->sc_mem_res, I2C_REG_SYSC, 0x0002);
+
+	/* Re-enable the module and then check for the reset done */
+	ti_i2c_write_reg(sc, I2C_REG_CON, I2C_CON_I2C_EN);
+
+	while ((ti_i2c_read_reg(sc, I2C_REG_SYSS) & 0x01) == 0x00) {
+		if (timeout++ > 100) {
+			return (EBUSY);
+		}
+		DELAY(100);
+	}
+
+	/* Disable the I2C controller once again, now that the reset has finished */
+	ti_i2c_write_reg(sc, I2C_REG_CON, 0x0000);
+
+	/* 2. Program the prescaler to obtain an approximately 12-MHz internal
+	 *    sampling clock (I2Ci_INTERNAL_CLK) by programming the corresponding
+	 *    value in the I2Ci.I2C_PSC[3:0] PSC field.
+	 *    This value depends on the frequency of the functional clock (I2Ci_FCLK).
+	 *    Because this frequency is 96MHz, the I2Ci.I2C_PSC[7:0] PSC field value
+	 *    is 0x7.
+	 */
+
+	/* Program the prescaler to obtain an approximately 12-MHz internal
+	 * sampling clock.
+	 */
+	ti_i2c_write_reg(sc, I2C_REG_PSC, 0x0017);
+
+	/* 3. Program the I2Ci.I2C_SCLL[7:0] SCLL and I2Ci.I2C_SCLH[7:0] SCLH fields
+	 *    to obtain a bit rate of 100K bps or 400K bps. These values depend on
+	 *    the internal sampling clock frequency (see Table 18-12).
+	 */
+
+	/* Set the bitrate to 100kbps */
+	ti_i2c_write_reg(sc, I2C_REG_SCLL, 0x000d);
+	ti_i2c_write_reg(sc, I2C_REG_SCLH, 0x000f);
+
+	/* 4. (Optional) Program the I2Ci.I2C_SCLL[15:8] HSSCLL and
+	 *    I2Ci.I2C_SCLH[15:8] HSSCLH fields to obtain a bit rate of 400K bps or
+	 *    3.4M bps (for the second phase of HS mode). These values depend on the
+	 *    internal sampling clock frequency (see Table 18-12).
+	 *
+	 * 5. (Optional) If a bit rate of 3.4M bps is used and the bus line
+	 *    capacitance exceeds 45 pF, program the CONTROL.CONTROL_DEVCONF1[12]
+	 *    I2C1HSMASTER bit for I2C1, the CONTROL.CONTROL_DEVCONF1[13]
+	 *    I2C2HSMASTER bit for I2C2, or the CONTROL.CONTROL_DEVCONF1[14]
+	 *    I2C3HSMASTER bit for I2C3.
+	 */
+
+	/* 6. Configure the Own Address of the I2C controller by storing it in the
+	 *    I2Ci.I2C_OA0 register. Up to four Own Addresses can be programmed in
+	 *    the I2Ci.I2C_OAi registers (with I = 0, 1, 2, 3) for each I2C
+	 *    controller.
+	 *
+	 * Note: For a 10-bit address, set the corresponding expand Own Address bit
+	 * in the I2Ci.I2C_CON register.
+	 */
+
+	/* Driver currently always in single master mode so ignore this step */
+
+	/* 7. Set the TX threshold (in transmitter mode) and the RX threshold (in
+	 *    receiver mode) by setting the I2Ci.I2C_BUF[5:0]XTRSH field to (TX
+	 *    threshold - 1) and the I2Ci.I2C_BUF[13:8]RTRSH field to (RX threshold
+	 *    - 1), where the TX and RX thresholds are greater than or equal to 1.
+	 */
+
+	/* Set the FIFO buffer threshold, note I2C1 & I2C2 have 8 byte FIFO, whereas
+	 * I2C3 has 64 bytes.  Threshold set to 5 for now.
+	 */
+	ti_i2c_write_reg(sc, I2C_REG_BUF, 0x0404);
+
+	/*
+	 * 8. Take the I2C controller out of reset by setting the I2Ci.I2C_CON[15]
+	 *    I2C_EN bit to 1.
+	 */
+	ti_i2c_write_reg(sc, I2C_REG_CON, I2C_CON_I2C_EN | I2C_CON_OPMODE_STD);
+
+	/*
+	 * To initialize the I2C controller, perform the following steps:
+	 *
+	 * 1. Configure the I2Ci.I2C_CON register:
+	 *    · For master or slave mode, set the I2Ci.I2C_CON[10] MST bit (0: slave,
+	 *      1: master).
+	 *    · For transmitter or receiver mode, set the I2Ci.I2C_CON[9] TRX bit
+	 *      (0: receiver, 1: transmitter).
+	 */
+	con_reg = ti_i2c_read_reg(sc, I2C_REG_CON);
+	con_reg |= I2C_CON_MST;
+	ti_i2c_write_reg(sc, I2C_REG_CON, con_reg);
+
+	/* 2. If using an interrupt to transmit/receive data, set to 1 the
+	 *    corresponding bit in the I2Ci.I2C_IE register (the I2Ci.I2C_IE[4]
+	 *    XRDY_IE bit for the transmit interrupt, the I2Ci.I2C_IE[3] RRDY bit
+	 *    for the receive interrupt).
+	 */
+	ti_i2c_set_intr_enable(sc, I2C_IE_XRDY | I2C_IE_RRDY);
+
+	/* 3. If using DMA to receive/transmit data, set to 1 the corresponding bit
+	 *    in the I2Ci.I2C_BUF register (the I2Ci.I2C_BUF[15] RDMA_EN bit for the
+	 *    receive DMA channel, the I2Ci.I2C_BUF[7] XDMA_EN bit for the transmit
+	 *    DMA channel).
+	 */
+
+	/* not using DMA for now, so ignore this */
+
+	return (0);
+}
+
+/**
+ *	ti_i2c_deactivate - deactivates the controller and releases resources
+ *	@dev: i2c device handle
+ *
+ *
+ *
+ *	LOCKING:
+ *	Assumed called in an atomic context.
+ *
+ *	RETURNS:
+ *	nothing
+ */
+static void
+ti_i2c_deactivate(device_t dev)
+{
+	struct ti_i2c_softc *sc = device_get_softc(dev);
+	clk_ident_t clk;
+
+	/* Disable the controller - cancel all transactions */
+	ti_i2c_write_reg(sc, I2C_REG_CON, 0x0000);
+
+	/* Release the interrupt handler */
+	if (sc->sc_irq_h) {
+		bus_teardown_intr(dev, sc->sc_irq_res, sc->sc_irq_h);
+		sc->sc_irq_h = 0;
+	}
+
+	bus_generic_detach(sc->sc_dev);
+
+	/* Unmap the I2C controller registers */
+	if (sc->sc_mem_res != 0) {
+		bus_release_resource(dev, SYS_RES_MEMORY, rman_get_rid(sc->sc_irq_res),
+							 sc->sc_mem_res);
+		sc->sc_mem_res = NULL;
+	}
+
+	/* Release the IRQ resource */
+	if (sc->sc_irq_res != NULL) {
+		bus_release_resource(dev, SYS_RES_IRQ, rman_get_rid(sc->sc_irq_res),
+							 sc->sc_irq_res);
+		sc->sc_irq_res = NULL;
+	}
+
+	/* Finally disable the functional and interface clocks */
+	clk = I2C0_CLK + sc->device_id;
+	ti_prcm_clk_disable(clk);
+
+	return;
+}
+
+/**
+ *	ti_i2c_probe - probe function for the driver
+ *	@dev: i2c device handle
+ *
+ *
+ *
+ *	LOCKING:
+ *
+ *
+ *	RETURNS:
+ *	Always returns 0
+ */
+static int
+ti_i2c_probe(device_t dev)
+{
+	if (!ofw_bus_is_compatible(dev, "ti,i2c"))
+		return (ENXIO);
+
+	device_set_desc(dev, "TI I2C Controller");
+	return (0);
+}
+
+/**
+ *	ti_i2c_attach - attach function for the driver
+ *	@dev: i2c device handle
+ *
+ *	Initialised driver data structures and activates the I2C controller.
+ *
+ *	LOCKING:
+ *
+ *
+ *	RETURNS:
+ *
+ */
+static int
+ti_i2c_attach(device_t dev)
+{
+	struct ti_i2c_softc *sc = device_get_softc(dev);
+	phandle_t node;
+	pcell_t did;
+	int err;
+	int rid;
+
+	sc->sc_dev = dev;
+
+	/* Get the i2c device id from FDT */
+	node = ofw_bus_get_node(dev);
+	if ((OF_getprop(node, "i2c-device-id", &did, sizeof(did))) <= 0) {
+		device_printf(dev, "missing i2c-device-id attribute in FDT\n");
+		return (ENXIO);
+	}
+	sc->device_id = fdt32_to_cpu(did);
+
+	TI_I2C_LOCK_INIT(sc);
+
+	/* Get the memory resource for the register mapping */
+	rid = 0;
+	sc->sc_mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid,
+	                                        RF_ACTIVE);
+	if (sc->sc_mem_res == NULL)
+		panic("%s: Cannot map registers", device_get_name(dev));
+
+	/* Allocate an IRQ resource for the MMC controller */
+	rid = 0;
+	sc->sc_irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid,
+	                                        RF_ACTIVE | RF_SHAREABLE);
+	if (sc->sc_irq_res == NULL) {
+		err = ENOMEM;
+		goto out;
+	}
+
+	/* XXXOMAP3: FIXME get proper revision here */
+	/* First read the version number of the I2C module */
+	sc->sc_rev = ti_i2c_read_2(sc, I2C_REG_REVNB_HI) & 0xff;
+
+	device_printf(dev, "I2C revision %d.%d\n", sc->sc_rev >> 4,
+	    sc->sc_rev & 0xf);
+
+	/* Activate the H/W */
+	err = ti_i2c_activate(dev);
+	if (err) {
+		device_printf(dev, "ti_i2c_activate failed\n");
+		goto out;
+	}
+
+	/* activate the interrupt */
+	err = bus_setup_intr(dev, sc->sc_irq_res, INTR_TYPE_MISC | INTR_MPSAFE,
+				NULL, ti_i2c_intr, sc, &sc->sc_irq_h);
+	if (err)
+		goto out;
+
+	/* Attach to the iicbus */
+	if ((sc->sc_iicbus = device_add_child(dev, "iicbus", -1)) == NULL)
+		device_printf(dev, "could not allocate iicbus instance\n");
+
+	/* Probe and attach the iicbus */
+	bus_generic_attach(dev);
+
+out:
+	if (err) {
+		ti_i2c_deactivate(dev);
+		TI_I2C_LOCK_DESTROY(sc);
+	}
+
+	return (err);
+}
+
+/**
+ *	ti_i2c_detach - detach function for the driver
+ *	@dev: i2c device handle
+ *
+ *
+ *
+ *	LOCKING:
+ *
+ *
+ *	RETURNS:
+ *	Always returns 0
+ */
+static int
+ti_i2c_detach(device_t dev)
+{
+	struct ti_i2c_softc *sc = device_get_softc(dev);
+	int rv;
+
+	ti_i2c_deactivate(dev);
+
+	if (sc->sc_iicbus && (rv = device_delete_child(dev, sc->sc_iicbus)) != 0)
+		return (rv);
+
+	TI_I2C_LOCK_DESTROY(sc);
+
+	return (0);
+}
+
+
+static phandle_t
+ti_i2c_get_node(device_t bus, device_t dev)
+{
+	/* 
+	 * Share controller node with iibus device
+	 */
+	return ofw_bus_get_node(bus);
+}
+
+static device_method_t ti_i2c_methods[] = {
+	/* Device interface */
+	DEVMETHOD(device_probe,		ti_i2c_probe),
+	DEVMETHOD(device_attach,	ti_i2c_attach),
+	DEVMETHOD(device_detach,	ti_i2c_detach),
+
+	/* OFW methods */
+	DEVMETHOD(ofw_bus_get_node,	ti_i2c_get_node),
+
+	/* iicbus interface */
+	DEVMETHOD(iicbus_callback,	ti_i2c_callback),
+	DEVMETHOD(iicbus_reset,		ti_i2c_reset),
+	DEVMETHOD(iicbus_transfer,	ti_i2c_transfer),
+	{ 0, 0 }
+};
+
+static driver_t ti_i2c_driver = {
+	"iichb",
+	ti_i2c_methods,
+	sizeof(struct ti_i2c_softc),
+};
+
+DRIVER_MODULE(ti_iic, simplebus, ti_i2c_driver, ti_i2c_devclass, 0, 0);
+DRIVER_MODULE(iicbus, ti_iic, iicbus_driver, iicbus_devclass, 0, 0);
+
+MODULE_DEPEND(ti_iic, ti_prcm, 1, 1, 1);
+MODULE_DEPEND(ti_iic, iicbus, 1, 1, 1);
diff -r 7fffa673adcd -r a301a330526b head/sys/arm/ti/ti_i2c.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/head/sys/arm/ti/ti_i2c.h	Wed Aug 15 11:16:36 2012 +0300
@@ -0,0 +1,115 @@
+/*-
+ * Copyright (c) 2011
+ *	Ben Gray <ben.r.gray at 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.
+ *
+ * $FreeBSD: head/sys/arm/ti/ti_i2c.h 239281 2012-08-15 06:31:32Z gonzo $
+ */
+
+#ifndef _TI_I2C_H_
+#define	_TI_I2C_H_
+
+/**
+ * Header file for the OMAP I2C driver.
+ *
+ * Simply contains register bit flags.
+ */
+
+/*
+ * OMAP4 I2C Registers, Summary 1
+ */
+#define	I2C_REG_IE		0x84
+#define		I2C_IE_XDR		(1UL << 14)   /* Transmit draining interrupt */
+#define		I2C_IE_RDR		(1UL << 13)   /* Receive draining interrupt */
+#define		I2C_IE_AAS		(1UL << 9)    /* Addressed as Slave interrupt */
+#define		I2C_IE_BF		(1UL << 8)    /* Bus Free interrupt */
+#define		I2C_IE_AERR		(1UL << 7)    /* Access Error interrupt */
+#define		I2C_IE_STC		(1UL << 6)    /* Start Condition interrupt */
+#define		I2C_IE_GC		(1UL << 5)    /* General Call interrupt */
+#define		I2C_IE_XRDY		(1UL << 4)    /* Transmit Data Ready interrupt */
+#define		I2C_IE_RRDY		(1UL << 3)    /* Receive Data Ready interrupt */
+#define		I2C_IE_ARDY		(1UL << 2)    /* Register Access Ready interrupt */
+#define		I2C_IE_NACK		(1UL << 1)    /* No Acknowledgment interrupt */
+#define		I2C_IE_AL		(1UL << 0)    /* Arbitration Lost interrupt */
+#define	I2C_REG_STAT		0x88
+#define		I2C_STAT_XDR		(1UL << 14)
+#define		I2C_STAT_RDR		(1UL << 13)
+#define		I2C_STAT_BB		(1UL << 12)
+#define		I2C_STAT_ROVR		(1UL << 11)
+#define		I2C_STAT_XUDF		(1UL << 10)
+#define		I2C_STAT_AAS		(1UL << 9)
+#define		I2C_STAT_BF		(1UL << 8)
+#define		I2C_STAT_AERR		(1UL << 7)
+#define		I2C_STAT_STC		(1UL << 6)
+#define		I2C_STAT_GC		(1UL << 5)
+#define		I2C_STAT_XRDY		(1UL << 4)
+#define		I2C_STAT_RRDY		(1UL << 3)
+#define		I2C_STAT_ARDY		(1UL << 2)
+#define		I2C_STAT_NACK		(1UL << 1)
+#define		I2C_STAT_AL		(1UL << 0)
+#define	I2C_REG_SYSS		0x90
+#define	I2C_REG_BUF		0x94
+#define	I2C_REG_CNT		0x98
+#define	I2C_REG_DATA		0x9c
+#define	I2C_REG_CON		0xa4
+#define		I2C_CON_I2C_EN		(1UL << 15)
+#define		I2C_CON_OPMODE_STD	(0UL << 12)
+#define		I2C_CON_OPMODE_HS	(1UL << 12)
+#define		I2C_CON_OPMODE_SCCB	(2UL << 12)
+#define		I2C_CON_OPMODE_MASK	(3UL << 13)
+#define		I2C_CON_I2C_STB		(1UL << 11)
+#define		I2C_CON_MST		(1UL << 10)
+#define		I2C_CON_TRX		(1UL << 9)
+#define		I2C_CON_XSA		(1UL << 8)
+#define		I2C_CON_XOA0		(1UL << 7)
+#define		I2C_CON_XOA1		(1UL << 6)
+#define		I2C_CON_XOA2		(1UL << 5)
+#define		I2C_CON_XOA3		(1UL << 4)
+#define		I2C_CON_STP		(1UL << 1)
+#define		I2C_CON_STT		(1UL << 0)
+#define	I2C_REG_OA0		0xa8
+#define	I2C_REG_SA		0xac
+#define	I2C_REG_PSC		0xb0
+#define	I2C_REG_SCLL		0xb4
+#define	I2C_REG_SCLH		0xb8
+#define	I2C_REG_SYSTEST		0xbc
+#define	I2C_REG_BUFSTAT		0xc0
+#define	I2C_REG_OA1		0xc4
+#define	I2C_REG_OA2		0xc8
+#define	I2C_REG_OA3		0xcc
+#define	I2C_REG_ACTOA		0xd0
+#define	I2C_REG_SBLOCK		0xd4
+
+/*
+ * OMAP4 I2C Registers, Summary 2 
+ */
+#define	I2C_REG_REVNB_LO	0x00
+#define	I2C_REG_REVNB_HI	0x04
+#define	I2C_REG_SYSC		0x10
+#define	I2C_REG_IRQENABLE_SET	0x2C
+#define	I2C_REG_IRQENABLE_CLR	0x30
+
+
+
+#endif /* _TI_I2C_H_ */
diff -r 7fffa673adcd -r a301a330526b head/sys/arm/ti/ti_machdep.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/head/sys/arm/ti/ti_machdep.c	Wed Aug 15 11:16:36 2012 +0300
@@ -0,0 +1,618 @@
+/*-
+ * 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.
+ *
+ * from: FreeBSD: //depot/projects/arm/src/sys/arm/at91/kb920x_machdep.c, rev 45
+ */
+
+#include "opt_ddb.h"
+#include "opt_platform.h"
+#include "opt_global.h"
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: head/sys/arm/ti/ti_machdep.c 239281 2012-08-15 06:31:32Z gonzo $");
+
+#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 <machine/fdt.h>
+
+#include <dev/fdt/fdt_common.h>
+#include <dev/ofw/openfirm.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/pte.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/ti/omap4/omap4_reg.h>
+
+#define  DEBUG
+#ifdef  DEBUG
+#define debugf(fmt, args...) printf(fmt, ##args)
+#else
+#define debugf(fmt, args...)
+#endif
+
+/* Start of address space used for bootstrap map */
+#define DEVMAP_BOOTSTRAP_MAP_START	0xE0000000
+
+/*
+ * This is the number of L2 page tables required for covering max
+ * (hypothetical) memsize of 4GB and all kernel mappings (vectors, msgbuf,
+ * stacks etc.), uprounded to be divisible by 4.
+ */
+#define KERNEL_PT_MAX	78
+
+/* Define various stack sizes in pages */
+#define IRQ_STACK_SIZE	1
+#define ABT_STACK_SIZE	1
+#define UND_STACK_SIZE	1
+
+extern unsigned char kernbase[];
+extern unsigned char _etext[];
+extern unsigned char _edata[];
+extern unsigned char __bss_start[];
+extern unsigned char _end[];
+
+#ifdef DDB
+extern vm_offset_t ksym_start, ksym_end;
+#endif
+
+extern u_int data_abort_handler_address;
+extern u_int prefetch_abort_handler_address;
+extern u_int undefined_handler_address;
+
+extern vm_offset_t pmap_bootstrap_lastaddr;
+extern int *end;
+
+struct pv_addr kernel_pt_table[KERNEL_PT_MAX];
+
+/* 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;
+vm_offset_t pmap_bootstrap_lastaddr;
+vm_paddr_t pmap_pa;
+
+const struct pmap_devmap *pmap_devmap_bootstrap_table;
+struct pv_addr systempage;
+struct pv_addr msgbufpv;
+struct pv_addr irqstack;
+struct pv_addr undstack;
+struct pv_addr abtstack;
+struct pv_addr kernelstack;
+
+void set_stackptrs(int cpu);
+
+static struct mem_region availmem_regions[FDT_MEM_REGIONS];
+static int availmem_regions_sz;
+
+static void print_kenv(void);
+static void print_kernel_section_addr(void);
+
+static void physmap_init(void);
+static int platform_devmap_init(void);
+void (*ti_cpu_reset)(void);
+
+static char *
+kenv_next(char *cp)
+{
+
+	if (cp != NULL) {
+		while (*cp != 0)
+			cp++;
+		cp++;
+		if (*cp == 0)
+			cp = NULL;
+	}
+	return (cp);
+}
+
+static void
+print_kenv(void)
+{
+	int len;
+	char *cp;
+
+	debugf("loader passed (static) kenv:\n");
+	if (kern_envp == NULL) {
+		debugf(" no env, null ptr\n");
+		return;
+	}
+	debugf(" kern_envp = 0x%08x\n", (uint32_t)kern_envp);
+
+	len = 0;
+	for (cp = kern_envp; cp != NULL; cp = kenv_next(cp))
+		debugf(" %x %s\n", (uint32_t)cp, cp);
+}
+
+static void
+print_kernel_section_addr(void)
+{
+
+	debugf("kernel image addresses:\n");
+	debugf(" kernbase       = 0x%08x\n", (uint32_t)kernbase);
+	debugf(" _etext (sdata) = 0x%08x\n", (uint32_t)_etext);
+	debugf(" _edata         = 0x%08x\n", (uint32_t)_edata);
+	debugf(" __bss_start    = 0x%08x\n", (uint32_t)__bss_start);
+	debugf(" _end           = 0x%08x\n", (uint32_t)_end);
+}
+
+static void
+physmap_init(void)
+{
+	int i, j, cnt;
+	vm_offset_t phys_kernelend, kernload;
+	uint32_t s, e, sz;
+	struct mem_region *mp, *mp1;
+
+	phys_kernelend = KERNPHYSADDR + (virtual_avail - KERNVIRTADDR);
+	kernload = KERNPHYSADDR;
+	ti_cpu_reset = NULL;
+
+	/*
+	 * Remove kernel physical address range from avail
+	 * regions list. Page align all regions.
+	 * Non-page aligned memory isn't very interesting to us.
+	 * Also, sort the entries for ascending addresses.
+	 */
+	sz = 0;
+	cnt = availmem_regions_sz;
+	debugf("processing avail regions:\n");
+	for (mp = availmem_regions; mp->mr_size; mp++) {
+		s = mp->mr_start;
+		e = mp->mr_start + mp->mr_size;
+		debugf(" %08x-%08x -> ", s, e);
+		/* Check whether this region holds all of the kernel. */
+		if (s < kernload && e > phys_kernelend) {
+			availmem_regions[cnt].mr_start = phys_kernelend;
+			availmem_regions[cnt++].mr_size = e - phys_kernelend;
+			e = kernload;
+		}
+		/* Look whether this regions starts within the kernel. */
+		if (s >= kernload && s < phys_kernelend) {
+			if (e <= phys_kernelend)
+				goto empty;
+			s = phys_kernelend;
+		}
+		/* Now look whether this region ends within the kernel. */
+		if (e > kernload && e <= phys_kernelend) {
+			if (s >= kernload) {
+				goto empty;
+			}
+			e = kernload;
+		}
+		/* Now page align the start and size of the region. */
+		s = round_page(s);
+		e = trunc_page(e);
+		if (e < s)
+			e = s;
+		sz = e - s;
+		debugf("%08x-%08x = %x\n", s, e, sz);
+
+		/* Check whether some memory is left here. */
+		if (sz == 0) {
+		empty:
+			printf("skipping\n");
+			bcopy(mp + 1, mp,
+			    (cnt - (mp - availmem_regions)) * sizeof(*mp));
+			cnt--;
+			mp--;
+			continue;
+		}
+
+		/* Do an insertion sort. */
+		for (mp1 = availmem_regions; mp1 < mp; mp1++)
+			if (s < mp1->mr_start)
+				break;
+		if (mp1 < mp) {
+			bcopy(mp1, mp1 + 1, (char *)mp - (char *)mp1);
+			mp1->mr_start = s;
+			mp1->mr_size = sz;
+		} else {
+			mp->mr_start = s;
+			mp->mr_size = sz;
+		}
+	}
+	availmem_regions_sz = cnt;
+
+	/* Fill in phys_avail table, based on availmem_regions */
+	debugf("fill in phys_avail:\n");
+	for (i = 0, j = 0; i < availmem_regions_sz; i++, j += 2) {
+
+		debugf(" region: 0x%08x - 0x%08x (0x%08x)\n",
+		    availmem_regions[i].mr_start,
+		    availmem_regions[i].mr_start + availmem_regions[i].mr_size,
+		    availmem_regions[i].mr_size);
+
+		phys_avail[j] = availmem_regions[i].mr_start;
+		phys_avail[j + 1] = availmem_regions[i].mr_start +
+		    availmem_regions[i].mr_size;
+	}
+	phys_avail[j] = 0;
+	phys_avail[j + 1] = 0;
+}
+
+void *
+initarm(struct arm_boot_params *abp)
+{
+	struct pv_addr kernel_l1pt;
+	struct pv_addr dpcpu;
+	vm_offset_t dtbp, freemempos, l2_start, lastaddr;
+	uint32_t memsize, l2size;
+	void *kmdp;
+	u_int l1pagetable;
+	int i = 0, j = 0, err_devmap = 0;
+
+	lastaddr = parse_boot_param(abp);
+	memsize = 0;
+	set_cpufuncs();
+
+
+	kmdp = preload_search_by_type("elf kernel");
+	if (kmdp != NULL)
+		dtbp = MD_FETCH(kmdp, MODINFOMD_DTBP, vm_offset_t);
+	else
+		dtbp = (vm_offset_t)NULL;
+ 
+#if defined(FDT_DTB_STATIC)
+	/*
+	 * In case the device tree blob was not retrieved (from metadata) try
+	 * to use the statically embedded one.
+	 */
+	if (dtbp == (vm_offset_t)NULL)
+		dtbp = (vm_offset_t)&fdt_static_dtb;
+#endif
+
+	if (OF_install(OFW_FDT, 0) == FALSE)
+		while (1);
+
+	if (OF_init((void *)dtbp) != 0)
+		while (1);
+
+	/* Grab physical memory regions information from device tree. */
+	if (fdt_get_mem_regions(availmem_regions, &availmem_regions_sz,
+	    &memsize) != 0)
+		while(1);
+
+//	if (fdt_immr_addr(OMAP44XX_L4_PERIPH_VBASE) != 0)
+//		while (1);
+
+	/* Platform-specific initialisation */
+	pmap_bootstrap_lastaddr = DEVMAP_BOOTSTRAP_MAP_START - ARM_NOCACHE_KVA_SIZE;
+
+	pcpu0_init();
+
+	/* Calculate number of L2 tables needed for mapping vm_page_array */
+	l2size = (memsize / PAGE_SIZE) * sizeof(struct vm_page);
+	l2size = (l2size >> L1_S_SHIFT) + 1;
+
+	/*
+	 * Add one table for end of kernel map, one for stacks, msgbuf and
+	 * L1 and L2 tables map and one for vectors map.
+	 */
+	l2size += 3;
+
+	/* Make it divisible by 4 */
+	l2size = (l2size + 3) & ~3;
+
+#define KERNEL_TEXT_BASE (KERNBASE)
+	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 (i = 0; i < l2size; ++i) {
+		if (!(i % (PAGE_SIZE / L2_TABLE_SIZE_REAL))) {
+			valloc_pages(kernel_pt_table[i],
+			    L2_TABLE_SIZE / PAGE_SIZE);
+			j = i;
+		} else {
+			kernel_pt_table[i].pv_va = kernel_pt_table[j].pv_va +
+			    L2_TABLE_SIZE_REAL * (i - j);
+			kernel_pt_table[i].pv_pa =
+			    kernel_pt_table[i].pv_va - KERNVIRTADDR +
+			    KERNPHYSADDR;
+
+		}
+	}
+	/*
+	 * Allocate a page for the system page mapped to 0x00000000
+	 * or 0xffff0000. 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 * MAXCPU));
+	valloc_pages(abtstack, (ABT_STACK_SIZE * MAXCPU));
+	valloc_pages(undstack, (UND_STACK_SIZE * MAXCPU));
+	valloc_pages(kernelstack, (KSTACK_PAGES * MAXCPU));
+
+	init_param1();
+
+	valloc_pages(msgbufpv, round_page(msgbufsize) / 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;
+
+	/*
+	 * Try to map as much as possible of kernel text and data using
+	 * 1MB section mapping and for the rest of initial kernel address
+	 * space use L2 coarse tables.
+	 *
+	 * Link L2 tables for mapping remainder of kernel (modulo 1MB)
+	 * and kernel structures
+	 */
+	l2_start = lastaddr & ~(L1_S_OFFSET);
+	for (i = 0 ; i < l2size - 1; i++)
+		pmap_link_l2pt(l1pagetable, l2_start + i * L1_S_SIZE,
+		    &kernel_pt_table[i]);
+
+	pmap_curmaxkvaddr = l2_start + (l2size - 1) * L1_S_SIZE;
+	
+	/* Map kernel code and data */
+	pmap_map_chunk(l1pagetable, KERNVIRTADDR, KERNPHYSADDR,
+	   (((uint32_t)(lastaddr) - KERNVIRTADDR) + PAGE_MASK) & ~PAGE_MASK,
+	    VM_PROT_READ|VM_PROT_WRITE, PTE_CACHE);
+
+
+	/* Map L1 directory and allocated L2 page tables */
+	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, kernel_pt_table[0].pv_va,
+	    kernel_pt_table[0].pv_pa,
+	    L2_TABLE_SIZE_REAL * l2size,
+	    VM_PROT_READ|VM_PROT_WRITE, PTE_PAGETABLE);
+
+	/* Map allocated DPCPU, stacks and msgbuf */
+	pmap_map_chunk(l1pagetable, dpcpu.pv_va, dpcpu.pv_pa,
+	    freemempos - dpcpu.pv_va,
+	    VM_PROT_READ|VM_PROT_WRITE, PTE_CACHE);
+
+	/* Link and map the vector page */
+	pmap_link_l2pt(l1pagetable, ARM_VECTORS_HIGH,
+	    &kernel_pt_table[l2size - 1]);
+	pmap_map_entry(l1pagetable, ARM_VECTORS_HIGH, systempage.pv_pa,
+	    VM_PROT_READ|VM_PROT_WRITE|VM_PROT_EXECUTE, PTE_CACHE);
+
+	/* Map pmap_devmap[] entries */
+	err_devmap = platform_devmap_init();
+	pmap_devmap_bootstrap(l1pagetable, pmap_devmap_bootstrap_table);
+
+	cpu_domains((DOMAIN_CLIENT << (PMAP_DOMAIN_KERNEL * 2)) |
+	    DOMAIN_CLIENT);
+	pmap_pa = kernel_l1pt.pv_pa;
+	setttb(kernel_l1pt.pv_pa);
+	cpu_tlb_flushID();
+	cpu_domains(DOMAIN_CLIENT << (PMAP_DOMAIN_KERNEL * 2));
+
+	/*
+	 * Only after the SOC registers block is mapped we can perform device
+	 * tree fixups, as they may attempt to read parameters from hardware.
+	 */
+	OF_interpret("perform-fixup", 0);
+
+	cninit();
+
+	physmem = memsize / PAGE_SIZE;
+
+	debugf("initarm: console initialized\n");
+	debugf(" arg1 kmdp = 0x%08x\n", (uint32_t)kmdp);
+	debugf(" boothowto = 0x%08x\n", boothowto);
+	debugf(" dtbp = 0x%08x\n", (uint32_t)dtbp);
+	print_kernel_section_addr();
+	print_kenv();
+
+	if (err_devmap != 0)
+		printf("WARNING: could not fully configure devmap, error=%d\n",
+			err_devmap);
+
+	/*
+	 * 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_stackptrs(0);
+
+	/*
+	 * 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();
+
+    init_proc0(kernelstack.pv_va);
+	arm_vector_init(ARM_VECTORS_HIGH, ARM_VEC_ALL);
+
+	arm_dump_avail_init(memsize, sizeof(dump_avail) / sizeof(dump_avail[0]));
+	pmap_bootstrap(freemempos, pmap_bootstrap_lastaddr, &kernel_l1pt);
+	msgbufp = (void *)msgbufpv.pv_va;
+	msgbufinit(msgbufp, msgbufsize);
+	mutex_init();
+
+	/*
+	 * Prepare map of physical memory regions available to vm subsystem.
+	 */
+	physmap_init();
+
+	/* Do basic tuning, hz etc */
+	init_param2(physmem);
+	kdb_init();
+
+	return ((void *)(kernelstack.pv_va + USPACE_SVC_STACK_TOP -
+	    sizeof(struct pcb)));
+}
+
+void
+set_stackptrs(int cpu)
+{
+
+	set_stackptr(PSR_IRQ32_MODE,
+	    irqstack.pv_va + ((IRQ_STACK_SIZE * PAGE_SIZE) * (cpu + 1)));
+	set_stackptr(PSR_ABT32_MODE,
+	    abtstack.pv_va + ((ABT_STACK_SIZE * PAGE_SIZE) * (cpu + 1)));
+	set_stackptr(PSR_UND32_MODE,
+	    undstack.pv_va + ((UND_STACK_SIZE * PAGE_SIZE) * (cpu + 1)));
+}
+
+#define FDT_DEVMAP_MAX	(2)		// FIXME
+static struct pmap_devmap fdt_devmap[FDT_DEVMAP_MAX] = {
+	{ 0, 0, 0, 0, 0, }
+};
+
+
+/*
+ * Construct pmap_devmap[] with DT-derived config data.
+ */
+static int
+platform_devmap_init(void)
+{
+	int i = 0;
+#if defined(SOC_OMAP4)
+	fdt_devmap[i].pd_va = 0xE8000000;
+	fdt_devmap[i].pd_pa = 0x48000000;
+	fdt_devmap[i].pd_size = 0x1000000;
+	fdt_devmap[i].pd_prot = VM_PROT_READ | VM_PROT_WRITE;
+	fdt_devmap[i].pd_cache = PTE_DEVICE;
+	i++;
+#elif defined(SOC_TI_AM335X)
+	fdt_devmap[i].pd_va = 0xE4C00000;
+	fdt_devmap[i].pd_pa = 0x44C00000;       /* L4_WKUP */
+	fdt_devmap[i].pd_size = 0x400000;       /* 4 MB */
+	fdt_devmap[i].pd_prot = VM_PROT_READ | VM_PROT_WRITE;
+	fdt_devmap[i].pd_cache = PTE_DEVICE;
+	i++;
+#else
+#error "Unknown SoC"
+#endif
+
+	pmap_devmap_bootstrap_table = &fdt_devmap[0];
+	return (0);
+}
+
+struct arm32_dma_range *
+bus_dma_get_range(void)
+{
+
+	return (NULL);
+}
+
+int
+bus_dma_get_range_nb(void)
+{
+
+	return (0);
+}
+
+void
+cpu_reset()
+{
+	if (ti_cpu_reset)
+		(*ti_cpu_reset)();
+	else
+		printf("no cpu_reset implementation\n");
+	printf("Reset failed!\n");
+	while (1);
+}
+
diff -r 7fffa673adcd -r a301a330526b head/sys/arm/ti/ti_mmchs.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/head/sys/arm/ti/ti_mmchs.c	Wed Aug 15 11:16:36 2012 +0300
@@ -0,0 +1,1839 @@
+/*-
+ * Copyright (c) 2011
+ *	Ben Gray <ben.r.gray at 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.
+ */
+
+/**
+ * Driver for the MMC/SD/SDIO module on the TI OMAP series of SoCs.
+ *
+ * This driver is heavily based on the SD/MMC driver for the AT91 (at91_mci.c).
+ *
+ * It's important to realise that the MMC state machine is already in the kernel
+ * and this driver only exposes the specific interfaces of the controller.
+ *
+ * This driver is still very much a work in progress, I've verified that basic
+ * sector reading can be performed. But I've yet to test it with a file system
+ * or even writing.  In addition I've only tested the driver with an SD card,
+ * I've no idea if MMC cards work.
+ *
+ */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: head/sys/arm/ti/ti_mmchs.c 239281 2012-08-15 06:31:32Z gonzo $");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/bio.h>
+#include <sys/bus.h>
+#include <sys/conf.h>
+#include <sys/endian.h>
+#include <sys/kernel.h>
+#include <sys/kthread.h>
+#include <sys/lock.h>
+#include <sys/malloc.h>
+#include <sys/module.h>
+#include <sys/mutex.h>
+#include <sys/queue.h>
+#include <sys/resource.h>
+#include <sys/rman.h>
+#include <sys/time.h>
+#include <sys/timetc.h>
+#include <sys/gpio.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 <dev/mmc/bridge.h>
+#include <dev/mmc/mmcreg.h>
+#include <dev/mmc/mmcbrvar.h>
+
+#include <dev/fdt/fdt_common.h>
+#include <dev/ofw/openfirm.h>
+#include <dev/ofw/ofw_bus.h>
+#include <dev/ofw/ofw_bus_subr.h>
+
+#include "gpio_if.h"
+
+#include "mmcbr_if.h"
+#include "mmcbus_if.h"
+
+#include <arm/ti/ti_sdma.h>
+#include <arm/ti/ti_edma3.h>
+#include <arm/ti/ti_mmchs.h>
+#include <arm/ti/ti_cpuid.h>
+#include <arm/ti/ti_prcm.h>
+
+#include <arm/ti/twl/twl.h>
+#include <arm/ti/twl/twl_vreg.h>
+
+#ifdef DEBUG
+#define ti_mmchs_dbg(sc, fmt, args...) \
+	device_printf((sc)->sc_dev, fmt, ## args);
+#else
+#define ti_mmchs_dbg(sc, fmt, args...)
+#endif
+
+/**
+ *	Structure that stores the driver context
+ */
+struct ti_mmchs_softc {
+	device_t		sc_dev;
+	uint32_t		device_id;
+	struct resource*	sc_irq_res;
+	struct resource*	sc_mem_res;
+
+	void*			sc_irq_h;
+
+	bus_dma_tag_t		sc_dmatag;
+	bus_dmamap_t		sc_dmamap;
+	int			sc_dmamapped;
+
+	unsigned int		sc_dmach_rd;
+	unsigned int		sc_dmach_wr;
+	int			dma_rx_trig;
+	int			dma_tx_trig;
+
+	device_t		sc_gpio_dev;
+	int			sc_wp_gpio_pin;  /* GPIO pin for MMC write protect */
+
+	device_t		sc_vreg_dev;
+	const char*		sc_vreg_name;
+
+	struct mtx		sc_mtx;
+
+	struct mmc_host		host;
+	struct mmc_request*	req;
+	struct mmc_command*	curcmd;
+
+	int			flags;
+#define CMD_STARTED     1
+#define STOP_STARTED    2
+
+	int			bus_busy;  /* TODO: Needed ? */
+
+	void*			sc_cmd_data_vaddr;
+	int			sc_cmd_data_len;
+
+	/* The offset applied to each of the register base addresses, OMAP4
+	 * register sets are offset 0x100 from the OMAP3 series.
+	 */
+	unsigned long		sc_reg_off;
+
+	/* The physical address of the MMCHS_DATA register, used for the DMA xfers */
+	unsigned long		sc_data_reg_paddr;
+
+	/* The reference clock frequency */
+	unsigned int		sc_ref_freq;
+
+	enum mmc_power_mode	sc_cur_power_mode;
+};
+
+/**
+ *	Macros for driver mutex locking
+ */
+#define TI_MMCHS_LOCK(_sc)              mtx_lock(&(_sc)->sc_mtx)
+#define	TI_MMCHS_UNLOCK(_sc)            mtx_unlock(&(_sc)->sc_mtx)
+#define TI_MMCHS_LOCK_INIT(_sc) \
+	mtx_init(&_sc->sc_mtx, device_get_nameunit(_sc->sc_dev), \
+	         "ti_mmchs", MTX_DEF)
+#define TI_MMCHS_LOCK_DESTROY(_sc)      mtx_destroy(&_sc->sc_mtx);
+#define TI_MMCHS_ASSERT_LOCKED(_sc)     mtx_assert(&_sc->sc_mtx, MA_OWNED);
+#define TI_MMCHS_ASSERT_UNLOCKED(_sc)   mtx_assert(&_sc->sc_mtx, MA_NOTOWNED);
+
+static void ti_mmchs_start(struct ti_mmchs_softc *sc);
+
+/**
+ *	ti_mmchs_read_4 - reads a 32-bit value from a register
+ *	ti_mmchs_write_4 - writes a 32-bit value to a register
+ *	@sc: pointer to the driver context
+ *	@off: register offset to read from
+ *	@val: the value to write into the register
+ *
+ *	LOCKING:
+ *	None
+ *
+ *	RETURNS:
+ *	The 32-bit value read from the register
+ */
+static inline uint32_t
+ti_mmchs_read_4(struct ti_mmchs_softc *sc, bus_size_t off)
+{
+	return bus_read_4(sc->sc_mem_res, (sc->sc_reg_off + off));
+}
+
+static inline void
+ti_mmchs_write_4(struct ti_mmchs_softc *sc, bus_size_t off, uint32_t val)
+{
+	bus_write_4(sc->sc_mem_res, (sc->sc_reg_off + off), val);
+}
+
+/**
+ *	ti_mmchs_reset_controller -
+ *	@arg: caller supplied arg
+ *	@segs: array of segments (although in our case should only be one)
+ *	@nsegs: number of segments (in our case should be 1)
+ *	@error:
+ *
+ *
+ *
+ */
+static void
+ti_mmchs_reset_controller(struct ti_mmchs_softc *sc, uint32_t bit)
+{
+	unsigned long attempts;
+	uint32_t sysctl;
+
+	ti_mmchs_dbg(sc, "reseting controller - bit 0x%08x\n", bit);
+
+	sysctl = ti_mmchs_read_4(sc, MMCHS_SYSCTL);
+	ti_mmchs_write_4(sc, MMCHS_SYSCTL, sysctl | bit);
+
+	if ((ti_chip() == CHIP_OMAP_4) && (ti_revision() > OMAP4430_REV_ES1_0)) {
+		/* OMAP4 ES2 and greater has an updated reset logic.
+		 * Monitor a 0->1 transition first
+		 */
+		attempts = 10000;
+		while (!(ti_mmchs_read_4(sc, MMCHS_SYSCTL) & bit) && (attempts-- > 0))
+			continue;
+	}
+
+	attempts = 10000;
+	while ((ti_mmchs_read_4(sc, MMCHS_SYSCTL) & bit) && (attempts-- > 0))
+		continue;
+
+	if (ti_mmchs_read_4(sc, MMCHS_SYSCTL) & bit)
+		device_printf(sc->sc_dev, "Error - Timeout waiting on controller reset\n");
+}
+
+/**
+ *	ti_mmchs_getaddr - called by the DMA function to simply return the phys addr
+ *	@arg: caller supplied arg
+ *	@segs: array of segments (although in our case should only be one)
+ *	@nsegs: number of segments (in our case should be 1)
+ *	@error:
+ *
+ *	This function is called by bus_dmamap_load() after it has compiled an array
+ *	of segments, each segment is a phsyical chunk of memory. However in our case
+ *	we should only have one segment, because we don't (yet?) support DMA scatter
+ *	gather. To ensure we only have one segment, the DMA tag was created by
+ *	bus_dma_tag_create() (called from ti_mmchs_attach) with nsegments set to 1.
+ *
+ */
+static void
+ti_mmchs_getaddr(void *arg, bus_dma_segment_t *segs, int nsegs, int error)
+{
+	if (error != 0)
+		return;
+
+	*(bus_addr_t *)arg = segs[0].ds_addr;
+}
+
+#ifndef SOC_TI_AM335X
+/**
+ *	ti_mmchs_dma_intr - interrupt handler for DMA events triggered by the controller
+ *	@ch: the dma channel number
+ *	@status: bit field of the status bytes
+ *	@data: callback data, in this case a pointer to the controller struct
+ *
+ *
+ *	LOCKING:
+ *	Called from interrupt context
+ *
+ */
+static void
+ti_mmchs_dma_intr(unsigned int ch, uint32_t status, void *data)
+{
+	/* Ignore for now ... we don't need this interrupt as we already have the
+	 * interrupt from the MMC controller.
+	 */
+}
+#endif
+
+/**
+ *	ti_mmchs_intr_xfer_compl - called if a 'transfer complete' IRQ was received
+ *	@sc: pointer to the driver context
+ *	@cmd: the command that was sent previously
+ *
+ *	This function is simply responsible for syncing up the DMA buffer.
+ *
+ *	LOCKING:
+ *	Called from interrupt context
+ *
+ *	RETURNS:
+ *	Return value indicates if the transaction is complete, not done = 0, done != 0
+ */
+static int
+ti_mmchs_intr_xfer_compl(struct ti_mmchs_softc *sc, struct mmc_command *cmd)
+{
+	uint32_t cmd_reg;
+
+	/* Read command register to test whether this command was a read or write. */
+	cmd_reg = ti_mmchs_read_4(sc, MMCHS_CMD);
+
+	/* Sync-up the DMA buffer so the caller can access the new memory */
+	if (cmd_reg & MMCHS_CMD_DDIR) {
+		bus_dmamap_sync(sc->sc_dmatag, sc->sc_dmamap, BUS_DMASYNC_POSTREAD);
+		bus_dmamap_unload(sc->sc_dmatag, sc->sc_dmamap);
+	}
+	else {
+		bus_dmamap_sync(sc->sc_dmatag, sc->sc_dmamap, BUS_DMASYNC_POSTWRITE);
+		bus_dmamap_unload(sc->sc_dmatag, sc->sc_dmamap);
+	}
+	sc->sc_dmamapped--;
+
+	/* Debugging dump of the data received */
+#if 0
+	{
+		int i;
+		uint8_t *p = (uint8_t*) sc->sc_cmd_data_vaddr;
+		for (i=0; i<sc->sc_cmd_data_len; i++) {
+			if ((i % 16) == 0)
+				printf("\n0x%04x : ", i);
+			printf("%02X ", *p++);
+		}
+		printf("\n");
+	}
+#endif
+
+	/* We are done, transfer complete */
+	return 1;
+}
+
+/**
+ *	ti_mmchs_intr_cmd_compl - called if a 'command complete' IRQ was received
+ *	@sc: pointer to the driver context
+ *	@cmd: the command that was sent previously
+ *
+ *
+ *	LOCKING:
+ *	Called from interrupt context
+ *
+ *	RETURNS:
+ *	Return value indicates if the transaction is complete, not done = 0, done != 0
+ */
+static int
+ti_mmchs_intr_cmd_compl(struct ti_mmchs_softc *sc, struct mmc_command *cmd)
+{
+	uint32_t cmd_reg;
+
+	/* Copy the response into the request struct ... if a response was
+	 * expected */
+	if (cmd != NULL && (cmd->flags & MMC_RSP_PRESENT)) {
+		if (cmd->flags & MMC_RSP_136) {
+			cmd->resp[3] = ti_mmchs_read_4(sc, MMCHS_RSP10);
+			cmd->resp[2] = ti_mmchs_read_4(sc, MMCHS_RSP32);
+			cmd->resp[1] = ti_mmchs_read_4(sc, MMCHS_RSP54);
+			cmd->resp[0] = ti_mmchs_read_4(sc, MMCHS_RSP76);
+		} else {
+			cmd->resp[0] = ti_mmchs_read_4(sc, MMCHS_RSP10);
+		}
+	}
+
+	/* Check if the command was expecting some data transfer, if not
+	 * we are done. */
+	cmd_reg = ti_mmchs_read_4(sc, MMCHS_CMD);
+	return ((cmd_reg & MMCHS_CMD_DP) == 0);
+}
+
+/**
+ *	ti_mmchs_intr_error - handles error interrupts
+ *	@sc: pointer to the driver context
+ *	@cmd: the command that was sent previously
+ *	@stat_reg: the value that was in the status register
+ *
+ *
+ *	LOCKING:
+ *	Called from interrupt context
+ *
+ *	RETURNS:
+ *	Return value indicates if the transaction is complete, not done = 0, done != 0
+ */
+static int
+ti_mmchs_intr_error(struct ti_mmchs_softc *sc, struct mmc_command *cmd,
+					 uint32_t stat_reg)
+{
+	ti_mmchs_dbg(sc, "error in xfer - stat 0x%08x\n", stat_reg);
+
+	/* Ignore CRC errors on CMD2 and ACMD47, per relevant standards */
+	if ((stat_reg & MMCHS_STAT_CCRC) && (cmd->opcode == MMC_SEND_OP_COND ||
+	    cmd->opcode == ACMD_SD_SEND_OP_COND))
+		cmd->error = MMC_ERR_NONE;
+	else if (stat_reg & (MMCHS_STAT_CTO | MMCHS_STAT_DTO))
+		cmd->error = MMC_ERR_TIMEOUT;
+	else if (stat_reg & (MMCHS_STAT_CCRC | MMCHS_STAT_DCRC))
+		cmd->error = MMC_ERR_BADCRC;
+	else
+		cmd->error = MMC_ERR_FAILED;
+
+	/* If a dma transaction we should also stop the dma transfer */
+	if (ti_mmchs_read_4(sc, MMCHS_CMD) & MMCHS_CMD_DE) {
+
+		/* Abort the DMA transfer (DDIR bit tells direction) */
+		if (ti_mmchs_read_4(sc, MMCHS_CMD) & MMCHS_CMD_DDIR)
+#ifdef SOC_TI_AM335X
+			printf("%s: DMA unimplemented\n", __func__);
+#else
+			ti_sdma_stop_xfer(sc->sc_dmach_rd);
+#endif
+		else
+#ifdef SOC_TI_AM335X
+			printf("%s: DMA unimplemented\n", __func__);
+#else
+			ti_sdma_stop_xfer(sc->sc_dmach_wr);
+#endif
+
+		/* If an error occure abort the DMA operation and free the dma map */
+		if ((sc->sc_dmamapped > 0) && (cmd->error != MMC_ERR_NONE)) {
+			bus_dmamap_unload(sc->sc_dmatag, sc->sc_dmamap);
+			sc->sc_dmamapped--;
+		}
+	}
+
+	/* Command error occured? ... if so issue a soft reset for the cmd fsm */
+	if (stat_reg & (MMCHS_STAT_CCRC | MMCHS_STAT_CTO)) {
+		ti_mmchs_reset_controller(sc, MMCHS_SYSCTL_SRC);
+	}
+
+	/* Data error occured? ... if so issue a soft reset for the data line */
+	if (stat_reg & (MMCHS_STAT_DEB | MMCHS_STAT_DCRC | MMCHS_STAT_DTO)) {
+		ti_mmchs_reset_controller(sc, MMCHS_SYSCTL_SRD);
+	}
+
+	/* On any error the command is cancelled ... so we are done */
+	return 1;
+}
+
+/**
+ *	ti_mmchs_intr - interrupt handler for MMC/SD/SDIO controller
+ *	@arg: pointer to the driver context
+ *
+ *	Interrupt handler for the MMC/SD/SDIO controller, responsible for handling
+ *	the IRQ and clearing the status flags.
+ *
+ *	LOCKING:
+ *	Called from interrupt context
+ *
+ *	RETURNS:
+ *	nothing
+ */
+static void
+ti_mmchs_intr(void *arg)
+{
+	struct ti_mmchs_softc *sc = (struct ti_mmchs_softc *) arg;
+	uint32_t stat_reg;
+	int done = 0;
+
+	TI_MMCHS_LOCK(sc);
+
+	stat_reg = ti_mmchs_read_4(sc, MMCHS_STAT) & (ti_mmchs_read_4(sc,
+	    MMCHS_IE) | MMCHS_STAT_ERRI);
+
+	if (sc->curcmd == NULL) {
+		device_printf(sc->sc_dev, "Error: current cmd NULL, already done?\n");
+		ti_mmchs_write_4(sc, MMCHS_STAT, stat_reg);
+		TI_MMCHS_UNLOCK(sc);
+		return;
+	}
+
+	if (stat_reg & MMCHS_STAT_ERRI) {
+		/* An error has been tripped in the status register */
+		done = ti_mmchs_intr_error(sc, sc->curcmd, stat_reg);
+
+	} else {
+
+		/* NOTE: This implementation could be a bit inefficent, I don't think
+		 * it is necessary to handle both the 'command complete' and 'transfer
+		 * complete' for data transfers ... presumably just transfer complete
+		 * is enough.
+		 */
+
+		/* No error */
+		sc->curcmd->error = MMC_ERR_NONE;
+
+		/* Check if the command completed */
+		if (stat_reg & MMCHS_STAT_CC) {
+			done = ti_mmchs_intr_cmd_compl(sc, sc->curcmd);
+		}
+
+		/* Check if the transfer has completed */
+		if (stat_reg & MMCHS_STAT_TC) {
+			done = ti_mmchs_intr_xfer_compl(sc, sc->curcmd);
+		}
+
+	}
+
+	/* Clear all the interrupt status bits by writing the value back */
+	ti_mmchs_write_4(sc, MMCHS_STAT, stat_reg);
+
+	/* This may mark the command as done if there is no stop request */
+	/* TODO: This is a bit ugly, needs fix-up */
+	if (done) {
+		ti_mmchs_start(sc);
+	}
+
+	TI_MMCHS_UNLOCK(sc);
+}
+
+#ifdef SOC_TI_AM335X
+static void
+ti_mmchs_edma3_rx_xfer_setup(struct ti_mmchs_softc *sc, uint32_t src_paddr,
+    uint32_t dst_paddr, uint16_t blk_size, uint16_t num_blks)
+{
+	struct ti_edma3cc_param_set ps;
+
+	bzero(&ps, sizeof(struct ti_edma3cc_param_set));
+	ps.src		= src_paddr;
+	ps.dst		= dst_paddr;
+	ps.dstbidx	= 4;
+	ps.dstcidx	= blk_size;
+	ps.acnt		= 4;
+	ps.bcnt		= blk_size/4;
+	ps.ccnt		= num_blks;
+	ps.link		= 0xffff;
+	ps.opt.tcc	= sc->dma_rx_trig;
+	ps.opt.tcinten	= 1;
+	ps.opt.fwid	= 2; /* fifo width is 32 */
+	ps.opt.sam	= 1;
+	ps.opt.syncdim	= 1;
+
+	ti_edma3_param_write(sc->dma_rx_trig, &ps);
+	ti_edma3_enable_transfer_event(sc->dma_rx_trig);
+}
+
+static void
+ti_mmchs_edma3_tx_xfer_setup(struct ti_mmchs_softc *sc, uint32_t src_paddr,
+    uint32_t dst_paddr, uint16_t blk_size, uint16_t num_blks)
+{
+	struct ti_edma3cc_param_set ps;
+
+	bzero(&ps, sizeof(struct ti_edma3cc_param_set));
+	ps.src		= src_paddr;
+	ps.dst		= dst_paddr;
+	ps.srccidx	= blk_size;
+	ps.bcnt		= blk_size/4;
+	ps.ccnt		= num_blks;
+	ps.srcbidx	= 4;
+	ps.acnt		= 0x4;
+	ps.link		= 0xffff;
+	ps.opt.tcc	= sc->dma_tx_trig;
+	ps.opt.tcinten	= 1;
+	ps.opt.fwid	= 2; /* fifo width is 32 */
+	ps.opt.dam	= 1;
+	ps.opt.syncdim	= 1;
+
+	ti_edma3_param_write(sc->dma_tx_trig, &ps);
+	ti_edma3_enable_transfer_event(sc->dma_tx_trig);
+}
+#endif
+
+/**
+ *	ti_mmchs_start_cmd - starts the given command
+ *	@sc: pointer to the driver context
+ *	@cmd: the command to start
+ *
+ *	The call tree for this function is
+ *		- ti_mmchs_start_cmd
+ *			- ti_mmchs_start
+ *				- ti_mmchs_request
+ *
+ *	LOCKING:
+ *	Caller should be holding the OMAP_MMC lock.
+ *
+ *	RETURNS:
+ *	nothing
+ */
+static void
+ti_mmchs_start_cmd(struct ti_mmchs_softc *sc, struct mmc_command *cmd)
+{
+	uint32_t cmd_reg, con_reg, ise_reg;
+	struct mmc_data *data;
+	struct mmc_request *req;
+	void *vaddr;
+	bus_addr_t paddr;
+#ifndef SOC_TI_AM335X
+	uint32_t pktsize;
+#endif
+	sc->curcmd = cmd;
+	data = cmd->data;
+	req = cmd->mrq;
+
+	/* Ensure the STR and MIT bits are cleared, these are only used for special
+	 * command types.
+	 */
+	con_reg = ti_mmchs_read_4(sc, MMCHS_CON);
+	con_reg &= ~(MMCHS_CON_STR | MMCHS_CON_MIT);
+
+	/* Load the command into bits 29:24 of the CMD register */
+	cmd_reg = (uint32_t)(cmd->opcode & 0x3F) << 24;
+
+	/* Set the default set of interrupts */
+	ise_reg = (MMCHS_STAT_CERR | MMCHS_STAT_CTO | MMCHS_STAT_CC | MMCHS_STAT_CEB);
+
+	/* Enable CRC checking if requested */
+	if (cmd->flags & MMC_RSP_CRC)
+		ise_reg |= MMCHS_STAT_CCRC;
+
+	/* Enable reply index checking if the response supports it */
+	if (cmd->flags & MMC_RSP_OPCODE)
+		ise_reg |= MMCHS_STAT_CIE;
+
+	/* Set the expected response length */
+	if (MMC_RSP(cmd->flags) == MMC_RSP_NONE) {
+		cmd_reg |= MMCHS_CMD_RSP_TYPE_NO;
+	} else {
+		if (cmd->flags & MMC_RSP_136)
+			cmd_reg |= MMCHS_CMD_RSP_TYPE_136;
+		else if (cmd->flags & MMC_RSP_BUSY)
+			cmd_reg |= MMCHS_CMD_RSP_TYPE_48_BSY;
+		else
+			cmd_reg |= MMCHS_CMD_RSP_TYPE_48;
+
+		/* Enable command index/crc checks if necessary expected */
+		if (cmd->flags & MMC_RSP_CRC)
+			cmd_reg |= MMCHS_CMD_CCCE;
+		if (cmd->flags & MMC_RSP_OPCODE)
+			cmd_reg |= MMCHS_CMD_CICE;
+	}
+
+	/* Set the bits for the special commands CMD12 (MMC_STOP_TRANSMISSION) and
+	 * CMD52 (SD_IO_RW_DIRECT) */
+	if (cmd->opcode == MMC_STOP_TRANSMISSION)
+		cmd_reg |= MMCHS_CMD_CMD_TYPE_IO_ABORT;
+
+	/* Check if there is any data to write */
+	if (data == NULL) {
+		/* Clear the block count */
+		ti_mmchs_write_4(sc, MMCHS_BLK, 0);
+
+		/* The no data case is fairly simple */
+		ti_mmchs_write_4(sc, MMCHS_CON, con_reg);
+		ti_mmchs_write_4(sc, MMCHS_IE, ise_reg);
+		ti_mmchs_write_4(sc, MMCHS_ISE, ise_reg);
+		ti_mmchs_write_4(sc, MMCHS_ARG, cmd->arg);
+		ti_mmchs_write_4(sc, MMCHS_CMD, cmd_reg);
+		return;
+	}
+
+	/* Indicate that data is present */
+	cmd_reg |= MMCHS_CMD_DP | MMCHS_CMD_MSBS | MMCHS_CMD_BCE;
+
+	/* Indicate a read operation */
+	if (data->flags & MMC_DATA_READ)
+		cmd_reg |= MMCHS_CMD_DDIR;
+
+	/* Streaming mode */
+	if (data->flags & MMC_DATA_STREAM) {
+		con_reg |= MMCHS_CON_STR;
+	}
+
+	/* Multi-block mode */
+	if (data->flags & MMC_DATA_MULTI) {
+		cmd_reg |= MMCHS_CMD_MSBS;
+	}
+
+	/* Enable extra interrupt sources for the transfer */
+	ise_reg |= (MMCHS_STAT_TC | MMCHS_STAT_DTO | MMCHS_STAT_DEB | MMCHS_STAT_CEB);
+	if (cmd->flags & MMC_RSP_CRC)
+		ise_reg |= MMCHS_STAT_DCRC;
+
+	/* Enable the DMA transfer bit */
+	cmd_reg |= MMCHS_CMD_DE;
+
+	/* Set the block size and block count */
+	ti_mmchs_write_4(sc, MMCHS_BLK, (1 << 16) | data->len);
+
+	/* Setup the DMA stuff */
+	if (data->flags & (MMC_DATA_READ | MMC_DATA_WRITE)) {
+
+		vaddr = data->data;
+		data->xfer_len = 0;
+
+		/* Map the buffer buf into bus space using the dmamap map. */
+		if (bus_dmamap_load(sc->sc_dmatag, sc->sc_dmamap, vaddr, data->len,
+		    ti_mmchs_getaddr, &paddr, 0) != 0) {
+
+			if (req->cmd->flags & STOP_STARTED)
+				req->stop->error = MMC_ERR_NO_MEMORY;
+			else
+				req->cmd->error = MMC_ERR_NO_MEMORY;
+			sc->req = NULL;
+			sc->curcmd = NULL;
+			req->done(req);
+			return;
+		}
+
+#ifndef SOC_TI_AM335X
+		/* Calculate the packet size, the max packet size is 512 bytes
+		 * (or 128 32-bit elements).
+		 */
+		pktsize = min((data->len / 4), (512 / 4));
+#endif
+		/* Sync the DMA buffer and setup the DMA controller */
+		if (data->flags & MMC_DATA_READ) {
+			bus_dmamap_sync(sc->sc_dmatag, sc->sc_dmamap, BUS_DMASYNC_PREREAD);
+#ifdef SOC_TI_AM335X
+			ti_mmchs_edma3_rx_xfer_setup(sc, sc->sc_data_reg_paddr, 
+			    paddr, data->len, 1);
+#else
+			ti_sdma_start_xfer_packet(sc->sc_dmach_rd, sc->sc_data_reg_paddr,
+			    paddr, 1, (data->len / 4), pktsize);
+#endif
+		} else {
+			bus_dmamap_sync(sc->sc_dmatag, sc->sc_dmamap, BUS_DMASYNC_PREWRITE);
+#ifdef SOC_TI_AM335X
+			ti_mmchs_edma3_tx_xfer_setup(sc, paddr,
+			    sc->sc_data_reg_paddr, data->len, 1);
+#else
+			ti_sdma_start_xfer_packet(sc->sc_dmach_wr, paddr,
+			    sc->sc_data_reg_paddr, 1, (data->len / 4), pktsize);
+#endif
+		}
+
+		/* Increase the mapped count */
+		sc->sc_dmamapped++;
+
+		sc->sc_cmd_data_vaddr = vaddr;
+		sc->sc_cmd_data_len = data->len;
+	}
+
+	/* Finally kick off the command */
+	ti_mmchs_write_4(sc, MMCHS_CON, con_reg);
+	ti_mmchs_write_4(sc, MMCHS_IE, ise_reg);
+	ti_mmchs_write_4(sc, MMCHS_ISE, ise_reg);
+	ti_mmchs_write_4(sc, MMCHS_ARG, cmd->arg);
+	ti_mmchs_write_4(sc, MMCHS_CMD, cmd_reg);
+
+	/* and we're done */
+}
+
+/**
+ *	ti_mmchs_start - starts a request stored in the driver context
+ *	@sc: pointer to the driver context
+ *
+ *	This function is called by ti_mmchs_request() in response to a read/write
+ *	request from the MMC core module.
+ *
+ *	LOCKING:
+ *	Caller should be holding the OMAP_MMC lock.
+ *
+ *	RETURNS:
+ *	nothing
+ */
+static void
+ti_mmchs_start(struct ti_mmchs_softc *sc)
+{
+	struct mmc_request *req;
+
+	/* Sanity check we have a request */
+	req = sc->req;
+	if (req == NULL)
+		return;
+
+	/* assert locked */
+	if (!(sc->flags & CMD_STARTED)) {
+		sc->flags |= CMD_STARTED;
+		ti_mmchs_start_cmd(sc, req->cmd);
+		return;
+	}
+
+	if (!(sc->flags & STOP_STARTED) && req->stop) {
+		sc->flags |= STOP_STARTED;
+		ti_mmchs_start_cmd(sc, req->stop);
+		return;
+	}
+
+	/* We must be done -- bad idea to do this while locked? */
+	sc->req = NULL;
+	sc->curcmd = NULL;
+	req->done(req);
+}
+
+/**
+ *	ti_mmchs_request - entry point for all read/write/cmd requests
+ *	@brdev: mmc bridge device handle
+ *	@reqdev: the device doing the requesting ?
+ *	@req: the action requested
+ *
+ *	LOCKING:
+ *	None, internally takes the OMAP_MMC lock.
+ *
+ *	RETURNS:
+ *	0 on success
+ *	EBUSY if the driver is already performing a request
+ */
+static int
+ti_mmchs_request(device_t brdev, device_t reqdev, struct mmc_request *req)
+{
+	struct ti_mmchs_softc *sc = device_get_softc(brdev);
+
+	TI_MMCHS_LOCK(sc);
+
+	/*
+	 * XXX do we want to be able to queue up multiple commands?
+	 * XXX sounds like a good idea, but all protocols are sync, so
+	 * XXX maybe the idea is naive...
+	 */
+	if (sc->req != NULL) {
+		TI_MMCHS_UNLOCK(sc);
+		return (EBUSY);
+	}
+
+	/* Store the request and start the command */
+	sc->req = req;
+	sc->flags = 0;
+	ti_mmchs_start(sc);
+
+	TI_MMCHS_UNLOCK(sc);
+
+	return (0);
+}
+
+/**
+ *	ti_mmchs_get_ro - returns the status of the read-only setting
+ *	@brdev: mmc bridge device handle
+ *	@reqdev: device doing the request
+ *
+ *	This function is relies on hint'ed values to determine which GPIO is used
+ *	to determine if the write protect is enabled. On the BeagleBoard the pin
+ *	is GPIO_23.
+ *
+ *	LOCKING:
+ *	-
+ *
+ *	RETURNS:
+ *	0 if not read-only
+ *	1 if read only
+ */
+static int
+ti_mmchs_get_ro(device_t brdev, device_t reqdev)
+{
+	struct ti_mmchs_softc *sc = device_get_softc(brdev);
+	unsigned int readonly = 0;
+
+	TI_MMCHS_LOCK(sc);
+
+	if ((sc->sc_wp_gpio_pin != -1) && (sc->sc_gpio_dev != NULL)) {
+		if (GPIO_PIN_GET(sc->sc_gpio_dev, sc->sc_wp_gpio_pin, &readonly) != 0)
+			readonly = 0;
+		else
+			readonly = (readonly == 0) ? 0 : 1;
+	}
+
+	TI_MMCHS_UNLOCK(sc);
+
+	return (readonly);
+}
+
+/**
+ *	ti_mmchs_send_init_stream - sets bus/controller settings
+ *	@brdev: mmc bridge device handle
+ *	@reqdev: device doing the request
+ *
+ *	Send init stream sequence to card before sending IDLE command
+ *
+ *	LOCKING:
+ *
+ *
+ *	RETURNS:
+ *	0 if function succeeded
+ */
+static void
+ti_mmchs_send_init_stream(struct ti_mmchs_softc *sc)
+{
+	unsigned long timeout;
+	uint32_t ie, ise, con;
+
+	ti_mmchs_dbg(sc, "Performing init sequence\n");
+
+	/* Prior to issuing any command, the MMCHS controller has to execute a
+	 * special INIT procedure. The MMCHS controller has to generate a clock
+	 * during 1ms. During the INIT procedure, the MMCHS controller generates 80
+	 * clock periods. In order to keep the 1ms gap, the MMCHS controller should
+	 * be configured to generate a clock whose frequency is smaller or equal to
+	 * 80 KHz. If the MMCHS controller divider bitfield width doesn't allow to
+	 * choose big values, the MMCHS controller driver should perform the INIT
+	 * procedure twice or three times. Twice is generally enough.
+	 *
+	 * The INIt procedure is executed by setting MMCHS1.MMCHS_CON[1] INIT
+	 * bitfield to 1 and by sending a dummy command, writing 0x00000000 in
+	 * MMCHS1.MMCHS_CMD register.
+	 */
+
+	/* Disable interrupt status events but enable interrupt generation.
+	 * This doesn't seem right to me, but if the interrupt generation is not
+	 * enabled the CC bit doesn't seem to be set in the STAT register.
+	 */
+
+	/* Enable interrupt generation */
+	ie = ti_mmchs_read_4(sc, MMCHS_IE);
+	ti_mmchs_write_4(sc, MMCHS_IE, 0x307F0033);
+
+	/* Disable generation of status events (stops interrupt triggering) */
+	ise = ti_mmchs_read_4(sc, MMCHS_ISE);
+	ti_mmchs_write_4(sc, MMCHS_ISE, 0);
+
+	/* Set the initialise stream bit */
+	con = ti_mmchs_read_4(sc, MMCHS_CON);
+	con |= MMCHS_CON_INIT;
+	ti_mmchs_write_4(sc, MMCHS_CON, con);
+
+	/* Write a dummy command 0x00 */
+	ti_mmchs_write_4(sc, MMCHS_CMD, 0x00000000);
+
+	/* Loop waiting for the command to finish */
+	timeout = hz;
+	do {
+		pause("MMCINIT", 1);
+		if (timeout-- == 0) {
+			device_printf(sc->sc_dev, "Error: first stream init timed out\n");
+			break;
+		}
+	} while (!(ti_mmchs_read_4(sc, MMCHS_STAT) & MMCHS_STAT_CC));
+
+	/* Clear the command complete status bit */
+	ti_mmchs_write_4(sc, MMCHS_STAT, MMCHS_STAT_CC);
+
+	/* Write another dummy command 0x00 */
+	ti_mmchs_write_4(sc, MMCHS_CMD, 0x00000000);
+
+	/* Loop waiting for the second command to finish */
+	timeout = hz;
+	do {
+		pause("MMCINIT", 1);
+		if (timeout-- == 0) {
+			device_printf(sc->sc_dev, "Error: second stream init timed out\n");
+			break;
+		}
+	} while (!(ti_mmchs_read_4(sc, MMCHS_STAT) & MMCHS_STAT_CC));
+
+	/* Clear the stream init bit */
+	con &= ~MMCHS_CON_INIT;
+	ti_mmchs_write_4(sc, MMCHS_CON, con);
+
+	/* Clear the status register, then restore the IE and ISE registers */
+	ti_mmchs_write_4(sc, MMCHS_STAT, 0xffffffff);
+	ti_mmchs_read_4(sc, MMCHS_STAT);
+
+	ti_mmchs_write_4(sc, MMCHS_ISE, ise);
+	ti_mmchs_write_4(sc, MMCHS_IE, ie);
+}
+
+/**
+ *	ti_mmchs_update_ios - sets bus/controller settings
+ *	@brdev: mmc bridge device handle
+ *	@reqdev: device doing the request
+ *
+ *	Called to set the bus and controller settings that need to be applied to
+ *	the actual HW.  Currently this function just sets the bus width and the
+ *	clock speed.
+ *
+ *	LOCKING:
+ *
+ *
+ *	RETURNS:
+ *	0 if function succeeded
+ */
+static int
+ti_mmchs_update_ios(device_t brdev, device_t reqdev)
+{
+	struct ti_mmchs_softc *sc;
+	struct mmc_host *host;
+	struct mmc_ios *ios;
+	uint32_t clkdiv;
+	uint32_t hctl_reg;
+	uint32_t con_reg;
+	uint32_t sysctl_reg;
+#ifndef SOC_TI_AM335X
+	uint16_t mv;
+#endif
+	unsigned long timeout;
+	int do_card_init = 0;
+
+	sc = device_get_softc(brdev);
+	host = &sc->host;
+	ios = &host->ios;
+
+	/* Read the initial values of the registers */
+	hctl_reg = ti_mmchs_read_4(sc, MMCHS_HCTL);
+	con_reg = ti_mmchs_read_4(sc, MMCHS_CON);
+
+	/* Set the bus width */
+	switch (ios->bus_width) {
+		case bus_width_1:
+			hctl_reg &= ~MMCHS_HCTL_DTW;
+			con_reg &= ~MMCHS_CON_DW8;
+			break;
+		case bus_width_4:
+			hctl_reg |= MMCHS_HCTL_DTW;
+			con_reg &= ~MMCHS_CON_DW8;
+			break;
+		case bus_width_8:
+			con_reg |= MMCHS_CON_DW8;
+			break;
+	}
+
+	/* Finally write all these settings back to the registers */
+	ti_mmchs_write_4(sc, MMCHS_HCTL, hctl_reg);
+	ti_mmchs_write_4(sc, MMCHS_CON, con_reg);
+
+	/* Check if we need to change the external voltage regulator */
+	if (sc->sc_cur_power_mode != ios->power_mode) {
+
+		if (ios->power_mode == power_up) {
+
+			/* Set the power level */
+			hctl_reg = ti_mmchs_read_4(sc, MMCHS_HCTL);
+			hctl_reg &= ~(MMCHS_HCTL_SDVS_MASK | MMCHS_HCTL_SDBP);
+
+			if ((ios->vdd == -1) || (ios->vdd >= vdd_240)) {
+#ifndef SOC_TI_AM335X
+				mv = 3000;
+#endif
+				hctl_reg |= MMCHS_HCTL_SDVS_V30;
+			} else {
+#ifndef SOC_TI_AM335X
+				mv = 1800;
+#endif
+				hctl_reg |= MMCHS_HCTL_SDVS_V18;
+			}
+
+			ti_mmchs_write_4(sc, MMCHS_HCTL, hctl_reg);
+
+#ifdef SOC_TI_AM335X
+			printf("%s: TWL unimplemented\n", __func__);
+#else
+			/* Set the desired voltage on the regulator */
+			if (sc->sc_vreg_dev && sc->sc_vreg_name)
+				twl_vreg_set_voltage(sc->sc_vreg_dev, sc->sc_vreg_name, mv);
+#endif
+			/* Enable the bus power */
+			ti_mmchs_write_4(sc, MMCHS_HCTL, (hctl_reg | MMCHS_HCTL_SDBP));
+			timeout = hz;
+			while (!(ti_mmchs_read_4(sc, MMCHS_HCTL) & MMCHS_HCTL_SDBP)) {
+				if (timeout-- == 0)
+					break;
+				pause("MMC_PWRON", 1);
+			}
+
+		} else if (ios->power_mode == power_off) {
+			/* Disable the bus power */
+			hctl_reg = ti_mmchs_read_4(sc, MMCHS_HCTL);
+			ti_mmchs_write_4(sc, MMCHS_HCTL, (hctl_reg & ~MMCHS_HCTL_SDBP));
+
+#ifdef SOC_TI_AM335X
+			printf("%s: TWL unimplemented\n", __func__);
+#else
+			/* Turn the power off on the voltage regulator */
+			if (sc->sc_vreg_dev && sc->sc_vreg_name)
+				twl_vreg_set_voltage(sc->sc_vreg_dev, sc->sc_vreg_name, 0);
+#endif
+		} else if (ios->power_mode == power_on) {
+			/* Force a card re-initialisation sequence */
+			do_card_init = 1;
+		}
+
+		/* Save the new power state */
+		sc->sc_cur_power_mode = ios->power_mode;
+	}
+
+	/* need the MMCHS_SYSCTL register */
+	sysctl_reg = ti_mmchs_read_4(sc, MMCHS_SYSCTL);
+
+	/* Just in case this hasn't been setup before, set the timeout to the default */
+	sysctl_reg &= ~MMCHS_SYSCTL_DTO_MASK;
+	sysctl_reg |= MMCHS_SYSCTL_DTO(0xe);
+
+	/* Disable the clock output while configuring the new clock */
+	sysctl_reg &= ~(MMCHS_SYSCTL_ICE | MMCHS_SYSCTL_CEN);
+	ti_mmchs_write_4(sc, MMCHS_SYSCTL, sysctl_reg);
+
+	/* bus mode? */
+	if (ios->clock == 0) {
+		clkdiv = 0;
+	} else {
+		clkdiv = sc->sc_ref_freq / ios->clock;
+		if (clkdiv < 1)
+			clkdiv = 1;
+		if ((sc->sc_ref_freq / clkdiv) > ios->clock)
+			clkdiv += 1;
+		if (clkdiv > 250)
+			clkdiv = 250;
+	}
+
+	/* Set the new clock divider */
+	sysctl_reg &= ~MMCHS_SYSCTL_CLKD_MASK;
+	sysctl_reg |= MMCHS_SYSCTL_CLKD(clkdiv);
+
+	/* Write the new settings ... */
+	ti_mmchs_write_4(sc, MMCHS_SYSCTL, sysctl_reg);
+	/* ... write the internal clock enable bit ... */
+	ti_mmchs_write_4(sc, MMCHS_SYSCTL, sysctl_reg | MMCHS_SYSCTL_ICE);
+	/* ... wait for the clock to stablise ... */
+	while (((sysctl_reg = ti_mmchs_read_4(sc, MMCHS_SYSCTL)) &
+	    MMCHS_SYSCTL_ICS) == 0) {
+		continue;
+	}
+	/* ... then enable */
+	sysctl_reg |= MMCHS_SYSCTL_CEN;
+	ti_mmchs_write_4(sc, MMCHS_SYSCTL, sysctl_reg);
+
+	/* If the power state has changed to 'power_on' then run the init sequence*/
+	if (do_card_init) {
+		ti_mmchs_send_init_stream(sc);
+	}
+
+	/* Set the bus mode (opendrain or normal) */
+	con_reg = ti_mmchs_read_4(sc, MMCHS_CON);
+	if (ios->bus_mode == opendrain)
+		con_reg |= MMCHS_CON_OD;
+	else
+		con_reg &= ~MMCHS_CON_OD;
+	ti_mmchs_write_4(sc, MMCHS_CON, con_reg);
+
+	return (0);
+}
+
+/**
+ *	ti_mmchs_acquire_host -
+ *	@brdev: mmc bridge device handle
+ *	@reqdev: device doing the request
+ *
+ *	TODO: Is this function needed ?
+ *
+ *	LOCKING:
+ *	none
+ *
+ *	RETURNS:
+ *	0 function succeeded
+ *
+ */
+static int
+ti_mmchs_acquire_host(device_t brdev, device_t reqdev)
+{
+	struct ti_mmchs_softc *sc = device_get_softc(brdev);
+	int err = 0;
+
+	TI_MMCHS_LOCK(sc);
+
+	while (sc->bus_busy) {
+		msleep(sc, &sc->sc_mtx, PZERO, "mmc", hz / 5);
+	}
+
+	sc->bus_busy++;
+
+	TI_MMCHS_UNLOCK(sc);
+
+	return (err);
+}
+
+/**
+ *	ti_mmchs_release_host -
+ *	@brdev: mmc bridge device handle
+ *	@reqdev: device doing the request
+ *
+ *	TODO: Is this function needed ?
+ *
+ *	LOCKING:
+ *	none
+ *
+ *	RETURNS:
+ *	0 function succeeded
+ *
+ */
+static int
+ti_mmchs_release_host(device_t brdev, device_t reqdev)
+{
+	struct ti_mmchs_softc *sc = device_get_softc(brdev);
+
+	TI_MMCHS_LOCK(sc);
+
+	sc->bus_busy--;
+	wakeup(sc);
+
+	TI_MMCHS_UNLOCK(sc);
+
+	return (0);
+}
+
+/**
+ *	ti_mmchs_read_ivar - returns driver conf variables
+ *	@bus:
+ *	@child:
+ *	@which: The variable to get the result for
+ *	@result: Upon return will store the variable value
+ *
+ *
+ *
+ *	LOCKING:
+ *	None, caller must hold locks
+ *
+ *	RETURNS:
+ *	0 on success
+ *	EINVAL if the variable requested is invalid
+ */
+static int
+ti_mmchs_read_ivar(device_t bus, device_t child, int which, uintptr_t *result)
+{
+	struct ti_mmchs_softc *sc = device_get_softc(bus);
+
+	switch (which) {
+		case MMCBR_IVAR_BUS_MODE:
+			*(int *)result = sc->host.ios.bus_mode;
+			break;
+		case MMCBR_IVAR_BUS_WIDTH:
+			*(int *)result = sc->host.ios.bus_width;
+			break;
+		case MMCBR_IVAR_CHIP_SELECT:
+			*(int *)result = sc->host.ios.chip_select;
+			break;
+		case MMCBR_IVAR_CLOCK:
+			*(int *)result = sc->host.ios.clock;
+			break;
+		case MMCBR_IVAR_F_MIN:
+			*(int *)result = sc->host.f_min;
+			break;
+		case MMCBR_IVAR_F_MAX:
+			*(int *)result = sc->host.f_max;
+			break;
+		case MMCBR_IVAR_HOST_OCR:
+			*(int *)result = sc->host.host_ocr;
+			break;
+		case MMCBR_IVAR_MODE:
+			*(int *)result = sc->host.mode;
+			break;
+		case MMCBR_IVAR_OCR:
+			*(int *)result = sc->host.ocr;
+			break;
+		case MMCBR_IVAR_POWER_MODE:
+			*(int *)result = sc->host.ios.power_mode;
+			break;
+		case MMCBR_IVAR_VDD:
+			*(int *)result = sc->host.ios.vdd;
+			break;
+		case MMCBR_IVAR_CAPS:
+			*(int *)result = sc->host.caps;
+			break;
+		case MMCBR_IVAR_MAX_DATA:
+			*(int *)result = 1;
+			break;
+		default:
+			return (EINVAL);
+	}
+	return (0);
+}
+
+/**
+ *	ti_mmchs_write_ivar - writes a driver conf variables
+ *	@bus:
+ *	@child:
+ *	@which: The variable to set
+ *	@value: The value to write into the variable
+ *
+ *
+ *
+ *	LOCKING:
+ *	None, caller must hold locks
+ *
+ *	RETURNS:
+ *	0 on success
+ *	EINVAL if the variable requested is invalid
+ */
+static int
+ti_mmchs_write_ivar(device_t bus, device_t child, int which, uintptr_t value)
+{
+	struct ti_mmchs_softc *sc = device_get_softc(bus);
+
+	switch (which) {
+		case MMCBR_IVAR_BUS_MODE:
+			sc->host.ios.bus_mode = value;
+			break;
+		case MMCBR_IVAR_BUS_WIDTH:
+			sc->host.ios.bus_width = value;
+			break;
+		case MMCBR_IVAR_CHIP_SELECT:
+			sc->host.ios.chip_select = value;
+			break;
+		case MMCBR_IVAR_CLOCK:
+			sc->host.ios.clock = value;
+			break;
+		case MMCBR_IVAR_MODE:
+			sc->host.mode = value;
+			break;
+		case MMCBR_IVAR_OCR:
+			sc->host.ocr = value;
+			break;
+		case MMCBR_IVAR_POWER_MODE:
+			sc->host.ios.power_mode = value;
+			break;
+		case MMCBR_IVAR_VDD:
+			sc->host.ios.vdd = value;
+			break;
+			/* These are read-only */
+		case MMCBR_IVAR_CAPS:
+		case MMCBR_IVAR_HOST_OCR:
+		case MMCBR_IVAR_F_MIN:
+		case MMCBR_IVAR_F_MAX:
+		case MMCBR_IVAR_MAX_DATA:
+			return (EINVAL);
+		default:
+			return (EINVAL);
+	}
+	return (0);
+}
+
+/**
+ *	ti_mmchs_hw_init - initialises the MMC/SD/SIO controller
+ *	@dev: mmc device handle
+ *
+ *	Called by the driver attach function during driver initialisation. This
+ *	function is responsibly to setup the controller ready for transactions.
+ *
+ *	LOCKING:
+ *	No locking, assumed to only be called during initialisation.
+ *
+ *	RETURNS:
+ *	nothing
+ */
+static void
+ti_mmchs_hw_init(device_t dev)
+{
+	struct ti_mmchs_softc *sc = device_get_softc(dev);
+	clk_ident_t clk;
+	unsigned long timeout;
+	uint32_t sysctl;
+	uint32_t capa;
+	uint32_t con;
+
+	/* 1: Enable the controller and interface/functional clocks */
+	clk = MMC0_CLK + sc->device_id;
+
+	if (ti_prcm_clk_enable(clk) != 0) {
+		device_printf(dev, "Error: failed to enable MMC clock\n");
+		return;
+	}
+
+	/* 1a: Get the frequency of the source clock */
+	if (ti_prcm_clk_get_source_freq(clk, &sc->sc_ref_freq) != 0) {
+		device_printf(dev, "Error: failed to get source clock freq\n");
+		return;
+	}
+
+	/* 2: Issue a softreset to the controller */
+	ti_mmchs_write_4(sc, MMCHS_SYSCONFIG, 0x0002);
+	timeout = 100;
+	while ((ti_mmchs_read_4(sc, MMCHS_SYSSTATUS) & 0x01) == 0x0) {
+		DELAY(1000);
+		if (timeout-- == 0) {
+			device_printf(dev, "Error: reset operation timed out\n");
+			return;
+		}
+	}
+
+	/* 3: Reset both the command and data state machines */
+	sysctl = ti_mmchs_read_4(sc, MMCHS_SYSCTL);
+	ti_mmchs_write_4(sc, MMCHS_SYSCTL, sysctl | MMCHS_SYSCTL_SRA);
+	timeout = 100;
+	while ((ti_mmchs_read_4(sc, MMCHS_SYSCTL) & MMCHS_SYSCTL_SRA) != 0x0) {
+		DELAY(1000);
+		if (timeout-- == 0) {
+			device_printf(dev, "Error: reset operation timed out\n");
+			return;
+		}
+	}
+
+	/* 4: Set initial host configuration (1-bit mode, pwroff) and capabilities */
+	ti_mmchs_write_4(sc, MMCHS_HCTL, MMCHS_HCTL_SDVS_V30);
+
+	capa = ti_mmchs_read_4(sc, MMCHS_CAPA);
+	ti_mmchs_write_4(sc, MMCHS_CAPA, capa | MMCHS_CAPA_VS30 | MMCHS_CAPA_VS18);
+
+	/* 5: Set the initial bus configuration
+	 *       0  CTPL_MMC_SD      : Control Power for DAT1 line
+	 *       0  WPP_ACTIVE_HIGH  : Write protect polarity
+	 *       0  CDP_ACTIVE_HIGH  : Card detect polarity
+	 *       0  CTO_ENABLED      : MMC interrupt command
+	 *       0  DW8_DISABLED     : 8-bit mode MMC select
+	 *       0  MODE_FUNC        : Mode select
+	 *       0  STREAM_DISABLED  : Stream command
+	 *       0  HR_DISABLED      : Broadcast host response
+	 *       0  INIT_DISABLED    : Send initialization stream
+	 *       0  OD_DISABLED      : No Open Drain
+	 */
+	con = ti_mmchs_read_4(sc, MMCHS_CON) & MMCHS_CON_DVAL_MASK;
+	ti_mmchs_write_4(sc, MMCHS_CON, con);
+
+}
+
+/**
+ *	ti_mmchs_fini - shutdown the MMC/SD/SIO controller
+ *	@dev: mmc device handle
+ *
+ *	Responsible for shutting done the MMC controller, this function may be
+ *	called as part of a reset sequence.
+ *
+ *	LOCKING:
+ *	No locking, assumed to be called during tear-down/reset.
+ *
+ *	RETURNS:
+ *	nothing
+ */
+static void
+ti_mmchs_hw_fini(device_t dev)
+{
+	struct ti_mmchs_softc *sc = device_get_softc(dev);
+
+	/* Disable all interrupts */
+	ti_mmchs_write_4(sc, MMCHS_ISE, 0x00000000);
+	ti_mmchs_write_4(sc, MMCHS_IE, 0x00000000);
+
+	/* Disable the functional and interface clocks */
+	ti_prcm_clk_disable(MMC0_CLK + sc->device_id);
+}
+
+/**
+ *	ti_mmchs_init_dma_channels - initalise the DMA channels
+ *	@sc: driver soft context
+ *
+ *	Attempts to activate an RX and TX DMA channel for the MMC device.
+ *
+ *	LOCKING:
+ *	No locking, assumed to be called during tear-down/reset.
+ *
+ *	RETURNS:
+ *	0 on success, a negative error code on failure.
+ */
+static int
+ti_mmchs_init_dma_channels(struct ti_mmchs_softc *sc)
+{
+#ifdef SOC_TI_AM335X
+	switch (sc->device_id) {
+		case 0:
+			sc->dma_tx_trig = TI_EDMA3_EVENT_SDTXEVT0;
+			sc->dma_rx_trig = TI_EDMA3_EVENT_SDRXEVT0;
+			break;
+		case 1:
+			sc->dma_tx_trig = TI_EDMA3_EVENT_SDTXEVT1;
+			sc->dma_rx_trig = TI_EDMA3_EVENT_SDRXEVT1;
+			break;
+		default:
+			return(EINVAL);
+	}
+
+#define EVTQNUM		0
+	/* TODO EDMA3 have 3 queues, so we need some queue allocation call */
+	ti_edma3_init(EVTQNUM);
+	ti_edma3_request_dma_ch(sc->dma_tx_trig, sc->dma_tx_trig, EVTQNUM);
+	ti_edma3_request_dma_ch(sc->dma_rx_trig, sc->dma_rx_trig, EVTQNUM);
+#else
+	int err;
+	uint32_t rev;
+
+	/* Get the current chip revision */
+	rev = ti_revision();
+	if ((OMAP_REV_DEVICE(rev) != OMAP4430_DEV) && (sc->device_id > 3))
+		return(EINVAL);
+
+	/* Get the DMA MMC triggers */
+	switch (sc->device_id) {
+		case 1:
+			sc->dma_tx_trig = 60;
+			sc->dma_rx_trig = 61;
+			break;
+		case 2:
+			sc->dma_tx_trig = 46;
+			sc->dma_rx_trig = 47;
+			break;
+		case 3:
+			sc->dma_tx_trig = 76;
+			sc->dma_rx_trig = 77;
+			break;
+		/* The following are OMAP4 only */
+		case 4:
+			sc->dma_tx_trig = 56;
+			sc->dma_rx_trig = 57;
+			break;
+		case 5:
+			sc->dma_tx_trig = 58;
+			sc->dma_rx_trig = 59;
+			break;
+		default:
+			return(EINVAL);
+	}
+
+	/* Activate a RX channel from the OMAP DMA driver */
+	err = ti_sdma_activate_channel(&sc->sc_dmach_rd, ti_mmchs_dma_intr, sc);
+	if (err != 0)
+		return(err);
+
+	/* Setup the RX channel for MMC data transfers */
+	ti_sdma_set_xfer_burst(sc->sc_dmach_rd, TI_SDMA_BURST_NONE,
+	    TI_SDMA_BURST_64);
+	ti_sdma_set_xfer_data_type(sc->sc_dmach_rd, TI_SDMA_DATA_32BITS_SCALAR);
+	ti_sdma_sync_params(sc->sc_dmach_rd, sc->dma_rx_trig,
+	    TI_SDMA_SYNC_PACKET | TI_SDMA_SYNC_TRIG_ON_SRC);
+	ti_sdma_set_addr_mode(sc->sc_dmach_rd, TI_SDMA_ADDR_CONSTANT,
+	    TI_SDMA_ADDR_POST_INCREMENT);
+
+	/* Activate and configure the TX DMA channel */
+	err = ti_sdma_activate_channel(&sc->sc_dmach_wr, ti_mmchs_dma_intr, sc);
+	if (err != 0)
+		return(err);
+
+	/* Setup the TX channel for MMC data transfers */
+	ti_sdma_set_xfer_burst(sc->sc_dmach_wr, TI_SDMA_BURST_64,
+	    TI_SDMA_BURST_NONE);
+	ti_sdma_set_xfer_data_type(sc->sc_dmach_wr, TI_SDMA_DATA_32BITS_SCALAR);
+	ti_sdma_sync_params(sc->sc_dmach_wr, sc->dma_tx_trig,
+	    TI_SDMA_SYNC_PACKET | TI_SDMA_SYNC_TRIG_ON_DST);
+	ti_sdma_set_addr_mode(sc->sc_dmach_wr, TI_SDMA_ADDR_POST_INCREMENT,
+	    TI_SDMA_ADDR_CONSTANT);
+#endif
+	return(0);
+}
+
+/**
+ *	ti_mmchs_deactivate - deactivates the driver
+ *	@dev: mmc device handle
+ *
+ *	Unmaps the register set and releases the IRQ resource.
+ *
+ *	LOCKING:
+ *	None required
+ *
+ *	RETURNS:
+ *	nothing
+ */
+static void
+ti_mmchs_deactivate(device_t dev)
+{
+	struct ti_mmchs_softc *sc= device_get_softc(dev);
+
+	/* Remove the IRQ handler */
+	if (sc->sc_irq_h != NULL) {
+		bus_teardown_intr(dev, sc->sc_irq_res, sc->sc_irq_h);
+		sc->sc_irq_h = NULL;
+	}
+
+	/* Do the generic detach */
+	bus_generic_detach(sc->sc_dev);
+
+#ifdef SOC_TI_AM335X
+	printf("%s: DMA unimplemented\n", __func__);
+#else
+	/* Deactivate the DMA channels */
+	ti_sdma_deactivate_channel(sc->sc_dmach_rd);
+	ti_sdma_deactivate_channel(sc->sc_dmach_wr);
+#endif
+
+	/* Unmap the MMC controller registers */
+	if (sc->sc_mem_res != 0) {
+		bus_release_resource(dev, SYS_RES_MEMORY, rman_get_rid(sc->sc_irq_res),
+		    sc->sc_mem_res);
+		sc->sc_mem_res = NULL;
+	}
+
+	/* Release the IRQ resource */
+	if (sc->sc_irq_res != NULL) {
+		bus_release_resource(dev, SYS_RES_IRQ, rman_get_rid(sc->sc_irq_res),
+		    sc->sc_irq_res);
+		sc->sc_irq_res = NULL;
+	}
+
+	return;
+}
+
+/**
+ *	ti_mmchs_activate - activates the driver
+ *	@dev: mmc device handle
+ *
+ *	Maps in the register set and requests an IRQ handler for the MMC controller.
+ *
+ *	LOCKING:
+ *	None required
+ *
+ *	RETURNS:
+ *	0 on sucess
+ *	ENOMEM if failed to map register set
+ */
+static int
+ti_mmchs_activate(device_t dev)
+{
+	struct ti_mmchs_softc *sc = device_get_softc(dev);
+	unsigned long addr;
+	int rid;
+	int err;
+
+	/* Get the memory resource for the register mapping */
+	rid = 0;
+	sc->sc_mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid,
+	    RF_ACTIVE);
+	if (sc->sc_mem_res == NULL)
+		panic("%s: Cannot map registers", device_get_name(dev));
+
+	/* Allocate an IRQ resource for the MMC controller */
+	rid = 0;
+	sc->sc_irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid,
+	    RF_ACTIVE | RF_SHAREABLE);
+	if (sc->sc_irq_res == NULL)
+		goto errout;
+
+	/* Allocate DMA tags and maps */
+	err = bus_dma_tag_create(bus_get_dma_tag(dev), 1, 0,
+	    BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, NULL,
+	    NULL, MAXPHYS, 1, MAXPHYS, BUS_DMA_ALLOCNOW, NULL,
+	    NULL, &sc->sc_dmatag);
+	if (err != 0)
+		goto errout;
+
+	err = bus_dmamap_create(sc->sc_dmatag, 0,  &sc->sc_dmamap);
+	if (err != 0)
+		goto errout;
+
+	/* Initialise the DMA channels to be used by the controller */
+	err = ti_mmchs_init_dma_channels(sc);
+	if (err != 0)
+		goto errout;
+
+	/* Set the register offset */
+	if (ti_chip() == CHIP_OMAP_3)
+		sc->sc_reg_off = OMAP3_MMCHS_REG_OFFSET;
+	else if (ti_chip() == CHIP_OMAP_4)
+		sc->sc_reg_off = OMAP4_MMCHS_REG_OFFSET;
+	else if (ti_chip() == CHIP_AM335X)
+		sc->sc_reg_off = AM335X_MMCHS_REG_OFFSET;
+	else
+		panic("Unknown OMAP device\n");
+
+	/* Get the physical address of the MMC data register, needed for DMA */
+	addr = vtophys(rman_get_start(sc->sc_mem_res));
+	sc->sc_data_reg_paddr = addr + sc->sc_reg_off + MMCHS_DATA;
+
+	/* Set the initial power state to off */
+	sc->sc_cur_power_mode = power_off;
+
+	return (0);
+
+errout:
+	ti_mmchs_deactivate(dev);
+	return (ENOMEM);
+}
+
+/**
+ *	ti_mmchs_probe - probe function for the driver
+ *	@dev: mmc device handle
+ *
+ *
+ *
+ *	RETURNS:
+ *	always returns 0
+ */
+static int
+ti_mmchs_probe(device_t dev)
+{
+	if (!ofw_bus_is_compatible(dev, "ti,mmchs"))
+		return (ENXIO);
+
+	device_set_desc(dev, "TI MMC/SD/SDIO High Speed Interface");
+	return (0);
+}
+
+/**
+ *	ti_mmchs_attach - attach function for the driver
+ *	@dev: mmc device handle
+ *
+ *	Driver initialisation, sets-up the bus mappings, DMA mapping/channels and
+ *	the actual controller by calling ti_mmchs_init().
+ *
+ *	RETURNS:
+ *	Returns 0 on success or a negative error code.
+ */
+static int
+ti_mmchs_attach(device_t dev)
+{
+	struct ti_mmchs_softc *sc = device_get_softc(dev);
+	int unit = device_get_unit(dev);
+	phandle_t node;
+	pcell_t did;
+	int err;
+
+	/* Save the device and bus tag */
+	sc->sc_dev = dev;
+
+	/* Get the mmchs device id from FDT */
+	node = ofw_bus_get_node(dev);
+	if ((OF_getprop(node, "mmchs-device-id", &did, sizeof(did))) <= 0) {
+	    device_printf(dev, "missing mmchs-device-id attribute in FDT\n");
+		return (ENXIO);
+	}
+	sc->device_id = fdt32_to_cpu(did);
+
+	/* Initiate the mtex lock */
+	TI_MMCHS_LOCK_INIT(sc);
+
+	/* Indicate the DMA channels haven't yet been allocated */
+	sc->sc_dmach_rd = (unsigned int)-1;
+	sc->sc_dmach_wr = (unsigned int)-1;
+
+	/* Get the hint'ed write detect pin */
+	/* TODO: take this from FDT */
+	if (resource_int_value("ti_mmchs", unit, "wp_gpio", &sc->sc_wp_gpio_pin) != 0){
+		sc->sc_wp_gpio_pin = -1;
+	} else {
+		/* Get the GPIO device, we need this for the write protect pin */
+		sc->sc_gpio_dev = devclass_get_device(devclass_find("gpio"), 0);
+		if (sc->sc_gpio_dev == NULL)
+			device_printf(dev, "Error: failed to get the GPIO device\n");
+		else
+			GPIO_PIN_SETFLAGS(sc->sc_gpio_dev, sc->sc_wp_gpio_pin,
+			                  GPIO_PIN_INPUT);
+	}
+
+	/* Get the TWL voltage regulator device, we need this to for setting the
+	 * voltage of the bus on certain OMAP platforms.
+	 */
+	sc->sc_vreg_name = NULL;
+
+	/* TODO: add voltage regulator knob to FDT */
+#ifdef notyet
+	sc->sc_vreg_dev = devclass_get_device(devclass_find("twl_vreg"), 0);
+	if (sc->sc_vreg_dev == NULL) {
+		device_printf(dev, "Error: failed to get the votlage regulator"
+		    " device\n");
+		sc->sc_vreg_name = NULL;
+	}
+#endif
+
+	/* Activate the device */
+	err = ti_mmchs_activate(dev);
+	if (err)
+		goto out;
+
+	/* Initialise the controller */
+	ti_mmchs_hw_init(dev);
+
+	/* Activate the interrupt and attach a handler */
+	err = bus_setup_intr(dev, sc->sc_irq_res, INTR_TYPE_MISC | INTR_MPSAFE,
+	    NULL, ti_mmchs_intr, sc, &sc->sc_irq_h);
+	if (err != 0)
+		goto out;
+
+	/* Add host details */
+	sc->host.f_min = sc->sc_ref_freq / 1023;
+	sc->host.f_max = sc->sc_ref_freq;
+	sc->host.host_ocr = MMC_OCR_290_300 | MMC_OCR_300_310;
+	sc->host.caps = MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA;
+
+	device_add_child(dev, "mmc", 0);
+
+	device_set_ivars(dev, &sc->host);
+	err = bus_generic_attach(dev);
+
+out:
+	if (err) {
+		TI_MMCHS_LOCK_DESTROY(sc);
+		ti_mmchs_deactivate(dev);
+
+#ifdef SOC_TI_AM335X
+		printf("%s: DMA unimplemented\n", __func__);
+#else
+		if (sc->sc_dmach_rd != (unsigned int)-1)
+			ti_sdma_deactivate_channel(sc->sc_dmach_rd);
+		if (sc->sc_dmach_wr != (unsigned int)-1)
+			ti_sdma_deactivate_channel(sc->sc_dmach_wr);
+#endif
+	}
+
+	return (err);
+}
+
+/**
+ *	ti_mmchs_detach - dettach function for the driver
+ *	@dev: mmc device handle
+ *
+ *	Shutdowns the controll and release resources allocated by the driver.
+ *
+ *	RETURNS:
+ *	Always returns 0.
+ */
+static int
+ti_mmchs_detach(device_t dev)
+{
+#ifndef SOC_TI_AM335X
+	struct ti_mmchs_softc *sc = device_get_softc(dev);
+#endif
+
+	ti_mmchs_hw_fini(dev);
+	ti_mmchs_deactivate(dev);
+
+#ifdef SOC_TI_AM335X
+		printf("%s: DMA unimplemented\n", __func__);
+#else
+	ti_sdma_deactivate_channel(sc->sc_dmach_wr);
+	ti_sdma_deactivate_channel(sc->sc_dmach_rd);
+#endif
+
+	return (0);
+}
+
+static device_method_t ti_mmchs_methods[] = {
+	/* device_if */
+	DEVMETHOD(device_probe, ti_mmchs_probe),
+	DEVMETHOD(device_attach, ti_mmchs_attach),
+	DEVMETHOD(device_detach, ti_mmchs_detach),
+
+	/* Bus interface */
+	DEVMETHOD(bus_read_ivar,	ti_mmchs_read_ivar),
+	DEVMETHOD(bus_write_ivar,	ti_mmchs_write_ivar),
+
+	/* mmcbr_if - MMC state machine callbacks */
+	DEVMETHOD(mmcbr_update_ios, ti_mmchs_update_ios),
+	DEVMETHOD(mmcbr_request, ti_mmchs_request),
+	DEVMETHOD(mmcbr_get_ro, ti_mmchs_get_ro),
+	DEVMETHOD(mmcbr_acquire_host, ti_mmchs_acquire_host),
+	DEVMETHOD(mmcbr_release_host, ti_mmchs_release_host),
+
+	{0, 0},
+};
+
+static driver_t ti_mmchs_driver = {
+	"ti_mmchs",
+	ti_mmchs_methods,
+	sizeof(struct ti_mmchs_softc),
+};
+static devclass_t ti_mmchs_devclass;
+
+DRIVER_MODULE(ti_mmchs, simplebus, ti_mmchs_driver, ti_mmchs_devclass, 0, 0);
+MODULE_DEPEND(ti_mmchs, ti_prcm, 1, 1, 1);
+#ifdef SOC_TI_AM335X
+MODULE_DEPEND(ti_mmchs, ti_edma, 1, 1, 1);
+#else
+MODULE_DEPEND(ti_mmchs, ti_sdma, 1, 1, 1);
+#endif
+MODULE_DEPEND(ti_mmchs, ti_gpio, 1, 1, 1);
+
+/* FIXME: MODULE_DEPEND(ti_mmchs, twl_vreg, 1, 1, 1); */
diff -r 7fffa673adcd -r a301a330526b head/sys/arm/ti/ti_mmchs.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/head/sys/arm/ti/ti_mmchs.h	Wed Aug 15 11:16:36 2012 +0300
@@ -0,0 +1,170 @@
+/*-
+ * Copyright (c) 2011
+ *	Ben Gray <ben.r.gray at 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.
+ *
+ * $FreeBSD: head/sys/arm/ti/ti_mmchs.h 239281 2012-08-15 06:31:32Z gonzo $
+ */
+#ifndef _TI_MMCHS_H_
+#define _TI_MMCHS_H_
+
+/**
+ * Header file for the TI MMC/SD/SDIO driver.
+ *
+ * Simply contains register addresses and bit flags.
+ */
+
+/* Register offsets within each of the MMC/SD/SDIO controllers */
+#define MMCHS_SYSCONFIG             0x010
+#define MMCHS_SYSSTATUS             0x014
+#define MMCHS_CSRE                  0x024
+#define MMCHS_SYSTEST               0x028
+#define MMCHS_CON                   0x02C
+#define MMCHS_PWCNT                 0x030
+#define MMCHS_BLK                   0x104
+#define MMCHS_ARG                   0x108
+#define MMCHS_CMD                   0x10C
+#define MMCHS_RSP10                 0x110
+#define MMCHS_RSP32                 0x114
+#define MMCHS_RSP54                 0x118
+#define MMCHS_RSP76                 0x11C
+#define MMCHS_DATA                  0x120
+#define MMCHS_PSTATE                0x124
+#define MMCHS_HCTL                  0x128
+#define MMCHS_SYSCTL                0x12C
+#define MMCHS_STAT                  0x130
+#define MMCHS_IE                    0x134
+#define MMCHS_ISE                   0x138
+#define MMCHS_AC12                  0x13C
+#define MMCHS_CAPA                  0x140
+#define MMCHS_CUR_CAPA              0x148
+#define MMCHS_REV                   0x1FC
+
+/* OMAP4 and OMAP4 have different register addresses */
+#define OMAP3_MMCHS_REG_OFFSET      0x000
+#define OMAP4_MMCHS_REG_OFFSET      0x100
+#define AM335X_MMCHS_REG_OFFSET     0x100
+
+/* Register bit settings */
+#define MMCHS_STAT_BADA             (1UL << 29)
+#define MMCHS_STAT_CERR             (1UL << 28)
+#define MMCHS_STAT_ACE              (1UL << 24)
+#define MMCHS_STAT_DEB              (1UL << 22)
+#define MMCHS_STAT_DCRC             (1UL << 21)
+#define MMCHS_STAT_DTO              (1UL << 20)
+#define MMCHS_STAT_CIE              (1UL << 19)
+#define MMCHS_STAT_CEB              (1UL << 18)
+#define MMCHS_STAT_CCRC             (1UL << 17)
+#define MMCHS_STAT_CTO              (1UL << 16)
+#define MMCHS_STAT_ERRI             (1UL << 15)
+#define MMCHS_STAT_OBI              (1UL << 9)
+#define MMCHS_STAT_CIRQ             (1UL << 8)
+#define MMCHS_STAT_BRR              (1UL << 5)
+#define MMCHS_STAT_BWR              (1UL << 4)
+#define MMCHS_STAT_BGE              (1UL << 2)
+#define MMCHS_STAT_TC               (1UL << 1)
+#define MMCHS_STAT_CC               (1UL << 0)
+
+#define MMCHS_STAT_CLEAR_MASK       0x3BFF8337UL
+
+#define MMCHS_SYSCTL_SRD            (1UL << 26)
+#define MMCHS_SYSCTL_SRC            (1UL << 25)
+#define MMCHS_SYSCTL_SRA            (1UL << 24)
+#define MMCHS_SYSCTL_DTO(x)         (((x) & 0xf) << 16)
+#define MMCHS_SYSCTL_DTO_MASK       MMCHS_SYSCTL_DTO(0xf)
+#define MMCHS_SYSCTL_CLKD(x)        (((x) & 0x3ff) << 6)
+#define MMCHS_SYSCTL_CLKD_MASK      MMCHS_SYSCTL_CLKD(0x3ff)
+#define MMCHS_SYSCTL_CEN            (1UL << 2)
+#define MMCHS_SYSCTL_ICS            (1UL << 1)
+#define MMCHS_SYSCTL_ICE            (1UL << 0)
+
+#define MMCHS_HCTL_OBWE             (1UL << 27)
+#define MMCHS_HCTL_REM              (1UL << 26)
+#define MMCHS_HCTL_INS              (1UL << 25)
+#define MMCHS_HCTL_IWE              (1UL << 24)
+#define MMCHS_HCTL_IBG              (1UL << 19)
+#define MMCHS_HCTL_RWC              (1UL << 18)
+#define MMCHS_HCTL_CR               (1UL << 17)
+#define MMCHS_HCTL_SBGR             (1UL << 16)
+#define MMCHS_HCTL_SDVS_MASK        (7UL << 9)
+#define MMCHS_HCTL_SDVS_V18         (5UL << 9)
+#define MMCHS_HCTL_SDVS_V30         (6UL << 9)
+#define MMCHS_HCTL_SDVS_V33         (7UL << 9)
+#define MMCHS_HCTL_SDBP             (1UL << 8)
+#define MMCHS_HCTL_DTW              (1UL << 1)
+
+#define MMCHS_CAPA_VS18             (1UL << 26)
+#define MMCHS_CAPA_VS30             (1UL << 25)
+#define MMCHS_CAPA_VS33             (1UL << 24)
+
+#define MMCHS_CMD_CMD_TYPE_IO_ABORT (3UL << 21)
+#define MMCHS_CMD_CMD_TYPE_FUNC_SEL (2UL << 21)
+#define MMCHS_CMD_CMD_TYPE_SUSPEND  (1UL << 21)
+#define MMCHS_CMD_CMD_TYPE_OTHERS   (0UL << 21)
+#define MMCHS_CMD_CMD_TYPE_MASK     (3UL << 22)
+
+#define MMCHS_CMD_DP                (1UL << 21)
+#define MMCHS_CMD_CICE              (1UL << 20)
+#define MMCHS_CMD_CCCE              (1UL << 19)
+
+#define MMCHS_CMD_RSP_TYPE_MASK     (3UL << 16)
+#define MMCHS_CMD_RSP_TYPE_NO       (0UL << 16)
+#define MMCHS_CMD_RSP_TYPE_136      (1UL << 16)
+#define MMCHS_CMD_RSP_TYPE_48       (2UL << 16)
+#define MMCHS_CMD_RSP_TYPE_48_BSY   (3UL << 16)
+
+#define MMCHS_CMD_MSBS              (1UL << 5)
+#define MMCHS_CMD_DDIR              (1UL << 4)
+#define MMCHS_CMD_ACEN              (1UL << 2)
+#define MMCHS_CMD_BCE               (1UL << 1)
+#define MMCHS_CMD_DE                (1UL << 0)
+
+#define MMCHS_CON_CLKEXTFREE        (1UL << 16)
+#define MMCHS_CON_PADEN             (1UL << 15)
+#define MMCHS_CON_OBIE              (1UL << 14)
+#define MMCHS_CON_OBIP              (1UL << 13)
+#define MMCHS_CON_CEATA             (1UL << 12)
+#define MMCHS_CON_CTPL              (1UL << 11)
+
+#define MMCHS_CON_DVAL_8_4MS        (3UL << 9)
+#define MMCHS_CON_DVAL_1MS          (2UL << 9)
+#define MMCHS_CON_DVAL_231US        (1UL << 9)
+#define MMCHS_CON_DVAL_33US         (0UL << 9)
+#define MMCHS_CON_DVAL_MASK         (3UL << 9)
+
+#define MMCHS_CON_WPP               (1UL << 8)
+#define MMCHS_CON_CDP               (1UL << 7)
+#define MMCHS_CON_MIT               (1UL << 6)
+#define MMCHS_CON_DW8               (1UL << 5)
+#define MMCHS_CON_MODE              (1UL << 4)
+#define MMCHS_CON_STR               (1UL << 3)
+#define MMCHS_CON_HR                (1UL << 2)
+#define MMCHS_CON_INIT              (1UL << 1)
+#define MMCHS_CON_OD                (1UL << 0)
+
+#define MMCHS_CAPA_VS18             (1UL << 26)
+#define MMCHS_CAPA_VS30             (1UL << 25)
+#define MMCHS_CAPA_VS33             (1UL << 24)
+
+#endif  /* _TI_MMCHS_H_ */
diff -r 7fffa673adcd -r a301a330526b head/sys/arm/ti/ti_prcm.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/head/sys/arm/ti/ti_prcm.c	Wed Aug 15 11:16:36 2012 +0300
@@ -0,0 +1,309 @@
+/*
+ * Copyright (c) 2010
+ *	Ben Gray <ben.r.gray at 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.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by Ben Gray.
+ * 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 BEN GRAY ``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 BEN GRAY 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.
+ */
+
+/**
+ * Power, Reset and Clock Managment Module
+ *
+ * This is a very simple driver wrapper around the PRCM set of registers in
+ * the OMAP3 chip. It allows you to turn on and off things like the functional
+ * and interface clocks to the various on-chip modules.
+ *
+ */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: head/sys/arm/ti/ti_prcm.c 239281 2012-08-15 06:31:32Z gonzo $");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/module.h>
+#include <sys/bus.h>
+#include <sys/resource.h>
+#include <sys/rman.h>
+#include <sys/lock.h>
+#include <sys/mutex.h>
+
+#include <machine/bus.h>
+#include <machine/cpu.h>
+#include <machine/cpufunc.h>
+#include <machine/frame.h>
+#include <machine/resource.h>
+#include <machine/intr.h>
+
+#include <arm/ti/ti_prcm.h>
+
+/**
+ *	ti_clk_devmap - Array of clock devices, should be defined one per SoC 
+ *
+ *	This array is typically defined in one of the targeted *_prcm_clk.c
+ *	files and is specific to the given SoC platform.  Each entry in the array
+ *	corresponds to an individual clock device.
+ */
+extern struct ti_clock_dev ti_clk_devmap[];
+
+/**
+ *	ti_prcm_clk_dev - returns a pointer to the clock device with given id
+ *	@clk: the ID of the clock device to get
+ *
+ *	Simply iterates through the clk_devmap global array and returns a pointer
+ *	to the clock device if found. 
+ *
+ *	LOCKING:
+ *	None
+ *
+ *	RETURNS:
+ *	The pointer to the clock device on success, on failure NULL is returned.
+ */
+static struct ti_clock_dev *
+ti_prcm_clk_dev(clk_ident_t clk)
+{
+	struct ti_clock_dev *clk_dev;
+	
+	/* Find the clock within the devmap - it's a bit inefficent having a for 
+	 * loop for this, but this function should only called when a driver is 
+	 * being activated so IMHO not a big issue.
+	 */
+	clk_dev = &(ti_clk_devmap[0]);
+	while (clk_dev->id != INVALID_CLK_IDENT) {
+		if (clk_dev->id == clk) {
+			return (clk_dev);
+		}
+		clk_dev++;
+	}
+
+	/* Sanity check we managed to find the clock */
+	printf("ti_prcm: Failed to find clock device (%d)\n", clk);
+	return (NULL);
+}
+
+/**
+ *	ti_prcm_clk_valid - enables a clock for a particular module
+ *	@clk: identifier for the module to enable, see ti_prcm.h for a list
+ *	      of possible modules.
+ *	         Example: OMAP3_MODULE_MMC1_ICLK or OMAP3_MODULE_GPTIMER10_FCLK.
+ *	
+ *	This function can enable either a functional or interface clock.
+ *
+ *	The real work done to enable the clock is really done in the callback
+ *	function associated with the clock, this function is simply a wrapper
+ *	around that.
+ *
+ *	LOCKING:
+ *	Internally locks the driver context.
+ *
+ *	RETURNS:
+ *	Returns 0 on success or positive error code on failure.
+ */
+int
+ti_prcm_clk_valid(clk_ident_t clk)
+{
+	int ret = 0;
+
+	if (ti_prcm_clk_dev(clk) == NULL)
+		ret = EINVAL;
+	
+	return (ret);
+}
+
+
+/**
+ *	ti_prcm_clk_enable - enables a clock for a particular module
+ *	@clk: identifier for the module to enable, see ti_prcm.h for a list
+ *	      of possible modules.
+ *	         Example: OMAP3_MODULE_MMC1_ICLK or OMAP3_MODULE_GPTIMER10_FCLK.
+ *	
+ *	This function can enable either a functional or interface clock.
+ *
+ *	The real work done to enable the clock is really done in the callback
+ *	function associated with the clock, this function is simply a wrapper
+ *	around that.
+ *
+ *	LOCKING:
+ *	Internally locks the driver context.
+ *
+ *	RETURNS:
+ *	Returns 0 on success or positive error code on failure.
+ */
+int
+ti_prcm_clk_enable(clk_ident_t clk)
+{
+	struct ti_clock_dev *clk_dev;
+	int ret;
+
+	/* Find the clock within the devmap - it's a bit inefficent having a for 
+	 * loop for this, but this function should only called when a driver is 
+	 * being activated so IMHO not a big issue.
+	 */
+	clk_dev = ti_prcm_clk_dev(clk);
+
+	/* Sanity check we managed to find the clock */
+	if (clk_dev == NULL)
+		return (EINVAL);
+
+	/* Activate the clock */
+	if (clk_dev->clk_activate)
+		ret = clk_dev->clk_activate(clk_dev);
+	else
+		ret = EINVAL;
+
+	return (ret);
+}
+
+
+/**
+ *	ti_prcm_clk_disable - disables a clock for a particular module
+ *	@clk: identifier for the module to enable, see ti_prcm.h for a list
+ *	      of possible modules.
+ *	         Example: OMAP3_MODULE_MMC1_ICLK or OMAP3_MODULE_GPTIMER10_FCLK.
+ *	
+ *	This function can enable either a functional or interface clock.
+ *
+ *	The real work done to enable the clock is really done in the callback
+ *	function associated with the clock, this function is simply a wrapper
+ *	around that.
+ *
+ *	LOCKING:
+ *	Internally locks the driver context.
+ *
+ *	RETURNS:
+ *	Returns 0 on success or positive error code on failure.
+ */
+int
+ti_prcm_clk_disable(clk_ident_t clk)
+{
+	struct ti_clock_dev *clk_dev;
+	int ret;
+
+	/* Find the clock within the devmap - it's a bit inefficent having a for 
+	 * loop for this, but this function should only called when a driver is 
+	 * being activated so IMHO not a big issue.
+	 */
+	clk_dev = ti_prcm_clk_dev(clk);
+
+	/* Sanity check we managed to find the clock */
+	if (clk_dev == NULL)
+		return (EINVAL);
+
+	/* Activate the clock */
+	if (clk_dev->clk_deactivate)
+		ret = clk_dev->clk_deactivate(clk_dev);
+	else
+		ret = EINVAL;
+	
+	return (ret);
+}
+
+/**
+ *	ti_prcm_clk_set_source - sets the source 
+ *	@clk: identifier for the module to enable, see ti_prcm.h for a list
+ *	      of possible modules.
+ *	         Example: OMAP3_MODULE_MMC1_ICLK or OMAP3_MODULE_GPTIMER10_FCLK.
+ *	
+ *	This function can enable either a functional or interface clock.
+ *
+ *	The real work done to enable the clock is really done in the callback
+ *	function associated with the clock, this function is simply a wrapper
+ *	around that.
+ *
+ *	LOCKING:
+ *	Internally locks the driver context.
+ *
+ *	RETURNS:
+ *	Returns 0 on success or positive error code on failure.
+ */
+int
+ti_prcm_clk_set_source(clk_ident_t clk, clk_src_t clksrc)
+{
+	struct ti_clock_dev *clk_dev;
+	int ret;
+
+	/* Find the clock within the devmap - it's a bit inefficent having a for 
+	 * loop for this, but this function should only called when a driver is 
+	 * being activated so IMHO not a big issue.
+	 */
+	clk_dev = ti_prcm_clk_dev(clk);
+
+	/* Sanity check we managed to find the clock */
+	if (clk_dev == NULL)
+		return (EINVAL);
+
+	/* Activate the clock */
+	if (clk_dev->clk_set_source)
+		ret = clk_dev->clk_set_source(clk_dev, clksrc);
+	else
+		ret = EINVAL;
+
+	return (ret);
+}
+
+
+/**
+ *	ti_prcm_clk_get_source_freq - gets the source clock frequency
+ *	@clk: identifier for the module to enable, see ti_prcm.h for a list
+ *	      of possible modules.
+ *	@freq: pointer to an integer that upon return will contain the src freq
+ *	
+ *	This function returns the frequency of the source clock.
+ *
+ *	The real work done to enable the clock is really done in the callback
+ *	function associated with the clock, this function is simply a wrapper
+ *	around that.
+ *
+ *	LOCKING:
+ *	Internally locks the driver context.
+ *
+ *	RETURNS:
+ *	Returns 0 on success or positive error code on failure.
+ */
+int
+ti_prcm_clk_get_source_freq(clk_ident_t clk, unsigned int *freq)
+{
+	struct ti_clock_dev *clk_dev;
+	int ret;
+
+	/* Find the clock within the devmap - it's a bit inefficent having a for 
+	 * loop for this, but this function should only called when a driver is 
+	 * being activated so IMHO not a big issue.
+	 */
+	clk_dev = ti_prcm_clk_dev(clk);
+
+	/* Sanity check we managed to find the clock */
+	if (clk_dev == NULL)
+		return (EINVAL);
+
+	/* Get the source frequency of the clock */
+	if (clk_dev->clk_get_source_freq)
+		ret = clk_dev->clk_get_source_freq(clk_dev, freq);
+	else
+		ret = EINVAL;
+	
+	return (ret);
+}
diff -r 7fffa673adcd -r a301a330526b head/sys/arm/ti/ti_prcm.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/head/sys/arm/ti/ti_prcm.h	Wed Aug 15 11:16:36 2012 +0300
@@ -0,0 +1,185 @@
+/*
+ * Copyright (c) 2010
+ *	Ben Gray <ben.r.gray at 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.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by Ben Gray.
+ * 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 BEN GRAY ``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 BEN GRAY 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: head/sys/arm/ti/ti_prcm.h 239281 2012-08-15 06:31:32Z gonzo $
+ */
+
+
+/*
+ * Texas Instruments - OMAP3xxx series processors
+ *
+ * Reference:
+ *  OMAP35x Applications Processor
+ *   Technical Reference Manual
+ *  (omap35xx_techref.pdf)
+ */
+#ifndef _TI_PRCM_H_
+#define _TI_PRCM_H_
+
+typedef enum {
+
+	/* System clocks, typically you can only call ti_prcm_clk_get_source_freq()
+	 * on these clocks as they are enabled by default.
+	 */
+	SYS_CLK = 1,
+
+	/* The MPU (ARM) core clock */
+	MPU_CLK = 20,
+
+	/* MMC modules */
+	MMC0_CLK = 100,
+	MMC1_CLK,
+	MMC2_CLK,
+	MMC3_CLK,
+	MMC4_CLK,
+	MMC5_CLK,
+
+	/* I2C modules */
+	I2C0_CLK = 200,
+	I2C1_CLK,
+	I2C2_CLK,
+	I2C3_CLK,
+	I2C4_CLK,
+
+	/* USB module(s) */
+	USBTLL_CLK = 300,
+	USBHSHOST_CLK,
+	USBFSHOST_CLK,
+	USBP1_PHY_CLK,
+	USBP2_PHY_CLK,
+	USBP1_UTMI_CLK,
+	USBP2_UTMI_CLK,
+	USBP1_HSIC_CLK,
+	USBP2_HSIC_CLK,
+
+	/* UART modules */
+	UART1_CLK = 400,
+	UART2_CLK,
+	UART3_CLK,
+	UART4_CLK,
+
+	/* General purpose timer modules */
+	GPTIMER1_CLK = 500,
+	GPTIMER2_CLK,
+	GPTIMER3_CLK,
+	GPTIMER4_CLK,
+	GPTIMER5_CLK,
+	GPTIMER6_CLK,
+	GPTIMER7_CLK,
+	GPTIMER8_CLK,
+	GPTIMER9_CLK,
+	GPTIMER10_CLK,
+	GPTIMER11_CLK,
+	GPTIMER12_CLK,
+
+	/* McBSP module(s) */
+	MCBSP1_CLK = 600,
+	MCBSP2_CLK,
+	MCBSP3_CLK,
+	MCBSP4_CLK,
+	MCBSP5_CLK,
+
+	/* General purpose I/O modules */
+	GPIO0_CLK = 700,
+	GPIO1_CLK,
+	GPIO2_CLK,
+	GPIO3_CLK,
+	GPIO4_CLK,
+	GPIO5_CLK,
+	GPIO6_CLK,
+
+	/* sDMA module */
+	SDMA_CLK = 800,
+
+	/* DMTimer modules */
+	DMTIMER0_CLK = 900,
+	DMTIMER1_CLK,
+	DMTIMER2_CLK,
+	DMTIMER3_CLK,
+	DMTIMER4_CLK,
+	DMTIMER5_CLK,
+	DMTIMER6_CLK,
+	DMTIMER7_CLK,
+
+	/* CPSW modules */
+	CPSW_CLK = 1000,
+
+	/* Mentor USB modules */
+	MUSB0_CLK = 1100,
+
+	/* EDMA module */
+	EDMA_TPCC_CLK = 1200,
+	EDMA_TPTC0_CLK,
+	EDMA_TPTC1_CLK,
+	EDMA_TPTC2_CLK,
+
+	INVALID_CLK_IDENT
+
+} clk_ident_t;
+
+/*
+ *
+ */
+typedef enum {
+	SYSCLK_CLK,   /* System clock */
+	EXT_CLK,
+
+	F32KHZ_CLK,   /* 32KHz clock */
+	F48MHZ_CLK,   /* 48MHz clock */
+	F64MHZ_CLK,   /* 64MHz clock */
+	F96MHZ_CLK,   /* 96MHz clock */
+
+} clk_src_t;
+
+struct ti_clock_dev {
+	/* The profile of the timer */
+	clk_ident_t  id;
+
+	/* A bunch of callbacks associated with the clock device */
+	int (*clk_activate)(struct ti_clock_dev *clkdev);
+	int (*clk_deactivate)(struct ti_clock_dev *clkdev);
+	int (*clk_set_source)(struct ti_clock_dev *clkdev,
+	    clk_src_t clksrc);
+	int (*clk_accessible)(struct ti_clock_dev *clkdev);
+	int (*clk_get_source_freq)(struct ti_clock_dev *clkdev,
+	    unsigned int *freq);
+};
+
+int ti_prcm_clk_valid(clk_ident_t clk);
+int ti_prcm_clk_enable(clk_ident_t clk);
+int ti_prcm_clk_disable(clk_ident_t clk);
+int ti_prcm_clk_accessible(clk_ident_t clk);
+int ti_prcm_clk_disable_autoidle(clk_ident_t clk);
+int ti_prcm_clk_set_source(clk_ident_t clk, clk_src_t clksrc);
+int ti_prcm_clk_get_source_freq(clk_ident_t clk, unsigned int *freq);
+void ti_prcm_reset(void);
+
+#endif   /* _TI_PRCM_H_ */
diff -r 7fffa673adcd -r a301a330526b head/sys/arm/ti/ti_scm.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/head/sys/arm/ti/ti_scm.c	Wed Aug 15 11:16:36 2012 +0300
@@ -0,0 +1,493 @@
+/*
+ * Copyright (c) 2010
+ *	Ben Gray <ben.r.gray at 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.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by Ben Gray.
+ * 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 BEN GRAY ``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 BEN GRAY 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.
+ */
+
+/**
+ *	SCM - System Control Module
+ *
+ *	Hopefully in the end this module will contain a bunch of utility functions
+ *	for configuring and querying the general system control registers, but for
+ *	now it only does pin(pad) multiplexing.
+ *
+ *	This is different from the GPIO module in that it is used to configure the
+ *	pins between modules not just GPIO input/output.
+ *
+ *	This file contains the generic top level driver, however it relies on chip
+ *	specific settings and therefore expects an array of ti_scm_padconf structs
+ *	call ti_padconf_devmap to be located somewhere in the kernel.
+ *
+ */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: head/sys/arm/ti/ti_scm.c 239281 2012-08-15 06:31:32Z gonzo $");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/module.h>
+#include <sys/bus.h>
+#include <sys/resource.h>
+#include <sys/rman.h>
+#include <sys/lock.h>
+#include <sys/mutex.h>
+
+#include <machine/bus.h>
+#include <machine/cpu.h>
+#include <machine/cpufunc.h>
+#include <machine/frame.h>
+#include <machine/resource.h>
+
+#include <dev/fdt/fdt_common.h>
+#include <dev/ofw/openfirm.h>
+#include <dev/ofw/ofw_bus.h>
+#include <dev/ofw/ofw_bus_subr.h>
+
+#include "ti_scm.h"
+
+static struct resource_spec ti_scm_res_spec[] = {
+	{ SYS_RES_MEMORY,	0,	RF_ACTIVE },	/* Control memory window */
+	{ -1, 0 }
+};
+
+static struct ti_scm_softc *ti_scm_sc;
+
+#define	ti_scm_read_2(sc, reg)		\
+    bus_space_read_2((sc)->sc_bst, (sc)->sc_bsh, (reg))
+#define	ti_scm_write_2(sc, reg, val)		\
+    bus_space_write_2((sc)->sc_bst, (sc)->sc_bsh, (reg), (val))
+#define	ti_scm_read_4(sc, reg)		\
+    bus_space_read_4((sc)->sc_bst, (sc)->sc_bsh, (reg))
+#define	ti_scm_write_4(sc, reg, val)		\
+    bus_space_write_4((sc)->sc_bst, (sc)->sc_bsh, (reg), (val))
+
+
+/**
+ *	ti_padconf_devmap - Array of pins, should be defined one per SoC
+ *
+ *	This array is typically defined in one of the targeted *_scm_pinumx.c
+ *	files and is specific to the given SoC platform. Each entry in the array
+ *	corresponds to an individual pin.
+ */
+extern const struct ti_scm_device ti_scm_dev;
+
+
+/**
+ *	ti_scm_padconf_from_name - searches the list of pads and returns entry
+ *	                             with matching ball name.
+ *	@ballname: the name of the ball
+ *
+ *	RETURNS:
+ *	A pointer to the matching padconf or NULL if the ball wasn't found.
+ */
+static const struct ti_scm_padconf*
+ti_scm_padconf_from_name(const char *ballname)
+{
+	const struct ti_scm_padconf *padconf;
+
+	padconf = ti_scm_dev.padconf;
+	while (padconf->ballname != NULL) {
+		if (strcmp(ballname, padconf->ballname) == 0)
+			return(padconf);
+		padconf++;
+	}
+	
+	return (NULL);
+}
+
+/**
+ *	ti_scm_padconf_set_internal - sets the muxmode and state for a pad/pin
+ *	@padconf: pointer to the pad structure
+ *	@muxmode: the name of the mode to use for the pin, i.e. "uart1_rx"
+ *	@state: the state to put the pad/pin in, i.e. PADCONF_PIN_???
+ *	
+ *
+ *	LOCKING:
+ *	Internally locks it's own context.
+ *
+ *	RETURNS:
+ *	0 on success.
+ *	EINVAL if pin requested is outside valid range or already in use.
+ */
+static int
+ti_scm_padconf_set_internal(struct ti_scm_softc *sc,
+    const struct ti_scm_padconf *padconf,
+    const char *muxmode, unsigned int state)
+{
+	unsigned int mode;
+	uint16_t reg_val;
+
+	/* populate the new value for the PADCONF register */
+	reg_val = (uint16_t)(state & ti_scm_dev.padconf_sate_mask);
+
+	/* find the new mode requested */
+	for (mode = 0; mode < 8; mode++) {
+		if ((padconf->muxmodes[mode] != NULL) &&
+		    (strcmp(padconf->muxmodes[mode], muxmode) == 0)) {
+			break;
+		}
+	}
+
+	/* couldn't find the mux mode */
+	if (mode >= 8)
+		return (EINVAL);
+
+	/* set the mux mode */
+	reg_val |= (uint16_t)(mode & ti_scm_dev.padconf_muxmode_mask);
+	
+	printf("setting internal %x for %s\n", reg_val, muxmode);
+	/* write the register value (16-bit writes) */
+	ti_scm_write_2(sc, padconf->reg_off, reg_val);
+	
+	return (0);
+}
+
+/**
+ *	ti_scm_padconf_set - sets the muxmode and state for a pad/pin
+ *	@padname: the name of the pad, i.e. "c12"
+ *	@muxmode: the name of the mode to use for the pin, i.e. "uart1_rx"
+ *	@state: the state to put the pad/pin in, i.e. PADCONF_PIN_???
+ *	
+ *
+ *	LOCKING:
+ *	Internally locks it's own context.
+ *
+ *	RETURNS:
+ *	0 on success.
+ *	EINVAL if pin requested is outside valid range or already in use.
+ */
+int
+ti_scm_padconf_set(const char *padname, const char *muxmode, unsigned int state)
+{
+	const struct ti_scm_padconf *padconf;
+
+	if (!ti_scm_sc)
+		return (ENXIO);
+
+	/* find the pin in the devmap */
+	padconf = ti_scm_padconf_from_name(padname);
+	if (padconf == NULL)
+		return (EINVAL);
+	
+	return (ti_scm_padconf_set_internal(ti_scm_sc, padconf, muxmode, state));
+}
+
+/**
+ *	ti_scm_padconf_get - gets the muxmode and state for a pad/pin
+ *	@padname: the name of the pad, i.e. "c12"
+ *	@muxmode: upon return will contain the name of the muxmode of the pin
+ *	@state: upon return will contain the state of the the pad/pin
+ *	
+ *
+ *	LOCKING:
+ *	Internally locks it's own context.
+ *
+ *	RETURNS:
+ *	0 on success.
+ *	EINVAL if pin requested is outside valid range or already in use.
+ */
+int
+ti_scm_padconf_get(const char *padname, const char **muxmode,
+    unsigned int *state)
+{
+	const struct ti_scm_padconf *padconf;
+	uint16_t reg_val;
+
+	if (!ti_scm_sc)
+		return (ENXIO);
+
+	/* find the pin in the devmap */
+	padconf = ti_scm_padconf_from_name(padname);
+	if (padconf == NULL)
+		return (EINVAL);
+	
+	/* read the register value (16-bit reads) */
+	reg_val = ti_scm_read_2(ti_scm_sc, padconf->reg_off);
+
+	/* save the state */
+	if (state)
+		*state = (reg_val & ti_scm_dev.padconf_sate_mask);
+
+	/* save the mode */
+	if (muxmode)
+		*muxmode = padconf->muxmodes[(reg_val & ti_scm_dev.padconf_muxmode_mask)];
+	
+	return (0);
+}
+
+/**
+ *	ti_scm_padconf_set_gpiomode - converts a pad to GPIO mode.
+ *	@gpio: the GPIO pin number (0-195)
+ *	@state: the state to put the pad/pin in, i.e. PADCONF_PIN_???
+ *
+ *	
+ *
+ *	LOCKING:
+ *	Internally locks it's own context.
+ *
+ *	RETURNS:
+ *	0 on success.
+ *	EINVAL if pin requested is outside valid range or already in use.
+ */
+int
+ti_scm_padconf_set_gpiomode(uint32_t gpio, unsigned int state)
+{
+	const struct ti_scm_padconf *padconf;
+	uint16_t reg_val;
+
+	if (!ti_scm_sc)
+		return (ENXIO);
+	
+	/* find the gpio pin in the padconf array */
+	padconf = ti_scm_dev.padconf;
+	while (padconf->ballname != NULL) {
+		if (padconf->gpio_pin == gpio)
+			break;
+		padconf++;
+	}
+	if (padconf->ballname == NULL)
+		return (EINVAL);
+
+	/* populate the new value for the PADCONF register */
+	reg_val = (uint16_t)(state & ti_scm_dev.padconf_sate_mask);
+
+	/* set the mux mode */
+	reg_val |= (uint16_t)(padconf->gpio_mode & ti_scm_dev.padconf_muxmode_mask);
+
+	/* write the register value (16-bit writes) */
+	ti_scm_write_2(ti_scm_sc, padconf->reg_off, reg_val);
+
+	return (0);
+}
+
+/**
+ *	ti_scm_padconf_get_gpiomode - gets the current GPIO mode of the pin
+ *	@gpio: the GPIO pin number (0-195)
+ *	@state: upon return will contain the state
+ *
+ *	
+ *
+ *	LOCKING:
+ *	Internally locks it's own context.
+ *
+ *	RETURNS:
+ *	0 on success.
+ *	EINVAL if pin requested is outside valid range or not configured as GPIO.
+ */
+int
+ti_scm_padconf_get_gpiomode(uint32_t gpio, unsigned int *state)
+{
+	const struct ti_scm_padconf *padconf;
+	uint16_t reg_val;
+
+	if (!ti_scm_sc)
+		return (ENXIO);
+	
+	/* find the gpio pin in the padconf array */
+	padconf = ti_scm_dev.padconf;
+	while (padconf->ballname != NULL) {
+		if (padconf->gpio_pin == gpio)
+			break;
+		padconf++;
+	}
+	if (padconf->ballname == NULL)
+		return (EINVAL);
+
+	/* read the current register settings */
+	reg_val = ti_scm_read_2(ti_scm_sc, padconf->reg_off);
+	
+	/* check to make sure the pins is configured as GPIO in the first state */
+	if ((reg_val & ti_scm_dev.padconf_muxmode_mask) != padconf->gpio_mode)
+		return (EINVAL);
+	
+	/* read and store the reset of the state, i.e. pull-up, pull-down, etc */
+	if (state)
+		*state = (reg_val & ti_scm_dev.padconf_sate_mask);
+	
+	return (0);
+}
+
+/**
+ *	ti_scm_padconf_init_from_hints - processes the hints for padconf
+ *	@sc: the driver soft context
+ *
+ *	
+ *
+ *	LOCKING:
+ *	Internally locks it's own context.
+ *
+ *	RETURNS:
+ *	0 on success.
+ *	EINVAL if pin requested is outside valid range or already in use.
+ */
+static int
+ti_scm_padconf_init_from_fdt(struct ti_scm_softc *sc)
+{
+	const struct ti_scm_padconf *padconf;
+	const struct ti_scm_padstate *padstates;
+	int err;
+	phandle_t node;
+	int len;
+	char *fdt_pad_config;
+	int i;
+	char *padname, *muxname, *padstate;
+
+	node = ofw_bus_get_node(sc->sc_dev);
+	len = OF_getproplen(node, "scm-pad-config");
+        OF_getprop_alloc(node, "scm-pad-config", 1, (void **)&fdt_pad_config);
+
+	i = len;
+	while (i > 0) {
+		padname = fdt_pad_config;
+		fdt_pad_config += strlen(padname) + 1;
+		i -= strlen(padname) + 1;
+		if (i <= 0)
+			break;
+
+		muxname = fdt_pad_config;
+		fdt_pad_config += strlen(muxname) + 1;
+		i -= strlen(muxname) + 1;
+		if (i <= 0)
+			break;
+
+		padstate = fdt_pad_config;
+		fdt_pad_config += strlen(padstate) + 1;
+		i -= strlen(padstate) + 1;
+		if (i < 0)
+			break;
+
+		padconf = ti_scm_dev.padconf;
+
+		while (padconf->ballname != NULL) {
+			if (strcmp(padconf->ballname, padname) == 0) {
+				padstates = ti_scm_dev.padstate;
+				err = 1;
+				while (padstates->state != NULL) {
+					if (strcmp(padstates->state, padstate) == 0) {
+						err = ti_scm_padconf_set_internal(sc,
+							padconf, muxname, padstates->reg);
+					}
+					padstates++;
+				}
+				if (err)
+					device_printf(sc->sc_dev, "err: failed to configure"
+						"pin \"%s\"\n", padconf->ballname);
+			}
+			padconf++;
+		}
+	}
+	return (0);
+}
+
+/*
+ * Device part of OMAP SCM driver
+ */
+
+static int
+ti_scm_probe(device_t dev)
+{
+	if (!ofw_bus_is_compatible(dev, "ti,scm"))
+		return (ENXIO);
+
+	device_set_desc(dev, "TI Control Module");
+	return (BUS_PROBE_DEFAULT);
+}
+
+/**
+ *	ti_scm_attach - attaches the timer to the simplebus
+ *	@dev: new device
+ *
+ *	Reserves memory and interrupt resources, stores the softc structure
+ *	globally and registers both the timecount and eventtimer objects.
+ *
+ *	RETURNS
+ *	Zero on sucess or ENXIO if an error occuried.
+ */
+static int
+ti_scm_attach(device_t dev)
+{
+	struct ti_scm_softc *sc = device_get_softc(dev);
+
+	if (ti_scm_sc)
+		return (ENXIO);
+
+	sc->sc_dev = dev;
+
+	if (bus_alloc_resources(dev, ti_scm_res_spec, sc->sc_res)) {
+		device_printf(dev, "could not allocate resources\n");
+		return (ENXIO);
+	}
+
+	/* Global timer interface */
+	sc->sc_bst = rman_get_bustag(sc->sc_res[0]);
+	sc->sc_bsh = rman_get_bushandle(sc->sc_res[0]);
+
+	ti_scm_sc = sc;
+
+	ti_scm_padconf_init_from_fdt(sc);
+
+	return (0);
+}
+
+int
+ti_scm_reg_read_4(uint32_t reg, uint32_t *val)
+{
+	if (!ti_scm_sc)
+		return (ENXIO);
+
+	*val = ti_scm_read_4(ti_scm_sc, reg);
+	return (0);
+}
+
+int
+ti_scm_reg_write_4(uint32_t reg, uint32_t val)
+{
+	if (!ti_scm_sc)
+		return (ENXIO);
+
+	ti_scm_write_4(ti_scm_sc, reg, val);
+	return (0);
+}
+
+
+static device_method_t ti_scm_methods[] = {
+	DEVMETHOD(device_probe,		ti_scm_probe),
+	DEVMETHOD(device_attach,	ti_scm_attach),
+	{ 0, 0 }
+};
+
+static driver_t ti_scm_driver = {
+	"ti_scm",
+	ti_scm_methods,
+	sizeof(struct ti_scm_softc),
+};
+
+static devclass_t ti_scm_devclass;
+
+DRIVER_MODULE(ti_scm, simplebus, ti_scm_driver, ti_scm_devclass, 0, 0);
diff -r 7fffa673adcd -r a301a330526b head/sys/arm/ti/ti_scm.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/head/sys/arm/ti/ti_scm.h	Wed Aug 15 11:16:36 2012 +0300
@@ -0,0 +1,84 @@
+/*
+ * Copyright (c) 2010
+ *	Ben Gray <ben.r.gray at 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.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by Ben Gray.
+ * 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 BEN GRAY ``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 BEN GRAY 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: head/sys/arm/ti/ti_scm.h 239281 2012-08-15 06:31:32Z gonzo $
+ */
+
+
+/**
+ *	Functions to configure the PIN multiplexing on the chip.
+ *
+ *	This is different from the GPIO module in that it is used to configure the
+ *	pins between modules not just GPIO input output.
+ *
+ */
+#ifndef _TI_SCM_H_
+#define _TI_SCM_H_
+
+struct ti_scm_padconf {
+	uint16_t    reg_off;
+	uint16_t    gpio_pin;
+	uint16_t    gpio_mode;
+	const char  *ballname;
+	const char  *muxmodes[8];
+};
+
+struct ti_scm_padstate {
+	const char  *state;
+	uint16_t    reg;
+};
+
+struct ti_scm_device {
+	uint16_t		padconf_muxmode_mask;
+	uint16_t		padconf_sate_mask;
+	struct ti_scm_padstate	*padstate;
+	struct ti_scm_padconf	*padconf;
+};
+
+struct ti_scm_softc {
+	device_t		sc_dev;
+	struct resource *	sc_res[4];
+	bus_space_tag_t		sc_bst;
+	bus_space_handle_t	sc_bsh;
+};
+
+int ti_scm_padconf_set(const char *padname, const char *muxmode, 
+    unsigned int state);
+int ti_scm_padconf_get(const char *padname, const char **muxmode,
+    unsigned int *state);
+int ti_scm_padconf_set_gpiomode(uint32_t gpio, unsigned int state);
+int ti_scm_padconf_get_gpiomode(uint32_t gpio, unsigned int *state);
+int ti_scm_padconf_set_gpioflags(uint32_t gpio, uint32_t flags);
+void ti_scm_padconf_get_gpioflags(uint32_t gpio, uint32_t *flags);
+int ti_scm_reg_read_4(uint32_t reg, uint32_t *val);
+int ti_scm_reg_write_4(uint32_t reg, uint32_t val);
+
+#endif /* _TI_SCM_H_ */
diff -r 7fffa673adcd -r a301a330526b head/sys/arm/ti/ti_sdma.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/head/sys/arm/ti/ti_sdma.c	Wed Aug 15 11:16:36 2012 +0300
@@ -0,0 +1,1246 @@
+/*-
+ * Copyright (c) 2011
+ *	Ben Gray <ben.r.gray at 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: head/sys/arm/ti/ti_sdma.c 239281 2012-08-15 06:31:32Z gonzo $");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/bus.h>
+#include <sys/kernel.h>
+#include <sys/lock.h>
+#include <sys/interrupt.h>
+#include <sys/module.h>
+#include <sys/malloc.h>
+#include <sys/mutex.h>
+#include <sys/rman.h>
+#include <sys/queue.h>
+#include <sys/taskqueue.h>
+#include <sys/timetc.h>
+#include <machine/bus.h>
+#include <machine/intr.h>
+
+#include <dev/fdt/fdt_common.h>
+#include <dev/ofw/openfirm.h>
+#include <dev/ofw/ofw_bus.h>
+#include <dev/ofw/ofw_bus_subr.h>
+
+#include <arm/ti/ti_cpuid.h>
+#include <arm/ti/ti_prcm.h>
+#include <arm/ti/ti_sdma.h>
+#include <arm/ti/ti_sdmareg.h>
+
+/**
+ *	Kernel functions for using the DMA controller
+ *
+ *
+ *	DMA TRANSFERS:
+ *	A DMA transfer block consists of a number of frames (FN). Each frame
+ *	consists of a number of elements, and each element can have a size of 8, 16,
+ *	or 32 bits.
+ *
+ *	OMAP44xx and newer chips support linked list (aka scatter gather) transfers,
+ *	where a linked list of source/destination pairs can be placed in memory
+ *	for the H/W to process.  Earlier chips only allowed you to chain multiple
+ *	channels together.  However currently this linked list feature is not
+ *	supported by the driver.
+ *
+ */
+
+/**
+ *	Data structure per DMA channel.
+ *
+ *
+ */
+struct ti_sdma_channel {
+
+	/* 
+	 * The configuration registers for the given channel, these are modified
+	 * by the set functions and only written to the actual registers when a
+	 * transaction is started.
+	 */
+	uint32_t		reg_csdp;
+	uint32_t		reg_ccr;
+	uint32_t		reg_cicr;
+
+	/* Set when one of the configuration registers above change */
+	uint32_t		need_reg_write;
+
+	/* Callback function used when an interrupt is tripped on the given channel */
+	void (*callback)(unsigned int ch, uint32_t ch_status, void *data);
+
+	/* Callback data passed in the callback ... duh */
+	void*			callback_data;
+
+};
+
+/**
+ *	DMA driver context, allocated and stored globally, this driver is not
+ *	intetned to ever be unloaded (see ti_sdma_sc).
+ *
+ */
+struct ti_sdma_softc {
+	device_t		sc_dev;
+	struct resource*	sc_irq_res;
+	struct resource*	sc_mem_res;
+
+	/* 
+	 * I guess in theory we should have a mutex per DMA channel for register
+	 * modifications. But since we know we are never going to be run on a SMP
+	 * system, we can use just the single lock for all channels.
+	 */
+	struct mtx		sc_mtx;
+
+	/* Stores the H/W revision read from the registers */
+	uint32_t		sc_hw_rev;
+
+	/* 
+	 * Bits in the sc_active_channels data field indicate if the channel has
+	 * been activated.
+	 */
+	uint32_t		sc_active_channels;
+
+	struct ti_sdma_channel sc_channel[NUM_DMA_CHANNELS];
+
+};
+
+static struct ti_sdma_softc *ti_sdma_sc = NULL;
+
+/**
+ *	Macros for driver mutex locking
+ */
+#define TI_SDMA_LOCK(_sc)             mtx_lock_spin(&(_sc)->sc_mtx)
+#define TI_SDMA_UNLOCK(_sc)           mtx_unlock_spin(&(_sc)->sc_mtx)
+#define TI_SDMA_LOCK_INIT(_sc) \
+	mtx_init(&_sc->sc_mtx, device_get_nameunit(_sc->sc_dev), \
+	         "ti_sdma", MTX_SPIN)
+#define TI_SDMA_LOCK_DESTROY(_sc)     mtx_destroy(&_sc->sc_mtx);
+#define TI_SDMA_ASSERT_LOCKED(_sc)    mtx_assert(&_sc->sc_mtx, MA_OWNED);
+#define TI_SDMA_ASSERT_UNLOCKED(_sc)  mtx_assert(&_sc->sc_mtx, MA_NOTOWNED);
+
+/**
+ *	Function prototypes
+ *
+ */
+static void ti_sdma_intr(void *);
+
+/**
+ *	ti_sdma_read_4 - reads a 32-bit value from one of the DMA registers
+ *	@sc: DMA device context
+ *	@off: The offset of a register from the DMA register address range
+ *
+ *
+ *	RETURNS:
+ *	32-bit value read from the register.
+ */
+static inline uint32_t
+ti_sdma_read_4(struct ti_sdma_softc *sc, bus_size_t off)
+{
+	return bus_read_4(sc->sc_mem_res, off);
+}
+
+/**
+ *	ti_sdma_write_4 - writes a 32-bit value to one of the DMA registers
+ *	@sc: DMA device context
+ *	@off: The offset of a register from the DMA register address range
+ *
+ *
+ *	RETURNS:
+ *	32-bit value read from the register.
+ */
+static inline void
+ti_sdma_write_4(struct ti_sdma_softc *sc, bus_size_t off, uint32_t val)
+{
+	bus_write_4(sc->sc_mem_res, off, val);
+}
+
+/**
+ *	ti_sdma_is_omap3_rev - returns true if H/W is from OMAP3 series
+ *	@sc: DMA device context
+ *
+ */
+static inline int
+ti_sdma_is_omap3_rev(struct ti_sdma_softc *sc)
+{
+	return (sc->sc_hw_rev == DMA4_OMAP3_REV);
+}
+
+/**
+ *	ti_sdma_is_omap4_rev - returns true if H/W is from OMAP4 series
+ *	@sc: DMA device context
+ *
+ */
+static inline int
+ti_sdma_is_omap4_rev(struct ti_sdma_softc *sc)
+{
+	return (sc->sc_hw_rev == DMA4_OMAP4_REV);
+}
+
+/**
+ *	ti_sdma_intr - interrupt handler for all 4 DMA IRQs
+ *	@arg: ignored
+ *
+ *	Called when any of the four DMA IRQs are triggered.
+ *
+ *	LOCKING:
+ *	DMA registers protected by internal mutex
+ *
+ *	RETURNS:
+ *	nothing
+ */
+static void
+ti_sdma_intr(void *arg)
+{
+	struct ti_sdma_softc *sc = ti_sdma_sc;
+	uint32_t intr;
+	uint32_t csr;
+	unsigned int ch, j;
+	struct ti_sdma_channel* channel;
+
+	TI_SDMA_LOCK(sc);
+
+	for (j = 0; j < NUM_DMA_IRQS; j++) {
+
+		/* Get the flag interrupts (enabled) */
+		intr = ti_sdma_read_4(sc, DMA4_IRQSTATUS_L(j));
+		intr &= ti_sdma_read_4(sc, DMA4_IRQENABLE_L(j));
+		if (intr == 0x00000000)
+			continue;
+
+		/* Loop through checking the status bits */
+		for (ch = 0; ch < NUM_DMA_CHANNELS; ch++) {
+			if (intr & (1 << ch)) {
+				channel = &sc->sc_channel[ch];
+
+				/* Read the CSR regsiter and verify we don't have a spurious IRQ */
+				csr = ti_sdma_read_4(sc, DMA4_CSR(ch));
+				if (csr == 0) {
+					device_printf(sc->sc_dev, "Spurious DMA IRQ for channel "
+					              "%d\n", ch);
+					continue;
+				}
+
+				/* Sanity check this channel is active */
+				if ((sc->sc_active_channels & (1 << ch)) == 0) {
+					device_printf(sc->sc_dev, "IRQ %d for a non-activated "
+					              "channel %d\n", j, ch);
+					continue;
+				}
+
+				/* Check the status error codes */
+				if (csr & DMA4_CSR_DROP)
+					device_printf(sc->sc_dev, "Synchronization event drop "
+					              "occurred during the transfer on channel %u\n",
+								  ch);
+				if (csr & DMA4_CSR_SECURE_ERR)
+					device_printf(sc->sc_dev, "Secure transaction error event "
+					              "on channel %u\n", ch);
+				if (csr & DMA4_CSR_MISALIGNED_ADRS_ERR)
+					device_printf(sc->sc_dev, "Misaligned address error event "
+					              "on channel %u\n", ch);
+				if (csr & DMA4_CSR_TRANS_ERR) {
+					device_printf(sc->sc_dev, "Transaction error event on "
+					              "channel %u\n", ch);
+					/* 
+					 * Apparently according to linux code, there is an errata
+					 * that says the channel is not disabled upon this error.
+					 * They explicitly disable the channel here .. since I
+					 * haven't seen the errata, I'm going to ignore for now.
+					 */
+				}
+
+				/* Clear the status flags for the IRQ */
+				ti_sdma_write_4(sc, DMA4_CSR(ch), DMA4_CSR_CLEAR_MASK);
+				ti_sdma_write_4(sc, DMA4_IRQSTATUS_L(j), (1 << ch));
+
+				/* Call the callback for the given channel */
+				if (channel->callback)
+					channel->callback(ch, csr, channel->callback_data);
+			}
+		}
+	}
+
+	TI_SDMA_UNLOCK(sc);
+
+	return;
+}
+
+/**
+ *	ti_sdma_activate_channel - activates a DMA channel
+ *	@ch: upon return contains the channel allocated
+ *	@callback: a callback function to associate with the channel
+ *	@data: optional data supplied when the callback is called
+ *
+ *	Simply activates a channel be enabling and writing default values to the
+ *	channel's register set.  It doesn't start a transaction, just populates the
+ *	internal data structures and sets defaults.
+ *
+ *	Note this function doesn't enable interrupts, for that you need to call
+ *	ti_sdma_enable_channel_irq(). If not using IRQ to detect the end of the
+ *	transfer, you can use ti_sdma_status_poll() to detect a change in the
+ *	status.
+ *
+ *	A channel must be activated before any of the other DMA functions can be
+ *	called on it.
+ *
+ *	LOCKING:
+ *	DMA registers protected by internal mutex
+ *
+ *	RETURNS:
+ *	0 on success, otherwise an error code
+ */
+int
+ti_sdma_activate_channel(unsigned int *ch,
+                          void (*callback)(unsigned int ch, uint32_t status, void *data),
+                          void *data)
+{
+	struct ti_sdma_softc *sc = ti_sdma_sc;
+	struct ti_sdma_channel *channel = NULL;
+	uint32_t addr;
+	unsigned int i;
+
+	/* Sanity check */
+	if (sc == NULL)
+		return (ENOMEM);
+
+	if (ch == NULL)
+		return (EINVAL);
+
+	TI_SDMA_LOCK(sc);
+
+	/* Check to see if all channels are in use */
+	if (sc->sc_active_channels == 0xffffffff) {
+		TI_SDMA_UNLOCK(sc);
+		return (ENOMEM);
+	}
+
+	/* Find the first non-active channel */
+	for (i = 0; i < NUM_DMA_CHANNELS; i++) {
+		if (!(sc->sc_active_channels & (0x1 << i))) {
+			sc->sc_active_channels |= (0x1 << i);
+			*ch = i;
+			break;
+		}
+	}
+
+	/* Get the channel struct and populate the fields */
+	channel = &sc->sc_channel[*ch];
+
+	channel->callback = callback;
+	channel->callback_data = data;
+
+	channel->need_reg_write = 1;
+
+	/* Set the default configuration for the DMA channel */
+	channel->reg_csdp = DMA4_CSDP_DATA_TYPE(0x2)
+		| DMA4_CSDP_SRC_BURST_MODE(0)
+		| DMA4_CSDP_DST_BURST_MODE(0)
+		| DMA4_CSDP_SRC_ENDIANISM(0)
+		| DMA4_CSDP_DST_ENDIANISM(0)
+		| DMA4_CSDP_WRITE_MODE(0)
+		| DMA4_CSDP_SRC_PACKED(0)
+		| DMA4_CSDP_DST_PACKED(0);
+
+	channel->reg_ccr = DMA4_CCR_DST_ADDRESS_MODE(1)
+		| DMA4_CCR_SRC_ADDRESS_MODE(1)
+		| DMA4_CCR_READ_PRIORITY(0)
+		| DMA4_CCR_WRITE_PRIORITY(0)
+		| DMA4_CCR_SYNC_TRIGGER(0)
+		| DMA4_CCR_FRAME_SYNC(0)
+		| DMA4_CCR_BLOCK_SYNC(0);
+
+	channel->reg_cicr = DMA4_CICR_TRANS_ERR_IE
+		| DMA4_CICR_SECURE_ERR_IE
+		| DMA4_CICR_SUPERVISOR_ERR_IE
+		| DMA4_CICR_MISALIGNED_ADRS_ERR_IE;
+
+	/* Clear all the channel registers, this should abort any transaction */
+	for (addr = DMA4_CCR(*ch); addr <= DMA4_COLOR(*ch); addr += 4)
+		ti_sdma_write_4(sc, addr, 0x00000000);
+
+	TI_SDMA_UNLOCK(sc);
+
+	return 0;
+}
+
+/**
+ *	ti_sdma_deactivate_channel - deactivates a channel
+ *	@ch: the channel to deactivate
+ *
+ *
+ *
+ *	LOCKING:
+ *	DMA registers protected by internal mutex
+ *
+ *	RETURNS:
+ *	EH_HANDLED or EH_NOT_HANDLED
+ */
+int
+ti_sdma_deactivate_channel(unsigned int ch)
+{
+	struct ti_sdma_softc *sc = ti_sdma_sc;
+	unsigned int j;
+	unsigned int addr;
+
+	/* Sanity check */
+	if (sc == NULL)
+		return (ENOMEM);
+
+	TI_SDMA_LOCK(sc);
+
+	/* First check if the channel is currently active */
+	if ((sc->sc_active_channels & (1 << ch)) == 0) {
+		TI_SDMA_UNLOCK(sc);
+		return (EBUSY);
+	}
+
+	/* Mark the channel as inactive */
+	sc->sc_active_channels &= ~(1 << ch);
+
+	/* Disable all DMA interrupts for the channel. */
+	ti_sdma_write_4(sc, DMA4_CICR(ch), 0);
+
+	/* Make sure the DMA transfer is stopped. */
+	ti_sdma_write_4(sc, DMA4_CCR(ch), 0);
+
+	/* Clear the CSR register and IRQ status register */
+	ti_sdma_write_4(sc, DMA4_CSR(ch), DMA4_CSR_CLEAR_MASK);
+	for (j = 0; j < NUM_DMA_IRQS; j++) {
+		ti_sdma_write_4(sc, DMA4_IRQSTATUS_L(j), (1 << ch));
+	}
+
+	/* Clear all the channel registers, this should abort any transaction */
+	for (addr = DMA4_CCR(ch); addr <= DMA4_COLOR(ch); addr += 4)
+		ti_sdma_write_4(sc, addr, 0x00000000);
+
+	TI_SDMA_UNLOCK(sc);
+
+	return 0;
+}
+
+/**
+ *	ti_sdma_disable_channel_irq - disables IRQ's on the given channel
+ *	@ch: the channel to disable IRQ's on
+ *
+ *	Disable interupt generation for the given channel.
+ *
+ *	LOCKING:
+ *	DMA registers protected by internal mutex
+ *
+ *	RETURNS:
+ *	EH_HANDLED or EH_NOT_HANDLED
+ */
+int
+ti_sdma_disable_channel_irq(unsigned int ch)
+{
+	struct ti_sdma_softc *sc = ti_sdma_sc;
+	uint32_t irq_enable;
+	unsigned int j;
+
+	/* Sanity check */
+	if (sc == NULL)
+		return (ENOMEM);
+
+	TI_SDMA_LOCK(sc);
+
+	if ((sc->sc_active_channels & (1 << ch)) == 0) {
+		TI_SDMA_UNLOCK(sc);
+		return (EINVAL);
+	}
+
+	/* Disable all the individual error conditions */
+	sc->sc_channel[ch].reg_cicr = 0x0000;
+	ti_sdma_write_4(sc, DMA4_CICR(ch), 0x0000);
+
+	/* Disable the channel interrupt enable */
+	for (j = 0; j < NUM_DMA_IRQS; j++) {
+		irq_enable = ti_sdma_read_4(sc, DMA4_IRQENABLE_L(j));
+		irq_enable &= ~(1 << ch);
+
+		ti_sdma_write_4(sc, DMA4_IRQENABLE_L(j), irq_enable);
+	}
+
+	/* Indicate the registers need to be rewritten on the next transaction */
+	sc->sc_channel[ch].need_reg_write = 1;
+
+	TI_SDMA_UNLOCK(sc);
+
+	return (0);
+}
+
+/**
+ *	ti_sdma_disable_channel_irq - enables IRQ's on the given channel
+ *	@ch: the channel to enable IRQ's on
+ *	@flags: bitmask of interrupt types to enable
+ *
+ *	Flags can be a bitmask of the following options:
+ *		DMA_IRQ_FLAG_DROP
+ *		DMA_IRQ_FLAG_HALF_FRAME_COMPL
+ *		DMA_IRQ_FLAG_FRAME_COMPL
+ *		DMA_IRQ_FLAG_START_LAST_FRAME
+ *		DMA_IRQ_FLAG_BLOCK_COMPL
+ *		DMA_IRQ_FLAG_ENDOF_PKT
+ *		DMA_IRQ_FLAG_DRAIN
+ *
+ *
+ *	LOCKING:
+ *	DMA registers protected by internal mutex
+ *
+ *	RETURNS:
+ *	EH_HANDLED or EH_NOT_HANDLED
+ */
+int
+ti_sdma_enable_channel_irq(unsigned int ch, uint32_t flags)
+{
+	struct ti_sdma_softc *sc = ti_sdma_sc;
+	uint32_t irq_enable;
+
+	/* Sanity check */
+	if (sc == NULL)
+		return (ENOMEM);
+
+	TI_SDMA_LOCK(sc);
+
+	if ((sc->sc_active_channels & (1 << ch)) == 0) {
+		TI_SDMA_UNLOCK(sc);
+		return (EINVAL);
+	}
+
+	/* Always enable the error interrupts if we have interrupts enabled */
+	flags |= DMA4_CICR_TRANS_ERR_IE | DMA4_CICR_SECURE_ERR_IE |
+	         DMA4_CICR_SUPERVISOR_ERR_IE | DMA4_CICR_MISALIGNED_ADRS_ERR_IE;
+
+	sc->sc_channel[ch].reg_cicr = flags;
+
+	/* Write the values to the register */
+	ti_sdma_write_4(sc, DMA4_CICR(ch), flags);
+
+	/* Enable the channel interrupt enable */
+	irq_enable = ti_sdma_read_4(sc, DMA4_IRQENABLE_L(0));
+	irq_enable |= (1 << ch);
+
+	ti_sdma_write_4(sc, DMA4_IRQENABLE_L(0), irq_enable);
+
+	/* Indicate the registers need to be rewritten on the next transaction */
+	sc->sc_channel[ch].need_reg_write = 1;
+
+	TI_SDMA_UNLOCK(sc);
+
+	return (0);
+}
+
+/**
+ *	ti_sdma_get_channel_status - returns the status of a given channel
+ *	@ch: the channel number to get the status of
+ *	@status: upon return will contain the status bitmask, see below for possible
+ *	         values.
+ *
+ *	      DMA_STATUS_DROP
+ *	      DMA_STATUS_HALF
+ *	      DMA_STATUS_FRAME
+ *	      DMA_STATUS_LAST
+ *	      DMA_STATUS_BLOCK
+ *	      DMA_STATUS_SYNC
+ *	      DMA_STATUS_PKT
+ *	      DMA_STATUS_TRANS_ERR
+ *	      DMA_STATUS_SECURE_ERR
+ *	      DMA_STATUS_SUPERVISOR_ERR
+ *	      DMA_STATUS_MISALIGNED_ADRS_ERR
+ *	      DMA_STATUS_DRAIN_END
+ *
+ *
+ *	LOCKING:
+ *	DMA registers protected by internal mutex
+ *
+ *	RETURNS:
+ *	EH_HANDLED or EH_NOT_HANDLED
+ */
+int
+ti_sdma_get_channel_status(unsigned int ch, uint32_t *status)
+{
+	struct ti_sdma_softc *sc = ti_sdma_sc;
+	uint32_t csr;
+
+	/* Sanity check */
+	if (sc == NULL)
+		return (ENOMEM);
+
+	TI_SDMA_LOCK(sc);
+
+	if ((sc->sc_active_channels & (1 << ch)) == 0) {
+		TI_SDMA_UNLOCK(sc);
+		return (EINVAL);
+	}
+
+	TI_SDMA_UNLOCK(sc);
+
+	csr = ti_sdma_read_4(sc, DMA4_CSR(ch));
+
+	if (status != NULL)
+		*status = csr;
+
+	return (0);
+}
+
+/**
+ *	ti_sdma_start_xfer - starts a DMA transfer
+ *	@ch: the channel number to set the endianess of
+ *	@src_paddr: the source phsyical address
+ *	@dst_paddr: the destination phsyical address
+ *	@frmcnt: the number of frames per block
+ *	@elmcnt: the number of elements in a frame, an element is either an 8, 16
+ *           or 32-bit value as defined by ti_sdma_set_xfer_burst()
+ *
+ *
+ *	LOCKING:
+ *	DMA registers protected by internal mutex
+ *
+ *	RETURNS:
+ *	EH_HANDLED or EH_NOT_HANDLED
+ */
+int
+ti_sdma_start_xfer(unsigned int ch, unsigned int src_paddr,
+                    unsigned long dst_paddr,
+                    unsigned int frmcnt, unsigned int elmcnt)
+{
+	struct ti_sdma_softc *sc = ti_sdma_sc;
+	struct ti_sdma_channel *channel;
+	uint32_t ccr;
+
+	/* Sanity check */
+	if (sc == NULL)
+		return (ENOMEM);
+
+	TI_SDMA_LOCK(sc);
+
+	if ((sc->sc_active_channels & (1 << ch)) == 0) {
+		TI_SDMA_UNLOCK(sc);
+		return (EINVAL);
+	}
+
+	channel = &sc->sc_channel[ch];
+
+	/* a) Write the CSDP register */
+	ti_sdma_write_4(sc, DMA4_CSDP(ch),
+	    channel->reg_csdp | DMA4_CSDP_WRITE_MODE(1));
+
+	/* b) Set the number of element per frame CEN[23:0] */
+	ti_sdma_write_4(sc, DMA4_CEN(ch), elmcnt);
+
+	/* c) Set the number of frame per block CFN[15:0] */
+	ti_sdma_write_4(sc, DMA4_CFN(ch), frmcnt);
+
+	/* d) Set the Source/dest start address index CSSA[31:0]/CDSA[31:0] */
+	ti_sdma_write_4(sc, DMA4_CSSA(ch), src_paddr);
+	ti_sdma_write_4(sc, DMA4_CDSA(ch), dst_paddr);
+
+	/* e) Write the CCR register */
+	ti_sdma_write_4(sc, DMA4_CCR(ch), channel->reg_ccr);
+
+	/* f)  - Set the source element index increment CSEI[15:0] */
+	ti_sdma_write_4(sc, DMA4_CSE(ch), 0x0001);
+
+	/*     - Set the source frame index increment CSFI[15:0] */
+	ti_sdma_write_4(sc, DMA4_CSF(ch), 0x0001);
+
+	/*     - Set the destination element index increment CDEI[15:0]*/
+	ti_sdma_write_4(sc, DMA4_CDE(ch), 0x0001);
+
+	/* - Set the destination frame index increment CDFI[31:0] */
+	ti_sdma_write_4(sc, DMA4_CDF(ch), 0x0001);
+
+	/* Clear the status register */
+	ti_sdma_write_4(sc, DMA4_CSR(ch), 0x1FFE);
+
+	/* Write the start-bit and away we go */
+	ccr = ti_sdma_read_4(sc, DMA4_CCR(ch));
+	ccr |= (1 << 7);
+	ti_sdma_write_4(sc, DMA4_CCR(ch), ccr);
+
+	/* Clear the reg write flag */
+	channel->need_reg_write = 0;
+
+	TI_SDMA_UNLOCK(sc);
+
+	return (0);
+}
+
+/**
+ *	ti_sdma_start_xfer_packet - starts a packet DMA transfer
+ *	@ch: the channel number to use for the transfer
+ *	@src_paddr: the source physical address
+ *	@dst_paddr: the destination physical address
+ *	@frmcnt: the number of frames to transfer
+ *	@elmcnt: the number of elements in a frame, an element is either an 8, 16
+ *           or 32-bit value as defined by ti_sdma_set_xfer_burst()
+ *	@pktsize: the number of elements in each transfer packet
+ *
+ *	The @frmcnt and @elmcnt define the overall number of bytes to transfer,
+ *	typically @frmcnt is 1 and @elmcnt contains the total number of elements.
+ *	@pktsize is the size of each individual packet, there might be multiple
+ *	packets per transfer.  i.e. for the following with element size of 32-bits
+ *
+ *		frmcnt = 1, elmcnt = 512, pktsize = 128
+ *
+ *	       Total transfer bytes = 1 * 512 = 512 elements or 2048 bytes
+ *	       Packets transfered   = 128 / 512 = 4
+ *
+ *
+ *	LOCKING:
+ *	DMA registers protected by internal mutex
+ *
+ *	RETURNS:
+ *	EH_HANDLED or EH_NOT_HANDLED
+ */
+int
+ti_sdma_start_xfer_packet(unsigned int ch, unsigned int src_paddr,
+                           unsigned long dst_paddr, unsigned int frmcnt,
+                           unsigned int elmcnt, unsigned int pktsize)
+{
+	struct ti_sdma_softc *sc = ti_sdma_sc;
+	struct ti_sdma_channel *channel;
+	uint32_t ccr;
+
+	/* Sanity check */
+	if (sc == NULL)
+		return (ENOMEM);
+
+	TI_SDMA_LOCK(sc);
+
+	if ((sc->sc_active_channels & (1 << ch)) == 0) {
+		TI_SDMA_UNLOCK(sc);
+		return (EINVAL);
+	}
+
+	channel = &sc->sc_channel[ch];
+
+	/* a) Write the CSDP register */
+	if (channel->need_reg_write)
+		ti_sdma_write_4(sc, DMA4_CSDP(ch),
+		    channel->reg_csdp | DMA4_CSDP_WRITE_MODE(1));
+
+	/* b) Set the number of elements to transfer CEN[23:0] */
+	ti_sdma_write_4(sc, DMA4_CEN(ch), elmcnt);
+
+	/* c) Set the number of frames to transfer CFN[15:0] */
+	ti_sdma_write_4(sc, DMA4_CFN(ch), frmcnt);
+
+	/* d) Set the Source/dest start address index CSSA[31:0]/CDSA[31:0] */
+	ti_sdma_write_4(sc, DMA4_CSSA(ch), src_paddr);
+	ti_sdma_write_4(sc, DMA4_CDSA(ch), dst_paddr);
+
+	/* e) Write the CCR register */
+	ti_sdma_write_4(sc, DMA4_CCR(ch),
+	    channel->reg_ccr | DMA4_CCR_PACKET_TRANS);
+
+	/* f)  - Set the source element index increment CSEI[15:0] */
+	ti_sdma_write_4(sc, DMA4_CSE(ch), 0x0001);
+
+	/*     - Set the packet size, this is dependent on the sync source */
+	if (channel->reg_ccr & DMA4_CCR_SEL_SRC_DST_SYNC(1))
+		ti_sdma_write_4(sc, DMA4_CSF(ch), pktsize);
+	else
+		ti_sdma_write_4(sc, DMA4_CDF(ch), pktsize);
+
+	/* - Set the destination frame index increment CDFI[31:0] */
+	ti_sdma_write_4(sc, DMA4_CDE(ch), 0x0001);
+
+	/* Clear the status register */
+	ti_sdma_write_4(sc, DMA4_CSR(ch), 0x1FFE);
+
+	/* Write the start-bit and away we go */
+	ccr = ti_sdma_read_4(sc, DMA4_CCR(ch));
+	ccr |= (1 << 7);
+	ti_sdma_write_4(sc, DMA4_CCR(ch), ccr);
+
+	/* Clear the reg write flag */
+	channel->need_reg_write = 0;
+
+	TI_SDMA_UNLOCK(sc);
+
+	return (0);
+}
+
+/**
+ *	ti_sdma_stop_xfer - stops any currently active transfers
+ *	@ch: the channel number to set the endianess of
+ *
+ *	This function call is effectively a NOP if no transaction is in progress.
+ *
+ *	LOCKING:
+ *	DMA registers protected by internal mutex
+ *
+ *	RETURNS:
+ *	EH_HANDLED or EH_NOT_HANDLED
+ */
+int
+ti_sdma_stop_xfer(unsigned int ch)
+{
+	struct ti_sdma_softc *sc = ti_sdma_sc;
+	unsigned int j;
+
+	/* Sanity check */
+	if (sc == NULL)
+		return (ENOMEM);
+
+	TI_SDMA_LOCK(sc);
+
+	if ((sc->sc_active_channels & (1 << ch)) == 0) {
+		TI_SDMA_UNLOCK(sc);
+		return (EINVAL);
+	}
+
+	/* Disable all DMA interrupts for the channel. */
+	ti_sdma_write_4(sc, DMA4_CICR(ch), 0);
+
+	/* Make sure the DMA transfer is stopped. */
+	ti_sdma_write_4(sc, DMA4_CCR(ch), 0);
+
+	/* Clear the CSR register and IRQ status register */
+	ti_sdma_write_4(sc, DMA4_CSR(ch), DMA4_CSR_CLEAR_MASK);
+	for (j = 0; j < NUM_DMA_IRQS; j++) {
+		ti_sdma_write_4(sc, DMA4_IRQSTATUS_L(j), (1 << ch));
+	}
+
+	/* Configuration registers need to be re-written on the next xfer */
+	sc->sc_channel[ch].need_reg_write = 1;
+
+	TI_SDMA_UNLOCK(sc);
+
+	return (0);
+}
+
+/**
+ *	ti_sdma_set_xfer_endianess - sets the endianess of subsequent transfers
+ *	@ch: the channel number to set the endianess of
+ *	@src: the source endianess (either DMA_ENDIAN_LITTLE or DMA_ENDIAN_BIG)
+ *	@dst: the destination endianess (either DMA_ENDIAN_LITTLE or DMA_ENDIAN_BIG)
+ *
+ *
+ *	LOCKING:
+ *	DMA registers protected by internal mutex
+ *
+ *	RETURNS:
+ *	EH_HANDLED or EH_NOT_HANDLED
+ */
+int
+ti_sdma_set_xfer_endianess(unsigned int ch, unsigned int src, unsigned int dst)
+{
+	struct ti_sdma_softc *sc = ti_sdma_sc;
+
+	/* Sanity check */
+	if (sc == NULL)
+		return (ENOMEM);
+
+	TI_SDMA_LOCK(sc);
+
+	if ((sc->sc_active_channels & (1 << ch)) == 0) {
+		TI_SDMA_UNLOCK(sc);
+		return (EINVAL);
+	}
+
+	sc->sc_channel[ch].reg_csdp &= ~DMA4_CSDP_SRC_ENDIANISM(1);
+	sc->sc_channel[ch].reg_csdp |= DMA4_CSDP_SRC_ENDIANISM(src);
+
+	sc->sc_channel[ch].reg_csdp &= ~DMA4_CSDP_DST_ENDIANISM(1);
+	sc->sc_channel[ch].reg_csdp |= DMA4_CSDP_DST_ENDIANISM(dst);
+
+	sc->sc_channel[ch].need_reg_write = 1;
+
+	TI_SDMA_UNLOCK(sc);
+
+	return 0;
+}
+
+/**
+ *	ti_sdma_set_xfer_burst - sets the source and destination element size
+ *	@ch: the channel number to set the burst settings of
+ *	@src: the source endianess (either DMA_BURST_NONE, DMA_BURST_16, DMA_BURST_32
+ *	      or DMA_BURST_64)
+ *	@dst: the destination endianess (either DMA_BURST_NONE, DMA_BURST_16,
+ *	      DMA_BURST_32 or DMA_BURST_64)
+ *
+ *	This function sets the size of the elements for all subsequent transfers.
+ *
+ *	LOCKING:
+ *	DMA registers protected by internal mutex
+ *
+ *	RETURNS:
+ *	EH_HANDLED or EH_NOT_HANDLED
+ */
+int
+ti_sdma_set_xfer_burst(unsigned int ch, unsigned int src, unsigned int dst)
+{
+	struct ti_sdma_softc *sc = ti_sdma_sc;
+
+	/* Sanity check */
+	if (sc == NULL)
+		return (ENOMEM);
+
+	TI_SDMA_LOCK(sc);
+
+	if ((sc->sc_active_channels & (1 << ch)) == 0) {
+		TI_SDMA_UNLOCK(sc);
+		return (EINVAL);
+	}
+
+	sc->sc_channel[ch].reg_csdp &= ~DMA4_CSDP_SRC_BURST_MODE(0x3);
+	sc->sc_channel[ch].reg_csdp |= DMA4_CSDP_SRC_BURST_MODE(src);
+
+	sc->sc_channel[ch].reg_csdp &= ~DMA4_CSDP_DST_BURST_MODE(0x3);
+	sc->sc_channel[ch].reg_csdp |= DMA4_CSDP_DST_BURST_MODE(dst);
+
+	sc->sc_channel[ch].need_reg_write = 1;
+
+	TI_SDMA_UNLOCK(sc);
+
+	return 0;
+}
+
+/**
+ *	ti_sdma_set_xfer_data_type - driver attach function
+ *	@ch: the channel number to set the endianess of
+ *	@type: the xfer data type (either DMA_DATA_8BITS_SCALAR, DMA_DATA_16BITS_SCALAR
+ *	       or DMA_DATA_32BITS_SCALAR)
+ *
+ *
+ *	LOCKING:
+ *	DMA registers protected by internal mutex
+ *
+ *	RETURNS:
+ *	EH_HANDLED or EH_NOT_HANDLED
+ */
+int
+ti_sdma_set_xfer_data_type(unsigned int ch, unsigned int type)
+{
+	struct ti_sdma_softc *sc = ti_sdma_sc;
+
+	/* Sanity check */
+	if (sc == NULL)
+		return (ENOMEM);
+
+	TI_SDMA_LOCK(sc);
+
+	if ((sc->sc_active_channels & (1 << ch)) == 0) {
+		TI_SDMA_UNLOCK(sc);
+		return (EINVAL);
+	}
+
+	sc->sc_channel[ch].reg_csdp &= ~DMA4_CSDP_DATA_TYPE(0x3);
+	sc->sc_channel[ch].reg_csdp |= DMA4_CSDP_DATA_TYPE(type);
+
+	sc->sc_channel[ch].need_reg_write = 1;
+
+	TI_SDMA_UNLOCK(sc);
+
+	return 0;
+}
+
+/**
+ *	ti_sdma_set_callback - driver attach function
+ *	@dev: dma device handle
+ *
+ *
+ *
+ *	LOCKING:
+ *	DMA registers protected by internal mutex
+ *
+ *	RETURNS:
+ *	EH_HANDLED or EH_NOT_HANDLED
+ */
+int
+ti_sdma_set_callback(unsigned int ch,
+                      void (*callback)(unsigned int ch, uint32_t status, void *data),
+                      void *data)
+{
+	struct ti_sdma_softc *sc = ti_sdma_sc;
+
+	/* Sanity check */
+	if (sc == NULL)
+		return (ENOMEM);
+
+	TI_SDMA_LOCK(sc);
+
+	if ((sc->sc_active_channels & (1 << ch)) == 0) {
+		TI_SDMA_UNLOCK(sc);
+		return (EINVAL);
+	}
+
+	sc->sc_channel[ch].callback = callback;
+	sc->sc_channel[ch].callback_data = data;
+
+	sc->sc_channel[ch].need_reg_write = 1;
+
+	TI_SDMA_UNLOCK(sc);
+
+	return 0;
+}
+
+/**
+ *	ti_sdma_sync_params - sets channel sync settings
+ *	@ch: the channel number to set the sync on
+ *	@trigger: the number of the sync trigger, this depends on what other H/W
+ *	          module is triggering/receiving the DMA transactions
+ *	@mode: flags describing the sync mode to use, it may have one or more of
+ *	          the following bits set; TI_SDMA_SYNC_FRAME,
+ *	          TI_SDMA_SYNC_BLOCK, TI_SDMA_SYNC_TRIG_ON_SRC.
+ *
+ *
+ *
+ *	LOCKING:
+ *	DMA registers protected by internal mutex
+ *
+ *	RETURNS:
+ *	EH_HANDLED or EH_NOT_HANDLED
+ */
+int
+ti_sdma_sync_params(unsigned int ch, unsigned int trigger, unsigned int mode)
+{
+	struct ti_sdma_softc *sc = ti_sdma_sc;
+	uint32_t ccr;
+
+	/* Sanity check */
+	if (sc == NULL)
+		return (ENOMEM);
+
+	TI_SDMA_LOCK(sc);
+
+	if ((sc->sc_active_channels & (1 << ch)) == 0) {
+		TI_SDMA_UNLOCK(sc);
+		return (EINVAL);
+	}
+
+	ccr = sc->sc_channel[ch].reg_ccr;
+
+	ccr &= ~DMA4_CCR_SYNC_TRIGGER(0x7F);
+	ccr |= DMA4_CCR_SYNC_TRIGGER(trigger + 1);
+
+	if (mode & TI_SDMA_SYNC_FRAME)
+		ccr |= DMA4_CCR_FRAME_SYNC(1);
+	else
+		ccr &= ~DMA4_CCR_FRAME_SYNC(1);
+
+	if (mode & TI_SDMA_SYNC_BLOCK)
+		ccr |= DMA4_CCR_BLOCK_SYNC(1);
+	else
+		ccr &= ~DMA4_CCR_BLOCK_SYNC(1);
+
+	if (mode & TI_SDMA_SYNC_TRIG_ON_SRC)
+		ccr |= DMA4_CCR_SEL_SRC_DST_SYNC(1);
+	else
+		ccr &= ~DMA4_CCR_SEL_SRC_DST_SYNC(1);
+
+	sc->sc_channel[ch].reg_ccr = ccr;
+
+	sc->sc_channel[ch].need_reg_write = 1;
+
+	TI_SDMA_UNLOCK(sc);
+
+	return 0;
+}
+
+/**
+ *	ti_sdma_set_addr_mode - driver attach function
+ *	@ch: the channel number to set the endianess of
+ *	@rd_mode: the xfer source addressing mode (either DMA_ADDR_CONSTANT,
+ *	          DMA_ADDR_POST_INCREMENT, DMA_ADDR_SINGLE_INDEX or
+ *	          DMA_ADDR_DOUBLE_INDEX)
+ *	@wr_mode: the xfer destination addressing mode (either DMA_ADDR_CONSTANT,
+ *	          DMA_ADDR_POST_INCREMENT, DMA_ADDR_SINGLE_INDEX or
+ *	          DMA_ADDR_DOUBLE_INDEX)
+ *
+ *
+ *	LOCKING:
+ *	DMA registers protected by internal mutex
+ *
+ *	RETURNS:
+ *	EH_HANDLED or EH_NOT_HANDLED
+ */
+int
+ti_sdma_set_addr_mode(unsigned int ch, unsigned int src_mode,
+                       unsigned int dst_mode)
+{
+	struct ti_sdma_softc *sc = ti_sdma_sc;
+	uint32_t ccr;
+
+	/* Sanity check */
+	if (sc == NULL)
+		return (ENOMEM);
+
+	TI_SDMA_LOCK(sc);
+
+	if ((sc->sc_active_channels & (1 << ch)) == 0) {
+		TI_SDMA_UNLOCK(sc);
+		return (EINVAL);
+	}
+
+	ccr = sc->sc_channel[ch].reg_ccr;
+
+	ccr &= ~DMA4_CCR_SRC_ADDRESS_MODE(0x3);
+	ccr |= DMA4_CCR_SRC_ADDRESS_MODE(src_mode);
+
+	ccr &= ~DMA4_CCR_DST_ADDRESS_MODE(0x3);
+	ccr |= DMA4_CCR_DST_ADDRESS_MODE(dst_mode);
+
+	sc->sc_channel[ch].reg_ccr = ccr;
+
+	sc->sc_channel[ch].need_reg_write = 1;
+
+	TI_SDMA_UNLOCK(sc);
+
+	return 0;
+}
+
+/**
+ *	ti_sdma_probe - driver probe function
+ *	@dev: dma device handle
+ *
+ *
+ *
+ *	RETURNS:
+ *	Always returns 0.
+ */
+static int
+ti_sdma_probe(device_t dev)
+{
+	if (!ofw_bus_is_compatible(dev, "ti,sdma"))
+		return (ENXIO);
+
+	device_set_desc(dev, "TI sDMA Controller");
+	return (0);
+}
+
+/**
+ *	ti_sdma_attach - driver attach function
+ *	@dev: dma device handle
+ *
+ *	Initialises memory mapping/pointers to the DMA register set and requests
+ *	IRQs. This is effectively the setup function for the driver.
+ *
+ *	RETURNS:
+ *	0 on success or a negative error code failure.
+ */
+static int
+ti_sdma_attach(device_t dev)
+{
+	struct ti_sdma_softc *sc = device_get_softc(dev);
+	unsigned int timeout;
+	unsigned int i;
+	int      rid;
+	void    *ihl;
+	int      err;
+
+	/* Setup the basics */
+	sc->sc_dev = dev;
+
+	/* No channels active at the moment */
+	sc->sc_active_channels = 0x00000000;
+
+	/* Mutex to protect the shared data structures */
+	TI_SDMA_LOCK_INIT(sc);
+
+	/* Get the memory resource for the register mapping */
+	rid = 0;
+	sc->sc_mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, RF_ACTIVE);
+	if (sc->sc_mem_res == NULL)
+		panic("%s: Cannot map registers", device_get_name(dev));
+
+	/* Enable the interface and functional clocks */
+	ti_prcm_clk_enable(SDMA_CLK);
+
+	/* Read the sDMA revision register and sanity check it's known */
+	sc->sc_hw_rev = ti_sdma_read_4(sc, DMA4_REVISION);
+	device_printf(dev, "sDMA revision %08x\n", sc->sc_hw_rev);
+
+	if (!ti_sdma_is_omap4_rev(sc) && !ti_sdma_is_omap3_rev(sc)) {
+		device_printf(sc->sc_dev, "error - unknown sDMA H/W revision\n");
+		return (EINVAL);
+	}
+
+	/* Disable all interrupts */
+	for (i = 0; i < NUM_DMA_IRQS; i++) {
+		ti_sdma_write_4(sc, DMA4_IRQENABLE_L(i), 0x00000000);
+	}
+
+	/* Soft-reset is only supported on pre-OMAP44xx devices */
+	if (ti_sdma_is_omap3_rev(sc)) {
+
+		/* Soft-reset */
+		ti_sdma_write_4(sc, DMA4_OCP_SYSCONFIG, 0x0002);
+
+		/* Set the timeout to 100ms*/
+		timeout = (hz < 10) ? 1 : ((100 * hz) / 1000);
+
+		/* Wait for DMA reset to complete */
+		while ((ti_sdma_read_4(sc, DMA4_SYSSTATUS) & 0x1) == 0x0) {
+
+			/* Sleep for a tick */
+			pause("DMARESET", 1);
+
+			if (timeout-- == 0) {
+				device_printf(sc->sc_dev, "sDMA reset operation timed out\n");
+				return (EINVAL);
+			}
+		}
+	}
+
+	/* 
+	 * Install interrupt handlers for the for possible interrupts. Any channel
+	 * can trip one of the four IRQs
+	 */
+	rid = 0;
+	sc->sc_irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid,
+	    RF_ACTIVE | RF_SHAREABLE);
+	if (sc->sc_irq_res == NULL)
+		panic("Unable to setup the dma irq handler.\n");
+
+	err = bus_setup_intr(dev, sc->sc_irq_res, INTR_TYPE_MISC | INTR_MPSAFE,
+	    NULL, ti_sdma_intr, NULL, &ihl);
+	if (err)
+		panic("%s: Cannot register IRQ", device_get_name(dev));
+
+	/* Store the DMA structure globally ... this driver should never be unloaded */
+	ti_sdma_sc = sc;
+
+	return (0);
+}
+
+static device_method_t ti_sdma_methods[] = {
+	DEVMETHOD(device_probe, ti_sdma_probe),
+	DEVMETHOD(device_attach, ti_sdma_attach),
+	{0, 0},
+};
+
+static driver_t ti_sdma_driver = {
+	"ti_sdma",
+	ti_sdma_methods,
+	sizeof(struct ti_sdma_softc),
+};
+static devclass_t ti_sdma_devclass;
+
+DRIVER_MODULE(ti_sdma, simplebus, ti_sdma_driver, ti_sdma_devclass, 0, 0);
+MODULE_DEPEND(ti_sdma, ti_prcm, 1, 1, 1);
diff -r 7fffa673adcd -r a301a330526b head/sys/arm/ti/ti_sdma.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/head/sys/arm/ti/ti_sdma.h	Wed Aug 15 11:16:36 2012 +0300
@@ -0,0 +1,111 @@
+/*-
+ * Copyright (c) 2011
+ *	Ben Gray <ben.r.gray at 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.
+ *
+ * $FreeBSD: head/sys/arm/ti/ti_sdma.h 239281 2012-08-15 06:31:32Z gonzo $
+ */
+
+/**
+ * sDMA device driver interface for the TI SoC
+ *
+ * See the ti_sdma.c file for implementation details.
+ *
+ * Reference:
+ *  OMAP35x Applications Processor
+ *   Technical Reference Manual
+ *  (omap35xx_techref.pdf)
+ */
+#ifndef _TI_DMA_H_
+#define _TI_DMA_H_
+
+#define TI_SDMA_ENDIAN_BIG          0x1
+#define TI_SDMA_ENDIAN_LITTLE       0x0
+
+#define TI_SDMA_BURST_NONE          0x0
+#define TI_SDMA_BURST_16            0x1
+#define TI_SDMA_BURST_32            0x2
+#define TI_SDMA_BURST_64            0x3
+
+#define TI_SDMA_DATA_8BITS_SCALAR   0x0
+#define TI_SDMA_DATA_16BITS_SCALAR  0x1
+#define TI_SDMA_DATA_32BITS_SCALAR  0x2
+
+#define TI_SDMA_ADDR_CONSTANT       0x0
+#define TI_SDMA_ADDR_POST_INCREMENT 0x1
+#define TI_SDMA_ADDR_SINGLE_INDEX   0x2
+#define TI_SDMA_ADDR_DOUBLE_INDEX   0x3
+
+/**
+ * Status flags for the DMA callback
+ *
+ */
+#define TI_SDMA_STATUS_DROP                  (1UL << 1)
+#define TI_SDMA_STATUS_HALF                  (1UL << 2)
+#define TI_SDMA_STATUS_FRAME                 (1UL << 3)
+#define TI_SDMA_STATUS_LAST                  (1UL << 4)
+#define TI_SDMA_STATUS_BLOCK                 (1UL << 5)
+#define TI_SDMA_STATUS_SYNC                  (1UL << 6)
+#define TI_SDMA_STATUS_PKT                   (1UL << 7)
+#define TI_SDMA_STATUS_TRANS_ERR             (1UL << 8)
+#define TI_SDMA_STATUS_SECURE_ERR            (1UL << 9)
+#define TI_SDMA_STATUS_SUPERVISOR_ERR        (1UL << 10)
+#define TI_SDMA_STATUS_MISALIGNED_ADRS_ERR   (1UL << 11)
+#define TI_SDMA_STATUS_DRAIN_END             (1UL << 12)
+
+#define TI_SDMA_SYNC_FRAME                   (1UL << 0)
+#define TI_SDMA_SYNC_BLOCK                   (1UL << 1)
+#define TI_SDMA_SYNC_PACKET                  (TI_SDMA_SYNC_FRAME | TI_SDMA_SYNC_BLOCK)
+#define TI_SDMA_SYNC_TRIG_ON_SRC             (1UL << 8)
+#define TI_SDMA_SYNC_TRIG_ON_DST             (1UL << 9)
+
+#define TI_SDMA_IRQ_FLAG_DROP                (1UL << 1)
+#define TI_SDMA_IRQ_FLAG_HALF_FRAME_COMPL    (1UL << 2)
+#define TI_SDMA_IRQ_FLAG_FRAME_COMPL         (1UL << 3)
+#define TI_SDMA_IRQ_FLAG_START_LAST_FRAME    (1UL << 4)
+#define TI_SDMA_IRQ_FLAG_BLOCK_COMPL         (1UL << 5)
+#define TI_SDMA_IRQ_FLAG_ENDOF_PKT           (1UL << 7)
+#define TI_SDMA_IRQ_FLAG_DRAIN               (1UL << 12)
+
+int ti_sdma_activate_channel(unsigned int *ch,
+    void (*callback)(unsigned int ch, uint32_t status, void *data), void *data);
+int ti_sdma_deactivate_channel(unsigned int ch);
+int ti_sdma_start_xfer(unsigned int ch, unsigned int src_paddr,
+    unsigned long dst_paddr, unsigned int frmcnt, unsigned int elmcnt);
+int ti_sdma_start_xfer_packet(unsigned int ch, unsigned int src_paddr,
+    unsigned long dst_paddr, unsigned int frmcnt, unsigned int elmcnt, 
+    unsigned int pktsize);
+int ti_sdma_stop_xfer(unsigned int ch);
+int ti_sdma_enable_channel_irq(unsigned int ch, uint32_t flags);
+int ti_sdma_disable_channel_irq(unsigned int ch);
+int ti_sdma_get_channel_status(unsigned int ch, uint32_t *status);
+int ti_sdma_set_xfer_endianess(unsigned int ch, unsigned int src, unsigned int dst);
+int ti_sdma_set_xfer_burst(unsigned int ch, unsigned int src, unsigned int dst);
+int ti_sdma_set_xfer_data_type(unsigned int ch, unsigned int type);
+int ti_sdma_set_callback(unsigned int ch,
+    void (*callback)(unsigned int ch, uint32_t status, void *data), void *data);
+int ti_sdma_sync_params(unsigned int ch, unsigned int trigger, unsigned int mode);
+int ti_sdma_set_addr_mode(unsigned int ch, unsigned int src_mode, unsigned int dst_mode);
+
+#endif /* _TI_SDMA_H_ */
diff -r 7fffa673adcd -r a301a330526b head/sys/arm/ti/ti_sdmareg.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/head/sys/arm/ti/ti_sdmareg.h	Wed Aug 15 11:16:36 2012 +0300
@@ -0,0 +1,133 @@
+/*-
+ * Copyright (c) 2011
+ *	Ben Gray <ben.r.gray at 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.
+ *
+ * $FreeBSD: head/sys/arm/ti/ti_sdmareg.h 239281 2012-08-15 06:31:32Z gonzo $
+ */
+#ifndef	__TI_SDMAREG_H__
+#define	__TI_SDMAREG_H__
+
+/**
+ * The number of DMA channels possible on the controller.
+ */
+#define NUM_DMA_CHANNELS	32
+#define NUM_DMA_IRQS		4
+
+/**
+ * Register offsets
+ */
+#define DMA4_REVISION                            0x0000
+#define DMA4_IRQSTATUS_L(j)                     (0x0008 + ((j) * 0x4))
+#define DMA4_IRQENABLE_L(j)                     (0x0018 + ((j) * 0x4))
+#define DMA4_SYSSTATUS                           0x0028
+#define DMA4_OCP_SYSCONFIG                       0x002C
+#define DMA4_CAPS_0                              0x0064
+#define DMA4_CAPS_2                              0x006C
+#define DMA4_CAPS_3                              0x0070
+#define DMA4_CAPS_4                              0x0074
+#define DMA4_GCR                                 0x0078
+#define DMA4_CCR(i)                             (0x0080 + ((i) * 0x60))
+#define DMA4_CLNK_CTRL(i)                       (0x0084 + ((i) * 0x60))
+#define DMA4_CICR(i)                            (0x0088 + ((i) * 0x60))
+#define DMA4_CSR(i)                             (0x008C + ((i) * 0x60))
+#define DMA4_CSDP(i)                            (0x0090 + ((i) * 0x60))
+#define DMA4_CEN(i)                             (0x0094 + ((i) * 0x60))
+#define DMA4_CFN(i)                             (0x0098 + ((i) * 0x60))
+#define DMA4_CSSA(i)                            (0x009C + ((i) * 0x60))
+#define DMA4_CDSA(i)                            (0x00A0 + ((i) * 0x60))
+#define DMA4_CSE(i)                             (0x00A4 + ((i) * 0x60))
+#define DMA4_CSF(i)                             (0x00A8 + ((i) * 0x60))
+#define DMA4_CDE(i)                             (0x00AC + ((i) * 0x60))
+#define DMA4_CDF(i)                             (0x00B0 + ((i) * 0x60))
+#define DMA4_CSAC(i)                            (0x00B4 + ((i) * 0x60))
+#define DMA4_CDAC(i)                            (0x00B8 + ((i) * 0x60))
+#define DMA4_CCEN(i)                            (0x00BC + ((i) * 0x60))
+#define DMA4_CCFN(i)                            (0x00C0 + ((i) * 0x60))
+#define DMA4_COLOR(i)                           (0x00C4 + ((i) * 0x60))
+
+/* The following register are only defined on OMAP44xx (and newer?) */
+#define DMA4_CDP(i)                             (0x00D0 + ((i) * 0x60))
+#define DMA4_CNDP(i)                            (0x00D4 + ((i) * 0x60))
+#define DMA4_CCDN(i)                            (0x00D8 + ((i) * 0x60))
+
+/**
+ * Various register field settings
+ */
+#define DMA4_CSDP_DATA_TYPE(x)                  (((x) & 0x3) << 0)
+#define DMA4_CSDP_SRC_BURST_MODE(x)             (((x) & 0x3) << 7)
+#define DMA4_CSDP_DST_BURST_MODE(x)             (((x) & 0x3) << 14)
+#define DMA4_CSDP_SRC_ENDIANISM(x)              (((x) & 0x1) << 21)
+#define DMA4_CSDP_DST_ENDIANISM(x)              (((x) & 0x1) << 19)
+#define DMA4_CSDP_WRITE_MODE(x)                 (((x) & 0x3) << 16)
+#define DMA4_CSDP_SRC_PACKED(x)                 (((x) & 0x1) << 6)
+#define DMA4_CSDP_DST_PACKED(x)                 (((x) & 0x1) << 13)
+
+#define DMA4_CCR_DST_ADDRESS_MODE(x)            (((x) & 0x3) << 14)
+#define DMA4_CCR_SRC_ADDRESS_MODE(x)            (((x) & 0x3) << 12)
+#define DMA4_CCR_READ_PRIORITY(x)               (((x) & 0x1) << 6)
+#define DMA4_CCR_WRITE_PRIORITY(x)              (((x) & 0x1) << 26)
+#define DMA4_CCR_SYNC_TRIGGER(x)                ((((x) & 0x60) << 14) \
+                                                 | ((x) & 0x1f))
+#define	DMA4_CCR_FRAME_SYNC(x)                  (((x) & 0x1) << 5)
+#define	DMA4_CCR_BLOCK_SYNC(x)                  (((x) & 0x1) << 18)
+#define DMA4_CCR_SEL_SRC_DST_SYNC(x)            (((x) & 0x1) << 24)
+
+#define DMA4_CCR_PACKET_TRANS                   (DMA4_CCR_FRAME_SYNC(1) | \
+                                                 DMA4_CCR_BLOCK_SYNC(1) )
+
+#define DMA4_CSR_DROP                           (1UL << 1)
+#define DMA4_CSR_HALF                           (1UL << 2)
+#define DMA4_CSR_FRAME                          (1UL << 3)
+#define DMA4_CSR_LAST                           (1UL << 4)
+#define DMA4_CSR_BLOCK                          (1UL << 5)
+#define DMA4_CSR_SYNC                           (1UL << 6)
+#define DMA4_CSR_PKT                            (1UL << 7)
+#define DMA4_CSR_TRANS_ERR                      (1UL << 8)
+#define DMA4_CSR_SECURE_ERR                     (1UL << 9)
+#define DMA4_CSR_SUPERVISOR_ERR                 (1UL << 10)
+#define DMA4_CSR_MISALIGNED_ADRS_ERR            (1UL << 11)
+#define DMA4_CSR_DRAIN_END                      (1UL << 12)
+#define DMA4_CSR_CLEAR_MASK                     (0xffe)
+
+#define DMA4_CICR_DROP_IE                       (1UL << 1)
+#define DMA4_CICR_HALF_IE                       (1UL << 2)
+#define DMA4_CICR_FRAME_IE                      (1UL << 3)
+#define DMA4_CICR_LAST_IE                       (1UL << 4)
+#define DMA4_CICR_BLOCK_IE                      (1UL << 5)
+#define DMA4_CICR_PKT_IE                        (1UL << 7)
+#define DMA4_CICR_TRANS_ERR_IE                  (1UL << 8)
+#define DMA4_CICR_SECURE_ERR_IE                 (1UL << 9)
+#define DMA4_CICR_SUPERVISOR_ERR_IE             (1UL << 10)
+#define DMA4_CICR_MISALIGNED_ADRS_ERR_IE        (1UL << 11)
+#define DMA4_CICR_DRAIN_IE                      (1UL << 12)
+
+/**
+ *	The following H/W revision values were found be experimentation, TI don't
+ *	publish the revision numbers.  The TRM says "TI internal Data".
+ */
+#define DMA4_OMAP3_REV                          0x00000040
+#define DMA4_OMAP4_REV                          0x00010900
+
+#endif	/* __TI_SDMAREG_H__ */
diff -r 7fffa673adcd -r a301a330526b head/sys/arm/ti/ti_smc.S
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/head/sys/arm/ti/ti_smc.S	Wed Aug 15 11:16:36 2012 +0300
@@ -0,0 +1,39 @@
+/*-
+ * Copyright (c) 2012 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 THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <machine/armreg.h>
+#include <machine/asm.h>
+__FBSDID("$FreeBSD: head/sys/arm/ti/ti_smc.S 239283 2012-08-15 07:00:34Z gonzo $");
+
+.arch armv7a
+
+/* Issue a smc #0 call */
+/* r0 and r1 contains the eventual arguments, r2 contains the function ID */
+ENTRY(ti_smc0)
+	stmfd	sp!, {r4-r12, lr}
+	mov	r12, r2 /* the rom expects the function ID in r12 */
+	dsb
+	smc	#0
+	ldmfd	sp!, {r4-r12, pc}
+	
diff -r 7fffa673adcd -r a301a330526b head/sys/arm/ti/ti_smc.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/head/sys/arm/ti/ti_smc.h	Wed Aug 15 11:16:36 2012 +0300
@@ -0,0 +1,33 @@
+/*-
+ * Copyright (c) 2012 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 THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+/*
+ * $FreeBSD: head/sys/arm/ti/ti_smc.h 239281 2012-08-15 06:31:32Z gonzo $
+ */
+
+#ifndef TI_SMC_H_
+#define TI_SMC_H_
+uint32_t ti_smc0(uint32_t r0, uint32_t r1, uint32_t function_id);
+#endif /* TI_SMC_H_ */
diff -r 7fffa673adcd -r a301a330526b head/sys/arm/ti/tivar.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/head/sys/arm/ti/tivar.h	Wed Aug 15 11:16:36 2012 +0300
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2010
+ *	Ben Gray <ben.r.gray at 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.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by Ben Gray.
+ * 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 BEN GRAY ``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 BEN GRAY 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: head/sys/arm/ti/tivar.h 239281 2012-08-15 06:31:32Z gonzo $
+ */
+
+#ifndef _TIVAR_H_
+#define	_TIVAR_H_
+
+/* board-dependent reset function implementation */
+extern void (*ti_cpu_reset)(void);
+
+#endif /* _TIVAR_H_ */
diff -r 7fffa673adcd -r a301a330526b head/sys/arm/ti/twl/twl.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/head/sys/arm/ti/twl/twl.c	Wed Aug 15 11:16:36 2012 +0300
@@ -0,0 +1,464 @@
+/*-
+ * Copyright (c) 2011
+ *	Ben Gray <ben.r.gray at 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: head/sys/arm/ti/twl/twl.c 239281 2012-08-15 06:31:32Z gonzo $");
+
+/*
+ * Texas Instruments TWL4030/TWL5030/TWL60x0/TPS659x0 Power Management and
+ * Audio CODEC devices.
+ *
+ * This code is based on the Linux TWL multifunctional device driver, which is
+ * copyright (C) 2005-2006 Texas Instruments, Inc.
+ *
+ * These chips are typically used as support ICs for the OMAP range of embedded
+ * ARM processes/SOC from Texas Instruments.  They are typically used to control
+ * on board voltages, however some variants have other features like audio
+ * codecs, USB OTG transceivers, RTC, PWM, etc.
+ *
+ * This driver acts as a bus for more specific companion devices.
+ *
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/lock.h>
+#include <sys/module.h>
+#include <sys/bus.h>
+#include <sys/resource.h>
+#include <sys/rman.h>
+#include <sys/sysctl.h>
+#include <sys/mutex.h>
+#include <sys/malloc.h>
+
+#include <machine/bus.h>
+#include <machine/cpu.h>
+#include <machine/cpufunc.h>
+#include <machine/frame.h>
+#include <machine/resource.h>
+#include <machine/intr.h>
+
+#include <dev/iicbus/iicbus.h>
+#include <dev/iicbus/iiconf.h>
+
+#include <dev/ofw/openfirm.h>
+#include <dev/ofw/ofw_bus.h>
+#include <dev/ofw/ofw_bus_subr.h>
+
+#include "arm/ti/twl/twl.h"
+
+/* TWL device IDs */
+#define TWL_DEVICE_UNKNOWN          0xffff
+#define TWL_DEVICE_4030             0x4030
+#define TWL_DEVICE_6025             0x6025
+#define TWL_DEVICE_6030             0x6030
+
+/* Each TWL device typically has more than one I2C address */
+#define TWL_MAX_SUBADDRS            4
+
+/* The maxium number of bytes that can be written in one call */
+#define TWL_MAX_IIC_DATA_SIZE       63
+
+/* The TWL devices typically use 4 I2C address for the different internal
+ * register sets, plus one SmartReflex I2C address.
+ */
+#define TWL_CHIP_ID0                0x48
+#define TWL_CHIP_ID1                0x49
+#define TWL_CHIP_ID2                0x4A
+#define TWL_CHIP_ID3                0x4B
+
+#define TWL_SMARTREFLEX_CHIP_ID     0x12
+
+#define TWL_INVALID_CHIP_ID         0xff
+
+struct twl_softc {
+	device_t		sc_dev;
+	struct mtx		sc_mtx;
+	unsigned int	sc_type;
+
+	uint8_t			sc_subaddr_map[TWL_MAX_SUBADDRS];
+
+	struct intr_config_hook	sc_scan_hook;
+
+	device_t		sc_vreg;
+	device_t		sc_clks;
+};
+
+/**
+ *	Macros for driver mutex locking
+ */
+#define TWL_LOCK(_sc)             mtx_lock(&(_sc)->sc_mtx)
+#define	TWL_UNLOCK(_sc)           mtx_unlock(&(_sc)->sc_mtx)
+#define TWL_LOCK_INIT(_sc) \
+	mtx_init(&_sc->sc_mtx, device_get_nameunit(_sc->sc_dev), \
+	         "twl", MTX_DEF)
+#define TWL_LOCK_DESTROY(_sc)     mtx_destroy(&_sc->sc_mtx);
+#define TWL_ASSERT_LOCKED(_sc)    mtx_assert(&_sc->sc_mtx, MA_OWNED);
+#define TWL_ASSERT_UNLOCKED(_sc)  mtx_assert(&_sc->sc_mtx, MA_NOTOWNED);
+
+
+/**
+ *	twl_is_4030 - returns true if the device is TWL4030
+ *	twl_is_6025 - returns true if the device is TWL6025
+ *	twl_is_6030 - returns true if the device is TWL6030
+ *	@sc: device soft context
+ *
+ *	Returns a non-zero value if the device matches.
+ *
+ *	RETURNS:
+ *	Returns a non-zero value if the device matches, otherwise zero.
+ */
+int
+twl_is_4030(device_t dev)
+{
+	struct twl_softc *sc = device_get_softc(dev);
+	return (sc->sc_type == TWL_DEVICE_4030);
+}
+
+int
+twl_is_6025(device_t dev)
+{
+	struct twl_softc *sc = device_get_softc(dev);
+	return (sc->sc_type == TWL_DEVICE_6025);
+}
+
+int
+twl_is_6030(device_t dev)
+{
+	struct twl_softc *sc = device_get_softc(dev);
+	return (sc->sc_type == TWL_DEVICE_6030);
+}
+
+
+/**
+ *	twl_read - read one or more registers from the TWL device
+ *	@sc: device soft context
+ *	@nsub: the sub-module to read from
+ *	@reg: the register offset within the module to read
+ *	@buf: buffer to store the bytes in
+ *	@cnt: the number of bytes to read
+ *
+ *	Reads one or more registers and stores the result in the suppled buffer.
+ *
+ *	RETURNS:
+ *	Zero on success or an error code on failure.
+ */
+int
+twl_read(device_t dev, uint8_t nsub, uint8_t reg, uint8_t *buf, uint16_t cnt)
+{
+	struct twl_softc *sc;
+	struct iic_msg msg[2];
+	uint8_t addr;
+	int rc;
+
+	sc = device_get_softc(dev);
+
+	TWL_LOCK(sc);
+	addr = sc->sc_subaddr_map[nsub];
+	TWL_UNLOCK(sc);
+
+	if (addr == TWL_INVALID_CHIP_ID)
+		return (EIO);
+
+
+	/* Set the address to read from */
+	msg[0].slave = addr;
+	msg[0].flags = IIC_M_WR | IIC_M_NOSTOP;
+	msg[0].len = 1;
+	msg[0].buf = ®
+	/* Read the data back */
+	msg[1].slave = addr;
+	msg[1].flags = IIC_M_RD;
+	msg[1].len = cnt;
+	msg[1].buf = buf;
+
+	rc = iicbus_transfer(dev, msg, 2);
+	if (rc != 0) {
+		device_printf(dev, "iicbus read failed (adr:0x%02x, reg:0x%02x)\n",
+		              addr, reg);
+		return (EIO);
+	}
+
+	return (0);
+}
+
+/**
+ *	twl_write - writes one or more registers to the TWL device
+ *	@sc: device soft context
+ *	@nsub: the sub-module to read from
+ *	@reg: the register offset within the module to read
+ *	@buf: data to write
+ *	@cnt: the number of bytes to write
+ *
+ *	Writes one or more registers.
+ *
+ *	RETURNS:
+ *	Zero on success or a negative error code on failure.
+ */
+int
+twl_write(device_t dev, uint8_t nsub, uint8_t reg, uint8_t *buf, uint16_t cnt)
+{
+	struct twl_softc *sc;
+	struct iic_msg msg;
+	uint8_t addr;
+	uint8_t tmp_buf[TWL_MAX_IIC_DATA_SIZE + 1];
+	int rc;
+
+	if (cnt > TWL_MAX_IIC_DATA_SIZE)
+		return (ENOMEM);
+
+	/* Set the register address as the first byte */
+	tmp_buf[0] = reg;
+	memcpy(&tmp_buf[1], buf, cnt);
+
+	sc = device_get_softc(dev);
+
+	TWL_LOCK(sc);
+	addr = sc->sc_subaddr_map[nsub];
+	TWL_UNLOCK(sc);
+
+	if (addr == TWL_INVALID_CHIP_ID)
+		return (EIO);
+
+
+	/* Setup the transfer and execute it */
+	msg.slave = addr;
+	msg.flags = IIC_M_WR;
+	msg.len = cnt + 1;
+	msg.buf = tmp_buf;
+
+	rc = iicbus_transfer(dev, &msg, 1);
+	if (rc != 0) {
+		device_printf(sc->sc_dev, "iicbus write failed (adr:0x%02x, reg:0x%02x)\n",
+		              addr, reg);
+		return (EIO);
+	}
+
+	return (0);
+}
+
+/**
+ *	twl_test_present - checks if a device with given address is present
+ *	@sc: device soft context
+ *	@addr: the address of the device to scan for
+ *
+ *	Sends just the address byte and checks for an ACK. If no ACK then device
+ *	is assumed to not be present.
+ *
+ *	RETURNS:
+ *	EIO if device is not present, otherwise 0 is returned.
+ */
+static int
+twl_test_present(struct twl_softc *sc, uint8_t addr)
+{
+	struct iic_msg msg;
+	uint8_t tmp;
+
+	/* Set the address to read from */
+	msg.slave = addr;
+	msg.flags = IIC_M_RD;
+	msg.len = 1;
+	msg.buf = &tmp;
+
+	if (iicbus_transfer(sc->sc_dev, &msg, 1) != 0)
+		return (EIO);
+
+	return (0);
+}
+
+/**
+ *	twl_scan - scans the i2c bus for sub modules
+ *	@dev: the twl device
+ *
+ *	TWL devices don't just have one i2c slave address, rather they have up to
+ *	5 other addresses, each is for separate modules within the device. This
+ *	function scans the bus for 4 possible sub-devices and stores the info
+ *	internally.
+ *
+ */
+static void
+twl_scan(void *dev)
+{
+	struct twl_softc *sc;
+	unsigned i;
+	uint8_t devs[TWL_MAX_SUBADDRS];
+	uint8_t base = TWL_CHIP_ID0;
+
+	sc = device_get_softc((device_t)dev);
+
+	memset(devs, TWL_INVALID_CHIP_ID, TWL_MAX_SUBADDRS);
+
+	/* Try each of the addresses (0x48, 0x49, 0x4a & 0x4b) to determine which
+	 * sub modules we have.
+	 */
+	for (i = 0; i < TWL_MAX_SUBADDRS; i++) {
+		if (twl_test_present(sc, (base + i)) == 0) {
+			devs[i] = (base + i);
+			device_printf(sc->sc_dev, "Found (sub)device at 0x%02x\n", (base + i));
+		}
+	}
+
+	TWL_LOCK(sc);
+	memcpy(sc->sc_subaddr_map, devs, TWL_MAX_SUBADDRS);
+	TWL_UNLOCK(sc);
+
+	/* Finished with the interrupt hook */
+	config_intrhook_disestablish(&sc->sc_scan_hook);
+}
+
+/**
+ *	twl_probe - 
+ *	@dev: the twl device
+ *
+ *	Scans the FDT for a match for the device, possible compatible device
+ *	strings are; "ti,twl6030", "ti,twl6025", "ti,twl4030".  
+ *
+ *	The FDT compat string also determines the type of device (it is currently
+ *	not possible to dynamically determine the device type).
+ *
+ */
+static int
+twl_probe(device_t dev)
+{
+	phandle_t node;
+	const char *compat;
+	int len, l;
+	struct twl_softc *sc;
+
+	if ((compat = ofw_bus_get_compat(dev)) == NULL)
+		return (ENXIO);
+
+	if ((node = ofw_bus_get_node(dev)) == 0)
+		return (ENXIO);
+
+	/* Get total 'compatible' prop len */
+	if ((len = OF_getproplen(node, "compatible")) <= 0)
+		return (ENXIO);
+
+	sc = device_get_softc(dev);
+	sc->sc_dev = dev;
+	sc->sc_type = TWL_DEVICE_UNKNOWN;
+
+	while (len > 0) {
+		if (strncasecmp(compat, "ti,twl6030", 10) == 0)
+			sc->sc_type = TWL_DEVICE_6030;
+		else if (strncasecmp(compat, "ti,twl6025", 10) == 0)
+			sc->sc_type = TWL_DEVICE_6025;
+		else if (strncasecmp(compat, "ti,twl4030", 10) == 0)
+			sc->sc_type = TWL_DEVICE_4030;
+		
+		if (sc->sc_type != TWL_DEVICE_UNKNOWN)
+			break;
+
+		/* Slide to the next sub-string. */
+		l = strlen(compat) + 1;
+		compat += l;
+		len -= l;
+	}
+	
+	switch (sc->sc_type) {
+	case TWL_DEVICE_4030:
+		device_set_desc(dev, "TI TWL4030/TPS659x0 Companion IC");
+		break;
+	case TWL_DEVICE_6025:
+		device_set_desc(dev, "TI TWL6025 Companion IC");
+		break;
+	case TWL_DEVICE_6030:
+		device_set_desc(dev, "TI TWL6030 Companion IC");
+		break;
+	case TWL_DEVICE_UNKNOWN:
+	default:
+		return (ENXIO);
+	}
+	
+	return (0);
+}
+
+static int
+twl_attach(device_t dev)
+{
+	struct twl_softc *sc;
+
+	sc = device_get_softc(dev);
+	sc->sc_dev = dev;
+
+	TWL_LOCK_INIT(sc);
+
+	/* We have to wait until interrupts are enabled. I2C read and write
+	 * only works if the interrupts are available.
+	 */
+	sc->sc_scan_hook.ich_func = twl_scan;
+	sc->sc_scan_hook.ich_arg = dev;
+
+	if (config_intrhook_establish(&sc->sc_scan_hook) != 0)
+		return (ENOMEM);
+
+	/* FIXME: should be in DTS file */
+	if ((sc->sc_vreg = device_add_child(dev, "twl_vreg", -1)) == NULL)
+		device_printf(dev, "could not allocate twl_vreg instance\n");
+	if ((sc->sc_clks = device_add_child(dev, "twl_clks", -1)) == NULL)
+		device_printf(dev, "could not allocate twl_clks instance\n");
+
+	return (bus_generic_attach(dev));
+}
+
+static int
+twl_detach(device_t dev)
+{
+	struct twl_softc *sc;
+
+	sc = device_get_softc(dev);
+
+	if (sc->sc_vreg)
+		device_delete_child(dev, sc->sc_vreg);
+	if (sc->sc_clks)
+		device_delete_child(dev, sc->sc_clks);
+	
+
+	TWL_LOCK_DESTROY(sc);
+
+	return (0);
+}
+
+static device_method_t twl_methods[] = {
+	DEVMETHOD(device_probe,		twl_probe),
+	DEVMETHOD(device_attach,	twl_attach),
+	DEVMETHOD(device_detach,	twl_detach),
+
+	{0, 0},
+};
+
+static driver_t twl_driver = {
+	"twl",
+	twl_methods,
+	sizeof(struct twl_softc),
+};
+static devclass_t twl_devclass;
+
+DRIVER_MODULE(twl, iicbus, twl_driver, twl_devclass, 0, 0);
+MODULE_VERSION(twl, 1);
diff -r 7fffa673adcd -r a301a330526b head/sys/arm/ti/twl/twl.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/head/sys/arm/ti/twl/twl.h	Wed Aug 15 11:16:36 2012 +0300
@@ -0,0 +1,39 @@
+/*-
+ * Copyright (c) 2011
+ *	Ben Gray <ben.r.gray at 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.
+ *
+ * $FreeBSD: head/sys/arm/ti/twl/twl.h 239281 2012-08-15 06:31:32Z gonzo $
+ */
+#ifndef _TWL_H_
+#define _TWL_H_
+
+int twl_read(device_t dev, uint8_t nsub, uint8_t reg, uint8_t *buf, uint16_t cnt);
+int twl_write(device_t dev, uint8_t nsub, uint8_t reg, uint8_t *buf, uint16_t cnt);
+
+int twl_is_4030(device_t dev);
+int twl_is_6025(device_t dev);
+int twl_is_6030(device_t dev);
+
+#endif /* _TWL_H_ */
diff -r 7fffa673adcd -r a301a330526b head/sys/arm/ti/twl/twl_clks.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/head/sys/arm/ti/twl/twl_clks.c	Wed Aug 15 11:16:36 2012 +0300
@@ -0,0 +1,675 @@
+/*-
+ * Copyright (c) 2012
+ *	Ben Gray <bgray at freebsd.org>.
+ * 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: head/sys/arm/ti/twl/twl_clks.c 239281 2012-08-15 06:31:32Z gonzo $");
+
+/*
+ * Texas Instruments TWL4030/TWL5030/TWL60x0/TPS659x0 Power Management.
+ *
+ * This driver covers the external clocks, allows for enabling &
+ * disabling their output.
+ *
+ *
+ *
+ * FLATTENED DEVICE TREE (FDT)
+ * Startup override settings can be specified in the FDT, if they are they
+ * should be under the twl parent device and take the following form:
+ *
+ *    external-clocks = "name1", "state1",
+ *                      "name2", "state2",
+ *                      etc;
+ *
+ * Each override should be a pair, the first entry is the name of the clock
+ * the second is the state to set, possible strings are either "on" or "off".
+ *
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/lock.h>
+#include <sys/module.h>
+#include <sys/bus.h>
+#include <sys/resource.h>
+#include <sys/rman.h>
+#include <sys/sysctl.h>
+#include <sys/sx.h>
+#include <sys/malloc.h>
+
+#include <machine/bus.h>
+#include <machine/cpu.h>
+#include <machine/cpufunc.h>
+#include <machine/frame.h>
+#include <machine/resource.h>
+#include <machine/intr.h>
+
+#include <dev/ofw/openfirm.h>
+#include <dev/ofw/ofw_bus.h>
+
+#include "twl.h"
+#include "twl_clks.h"
+
+
+static int twl_clks_debug = 1;
+
+
+/*
+ * Power Groups bits for the 4030 and 6030 devices
+ */
+#define TWL4030_P3_GRP		0x80	/* Peripherals, power group */
+#define TWL4030_P2_GRP		0x40	/* Modem power group */
+#define TWL4030_P1_GRP		0x20	/* Application power group (FreeBSD control) */
+
+#define TWL6030_P3_GRP		0x04	/* Modem power group */
+#define TWL6030_P2_GRP		0x02	/* Connectivity power group */
+#define TWL6030_P1_GRP		0x01	/* Application power group (FreeBSD control) */
+
+/*
+ * Register offsets within a clk regulator register set
+ */
+#define TWL_CLKS_GRP		0x00	/* Regulator GRP register */
+#define TWL_CLKS_STATE		0x02	/* TWL6030 only */
+
+
+
+/**
+ *  Support voltage regulators for the different IC's
+ */
+struct twl_clock {
+	const char	*name;
+	uint8_t		subdev;
+	uint8_t		regbase;
+};
+
+static const struct twl_clock twl4030_clocks[] = {
+	{ "32kclkout", 0, 0x8e },
+	{ NULL, 0, 0x00 } 
+};
+
+static const struct twl_clock twl6030_clocks[] = {
+	{ "clk32kg",     0, 0xbc },
+	{ "clk32kao",    0, 0xb9 },
+	{ "clk32kaudio", 0, 0xbf },
+	{ NULL, 0, 0x00 } 
+};
+
+#define TWL_CLKS_MAX_NAMELEN  32
+
+struct twl_clk_entry {
+	LIST_ENTRY(twl_clk_entry) link;
+	struct sysctl_oid *oid;
+	char		       name[TWL_CLKS_MAX_NAMELEN];
+	uint8_t            sub_dev;  /* the sub-device number for the clock */
+	uint8_t            reg_off;  /* register base address of the clock */
+};
+
+struct twl_clks_softc {
+	device_t           sc_dev;   /* twl_clk device */
+	device_t           sc_pdev;  /* parent device (twl) */
+	struct sx          sc_sx;    /* internal locking */
+	struct intr_config_hook sc_init_hook;
+	LIST_HEAD(twl_clk_list, twl_clk_entry) sc_clks_list;
+};
+
+/**
+ *	Macros for driver shared locking
+ */
+#define TWL_CLKS_XLOCK(_sc)			sx_xlock(&(_sc)->sc_sx)
+#define	TWL_CLKS_XUNLOCK(_sc)		sx_xunlock(&(_sc)->sc_sx)
+#define TWL_CLKS_SLOCK(_sc)			sx_slock(&(_sc)->sc_sx)
+#define	TWL_CLKS_SUNLOCK(_sc)		sx_sunlock(&(_sc)->sc_sx)
+#define TWL_CLKS_LOCK_INIT(_sc)		sx_init(&(_sc)->sc_sx, "twl_clks")
+#define TWL_CLKS_LOCK_DESTROY(_sc)	sx_destroy(&(_sc)->sc_sx);
+
+#define TWL_CLKS_ASSERT_LOCKED(_sc)	sx_assert(&(_sc)->sc_sx, SA_LOCKED);
+
+#define TWL_CLKS_LOCK_UPGRADE(_sc)               \
+	do {                                         \
+		while (!sx_try_upgrade(&(_sc)->sc_sx))   \
+			pause("twl_clks_ex", (hz / 100));    \
+	} while(0)
+#define TWL_CLKS_LOCK_DOWNGRADE(_sc)	sx_downgrade(&(_sc)->sc_sx);
+
+
+
+
+/**
+ *	twl_clks_read_1 - read single register from the TWL device
+ *	twl_clks_write_1 - writes a single register in the TWL device
+ *	@sc: device context
+ *	@clk: the clock device we're reading from / writing to
+ *	@off: offset within the clock's register set
+ *	@val: the value to write or a pointer to a variable to store the result
+ *
+ *	RETURNS:
+ *	Zero on success or an error code on failure.
+ */
+static inline int
+twl_clks_read_1(struct twl_clks_softc *sc, struct twl_clk_entry *clk,
+	uint8_t off, uint8_t *val)
+{
+	return (twl_read(sc->sc_pdev, clk->sub_dev, clk->reg_off + off, val, 1));
+}
+
+static inline int
+twl_clks_write_1(struct twl_clks_softc *sc, struct twl_clk_entry *clk,
+	uint8_t off, uint8_t val)
+{
+	return (twl_write(sc->sc_pdev, clk->sub_dev, clk->reg_off + off, &val, 1));
+}
+
+
+/**
+ *	twl_clks_is_enabled - determines if a clock is enabled
+ *	@dev: TWL CLK device
+ *	@name: the name of the clock
+ *	@enabled: upon return will contain the 'enabled' state
+ *
+ *	LOCKING:
+ *	Internally the function takes and releases the TWL lock.
+ *
+ *	RETURNS:
+ *	Zero on success or a negative error code on failure.
+ */
+int
+twl_clks_is_enabled(device_t dev, const char *name, int *enabled)
+{
+	struct twl_clks_softc *sc = device_get_softc(dev);
+	struct twl_clk_entry *clk;
+	int found = 0;
+	int err;
+	uint8_t grp, state;
+
+	TWL_CLKS_SLOCK(sc);
+
+	LIST_FOREACH(clk, &sc->sc_clks_list, link) {
+		if (strcmp(clk->name, name) == 0) {
+			found = 1;
+			break;
+		}
+	}
+
+	if (!found) {
+		TWL_CLKS_SUNLOCK(sc);
+		return (EINVAL);
+	}
+
+
+	if (twl_is_4030(sc->sc_pdev)) {
+
+		err = twl_clks_read_1(sc, clk, TWL_CLKS_GRP, &grp);
+		if (!err)
+			*enabled = (grp & TWL4030_P1_GRP);
+
+	} else if (twl_is_6030(sc->sc_pdev) || twl_is_6025(sc->sc_pdev)) {
+
+		TWL_CLKS_LOCK_UPGRADE(sc);
+
+		/* Check the clock is in the application group */
+		if (twl_is_6030(sc->sc_pdev)) {
+			err = twl_clks_read_1(sc, clk, TWL_CLKS_GRP, &grp);
+			if (err) {
+				TWL_CLKS_LOCK_DOWNGRADE(sc);
+				goto done;
+			}
+			
+			if (!(grp & TWL6030_P1_GRP)) {
+				TWL_CLKS_LOCK_DOWNGRADE(sc);
+				*enabled = 0; /* disabled */
+				goto done;
+			}
+		}
+
+		/* Read the application mode state and verify it's ON */
+		err = twl_clks_read_1(sc, clk, TWL_CLKS_STATE, &state);
+		if (!err)
+			*enabled = ((state & 0x0C) == 0x04);
+			
+		TWL_CLKS_LOCK_DOWNGRADE(sc);
+
+	} else {
+		err = EINVAL;
+	}
+
+done:
+	TWL_CLKS_SUNLOCK(sc);
+	return (err);
+}
+
+
+/**
+ *	twl_clks_set_state - enables/disables a clock output
+ *	@sc: device context
+ *	@clk: the clock entry to enable/disable
+ *	@enable: non-zero the clock is enabled, zero the clock is disabled
+ *
+ *	LOCKING:
+ *	The TWL CLK lock must be held before this function is called.
+ *
+ *	RETURNS:
+ *	Zero on success or an error code on failure.
+ */
+static int
+twl_clks_set_state(struct twl_clks_softc *sc, struct twl_clk_entry *clk,
+	int enable)
+{
+	int xlocked;
+	int err;
+	uint8_t grp;
+
+	TWL_CLKS_ASSERT_LOCKED(sc);
+
+	/* Upgrade the lock to exclusive because about to perform read-mod-write */
+	xlocked = sx_xlocked(&sc->sc_sx);
+	if (!xlocked)
+		TWL_CLKS_LOCK_UPGRADE(sc);
+
+	err = twl_clks_read_1(sc, clk, TWL_CLKS_GRP, &grp);
+	if (err)
+		goto done;
+
+	if (twl_is_4030(sc->sc_pdev)) {
+
+		/* On the TWL4030 we just need to ensure the clock is in the right
+		 * power domain, don't need to turn on explicitly like TWL6030.
+		 */
+		if (enable)
+			grp |= TWL4030_P1_GRP;
+		else
+			grp &= ~(TWL4030_P1_GRP | TWL4030_P2_GRP | TWL4030_P3_GRP);
+		
+		err = twl_clks_write_1(sc, clk, TWL_CLKS_GRP, grp);
+
+	} else if (twl_is_6030(sc->sc_pdev) || twl_is_6025(sc->sc_pdev)) {
+
+		/* Make sure the clock belongs to at least the APP power group */
+		if (twl_is_6030(sc->sc_pdev) && !(grp & TWL6030_P1_GRP)) {
+			grp |= TWL6030_P1_GRP;
+			err = twl_clks_write_1(sc, clk, TWL_CLKS_GRP, grp);
+			if (err)
+				goto done;
+		}
+
+		/* On TWL6030 we need to make sure we disable power for all groups */
+		if (twl_is_6030(sc->sc_pdev))
+			grp = TWL6030_P1_GRP | TWL6030_P2_GRP | TWL6030_P3_GRP;
+		else
+			grp = 0x00;
+
+		/* Set the state of the clock */
+		if (enable)
+			err = twl_clks_write_1(sc, clk, TWL_CLKS_STATE, (grp << 5) | 0x01);
+		else
+			err = twl_clks_write_1(sc, clk, TWL_CLKS_STATE, (grp << 5));
+
+	} else {
+		
+		err = EINVAL;
+	}
+
+done:
+	if (!xlocked)
+		TWL_CLKS_LOCK_DOWNGRADE(sc);
+
+	if ((twl_clks_debug > 1) && !err)
+		device_printf(sc->sc_dev, "%s : %sabled\n", clk->name,
+			enable ? "en" : "dis");
+
+	return (err);
+}
+
+
+/**
+ *	twl_clks_disable - disables a clock output
+ *	@dev: TWL clk device
+*	@name: the name of the clock
+ *
+ *	LOCKING:
+ *	Internally the function takes and releases the TWL lock.
+ *
+ *	RETURNS:
+*	Zero on success or an error code on failure.
+ */
+int
+twl_clks_disable(device_t dev, const char *name)
+{
+	struct twl_clks_softc *sc = device_get_softc(dev);
+	struct twl_clk_entry *clk;
+	int err = EINVAL;
+
+	TWL_CLKS_SLOCK(sc);
+
+	LIST_FOREACH(clk, &sc->sc_clks_list, link) {
+		if (strcmp(clk->name, name) == 0) {
+			err = twl_clks_set_state(sc, clk, 0);
+			break;
+		}
+	}
+	
+	TWL_CLKS_SUNLOCK(sc);
+	return (err);
+}
+
+/**
+ *	twl_clks_enable - enables a clock output
+ *	@dev: TWL clk device
+ *	@name: the name of the clock
+ *
+ *	LOCKING:
+ *	Internally the function takes and releases the TWL CLKS lock.
+ *
+ *	RETURNS:
+ *	Zero on success or an error code on failure.
+ */
+int
+twl_clks_enable(device_t dev, const char *name)
+{
+	struct twl_clks_softc *sc = device_get_softc(dev);
+	struct twl_clk_entry *clk;
+	int err = EINVAL;
+
+	TWL_CLKS_SLOCK(sc);
+
+	LIST_FOREACH(clk, &sc->sc_clks_list, link) {
+		if (strcmp(clk->name, name) == 0) {
+			err = twl_clks_set_state(sc, clk, 1);
+			break;
+		}
+	}
+	
+	TWL_CLKS_SUNLOCK(sc);
+	return (err);
+}
+
+/**
+ *	twl_clks_sysctl_clock - reads the state of the clock
+ *	@SYSCTL_HANDLER_ARGS: arguments for the callback
+ *
+ *	Returns the clock status; disabled is zero and enabled is non-zero.
+ *
+ *	LOCKING:
+ *	It's expected the TWL lock is held while this function is called.
+ *
+ *	RETURNS:
+ *	EIO if device is not present, otherwise 0 is returned.
+ */
+static int
+twl_clks_sysctl_clock(SYSCTL_HANDLER_ARGS)
+{
+	struct twl_clks_softc *sc = (struct twl_clks_softc*)arg1;
+	int err;
+	int enabled = 0;
+
+	if ((err = twl_clks_is_enabled(sc->sc_dev, oidp->oid_name, &enabled)) != 0)
+		return err;
+	
+	return sysctl_handle_int(oidp, &enabled, 0, req);
+}
+
+/**
+ *	twl_clks_add_clock - adds single clock sysctls for the device
+ *	@sc: device soft context
+ *	@name: the name of the regulator
+ *	@nsub: the number of the subdevice
+ *	@regbase: the base address of the clocks registers
+ *
+ *	Adds a single clock to the device and also a sysctl interface for 
+ *	querying it's status.
+ *
+ *	LOCKING:
+ *	It's expected the exclusive lock is held while this function is called.
+ *
+ *	RETURNS:
+ *	Pointer to the new clock entry on success, otherwise NULL on failure.
+ */
+static struct twl_clk_entry*
+twl_clks_add_clock(struct twl_clks_softc *sc, const char *name,
+	uint8_t nsub, uint8_t regbase)
+{
+	struct sysctl_ctx_list *ctx = device_get_sysctl_ctx(sc->sc_dev);
+	struct sysctl_oid *tree = device_get_sysctl_tree(sc->sc_dev);
+	struct twl_clk_entry *new;
+
+	TWL_CLKS_ASSERT_LOCKED(sc);
+
+	new = malloc(sizeof(struct twl_clk_entry), M_DEVBUF, M_NOWAIT | M_ZERO);
+	if (new == NULL)
+		return (NULL);
+
+
+	strncpy(new->name, name, TWL_CLKS_MAX_NAMELEN);
+	new->name[TWL_CLKS_MAX_NAMELEN - 1] = '\0';
+
+	new->sub_dev = nsub;
+	new->reg_off = regbase;
+
+
+
+	/* Add a sysctl entry for the clock */
+	new->oid = SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(tree), OID_AUTO, name,
+	    CTLTYPE_INT | CTLFLAG_RD, sc, 0,
+	    twl_clks_sysctl_clock, "I", "external clock");
+
+	/* Finally add the regulator to list of supported regulators */
+	LIST_INSERT_HEAD(&sc->sc_clks_list, new, link);
+
+	return (new);
+}
+
+/**
+ *	twl_clks_add_clocks - populates the internal list of clocks
+ *	@sc: device soft context
+ *	@chip: the name of the chip used in the hints
+ *	@clks the list of clocks supported by the device
+ *
+ *	Loops over the list of clocks and adds them to the device context. Also
+ *	scans the FDT to determine if there are any clocks that should be
+ *	enabled/disabled automatically.
+ *
+ *	LOCKING:
+ *	Internally takes the exclusive lock while adding the clocks to the
+ *	device context.
+ *
+ *	RETURNS:
+ *	Always returns 0.
+ */
+static int
+twl_clks_add_clocks(struct twl_clks_softc *sc, const struct twl_clock *clks)
+{
+	int err;
+	const struct twl_clock *walker;
+	struct twl_clk_entry *entry;
+	phandle_t child;
+	char rnames[256];
+	char *name, *state;
+	int len = 0, prop_len;
+	int enable;
+
+
+	TWL_CLKS_XLOCK(sc);
+
+	/* Add the regulators from the list */
+	walker = &clks[0];
+	while (walker->name != NULL) {
+
+		/* Add the regulator to the list */
+		entry = twl_clks_add_clock(sc, walker->name, walker->subdev,
+		    walker->regbase);
+		if (entry == NULL)
+			continue;
+
+		walker++;
+	}
+
+	/* Check for any FDT settings that need to be applied */
+	child = ofw_bus_get_node(sc->sc_pdev);
+	if (child) {
+
+		prop_len = OF_getprop(child, "external-clocks", rnames, sizeof(rnames));
+		while (len < prop_len) {
+			name = rnames + len;
+			len += strlen(name) + 1;
+			if ((len >= prop_len) || (name[0] == '\0'))
+				break;
+			
+			state = rnames + len;
+			len += strlen(state) + 1;
+			if (state[0] == '\0')
+				break;
+			
+			enable = !strncmp(state, "on", 2);
+			
+			LIST_FOREACH(entry, &sc->sc_clks_list, link) {
+				if (strcmp(entry->name, name) == 0) {
+					twl_clks_set_state(sc, entry, enable);
+					break;
+				}
+			}
+		}
+	}
+	
+	TWL_CLKS_XUNLOCK(sc);
+
+	
+	if (twl_clks_debug) {
+		LIST_FOREACH(entry, &sc->sc_clks_list, link) {
+			err = twl_clks_is_enabled(sc->sc_dev, entry->name, &enable);
+			if (!err)
+				device_printf(sc->sc_dev, "%s : %s\n", entry->name,
+					enable ? "on" : "off");
+		}
+	}
+
+	return (0);
+}
+
+/**
+ *	twl_clks_init - initialises the list of clocks
+ *	@dev: the twl_clks device
+ *
+ *	This function is called as an intrhook once interrupts have been enabled,
+ *	this is done so that the driver has the option to enable/disable a clock
+ *	based on settings providied in the FDT.
+ *
+ *	LOCKING:
+ *	May takes the exclusive lock in the function.
+ */
+static void
+twl_clks_init(void *dev)
+{
+	struct twl_clks_softc *sc;
+
+	sc = device_get_softc((device_t)dev);
+
+	if (twl_is_4030(sc->sc_pdev))
+		twl_clks_add_clocks(sc, twl4030_clocks);
+	else if (twl_is_6030(sc->sc_pdev) || twl_is_6025(sc->sc_pdev))
+		twl_clks_add_clocks(sc, twl6030_clocks);
+
+	config_intrhook_disestablish(&sc->sc_init_hook);
+}
+
+static int
+twl_clks_probe(device_t dev)
+{
+	if (twl_is_4030(device_get_parent(dev)))
+		device_set_desc(dev, "TI TWL4030 PMIC External Clocks");
+	else if (twl_is_6025(device_get_parent(dev)) ||
+	         twl_is_6030(device_get_parent(dev)))
+		device_set_desc(dev, "TI TWL6025/TWL6030 PMIC External Clocks");
+	else
+		return (ENXIO);
+
+	return (0);
+}
+
+static int
+twl_clks_attach(device_t dev)
+{
+	struct twl_clks_softc *sc;
+
+	sc = device_get_softc(dev);
+	sc->sc_dev = dev;
+	sc->sc_pdev = device_get_parent(dev);
+
+	TWL_CLKS_LOCK_INIT(sc);
+
+	LIST_INIT(&sc->sc_clks_list);
+
+
+	sc->sc_init_hook.ich_func = twl_clks_init;
+	sc->sc_init_hook.ich_arg = dev;
+
+	if (config_intrhook_establish(&sc->sc_init_hook) != 0)
+		return (ENOMEM);
+
+	return (0);
+}
+
+static int
+twl_clks_detach(device_t dev)
+{
+	struct twl_clks_softc *sc;
+	struct twl_clk_entry *clk;
+	struct twl_clk_entry *tmp;
+
+	sc = device_get_softc(dev);
+
+	TWL_CLKS_XLOCK(sc);
+
+	LIST_FOREACH_SAFE(clk, &sc->sc_clks_list, link, tmp) {
+		LIST_REMOVE(clk, link);
+		sysctl_remove_oid(clk->oid, 1, 0);
+		free(clk, M_DEVBUF);
+	}
+
+	TWL_CLKS_XUNLOCK(sc);
+
+	TWL_CLKS_LOCK_DESTROY(sc);
+
+	return (0);
+}
+
+static device_method_t twl_clks_methods[] = {
+	DEVMETHOD(device_probe,		twl_clks_probe),
+	DEVMETHOD(device_attach,	twl_clks_attach),
+	DEVMETHOD(device_detach,	twl_clks_detach),
+
+	{0, 0},
+};
+
+static driver_t twl_clks_driver = {
+	"twl_clks",
+	twl_clks_methods,
+	sizeof(struct twl_clks_softc),
+};
+
+static devclass_t twl_clks_devclass;
+
+DRIVER_MODULE(twl_clks, twl, twl_clks_driver, twl_clks_devclass, 0, 0);
+MODULE_VERSION(twl_clks, 1);
diff -r 7fffa673adcd -r a301a330526b head/sys/arm/ti/twl/twl_clks.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/head/sys/arm/ti/twl/twl_clks.h	Wed Aug 15 11:16:36 2012 +0300
@@ -0,0 +1,38 @@
+/*-
+ * Copyright (c) 2012
+ *	Ben Gray <bgray at freebsd.org>.
+ * 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: head/sys/arm/ti/twl/twl_clks.h 239281 2012-08-15 06:31:32Z gonzo $
+ */
+#ifndef _TWL_CLKS_H_
+#define _TWL_CLKS_H_
+
+
+int twl_clks_enable(device_t dev, const char *name);
+int twl_clks_disable(device_t dev, const char *name);
+int twl_clks_is_enabled(device_t dev, const char *name, int *enabled);
+
+
+#endif /* _TWL_CLKS_H_ */
diff -r 7fffa673adcd -r a301a330526b head/sys/arm/ti/twl/twl_vreg.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/head/sys/arm/ti/twl/twl_vreg.c	Wed Aug 15 11:16:36 2012 +0300
@@ -0,0 +1,1053 @@
+/*-
+ * Copyright (c) 2011
+ *	Ben Gray <ben.r.gray at 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: head/sys/arm/ti/twl/twl_vreg.c 239281 2012-08-15 06:31:32Z gonzo $");
+
+/*
+ * Texas Instruments TWL4030/TWL5030/TWL60x0/TPS659x0 Power Management.
+ *
+ * This driver covers the voltages regulators (LDO), allows for enabling &
+ * disabling the voltage output and adjusting the voltage level.
+ *
+ * Voltage regulators can belong to different power groups, in this driver we
+ * put the regulators under our control in the "Application power group".
+ *
+ *
+ * FLATTENED DEVICE TREE (FDT)
+ * Startup override settings can be specified in the FDT, if they are they
+ * should be under the twl parent device and take the following form:
+ *
+ *    voltage-regulators = "name1", "millivolts1",
+ *                         "name2", "millivolts2";
+ *
+ * Each override should be a pair, the first entry is the name of the regulator
+ * the second is the voltage (in millivolts) to set for the given regulator.
+ *
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/lock.h>
+#include <sys/module.h>
+#include <sys/bus.h>
+#include <sys/resource.h>
+#include <sys/rman.h>
+#include <sys/sysctl.h>
+#include <sys/sx.h>
+#include <sys/malloc.h>
+
+#include <machine/bus.h>
+#include <machine/cpu.h>
+#include <machine/cpufunc.h>
+#include <machine/frame.h>
+#include <machine/resource.h>
+#include <machine/intr.h>
+
+#include <dev/ofw/openfirm.h>
+#include <dev/ofw/ofw_bus.h>
+
+#include "twl.h"
+#include "twl_vreg.h"
+
+static int twl_vreg_debug = 1;
+
+
+/*
+ * Power Groups bits for the 4030 and 6030 devices
+ */
+#define TWL4030_P3_GRP		0x80	/* Peripherals, power group */
+#define TWL4030_P2_GRP		0x40	/* Modem power group */
+#define TWL4030_P1_GRP		0x20	/* Application power group (FreeBSD control) */
+
+#define TWL6030_P3_GRP		0x04	/* Modem power group */
+#define TWL6030_P2_GRP		0x02	/* Connectivity power group */
+#define TWL6030_P1_GRP		0x01	/* Application power group (FreeBSD control) */
+
+/*
+ * Register offsets within a LDO regulator register set
+ */
+#define TWL_VREG_GRP		0x00	/* Regulator GRP register */
+#define TWL_VREG_STATE		0x02
+#define TWL_VREG_VSEL		0x03	/* Voltage select register */
+
+#define UNDF  0xFFFF
+
+static const uint16_t twl6030_voltages[] = {
+	0000, 1000, 1100, 1200, 1300, 1400, 1500, 1600,
+	1700, 1800, 1900, 2000, 2100, 2200, 2300, 2400,
+	2500, 2600, 2700, 2800, 2900, 3000, 3100, 3200,
+	3300, UNDF, UNDF, UNDF, UNDF, UNDF, UNDF, 2750
+};
+
+static const uint16_t twl4030_vaux1_voltages[] = {
+	1500, 1800, 2500, 2800, 3000, 3000, 3000, 3000
+};
+static const uint16_t twl4030_vaux2_voltages[] = {
+	1700, 1700, 1900, 1300, 1500, 1800, 2000, 2500,
+	2100, 2800, 2200, 2300, 2400, 2400, 2400, 2400
+};
+static const uint16_t twl4030_vaux3_voltages[] = {
+	1500, 1800, 2500, 2800, 3000, 3000, 3000, 3000
+};
+static const uint16_t twl4030_vaux4_voltages[] = {
+	700,  1000, 1200, 1300, 1500, 1800, 1850, 2500,
+	2600, 2800, 2850, 3000, 3150, 3150, 3150, 3150
+};
+static const uint16_t twl4030_vmmc1_voltages[] = {
+	1850, 2850, 3000, 3150
+};
+static const uint16_t twl4030_vmmc2_voltages[] = {
+	1000, 1000, 1200, 1300, 1500, 1800, 1850, 2500,
+	2600, 2800, 2850, 3000, 3150, 3150, 3150, 3150
+};
+static const uint16_t twl4030_vpll1_voltages[] = {
+	1000, 1200, 1300, 1800, 2800, 3000, 3000, 3000
+};
+static const uint16_t twl4030_vpll2_voltages[] = {
+	700,  1000, 1200, 1300, 1500, 1800, 1850, 2500,
+	2600, 2800, 2850, 3000, 3150, 3150, 3150, 3150
+};
+static const uint16_t twl4030_vsim_voltages[] = {
+	1000, 1200, 1300, 1800, 2800, 3000, 3000, 3000
+};
+static const uint16_t twl4030_vdac_voltages[] = {
+	1200, 1300, 1800, 1800
+};
+static const uint16_t twl4030_vdd1_voltages[] = {
+	800, 1450
+};
+static const uint16_t twl4030_vdd2_voltages[] = {
+	800, 1450, 1500
+};
+static const uint16_t twl4030_vio_voltages[] = {
+	1800, 1850
+};
+static const uint16_t twl4030_vintana2_voltages[] = {
+	2500, 2750
+};
+
+/**
+ *  Support voltage regulators for the different IC's
+ */
+struct twl_regulator {
+	const char	*name;
+	uint8_t		subdev;
+	uint8_t		regbase;
+
+	uint16_t	fixedvoltage;
+
+	const uint16_t	*voltages;
+	uint32_t	num_voltages;
+};
+
+#define TWL_REGULATOR_ADJUSTABLE(name, subdev, reg, voltages) \
+	{ name, subdev, reg, 0, voltages, (sizeof(voltages)/sizeof(voltages[0])) }
+#define TWL_REGULATOR_FIXED(name, subdev, reg, voltage) \
+	{ name, subdev, reg, voltage, NULL, 0 }
+
+static const struct twl_regulator twl4030_regulators[] = {
+	TWL_REGULATOR_ADJUSTABLE("vaux1",    0, 0x17, twl4030_vaux1_voltages),
+	TWL_REGULATOR_ADJUSTABLE("vaux2",    0, 0x1B, twl4030_vaux2_voltages),
+	TWL_REGULATOR_ADJUSTABLE("vaux3",    0, 0x1F, twl4030_vaux3_voltages),
+	TWL_REGULATOR_ADJUSTABLE("vaux4",    0, 0x23, twl4030_vaux4_voltages),
+	TWL_REGULATOR_ADJUSTABLE("vmmc1",    0, 0x27, twl4030_vmmc1_voltages),
+	TWL_REGULATOR_ADJUSTABLE("vmmc2",    0, 0x2B, twl4030_vmmc2_voltages),
+	TWL_REGULATOR_ADJUSTABLE("vpll1",    0, 0x2F, twl4030_vpll1_voltages),
+	TWL_REGULATOR_ADJUSTABLE("vpll2",    0, 0x33, twl4030_vpll2_voltages),
+	TWL_REGULATOR_ADJUSTABLE("vsim",     0, 0x37, twl4030_vsim_voltages),
+	TWL_REGULATOR_ADJUSTABLE("vdac",     0, 0x3B, twl4030_vdac_voltages),
+	TWL_REGULATOR_ADJUSTABLE("vintana2", 0, 0x43, twl4030_vintana2_voltages),
+	TWL_REGULATOR_FIXED("vintana1", 0, 0x3F, 1500),
+	TWL_REGULATOR_FIXED("vintdig",  0, 0x47, 1500),
+	TWL_REGULATOR_FIXED("vusb1v5",  0, 0x71, 1500),
+	TWL_REGULATOR_FIXED("vusb1v8",  0, 0x74, 1800),
+	TWL_REGULATOR_FIXED("vusb3v1",  0, 0x77, 3100),
+	{ NULL, 0, 0x00, 0, NULL, 0 }
+};
+
+static const struct twl_regulator twl6030_regulators[] = {
+	TWL_REGULATOR_ADJUSTABLE("vaux1", 0, 0x84, twl6030_voltages),
+	TWL_REGULATOR_ADJUSTABLE("vaux2", 0, 0x89, twl6030_voltages),
+	TWL_REGULATOR_ADJUSTABLE("vaux3", 0, 0x8C, twl6030_voltages),
+	TWL_REGULATOR_ADJUSTABLE("vmmc",  0, 0x98, twl6030_voltages),
+	TWL_REGULATOR_ADJUSTABLE("vpp",   0, 0x9C, twl6030_voltages),
+	TWL_REGULATOR_ADJUSTABLE("vusim", 0, 0xA4, twl6030_voltages),
+	TWL_REGULATOR_FIXED("vmem",  0, 0x64, 1800),
+	TWL_REGULATOR_FIXED("vusb",  0, 0xA0, 3300),
+	TWL_REGULATOR_FIXED("v1v8",  0, 0x46, 1800),
+	TWL_REGULATOR_FIXED("v2v1",  0, 0x4C, 2100),
+	TWL_REGULATOR_FIXED("v1v29", 0, 0x40, 1290),
+	TWL_REGULATOR_FIXED("vcxio", 0, 0x90, 1800),
+	TWL_REGULATOR_FIXED("vdac",  0, 0x94, 1800),
+	TWL_REGULATOR_FIXED("vana",  0, 0x80, 2100),
+	{ NULL, 0, 0x00, 0, NULL, 0 } 
+};
+
+#define TWL_VREG_MAX_NAMELEN  32
+
+struct twl_regulator_entry {
+	LIST_ENTRY(twl_regulator_entry) entries;
+	char                 name[TWL_VREG_MAX_NAMELEN];
+	struct sysctl_oid   *oid;
+	uint8_t          sub_dev;           /* TWL sub-device group */
+	uint8_t          reg_off;           /* base register offset for the LDO */
+	uint16_t         fixed_voltage;	    /* the (milli)voltage if LDO is fixed */ 
+	const uint16_t  *supp_voltages;     /* pointer to an array of possible voltages */
+	uint32_t         num_supp_voltages; /* the number of supplied voltages */
+};
+
+struct twl_vreg_softc {
+	device_t        sc_dev;
+	device_t        sc_pdev;
+	struct sx       sc_sx;
+
+	struct intr_config_hook sc_init_hook;
+	LIST_HEAD(twl_regulator_list, twl_regulator_entry) sc_vreg_list;
+};
+
+
+#define TWL_VREG_XLOCK(_sc)			sx_xlock(&(_sc)->sc_sx)
+#define	TWL_VREG_XUNLOCK(_sc)		sx_xunlock(&(_sc)->sc_sx)
+#define TWL_VREG_SLOCK(_sc)			sx_slock(&(_sc)->sc_sx)
+#define	TWL_VREG_SUNLOCK(_sc)		sx_sunlock(&(_sc)->sc_sx)
+#define TWL_VREG_LOCK_INIT(_sc)		sx_init(&(_sc)->sc_sx, "twl_vreg")
+#define TWL_VREG_LOCK_DESTROY(_sc)	sx_destroy(&(_sc)->sc_sx);
+
+#define TWL_VREG_ASSERT_LOCKED(_sc)	sx_assert(&(_sc)->sc_sx, SA_LOCKED);
+
+#define TWL_VREG_LOCK_UPGRADE(_sc)               \
+	do {                                         \
+		while (!sx_try_upgrade(&(_sc)->sc_sx))   \
+			pause("twl_vreg_ex", (hz / 100));    \
+	} while(0)
+#define TWL_VREG_LOCK_DOWNGRADE(_sc)	sx_downgrade(&(_sc)->sc_sx);
+
+
+
+
+/**
+ *	twl_vreg_read_1 - read single register from the TWL device
+ *	twl_vreg_write_1 - write a single register in the TWL device
+ *	@sc: device context
+ *	@clk: the clock device we're reading from / writing to
+ *	@off: offset within the clock's register set
+ *	@val: the value to write or a pointer to a variable to store the result
+ *
+ *	RETURNS:
+ *	Zero on success or an error code on failure.
+ */
+static inline int
+twl_vreg_read_1(struct twl_vreg_softc *sc, struct twl_regulator_entry *regulator,
+	uint8_t off, uint8_t *val)
+{
+	return (twl_read(sc->sc_pdev, regulator->sub_dev, 
+	    regulator->reg_off + off, val, 1));
+}
+
+static inline int
+twl_vreg_write_1(struct twl_vreg_softc *sc, struct twl_regulator_entry *regulator,
+	uint8_t off, uint8_t val)
+{
+	return (twl_write(sc->sc_pdev, regulator->sub_dev,
+	    regulator->reg_off + off, &val, 1));
+}
+
+/**
+ *	twl_millivolt_to_vsel - gets the vsel bit value to write into the register
+ *	                        for a desired voltage and regulator
+ *	@sc: the device soft context
+ *	@regulator: pointer to the regulator device
+ *	@millivolts: the millivolts to find the bit value for
+ *	@vsel: upon return will contain the corresponding register value
+ *
+ *	Accepts a (milli)voltage value and tries to find the closest match to the
+ *	actual supported voltages for the given regulator.  If a match is found
+ *	within 100mv of the target, @vsel is written with the match and 0 is
+ *	returned. If no voltage match is found the function returns an non-zero
+ *	value.
+ *
+ *	RETURNS:
+ *	Zero on success or an error code on failure.
+ */
+static int
+twl_vreg_millivolt_to_vsel(struct twl_vreg_softc *sc,
+	struct twl_regulator_entry *regulator, int millivolts, uint8_t *vsel)
+{
+	int delta, smallest_delta;
+	unsigned i, closest_idx;
+
+	TWL_VREG_ASSERT_LOCKED(sc);
+
+	if (regulator->supp_voltages == NULL)
+		return (EINVAL);
+
+	/* Loop over the support voltages and try and find the closest match */
+	closest_idx = 0;
+	smallest_delta = 0x7fffffff;
+	for (i = 0; i < regulator->num_supp_voltages; i++) {
+
+		/* Ignore undefined values */
+		if (regulator->supp_voltages[i] == UNDF)
+			continue;
+
+		/* Calculate the difference */
+		delta = millivolts - (int)regulator->supp_voltages[i];
+		if (abs(delta) < smallest_delta) {
+			smallest_delta = abs(delta);
+			closest_idx = i;
+		}
+	}
+
+	/* Check we got a voltage that was within 100mv of the actual target, this
+	 * is just a value I picked out of thin air.
+	 */
+	if ((smallest_delta > 100) && (closest_idx < 0x100))
+		return (EINVAL);
+
+	*vsel = closest_idx;
+	return (0);
+}
+
+/**
+ *	twl_vreg_is_regulator_enabled - returns the enabled status of the regulator
+ *	@sc: the device soft context
+ *	@regulator: pointer to the regulator device
+ *	@enabled: stores the enabled status, zero disabled, non-zero enabled
+ *
+ *	LOCKING:
+ *	On entry expects the TWL VREG lock to be held. Will upgrade the lock to
+ *	exclusive if not already but, if so, it will be downgraded again before
+ *	returning.
+ *
+ *	RETURNS:
+ *	Zero on success or an error code on failure.
+ */
+static int
+twl_vreg_is_regulator_enabled(struct twl_vreg_softc *sc,
+	struct twl_regulator_entry *regulator, int *enabled)
+{
+	int err;
+	uint8_t grp;
+	uint8_t state;
+	int xlocked;
+	
+	if (enabled == NULL)
+		return (EINVAL);
+
+	TWL_VREG_ASSERT_LOCKED(sc);
+
+	xlocked = sx_xlocked(&sc->sc_sx);
+	if (!xlocked)
+		TWL_VREG_LOCK_UPGRADE(sc);
+
+	/* The status reading is different for the different devices */
+	if (twl_is_4030(sc->sc_pdev)) {
+
+		err = twl_vreg_read_1(sc, regulator, TWL_VREG_GRP, &state);
+		if (err)
+			goto done;
+
+		*enabled = (state & TWL4030_P1_GRP);
+
+	} else if (twl_is_6030(sc->sc_pdev) || twl_is_6025(sc->sc_pdev)) {
+
+		/* Check the regulator is in the application group */
+		if (twl_is_6030(sc->sc_pdev)) {
+			err = twl_vreg_read_1(sc, regulator, TWL_VREG_GRP, &grp);
+			if (err)
+				goto done;
+
+			if (!(grp & TWL6030_P1_GRP)) {
+				*enabled = 0; /* disabled */
+				goto done;
+			}
+		}
+
+		/* Read the application mode state and verify it's ON */
+		err = twl_vreg_read_1(sc, regulator, TWL_VREG_STATE, &state);
+		if (err)
+			goto done;
+
+		*enabled = ((state & 0x0C) == 0x04);
+
+	} else {
+		err = EINVAL;
+	}
+
+done:
+	if (!xlocked)
+		TWL_VREG_LOCK_DOWNGRADE(sc);
+
+	return (err);
+}
+
+/**
+ *	twl_vreg_disable_regulator - disables a voltage regulator
+ *	@sc: the device soft context
+ *	@regulator: pointer to the regulator device
+ *
+ *	Disables the regulator which will stop the output drivers.
+ *
+ *	LOCKING:
+ *	On entry expects the TWL VREG lock to be held. Will upgrade the lock to
+ *	exclusive if not already but, if so, it will be downgraded again before
+ *	returning.
+ *
+ *	RETURNS:
+ *	Zero on success or a positive error code on failure.
+ */
+static int
+twl_vreg_disable_regulator(struct twl_vreg_softc *sc,
+	struct twl_regulator_entry *regulator)
+{
+	int err = 0;
+	uint8_t grp;
+	int xlocked;
+
+	TWL_VREG_ASSERT_LOCKED(sc);
+
+	xlocked = sx_xlocked(&sc->sc_sx);
+	if (!xlocked)
+		TWL_VREG_LOCK_UPGRADE(sc);
+
+	if (twl_is_4030(sc->sc_pdev)) {
+
+		/* Read the regulator CFG_GRP register */
+		err = twl_vreg_read_1(sc, regulator, TWL_VREG_GRP, &grp);
+		if (err)
+			goto done;
+
+		/* On the TWL4030 we just need to remove the regulator from all the
+		 * power groups.
+		 */
+		grp &= ~(TWL4030_P1_GRP | TWL4030_P2_GRP | TWL4030_P3_GRP);
+		err = twl_vreg_write_1(sc, regulator, TWL_VREG_GRP, grp);
+
+	} else if (twl_is_6030(sc->sc_pdev) || twl_is_6025(sc->sc_pdev)) {
+
+		/* On TWL6030 we need to make sure we disable power for all groups */
+		if (twl_is_6030(sc->sc_pdev))
+			grp = TWL6030_P1_GRP | TWL6030_P2_GRP | TWL6030_P3_GRP;
+		else
+			grp = 0x00;
+
+		/* Write the resource state to "OFF" */
+		err = twl_vreg_write_1(sc, regulator, TWL_VREG_STATE, (grp << 5));
+	}
+
+done:
+	if (!xlocked)
+		TWL_VREG_LOCK_DOWNGRADE(sc);
+	
+	return (err);
+}
+
+/**
+ *	twl_vreg_enable_regulator - enables the voltage regulator
+ *	@sc: the device soft context
+ *	@regulator: pointer to the regulator device
+ *
+ *	Enables the regulator which will enable the voltage out at the currently
+ *	set voltage.  Set the voltage before calling this function to avoid
+ *	driving the voltage too high/low by mistake.
+ *
+ *	LOCKING:
+ *	On entry expects the TWL VREG lock to be held. Will upgrade the lock to
+ *	exclusive if not already but, if so, it will be downgraded again before
+ *	returning.
+ *
+ *	RETURNS:
+ *	Zero on success or a positive error code on failure.
+ */
+static int
+twl_vreg_enable_regulator(struct twl_vreg_softc *sc,
+    struct twl_regulator_entry *regulator)
+{
+	int err;
+	uint8_t grp;
+	int xlocked;
+
+	TWL_VREG_ASSERT_LOCKED(sc);
+
+	xlocked = sx_xlocked(&sc->sc_sx);
+	if (!xlocked)
+		TWL_VREG_LOCK_UPGRADE(sc);
+
+
+	err = twl_vreg_read_1(sc, regulator, TWL_VREG_GRP, &grp);
+	if (err)
+		goto done;
+
+	/* Enable the regulator by ensuring it's in the application power group
+	 * and is in the "on" state.
+	 */
+	if (twl_is_4030(sc->sc_pdev)) {
+
+		/* On the TWL4030 we just need to ensure the regulator is in the right
+		 * power domain, don't need to turn on explicitly like TWL6030.
+		 */
+		grp |= TWL4030_P1_GRP;
+		err = twl_vreg_write_1(sc, regulator, TWL_VREG_GRP, grp);
+
+	} else if (twl_is_6030(sc->sc_pdev) || twl_is_6025(sc->sc_pdev)) {
+
+		if (twl_is_6030(sc->sc_pdev) && !(grp & TWL6030_P1_GRP)) {
+			grp |= TWL6030_P1_GRP;
+			err = twl_vreg_write_1(sc, regulator, TWL_VREG_GRP, grp);
+			if (err)
+				goto done;
+		}
+
+		/* Write the resource state to "ON" */
+		err = twl_vreg_write_1(sc, regulator, TWL_VREG_STATE, (grp << 5) | 0x01);
+	}
+
+done:
+	if (!xlocked)
+		TWL_VREG_LOCK_DOWNGRADE(sc);
+	
+	return (err);
+}
+
+/**
+ *	twl_vreg_write_regulator_voltage - sets the voltage level on a regulator
+ *	@sc: the device soft context
+ *	@regulator: pointer to the regulator structure
+ *	@millivolts: the voltage to set
+ *
+ *	Sets the voltage output on a given regulator, if the regulator is not
+ *	enabled, it will be enabled.
+ *
+ *	LOCKING:
+ *	On entry expects the TWL VREG lock to be held, may upgrade the lock to
+ *	exclusive but if so it will be downgraded once again before returning.
+ *
+ *	RETURNS:
+ *	Zero on success or an error code on failure.
+ */
+static int
+twl_vreg_write_regulator_voltage(struct twl_vreg_softc *sc,
+    struct twl_regulator_entry *regulator, int millivolts)
+{
+	int err;
+	uint8_t vsel;
+	int xlocked;
+
+	TWL_VREG_ASSERT_LOCKED(sc);
+
+	/* If millivolts is zero then we simply disable the output */
+	if (millivolts == 0)
+		return (twl_vreg_disable_regulator(sc, regulator));
+
+	/* If the regulator has a fixed voltage then check the setting matches
+	 * and simply enable.
+	 */
+	if (regulator->supp_voltages == NULL || regulator->num_supp_voltages == 0) {
+		if (millivolts != regulator->fixed_voltage)
+			return (EINVAL);
+
+		return (twl_vreg_enable_regulator(sc, regulator));
+	}
+
+	/* Get the VSEL value for the given voltage */
+	err = twl_vreg_millivolt_to_vsel(sc, regulator, millivolts, &vsel);
+	if (err)
+		return (err);
+
+	
+	/* Need to upgrade because writing the voltage and enabling should be atomic */
+	xlocked = sx_xlocked(&sc->sc_sx);
+	if (!xlocked)
+		TWL_VREG_LOCK_UPGRADE(sc);
+
+
+	/* Set voltage and enable (atomically) */
+	err = twl_vreg_write_1(sc, regulator, TWL_VREG_VSEL, (vsel & 0x1f));
+	if (!err) {
+		err = twl_vreg_enable_regulator(sc, regulator);
+	}
+
+	if (!xlocked)
+		TWL_VREG_LOCK_DOWNGRADE(sc);
+
+	if ((twl_vreg_debug > 1) && !err)
+		device_printf(sc->sc_dev, "%s : setting voltage to %dmV (vsel: 0x%x)\n",
+		    regulator->name, millivolts, vsel);
+
+	return (err);
+}
+
+/**
+ *	twl_vreg_read_regulator_voltage - reads the voltage on a given regulator
+ *	@sc: the device soft context
+ *	@regulator: pointer to the regulator structure
+ *	@millivolts: upon return will contain the voltage on the regulator
+ *
+ *	LOCKING:
+ *	On entry expects the TWL VREG lock to be held. It will upgrade the lock to
+ *	exclusive if not already, but if so, it will be downgraded again before
+ *	returning.
+ *
+ *	RETURNS:
+ *	Zero on success, or otherwise an error code.
+ */
+static int
+twl_vreg_read_regulator_voltage(struct twl_vreg_softc *sc,
+    struct twl_regulator_entry *regulator, int *millivolts)
+{
+	int err;
+	int en = 0;
+	int xlocked;
+	uint8_t vsel;
+	
+	TWL_VREG_ASSERT_LOCKED(sc);
+	
+	/* Need to upgrade the lock because checking enabled state and voltage
+	 * should be atomic.
+	 */
+	xlocked = sx_xlocked(&sc->sc_sx);
+	if (!xlocked)
+		TWL_VREG_LOCK_UPGRADE(sc);
+
+
+	/* Check if the regulator is currently enabled */
+	err = twl_vreg_is_regulator_enabled(sc, regulator, &en);
+	if (err)
+		goto done;
+
+	*millivolts = 0;	
+	if (!en)
+		goto done;
+
+
+	/* Not all voltages are adjustable */
+	if (regulator->supp_voltages == NULL || !regulator->num_supp_voltages) {
+		*millivolts = regulator->fixed_voltage;
+		goto done;
+	}
+
+	/* For variable voltages read the voltage register */
+	err = twl_vreg_read_1(sc, regulator, TWL_VREG_VSEL, &vsel);
+	if (err)
+		goto done;
+
+	vsel &= (regulator->num_supp_voltages - 1);
+	if (regulator->supp_voltages[vsel] == UNDF) {
+		err = EINVAL;
+		goto done;
+	}
+
+	*millivolts = regulator->supp_voltages[vsel];
+
+done:
+	if (!xlocked)
+		TWL_VREG_LOCK_DOWNGRADE(sc);
+	
+	if ((twl_vreg_debug > 1) && !err)
+		device_printf(sc->sc_dev, "%s : reading voltage is %dmV (vsel: 0x%x)\n",
+		    regulator->name, *millivolts, vsel);
+
+	return (err);
+}
+
+/**
+ *	twl_vreg_get_voltage - public interface to read the voltage on a regulator
+ *	@dev: TWL VREG device
+ *	@name: the name of the regulator to read the voltage of
+ *	@millivolts: pointer to an integer that upon return will contain the mV
+ *
+ *	If the regulator is disabled the function will set the @millivolts to zero.
+ *
+ *	LOCKING:
+ *	Internally the function takes and releases the TWL VREG lock.
+ *
+ *	RETURNS:
+ *	Zero on success or a negative error code on failure.
+ */
+int
+twl_vreg_get_voltage(device_t dev, const char *name, int *millivolts)
+{
+	struct twl_vreg_softc *sc;
+	struct twl_regulator_entry *regulator;
+	int err = EINVAL;
+
+	if (millivolts == NULL)
+		return (EINVAL);
+
+	sc = device_get_softc(dev);
+
+	TWL_VREG_SLOCK(sc);
+
+	LIST_FOREACH(regulator, &sc->sc_vreg_list, entries) {
+		if (strcmp(regulator->name, name) == 0) {
+			err = twl_vreg_read_regulator_voltage(sc, regulator, millivolts);
+			break;
+		}
+	}
+
+	TWL_VREG_SUNLOCK(sc);
+
+	return (err);
+}
+
+/**
+ *	twl_vreg_set_voltage - public interface to write the voltage on a regulator
+ *	@dev: TWL VREG device
+ *	@name: the name of the regulator to read the voltage of
+ *	@millivolts: the voltage to set in millivolts
+ *
+ *	Sets the output voltage on a given regulator. If the regulator is a fixed
+ *	voltage reg then the @millivolts value should match the fixed voltage. If
+ *	a variable regulator then the @millivolt value must fit within the max/min
+ *	range of the given regulator.
+ *
+ *	LOCKING:
+ *	Internally the function takes and releases the TWL VREG lock.
+ *
+ *	RETURNS:
+ *	Zero on success or a negative error code on failure.
+ */
+int
+twl_vreg_set_voltage(device_t dev, const char *name, int millivolts)
+{
+	struct twl_vreg_softc *sc;
+	struct twl_regulator_entry *regulator;
+	int err = EINVAL;
+
+	sc = device_get_softc(dev);
+
+	TWL_VREG_SLOCK(sc);
+
+	LIST_FOREACH(regulator, &sc->sc_vreg_list, entries) {
+		if (strcmp(regulator->name, name) == 0) {
+			err = twl_vreg_write_regulator_voltage(sc, regulator, millivolts);
+			break;
+		}
+	}
+
+	TWL_VREG_SUNLOCK(sc);
+
+	return (err);
+}
+
+/**
+ *	twl_sysctl_voltage - reads or writes the voltage for a regulator
+ *	@SYSCTL_HANDLER_ARGS: arguments for the callback
+ *
+ *	Callback for the sysctl entry for the regulator, simply used to return
+ *	the voltage on a particular regulator.
+ *
+ *	LOCKING:
+ *	Takes the TWL_VREG shared lock internally.
+ *
+ *	RETURNS:
+ *	Zero on success or an error code on failure.
+ */
+static int
+twl_vreg_sysctl_voltage(SYSCTL_HANDLER_ARGS)
+{
+	struct twl_vreg_softc *sc = (struct twl_vreg_softc*)arg1;
+	struct twl_regulator_entry *regulator;
+	int voltage;
+	int found = 0;
+
+	TWL_VREG_SLOCK(sc);
+
+	/* Find the regulator with the matching name */
+	LIST_FOREACH(regulator, &sc->sc_vreg_list, entries) {
+		if (strcmp(regulator->name, oidp->oid_name) == 0) {
+			found = 1;
+			break;
+		}
+	}
+
+	/* Sanity check that we found the regulator */
+	if (!found) {
+		TWL_VREG_SUNLOCK(sc);
+		return (EINVAL);
+	}
+
+	twl_vreg_read_regulator_voltage(sc, regulator, &voltage);
+
+	TWL_VREG_SUNLOCK(sc);
+
+	return sysctl_handle_int(oidp, &voltage, 0, req);
+}
+
+/**
+ *	twl_add_regulator - adds single voltage regulator sysctls for the device
+ *	@sc: device soft context
+ *	@name: the name of the regulator
+ *	@nsub: the number of the subdevice
+ *	@regbase: the base address of the voltage regulator registers
+ *	@fixed_voltage: if a fixed voltage regulator this defines it's voltage
+ *	@voltages: if a variable voltage regulator, an array of possible voltages
+ *	@num_voltages: the number of entries @voltages
+ *
+ *	Adds a voltage regulator to the device and also a sysctl interface for the
+ *	regulator.
+ *
+ *	LOCKING:
+ *	The TWL_VEG exclusive lock must be held while this function is called.
+ *
+ *	RETURNS:
+ *	Pointer to the new regulator entry on success, otherwise on failure NULL.
+ */
+static struct twl_regulator_entry*
+twl_vreg_add_regulator(struct twl_vreg_softc *sc, const char *name,
+	uint8_t nsub, uint8_t regbase, uint16_t fixed_voltage,
+	const uint16_t *voltages, uint32_t num_voltages)
+{
+	struct sysctl_ctx_list *ctx = device_get_sysctl_ctx(sc->sc_dev);
+	struct sysctl_oid *tree = device_get_sysctl_tree(sc->sc_dev);
+	struct twl_regulator_entry *new;
+
+	new = malloc(sizeof(struct twl_regulator_entry), M_DEVBUF, M_NOWAIT | M_ZERO);
+	if (new == NULL)
+		return (NULL);
+
+
+	strncpy(new->name, name, TWL_VREG_MAX_NAMELEN);
+	new->name[TWL_VREG_MAX_NAMELEN - 1] = '\0';
+
+	new->sub_dev = nsub;
+	new->reg_off = regbase;
+
+	new->fixed_voltage = fixed_voltage;
+
+	new->supp_voltages = voltages;
+	new->num_supp_voltages = num_voltages;
+
+
+	/* Add a sysctl entry for the voltage */
+	new->oid = SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(tree), OID_AUTO, name,
+	    CTLTYPE_INT | CTLFLAG_RD, sc, 0,
+	    twl_vreg_sysctl_voltage, "I", "voltage regulator");
+
+	/* Finally add the regulator to list of supported regulators */
+	LIST_INSERT_HEAD(&sc->sc_vreg_list, new, entries);
+
+	return (new);
+}
+
+/**
+ *	twl_vreg_add_regulators - adds any voltage regulators to the device
+ *	@sc: device soft context
+ *	@chip: the name of the chip used in the hints
+ *	@regulators: the list of possible voltage regulators
+ *
+ *	Loops over the list of regulators and matches up with the FDT values,
+ *	adjusting the actual voltage based on the supplied values.
+ *
+ *	LOCKING:
+ *	The TWL_VEG exclusive lock must be held while this function is called.
+ *
+ *	RETURNS:
+ *	Always returns 0.
+ */
+static int
+twl_vreg_add_regulators(struct twl_vreg_softc *sc,
+	const struct twl_regulator *regulators)
+{
+	int err;
+	int millivolts;
+	const struct twl_regulator *walker;
+	struct twl_regulator_entry *entry;
+	phandle_t child;
+	char rnames[256];
+	char *name, *voltage;
+	int len = 0, prop_len;
+
+
+	/* Add the regulators from the list */
+	walker = &regulators[0];
+	while (walker->name != NULL) {
+
+		/* Add the regulator to the list */
+		entry = twl_vreg_add_regulator(sc, walker->name, walker->subdev,
+		    walker->regbase, walker->fixedvoltage,
+		    walker->voltages, walker->num_voltages);
+		if (entry == NULL)
+			continue;
+
+		walker++;
+	}
+
+
+	/* Check if the FDT is telling us to set any voltages */
+	child = ofw_bus_get_node(sc->sc_pdev);
+	if (child) {
+
+		prop_len = OF_getprop(child, "voltage-regulators", rnames, sizeof(rnames));
+		while (len < prop_len) {
+			name = rnames + len;
+			len += strlen(name) + 1;
+			if ((len >= prop_len) || (name[0] == '\0'))
+				break;
+			
+			voltage = rnames + len;
+			len += strlen(voltage) + 1;
+			if (voltage[0] == '\0')
+				break;
+			
+			millivolts = strtoul(voltage, NULL, 0);
+			
+			LIST_FOREACH(entry, &sc->sc_vreg_list, entries) {
+				if (strcmp(entry->name, name) == 0) {
+					twl_vreg_write_regulator_voltage(sc, entry, millivolts);
+					break;
+				}
+			}
+		}
+	}
+	
+	
+	if (twl_vreg_debug) {
+		LIST_FOREACH(entry, &sc->sc_vreg_list, entries) {
+			err = twl_vreg_read_regulator_voltage(sc, entry, &millivolts);
+			if (!err)
+				device_printf(sc->sc_dev, "%s : %d mV\n", entry->name, millivolts);
+		}
+	}
+
+	return (0);
+}
+
+/**
+ *	twl_vreg_init - initialises the list of regulators
+ *	@dev: the twl_vreg device
+ *
+ *	This function is called as an intrhook once interrupts have been enabled,
+ *	this is done so that the driver has the option to enable/disable or set
+ *	the voltage level based on settings providied in the FDT.
+ *
+ *	LOCKING:
+ *	Takes the exclusive lock in the function.
+ */
+static void
+twl_vreg_init(void *dev)
+{
+	struct twl_vreg_softc *sc;
+
+	sc = device_get_softc((device_t)dev);
+
+	TWL_VREG_XLOCK(sc);
+
+	if (twl_is_4030(sc->sc_pdev))
+		twl_vreg_add_regulators(sc, twl4030_regulators);
+	else if (twl_is_6030(sc->sc_pdev) || twl_is_6025(sc->sc_pdev))
+		twl_vreg_add_regulators(sc, twl6030_regulators);
+
+	TWL_VREG_XUNLOCK(sc);
+
+	config_intrhook_disestablish(&sc->sc_init_hook);
+}
+
+static int
+twl_vreg_probe(device_t dev)
+{
+	if (twl_is_4030(device_get_parent(dev)))
+		device_set_desc(dev, "TI TWL4030 PMIC Voltage Regulators");
+	else if (twl_is_6025(device_get_parent(dev)) ||
+	         twl_is_6030(device_get_parent(dev)))
+		device_set_desc(dev, "TI TWL6025/TWL6030 PMIC Voltage Regulators");
+	else
+		return (ENXIO);
+
+	return (0);
+}
+
+static int
+twl_vreg_attach(device_t dev)
+{
+	struct twl_vreg_softc *sc;
+
+	sc = device_get_softc(dev);
+	sc->sc_dev = dev;
+	sc->sc_pdev = device_get_parent(dev);
+
+	TWL_VREG_LOCK_INIT(sc);
+
+	LIST_INIT(&sc->sc_vreg_list);
+
+	/* We have to wait until interrupts are enabled. I2C read and write
+	 * only works if the interrupts are available.
+	 */
+	sc->sc_init_hook.ich_func = twl_vreg_init;
+	sc->sc_init_hook.ich_arg = dev;
+
+	if (config_intrhook_establish(&sc->sc_init_hook) != 0)
+		return (ENOMEM);
+
+	return (0);
+}
+
+static int
+twl_vreg_detach(device_t dev)
+{
+	struct twl_vreg_softc *sc;
+	struct twl_regulator_entry *regulator;
+	struct twl_regulator_entry *tmp;
+
+	sc = device_get_softc(dev);
+
+	/* Take the lock and free all the added regulators */
+	TWL_VREG_XLOCK(sc);
+
+	LIST_FOREACH_SAFE(regulator, &sc->sc_vreg_list, entries, tmp) {
+		LIST_REMOVE(regulator, entries);
+		sysctl_remove_oid(regulator->oid, 1, 0);
+		free(regulator, M_DEVBUF);
+	}
+
+	TWL_VREG_XUNLOCK(sc);
+
+	TWL_VREG_LOCK_DESTROY(sc);
+
+	return (0);
+}
+
+static device_method_t twl_vreg_methods[] = {
+	DEVMETHOD(device_probe,		twl_vreg_probe),
+	DEVMETHOD(device_attach,	twl_vreg_attach),
+	DEVMETHOD(device_detach,	twl_vreg_detach),
+
+	{0, 0},
+};
+
+static driver_t twl_vreg_driver = {
+	"twl_vreg",
+	twl_vreg_methods,
+	sizeof(struct twl_vreg_softc),
+};
+
+static devclass_t twl_vreg_devclass;
+
+DRIVER_MODULE(twl_vreg, twl, twl_vreg_driver, twl_vreg_devclass, 0, 0);
+MODULE_VERSION(twl_vreg, 1);
diff -r 7fffa673adcd -r a301a330526b head/sys/arm/ti/twl/twl_vreg.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/head/sys/arm/ti/twl/twl_vreg.h	Wed Aug 15 11:16:36 2012 +0300
@@ -0,0 +1,36 @@
+/*-
+ * Copyright (c) 2011
+ *	Ben Gray <ben.r.gray at 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.
+ *
+ * $FreeBSD: head/sys/arm/ti/twl/twl_vreg.h 239281 2012-08-15 06:31:32Z gonzo $
+ */
+#ifndef _TWL_VREG_H_
+#define _TWL_VREG_H_
+
+
+int twl_vreg_get_voltage(device_t dev, const char *name, int *millivolts);
+int twl_vreg_set_voltage(device_t dev, const char *name, int millivolts);
+
+#endif /* _TWL_VREG_H_ */
diff -r 7fffa673adcd -r a301a330526b head/sys/arm/ti/usb/omap_ehci.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/head/sys/arm/ti/usb/omap_ehci.c	Wed Aug 15 11:16:36 2012 +0300
@@ -0,0 +1,1024 @@
+/*-
+ * Copyright (c) 2011
+ *	Ben Gray <ben.r.gray at 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.
+ */
+
+/**
+ * Driver for the High Speed USB EHCI module on the TI OMAP3530 SoC.
+ *
+ * WARNING: I've only tried this driver on a limited number of USB peripherals,
+ * it is still very raw and bound to have numerous bugs in it.
+ *
+ * This driver is based on the FreeBSD IXP4xx EHCI driver with a lot of the
+ * setup sequence coming from the Linux community and their EHCI driver for
+ * OMAP.  Without these as a base I don't think I would have been able to get
+ * this driver working.
+ *
+ * The driver only contains the EHCI parts, the module also supports OHCI and
+ * USB on-the-go (OTG), currently neither are supported.
+ *
+ * CAUTION: This driver was written to run on the beaglebaord dev board, so I
+ * have made some assumptions about the type of PHY used and some of the other
+ * settings.  Bare that in mind if you intend to use this driver on another
+ * platform.
+ *
+ * NOTE: This module uses a few different clocks, one being a 60Mhz clock for
+ * the TTL part of the module.  This clock is derived from DPPL5 which must be
+ * configured prior to loading this driver - it is not configured by the
+ * bootloader.  It took me a long time to figure this out, and caused much
+ * frustration.  This PLL is now setup in the timer/clocks part of the BSP,
+ * check out the omap_prcm_setup_dpll5() function in omap_prcm.c for more info.
+ *
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: head/sys/arm/ti/usb/omap_ehci.c 239281 2012-08-15 06:31:32Z gonzo $");
+
+#include "opt_bus.h"
+
+#include <sys/stdint.h>
+#include <sys/stddef.h>
+#include <sys/param.h>
+#include <sys/queue.h>
+#include <sys/types.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/bus.h>
+#include <sys/rman.h>
+#include <sys/linker_set.h>
+#include <sys/module.h>
+#include <sys/lock.h>
+#include <sys/mutex.h>
+#include <sys/condvar.h>
+#include <sys/sysctl.h>
+#include <sys/sx.h>
+#include <sys/unistd.h>
+#include <sys/callout.h>
+#include <sys/malloc.h>
+#include <sys/priv.h>
+#include <sys/gpio.h>
+
+#include <dev/fdt/fdt_common.h>
+#include <dev/ofw/openfirm.h>
+#include <dev/ofw/ofw_bus.h>
+#include <dev/ofw/ofw_bus_subr.h>
+
+#include <dev/usb/usb.h>
+#include <dev/usb/usbdi.h>
+
+#include <dev/usb/usb_core.h>
+#include <dev/usb/usb_busdma.h>
+#include <dev/usb/usb_process.h>
+#include <dev/usb/usb_util.h>
+
+#include <dev/usb/usb_controller.h>
+#include <dev/usb/usb_bus.h>
+#include <dev/usb/controller/ehci.h>
+#include <dev/usb/controller/ehcireg.h>
+
+#include <arm/ti/tivar.h>
+#include <arm/ti/ti_prcm.h>
+#include <arm/ti/ti_scm.h>
+
+#include <arm/ti/usb/omap_usb.h>
+
+#include "gpio_if.h"
+
+struct omap_ehci_softc {
+	ehci_softc_t        base;	/* storage for EHCI code */
+
+	device_t            sc_dev;
+	device_t            sc_gpio_dev;
+
+	/* TLL register set */
+	struct resource*    tll_mem_res;
+
+	/* UHH register set */
+	struct resource*    uhh_mem_res;
+
+	/* The revision of the HS USB HOST read from UHH_REVISION */
+	uint32_t            ehci_rev;
+
+	/* The following details are provided by conf hints */
+	int                 port_mode[3];
+	int                 phy_reset[3];
+	int                 reset_gpio_pin[3];
+};
+
+static device_attach_t omap_ehci_attach;
+static device_detach_t omap_ehci_detach;
+static device_shutdown_t omap_ehci_shutdown;
+static device_suspend_t omap_ehci_suspend;
+static device_resume_t omap_ehci_resume;
+
+/**
+ *	omap_tll_read_4 - read a 32-bit value from the USBTLL registers
+ *	omap_tll_write_4 - write a 32-bit value from the USBTLL registers
+ *	omap_tll_readb - read an 8-bit value from the USBTLL registers
+ *	omap_tll_writeb - write an 8-bit value from the USBTLL registers
+ *	@sc: omap ehci device context
+ *	@off: byte offset within the register set to read from
+ *	@val: the value to write into the register
+ *	
+ *
+ *	LOCKING:
+ *	None
+ *
+ *	RETURNS:
+ *	nothing in case of write function, if read function returns the value read.
+ */
+static inline uint32_t
+omap_tll_read_4(struct omap_ehci_softc *sc, bus_size_t off)
+{
+	return bus_read_4(sc->tll_mem_res, off);
+}
+
+static inline void
+omap_tll_write_4(struct omap_ehci_softc *sc, bus_size_t off, uint32_t val)
+{
+	bus_write_4(sc->tll_mem_res, off, val);
+}
+
+static inline uint8_t
+omap_tll_readb(struct omap_ehci_softc *sc, bus_size_t off)
+{
+	return bus_read_1(sc->tll_mem_res, off);
+}
+
+static inline void
+omap_tll_writeb(struct omap_ehci_softc *sc, bus_size_t off, uint8_t val)
+{
+	bus_write_1(sc->tll_mem_res, off, val);
+}
+
+/**
+ *	omap_ehci_read_4 - read a 32-bit value from the EHCI registers
+ *	omap_ehci_write_4 - write a 32-bit value from the EHCI registers
+ *	@sc: omap ehci device context
+ *	@off: byte offset within the register set to read from
+ *	@val: the value to write into the register
+ *	
+ *
+ *	LOCKING:
+ *	None
+ *
+ *	RETURNS:
+ *	nothing in case of write function, if read function returns the value read.
+ */
+static inline uint32_t
+omap_ehci_read_4(struct omap_ehci_softc *sc, bus_size_t off)
+{
+	return (bus_read_4(sc->base.sc_io_res, off));
+}
+static inline void
+omap_ehci_write_4(struct omap_ehci_softc *sc, bus_size_t off, uint32_t val)
+{
+	bus_write_4(sc->base.sc_io_res, off, val);
+}
+
+/**
+ *	omap_uhh_read_4 - read a 32-bit value from the UHH registers
+ *	omap_uhh_write_4 - write a 32-bit value from the UHH registers
+ *	@sc: omap ehci device context
+ *	@off: byte offset within the register set to read from
+ *	@val: the value to write into the register
+ *	
+ *
+ *	LOCKING:
+ *	None
+ *
+ *	RETURNS:
+ *	nothing in case of write function, if read function returns the value read.
+ */
+static inline uint32_t
+omap_uhh_read_4(struct omap_ehci_softc *sc, bus_size_t off)
+{
+	return bus_read_4(sc->uhh_mem_res, off);
+}
+static inline void
+omap_uhh_write_4(struct omap_ehci_softc *sc, bus_size_t off, uint32_t val)
+{
+	bus_write_4(sc->uhh_mem_res, off, val);
+}
+
+/**
+ *	omap_ehci_utmi_init - initialises the UTMI part of the controller
+ *	@isc: omap ehci device context
+ *
+ *	
+ *
+ *	LOCKING:
+ *	none
+ *
+ *	RETURNS:
+ *	nothing
+ */
+static void
+omap_ehci_utmi_init(struct omap_ehci_softc *isc, unsigned int en_mask)
+{
+	unsigned int i;
+	uint32_t reg;
+	
+	/* There are 3 TLL channels, one per USB controller so set them all up the
+	 * same, SDR mode, bit stuffing and no autoidle.
+	 */
+	for (i=0; i<3; i++) {
+		reg = omap_tll_read_4(isc, OMAP_USBTLL_TLL_CHANNEL_CONF(i));
+		
+		reg &= ~(TLL_CHANNEL_CONF_UTMIAUTOIDLE
+				 | TLL_CHANNEL_CONF_ULPINOBITSTUFF
+				 | TLL_CHANNEL_CONF_ULPIDDRMODE);
+		
+		omap_tll_write_4(isc, OMAP_USBTLL_TLL_CHANNEL_CONF(i), reg);
+	}
+	
+	/* Program the common TLL register */
+	reg = omap_tll_read_4(isc, OMAP_USBTLL_TLL_SHARED_CONF);
+
+	reg &= ~( TLL_SHARED_CONF_USB_90D_DDR_EN
+			| TLL_SHARED_CONF_USB_DIVRATIO_MASK);
+	reg |=  ( TLL_SHARED_CONF_FCLK_IS_ON
+			| TLL_SHARED_CONF_USB_DIVRATIO_2
+			| TLL_SHARED_CONF_USB_180D_SDR_EN);
+	
+	omap_tll_write_4(isc, OMAP_USBTLL_TLL_SHARED_CONF, reg);
+	
+	/* Enable channels now */
+	for (i = 0; i < 3; i++) {
+		reg = omap_tll_read_4(isc, OMAP_USBTLL_TLL_CHANNEL_CONF(i));
+		
+		/* Enable only the reg that is needed */
+		if ((en_mask & (1 << i)) == 0)
+			continue;
+		
+		reg |= TLL_CHANNEL_CONF_CHANEN;
+		omap_tll_write_4(isc, OMAP_USBTLL_TLL_CHANNEL_CONF(i), reg);
+	}
+}
+
+/**
+ *	omap_ehci_soft_phy_reset - resets the phy using the reset command
+ *	@isc: omap ehci device context
+ *	@port: port to send the reset over
+ *	
+ *
+ *	LOCKING:
+ *	none
+ *
+ *	RETURNS:
+ *	nothing
+ */
+static void 
+omap_ehci_soft_phy_reset(struct omap_ehci_softc *isc, unsigned int port)
+{
+	unsigned long timeout = (hz < 10) ? 1 : ((100 * hz) / 1000);
+	uint32_t reg;
+
+	reg = ULPI_FUNC_CTRL_RESET
+		/* FUNCTION_CTRL_SET register */
+		| (ULPI_SET(ULPI_FUNC_CTRL) << OMAP_USBHOST_INSNREG05_ULPI_REGADD_SHIFT)
+		/* Write */
+		| (2 << OMAP_USBHOST_INSNREG05_ULPI_OPSEL_SHIFT)
+		/* PORTn */
+		| ((port + 1) << OMAP_USBHOST_INSNREG05_ULPI_PORTSEL_SHIFT)
+		/* start ULPI access*/
+		| (1 << OMAP_USBHOST_INSNREG05_ULPI_CONTROL_SHIFT);
+
+	omap_ehci_write_4(isc, OMAP_USBHOST_INSNREG05_ULPI, reg);
+
+	/* Wait for ULPI access completion */
+	while ((omap_ehci_read_4(isc, OMAP_USBHOST_INSNREG05_ULPI)
+	       & (1 << OMAP_USBHOST_INSNREG05_ULPI_CONTROL_SHIFT))) {
+
+		/* Sleep for a tick */
+		pause("USBPHY_RESET", 1);
+		
+		if (timeout-- == 0) {
+			device_printf(isc->sc_dev, "PHY reset operation timed out\n");
+			break;
+		}
+	}
+}
+ 
+
+/**
+ *	omap_ehci_init - initialises the USB host EHCI controller
+ *	@isc: omap ehci device context
+ *
+ *	This initialisation routine is quite heavily based on the work done by the
+ *	OMAP Linux team (for which I thank them very much).  The init sequence is
+ *	almost identical, diverging only for the FreeBSD specifics.
+ *
+ *	LOCKING:
+ *	none
+ *
+ *	RETURNS:
+ *	0 on success, a negative error code on failure.
+ */
+static int
+omap_ehci_init(struct omap_ehci_softc *isc)
+{
+	unsigned long timeout;
+	int ret = 0;
+	uint8_t tll_ch_mask = 0;
+	uint32_t reg = 0;
+	int reset_performed = 0;
+	int i;
+	
+	device_printf(isc->sc_dev, "Starting TI EHCI USB Controller\n");
+	
+	
+	/* Enable Clocks for high speed USBHOST */
+	ti_prcm_clk_enable(USBHSHOST_CLK);
+	
+	/* Hold the PHY in reset while configuring */
+	for (int i = 0; i < 3; i++) {
+		if (isc->phy_reset[i]) {
+			/* Configure the GPIO to drive low (hold in reset) */
+			if ((isc->reset_gpio_pin[i] != -1) && (isc->sc_gpio_dev != NULL)) {
+				GPIO_PIN_SETFLAGS(isc->sc_gpio_dev, isc->reset_gpio_pin[i],
+				    GPIO_PIN_OUTPUT);
+				GPIO_PIN_SET(isc->sc_gpio_dev, isc->reset_gpio_pin[i],
+				    GPIO_PIN_LOW);
+				reset_performed = 1;
+			}
+		}
+	}
+
+	/* Hold the PHY in RESET for enough time till DIR is high */
+	if (reset_performed)
+		DELAY(10);
+
+	/* Read the UHH revision */
+	isc->ehci_rev = omap_uhh_read_4(isc, OMAP_USBHOST_UHH_REVISION);
+	device_printf(isc->sc_dev, "UHH revision 0x%08x\n", isc->ehci_rev);
+	
+	/* Initilise the low level interface module(s) */
+	if (isc->ehci_rev == OMAP_EHCI_REV1) {
+
+		/* Enable the USB TLL */
+		ti_prcm_clk_enable(USBTLL_CLK);
+
+		/* Perform TLL soft reset, and wait until reset is complete */
+		omap_tll_write_4(isc, OMAP_USBTLL_SYSCONFIG, TLL_SYSCONFIG_SOFTRESET);
+	
+		/* Set the timeout to 100ms*/
+		timeout = (hz < 10) ? 1 : ((100 * hz) / 1000);
+
+		/* Wait for TLL reset to complete */
+		while ((omap_tll_read_4(isc, OMAP_USBTLL_SYSSTATUS) & 
+		        TLL_SYSSTATUS_RESETDONE) == 0x00) {
+
+			/* Sleep for a tick */
+			pause("USBRESET", 1);
+		
+			if (timeout-- == 0) {
+				device_printf(isc->sc_dev, "TLL reset operation timed out\n");
+				ret = EINVAL;
+				goto err_sys_status;
+			}
+		}
+	
+		device_printf(isc->sc_dev, "TLL RESET DONE\n");
+		
+		/* CLOCKACTIVITY = 1 : OCP-derived internal clocks ON during idle
+		 * SIDLEMODE = 2     : Smart-idle mode. Sidleack asserted after Idlereq
+		 *                     assertion when no more activity on the USB.
+		 * ENAWAKEUP = 1     : Wakeup generation enabled
+		 */
+		omap_tll_write_4(isc, OMAP_USBTLL_SYSCONFIG, TLL_SYSCONFIG_ENAWAKEUP |
+		                                            TLL_SYSCONFIG_AUTOIDLE |
+		                                            TLL_SYSCONFIG_SIDLE_SMART_IDLE |
+		                                            TLL_SYSCONFIG_CACTIVITY);
+
+	} else if (isc->ehci_rev == OMAP_EHCI_REV2) {
+	
+		/* For OMAP44xx devices you have to enable the per-port clocks:
+		 *  PHY_MODE  - External ULPI clock
+		 *  TTL_MODE  - Internal UTMI clock
+		 *  HSIC_MODE - Internal 480Mhz and 60Mhz clocks
+		 */
+		if (isc->ehci_rev == OMAP_EHCI_REV2) {
+			if (isc->port_mode[0] == EHCI_HCD_OMAP_MODE_PHY) {
+				ti_prcm_clk_set_source(USBP1_PHY_CLK, EXT_CLK);
+				ti_prcm_clk_enable(USBP1_PHY_CLK);
+			} else if (isc->port_mode[0] == EHCI_HCD_OMAP_MODE_TLL)
+				ti_prcm_clk_enable(USBP1_UTMI_CLK);
+			else if (isc->port_mode[0] == EHCI_HCD_OMAP_MODE_HSIC)
+				ti_prcm_clk_enable(USBP1_HSIC_CLK);
+
+			if (isc->port_mode[1] == EHCI_HCD_OMAP_MODE_PHY) {
+				ti_prcm_clk_set_source(USBP2_PHY_CLK, EXT_CLK);
+				ti_prcm_clk_enable(USBP2_PHY_CLK);
+			} else if (isc->port_mode[1] == EHCI_HCD_OMAP_MODE_TLL)
+				ti_prcm_clk_enable(USBP2_UTMI_CLK);
+			else if (isc->port_mode[1] == EHCI_HCD_OMAP_MODE_HSIC)
+				ti_prcm_clk_enable(USBP2_HSIC_CLK);
+		}
+	}
+
+	/* Put UHH in SmartIdle/SmartStandby mode */
+	reg = omap_uhh_read_4(isc, OMAP_USBHOST_UHH_SYSCONFIG);
+	if (isc->ehci_rev == OMAP_EHCI_REV1) {
+		reg &= ~(UHH_SYSCONFIG_SIDLEMODE_MASK |
+		         UHH_SYSCONFIG_MIDLEMODE_MASK);
+		reg |= (UHH_SYSCONFIG_ENAWAKEUP |
+		        UHH_SYSCONFIG_AUTOIDLE |
+		        UHH_SYSCONFIG_CLOCKACTIVITY |
+		        UHH_SYSCONFIG_SIDLEMODE_SMARTIDLE |
+		        UHH_SYSCONFIG_MIDLEMODE_SMARTSTANDBY);
+	} else if (isc->ehci_rev == OMAP_EHCI_REV2) {
+		reg &= ~UHH_SYSCONFIG_IDLEMODE_MASK;
+		reg |=  UHH_SYSCONFIG_IDLEMODE_NOIDLE;
+		reg &= ~UHH_SYSCONFIG_STANDBYMODE_MASK;
+		reg |=  UHH_SYSCONFIG_STANDBYMODE_NOSTDBY;
+	}
+	omap_uhh_write_4(isc, OMAP_USBHOST_UHH_SYSCONFIG, reg);
+	device_printf(isc->sc_dev, "OMAP_UHH_SYSCONFIG: 0x%08x\n", reg);
+
+	reg = omap_uhh_read_4(isc, OMAP_USBHOST_UHH_HOSTCONFIG);
+	
+	/* Setup ULPI bypass and burst configurations */
+	reg |= (UHH_HOSTCONFIG_ENA_INCR4 |
+			UHH_HOSTCONFIG_ENA_INCR8 |
+			UHH_HOSTCONFIG_ENA_INCR16);
+	reg &= ~UHH_HOSTCONFIG_ENA_INCR_ALIGN;
+	
+	if (isc->ehci_rev == OMAP_EHCI_REV1) {
+		if (isc->port_mode[0] == EHCI_HCD_OMAP_MODE_UNKNOWN)
+			reg &= ~UHH_HOSTCONFIG_P1_CONNECT_STATUS;
+		if (isc->port_mode[1] == EHCI_HCD_OMAP_MODE_UNKNOWN)
+			reg &= ~UHH_HOSTCONFIG_P2_CONNECT_STATUS;
+		if (isc->port_mode[2] == EHCI_HCD_OMAP_MODE_UNKNOWN)
+			reg &= ~UHH_HOSTCONFIG_P3_CONNECT_STATUS;
+	
+		/* Bypass the TLL module for PHY mode operation */
+		if ((isc->port_mode[0] == EHCI_HCD_OMAP_MODE_PHY) ||
+		    (isc->port_mode[1] == EHCI_HCD_OMAP_MODE_PHY) ||
+		    (isc->port_mode[2] == EHCI_HCD_OMAP_MODE_PHY))
+			reg &= ~UHH_HOSTCONFIG_P1_ULPI_BYPASS;
+		else
+			reg |= UHH_HOSTCONFIG_P1_ULPI_BYPASS;
+			
+	} else if (isc->ehci_rev == OMAP_EHCI_REV2) {
+		reg |=  UHH_HOSTCONFIG_APP_START_CLK;
+		
+		/* Clear port mode fields for PHY mode*/
+		reg &= ~UHH_HOSTCONFIG_P1_MODE_MASK;
+		reg &= ~UHH_HOSTCONFIG_P2_MODE_MASK;
+
+		if (isc->port_mode[0] == EHCI_HCD_OMAP_MODE_TLL)
+			reg |= UHH_HOSTCONFIG_P1_MODE_UTMI_PHY;
+		else if (isc->port_mode[0] == EHCI_HCD_OMAP_MODE_HSIC)
+			reg |= UHH_HOSTCONFIG_P1_MODE_HSIC;
+
+		if (isc->port_mode[1] == EHCI_HCD_OMAP_MODE_TLL)
+			reg |= UHH_HOSTCONFIG_P2_MODE_UTMI_PHY;
+		else if (isc->port_mode[1] == EHCI_HCD_OMAP_MODE_HSIC)
+			reg |= UHH_HOSTCONFIG_P2_MODE_HSIC;
+	}
+
+	omap_uhh_write_4(isc, OMAP_USBHOST_UHH_HOSTCONFIG, reg);
+	device_printf(isc->sc_dev, "UHH setup done, uhh_hostconfig=0x%08x\n", reg);
+	
+
+	/* I found the code and comments in the Linux EHCI driver - thanks guys :)
+	 *
+	 * "An undocumented "feature" in the OMAP3 EHCI controller, causes suspended
+	 * ports to be taken out of suspend when the USBCMD.Run/Stop bit is cleared
+	 * (for example when we do ehci_bus_suspend). This breaks suspend-resume if
+	 * the root-hub is allowed to suspend. Writing 1 to this undocumented
+	 * register bit disables this feature and restores normal behavior."
+	 */
+#if 0
+	omap_ehci_write_4(isc, OMAP_USBHOST_INSNREG04,
+	                 OMAP_USBHOST_INSNREG04_DISABLE_UNSUSPEND);
+#endif
+
+	/* If any of the ports are configured in TLL mode, enable them */
+	if ((isc->port_mode[0] == EHCI_HCD_OMAP_MODE_TLL) ||
+		(isc->port_mode[1] == EHCI_HCD_OMAP_MODE_TLL) ||
+		(isc->port_mode[2] == EHCI_HCD_OMAP_MODE_TLL)) {
+		
+		if (isc->port_mode[0] == EHCI_HCD_OMAP_MODE_TLL)
+			tll_ch_mask |= 0x1;
+		if (isc->port_mode[1] == EHCI_HCD_OMAP_MODE_TLL)
+			tll_ch_mask |= 0x2;
+		if (isc->port_mode[2] == EHCI_HCD_OMAP_MODE_TLL)
+			tll_ch_mask |= 0x4;
+		
+		/* Enable UTMI mode for required TLL channels */
+		omap_ehci_utmi_init(isc, tll_ch_mask);
+	}
+
+
+	/* Release the PHY reset signal now we have configured everything */
+	if (reset_performed) {
+
+		/* Delay for 10ms */
+		DELAY(10000);
+		
+		for (i = 0; i < 3; i++) {
+			/* Release reset */
+	
+			if (isc->phy_reset[i] && (isc->reset_gpio_pin[i] != -1) 
+			    && (isc->sc_gpio_dev != NULL)) {
+				GPIO_PIN_SET(isc->sc_gpio_dev, 
+					isc->reset_gpio_pin[i], GPIO_PIN_HIGH);
+			}
+		}
+	}
+
+	/* Set the interrupt threshold control, it controls the maximum rate at
+	 * which the host controller issues interrupts.  We set it to 1 microframe
+	 * at startup - the default is 8 mircoframes (equates to 1ms).
+	 */
+	reg = omap_ehci_read_4(isc, OMAP_USBHOST_USBCMD);
+	reg &= 0xff00ffff;
+	reg |= (1 << 16);
+	omap_ehci_write_4(isc, OMAP_USBHOST_USBCMD, reg);
+
+	/* Soft reset the PHY using PHY reset command over ULPI */
+	if (isc->port_mode[0] == EHCI_HCD_OMAP_MODE_PHY)
+		omap_ehci_soft_phy_reset(isc, 0);
+	if (isc->port_mode[1] == EHCI_HCD_OMAP_MODE_PHY)
+		omap_ehci_soft_phy_reset(isc, 1);	
+
+	return(0);
+
+err_sys_status:
+	
+	/* Disable the TLL clocks */
+	ti_prcm_clk_disable(USBTLL_CLK);
+	
+	/* Disable Clocks for USBHOST */
+	ti_prcm_clk_disable(USBHSHOST_CLK);
+
+	return(ret);
+}
+
+
+/**
+ *	omap_ehci_fini - shutdown the EHCI controller
+ *	@isc: omap ehci device context
+ *
+ *	
+ *
+ *	LOCKING:
+ *	none
+ *
+ *	RETURNS:
+ *	0 on success, a negative error code on failure.
+ */
+static void
+omap_ehci_fini(struct omap_ehci_softc *isc)
+{
+	unsigned long timeout;
+	
+	device_printf(isc->sc_dev, "Stopping TI EHCI USB Controller\n");
+	
+	/* Set the timeout */
+	if (hz < 10)
+		timeout = 1;
+	else
+		timeout = (100 * hz) / 1000;
+
+	/* Reset the UHH, OHCI and EHCI modules */
+	omap_uhh_write_4(isc, OMAP_USBHOST_UHH_SYSCONFIG, 0x0002);
+	while ((omap_uhh_read_4(isc, OMAP_USBHOST_UHH_SYSSTATUS) & 0x07) == 0x00) {
+		/* Sleep for a tick */
+		pause("USBRESET", 1);
+		
+		if (timeout-- == 0) {
+			device_printf(isc->sc_dev, "operation timed out\n");
+			break;
+		}
+	}
+	
+
+	/* Set the timeout */
+	if (hz < 10)
+		timeout = 1;
+	else
+		timeout = (100 * hz) / 1000;
+
+	/* Reset the TLL module */
+	omap_tll_write_4(isc, OMAP_USBTLL_SYSCONFIG, 0x0002);
+	while ((omap_tll_read_4(isc, OMAP_USBTLL_SYSSTATUS) & (0x01)) == 0x00) {
+		/* Sleep for a tick */
+		pause("USBRESET", 1);
+		
+		if (timeout-- == 0) {
+			device_printf(isc->sc_dev, "operation timed out\n");
+			break;
+		}
+	}
+
+
+	/* Disable functional and interface clocks for the TLL and HOST modules */
+	ti_prcm_clk_disable(USBTLL_CLK);
+	ti_prcm_clk_disable(USBHSHOST_CLK);
+
+	device_printf(isc->sc_dev, "Clock to USB host has been disabled\n");
+	
+}
+
+
+
+/**
+ *	omap_ehci_suspend - suspends the bus
+ *	@dev: omap ehci device
+ *	
+ *	Effectively boilerplate EHCI suspend code.
+ *
+ *	TODO: There is a lot more we could do here - i.e. force the controller into
+ *	idle mode and disable all the clocks for start.
+ *
+ *	LOCKING:
+ *	none
+ *
+ *	RETURNS:
+ *	0 on success or a positive error code
+ */
+static int
+omap_ehci_suspend(device_t dev)
+{
+	ehci_softc_t *sc = device_get_softc(dev);
+	int err;
+	
+	sc = sc;
+	err = bus_generic_suspend(dev);
+	if (err)
+		return (err);
+	return (0);
+}
+
+
+/**
+ *	omap_ehci_resume - resumes a suspended bus
+ *	@dev: omap ehci device
+ *	
+ *	Effectively boilerplate EHCI resume code.
+ *
+ *	LOCKING:
+ *	none
+ *
+ *	RETURNS:
+ *	0 on success or a positive error code on failure
+ */
+static int
+omap_ehci_resume(device_t dev)
+{
+	ehci_softc_t *sc = device_get_softc(dev);
+	sc = sc;
+	
+	bus_generic_resume(dev);
+	
+	return (0);
+}
+
+
+/**
+ *	omap_ehci_shutdown - starts the given command
+ *	@dev: 
+ *	
+ *	Effectively boilerplate EHCI shutdown code.
+ *
+ *	LOCKING:
+ *	none.
+ *
+ *	RETURNS:
+ *	0 on success or a positive error code on failure
+ */
+static int
+omap_ehci_shutdown(device_t dev)
+{
+	ehci_softc_t *sc = device_get_softc(dev);
+	int err;
+	
+	sc = sc;
+	err = bus_generic_shutdown(dev);
+	if (err)
+		return (err);
+	
+	return (0);
+}
+
+
+/**
+ *	omap_ehci_probe - starts the given command
+ *	@dev: 
+ *	
+ *	Effectively boilerplate EHCI resume code.
+ *
+ *	LOCKING:
+ *	Caller should be holding the OMAP3_MMC lock.
+ *
+ *	RETURNS:
+ *	EH_HANDLED or EH_NOT_HANDLED
+ */
+static int
+omap_ehci_probe(device_t dev)
+{
+	if (!ofw_bus_is_compatible(dev, "ti,usb-ehci"))
+		return (ENXIO);
+
+	device_set_desc(dev, OMAP_EHCI_HC_DEVSTR);
+	
+	return (BUS_PROBE_DEFAULT);
+}
+
+/**
+ *	omap_ehci_attach - driver entry point, sets up the ECHI controller/driver
+ *	@dev: the new device handle
+ *	
+ *	Sets up bus spaces, interrupt handles, etc for the EHCI controller.  It also
+ *	parses the resource hints and calls omap_ehci_init() to initialise the
+ *	H/W.
+ *
+ *	LOCKING:
+ *	none
+ *
+ *	RETURNS:
+ *	0 on success or a positive error code on failure.
+ */
+static int
+omap_ehci_attach(device_t dev)
+{
+	struct omap_ehci_softc *isc = device_get_softc(dev);
+	phandle_t node;
+	/* 3 ports with 3 cells per port */
+	pcell_t phyconf[3 * 3];
+	pcell_t *phyconf_ptr;
+	ehci_softc_t *sc = &isc->base;
+	int err;
+	int rid;
+	int len, tuple_size;
+	int i;
+
+	/* initialise some bus fields */
+	sc->sc_bus.parent = dev;
+	sc->sc_bus.devices = sc->sc_devices;
+	sc->sc_bus.devices_max = EHCI_MAX_DEVICES;
+	
+	/* save the device */
+	isc->sc_dev = dev;
+	
+	/* get all DMA memory */
+	if (usb_bus_mem_alloc_all(&sc->sc_bus, USB_GET_DMA_TAG(dev),
+	                          &ehci_iterate_hw_softc)) {
+		return (ENOMEM);
+	}
+	
+	/* When the EHCI driver is added to the tree it is expected that 3
+	 * memory resources and 1 interrupt resource is assigned. The memory
+	 * resources should be:
+	 *   0 => EHCI register range
+	 *   1 => UHH register range
+	 *   2 => TLL register range
+	 *
+	 * The interrupt resource is just the single interupt for the controller.
+	 */
+
+	/* Allocate resource for the EHCI register set */
+	rid = 0;
+	sc->sc_io_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, RF_ACTIVE);
+	if (!sc->sc_io_res) {
+		device_printf(dev, "Error: Could not map EHCI memory\n");
+		goto error;
+	}
+	/* Request an interrupt resource */
+	rid = 0;
+	sc->sc_irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, RF_ACTIVE);
+	if (sc->sc_irq_res == NULL) {
+		device_printf(dev, "Error: could not allocate irq\n");
+		goto error;
+	}
+
+	/* Allocate resource for the UHH register set */
+	rid = 1;
+	isc->uhh_mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, RF_ACTIVE);
+	if (!isc->uhh_mem_res) {
+		device_printf(dev, "Error: Could not map UHH memory\n");
+		goto error;
+	}
+	/* Allocate resource for the TLL register set */
+	rid = 2;
+	isc->tll_mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, RF_ACTIVE);
+	if (!isc->tll_mem_res) {
+		device_printf(dev, "Error: Could not map TLL memory\n");
+		goto error;
+	}
+	
+	/* Add this device as a child of the USBus device */
+	sc->sc_bus.bdev = device_add_child(dev, "usbus", -1);
+	if (!sc->sc_bus.bdev) {
+		device_printf(dev, "Error: could not add USB device\n");
+		goto error;
+	}
+
+	device_set_ivars(sc->sc_bus.bdev, &sc->sc_bus);
+	device_set_desc(sc->sc_bus.bdev, OMAP_EHCI_HC_DEVSTR);
+	
+	/* Set the vendor name */
+	sprintf(sc->sc_vendor, "Texas Instruments");
+	
+	/* Get the GPIO device, we may need this if the driver needs to toggle
+	 * some pins for external PHY resets.
+	 */
+	isc->sc_gpio_dev = devclass_get_device(devclass_find("gpio"), 0);
+	if (isc->sc_gpio_dev == NULL) {
+		device_printf(dev, "Error: failed to get the GPIO device\n");
+		goto error;
+	}
+	
+	/* Set the defaults for the hints */
+	for (i = 0; i < 3; i++) {
+		isc->phy_reset[i] = 0;
+		isc->port_mode[i] = EHCI_HCD_OMAP_MODE_UNKNOWN;
+		isc->reset_gpio_pin[i] = -1;
+	}
+
+	tuple_size = sizeof(pcell_t) * 3;
+	node = ofw_bus_get_node(dev);
+	len = OF_getprop(node, "phy-config", phyconf, sizeof(phyconf));
+	if (len > 0) {
+		if (len % tuple_size)
+			goto error;
+		if ((len / tuple_size) != 3)
+			goto error;
+
+		phyconf_ptr = phyconf;
+		for (i = 0; i < 3; i++) {
+			isc->port_mode[i] = fdt32_to_cpu(*phyconf_ptr);
+			isc->phy_reset[i] = fdt32_to_cpu(*(phyconf_ptr + 1));
+			isc->reset_gpio_pin[i] = fdt32_to_cpu(*(phyconf_ptr + 2));
+
+			phyconf_ptr += 3;
+		}
+	}
+	
+	/* Initialise the ECHI registers */
+	err = omap_ehci_init(isc);
+	if (err) {
+		device_printf(dev, "Error: could not setup OMAP EHCI, %d\n", err);
+		goto error;
+	}
+		
+
+	/* Set the tag and size of the register set in the EHCI context */
+	sc->sc_io_hdl = rman_get_bushandle(sc->sc_io_res);
+	sc->sc_io_tag = rman_get_bustag(sc->sc_io_res);
+	sc->sc_io_size = rman_get_size(sc->sc_io_res);
+
+
+	/* Setup the interrupt */
+	err = bus_setup_intr(dev, sc->sc_irq_res, INTR_TYPE_BIO | INTR_MPSAFE,
+						 NULL, (driver_intr_t *)ehci_interrupt, sc, &sc->sc_intr_hdl);
+	if (err) {
+		device_printf(dev, "Error: could not setup irq, %d\n", err);
+		sc->sc_intr_hdl = NULL;
+		goto error;
+	}
+	
+	
+	/* Finally we are ready to kick off the ECHI host controller */
+	err = ehci_init(sc);
+	if (err == 0) {
+		err = device_probe_and_attach(sc->sc_bus.bdev);
+	}
+	if (err) {
+		device_printf(dev, "Error: USB init failed err=%d\n", err);
+		goto error;
+	}
+	
+	return (0);
+	
+error:
+	omap_ehci_detach(dev);
+	return (ENXIO);
+}
+
+/**
+ *	omap_ehci_detach - detach the device and cleanup the driver
+ *	@dev: device handle
+ *	
+ *	Clean-up routine where everything initialised in omap_ehci_attach is
+ *	freed and cleaned up.  This function calls omap_ehci_fini() to shutdown
+ *	the on-chip module.
+ *
+ *	LOCKING:
+ *	none
+ *
+ *	RETURNS:
+ *	Always returns 0 (success).
+ */
+static int
+omap_ehci_detach(device_t dev)
+{
+	struct omap_ehci_softc *isc = device_get_softc(dev);
+	ehci_softc_t *sc = &isc->base;
+	device_t bdev;
+	int err;
+	
+	if (sc->sc_bus.bdev) {
+		bdev = sc->sc_bus.bdev;
+		device_detach(bdev);
+		device_delete_child(dev, bdev);
+	}
+
+	/* during module unload there are lots of children leftover */
+	device_delete_children(dev);
+	
+	/*
+	 * disable interrupts that might have been switched on in ehci_init
+	 */
+	if (sc->sc_io_res) {
+		EWRITE4(sc, EHCI_USBINTR, 0);
+	}
+	
+	if (sc->sc_irq_res && sc->sc_intr_hdl) {
+		/*
+		 * only call ehci_detach() after ehci_init()
+		 */
+		ehci_detach(sc);
+		
+		err = bus_teardown_intr(dev, sc->sc_irq_res, sc->sc_intr_hdl);
+		if (err)
+			device_printf(dev, "Error: could not tear down irq, %d\n", err);
+		sc->sc_intr_hdl = NULL;
+	}
+	
+	/* Free the resources stored in the base EHCI handler */
+	if (sc->sc_irq_res) {
+		bus_release_resource(dev, SYS_RES_IRQ, 0, sc->sc_irq_res);
+		sc->sc_irq_res = NULL;
+	}
+	if (sc->sc_io_res) {
+		bus_release_resource(dev, SYS_RES_MEMORY, 0, sc->sc_io_res);
+		sc->sc_io_res = NULL;
+	}
+
+	/* Release the other register set memory maps */
+	if (isc->tll_mem_res) {
+		bus_release_resource(dev, SYS_RES_MEMORY, 0, isc->tll_mem_res);
+		isc->tll_mem_res = NULL;
+	}
+	if (isc->uhh_mem_res) {
+		bus_release_resource(dev, SYS_RES_MEMORY, 0, isc->uhh_mem_res);
+		isc->uhh_mem_res = NULL;
+	}
+
+	usb_bus_mem_free_all(&sc->sc_bus, &ehci_iterate_hw_softc);
+	
+	omap_ehci_fini(isc);
+	
+	return (0);
+}
+
+static device_method_t ehci_methods[] = {
+	/* Device interface */
+	DEVMETHOD(device_probe, omap_ehci_probe),
+	DEVMETHOD(device_attach, omap_ehci_attach),
+	DEVMETHOD(device_detach, omap_ehci_detach),
+	DEVMETHOD(device_suspend, omap_ehci_suspend),
+	DEVMETHOD(device_resume, omap_ehci_resume),
+	DEVMETHOD(device_shutdown, omap_ehci_shutdown),
+	
+	/* Bus interface */
+	DEVMETHOD(bus_print_child, bus_generic_print_child),
+	
+	{0, 0}
+};
+
+static driver_t ehci_driver = {
+	"ehci",
+	ehci_methods,
+	sizeof(struct omap_ehci_softc),
+};
+
+static devclass_t ehci_devclass;
+
+DRIVER_MODULE(ehci, simplebus, ehci_driver, ehci_devclass, 0, 0);
diff -r 7fffa673adcd -r a301a330526b head/sys/arm/ti/usb/omap_usb.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/head/sys/arm/ti/usb/omap_usb.h	Wed Aug 15 11:16:36 2012 +0300
@@ -0,0 +1,264 @@
+/*
+ * Copyright (c) 2010
+ *	Ben Gray <ben.r.gray at 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.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by Ben Gray.
+ * 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 BEN GRAY ``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 BEN GRAY 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: head/sys/arm/ti/usb/omap_usb.h 239281 2012-08-15 06:31:32Z gonzo $
+ */
+
+#ifndef _OMAP_USB_H_
+#define	_OMAP_USB_H_
+
+/*
+ * USB TTL Module
+ */
+#define	OMAP_USBTLL_REVISION                        0x0000
+#define	OMAP_USBTLL_SYSCONFIG                       0x0010
+#define	OMAP_USBTLL_SYSSTATUS                       0x0014
+#define	OMAP_USBTLL_IRQSTATUS                       0x0018
+#define	OMAP_USBTLL_IRQENABLE                       0x001C
+#define	OMAP_USBTLL_TLL_SHARED_CONF                 0x0030
+#define	OMAP_USBTLL_TLL_CHANNEL_CONF(i)             (0x0040 + (0x04 * (i)))
+#define	OMAP_USBTLL_SAR_CNTX(i)                     (0x0400 + (0x04 * (i)))
+#define	OMAP_USBTLL_ULPI_VENDOR_ID_LO(i)            (0x0800 + (0x100 * (i)))
+#define	OMAP_USBTLL_ULPI_VENDOR_ID_HI(i)            (0x0801 + (0x100 * (i)))
+#define	OMAP_USBTLL_ULPI_PRODUCT_ID_LO(i)           (0x0802 + (0x100 * (i)))
+#define	OMAP_USBTLL_ULPI_PRODUCT_ID_HI(i)           (0x0803 + (0x100 * (i)))
+#define	OMAP_USBTLL_ULPI_FUNCTION_CTRL(i)           (0x0804 + (0x100 * (i)))
+#define	OMAP_USBTLL_ULPI_FUNCTION_CTRL_SET(i)       (0x0805 + (0x100 * (i)))
+#define	OMAP_USBTLL_ULPI_FUNCTION_CTRL_CLR(i)       (0x0806 + (0x100 * (i)))
+#define	OMAP_USBTLL_ULPI_INTERFACE_CTRL(i)          (0x0807 + (0x100 * (i)))
+#define	OMAP_USBTLL_ULPI_INTERFACE_CTRL_SET(i)      (0x0808 + (0x100 * (i)))
+#define	OMAP_USBTLL_ULPI_INTERFACE_CTRL_CLR(i)      (0x0809 + (0x100 * (i)))
+#define	OMAP_USBTLL_ULPI_OTG_CTRL(i)                (0x080A + (0x100 * (i)))
+#define	OMAP_USBTLL_ULPI_OTG_CTRL_SET(i)            (0x080B + (0x100 * (i)))
+#define	OMAP_USBTLL_ULPI_OTG_CTRL_CLR(i)            (0x080C + (0x100 * (i)))
+#define	OMAP_USBTLL_ULPI_USB_INT_EN_RISE(i)         (0x080D + (0x100 * (i)))
+#define	OMAP_USBTLL_ULPI_USB_INT_EN_RISE_SET(i)     (0x080E + (0x100 * (i)))
+#define	OMAP_USBTLL_ULPI_USB_INT_EN_RISE_CLR(i)     (0x080F + (0x100 * (i)))
+#define	OMAP_USBTLL_ULPI_USB_INT_EN_FALL(i)         (0x0810 + (0x100 * (i)))
+#define	OMAP_USBTLL_ULPI_USB_INT_EN_FALL_SET(i)     (0x0811 + (0x100 * (i)))
+#define	OMAP_USBTLL_ULPI_USB_INT_EN_FALL_CLR(i)     (0x0812 + (0x100 * (i)))
+#define	OMAP_USBTLL_ULPI_USB_INT_STATUS(i)          (0x0813 + (0x100 * (i)))
+#define	OMAP_USBTLL_ULPI_USB_INT_LATCH(i)           (0x0814 + (0x100 * (i)))
+#define	OMAP_USBTLL_ULPI_DEBUG(i)                   (0x0815 + (0x100 * (i)))
+#define	OMAP_USBTLL_ULPI_SCRATCH_REGISTER(i)        (0x0816 + (0x100 * (i)))
+#define	OMAP_USBTLL_ULPI_SCRATCH_REGISTER_SET(i)    (0x0817 + (0x100 * (i)))
+#define	OMAP_USBTLL_ULPI_SCRATCH_REGISTER_CLR(i)    (0x0818 + (0x100 * (i)))
+#define	OMAP_USBTLL_ULPI_EXTENDED_SET_ACCESS(i)     (0x082F + (0x100 * (i)))
+#define	OMAP_USBTLL_ULPI_UTMI_VCONTROL_EN(i)        (0x0830 + (0x100 * (i)))
+#define	OMAP_USBTLL_ULPI_UTMI_VCONTROL_EN_SET(i)    (0x0831 + (0x100 * (i)))
+#define	OMAP_USBTLL_ULPI_UTMI_VCONTROL_EN_CLR(i)    (0x0832 + (0x100 * (i)))
+#define	OMAP_USBTLL_ULPI_UTMI_VCONTROL_STATUS(i)    (0x0833 + (0x100 * (i)))
+#define	OMAP_USBTLL_ULPI_UTMI_VCONTROL_LATCH(i)     (0x0834 + (0x100 * (i)))
+#define	OMAP_USBTLL_ULPI_UTMI_VSTATUS(i)            (0x0835 + (0x100 * (i)))
+#define	OMAP_USBTLL_ULPI_UTMI_VSTATUS_SET(i)        (0x0836 + (0x100 * (i)))
+#define	OMAP_USBTLL_ULPI_UTMI_VSTATUS_CLR(i)        (0x0837 + (0x100 * (i)))
+#define	OMAP_USBTLL_ULPI_USB_INT_LATCH_NOCLR(i)     (0x0838 + (0x100 * (i)))
+#define	OMAP_USBTLL_ULPI_VENDOR_INT_EN(i)           (0x083B + (0x100 * (i)))
+#define	OMAP_USBTLL_ULPI_VENDOR_INT_EN_SET(i)       (0x083C + (0x100 * (i)))
+#define	OMAP_USBTLL_ULPI_VENDOR_INT_EN_CLR(i)       (0x083D + (0x100 * (i)))
+#define	OMAP_USBTLL_ULPI_VENDOR_INT_STATUS(i)       (0x083E + (0x100 * (i)))
+#define	OMAP_USBTLL_ULPI_VENDOR_INT_LATCH(i)        (0x083F + (0x100 * (i)))
+
+
+/*
+ * USB Host Module
+ */
+
+/* UHH */
+#define	OMAP_USBHOST_UHH_REVISION                   0x0000
+#define	OMAP_USBHOST_UHH_SYSCONFIG                  0x0010
+#define	OMAP_USBHOST_UHH_SYSSTATUS                  0x0014
+#define	OMAP_USBHOST_UHH_HOSTCONFIG                 0x0040
+#define	OMAP_USBHOST_UHH_DEBUG_CSR                  0x0044
+
+/* EHCI */
+#define	OMAP_USBHOST_HCCAPBASE                      0x0000
+#define	OMAP_USBHOST_HCSPARAMS                      0x0004
+#define	OMAP_USBHOST_HCCPARAMS                      0x0008
+#define	OMAP_USBHOST_USBCMD                         0x0010
+#define	OMAP_USBHOST_USBSTS                         0x0014
+#define	OMAP_USBHOST_USBINTR                        0x0018
+#define	OMAP_USBHOST_FRINDEX                        0x001C
+#define	OMAP_USBHOST_CTRLDSSEGMENT                  0x0020
+#define	OMAP_USBHOST_PERIODICLISTBASE               0x0024
+#define	OMAP_USBHOST_ASYNCLISTADDR                  0x0028
+#define	OMAP_USBHOST_CONFIGFLAG                     0x0050
+#define	OMAP_USBHOST_PORTSC(i)                      (0x0054 + (0x04 * (i)))
+#define	OMAP_USBHOST_INSNREG00                      0x0090
+#define	OMAP_USBHOST_INSNREG01                      0x0094
+#define	OMAP_USBHOST_INSNREG02                      0x0098
+#define	OMAP_USBHOST_INSNREG03                      0x009C
+#define	OMAP_USBHOST_INSNREG04                      0x00A0
+#define	OMAP_USBHOST_INSNREG05_UTMI                 0x00A4
+#define	OMAP_USBHOST_INSNREG05_ULPI                 0x00A4
+#define	OMAP_USBHOST_INSNREG06                      0x00A8
+#define	OMAP_USBHOST_INSNREG07                      0x00AC
+#define	OMAP_USBHOST_INSNREG08                      0x00B0
+
+#define OMAP_USBHOST_INSNREG04_DISABLE_UNSUSPEND   (1 << 5)
+
+#define OMAP_USBHOST_INSNREG05_ULPI_CONTROL_SHIFT   31
+#define OMAP_USBHOST_INSNREG05_ULPI_PORTSEL_SHIFT   24
+#define OMAP_USBHOST_INSNREG05_ULPI_OPSEL_SHIFT     22
+#define OMAP_USBHOST_INSNREG05_ULPI_REGADD_SHIFT    16
+#define OMAP_USBHOST_INSNREG05_ULPI_EXTREGADD_SHIFT 8
+#define OMAP_USBHOST_INSNREG05_ULPI_WRDATA_SHIFT    0
+
+
+
+
+
+/* TLL Register Set */
+#define	TLL_SYSCONFIG_CACTIVITY                 (1UL << 8)
+#define	TLL_SYSCONFIG_SIDLE_SMART_IDLE          (2UL << 3)
+#define	TLL_SYSCONFIG_SIDLE_NO_IDLE             (1UL << 3)
+#define	TLL_SYSCONFIG_SIDLE_FORCED_IDLE         (0UL << 3)
+#define	TLL_SYSCONFIG_ENAWAKEUP                 (1UL << 2)
+#define	TLL_SYSCONFIG_SOFTRESET                 (1UL << 1)
+#define	TLL_SYSCONFIG_AUTOIDLE                  (1UL << 0)
+
+#define	TLL_SYSSTATUS_RESETDONE                 (1UL << 0)
+
+#define TLL_SHARED_CONF_USB_90D_DDR_EN          (1UL << 6)
+#define TLL_SHARED_CONF_USB_180D_SDR_EN         (1UL << 5)
+#define TLL_SHARED_CONF_USB_DIVRATIO_MASK       (7UL << 2)
+#define TLL_SHARED_CONF_USB_DIVRATIO_128        (7UL << 2)
+#define TLL_SHARED_CONF_USB_DIVRATIO_64         (6UL << 2)
+#define TLL_SHARED_CONF_USB_DIVRATIO_32         (5UL << 2)
+#define TLL_SHARED_CONF_USB_DIVRATIO_16         (4UL << 2)
+#define TLL_SHARED_CONF_USB_DIVRATIO_8          (3UL << 2)
+#define TLL_SHARED_CONF_USB_DIVRATIO_4          (2UL << 2)
+#define TLL_SHARED_CONF_USB_DIVRATIO_2          (1UL << 2)
+#define TLL_SHARED_CONF_USB_DIVRATIO_1          (0UL << 2)
+#define TLL_SHARED_CONF_FCLK_REQ                (1UL << 1)
+#define TLL_SHARED_CONF_FCLK_IS_ON              (1UL << 0)
+
+#define TLL_CHANNEL_CONF_DRVVBUS                (1UL << 16)
+#define TLL_CHANNEL_CONF_CHRGVBUS               (1UL << 15)
+#define TLL_CHANNEL_CONF_ULPINOBITSTUFF         (1UL << 11)
+#define TLL_CHANNEL_CONF_ULPIAUTOIDLE           (1UL << 10)
+#define TLL_CHANNEL_CONF_UTMIAUTOIDLE           (1UL << 9)
+#define TLL_CHANNEL_CONF_ULPIDDRMODE            (1UL << 8)
+#define TLL_CHANNEL_CONF_ULPIOUTCLKMODE         (1UL << 7)
+#define TLL_CHANNEL_CONF_TLLFULLSPEED           (1UL << 6)
+#define TLL_CHANNEL_CONF_TLLCONNECT             (1UL << 5)
+#define TLL_CHANNEL_CONF_TLLATTACH              (1UL << 4)
+#define TLL_CHANNEL_CONF_UTMIISADEV             (1UL << 3)
+#define TLL_CHANNEL_CONF_CHANEN                 (1UL << 0)
+
+
+/* UHH Register Set */
+#define UHH_SYSCONFIG_MIDLEMODE_MASK            (3UL << 12)
+#define UHH_SYSCONFIG_MIDLEMODE_SMARTSTANDBY    (2UL << 12)
+#define UHH_SYSCONFIG_MIDLEMODE_NOSTANDBY       (1UL << 12)
+#define UHH_SYSCONFIG_MIDLEMODE_FORCESTANDBY    (0UL << 12)
+#define UHH_SYSCONFIG_CLOCKACTIVITY             (1UL << 8)
+#define UHH_SYSCONFIG_SIDLEMODE_MASK            (3UL << 3)
+#define UHH_SYSCONFIG_SIDLEMODE_SMARTIDLE       (2UL << 3)
+#define UHH_SYSCONFIG_SIDLEMODE_NOIDLE          (1UL << 3)
+#define UHH_SYSCONFIG_SIDLEMODE_FORCEIDLE       (0UL << 3)
+#define UHH_SYSCONFIG_ENAWAKEUP                 (1UL << 2)
+#define UHH_SYSCONFIG_SOFTRESET                 (1UL << 1)
+#define UHH_SYSCONFIG_AUTOIDLE                  (1UL << 0)
+
+#define UHH_HOSTCONFIG_APP_START_CLK            (1UL << 31)
+#define UHH_HOSTCONFIG_P3_CONNECT_STATUS        (1UL << 10)
+#define UHH_HOSTCONFIG_P2_CONNECT_STATUS        (1UL << 9)
+#define UHH_HOSTCONFIG_P1_CONNECT_STATUS        (1UL << 8)
+#define UHH_HOSTCONFIG_ENA_INCR_ALIGN           (1UL << 5)
+#define UHH_HOSTCONFIG_ENA_INCR16               (1UL << 4)
+#define UHH_HOSTCONFIG_ENA_INCR8                (1UL << 3)
+#define UHH_HOSTCONFIG_ENA_INCR4                (1UL << 2)
+#define UHH_HOSTCONFIG_AUTOPPD_ON_OVERCUR_EN    (1UL << 1)
+#define UHH_HOSTCONFIG_P1_ULPI_BYPASS           (1UL << 0)
+
+/* The following are on rev2 (OMAP44xx) of the EHCI only */ 
+#define UHH_SYSCONFIG_IDLEMODE_MASK             (3UL << 2)
+#define UHH_SYSCONFIG_IDLEMODE_NOIDLE           (1UL << 2)
+#define UHH_SYSCONFIG_STANDBYMODE_MASK          (3UL << 4)
+#define UHH_SYSCONFIG_STANDBYMODE_NOSTDBY       (1UL << 4)
+
+#define UHH_HOSTCONFIG_P1_MODE_MASK             (3UL << 16)
+#define UHH_HOSTCONFIG_P1_MODE_ULPI_PHY         (0UL << 16)
+#define UHH_HOSTCONFIG_P1_MODE_UTMI_PHY         (1UL << 16)
+#define UHH_HOSTCONFIG_P1_MODE_HSIC             (3UL << 16)
+#define UHH_HOSTCONFIG_P2_MODE_MASK             (3UL << 18)
+#define UHH_HOSTCONFIG_P2_MODE_ULPI_PHY         (0UL << 18)
+#define UHH_HOSTCONFIG_P2_MODE_UTMI_PHY         (1UL << 18)
+#define UHH_HOSTCONFIG_P2_MODE_HSIC             (3UL << 18)
+
+#define ULPI_FUNC_CTRL_RESET                    (1 << 5)
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ * Macros for Set and Clear
+ * See ULPI 1.1 specification to find the registers with Set and Clear offsets
+ */
+#define ULPI_SET(a)                             (a + 1)
+#define ULPI_CLR(a)                             (a + 2)
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ * Register Map
+ */
+#define ULPI_VENDOR_ID_LOW                      0x00
+#define ULPI_VENDOR_ID_HIGH                     0x01
+#define ULPI_PRODUCT_ID_LOW                     0x02
+#define ULPI_PRODUCT_ID_HIGH                    0x03
+#define ULPI_FUNC_CTRL                          0x04
+#define ULPI_IFC_CTRL                           0x07
+#define ULPI_OTG_CTRL                           0x0a
+#define ULPI_USB_INT_EN_RISE                    0x0d
+#define ULPI_USB_INT_EN_FALL                    0x10
+#define ULPI_USB_INT_STS                        0x13
+#define ULPI_USB_INT_LATCH                      0x14
+#define ULPI_DEBUG                              0x15
+#define ULPI_SCRATCH                            0x16
+
+/* 
+ * Values of UHH_REVISION - Note: these are not given in the TRM but taken
+ * from the linux OMAP EHCI driver (thanks guys).  It has been verified on
+ * a Panda and Beagle board.
+ */
+#define OMAP_EHCI_REV1  0x00000010      /* OMAP3 */
+#define OMAP_EHCI_REV2  0x50700100      /* OMAP4 */
+
+#define EHCI_VENDORID_OMAP3     0x42fa05
+#define OMAP_EHCI_HC_DEVSTR    "TI OMAP USB 2.0 controller"
+
+#define EHCI_HCD_OMAP_MODE_UNKNOWN  0
+#define EHCI_HCD_OMAP_MODE_PHY      1
+#define EHCI_HCD_OMAP_MODE_TLL      2
+#define EHCI_HCD_OMAP_MODE_HSIC     3
+
+#endif	/* _OMAP_USB_H_ */
diff -r 7fffa673adcd -r a301a330526b head/sys/arm/xscale/i80321/ep80219_machdep.c
--- a/head/sys/arm/xscale/i80321/ep80219_machdep.c	Wed Aug 15 11:15:12 2012 +0300
+++ b/head/sys/arm/xscale/i80321/ep80219_machdep.c	Wed Aug 15 11:16:36 2012 +0300
@@ -46,7 +46,7 @@
  */
 
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD: head/sys/arm/xscale/i80321/ep80219_machdep.c 238329 2012-07-10 01:49:50Z imp $");
+__FBSDID("$FreeBSD: head/sys/arm/xscale/i80321/ep80219_machdep.c 239268 2012-08-15 03:03:03Z gonzo $");
 
 #define _ARM32_BUS_DMA_PRIVATE
 #include <sys/param.h>
@@ -115,9 +115,6 @@
 
 struct pv_addr kernel_pt_table[NUM_KERNEL_PTS];
 
-struct pcpu __pcpu;
-struct pcpu *pcpup = &__pcpu;
-
 /* Physical and virtual addresses for some global pages */
 
 vm_paddr_t phys_avail[10];
diff -r 7fffa673adcd -r a301a330526b head/sys/arm/xscale/i80321/iq31244_machdep.c
--- a/head/sys/arm/xscale/i80321/iq31244_machdep.c	Wed Aug 15 11:15:12 2012 +0300
+++ b/head/sys/arm/xscale/i80321/iq31244_machdep.c	Wed Aug 15 11:16:36 2012 +0300
@@ -46,7 +46,7 @@
  */
 
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD: head/sys/arm/xscale/i80321/iq31244_machdep.c 238329 2012-07-10 01:49:50Z imp $");
+__FBSDID("$FreeBSD: head/sys/arm/xscale/i80321/iq31244_machdep.c 239268 2012-08-15 03:03:03Z gonzo $");
 
 #define _ARM32_BUS_DMA_PRIVATE
 #include <sys/param.h>
@@ -115,9 +115,6 @@
 
 struct pv_addr kernel_pt_table[NUM_KERNEL_PTS];
 
-struct pcpu __pcpu;
-struct pcpu *pcpup = &__pcpu;
-
 /* Physical and virtual addresses for some global pages */
 
 vm_paddr_t phys_avail[10];
diff -r 7fffa673adcd -r a301a330526b head/sys/arm/xscale/i8134x/crb_machdep.c
--- a/head/sys/arm/xscale/i8134x/crb_machdep.c	Wed Aug 15 11:15:12 2012 +0300
+++ b/head/sys/arm/xscale/i8134x/crb_machdep.c	Wed Aug 15 11:16:36 2012 +0300
@@ -46,7 +46,7 @@
  */
 
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD: head/sys/arm/xscale/i8134x/crb_machdep.c 238329 2012-07-10 01:49:50Z imp $");
+__FBSDID("$FreeBSD: head/sys/arm/xscale/i8134x/crb_machdep.c 239268 2012-08-15 03:03:03Z gonzo $");
 
 #define _ARM32_BUS_DMA_PRIVATE
 #include <sys/param.h>
@@ -118,9 +118,6 @@
 
 struct pv_addr kernel_pt_table[NUM_KERNEL_PTS];
 
-struct pcpu __pcpu;
-struct pcpu *pcpup = &__pcpu;
-
 /* Physical and virtual addresses for some global pages */
 
 vm_paddr_t phys_avail[10];
diff -r 7fffa673adcd -r a301a330526b head/sys/arm/xscale/ixp425/avila_machdep.c
--- a/head/sys/arm/xscale/ixp425/avila_machdep.c	Wed Aug 15 11:15:12 2012 +0300
+++ b/head/sys/arm/xscale/ixp425/avila_machdep.c	Wed Aug 15 11:16:36 2012 +0300
@@ -46,7 +46,7 @@
  */
 
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD: head/sys/arm/xscale/ixp425/avila_machdep.c 238329 2012-07-10 01:49:50Z imp $");
+__FBSDID("$FreeBSD: head/sys/arm/xscale/ixp425/avila_machdep.c 239268 2012-08-15 03:03:03Z gonzo $");
 
 #define _ARM32_BUS_DMA_PRIVATE
 #include <sys/param.h>
@@ -119,9 +119,6 @@
 
 struct pv_addr kernel_pt_table[NUM_KERNEL_PTS];
 
-struct pcpu __pcpu;
-struct pcpu *pcpup = &__pcpu;
-
 /* Physical and virtual addresses for some global pages */
 
 vm_paddr_t phys_avail[10];
diff -r 7fffa673adcd -r a301a330526b head/sys/arm/xscale/pxa/pxa_machdep.c
--- a/head/sys/arm/xscale/pxa/pxa_machdep.c	Wed Aug 15 11:15:12 2012 +0300
+++ b/head/sys/arm/xscale/pxa/pxa_machdep.c	Wed Aug 15 11:16:36 2012 +0300
@@ -48,7 +48,7 @@
 #include "opt_ddb.h"
 
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD: head/sys/arm/xscale/pxa/pxa_machdep.c 238329 2012-07-10 01:49:50Z imp $");
+__FBSDID("$FreeBSD: head/sys/arm/xscale/pxa/pxa_machdep.c 239268 2012-08-15 03:03:03Z gonzo $");
 
 #define _ARM32_BUS_DMA_PRIVATE
 #include <sys/param.h>
@@ -115,9 +115,6 @@
 
 struct pv_addr kernel_pt_table[NUM_KERNEL_PTS];
 
-struct pcpu __pcpu;
-struct pcpu *pcpup = &__pcpu;
-
 /* Physical and virtual addresses for some global pages */
 
 vm_paddr_t phys_avail[PXA2X0_SDRAM_BANKS * 2 + 4];
diff -r 7fffa673adcd -r a301a330526b head/sys/arm/xscale/std.xscale
--- a/head/sys/arm/xscale/std.xscale	Wed Aug 15 11:15:12 2012 +0300
+++ b/head/sys/arm/xscale/std.xscale	Wed Aug 15 11:16:36 2012 +0300
@@ -1,3 +1,4 @@
-# $FreeBSD: head/sys/arm/xscale/std.xscale 238327 2012-07-10 01:32:52Z imp $
+# $FreeBSD: head/sys/arm/xscale/std.xscale 239268 2012-08-15 03:03:03Z gonzo $
 # machine arm armeb
 options		ARM_CACHE_LOCK_ENABLE
+options		NO_EVENTTIMERS



More information about the Zrouter-src-freebsd mailing list