[树莓派内核学习] u-boot移植-续

经过2天的折腾,u-boot基本上可以用了。不过之前编译的zImage就是不能启动。
之前不清楚,u-boot的代码实际上github上面的不是最新的。
之后使用了官网上的源码,编译之后还是不能启动之前编译的zImage。
所以在这里做一个记录。

代码地址: http://ftp.denx.de/pub/u-boot/u-boot-2014.07.tar.bz2
编译方法按照之前的方法来做。

在启动kernel时候,include/configs/rpi_b.h里默认的启动选项有点复杂,改简单一点:
 #define CONFIG_BOOTCOMMAND \
         "mmc dev 0;" \
         "fatload mmc 0:1 ${kernel_addr_r} zImage;" \
         "setenv bootargs dwc_otg.lpm_enable=0 earlyprintk console=ttyAMA0 console=tty1 root=/dev/mmcblk0p2 rootwait;" \
         "bootz ${kernel_addr_r};"


在进入u-boot执行boot之后,出现之下的情况:
在kernel中的sdhci有问题不能启动,不过将zImage转成kernel.img是没问题的。
Uncompressing Linux... done, booting the kernel.
[    0.000000] Booting Linux on physical CPU 0x0
[    0.000000] Initializing cgroup subsys cpu
[    0.000000] Initializing cgroup subsys cpuacct
[    0.000000] Linux version 3.12.26 (debian@debian) (gcc version 4.7.1 20120402 (prerelease) (crosstool-NG 1.15.2) ) #1 PREEMPT Sat Sep 27 10:43:35 CST 2014
[    0.000000] CPU: ARMv6-compatible processor [410fb767] revision 7 (ARMv7), cr=00c5387d
[    0.000000] CPU: PIPT / VIPT nonaliasing data cache, VIPT nonaliasing instruction cache
[    0.000000] Machine: BCM2708
[    0.000000] cma: CMA: reserved 8 MiB at 1b800000
[    0.000000] Memory policy: ECC disabled, Data cache writeback
[    0.000000] Built 1 zonelists in Zone order, mobility grouping on.  Total pages: 113792
[    0.000000] Kernel command line: dwc_otg.lpm_enable=0 earlyprintk console=ttyAMA0 console=tty1 root=/dev/mmcblk0p2 rootwait
[    0.000000] PID hash table entries: 2048 (order: 1, 8192 bytes)
[    0.000000] Dentry cache hash table entries: 65536 (order: 6, 262144 bytes)
[    0.000000] Inode-cache hash table entries: 32768 (order: 5, 131072 bytes)
[    0.000000] Memory: 439632K/458752K available (4405K kernel code, 241K rwdata, 1344K rodata, 143K init, 702K bss, 19120K reserved)
[    0.000000] Virtual kernel memory layout:
[    0.000000]     vector  : 0xffff0000 - 0xffff1000   (   4 kB)
[    0.000000]     fixmap  : 0xfff00000 - 0xfffe0000   ( 896 kB)
[    0.000000]     vmalloc : 0xdc800000 - 0xff000000   ( 552 MB)
[    0.000000]     lowmem  : 0xc0000000 - 0xdc000000   ( 448 MB)
[    0.000000]     modules : 0xbf000000 - 0xc0000000   (  16 MB)
[    0.000000]       .text : 0xc0008000 - 0xc05a571c   (5750 kB)
[    0.000000]       .init : 0xc05a6000 - 0xc05c9f6c   ( 144 kB)
[    0.000000]       .data : 0xc05ca000 - 0xc0606680   ( 242 kB)
[    0.000000]        .bss : 0xc060668c - 0xc06b5eb8   ( 703 kB)
[    0.000000] SLUB: HWalign=32, Order=0-3, MinObjects=0, CPUs=1, Nodes=1
[    0.000000] Preemptible hierarchical RCU implementation.
[    0.000000] NR_IRQS:394
[    0.000000] sched_clock: 32 bits at 1000kHz, resolution 1000ns, wraps every 4294967ms
[    0.000000] Switching to timer-based delay loop
[    0.000000] Console: colour dummy device 80x30
[    0.000000] console [tty1] enabled
[    0.001191] Calibrating delay loop (skipped), value calculated using timer frequency.. 2.00 BogoMIPS (lpj=10000)
[    0.001253] pid_max: default: 32768 minimum: 301
[    0.001749] Mount-cache hash table entries: 512
[    0.002596] Initializing cgroup subsys memory
[    0.002710] Initializing cgroup subsys devices
[    0.002751] Initializing cgroup subsys freezer
[    0.002785] Initializing cgroup subsys blkio
[    0.002934] CPU: Testing write buffer coherency: ok
[    0.003415] Setting up static identity map for 0xc042ee18 - 0xc042ee74
[    0.005365] devtmpfs: initialized
[    0.021698] VFP support v0.3: implementor 41 architecture 1 part 20 variant b rev 5
[    0.023302] NET: Registered protocol family 16
[    0.028552] DMA: preallocated 4096 KiB pool for atomic coherent allocations
[    0.029231] cpuidle: using governor ladder
[    0.029279] cpuidle: using governor menu
[    0.029556] bcm2708.uart_clock = 0
[    0.031588] hw-breakpoint: found 6 breakpoint and 1 watchpoint registers.
[    0.031653] hw-breakpoint: maximum watchpoint size is 4 bytes.
[    0.031689] mailbox: Broadcom VideoCore Mailbox driver
[    0.031791] bcm2708_vcio: mailbox at f200b880
[    0.031898] bcm_power: Broadcom power driver
[    0.031937] bcm_power_open() -> 0
[    0.031964] bcm_power_request(0, 8)
[    0.532251] bcm_mailbox_read -> 00000080, 0
[    0.532293] bcm_power_request -> 0
[    0.532527] Serial: AMBA PL011 UART driver
[    0.532702] dev:f1: ttyAMA0 at MMIO 0x20201000 (irq = 83, base_baud = 0) is a PL011 rev3
[    0.863803] console [ttyAMA0] enabled
[    0.890208] bio: create slab <bio-0> at 0
[    0.895759] SCSI subsystem initialized
[    0.899761] usbcore: registered new interface driver usbfs
[    0.905480] usbcore: registered new interface driver hub
[    0.911049] usbcore: registered new device driver usb
[    0.917494] Switched to clocksource stc
[    0.921758] FS-Cache: Loaded
[    0.924921] CacheFiles: Loaded
[    0.940795] NET: Registered protocol family 2
[    0.946318] TCP established hash table entries: 4096 (order: 3, 32768 bytes)
[    0.953732] TCP bind hash table entries: 4096 (order: 2, 16384 bytes)
[    0.960306] TCP: Hash tables configured (established 4096 bind 4096)
[    0.966756] TCP: reno registered
[    0.970053] UDP hash table entries: 256 (order: 0, 4096 bytes)
[    0.975926] UDP-Lite hash table entries: 256 (order: 0, 4096 bytes)
[    0.982692] NET: Registered protocol family 1
[    0.987709] RPC: Registered named UNIX socket transport module.
[    0.993672] RPC: Registered udp transport module.
[    0.998471] RPC: Registered tcp transport module.
[    1.003196] RPC: Registered tcp NFSv4.1 backchannel transport module.
[    1.010419] bcm2708_dma: DMA manager at f2007000
[    1.015164] bcm2708_gpio: bcm2708_gpio_probe c05d7ed0
[    1.020739] vc-mem: phys_addr:0x00000000 mem_base=0x00000000 mem_size:0x00000000(0 MiB)
[    1.030143] audit: initializing netlink socket (disabled)
[    1.035649] type=2000 audit(0.910:1): initialized
[    1.203128] VFS: Disk quotas dquot_6.5.2
[    1.207403] Dquot-cache hash table entries: 1024 (order 0, 4096 bytes)
[    1.216410] FS-Cache: Netfs 'nfs' registered for caching
[    1.223370] NFS: Registering the id_resolver key type
[    1.228666] Key type id_resolver registered
[    1.232874] Key type id_legacy registered
[    1.237715] msgmni has been set to 874
[    1.243470] Block layer SCSI generic (bsg) driver version 0.4 loaded (major 252)
[    1.251334] io scheduler noop registered
[    1.255292] io scheduler deadline registered
[    1.260010] io scheduler cfq registered (default)
[    1.265974] BCM2708FB: allocated DMA memory 5bc00000
[    1.271160] BCM2708FB: allocated DMA channel 4 @ f2007400
[    1.281860] Console: switching to colour frame buffer device 100x30
[    1.293095] uart-pl011 dev:f1: no DMA platform data
[    1.300415] vc-cma: Videocore CMA driver
[    1.305998] vc-cma: vc_cma_base      = 0x00000000
[    1.312413] vc-cma: vc_cma_size      = 0x00000000 (0 MiB)
[    1.319493] vc-cma: vc_cma_initial   = 0x00000000 (0 MiB)
[    1.335809] brd: module loaded
[    1.345782] loop: module loaded
[    1.350795] vchiq: vchiq_init_state: slot_zero = 0xdb800000, is_master = 0
[    1.360258] Loading iSCSI transport class v2.0-870.
[    1.367987] usbcore: registered new interface driver smsc95xx
[    1.375739] dwc_otg: version 3.00a 10-AUG-2012 (platform bus)
[    1.583297] Core Release: 2.80a
[    1.588061] Setting default values for core params
[    1.594370] Finished setting default values for core params
[    1.801523] Using Buffer DMA mode
[    1.806378] Periodic Transfer Interrupt Enhancement - disabled
[    1.813781] Multiprocessor Interrupt Enhancement - disabled
[    1.820917] OTG VER PARAM: 0, OTG VER FLAG: 0
[    1.826752] Dedicated Tx FIFOs mode
[    1.832064] WARN::dwc_otg_hcd_init:1042: FIQ DMA bounce buffers: virt = 0xdbc14000 dma = 0x5bc14000 len=9024
[    1.845131] FIQ FSM acceleration enabled for :
[    1.845131] Non-periodic Split Transactions
[    1.845131] Periodic Split Transactions
[    1.845131] High-Speed Isochronous Endpoints
[    1.868307] WARN::hcd_init:473: FIQ at 0xc030ef44
[    1.874613] WARN::hcd_init:474: FIQ ASM at 0xc030f1c0 length 36
[    1.882170] WARN::hcd_init:500: MPHI regs_base at 0xdc806000
[    1.889500] dwc_otg bcm2708_usb: DWC OTG Controller
[    1.896069] dwc_otg bcm2708_usb: new USB bus registered, assigned bus number 1
[    1.905065] dwc_otg bcm2708_usb: irq 32, io mem 0x00000000
[    1.912311] Init: Port Power? op_state=1
[    1.917913] Init: Power Port (0)
[    1.923012] usb usb1: New USB device found, idVendor=1d6b, idProduct=0002
[    1.931518] usb usb1: New USB device strings: Mfr=3, Product=2, SerialNumber=1
[    1.940436] usb usb1: Product: DWC OTG Controller
[    1.946764] usb usb1: Manufacturer: Linux 3.12.26 dwc_otg_hcd
[    1.954169] usb usb1: SerialNumber: bcm2708_usb
[    1.961211] hub 1-0:1.0: USB hub found
[    1.966667] hub 1-0:1.0: 1 port detected
[    1.973198] usbcore: registered new interface driver usb-storage
[    1.981333] mousedev: PS/2 mouse device common for all mice
[    1.989331] bcm2835-cpufreq: min=700000 max=700000 cur=700000
[    1.996831] bcm2835-cpufreq: switching to governor powersave
[    2.004153] bcm2835-cpufreq: switching to governor powersave
[    2.011401] sdhci: Secure Digital Host Controller Interface driver
[    2.019096] sdhci: Copyright(c) Pierre Ossman
[    2.025014] sdhci: Enable low-latency mode
[    2.030754] bcm2708_sdhci bcm2708_sdhci.0: couldn't allocate a DMA channel
[    2.039273] bcm2708_sdhci bcm2708_sdhci.0: probe failed, err -12
[    2.046814] bcm2708_sdhci: probe of bcm2708_sdhci.0 failed with error -12
[    2.055247] sdhci-pltfm: SDHCI platform and OF driver helper
[    2.062587] ledtrig-cpu: registered to indicate activity on CPUs
[    2.070557] hidraw: raw HID events driver (C) Jiri Kosina
[    2.077830] usbcore: registered new interface driver usbhid
[    2.084970] usbhid: USB HID core driver
[    2.090882] TCP: cubic registered
[    2.095761] Initializing XFRM netlink socket
[    2.101625] NET: Registered protocol family 17
[    2.107788] Key type dns_resolver registered
[    2.114574] registered taskstats version 1
[    2.120305] vc-sm: Videocore shared memory driver
[    2.126500] [vc_sm_connected_init]: start
[    2.132918] [vc_sm_connected_init]: end - returning 0
[    2.140681] Waiting for root device /dev/mmcblk0p2...
[    2.167709] Indeed it is in host mode hprt0 = 00021501
[    2.347624] usb 1-1: new high-speed USB device number 2 using dwc_otg
[    2.355791] Indeed it is in host mode hprt0 = 00001101
[    2.557909] usb 1-1: New USB device found, idVendor=0424, idProduct=9514
[    2.566304] usb 1-1: New USB device strings: Mfr=0, Product=0, SerialNumber=0
[    2.575993] hub 1-1:1.0: USB hub found
[    2.581643] hub 1-1:1.0: 5 ports detected
[    2.867721] usb 1-1.1: new high-speed USB device number 3 using dwc_otg
[    2.987909] usb 1-1.1: New USB device found, idVendor=0424, idProduct=ec00
[    2.996460] usb 1-1.1: New USB device strings: Mfr=0, Product=0, SerialNumber=0
[    3.008314] smsc95xx v1.0.4
[    3.071254] smsc95xx 1-1.1:1.0 eth0: register 'smsc95xx' at usb-bcm2708_usb-1.1, smsc95xx USB 2.0 Ethernet, e2:ab:f7:8d:98:c9
[    3.177655] usb 1-1.3: new high-speed USB device number 4 using dwc_otg
[    3.299183] usb 1-1.3: New USB device found, idVendor=0bda, idProduct=8176
[    3.307930] usb 1-1.3: New USB device strings: Mfr=1, Product=2, SerialNumber=3
[    3.317080] usb 1-1.3: Manufacturer: Realtek
[    3.323137] usb 1-1.3: SerialNumber: 00e04c000001
[    3.567730] usb 1-1.5: new full-speed USB device number 5 using dwc_otg
[    3.691209] usb 1-1.5: New USB device found, idVendor=1d57, idProduct=5a66
[    3.700009] usb 1-1.5: New USB device strings: Mfr=0, Product=2, SerialNumber=0
[    3.709173] usb 1-1.5: Product: 2.4G Receiver
[    3.731831] input: 2.4G Receiver as /devices/platform/bcm2708_usb/usb1/1-1/1-1.5/1-1.5:1.0/input/input0
[    3.746148] hid-generic 0003:1D57:5A66.0001: input,hiddev0,hidraw0: USB HID v1.10 Mouse [2.4G Receiver] on usb-bcm2708_usb-1.5/input0
[    3.770481] input: 2.4G Receiver as /devices/platform/bcm2708_usb/usb1/1-1/1-1.5/1-1.5:1.1/input/input1
[    3.784566] hid-generic 0003:1D57:5A66.0002: input,hidraw1: USB HID v1.10 Keyboard [2.4G Receiver] on usb-bcm2708_usb-1.5/input1

