[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, ®, 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, ®, 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, ®);
+ 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, ®);
+ 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 handl