这个问题在以下几个文件有做改动:
文件地址: http://people.freebsd.org/~gonzo/arm/patches/rpi-sdhci.diff
Index: dev/mmc/mmc.c
===================================================================
--- dev/mmc/mmc.c	(revision 246573)
+++ dev/mmc/mmc.c	(working copy)
@@ -578,6 +578,8 @@
 	mmcbr_update_ios(dev);
 	mmc_ms_delay(1);
 
+	printf("mmcbr_set_clock %d == %d\n", __LINE__, 
+			mmcbr_get_f_min(sc->dev));
 	mmcbr_set_clock(dev, mmcbr_get_f_min(sc->dev));
 	mmcbr_set_timing(dev, bus_timing_normal);
 	mmcbr_set_power_mode(dev, power_on);
@@ -651,6 +653,8 @@
 	data.flags = MMC_DATA_READ;
 
 	err = mmc_wait_for_cmd(sc, &cmd, CMD_RETRIES);
+	if (err != MMC_ERR_NONE)
+		device_printf(sc->dev, "SWITCH command failed\n");
 	return (err);
 }
 
@@ -1067,7 +1071,8 @@
 	cmd.flags = MMC_RSP_R2 | MMC_CMD_BCR;
 	cmd.data = NULL;
 	err = mmc_wait_for_cmd(sc, &cmd, 0);
-	memcpy(rawcsd, cmd.resp, 4 * sizeof(uint32_t));
+	if (err == MMC_ERR_NONE)
+		memcpy(rawcsd, cmd.resp, 4 * sizeof(uint32_t));
 	return (err);
 }
 
@@ -1092,8 +1097,11 @@
 	data.flags = MMC_DATA_READ;
 
 	err = mmc_wait_for_app_cmd(sc, rca, &cmd, CMD_RETRIES);
-	rawscr[0] = be32toh(rawscr[0]);
-	rawscr[1] = be32toh(rawscr[1]);
+	if (err == MMC_ERR_NONE) {
+		rawscr[0] = be32toh(rawscr[0]);
+		rawscr[1] = be32toh(rawscr[1]);
+	}
+
 	return (err);
 }
 
@@ -1274,7 +1282,11 @@
 			mmc_send_relative_addr(sc, &resp);
 			ivar->rca = resp >> 16;
 			/* Get card CSD. */
-			mmc_send_csd(sc, ivar->rca, ivar->raw_csd);
+			err = mmc_send_csd(sc, ivar->rca, ivar->raw_csd);
+			if (err != MMC_ERR_NONE) {
+				device_printf(sc->dev, "Error reading CSD %d\n", err);
+				break;
+			}
 			if (bootverbose || mmc_debug)
 				device_printf(sc->dev,
 				    "%sard detected (CSD %08x%08x%08x%08x)\n",
@@ -1303,7 +1315,13 @@
 
 			/* Get card SCR. Card must be selected to fetch it. */
 			mmc_select_card(sc, ivar->rca);
-			mmc_app_send_scr(sc, ivar->rca, ivar->raw_scr);
+			err = mmc_app_send_scr(sc, ivar->rca, ivar->raw_scr);
+			if (err != MMC_ERR_NONE) {
+				device_printf(sc->dev,
+				    "Error reading card SCR %d\n", err);
+				break;
+			}
+
 			mmc_app_decode_scr(ivar->raw_scr, &ivar->scr);
 			/* Get card switch capabilities (command class 10). */
 			if ((ivar->scr.sda_vsn >= 1) &&
@@ -1357,7 +1375,11 @@
 		ivar->rca = rca++;
 		mmc_set_relative_addr(sc, ivar->rca);
 		/* Get card CSD. */
-		mmc_send_csd(sc, ivar->rca, ivar->raw_csd);
+		err = mmc_send_csd(sc, ivar->rca, ivar->raw_csd);
+		if (err != MMC_ERR_NONE) {
+			device_printf(sc->dev, "Error reading CSD %d\n", err);
+			break;
+		}
 		if (bootverbose || mmc_debug)
 			device_printf(sc->dev,
 			    "%sard detected (CSD %08x%08x%08x%08x)\n",
@@ -1533,6 +1555,8 @@
 			mmc_idle_cards(sc);
 	} else {
 		mmcbr_set_bus_mode(dev, opendrain);
+	printf("mmcbr_set_clock %d == %d\n", __LINE__, 
+			mmcbr_get_f_min(dev));
 		mmcbr_set_clock(dev, mmcbr_get_f_min(dev));
 		mmcbr_update_ios(dev);
 		/* XXX recompute vdd based on new cards? */
@@ -1604,7 +1628,7 @@
 	free(kids, M_TEMP);
 	if (max_timing == bus_timing_hs)
 		max_dtr = max_hs_dtr;
-	if (bootverbose || mmc_debug) {
+	if (1) {
 		device_printf(sc->dev,
 		    "setting transfer rate to %d.%03dMHz%s\n",
 		    max_dtr / 1000000, (max_dtr / 1000) % 1000,
Index: dev/sdhci/sdhci.h
===================================================================
--- dev/sdhci/sdhci.h	(revision 246573)
+++ dev/sdhci/sdhci.h	(working copy)
@@ -266,5 +266,6 @@
 int sdhci_generic_acquire_host(device_t brdev, device_t reqdev);
 int sdhci_generic_release_host(device_t brdev, device_t reqdev);
 void sdhci_generic_intr(struct sdhci_slot *slot);
+uint32_t sdhci_generic_min_freq(device_t brdev, struct sdhci_slot *slot);
 
 #endif	/* __SDHCI_H__ */
Index: dev/sdhci/sdhci_if.m
===================================================================
--- dev/sdhci/sdhci_if.m	(revision 246573)
+++ dev/sdhci/sdhci_if.m	(working copy)
@@ -58,7 +58,18 @@
 # that mmc/sd card drivers call to make requests.
 #
 
+#include <sys/types.h>
+#include <sys/systm.h>
+#include <sys/lock.h>
+#include <sys/mutex.h>
+#include <sys/taskqueue.h>
+
 #include <machine/bus.h>
+
+#include <dev/mmc/bridge.h>
+#include <dev/mmc/mmcreg.h>
+#include <dev/sdhci/sdhci.h>
+
 CODE {
 	struct sdhci_slot;
 }
@@ -119,3 +130,8 @@
 	uint32_t		*data;
 	bus_size_t		count;
 }
+
+METHOD uint32_t min_freq {
+	device_t		brdev;
+	struct sdhci_slot	*slot;
+} DEFAULT sdhci_generic_min_freq;
Index: dev/sdhci/sdhci.c
===================================================================
--- dev/sdhci/sdhci.c	(revision 246573)
+++ dev/sdhci/sdhci.c	(working copy)
@@ -65,7 +65,7 @@
 
 static SYSCTL_NODE(_hw, OID_AUTO, sdhci, CTLFLAG_RD, 0, "sdhci driver");
 
-int	sdhci_debug = 0;
+int	sdhci_debug = 1;
 TUNABLE_INT("hw.sdhci.debug", &sdhci_debug);
 SYSCTL_INT(_hw_sdhci, OID_AUTO, debug, CTLFLAG_RW, &sdhci_debug, 0, "Debug level");
 
@@ -98,6 +98,9 @@
 
 #define	SDHCI_DEFAULT_MAX_FREQ	50
 
+#define	SDHCI_200_MAX_DIVIDER	256
+#define	SDHCI_300_MAX_DIVIDER	2046
+
 static void
 sdhci_getaddr(void *arg, bus_dma_segment_t *segs, int nsegs, int error)
 {
@@ -238,7 +241,7 @@
 	if (slot->version < SDHCI_SPEC_300) {
 		/* Looking for highest freq <= clock. */
 		res = slot->max_clk;
-		for (div = 1; div < 256; div <<= 1) {
+		for (div = 1; div < SDHCI_200_MAX_DIVIDER; div <<= 1) {
 			if (res <= clock)
 				break;
 			res >>= 1;
@@ -248,10 +251,10 @@
 	}
 	else {
 		/* Version 3.0 divisors are multiples of two up to 1023*2 */
-		if (clock > slot->max_clk)
-			div = 2;
+		if (clock >= slot->max_clk)
+			div = 0;
 		else {
-			for (div = 2; div < 1023*2; div += 2) {
+			for (div = 2; div < SDHCI_300_MAX_DIVIDER; div += 2) { 
 				if ((slot->max_clk / div) <= clock) 
 					break;
 			}
@@ -545,7 +548,7 @@
 		    "frequency.\n");
 	}
 
-	slot->host.f_min = slot->max_clk / 256;
+	slot->host.f_min = SDHCI_MIN_FREQ(slot->bus, slot);
 	slot->host.f_max = slot->max_clk;
 	slot->host.host_ocr = 0;
 	if (caps & SDHCI_CAN_VDD_330)
@@ -635,6 +638,15 @@
 	return (0);
 }
 
+uint32_t
+sdhci_generic_min_freq(device_t brdev, struct sdhci_slot *slot)
+{
+	if (slot->version >= SDHCI_SPEC_300)
+		return (slot->max_clk / SDHCI_300_MAX_DIVIDER);
+	else
+		return (slot->max_clk / SDHCI_200_MAX_DIVIDER);
+}
+
 int
 sdhci_generic_update_ios(device_t brdev, device_t reqdev)
 {
@@ -1078,8 +1090,12 @@
 	}
 	if (intmask & SDHCI_INT_DATA_TIMEOUT)
 		slot->curcmd->error = MMC_ERR_TIMEOUT;
-	else if (intmask & (SDHCI_INT_DATA_CRC | SDHCI_INT_DATA_END_BIT))
+	else if (intmask & (SDHCI_INT_DATA_CRC | SDHCI_INT_DATA_END_BIT)) {
+		if (intmask & SDHCI_INT_DATA_CRC) {
+			panic("DATA CRC error\n");
+		}
 		slot->curcmd->error = MMC_ERR_BADCRC;
+	}
 	if (slot->curcmd->data == NULL &&
 	    (intmask & (SDHCI_INT_DATA_AVAIL | SDHCI_INT_SPACE_AVAIL |
 	    SDHCI_INT_DMA_END))) {
@@ -1299,14 +1315,30 @@
 		break;
 	case MMCBR_IVAR_CLOCK:
 		if (value > 0) {
-			uint32_t clock = slot->max_clk;
+			uint32_t max_clock;
+			uint32_t clock;
 			int i;
 
-			for (i = 0; i < 8; i++) {
-				if (clock <= value)
-					break;
-				clock >>= 1;
+			max_clock = slot->max_clk;
+			clock = max_clock;
+
+			if (slot->version < SDHCI_SPEC_300) {
+				for (i = 0; i < SDHCI_200_MAX_DIVIDER;
+				    i <<= 1) {
+					if (clock <= value)
+						break;
+					clock >>= 1;
+				}
 			}
+			else {
+				for (i = 0; i < SDHCI_300_MAX_DIVIDER;
+				    i += 2) {
+					if (clock <= value)
+						break;
+					clock = max_clock / (i + 2);
+				}
+			}
+
 			slot->host.ios.clock = clock;
 		} else
 			slot->host.ios.clock = 0;
Index: arm/broadcom/bcm2835/bcm2835_sdhci.c
===================================================================
--- arm/broadcom/bcm2835/bcm2835_sdhci.c	(revision 246573)
+++ arm/broadcom/bcm2835/bcm2835_sdhci.c	(working copy)
@@ -334,6 +334,18 @@
 	bus_space_write_multi_4(sc->sc_bst, sc->sc_bsh, off, data, count);
 }
 
+static uint32_t
+bcm_sdhci_min_freq(device_t dev, struct sdhci_slot *slot)
+{
+
+	/* 
+	 * Arasan HC seems to have problem with 
+	 * Data CRC on lower frequencies. Cap minimum
+	 * frequncy at 8MHz to work around this issue
+	 */
+	return (8*1000*1000);
+}
+
 static device_method_t bcm_sdhci_methods[] = {
 	/* Device interface */
 	DEVMETHOD(device_probe,		bcm_sdhci_probe),
@@ -353,6 +365,7 @@
 	DEVMETHOD(mmcbr_release_host,	sdhci_generic_release_host),
 
 	/* SDHCI registers accessors */
+	DEVMETHOD(sdhci_min_freq,	bcm_sdhci_min_freq),
 	DEVMETHOD(sdhci_read_1,		bcm_sdhci_read_1),
 	DEVMETHOD(sdhci_read_2,		bcm_sdhci_read_2),
 	DEVMETHOD(sdhci_read_4,		bcm_sdhci_read_4),
@@ -375,3 +388,4 @@
 
 DRIVER_MODULE(sdhci_bcm, simplebus, bcm_sdhci_driver, bcm_sdhci_devclass, 0, 0);
 MODULE_DEPEND(sdhci_bcm, sdhci, 1, 1, 1);
+MODULE_DEPEND(sdhci_bcm, mbox, 1, 1, 1);

下一个文件: http://people.freebsd.org/~gonzo/arm/patches/rpi_dma.diff
Index: boot/fdt/dts/bcm2835-rpi-b.dts
===================================================================
--- boot/fdt/dts/bcm2835-rpi-b.dts	(revision 245119)
+++ boot/fdt/dts/bcm2835-rpi-b.dts	(working copy)
@@ -98,10 +98,7 @@
 		dma: dma {
 			compatible = "broadcom,bcm2835-dma", "broadcom,bcm2708-dma";
 			reg = <0x7000 0x1000>, <0xE05000 0x1000>;
-			interrupts = <
-				26	/*  2 */
-				27	/*  3 */
-			>;
+			interrupts = <24 25 26 27 28 29 30 31 32 33 34 35 36>;
 			interrupt-parent = <&intc>;
 
 			broadcom,channels = <0>;	/* Set by VideoCore */
Index: dev/fdt/fdt_common.h
===================================================================
--- dev/fdt/fdt_common.h	(revision 245119)
+++ dev/fdt/fdt_common.h	(working copy)
@@ -39,7 +39,7 @@
 
 #define FDT_MEM_REGIONS	8
 
-#define DI_MAX_INTR_NUM	8
+#define DI_MAX_INTR_NUM	16
 
 struct fdt_pci_range {
 	u_long	base_pci;
Index: arm/broadcom/bcm2835/files.bcm2835
===================================================================
--- arm/broadcom/bcm2835/files.bcm2835	(revision 245119)
+++ arm/broadcom/bcm2835/files.bcm2835	(working copy)
@@ -1,5 +1,6 @@
 # $FreeBSD$
 
+arm/broadcom/bcm2835/bcm2835_dma.c		standard
 arm/broadcom/bcm2835/bcm2835_fb.c		optional sc
 arm/broadcom/bcm2835/bcm2835_gpio.c		optional gpio
 arm/broadcom/bcm2835/bcm2835_intr.c		standard
Index: arm/broadcom/bcm2835/bcm2835_dma.c
===================================================================
--- arm/broadcom/bcm2835/bcm2835_dma.c	(revision 0)
+++ arm/broadcom/bcm2835/bcm2835_dma.c	(working copy)
@@ -0,0 +1,625 @@
+/*
+ * Copyright (c) 2013 Daisuke Aoyama <[email protected]>
+ * Copyright (c) 2013 Oleksandr Tymoshenko <[email protected]>
+ *
+ * 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$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/bus.h>
+#include <sys/kernel.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 <dev/fdt/fdt_common.h>
+#include <dev/ofw/openfirm.h>
+#include <dev/ofw/ofw_bus.h>
+#include <dev/ofw/ofw_bus_subr.h>
+
+#include <vm/vm.h>
+#include <vm/pmap.h>
+#include <machine/bus.h>
+#include <machine/cpu.h>
+#include <machine/cpufunc.h>
+#include <machine/pmap.h>
+
+#include "bcm2835_dma.h"
+#include "bcm2835_vcbus.h"
+
+#define	MAX_REG			9
+
+/* private flags */
+#define	BCM_DMA_CH_USED		0x00000001
+#define	BCM_DMA_CH_FREE		0x40000000
+#define	BCM_DMA_CH_UNMAP	0x80000000
+
+/* Register Map (4.2.1.2) */
+#define	BCM_DMA_CS(n)		(0x100*(n) + 0x00)
+#define		CS_ACTIVE		(1 <<  0)
+#define		CS_END			(1 <<  1)
+#define		CS_INT			(1 <<  2)
+#define		CS_DREQ			(1 <<  3)
+#define		CS_ISPAUSED		(1 <<  4)
+#define		CS_ISHELD		(1 <<  5)
+#define		CS_ISWAIT		(1 <<  6)
+#define		CS_ERR			(1 <<  8)
+#define		CS_WAITWRT		(1 << 28)
+#define		CS_DISDBG		(1 << 29)
+#define		CS_ABORT		(1 << 30)
+#define		CS_RESET		(1 << 31)
+#define	BCM_DMA_CBADDR(n)	(0x100*(n) + 0x04)
+#define	BCM_DMA_INFO(n)		(0x100*(n) + 0x08)
+#define		INFO_INT_EN		(1 << 0)
+#define		INFO_TDMODE		(1 << 1)
+#define		INFO_WAIT_RESP		(1 << 3)
+#define		INFO_D_INC		(1 << 4)
+#define		INFO_D_WIDTH		(1 << 5)
+#define		INFO_D_DREQ		(1 << 6)
+#define		INFO_S_INC		(1 << 8)
+#define		INFO_S_WIDTH		(1 << 9)
+#define		INFO_S_DREQ		(1 << 10)
+#define		INFO_WAITS_SHIFT	(21)
+#define		INFO_PERMAP_SHIFT	(16)
+#define		INFO_PERMAP_MASK	(0x1f << INFO_PERMAP_SHIFT)
+
+#define	BCM_DMA_SRC(n)		(0x100*(n) + 0x0C)
+#define	BCM_DMA_DST(n)		(0x100*(n) + 0x10)
+#define	BCM_DMA_LEN(n)		(0x100*(n) + 0x14)
+#define	BCM_DMA_STRIDE(n)	(0x100*(n) + 0x18)
+#define	BCM_DMA_CBNEXT(n)	(0x100*(n) + 0x1C)
+#define	BCM_DMA_DEBUG(n)	(0x100*(n) + 0x20)
+#define		DEBUG_ERROR_MASK	(7)
+
+#define	BCM_DMA_INT_STATUS	0xfe0
+#define	BCM_DMA_ENABLE		0xff0
+
+/* relative offset from BCM_VC_DMA0_BASE (p.39) */
+#define	BCM_DMA_CH(n)		(0x100*(n))
+
+/* DMA Control Block - 256bit aligned (p.40) */
+struct bcm_dma_cb {
+	uint32_t info;		/* Transfer Information */
+	uint32_t src;		/* Source Address */
+	uint32_t dst;		/* Destination Address */
+	uint32_t len;		/* Transfer Length */
+	uint32_t stride;	/* 2D Mode Stride */
+	uint32_t next;		/* Next Control Block Address */
+	uint32_t rsvd1;		/* Reserved */
+	uint32_t rsvd2;		/* Reserved */
+};
+
+#ifdef DEBUG
+static void bcm_dma_cb_dump(struct bcm_dma_cb *cb);
+static void bcm_dma_reg_dump(int ch);
+#endif
+
+/* DMA channel private info */
+struct bcm_dma_ch {
+	int			ch;
+	uint32_t		flags;
+	struct bcm_dma_cb *	cb;
+	uint32_t		vc_cb;
+	bus_dmamap_t		dma_map;
+	void 			(*intr_func)(int, void *);
+	void *			intr_arg;
+};
+
+struct bcm_dma_softc {
+	device_t		sc_dev;
+	struct mtx		sc_mtx;
+	struct resource *	sc_mem;
+	struct resource *	sc_irq[BCM_DMA_CH_MAX];
+	void *			sc_intrhand[BCM_DMA_CH_MAX];
+	struct bcm_dma_ch	sc_dma_ch[BCM_DMA_CH_MAX];
+	bus_dma_tag_t		sc_dma_tag;
+};
+
+static struct bcm_dma_softc *bcm_dma_sc = NULL;
+
+static void
+bcm_dmamap_cb(void *arg, bus_dma_segment_t *segs,
+	int nseg, int err)
+{
+        bus_addr_t *addr;
+
+        if (err)
+                return;
+
+        addr = (bus_addr_t*)arg;
+        *addr = PHYS_TO_VCBUS(segs[0].ds_addr);
+}
+
+static void
+bcm_dma_reset(device_t dev, int ch)
+{
+	struct bcm_dma_softc *sc = device_get_softc(dev);
+	struct bcm_dma_cb *cb;
+	uint32_t cs;
+	int count;
+
+	if (ch < 0 || ch >= BCM_DMA_CH_MAX)
+		return;
+
+	cs = bus_read_4(sc->sc_mem, BCM_DMA_CS(ch));
+
+	if (cs & CS_ACTIVE) {
+		/* pause current task */
+		bus_write_4(sc->sc_mem, BCM_DMA_CS(ch), 0);
+
+		count = 1000;
+		do {
+			cs = bus_read_4(sc->sc_mem, BCM_DMA_CS(ch));
+		} while (!(cs & CS_ISPAUSED) && (count-- > 0));
+
+		if (!(cs & CS_ISPAUSED)) {
+			device_printf(dev,
+			    "Can't abort DMA transfer at channel %d\n", ch);
+		}
+
+		bus_write_4(sc->sc_mem, BCM_DMA_CBNEXT(ch), 0);
+
+		/* Complete everything, clear interrupt */
+		bus_write_4(sc->sc_mem, BCM_DMA_CS(ch),
+		    CS_ABORT | CS_INT | CS_END| CS_ACTIVE);
+	}
+
+	/* clear control blocks */
+	bus_write_4(sc->sc_mem, BCM_DMA_CBADDR(ch), 0);
+	bus_write_4(sc->sc_mem, BCM_DMA_CBNEXT(ch), 0);
+
+	/* Reset control block */
+	cb = sc->sc_dma_ch[ch].cb;
+	bzero(cb, sizeof(cb));
+}
+
+static int
+bcm_dma_init(device_t dev)
+{
+	struct bcm_dma_softc *sc = device_get_softc(dev);
+	uint32_t mask;
+	struct bcm_dma_ch *ch;
+	void *cb_virt;
+	vm_paddr_t cb_phys;
+	int err;
+	int i;
+
+	/* disable and clear interrupt status */
+	bus_write_4(sc->sc_mem, BCM_DMA_ENABLE, 0);
+	bus_write_4(sc->sc_mem, BCM_DMA_INT_STATUS, 0);
+
+	/* Allocate DMA chunks contorl blocks */
+	/* p.40 of spec - control block should be 32-bit aligned */
+	err = bus_dma_tag_create(bus_get_dma_tag(dev),
+	    32, 0, BUS_SPACE_MAXADDR_32BIT,
+	    BUS_SPACE_MAXADDR, NULL, NULL,
+	    sizeof(struct bcm_dma_cb), 1,
+	    sizeof(struct bcm_dma_cb),
+	    BUS_DMA_ALLOCNOW, NULL, NULL,
+	    &sc->sc_dma_tag);
+
+	if (err) {
+		device_printf(dev, "failed allocate DMA tag");
+		return (err);
+	}
+
+	/* setup initial settings */
+	for (i = 0; i < BCM_DMA_CH_MAX; i++) {
+		ch = &sc->sc_dma_ch[i];
+
+		err = bus_dmamem_alloc(sc->sc_dma_tag, &cb_virt,
+		    BUS_DMA_WAITOK | BUS_DMA_COHERENT | BUS_DMA_ZERO,
+		    &ch->dma_map);
+		if (err) {
+			device_printf(dev, "cannot allocate DMA memory\n");
+			break;
+		}
+
+		err = bus_dmamap_load(sc->sc_dma_tag, ch->dma_map, cb_virt,
+		    sizeof(struct bcm_dma_cb), bcm_dmamap_cb, &cb_phys,
+		    BUS_DMA_WAITOK);
+		if (err) {
+			device_printf(dev, "cannot load DMA memory\n");
+			break;
+		}
+
+		bzero(ch, sizeof(struct bcm_dma_ch));
+		ch->ch = i;
+		ch->cb = cb_virt;
+		ch->vc_cb = cb_phys;
+		ch->intr_func = NULL;
+		ch->intr_arg = NULL;
+		ch->flags = BCM_DMA_CH_UNMAP;
+
+		/* reset DMA engine */
+		bcm_dma_reset(dev, i);
+	}
+
+	/* now use DMA2/DMA3 only */
+	sc->sc_dma_ch[2].flags = BCM_DMA_CH_FREE;
+	sc->sc_dma_ch[3].flags = BCM_DMA_CH_FREE;
+
+	/* enable DMAs */
+	mask = 0;
+
+	for (i = 0; i < BCM_DMA_CH_MAX; i++)
+		if (sc->sc_dma_ch[i].flags & BCM_DMA_CH_FREE)
+			mask |= (1 << i);
+
+	bus_write_4(sc->sc_mem, BCM_DMA_ENABLE, mask);
+
+	return (0);
+}
+
+int
+bcm_dma_allocate(int req_ch)
+{
+	struct bcm_dma_softc *sc = bcm_dma_sc;
+	int ch = -1;
+	int i;
+
+	if (req_ch >= BCM_DMA_CH_MAX)
+		return (-1);
+
+	/* Auto(req_ch < 0) or CH specified */
+	mtx_lock(&sc->sc_mtx);
+
+	if (req_ch < 0) {
+		for (i = 0; i < BCM_DMA_CH_MAX; i++) {
+			if (sc->sc_dma_ch[i].flags & BCM_DMA_CH_FREE) {
+				ch = i;
+				sc->sc_dma_ch[ch].flags &= ~BCM_DMA_CH_FREE;
+				sc->sc_dma_ch[ch].flags |= BCM_DMA_CH_USED;
+				break;
+			}
+		}
+	}
+	else {
+		if (sc->sc_dma_ch[req_ch].flags & BCM_DMA_CH_FREE) {
+			ch = req_ch;
+			sc->sc_dma_ch[ch].flags &= ~BCM_DMA_CH_FREE;
+			sc->sc_dma_ch[ch].flags |= BCM_DMA_CH_USED;
+		}
+	}
+
+	mtx_unlock(&sc->sc_mtx);
+	return (ch);
+}
+
+int
+bcm_dma_free(int ch)
+{
+	struct bcm_dma_softc *sc = bcm_dma_sc;
+
+	if (ch < 0 || ch >= BCM_DMA_CH_MAX)
+		return (-1);
+
+	mtx_lock(&sc->sc_mtx);
+	if (sc->sc_dma_ch[ch].flags & BCM_DMA_CH_USED) {
+		sc->sc_dma_ch[ch].flags |= BCM_DMA_CH_FREE;
+		sc->sc_dma_ch[ch].flags &= ~BCM_DMA_CH_USED;
+		sc->sc_dma_ch[ch].intr_func = NULL;
+		sc->sc_dma_ch[ch].intr_arg = NULL;
+
+		/* reset DMA engine */
+		bcm_dma_reset(sc->sc_dev, ch);
+	}
+
+	mtx_unlock(&sc->sc_mtx);
+	return (0);
+}
+
+int
+bcm_dma_setup_intr(int ch, void (*func)(int, void *), void *arg)
+{
+	struct bcm_dma_softc *sc = bcm_dma_sc;
+	struct bcm_dma_cb *cb;
+
+	if (ch < 0 || ch >= BCM_DMA_CH_MAX)
+		return (-1);
+
+	if (!(sc->sc_dma_ch[ch].flags & BCM_DMA_CH_USED))
+		return (-1);
+
+	sc->sc_dma_ch[ch].intr_func = func;
+	sc->sc_dma_ch[ch].intr_arg = arg;
+	cb = sc->sc_dma_ch[ch].cb;
+	cb->info |= INFO_INT_EN;
+
+	return (0);
+}
+
+int
+bcm_dma_setup_src(int ch, int dreq, int increase_addr)
+{
+	struct bcm_dma_softc *sc = bcm_dma_sc;
+	uint32_t info;
+
+	if (ch < 0 || ch >= BCM_DMA_CH_MAX)
+		return (-1);
+
+	if (!(sc->sc_dma_ch[ch].flags & BCM_DMA_CH_USED))
+		return (-1);
+
+	info = sc->sc_dma_ch[ch].cb->info;
+	info &= ~INFO_PERMAP_MASK;
+	info &= ~INFO_S_DREQ;
+	info |= (dreq << INFO_PERMAP_SHIFT) & INFO_PERMAP_MASK;
+	if (dreq)
+		info |= INFO_S_DREQ;
+
+	if (increase_addr)
+		info |= INFO_S_INC;
+	else
+		info &= ~INFO_S_INC;
+
+	sc->sc_dma_ch[ch].cb->info = info;
+
+	return (0);
+}
+
+int
+bcm_dma_setup_dst(int ch, int dreq, int increase_addr)
+{
+	struct bcm_dma_softc *sc = bcm_dma_sc;
+	uint32_t info;
+
+	if (ch < 0 || ch >= BCM_DMA_CH_MAX)
+		return (-1);
+
+	if (!(sc->sc_dma_ch[ch].flags & BCM_DMA_CH_USED))
+		return (-1);
+
+	info = sc->sc_dma_ch[ch].cb->info;
+	info &= ~INFO_PERMAP_MASK;
+	info &= ~INFO_D_DREQ;
+	info |= (dreq << INFO_PERMAP_SHIFT) & INFO_PERMAP_MASK;
+	if (dreq)
+		info |= INFO_D_DREQ;
+
+	if (increase_addr)
+		info |= INFO_D_INC;
+	else
+		info &= ~INFO_D_INC;
+
+	sc->sc_dma_ch[ch].cb->info = info;
+
+	return (0);
+}
+
+#ifdef DEBUG
+void
+bcm_dma_cb_dump(struct bcm_dma_cb *cb)
+{
+
+	printf("DMA CB ");
+	printf("INFO: %8.8x ", cb->info);
+	printf("SRC: %8.8x ", cb->src);
+	printf("DST: %8.8x ", cb->dst);
+	printf("LEN: %8.8x ", cb->len);
+	printf("\n");
+	printf("STRIDE: %8.8x ", cb->stride);
+	printf("NEXT: %8.8x ", cb->next);
+	printf("RSVD1: %8.8x ", cb->rsvd1);
+	printf("RSVD2: %8.8x ", cb->rsvd2);
+	printf("\n");
+}
+
+void
+bcm_dma_reg_dump(int ch)
+{
+	struct bcm_dma_softc *sc = bcm_dma_sc;
+	int i;
+	uint32_t reg;
+
+	if (ch < 0 || ch >= BCM_DMA_CH_MAX)
+		return;
+
+	printf("DMA%d: ", ch);
+	for (i = 0; i < MAX_REG; i++) {
+		reg = bus_read_4(sc->sc_mem, BCM_DMA_CH(ch) + i*4);
+		printf("%8.8x ", reg);
+	}
+	printf("\n");
+}
+#endif
+
+int
+bcm_dma_start(int ch, vm_paddr_t src, vm_paddr_t dst, int len)
+{
+	struct bcm_dma_softc *sc = bcm_dma_sc;
+	struct bcm_dma_cb *cb;
+
+	if (ch < 0 || ch >= BCM_DMA_CH_MAX)
+		return (-1);
+
+	if (!(sc->sc_dma_ch[ch].flags & BCM_DMA_CH_USED))
+		return (-1);
+
+	cb = sc->sc_dma_ch[ch].cb;
+	cb->src = PHYS_TO_VCBUS(src);
+	cb->dst = PHYS_TO_VCBUS(dst);
+	cb->len = len;
+
+	bus_write_4(sc->sc_mem, BCM_DMA_CBADDR(ch),
+	    sc->sc_dma_ch[ch].vc_cb);
+	bus_write_4(sc->sc_mem, BCM_DMA_CS(ch), CS_ACTIVE);
+
+#ifdef DEBUG
+	bcm_dma_cb_dump(sc->sc_dma_ch[ch].cb);
+	bcm_dma_reg_dump(ch);
+#endif
+
+	return (0);
+}
+
+int
+bcm_dma_restart(int ch)
+{
+	if (ch < 0 || ch >= BCM_DMA_CH_MAX)
+		return (-1);
+
+	printf("Restart with CS\n");
+	return (0);
+}
+
+static void
+bcm_dma_intr(void *arg)
+{
+	struct bcm_dma_softc *sc = bcm_dma_sc;
+	struct bcm_dma_ch *ch = (struct bcm_dma_ch *)arg;
+	uint32_t cs, debug;
+
+	/* my interrupt? */
+	cs = bus_read_4(sc->sc_mem, BCM_DMA_CS(ch->ch));
+
+	if (!(cs & (CS_INT | CS_ERR)))
+		return;
+
+	/* running? */
+	if (!(ch->flags & BCM_DMA_CH_USED)) {
+		device_printf(sc->sc_dev,
+		    "unused DMA intr CH=%d, CS=%x\n", ch->ch, cs);
+		return;
+	}
+
+	if (cs & CS_ERR) {
+		debug = bus_read_4(sc->sc_mem, BCM_DMA_DEBUG(ch->ch));
+		device_printf(sc->sc_dev, "DMA error %d on CH%d\n",
+			debug & DEBUG_ERROR_MASK, ch->ch);
+		bus_write_4(sc->sc_mem, BCM_DMA_DEBUG(ch->ch), 
+		    debug & DEBUG_ERROR_MASK);
+	}
+
+	if (cs & CS_INT) {
+		/* acknowledge interrupt */
+		bus_write_4(sc->sc_mem, BCM_DMA_CS(ch->ch), 
+		    CS_INT | CS_END);
+
+		/* save callback function and argument */
+		if (ch->intr_func)
+			ch->intr_func(ch->ch, ch->intr_arg);
+	}
+}
+
+static int
+bcm_dma_probe(device_t dev)
+{
+
+	if (!ofw_bus_is_compatible(dev, "broadcom,bcm2835-dma"))
+		return (ENXIO);
+
+	device_set_desc(dev, "BCM2835 DMA Controller");
+	return (BUS_PROBE_DEFAULT);
+}
+
+static int
+bcm_dma_attach(device_t dev)
+{
+	struct bcm_dma_softc *sc = device_get_softc(dev);
+	int rid, err = 0;
+	int i;
+
+	sc->sc_dev = dev;
+
+	if (bcm_dma_sc)
+		return (ENXIO);
+
+	for (i = 0; i < BCM_DMA_CH_MAX; i++) {
+		sc->sc_irq[i] = NULL;
+		sc->sc_intrhand[i] = NULL;
+	}
+
+	/* DMA0 - DMA14 */
+	rid = 0;
+	sc->sc_mem = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, RF_ACTIVE);
+	if (sc->sc_mem == NULL) {
+		device_printf(dev, "could not allocate memory resource\n");
+		return (ENXIO);
+	}
+
+	/* IRQ DMA0 - DMA11 XXX NOT USE DMA12(spurious?) */
+	for (rid = 0; rid < BCM_DMA_CH_MAX; rid++) {
+		sc->sc_irq[rid] = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid,
+						       RF_ACTIVE);
+		if (sc->sc_irq[rid] == NULL) {
+			device_printf(dev, "cannot allocate interrupt\n");
+			err = ENXIO;
+			goto fail;
+		}
+		if (bus_setup_intr(dev, sc->sc_irq[rid], INTR_TYPE_MISC | INTR_MPSAFE,
+				   NULL, bcm_dma_intr, &sc->sc_dma_ch[rid],
+				   &sc->sc_intrhand[rid])) {
+			device_printf(dev, "cannot setup interrupt handler\n");
+			err = ENXIO;
+			goto fail;
+		}
+	}
+
+	mtx_init(&sc->sc_mtx, "bcmdma", "bcmdma", MTX_DEF);
+	bcm_dma_sc = sc;
+
+	err = bcm_dma_init(dev);
+	if (err)
+		goto fail;
+
+	return (err);
+
+fail:
+	if (sc->sc_mem)
+		bus_release_resource(dev, SYS_RES_MEMORY, 0, sc->sc_mem);
+
+	for (i = 0; i < BCM_DMA_CH_MAX; i++) {
+		if (sc->sc_intrhand[i])
+			bus_teardown_intr(dev, sc->sc_irq[i], sc->sc_intrhand[i]);
+		if (sc->sc_irq[i])
+			bus_release_resource(dev, SYS_RES_IRQ, 0, sc->sc_irq[i]);
+	}
+
+	return (err);
+}
+
+static device_method_t bcm_dma_methods[] = {
+	DEVMETHOD(device_probe,		bcm_dma_probe),
+	DEVMETHOD(device_attach,	bcm_dma_attach),
+	{ 0, 0 }
+};
+
+static driver_t bcm_dma_driver = {
+	"bcm_dma",
+	bcm_dma_methods,
+	sizeof(struct bcm_dma_softc),
+};
+
+static devclass_t bcm_dma_devclass;
+
+DRIVER_MODULE(bcm_dma, simplebus, bcm_dma_driver, bcm_dma_devclass, 0, 0);
+MODULE_VERSION(bcm_dma, 1);

Property changes on: arm/broadcom/bcm2835/bcm2835_dma.c
___________________________________________________________________
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
Added: svn:keywords
## -0,0 +1 ##
+FreeBSD=%H
Added: svn:eol-style
## -0,0 +1 ##
+native
Index: arm/broadcom/bcm2835/bcm2835_dma.h
===================================================================
--- arm/broadcom/bcm2835/bcm2835_dma.h	(revision 0)
+++ arm/broadcom/bcm2835/bcm2835_dma.h	(working copy)
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2013 Daisuke Aoyama <[email protected]>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef	_BCM2835_DMA_H_
+#define	_BCM2835_DMA_H_
+
+/* DMA0-DMA15 but DMA15 is special */
+#define	BCM_DMA_CH_MAX		12
+
+/* request CH for any nubmer */
+#define	BCM_DMA_CH_ANY		(-1)
+
+/* Peripheral DREQ Signals (4.2.1.3) */
+#define	BCM_DMA_DREQ_EMMC	11
+#define	BCM_DMA_DREQ_SDHOST	13
+
+int bcm_dma_allocate(int req_ch);
+int bcm_dma_free(int ch);
+int bcm_dma_setup_intr(int ch, void (*func)(int, void *), void *arg);
+int bcm_dma_setup_src(int ch, int dreq, int increase_addr);
+int bcm_dma_setup_dst(int ch, int dreq, int increase_addr);
+int bcm_dma_start(int ch, vm_paddr_t src, vm_paddr_t dst, int len);
+int bcm_dma_restart(int ch);
+
+#endif	/* _BCM2835_DMA_H_ */

Property changes on: arm/broadcom/bcm2835/bcm2835_dma.h
___________________________________________________________________
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
Added: svn:keywords
## -0,0 +1 ##
+FreeBSD=%H
Added: svn:eol-style
## -0,0 +1 ##
+native

以上两个文件我没有加到kernel中。这里算烂尾了。开了坑啥时候填都不知道。

猜你喜欢

转载自blog.csdn.net/u010398378/article/details/39700515